From f17f97fff6cd5ef4d82dd1cbed67bcc634d415df Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 17 Sep 2023 19:29:21 -0700 Subject: [PATCH 001/301] Merge in NotFine --- dependencies.gradle | 42 ++- gradle.properties | 5 +- .../client/renderer/texture/TextureMap.java | 3 + src/main/java/jss/notfine/NotFine.java | 51 ++++ .../jss/notfine/config/NotFineConfig.java | 30 +++ .../notfine/config/VideoSettingsConfig.java | 52 ++++ .../jss/notfine/core/LoadMenuButtons.java | 33 +++ src/main/java/jss/notfine/core/Settings.java | 165 ++++++++++++ .../jss/notfine/core/SettingsManager.java | 140 ++++++++++ .../java/jss/notfine/gui/GuiCustomMenu.java | 94 +++++++ .../jss/notfine/gui/GuiCustomMenuButton.java | 29 ++ .../notfine/gui/GuiCustomSettingButton.java | 27 ++ .../notfine/gui/GuiCustomSettingSlider.java | 65 +++++ .../notfine/gui/GuiCustomSettingsRowList.java | 121 +++++++++ .../notfine/gui/GuiVanillaSettingButton.java | 27 ++ .../notfine/gui/GuiVanillaSettingSlider.java | 68 +++++ .../java/jss/notfine/gui/MenuButtonLists.java | 102 +++++++ .../mixinplugin/NotFineEarlyMixins.java | 83 ++++++ .../mixinplugin/NotFineLateMixins.java | 59 ++++ .../early/minecraft/MixinGameSettings.java | 251 +++++++++++++++++ .../early/minecraft/MixinRenderGlobal.java | 29 ++ .../minecraft/clouds/MixinEntityRenderer.java | 24 ++ .../minecraft/clouds/MixinGameSettings.java | 22 ++ .../minecraft/clouds/MixinRenderGlobal.java | 255 ++++++++++++++++++ .../minecraft/clouds/MixinWorldType.java | 20 ++ .../minecraft/glint/MixinItemRenderer.java | 25 ++ .../minecraft/glint/MixinRenderBiped.java | 24 ++ .../minecraft/glint/MixinRenderItem.java | 79 ++++++ .../minecraft/glint/MixinRenderPlayer.java | 24 ++ .../early/minecraft/gui/MixinGuiSlot.java | 21 ++ .../minecraft/leaves/MixinBlockLeaves.java | 60 +++++ .../leaves/MixinBlockLeavesBase.java | 23 ++ .../particles/MixinBlockEnchantmentTable.java | 61 +++++ .../particles/MixinEffectRenderer.java | 94 +++++++ .../minecraft/particles/MixinWorldClient.java | 24 ++ .../particles/MixinWorldProvider.java | 25 ++ .../minecraft/toggle/MixinEntityRenderer.java | 27 ++ .../minecraft/toggle/MixinGuiIngame.java | 24 ++ .../early/minecraft/toggle/MixinRender.java | 27 ++ .../minecraft/toggle/MixinRenderItem.java | 27 ++ .../leaves/MixinBlockMagicalLeaves.java | 59 ++++ .../leaves/MixinBlockTFLeaves.java | 40 +++ .../leaves/MixinBlockTFLeaves3.java | 38 +++ .../leaves/MixinBlockTFMagicLeaves.java | 59 ++++ .../leaves/MixinBlockWitchLeaves.java | 58 ++++ .../java/jss/notfine/render/RenderStars.java | 72 +++++ .../java/jss/notfine/util/ILeafBlock.java | 5 + .../java/jss/notfine/util/LeafRenderUtil.java | 107 ++++++++ src/main/java/jss/util/DirectionHelper.java | 41 +++ .../jss/util/RandomXoshiro256StarStar.java | 190 +++++++++++++ src/main/resources/META-INF/notfine_at.cfg | 8 + .../resources/assets/notfine/lang/de_DE.lang | 54 ++++ .../resources/assets/notfine/lang/en_US.lang | 62 +++++ .../resources/assets/notfine/lang/zh_CN.lang | 54 ++++ src/main/resources/mcmod.info | 64 +++-- src/main/resources/mixins.notfine.early.json | 8 + src/main/resources/mixins.notfine.json | 11 + src/main/resources/mixins.notfine.late.json | 8 + 58 files changed, 3282 insertions(+), 18 deletions(-) create mode 100644 src/main/java/jss/notfine/NotFine.java create mode 100644 src/main/java/jss/notfine/config/NotFineConfig.java create mode 100644 src/main/java/jss/notfine/config/VideoSettingsConfig.java create mode 100644 src/main/java/jss/notfine/core/LoadMenuButtons.java create mode 100644 src/main/java/jss/notfine/core/Settings.java create mode 100644 src/main/java/jss/notfine/core/SettingsManager.java create mode 100644 src/main/java/jss/notfine/gui/GuiCustomMenu.java create mode 100644 src/main/java/jss/notfine/gui/GuiCustomMenuButton.java create mode 100644 src/main/java/jss/notfine/gui/GuiCustomSettingButton.java create mode 100644 src/main/java/jss/notfine/gui/GuiCustomSettingSlider.java create mode 100644 src/main/java/jss/notfine/gui/GuiCustomSettingsRowList.java create mode 100644 src/main/java/jss/notfine/gui/GuiVanillaSettingButton.java create mode 100644 src/main/java/jss/notfine/gui/GuiVanillaSettingSlider.java create mode 100644 src/main/java/jss/notfine/gui/MenuButtonLists.java create mode 100644 src/main/java/jss/notfine/mixinplugin/NotFineEarlyMixins.java create mode 100644 src/main/java/jss/notfine/mixinplugin/NotFineLateMixins.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/MixinGameSettings.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/MixinRenderGlobal.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinEntityRenderer.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinGameSettings.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinRenderGlobal.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinWorldType.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinItemRenderer.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderBiped.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderItem.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderPlayer.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/gui/MixinGuiSlot.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeaves.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeavesBase.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinBlockEnchantmentTable.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinEffectRenderer.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldClient.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldProvider.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinEntityRenderer.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinGuiIngame.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRender.java create mode 100644 src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRenderItem.java create mode 100644 src/main/java/jss/notfine/mixins/late/thaumcraft/leaves/MixinBlockMagicalLeaves.java create mode 100644 src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves.java create mode 100644 src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves3.java create mode 100644 src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFMagicLeaves.java create mode 100644 src/main/java/jss/notfine/mixins/late/witchery/leaves/MixinBlockWitchLeaves.java create mode 100644 src/main/java/jss/notfine/render/RenderStars.java create mode 100644 src/main/java/jss/notfine/util/ILeafBlock.java create mode 100644 src/main/java/jss/notfine/util/LeafRenderUtil.java create mode 100644 src/main/java/jss/util/DirectionHelper.java create mode 100644 src/main/java/jss/util/RandomXoshiro256StarStar.java create mode 100644 src/main/resources/META-INF/notfine_at.cfg create mode 100644 src/main/resources/assets/notfine/lang/de_DE.lang create mode 100644 src/main/resources/assets/notfine/lang/en_US.lang create mode 100644 src/main/resources/assets/notfine/lang/zh_CN.lang create mode 100644 src/main/resources/mixins.notfine.early.json create mode 100644 src/main/resources/mixins.notfine.json create mode 100644 src/main/resources/mixins.notfine.late.json diff --git a/dependencies.gradle b/dependencies.gradle index 6478ae269..12c1009df 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,10 +1,50 @@ +/* + * Add your dependencies here. Supported configurations: + * - api("group:name:version:classifier"): if you use the types from this dependency in the public API of this mod + * Available at runtime and compiletime for mods depending on this mod + * - implementation("g:n:v:c"): if you need this for internal implementation details of the mod, but none of it is visible via the public API + * Available at runtime but not compiletime for mods depending on this mod + * - compileOnly("g:n:v:c"): if the mod you're building doesn't need this dependency during runtime at all, e.g. for optional mods + * Not available at all for mods depending on this mod, only visible at compiletime for this mod + * - compileOnlyApi("g:n:v:c"): like compileOnly, but also visible at compiletime for mods depending on this mod + * Available at compiletime but not runtime for mods depending on this mod + * - runtimeOnlyNonPublishable("g:n:v:c"): if you want to include a mod in this mod's runClient/runServer runs, but not publish it as a dependency + * Not available at all for mods depending on this mod, only visible at runtime for this mod + * - devOnlyNonPublishable("g:n:v:c"): a combination of runtimeOnlyNonPublishable and compileOnly for dependencies present at both compiletime and runtime, + * but not published as Maven dependencies - useful for RFG-deobfuscated dependencies or local testing + * - runtimeOnly("g:n:v:c"): if you don't need this at compile time, but want it to be present at runtime + * Available at runtime for mods depending on this mod + * - annotationProcessor("g:n:v:c"): mostly for java compiler plugins, if you know you need this, use it, otherwise don't worry + * - testCONFIG("g:n:v:c") - replace CONFIG by one of the above (except api), same as above but for the test sources instead of main + * + * - shadowImplementation("g:n:v:c"): effectively the same as API, but the dependency is included in your jar under a renamed package name + * Requires you to enable usesShadowedDependencies in gradle.properties + * + * - compile("g:n:v:c"): deprecated, replace with "api" (works like the old "compile") or "implementation" (can be more efficient) + * + * You can exclude transitive dependencies (dependencies of the chosen dependency) by appending { transitive = false } if needed, + * but use this sparingly as it can break using your mod as another mod's dependency if you're not careful. + * + * To depend on obfuscated jars you can use `devOnlyNonPublishable(rfg.deobf("dep:spec:1.2.3"))` to fetch an obfuscated jar from maven, + * or `devOnlyNonPublishable(rfg.deobf(project.files("libs/my-mod-jar.jar")))` to use a file. + * + * Gradle names for some of the configuration can be misleading, compileOnlyApi and runtimeOnly both get published as dependencies in Maven, but compileOnly does not. + * The buildscript adds runtimeOnlyNonPublishable to also have a runtime dependency that's not published. + * + * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph + */ dependencies { compileOnly(sourceSets.compileStubs.output) compileStubs(sourceSets.compileStubsStubs.output) - + compileOnly("com.github.GTNewHorizons:ProjectRed:4.7.12-GTNH:dev") compileOnly(files("dependencies/SmartRender-1.7.10-2.1-dev.jar")) + compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev") + runtimeOnly("com.github.GTNewHorizons:Baubles:1.0.1.16:dev") + compileOnly("com.github.GTNewHorizons:twilightforest:2.3.8.18:dev") {transitive = false } + devOnlyNonPublishable(rfg.deobf('curse.maven:witchery-69673:2234410')) + runtimeOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughItems:2.3.55-GTNH:dev") } diff --git a/gradle.properties b/gradle.properties index 229caa031..c6f5bfb8c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -62,7 +62,7 @@ apiPackage = # Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/ # There can be multiple files in a comma-separated list. # Example value: mymodid_at.cfg,nei_at.cfg -accessTransformersFile = angelica_at.cfg +accessTransformersFile = angelica_at.cfg,notfine_at.cfg # Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! usesMixins = true @@ -136,7 +136,8 @@ curseForgeRelations = # Uncomment this to disable spotless checks # This should only be uncommented to keep it easier to sync with upstream/other forks. # That is, if there is no other active fork/upstream, NEVER change this. -# disableSpotless = true +# Disabling to make easier to sync if some of the additional mods get any changes upstream +disableSpotless = true # Override the IDEA build type. Valid value is "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle" # (force use delegated build). diff --git a/src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java b/src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java index b8e2a707c..1aa78f013 100644 --- a/src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java +++ b/src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java @@ -6,6 +6,7 @@ public class TextureMap extends AbstractTexture { public static ResourceLocation locationBlocksTexture; + public static ResourceLocation locationItemsTexture; public int angelica$atlasWidth; public int angelica$atlasHeight; @@ -17,6 +18,8 @@ public ResourceLocation completeResourceLocation(ResourceLocation p_147634_1_, i } public void updateAnimations() {} + public void setAnisotropicFiltering(int p_147632_1_) {} + public void setMipmapLevels(int p_147633_1_) {} public int getTextureType() { return 0; diff --git a/src/main/java/jss/notfine/NotFine.java b/src/main/java/jss/notfine/NotFine.java new file mode 100644 index 000000000..642467e32 --- /dev/null +++ b/src/main/java/jss/notfine/NotFine.java @@ -0,0 +1,51 @@ +package jss.notfine; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.relauncher.Side; +import jss.notfine.config.NotFineConfig; +import jss.notfine.core.LoadMenuButtons; +import jss.notfine.core.SettingsManager; +import net.minecraft.client.Minecraft; +import net.minecraft.client.settings.GameSettings; +import net.minecraftforge.common.MinecraftForge; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Mod( + modid = NotFine.MODID, + name = NotFine.NAME, + version = NotFine.VERSION, + acceptableRemoteVersions = "*" +) +public class NotFine { + public static final String MODID = "notfine"; + public static final String NAME = "NotFine"; + public static final String VERSION = "GRADLETOKEN_VERSION"; + public static final Logger logger = LogManager.getLogger(NAME); + + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent event) { + if(event.getSide() == Side.CLIENT) { + FMLCommonHandler.instance().bus().register(LoadMenuButtons.INSTANCE); + MinecraftForge.EVENT_BUS.register(LoadMenuButtons.INSTANCE); + GameSettings.Options.FRAMERATE_LIMIT.valueStep = 1f; + } + NotFineConfig config = new NotFineConfig(); + config.loadSettings(); + + if(!NotFineConfig.allowAdvancedOpenGL) { + Minecraft.getMinecraft().gameSettings.advancedOpengl = false; + } + } + + @Mod.EventHandler + public void postInit(FMLPostInitializationEvent event) { + if(event.getSide() == Side.CLIENT) { + SettingsManager.settingsFile.loadSettings(); + } + } + +} diff --git a/src/main/java/jss/notfine/config/NotFineConfig.java b/src/main/java/jss/notfine/config/NotFineConfig.java new file mode 100644 index 000000000..44ddd1723 --- /dev/null +++ b/src/main/java/jss/notfine/config/NotFineConfig.java @@ -0,0 +1,30 @@ +package jss.notfine.config; + +import net.minecraft.launchwrapper.Launch; +import net.minecraftforge.common.config.Configuration; +import jss.notfine.NotFine; + +import java.io.File; + +public class NotFineConfig { + + public static boolean allowAdvancedOpenGL = true; + + public static final String CATEGORY_CLIENT = "client"; + + private final Configuration notFineConfig; + + public NotFineConfig() { + File configFile = new File(Launch.minecraftHome + File.separator + "config" + File.separator + NotFine.MODID + File.separator + "notfine.cfg"); + notFineConfig = new Configuration(configFile); + } + + public void loadSettings() { + allowAdvancedOpenGL = notFineConfig.getBoolean("allowAdvancedOpenGL", CATEGORY_CLIENT, true, "Allow or always remove the Advanced OpenGL button"); + + if(notFineConfig.hasChanged()) { + notFineConfig.save(); + } + } + +} diff --git a/src/main/java/jss/notfine/config/VideoSettingsConfig.java b/src/main/java/jss/notfine/config/VideoSettingsConfig.java new file mode 100644 index 000000000..55a3ef7fa --- /dev/null +++ b/src/main/java/jss/notfine/config/VideoSettingsConfig.java @@ -0,0 +1,52 @@ +package jss.notfine.config; + +import jss.notfine.core.Settings; +import net.minecraftforge.common.config.Configuration; + +import java.io.File; + +public class VideoSettingsConfig { + private final Configuration settingsConfig; + + public VideoSettingsConfig(File userSettingsFile) { + settingsConfig = new Configuration(userSettingsFile); + } + + public void loadSettings() { + for(Settings setting : Settings.values()) { + + float value = settingsConfig.getFloat( + setting.name(), + ("Settings"), + setting.base, + setting.minimum, + setting.maximum, + setting.configComment + ); + + if(setting.step > 0f) { + value = setting.step * (float)Math.round(value / setting.step); + } + + setting.setValue(value); + } + if(settingsConfig.hasChanged()) { + settingsConfig.save(); + } + } + + public void saveSettings() { + for(Settings setting : Settings.values()) { + settingsConfig.get( + ("Settings"), + setting.name(), + setting.base, + setting.configComment, + setting.minimum, + setting.maximum + ).set(setting.getValue()); + } + settingsConfig.save(); + } + +} diff --git a/src/main/java/jss/notfine/core/LoadMenuButtons.java b/src/main/java/jss/notfine/core/LoadMenuButtons.java new file mode 100644 index 000000000..0ae773700 --- /dev/null +++ b/src/main/java/jss/notfine/core/LoadMenuButtons.java @@ -0,0 +1,33 @@ +package jss.notfine.core; + +import cpw.mods.fml.common.eventhandler.EventPriority; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import jss.notfine.gui.GuiCustomMenuButton; +import jss.notfine.gui.MenuButtonLists; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiOptions; +import net.minecraftforge.client.event.GuiScreenEvent.InitGuiEvent; + +import java.util.List; + +public class LoadMenuButtons { + + public static final LoadMenuButtons INSTANCE = new LoadMenuButtons(); + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onGui(InitGuiEvent.Post event) { + if(event.gui instanceof GuiOptions) { + GuiButton videoSettings = ((List)event.buttonList).stream().filter(button -> button.id == 101).findFirst().get(); + videoSettings.visible = false; + + event.buttonList.add( + new GuiCustomMenuButton( + videoSettings.xPosition, videoSettings.yPosition, + videoSettings.width, videoSettings.height, + MenuButtonLists.VIDEO + ) + ); + } + } + +} diff --git a/src/main/java/jss/notfine/core/Settings.java b/src/main/java/jss/notfine/core/Settings.java new file mode 100644 index 000000000..d937d8181 --- /dev/null +++ b/src/main/java/jss/notfine/core/Settings.java @@ -0,0 +1,165 @@ +package jss.notfine.core; + +import jss.notfine.render.RenderStars; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.MathHelper; + +public enum Settings { + CLOUD_HEIGHT(true, 128f, 96f, 384f, 8f) { + @Override + public void updateSetting() { + SettingsManager.cloudsUpdated(); + } + }, + CLOUD_SCALE(true, 1f, 0.5f, 5f, 0.25f), + FOG_DEPTH(false,0f, 0f, 1f, 1f, "0:On, 1:Off"), + GUI_BACKGROUND(false, -1f, -1f, 5f, 1f, "-1:Default, 0:Sand, 1:Mycelium, 2:Stonebrick, 3:Mossy Stonebrick, 4:Oak Planks, 5: Birch Planks") { + @Override + public void updateSetting() { + SettingsManager.backgroundUpdated(); + } + }, + MODE_CLOUD_TRANSLUCENCY(false, -1f,-1f,1f, 1f, "-1:Default, 0:Always, 1:Never") { + @Override + public void updateSetting() { + SettingsManager.cloudsUpdated(); + } + }, + MODE_CLOUDS(false,-1f, -1f, 2f, 1f, "-1:Default, 0:Fancy, 1:Fast, 2:Off") { + @Override + public void updateSetting() { + SettingsManager.cloudsUpdated(); + } + }, + MODE_DROPPED_ITEMS(false, -1f,-1f,1f, 1f, "-1:Default, 0:On, 1:Off") { + @Override + public void updateSetting() { + SettingsManager.droppedItemDetailUpdated(); + } + }, + MODE_GLINT_INV(false,0f, 0f, 1f, 1f, "0:On, 1:Off"), + MODE_GLINT_WORLD(false,0f, 0f, 1f, 1f, "0:On, 1:Off"), + MODE_GUI_BACKGROUND(false, 0f, 0f, 1f, 1f, "0:On, 1:Off"), + MODE_LEAVES(false,-1f, -1f, 4f,1f,"-1:Default, 0:Fancy, 1:Fast, 2: Smart, 3:Hybrid Fancy, 3:Hybrid Fast") { + @Override + public void updateSetting() { + SettingsManager.leavesUpdated(); + } + }, + MODE_SHADOWS(false, -1f,-1f,1f, 1f, "-1:Default, 0:On, 1:Off") { + @Override + public void updateSetting() { + SettingsManager.shadowsUpdated(); + } + }, + MODE_SKY(false,0f, 0f, 1f, 1f, "0:On, 1:Off"), + MODE_WATER(false, -1f,-1f,1f, 1f, "-1:Default, 0:Fancy, 1:Fast") { + @Override + public void updateSetting() { + SettingsManager.waterDetailUpdated(); + } + }, + MODE_VIGNETTE(false, -1f,-1f,1f, 1f, "-1:Default, 0:On, 1:Off") { + @Override + public void updateSetting() { + SettingsManager.vignetteUpdated(); + } + }, + PARTICLES_ENC_TABLE(true,1f, 0f, 16f, 1f), + PARTICLES_VOID(false,0f, 0f, 1f, 1f, "0:On, 1:Off"), + RENDER_DISTANCE_CLOUDS(true, 4f, 4f, 64f, 2f) { + @Override + public void updateSetting() { + SettingsManager.cloudsUpdated(); + } + }, + TOTAL_STARS(true, 1500f, 0f, 32000f, 500f) { + @Override + public void updateSetting() { + RenderStars.reloadStarRenderList(Minecraft.getMinecraft().renderGlobal); + } + }; + + public final boolean slider; + public final float base; + public final float minimum; + public final float maximum; + public final float step; + public final String configComment; + private float value; + + Settings(boolean slider, float base, float minimum, float maximum, float step, String configComment) { + this.slider = slider; + this.base = base; + this.minimum = minimum; + this.maximum = maximum; + this.step = step; + this.configComment = configComment; + value = base; + } + + Settings(boolean slider, float base, float minimum, float maximum, float step) { + this(slider, base, minimum, maximum, step, "Increments in steps of " + step); + } + + public void setValue(float value) { + value = MathHelper.clamp_float(value, minimum, maximum); + if(step > 0f) { + value = step * (float)Math.round(value / step); + } + if(this.value != value) { + this.value = value; + updateSetting(); + } + } + + public void setValueNormalized(float value) { + setValue(minimum + (maximum - minimum) * MathHelper.clamp_float(value, 0f, 1f)); + } + + public void incrementValue() { + value += step; + if(value > maximum) { + value = minimum; + } + updateSetting(); + } + + public float getValue() { + return value; + } + + public float getValueNormalized() { + return MathHelper.clamp_float((value - minimum) / (maximum - minimum), 0f, 1f); + } + + public boolean isValueBase() { + return value == base; + } + + public String getLocalization() { + String localized = I18n.format("options." + name().toLowerCase()) + ": "; + if(slider) { + if(step % 1f == 0f) { + localized += (int)value; + } else { + localized += value; + } + } else if(step == 1f && minimum == 0f && maximum == 1f) { + if(value == 0f) { + localized += I18n.format("options.on"); + } else { + localized += I18n.format("options.off"); + } + } else { + localized += I18n.format("options." + name().toLowerCase() + '.' + (int)value); + } + return localized; + } + + public void updateSetting() { + + } + +} diff --git a/src/main/java/jss/notfine/core/SettingsManager.java b/src/main/java/jss/notfine/core/SettingsManager.java new file mode 100644 index 000000000..3d9cc939e --- /dev/null +++ b/src/main/java/jss/notfine/core/SettingsManager.java @@ -0,0 +1,140 @@ +package jss.notfine.core; + +import jss.notfine.config.VideoSettingsConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.init.Blocks; +import net.minecraft.launchwrapper.Launch; +import net.minecraft.util.ResourceLocation; + +import java.io.File; + +public class SettingsManager { + + private static final Minecraft mc = Minecraft.getMinecraft(); + + public static VideoSettingsConfig settingsFile = new VideoSettingsConfig( + new File(Launch.minecraftHome + File.separator + "optionsGraphics.cfg") + ); + + public static int minimumFarPlaneDistance; + public static double cloudTranslucencyCheck; + public static boolean shadows; + public static boolean droppedItemDetail; + public static boolean leavesOpaque; + public static boolean waterDetail; + public static boolean vignette; + + public static ResourceLocation defaultBackground = Gui.optionsBackground; + public static ResourceLocation[] extraBackgrounds = new ResourceLocation[] { + new ResourceLocation("textures/blocks/sand.png"), + new ResourceLocation("textures/blocks/mycelium_top.png"), + new ResourceLocation("textures/blocks/stonebrick.png"), + new ResourceLocation("textures/blocks/stonebrick_mossy.png"), + new ResourceLocation("textures/blocks/planks_oak.png"), + new ResourceLocation("textures/blocks/planks_birch.png") + }; + + public static void backgroundUpdated() { + int value = (int)Settings.GUI_BACKGROUND.getValue(); + if(value < 0 | value >= extraBackgrounds.length) { + Gui.optionsBackground = defaultBackground; + } else { + Gui.optionsBackground = extraBackgrounds[(int)Settings.GUI_BACKGROUND.getValue()]; + } + } + + public static void cloudsUpdated() { + if(Settings.MODE_CLOUDS.getValue() != 2f) { + minimumFarPlaneDistance = (int)(32f * Settings.RENDER_DISTANCE_CLOUDS.getValue()); + minimumFarPlaneDistance += Math.abs(Settings.CLOUD_HEIGHT.getValue()); + mc.gameSettings.clouds = true; + } else { + minimumFarPlaneDistance = 128; + mc.gameSettings.clouds = false; + } + switch((int) Settings.MODE_CLOUD_TRANSLUCENCY.getValue()) { + case -1: + cloudTranslucencyCheck = Settings.CLOUD_HEIGHT.getValue(); + break; + case 0: + cloudTranslucencyCheck = Double.NEGATIVE_INFINITY; + break; + case 1: + cloudTranslucencyCheck = Double.POSITIVE_INFINITY; + break; + } + } + + public static void leavesUpdated() { + mc.renderGlobal.loadRenderers(); + leavesOpaque = Settings.MODE_LEAVES.getValue() == 1 || (Settings.MODE_LEAVES.getValue() == -1 && !mc.gameSettings.fancyGraphics); + Blocks.leaves.setGraphicsLevel(!leavesOpaque); + Blocks.leaves2.setGraphicsLevel(!leavesOpaque); + } + + public static void shadowsUpdated() { + switch((int)Settings.MODE_SHADOWS.getValue()) { + case -1: + shadows = mc.gameSettings.fancyGraphics; + break; + case 0: + shadows = true; + break; + case 1: + shadows = false; + break; + } + } + + public static void droppedItemDetailUpdated() { + switch((int)Settings.MODE_DROPPED_ITEMS.getValue()) { + case -1: + droppedItemDetail = mc.gameSettings.fancyGraphics; + break; + case 0: + droppedItemDetail = true; + break; + case 1: + droppedItemDetail = false; + break; + } + } + + public static void waterDetailUpdated() { + switch((int)Settings.MODE_DROPPED_ITEMS.getValue()) { + case -1: + waterDetail = mc.gameSettings.fancyGraphics; + break; + case 0: + waterDetail = true; + break; + case 1: + waterDetail = false; + break; + } + } + + public static void vignetteUpdated() { + switch((int)Settings.MODE_VIGNETTE.getValue()) { + case -1: + vignette = mc.gameSettings.fancyGraphics; + break; + case 0: + vignette = true; + break; + case 1: + vignette = false; + break; + } + } + + public static void graphicsUpdated() { + leavesUpdated(); + shadowsUpdated(); + droppedItemDetailUpdated(); + waterDetailUpdated(); + vignetteUpdated(); + } + +} diff --git a/src/main/java/jss/notfine/gui/GuiCustomMenu.java b/src/main/java/jss/notfine/gui/GuiCustomMenu.java new file mode 100644 index 000000000..70843b11a --- /dev/null +++ b/src/main/java/jss/notfine/gui/GuiCustomMenu.java @@ -0,0 +1,94 @@ +package jss.notfine.gui; + +import jss.notfine.core.SettingsManager; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiListExtended; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.resources.I18n; +import org.lwjgl.input.Keyboard; + +import java.awt.event.KeyListener; + +public class GuiCustomMenu extends GuiScreen { + private final GuiScreen parentGuiScreen; + private final MenuButtonLists buttonEnum; + protected String screenTitle; + + private GuiListExtended optionsRowList; + + public GuiCustomMenu(GuiScreen parentGuiScreen, MenuButtonLists buttonEnum) { + this.parentGuiScreen = parentGuiScreen; + this.screenTitle = buttonEnum.getTitleLabel(); + this.buttonEnum = buttonEnum; + } + + @Override + public void initGui() { + buttonList.clear(); + buttonList.add(new GuiButton(200, width / 2 - 100, height - 27, I18n.format("gui.done"))); + + optionsRowList = new GuiCustomSettingsRowList(mc, width, height, 32, height - 32, 25, buttonEnum); + } + + @Override + protected void actionPerformed(GuiButton button) { + if(button.enabled && button.id == 200) { + if(!(parentGuiScreen instanceof GuiCustomMenu)) { + saveSettings(); + } + mc.displayGuiScreen(parentGuiScreen); + } + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) { + int originalScale = mc.gameSettings.guiScale; + + super.mouseClicked(mouseX, mouseY, mouseButton); + optionsRowList.func_148179_a(mouseX, mouseY, mouseButton); + + if(mc.gameSettings.guiScale != originalScale) { + ScaledResolution scaledresolution = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); + setWorldAndResolution(mc, scaledresolution.getScaledWidth(), scaledresolution.getScaledHeight()); + } + } + + @Override + protected void mouseMovedOrUp(int mouseX, int mouseY, int state) { + int originalScale = mc.gameSettings.guiScale; + + super.mouseMovedOrUp(mouseX, mouseY, state); + optionsRowList.func_148181_b(mouseX, mouseY, state); + + if(mc.gameSettings.guiScale != originalScale) { + ScaledResolution scaledresolution = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); + setWorldAndResolution(mc, scaledresolution.getScaledWidth(), scaledresolution.getScaledHeight()); + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + if(mc.theWorld != null && Keyboard.isKeyDown(Keyboard.KEY_F1)) { + return; + } + drawDefaultBackground(); + optionsRowList.drawScreen(mouseX, mouseY, partialTicks); + drawCenteredString(fontRendererObj, screenTitle, width / 2, 5, 16777215); + super.drawScreen(mouseX, mouseY, partialTicks); + } + + @Override + protected void keyTyped(char typedChar, int keyCode) { + if(keyCode == Keyboard.KEY_ESCAPE) { + saveSettings(); + } + super.keyTyped(typedChar, keyCode); + } + + private void saveSettings() { + mc.gameSettings.saveOptions(); + SettingsManager.settingsFile.saveSettings(); + } + +} diff --git a/src/main/java/jss/notfine/gui/GuiCustomMenuButton.java b/src/main/java/jss/notfine/gui/GuiCustomMenuButton.java new file mode 100644 index 000000000..72eba0319 --- /dev/null +++ b/src/main/java/jss/notfine/gui/GuiCustomMenuButton.java @@ -0,0 +1,29 @@ +package jss.notfine.gui; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.resources.I18n; + +public class GuiCustomMenuButton extends GuiButton { + + private final MenuButtonLists linkedList; + + public GuiCustomMenuButton(int xPosition, int yPosition, int width, int height, MenuButtonLists list) { + super(-list.ordinal(), xPosition, yPosition, width, height, list.getButtonLabel()); + linkedList = list; + } + + public GuiCustomMenuButton(int xPosition, int yPosition, MenuButtonLists list) { + this(xPosition, yPosition, 150, 20, list); + } + + @Override + public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { + boolean load = super.mousePressed(mc, mouseX, mouseY); + if(load) { + mc.displayGuiScreen(new GuiCustomMenu(mc.currentScreen, linkedList)); + } + return load; + } + +} diff --git a/src/main/java/jss/notfine/gui/GuiCustomSettingButton.java b/src/main/java/jss/notfine/gui/GuiCustomSettingButton.java new file mode 100644 index 000000000..76dd904be --- /dev/null +++ b/src/main/java/jss/notfine/gui/GuiCustomSettingButton.java @@ -0,0 +1,27 @@ +package jss.notfine.gui; + +import jss.notfine.core.Settings; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; + +public class GuiCustomSettingButton extends GuiButton { + + private final Settings linkedSetting; + + public GuiCustomSettingButton(int xPosition, int yPosition, Settings setting) { + super(setting.ordinal(), xPosition, yPosition, 150, 20, setting.getLocalization()); + linkedSetting = setting; + } + + @Override + public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { + if(super.mousePressed(mc, mouseX, mouseY)) { + linkedSetting.incrementValue(); + displayString = linkedSetting.getLocalization(); + return true; + } else { + return false; + } + } + +} diff --git a/src/main/java/jss/notfine/gui/GuiCustomSettingSlider.java b/src/main/java/jss/notfine/gui/GuiCustomSettingSlider.java new file mode 100644 index 000000000..c712f8d75 --- /dev/null +++ b/src/main/java/jss/notfine/gui/GuiCustomSettingSlider.java @@ -0,0 +1,65 @@ +package jss.notfine.gui; + +import jss.notfine.core.Settings; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.util.MathHelper; +import org.lwjgl.opengl.GL11; + +public class GuiCustomSettingSlider extends GuiButton { + + private final Settings linkedSetting; + private float value; + public boolean mousePressed; + + public GuiCustomSettingSlider(int xPosition, int yPosition, Settings setting) { + super(setting.ordinal(), xPosition, yPosition, 150, 20, ""); + linkedSetting = setting; + value = setting.getValueNormalized(); + displayString = setting.getLocalization(); + } + + @Override + public int getHoverState(boolean mouseOver) { + return 0; + } + + @Override + protected void mouseDragged(Minecraft mc, int mouseX, int mouseY) { + if(visible) { + if(mousePressed) { + updateSlider(mouseX); + } + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)), yPosition, 0, 66, 4, 20); + drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)) + 4, yPosition, 196, 66, 4, 20); + } + } + + @Override + public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { + if(super.mousePressed(mc, mouseX, mouseY)) { + updateSlider(mouseX); + mousePressed = true; + return true; + } else { + return false; + } + } + + @Override + public void mouseReleased(int mouseX, int mouseY) { + mousePressed = false; + } + + private void updateSlider(int mouseX) { + value = (float)(mouseX - (xPosition + 4)) / (float)(width - 8); + value = MathHelper.clamp_float(value, 0f, 1f); + + linkedSetting.setValueNormalized(value); + value = linkedSetting.getValueNormalized(); + + displayString = linkedSetting.getLocalization(); + } + +} diff --git a/src/main/java/jss/notfine/gui/GuiCustomSettingsRowList.java b/src/main/java/jss/notfine/gui/GuiCustomSettingsRowList.java new file mode 100644 index 000000000..2c34c5c02 --- /dev/null +++ b/src/main/java/jss/notfine/gui/GuiCustomSettingsRowList.java @@ -0,0 +1,121 @@ +package jss.notfine.gui; + +import com.google.common.collect.Lists; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import jss.notfine.core.Settings; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiListExtended; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.settings.GameSettings; + +import java.util.List; + +@SideOnly(Side.CLIENT) +public class GuiCustomSettingsRowList extends GuiListExtended { + private final List settingsList = Lists.newArrayList(); + + public GuiCustomSettingsRowList(Minecraft mc, int width, int height, int top, int bottom, int slotHeight, MenuButtonLists buttonEnum) { + super(mc, width, height, top, bottom, slotHeight); + field_148163_i = false; + + Object[] settings = buttonEnum.entries(); + + for(int i = 0; i < settings.length; i += 2) { + Object settingOne = settings[i]; + Object settingTwo = i < settings.length - 1 ? settings[i + 1] : null; + GuiButton buttonOne = createButton(width / 2 - 155, 0, settingOne); + GuiButton buttonTwo = createButton(width / 2 - 155 + 160, 0, settingTwo); + settingsList.add(new Row(buttonOne, buttonTwo)); + } + } + + private GuiButton createButton(int xPosition, int yPosition, Object setting) { + if(setting instanceof Settings) { + Settings customSetting = (Settings)setting; + return customSetting.slider ? + new GuiCustomSettingSlider(xPosition, yPosition, customSetting) : + new GuiCustomSettingButton(xPosition, yPosition, customSetting); + } else if(setting instanceof GameSettings.Options) { + GameSettings.Options vanillaSetting = (GameSettings.Options)setting; + return vanillaSetting.getEnumFloat() ? + new GuiVanillaSettingSlider(xPosition, yPosition, vanillaSetting) : + new GuiVanillaSettingButton(xPosition, yPosition, vanillaSetting); + } else if(setting instanceof MenuButtonLists) { + MenuButtonLists menuType = (MenuButtonLists)setting; + return new GuiCustomMenuButton(xPosition, yPosition, menuType); + } + return null; + } + + @Override + public Row getListEntry(int index) { + return settingsList.get(index); + } + + @Override + protected int getSize() { + return settingsList.size(); + } + + @Override + public int getListWidth() { + return 400; + } + + @Override + protected int getScrollBarX() { + return super.getScrollBarX() + 32; + } + + @SideOnly(Side.CLIENT) + public static class Row implements IGuiListEntry { + private final Minecraft mc = Minecraft.getMinecraft(); + private final GuiButton buttonOne, buttonTwo; + + public Row(GuiButton one, GuiButton two) { + buttonOne = one; + buttonTwo = two; + + if(one != null && two == null) { + one.width += 160; + } + } + + @Override + public void drawEntry(int varU1, int x, int y, int varU2, int varU3, Tessellator tessellator, int mouseX, int mouseY, boolean varU4) { + if(buttonOne != null) { + buttonOne.yPosition = y; + buttonOne.drawButton(mc, mouseX, mouseY); + } + + if(buttonTwo != null) { + buttonTwo.yPosition = y; + buttonTwo.drawButton(mc, mouseX, mouseY); + } + } + + @Override + public boolean mousePressed(int index, int x, int y, int mouseEvent, int relativeX, int relativeY) { + if(buttonOne != null && buttonOne.mousePressed(mc, x, y)) { + return true; + } else if(buttonTwo != null && buttonTwo.mousePressed(mc, x, y)) { + return true; + } + return false; + } + + @Override + public void mouseReleased(int index, int x, int y, int mouseEvent, int relativeX, int relativeY) { + if(buttonOne != null) { + buttonOne.mouseReleased(x, y); + } + + if(buttonTwo != null) { + buttonTwo.mouseReleased(x, y); + } + } + } + +} diff --git a/src/main/java/jss/notfine/gui/GuiVanillaSettingButton.java b/src/main/java/jss/notfine/gui/GuiVanillaSettingButton.java new file mode 100644 index 000000000..3a160b6d3 --- /dev/null +++ b/src/main/java/jss/notfine/gui/GuiVanillaSettingButton.java @@ -0,0 +1,27 @@ +package jss.notfine.gui; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.settings.GameSettings; + +public class GuiVanillaSettingButton extends GuiButton { + + private final GameSettings.Options linkedSetting; + + public GuiVanillaSettingButton(int xPosition, int yPosition, GameSettings.Options setting) { + super(setting.ordinal(), xPosition, yPosition, 150, 20, Minecraft.getMinecraft().gameSettings.getKeyBinding(setting)); + linkedSetting = setting; + } + + @Override + public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { + if(super.mousePressed(mc, mouseX, mouseY)) { + mc.gameSettings.setOptionValue(linkedSetting, 1); + displayString = mc.gameSettings.getKeyBinding(linkedSetting); + return true; + } else { + return false; + } + } + +} diff --git a/src/main/java/jss/notfine/gui/GuiVanillaSettingSlider.java b/src/main/java/jss/notfine/gui/GuiVanillaSettingSlider.java new file mode 100644 index 000000000..112ca8ad6 --- /dev/null +++ b/src/main/java/jss/notfine/gui/GuiVanillaSettingSlider.java @@ -0,0 +1,68 @@ +package jss.notfine.gui; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.settings.GameSettings; +import net.minecraft.util.MathHelper; +import org.lwjgl.opengl.GL11; + +public class GuiVanillaSettingSlider extends GuiButton { + + private final GameSettings.Options linkedSetting; + private float value; + public boolean mousePressed; + + public GuiVanillaSettingSlider(int xPosition, int yPosition, GameSettings.Options setting) { + super(setting.ordinal(), xPosition, yPosition, 150, 20, ""); + linkedSetting = setting; + + Minecraft mc = Minecraft.getMinecraft(); + value = linkedSetting.normalizeValue(Minecraft.getMinecraft().gameSettings.getOptionFloatValue(linkedSetting)); + displayString = mc.gameSettings.getKeyBinding(setting); + } + + @Override + public int getHoverState(boolean mouseOver) { + return 0; + } + + @Override + protected void mouseDragged(Minecraft mc, int mouseX, int mouseY) { + if(visible) { + if(mousePressed) { + updateSlider(mc, mouseX); + } + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)), yPosition, 0, 66, 4, 20); + drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)) + 4, yPosition, 196, 66, 4, 20); + } + } + + @Override + public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { + if(super.mousePressed(mc, mouseX, mouseY)) { + updateSlider(mc, mouseX); + mousePressed = true; + return true; + } else { + return false; + } + } + + @Override + public void mouseReleased(int mouseX, int mouseY) { + mousePressed = false; + } + + private void updateSlider(Minecraft mc, int mouseX) { + value = (float)(mouseX - (xPosition + 4)) / (float)(width - 8); + value = MathHelper.clamp_float(value, 0f, 1f); + + value = linkedSetting.denormalizeValue(value); + mc.gameSettings.setOptionFloatValue(linkedSetting, value); + value = linkedSetting.normalizeValue(value); + + displayString = mc.gameSettings.getKeyBinding(linkedSetting); + } + +} diff --git a/src/main/java/jss/notfine/gui/MenuButtonLists.java b/src/main/java/jss/notfine/gui/MenuButtonLists.java new file mode 100644 index 000000000..f8e229e99 --- /dev/null +++ b/src/main/java/jss/notfine/gui/MenuButtonLists.java @@ -0,0 +1,102 @@ +package jss.notfine.gui; + +import jss.notfine.config.NotFineConfig; +import jss.notfine.core.Settings; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.settings.GameSettings; + +import java.util.ArrayList; + +public enum MenuButtonLists { + //list.add(); list.add(); + VIDEO("options.video") { + @Override + public Object[] entries() { + ArrayList list = new ArrayList<>(); + + list.add(GameSettings.Options.GRAPHICS); list.add(GameSettings.Options.RENDER_DISTANCE); + list.add(GameSettings.Options.ENABLE_VSYNC); list.add(GameSettings.Options.USE_FULLSCREEN); + list.add(GameSettings.Options.FRAMERATE_LIMIT); list.add(null); + list.add(GameSettings.Options.GUI_SCALE); list.add(GameSettings.Options.VIEW_BOBBING); + list.add(GameSettings.Options.AMBIENT_OCCLUSION); list.add(GameSettings.Options.GAMMA); + list.add(GameSettings.Options.ANISOTROPIC_FILTERING); list.add(GameSettings.Options.MIPMAP_LEVELS); + + list.add(DETAIL); list.add(SKY); + list.add(PARTICLE); list.add(OTHER); + + return list.toArray(); + } + }, + DETAIL("options.button.detail") { + @Override + public Object[] entries() { + ArrayList list = new ArrayList<>(); + + list.add(Settings.MODE_LEAVES); list.add(Settings.MODE_WATER); + list.add(Settings.MODE_SHADOWS); list.add(Settings.MODE_VIGNETTE); + list.add(Settings.MODE_DROPPED_ITEMS); list.add(Settings.MODE_GLINT_WORLD); + list.add(Settings.MODE_GLINT_INV); + + return list.toArray(); + } + }, + SKY("options.button.sky") { + @Override + public Object[] entries() { + ArrayList list = new ArrayList<>(); + + list.add(Settings.MODE_SKY); list.add(Settings.MODE_CLOUDS); + list.add(Settings.RENDER_DISTANCE_CLOUDS); list.add(Settings.CLOUD_HEIGHT); + list.add(Settings.CLOUD_SCALE); list.add(Settings.MODE_CLOUD_TRANSLUCENCY); + list.add(Settings.TOTAL_STARS); + + return list.toArray(); + } + }, + PARTICLE("options.button.particle") { + @Override + public Object[] entries() { + ArrayList list = new ArrayList<>(); + + list.add(GameSettings.Options.PARTICLES); list.add(Settings.PARTICLES_VOID); + list.add(Settings.PARTICLES_ENC_TABLE); + + return list.toArray(); + } + }, + OTHER("options.button.other") { + @Override + public Object[] entries() { + ArrayList list = new ArrayList<>(); + if(OpenGlHelper.field_153197_d && NotFineConfig.allowAdvancedOpenGL) { + list.add(GameSettings.Options.ADVANCED_OPENGL); + } else { + list.add(null); + } + list.add(GameSettings.Options.ANAGLYPH); + list.add(Settings.MODE_GUI_BACKGROUND); list.add(GameSettings.Options.SHOW_CAPE); + list.add(null); list.add(GameSettings.Options.FBO_ENABLE); + list.add(Settings.GUI_BACKGROUND); + + return list.toArray(); + } + }; + + private final String unlocalizedButton; + + MenuButtonLists(String button) { + unlocalizedButton = button; + } + + public final String getButtonLabel() { + return I18n.format(unlocalizedButton); + } + + public final String getTitleLabel() { + return I18n.format("options.title." + name().toLowerCase()); + } + + public abstract Object[] entries(); + +} diff --git a/src/main/java/jss/notfine/mixinplugin/NotFineEarlyMixins.java b/src/main/java/jss/notfine/mixinplugin/NotFineEarlyMixins.java new file mode 100644 index 000000000..603857c67 --- /dev/null +++ b/src/main/java/jss/notfine/mixinplugin/NotFineEarlyMixins.java @@ -0,0 +1,83 @@ +package jss.notfine.mixinplugin; + +import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader; +import cpw.mods.fml.relauncher.IFMLLoadingPlugin; +import jss.notfine.NotFine; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@IFMLLoadingPlugin.Name("NotFineEarlyMixins") +@IFMLLoadingPlugin.MCVersion("1.7.10") +public class NotFineEarlyMixins implements IFMLLoadingPlugin, IEarlyMixinLoader { + + @Override + public String getMixinConfig() { + return "mixins.notfine.early.json"; + } + + @Override + public List getMixins(Set loadedCoreMods) { + NotFine.logger.info("Kicking off NotFine early mixins."); + + List mixins = new ArrayList<>(); + + mixins.add("minecraft.clouds.MixinEntityRenderer"); + mixins.add("minecraft.clouds.MixinGameSettings"); + mixins.add("minecraft.clouds.MixinRenderGlobal"); + mixins.add("minecraft.clouds.MixinWorldType"); + + mixins.add("minecraft.glint.MixinItemRenderer"); + mixins.add("minecraft.glint.MixinRenderBiped"); + mixins.add("minecraft.glint.MixinRenderItem"); + mixins.add("minecraft.glint.MixinRenderPlayer"); + + mixins.add("minecraft.gui.MixinGuiSlot"); + + mixins.add("minecraft.leaves.MixinBlockLeaves"); + mixins.add("minecraft.leaves.MixinBlockLeavesBase"); + + mixins.add("minecraft.particles.MixinBlockEnchantmentTable"); + mixins.add("minecraft.particles.MixinEffectRenderer"); + mixins.add("minecraft.particles.MixinWorldClient"); + mixins.add("minecraft.particles.MixinWorldProvider"); + + mixins.add("minecraft.toggle.MixinGuiIngame"); + mixins.add("minecraft.toggle.MixinEntityRenderer"); + mixins.add("minecraft.toggle.MixinRender"); + mixins.add("minecraft.toggle.MixinRenderItem"); + + mixins.add("minecraft.MixinGameSettings"); + mixins.add("minecraft.MixinRenderGlobal"); + + return mixins; + } + + @Override + public String[] getASMTransformerClass() { + return null; + } + + @Override + public String getModContainerClass() { + return null; + } + + @Override + public String getSetupClass() { + return null; + } + + @Override + public void injectData(Map data) { + + } + + @Override + public String getAccessTransformerClass() { + return null; + } + +} diff --git a/src/main/java/jss/notfine/mixinplugin/NotFineLateMixins.java b/src/main/java/jss/notfine/mixinplugin/NotFineLateMixins.java new file mode 100644 index 000000000..e1c096c74 --- /dev/null +++ b/src/main/java/jss/notfine/mixinplugin/NotFineLateMixins.java @@ -0,0 +1,59 @@ +package jss.notfine.mixinplugin; + +import com.gtnewhorizon.gtnhmixins.ILateMixinLoader; +import com.gtnewhorizon.gtnhmixins.LateMixin; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.versioning.ArtifactVersion; +import cpw.mods.fml.common.versioning.DefaultArtifactVersion; +import cpw.mods.fml.common.versioning.InvalidVersionSpecificationException; +import cpw.mods.fml.common.versioning.VersionRange; +import jss.notfine.NotFine; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@LateMixin +public class NotFineLateMixins implements ILateMixinLoader { + + @Override + public String getMixinConfig() { + return "mixins.notfine.late.json"; + } + + @Override + public List getMixins(Set loadedMods) { + NotFine.logger.info("Kicking off NotFine late mixins."); + + List mixins = new ArrayList<>(); + + if(loadedMods.contains("Thaumcraft")) { + mixins.add("thaumcraft.leaves.MixinBlockMagicalLeaves"); + } + + if(loadedMods.contains("TwilightForest")) { + mixins.add("twilightforest.leaves.MixinBlockTFLeaves"); + mixins.add("twilightforest.leaves.MixinBlockTFLeaves3"); + + //Non-GTNH Twilight Forest builds will break horribly with this mixin. + boolean modernBuild = false; + try { + ArtifactVersion accepted = new DefaultArtifactVersion("TwilightForest", VersionRange.createFromVersionSpec("[2.3.8.18,)")); + ModContainer mc = Loader.instance().getIndexedModList().get("TwilightForest"); + if(mc != null) modernBuild = accepted.containsVersion(mc.getProcessedVersion()); + } catch (InvalidVersionSpecificationException ignored) { + } + if(modernBuild) { + mixins.add("twilightforest.leaves.MixinBlockTFMagicLeaves"); + } + } + + if(loadedMods.contains("witchery")) { + mixins.add("witchery.leaves.MixinBlockWitchLeaves"); + } + + return mixins; + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/MixinGameSettings.java b/src/main/java/jss/notfine/mixins/early/minecraft/MixinGameSettings.java new file mode 100644 index 000000000..676f6e99c --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/MixinGameSettings.java @@ -0,0 +1,251 @@ +package jss.notfine.mixins.early.minecraft; + +import jss.notfine.core.SettingsManager; +import net.minecraft.client.Minecraft; +import net.minecraft.client.settings.GameSettings; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.EnumDifficulty; +import org.lwjgl.opengl.Display; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(value = GameSettings.class, priority = 990) +public abstract class MixinGameSettings { + + @Final + private static String[] GUISCALES = new String[] { + "options.guiScale.auto", + "options.guiScale.small", + "options.guiScale.normal", + "options.guiScale.large", + "options.guiScale.massive" + }; + + /** + * @author jss2a98aj + * @reason Makes this function not unreasonably slow. + */ + @Overwrite + public void setOptionFloatValue(GameSettings.Options option, float value) { + switch(option) { + case SENSITIVITY: + mouseSensitivity = value; + break; + case FOV: + fovSetting = value; + break; + case GAMMA: + gammaSetting = value; + break; + case FRAMERATE_LIMIT: + limitFramerate = (int) value; + break; + case CHAT_OPACITY: + chatOpacity = value; + mc.ingameGUI.getChatGUI().refreshChat(); + break; + case CHAT_HEIGHT_FOCUSED: + chatHeightFocused = value; + mc.ingameGUI.getChatGUI().refreshChat(); + break; + case CHAT_HEIGHT_UNFOCUSED: + chatHeightUnfocused = value; + mc.ingameGUI.getChatGUI().refreshChat(); + break; + case CHAT_WIDTH: + chatWidth = value; + mc.ingameGUI.getChatGUI().refreshChat(); + break; + case CHAT_SCALE: + chatScale = value; + mc.ingameGUI.getChatGUI().refreshChat(); + break; + case ANISOTROPIC_FILTERING: + if(anisotropicFiltering != (int) value) { + anisotropicFiltering = (int) value; + mc.getTextureMapBlocks().setAnisotropicFiltering(this.anisotropicFiltering); + mc.scheduleResourcesRefresh(); + } + break; + case MIPMAP_LEVELS: + if(mipmapLevels != (int) value) { + mipmapLevels = (int) value; + mc.getTextureMapBlocks().setMipmapLevels(this.mipmapLevels); + mc.scheduleResourcesRefresh(); + } + break; + case RENDER_DISTANCE: + renderDistanceChunks = (int) value; + break; + case STREAM_BYTES_PER_PIXEL: + field_152400_J = value; + break; + case STREAM_VOLUME_MIC: + field_152401_K = value; + mc.func_152346_Z().func_152915_s(); + break; + case STREAM_VOLUME_SYSTEM: + field_152402_L = value; + mc.func_152346_Z().func_152915_s(); + break; + case STREAM_KBPS: + field_152403_M = value; + break; + case STREAM_FPS: + field_152404_N = value; + break; + } + } + + /** + * @author jss2a98aj + * @reason Makes this function not unreasonably slow. + */ + @Overwrite + public void setOptionValue(GameSettings.Options option, int value) { + switch(option) { + case INVERT_MOUSE: + invertMouse = !invertMouse; + break; + case GUI_SCALE: + guiScale = (guiScale + value) % 5; + break; + case PARTICLES: + particleSetting = (particleSetting + value) % 3; + break; + case VIEW_BOBBING: + viewBobbing = !viewBobbing; + break; + case RENDER_CLOUDS: + clouds = !clouds; + break; + case FORCE_UNICODE_FONT: + forceUnicodeFont = !forceUnicodeFont; + mc.fontRenderer.setUnicodeFlag(mc.getLanguageManager().isCurrentLocaleUnicode() || forceUnicodeFont); + break; + case ADVANCED_OPENGL: + advancedOpengl = !advancedOpengl; + mc.renderGlobal.loadRenderers(); + case FBO_ENABLE: + fboEnable = !fboEnable; + break; + case ANAGLYPH: + anaglyph = !anaglyph; + //refreshResources was overkill. + mc.renderGlobal.loadRenderers(); + break; + case DIFFICULTY: + difficulty = EnumDifficulty.getDifficultyEnum(difficulty.getDifficultyId() + value & 3); + break; + case GRAPHICS: + fancyGraphics = !fancyGraphics; + SettingsManager.graphicsUpdated(); + mc.renderGlobal.loadRenderers(); + break; + case AMBIENT_OCCLUSION: + ambientOcclusion = (ambientOcclusion + value) % 3; + mc.renderGlobal.loadRenderers(); + break; + case CHAT_VISIBILITY: + chatVisibility = EntityPlayer.EnumChatVisibility.getEnumChatVisibility((chatVisibility.getChatVisibility() + value) % 3); + break; + case STREAM_COMPRESSION: + field_152405_O = (field_152405_O + value) % 3; + break; + case STREAM_SEND_METADATA: + field_152406_P = !field_152406_P; + break; + case STREAM_CHAT_ENABLED: + field_152408_R = (field_152408_R + value) % 3; + break; + case STREAM_CHAT_USER_FILTER: + field_152409_S = (field_152409_S + value) % 3; + break; + case STREAM_MIC_TOGGLE_BEHAVIOR: + field_152410_T = (field_152410_T + value) % 2; + break; + case CHAT_COLOR: + chatColours = !chatColours; + break; + case CHAT_LINKS: + chatLinks = !chatLinks; + break; + case CHAT_LINKS_PROMPT: + chatLinksPrompt = !chatLinksPrompt; + break; + case SNOOPER_ENABLED: + snooperEnabled = !snooperEnabled; + break; + case SHOW_CAPE: + showCape = !showCape; + break; + case TOUCHSCREEN: + touchscreen = !touchscreen; + break; + case USE_FULLSCREEN: + fullScreen = !fullScreen; + if (mc.isFullScreen() != fullScreen) { + mc.toggleFullscreen(); + } + break; + case ENABLE_VSYNC: + enableVsync = !enableVsync; + Display.setVSyncEnabled(enableVsync); + break; + } + saveOptions(); + } + + @Shadow + public void saveOptions() { + } + + @Shadow protected Minecraft mc; + + @Shadow public float mouseSensitivity; + @Shadow public boolean invertMouse; + @Shadow public float fovSetting; + @Shadow public float gammaSetting; + @Shadow public int renderDistanceChunks; + @Shadow public int guiScale; + @Shadow public int particleSetting; + @Shadow public boolean viewBobbing; + @Shadow public boolean anaglyph; + @Shadow public boolean advancedOpengl; + @Shadow public int limitFramerate; + @Shadow public boolean fboEnable; + @Shadow public EnumDifficulty difficulty; + @Shadow public boolean fancyGraphics; + @Shadow public int ambientOcclusion; + @Shadow public boolean clouds; + @Shadow public EntityPlayer.EnumChatVisibility chatVisibility; + @Shadow public boolean chatColours; + @Shadow public boolean chatLinks; + @Shadow public boolean chatLinksPrompt; + @Shadow public float chatOpacity; + @Shadow public boolean snooperEnabled; + @Shadow public boolean fullScreen; + @Shadow public boolean enableVsync; + @Shadow public boolean showCape; + @Shadow public boolean touchscreen; + @Shadow public float chatHeightFocused; + @Shadow public float chatHeightUnfocused; + @Shadow public float chatScale; + @Shadow public float chatWidth; + @Shadow public int mipmapLevels; + @Shadow public int anisotropicFiltering; + @Shadow public float field_152400_J; + @Shadow public float field_152401_K; + @Shadow public float field_152402_L; + @Shadow public float field_152403_M; + @Shadow public float field_152404_N; + @Shadow public int field_152405_O; + @Shadow public boolean field_152406_P; + @Shadow public int field_152408_R; + @Shadow public int field_152409_S; + @Shadow public int field_152410_T; + @Shadow public boolean forceUnicodeFont; + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/MixinRenderGlobal.java b/src/main/java/jss/notfine/mixins/early/minecraft/MixinRenderGlobal.java new file mode 100644 index 000000000..b882e9fa1 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/MixinRenderGlobal.java @@ -0,0 +1,29 @@ +package jss.notfine.mixins.early.minecraft; + +import jss.notfine.core.Settings; +import jss.notfine.render.RenderStars; +import net.minecraft.client.renderer.RenderGlobal; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(RenderGlobal.class) +public abstract class MixinRenderGlobal { + + @Inject(method = "renderSky", at = @At("HEAD"), cancellable = true) + void notFine$toggleSky(CallbackInfo ci) { + if(!Settings.MODE_SKY.isValueBase()) ci.cancel(); + } + + /** + * @author jss2a98aj + * @reason Control star generation. + */ + @Overwrite + private void renderStars() { + RenderStars.renderStars(); + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinEntityRenderer.java b/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinEntityRenderer.java new file mode 100644 index 000000000..7f04ab5fb --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinEntityRenderer.java @@ -0,0 +1,24 @@ +package jss.notfine.mixins.early.minecraft.clouds; + +import jss.notfine.core.SettingsManager; +import net.minecraft.client.renderer.EntityRenderer; +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.ModifyArg; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(value = EntityRenderer.class, priority = 990) +public abstract class MixinEntityRenderer { + + @ModifyConstant(method = "renderWorld", constant = @Constant(doubleValue = 128.0D), expect = 2) + double notFine$modifyCloudHeightCheck(double original) { + return SettingsManager.cloudTranslucencyCheck; + } + + @ModifyArg(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false), index = 3) + private float notFine$modifyFarPlane(float original) { + return Math.max(original, SettingsManager.minimumFarPlaneDistance); + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinGameSettings.java b/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinGameSettings.java new file mode 100644 index 000000000..d33bcc128 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinGameSettings.java @@ -0,0 +1,22 @@ +package jss.notfine.mixins.early.minecraft.clouds; + +import net.minecraft.client.settings.GameSettings; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(value = GameSettings.class) +public abstract class MixinGameSettings { + + /** + * @author jss2a98aj + * @reason Make clouds render at any render distance. + */ + @Overwrite + public boolean shouldRenderClouds() { + return clouds; + } + + @Shadow public boolean clouds; + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinRenderGlobal.java b/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinRenderGlobal.java new file mode 100644 index 000000000..ea3e4f925 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinRenderGlobal.java @@ -0,0 +1,255 @@ +package jss.notfine.mixins.early.minecraft.clouds; + +import jss.notfine.core.Settings; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.util.MathHelper; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Vec3; +import net.minecraftforge.client.IRenderHandler; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(RenderGlobal.class) +public abstract class MixinRenderGlobal { + + /** + * @author jss2a98aj + * @reason Adjust how cloud render mode is selected. + */ + @Overwrite + public void renderClouds(float partialTicks) { + IRenderHandler renderer; + if((renderer = theWorld.provider.getCloudRenderer()) != null) { + renderer.render(partialTicks, theWorld, mc); + return; + } + if(mc.theWorld.provider.isSurfaceWorld()) { + int cloudMode = (int)Settings.MODE_CLOUDS.getValue(); + if(cloudMode == 0 || cloudMode == -1 && mc.gameSettings.fancyGraphics) { + renderCloudsFancy(partialTicks); + } else { + renderCloudsFast(partialTicks); + } + } + } + + /** + * @author jss2a98aj + * @reason Adjust fancy cloud render. + */ + @Overwrite + public void renderCloudsFancy(float partialTicks) { + Tessellator tessellator = Tessellator.instance; + GL11.glDisable(GL11.GL_CULL_FACE); + GL11.glEnable(GL11.GL_BLEND); + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + renderEngine.bindTexture(locationCloudsPng); + + Vec3 color = theWorld.getCloudColour(partialTicks); + float red = (float)color.xCoord; + float green = (float)color.yCoord; + float blue = (float)color.zCoord; + if(mc.gameSettings.anaglyph) { + float altRed = (red * 30.0F + green * 59.0F + blue * 11.0F) / 100.0F; + float altGreen = (red * 30.0F + green * 70.0F) / 100.0F; + float altBlue = (red * 30.0F + blue * 70.0F) / 100.0F; + red = altRed; + green = altGreen; + blue = altBlue; + } + double cloudTick = ((float)cloudTickCounter + partialTicks); + + float cloudScale = Settings.CLOUD_SCALE.getValue(); + float cloudInteriorWidth = 12.0F * cloudScale; + float cloudInteriorHeight = 4.0F * cloudScale; + float cameraOffsetY = (float)(mc.renderViewEntity.lastTickPosY + (mc.renderViewEntity.posY - mc.renderViewEntity.lastTickPosY) * (double)partialTicks); + double cameraOffsetX = (mc.renderViewEntity.prevPosX + (mc.renderViewEntity.posX - mc.renderViewEntity.prevPosX) * (double)partialTicks + cloudTick * 0.03D) / (double)cloudInteriorWidth; + double cameraOffsetZ = (mc.renderViewEntity.prevPosZ + (mc.renderViewEntity.posZ - mc.renderViewEntity.prevPosZ) * (double)partialTicks) / (double)cloudInteriorWidth + 0.33D; + cameraOffsetX -= MathHelper.floor_double(cameraOffsetX / 2048.0D) * 2048; + cameraOffsetZ -= MathHelper.floor_double(cameraOffsetZ / 2048.0D) * 2048; + + float cameraRelativeY = theWorld.provider.getCloudHeight() - cameraOffsetY + 0.33F; + float cameraRelativeX = (float)(cameraOffsetX - (double)MathHelper.floor_double(cameraOffsetX)); + float cameraRelativeZ = (float)(cameraOffsetZ - (double)MathHelper.floor_double(cameraOffsetZ)); + + float scrollSpeed = 0.00390625F; + float cloudScrollingX = (float)MathHelper.floor_double(cameraOffsetX) * scrollSpeed; + float cloudScrollingZ = (float)MathHelper.floor_double(cameraOffsetZ) * scrollSpeed; + + float cloudWidth = 8f; + int renderRadius = (int)(Settings.RENDER_DISTANCE_CLOUDS.getValue() / (cloudScale * 2f)); + float edgeOverlap = 0.0001f;//0.001F; + GL11.glScalef(cloudInteriorWidth, 1.0F, cloudInteriorWidth); + + for (int loop = 0; loop < 2; ++loop) { + if (loop == 0) { + GL11.glColorMask(false, false, false, false); + } else if (mc.gameSettings.anaglyph) { + if (EntityRenderer.anaglyphField == 0) { + GL11.glColorMask(false, true, true, true); + } else { + GL11.glColorMask(true, false, false, true); + } + } else { + GL11.glColorMask(true, true, true, true); + } + + for(int chunkX = -renderRadius + 1; chunkX <= renderRadius; ++chunkX) { + for(int chunkZ = -renderRadius + 1; chunkZ <= renderRadius; ++chunkZ) { + tessellator.startDrawingQuads(); + float chunkOffsetX = (chunkX * cloudWidth); + float chunkOffsetZ = (chunkZ * cloudWidth); + float startX = chunkOffsetX - cameraRelativeX; + float startZ = chunkOffsetZ - cameraRelativeZ; + + //Cloud top + if(cameraRelativeY > -cloudInteriorHeight - 1.0F) { + tessellator.setColorRGBA_F(red * 0.7F, green * 0.7F, blue * 0.7F, 0.8F); + tessellator.setNormal(0.0F, -1.0F, 0.0F); + tessellator.addVertexWithUV(startX, cameraRelativeY, (startZ + cloudWidth), (chunkOffsetX * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + cloudWidth) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV((startX + cloudWidth), cameraRelativeY, (startZ + cloudWidth), ((chunkOffsetX + cloudWidth) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + cloudWidth) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV((startX + cloudWidth), cameraRelativeY, startZ, ((chunkOffsetX + cloudWidth) * scrollSpeed + cloudScrollingX), (chunkOffsetZ * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV(startX, cameraRelativeY, startZ, (chunkOffsetX * scrollSpeed + cloudScrollingX), (chunkOffsetZ * scrollSpeed + cloudScrollingZ)); + } + //Cloud bottom + if(cameraRelativeY <= cloudInteriorHeight + 1.0F) { + tessellator.setColorRGBA_F(red, green, blue, 0.8F); + tessellator.setNormal(0.0F, 1.0F, 0.0F); + tessellator.addVertexWithUV(startX, (cameraRelativeY + cloudInteriorHeight - edgeOverlap), (startZ + cloudWidth), ((chunkOffsetX) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + cloudWidth) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV((startX + cloudWidth), (cameraRelativeY + cloudInteriorHeight - edgeOverlap), (startZ + cloudWidth), ((chunkOffsetX + cloudWidth) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + cloudWidth) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV((startX + cloudWidth), (cameraRelativeY + cloudInteriorHeight - edgeOverlap), startZ, ((chunkOffsetX + cloudWidth) * scrollSpeed + cloudScrollingX), (chunkOffsetZ * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV(startX, (cameraRelativeY + cloudInteriorHeight - edgeOverlap), startZ, (chunkOffsetX * scrollSpeed + cloudScrollingX), (chunkOffsetZ * scrollSpeed + cloudScrollingZ)); + } + + tessellator.setColorRGBA_F(red * 0.9F, green * 0.9F, blue * 0.9F, 0.8F); + if(Math.abs(chunkX) < 6 && Math.abs(chunkZ) < 6) { + float chunk; + + if (chunkX > -1) { + tessellator.setNormal(-1.0F, 0.0F, 0.0F); + for (chunk = 0f; chunk < cloudWidth; ++chunk) { + double x = startX + chunk; + tessellator.addVertexWithUV(x, cameraRelativeY, (startZ + cloudWidth), ((chunkOffsetX + chunk + 0.5F) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + cloudWidth) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV(x, (cameraRelativeY + cloudInteriorHeight), (startZ + cloudWidth), ((chunkOffsetX + chunk + 0.5F) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + cloudWidth) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV(x, (cameraRelativeY + cloudInteriorHeight), startZ, ((chunkOffsetX + chunk + 0.5F) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV(x, cameraRelativeY, startZ, ((chunkOffsetX + chunk + 0.5F) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ) * scrollSpeed + cloudScrollingZ)); + } + } + + if (chunkX <= 1) { + tessellator.setNormal(1.0F, 0.0F, 0.0F); + for (chunk = 0f; chunk < cloudWidth; ++chunk) { + double x = startX + chunk + 1.0F - edgeOverlap; + tessellator.addVertexWithUV(x, cameraRelativeY, (startZ + cloudWidth), ((chunkOffsetX + chunk + 0.5F) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + cloudWidth) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV(x, (cameraRelativeY + cloudInteriorHeight), (startZ + cloudWidth), ((chunkOffsetX + chunk + 0.5F) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + cloudWidth) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV(x, (cameraRelativeY + cloudInteriorHeight), startZ, ((chunkOffsetX + chunk + 0.5F) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV(x, cameraRelativeY, startZ, ((chunkOffsetX + chunk + 0.5F) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ) * scrollSpeed + cloudScrollingZ)); + } + } + + tessellator.setColorRGBA_F(red * 0.8F, green * 0.8F, blue * 0.8F, 0.8F); + + if (chunkZ > -1) { + tessellator.setNormal(0.0F, 0.0F, -1.0F); + for (chunk = 0f; chunk < cloudWidth; ++chunk) { + tessellator.addVertexWithUV(startX, (cameraRelativeY + cloudInteriorHeight), (startZ + chunk), ((chunkOffsetX) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + chunk + 0.5F) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV((startX + cloudWidth), (cameraRelativeY + cloudInteriorHeight), (startZ + chunk), ((chunkOffsetX + cloudWidth) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + chunk + 0.5F) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV((startX + cloudWidth), (cameraRelativeY), (startZ + chunk), ((chunkOffsetX + cloudWidth) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + chunk + 0.5F) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV(startX, (cameraRelativeY), (startZ + chunk), ((chunkOffsetX) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + chunk + 0.5F) * scrollSpeed + cloudScrollingZ)); + } + } + + if (chunkZ <= 1) { + tessellator.setNormal(0.0F, 0.0F, 1.0F); + for (chunk = 0f; chunk < cloudWidth; ++chunk) { + tessellator.addVertexWithUV(startX, (cameraRelativeY + cloudInteriorHeight), (startZ + chunk + 1.0F - edgeOverlap), (chunkOffsetX * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + chunk + 0.5F) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV((startX + cloudWidth), (cameraRelativeY + cloudInteriorHeight), (startZ + chunk + 1.0F - edgeOverlap), ((chunkOffsetX + cloudWidth) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + chunk + 0.5F) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV((startX + cloudWidth), cameraRelativeY, (startZ + chunk + 1.0F - edgeOverlap), ((chunkOffsetX + cloudWidth) * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + chunk + 0.5F) * scrollSpeed + cloudScrollingZ)); + tessellator.addVertexWithUV(startX, (cameraRelativeY), (startZ + chunk + 1.0F - edgeOverlap), (chunkOffsetX * scrollSpeed + cloudScrollingX), ((chunkOffsetZ + chunk + 0.5F) * scrollSpeed + cloudScrollingZ)); + } + } + } + tessellator.draw(); + } + } + } + + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glDisable(GL11.GL_BLEND); + GL11.glEnable(GL11.GL_CULL_FACE); + } + + public void renderCloudsFast(float partialTicks) { + Tessellator tessellator = Tessellator.instance; + GL11.glDisable(GL11.GL_CULL_FACE); + GL11.glEnable(GL11.GL_BLEND); + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + renderEngine.bindTexture(locationCloudsPng); + + Vec3 color = theWorld.getCloudColour(partialTicks); + float red = (float)color.xCoord; + float green = (float)color.yCoord; + float blue = (float)color.zCoord; + if (mc.gameSettings.anaglyph) { + float altRed = (red * 30.0F + green * 59.0F + blue * 11.0F) / 100.0F; + float altGreen = (red * 30.0F + green * 70.0F) / 100.0F; + float altBlue = (red * 30.0F + blue * 70.0F) / 100.0F; + red = altRed; + green = altGreen; + blue = altBlue; + } + double cloudTick = ((float)cloudTickCounter + partialTicks); + + float cameraOffsetY = (float)(mc.renderViewEntity.lastTickPosY + (mc.renderViewEntity.posY - mc.renderViewEntity.lastTickPosY) * (double)partialTicks); + double cameraOffsetX = mc.renderViewEntity.prevPosX + (mc.renderViewEntity.posX - mc.renderViewEntity.prevPosX) * (double)partialTicks + cloudTick * 0.029999999329447746D; + double cameraOffsetZ = mc.renderViewEntity.prevPosZ + (mc.renderViewEntity.posZ - mc.renderViewEntity.prevPosZ) * (double)partialTicks; + cameraOffsetX -= MathHelper.floor_double(cameraOffsetX / 2048.0D) * 2048; + cameraOffsetZ -= MathHelper.floor_double(cameraOffsetZ / 2048.0D) * 2048; + + float renderRadius = 32 * Settings.RENDER_DISTANCE_CLOUDS.getValue(); + double uvScale = 0.0005D / Settings.CLOUD_SCALE.getValue(); + + float uvShiftX = (float)(cameraOffsetX * uvScale); + float uvShiftZ = (float)(cameraOffsetZ * uvScale); + + double cameraRelativeY = theWorld.provider.getCloudHeight() - cameraOffsetY + 0.33F; + double neg = -renderRadius; + double pos = renderRadius; + + double startXUv = neg * uvScale + uvShiftX; + double startZUv = neg * uvScale + uvShiftZ; + double movedXUv = pos * uvScale + uvShiftX; + double movedZUv = pos * uvScale + uvShiftZ; + + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_F(red, green, blue, 0.8F); + tessellator.addVertexWithUV(neg, cameraRelativeY, pos, startXUv, movedZUv); + tessellator.addVertexWithUV(pos, cameraRelativeY, pos, movedXUv, movedZUv); + tessellator.addVertexWithUV(pos, cameraRelativeY, neg, movedXUv, startZUv); + tessellator.addVertexWithUV(neg, cameraRelativeY, neg, startXUv, startZUv); + tessellator.draw(); + + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glDisable(GL11.GL_BLEND); + GL11.glEnable(GL11.GL_CULL_FACE); + } + + @Shadow @Final + private static ResourceLocation locationCloudsPng; + @Shadow @Final + private TextureManager renderEngine; + + @Shadow private WorldClient theWorld; + @Shadow private Minecraft mc; + @Shadow private int cloudTickCounter; + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinWorldType.java b/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinWorldType.java new file mode 100644 index 000000000..010dfc95b --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinWorldType.java @@ -0,0 +1,20 @@ +package jss.notfine.mixins.early.minecraft.clouds; + +import jss.notfine.core.Settings; +import net.minecraft.world.WorldType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(value = WorldType.class) +public abstract class MixinWorldType { + + /** + * @author jss2a98aj + * @reason Control cloud height. + */ + @Overwrite(remap = false) + public float getCloudHeight() { + return Settings.CLOUD_HEIGHT.getValue(); + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinItemRenderer.java b/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinItemRenderer.java new file mode 100644 index 000000000..c6183e93d --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinItemRenderer.java @@ -0,0 +1,25 @@ +package jss.notfine.mixins.early.minecraft.glint; + +import jss.notfine.core.Settings; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = ItemRenderer.class) +public abstract class MixinItemRenderer { + + @Redirect( + method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/item/ItemStack;hasEffect(I)Z" + ), + remap = false + ) + private boolean notFine$toggleGlint(ItemStack stack, int pass) { + return Settings.MODE_GLINT_WORLD.isValueBase() && stack.hasEffect(pass); + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderBiped.java b/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderBiped.java new file mode 100644 index 000000000..e68d4a230 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderBiped.java @@ -0,0 +1,24 @@ +package jss.notfine.mixins.early.minecraft.glint; + +import jss.notfine.core.Settings; +import net.minecraft.client.renderer.entity.RenderBiped; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = RenderBiped.class) +public abstract class MixinRenderBiped { + + @Redirect( + method = "shouldRenderPass(Lnet/minecraft/entity/EntityLiving;IF)I", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/item/ItemStack;isItemEnchanted()Z" + ) + ) + private boolean notFine$toggleGlint(ItemStack stack) { + return Settings.MODE_GLINT_WORLD.isValueBase() && stack.isItemEnchanted(); + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderItem.java b/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderItem.java new file mode 100644 index 000000000..0d1c726e5 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderItem.java @@ -0,0 +1,79 @@ +package jss.notfine.mixins.early.minecraft.glint; + +import jss.notfine.core.Settings; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.entity.RenderItem; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = RenderItem.class) +public abstract class MixinRenderItem { + + /** + * @author jss2a98aj + * @reason Makes renderGlint faster and fixes glBlendFunc being left with the wrong values. + */ + @Overwrite + private void renderGlint(int unused, int posX, int posY, int width, int height) { + if(!Settings.MODE_GLINT_INV.isValueBase()) { + return; + } + final float timeUVSpeed = 0.00390625F; + final Tessellator tessellator = Tessellator.instance; + final long time = Minecraft.getSystemTime(); + + float layerUVNoise = 4.0F; + + OpenGlHelper.glBlendFunc(772, 1, 0, 1); + + //for(int layer = 0; layer < 2; ++layer) { + final int timeUVDenominator = 3000 /*+ layer * 1873*/; + final float timeUVNoise = (float)(time % (long)timeUVDenominator) / (float)timeUVDenominator * 256F; + + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV( + posX, (posY + height), zLevel, + ((timeUVNoise + (float)height * layerUVNoise) * timeUVSpeed), ((float)height * timeUVSpeed) + ); + tessellator.addVertexWithUV( + (posX + width), (posY + height), zLevel, + ((timeUVNoise + (float)width + (float)height * layerUVNoise) * timeUVSpeed), ((float)height * timeUVSpeed) + ); + tessellator.addVertexWithUV( + (posX + width), posY, zLevel, + ((timeUVNoise + (float)width) * timeUVSpeed), 0D + ); + tessellator.addVertexWithUV( + posX, posY, zLevel, + (timeUVNoise * timeUVSpeed), 0D + ); + tessellator.draw(); + + //layerUVNoise = -1.0F; + //} + + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + } + + @Redirect( + method = "renderDroppedItem(Lnet/minecraft/entity/item/EntityItem;Lnet/minecraft/util/IIcon;IFFFFI)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/item/ItemStack;hasEffect(I)Z" + ), + remap = false + ) + private boolean notFine$toggleGlint(ItemStack stack, int pass) { + return Settings.MODE_GLINT_WORLD.isValueBase() && stack.hasEffect(pass); + } + + @Shadow public float zLevel; + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderPlayer.java b/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderPlayer.java new file mode 100644 index 000000000..463162d29 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderPlayer.java @@ -0,0 +1,24 @@ +package jss.notfine.mixins.early.minecraft.glint; + +import jss.notfine.core.Settings; +import net.minecraft.client.renderer.entity.RenderPlayer; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = RenderPlayer.class) +public abstract class MixinRenderPlayer { + + @Redirect( + method = "shouldRenderPass(Lnet/minecraft/client/entity/AbstractClientPlayer;IF)I", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/item/ItemStack;isItemEnchanted()Z" + ) + ) + private boolean notFine$toggleGlint(ItemStack stack) { + return Settings.MODE_GLINT_WORLD.isValueBase() && stack.isItemEnchanted(); + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/gui/MixinGuiSlot.java b/src/main/java/jss/notfine/mixins/early/minecraft/gui/MixinGuiSlot.java new file mode 100644 index 000000000..e007571d6 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/gui/MixinGuiSlot.java @@ -0,0 +1,21 @@ +package jss.notfine.mixins.early.minecraft.gui; + +import jss.notfine.core.Settings; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiSlot; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GuiSlot.class) +public abstract class MixinGuiSlot { + + @Inject(method = "drawContainerBackground", at = @At("HEAD"), cancellable = true, remap = false) + private void notFine$toggleContainerBackground(CallbackInfo ci) { + if(!Settings.MODE_GUI_BACKGROUND.isValueBase() && Minecraft.getMinecraft().theWorld != null) { + ci.cancel(); + } + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeaves.java b/src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeaves.java new file mode 100644 index 000000000..9e7c27ce5 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeaves.java @@ -0,0 +1,60 @@ +package jss.notfine.mixins.early.minecraft.leaves; + +import jss.notfine.core.Settings; +import jss.notfine.core.SettingsManager; +import jss.notfine.util.ILeafBlock; +import jss.util.DirectionHelper; +import net.minecraft.block.BlockLeaves; +import net.minecraft.block.BlockLeavesBase; +import net.minecraft.block.material.Material; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(value = BlockLeaves.class) +public abstract class MixinBlockLeaves extends BlockLeavesBase { + + /** + * @author jss2a98aj + * @reason Control leaf opacity. + */ + @Overwrite + public boolean isOpaqueCube() { + return SettingsManager.leavesOpaque; + } + + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + if(field_150129_M[0] == null) { + //A mod dev had no idea what they were doing. + return getIcon(side, world.getBlockMetadata(x, y, z)); + } + int renderMode = (int)Settings.MODE_LEAVES.getValue(); + int maskedMeta = world.getBlockMetadata(x, y, z) & 3; + switch(renderMode) { + case -1: + renderMode = SettingsManager.leavesOpaque ? 1 : 0; + break; + case 4: + renderMode = world.getBlock( + x + DirectionHelper.xDirectionalIncrease[side], + y + DirectionHelper.yDirectionalIncrease[side], + z + DirectionHelper.zDirectionalIncrease[side] + ) instanceof ILeafBlock ? 1 : 0; + break; + default: + renderMode = renderMode > 1 ? 0 : renderMode; + break; + } + maskedMeta = maskedMeta >= field_150129_M[renderMode].length ? 0 : maskedMeta; + return field_150129_M[renderMode][maskedMeta]; + } + + @Shadow protected IIcon[][] field_150129_M; + + protected MixinBlockLeaves(Material material, boolean overridden) { + super(material, overridden); + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeavesBase.java b/src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeavesBase.java new file mode 100644 index 000000000..0e12f1bd9 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeavesBase.java @@ -0,0 +1,23 @@ +package jss.notfine.mixins.early.minecraft.leaves; + +import jss.notfine.util.ILeafBlock; +import jss.notfine.util.LeafRenderUtil; +import net.minecraft.block.Block; +import net.minecraft.block.BlockLeavesBase; +import net.minecraft.block.material.Material; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(value = BlockLeavesBase.class) +public abstract class MixinBlockLeavesBase extends Block implements ILeafBlock { + + @Override + public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int side) { + return LeafRenderUtil.shouldSideBeRendered(world, x, y, z, side); + } + + protected MixinBlockLeavesBase(Material material) { + super(material); + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinBlockEnchantmentTable.java b/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinBlockEnchantmentTable.java new file mode 100644 index 000000000..2bd6d883e --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinBlockEnchantmentTable.java @@ -0,0 +1,61 @@ +package jss.notfine.mixins.early.minecraft.particles; + +import java.util.Random; + +import jss.notfine.core.Settings; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +import net.minecraft.block.BlockContainer; +import net.minecraft.block.BlockEnchantmentTable; +import net.minecraft.block.material.Material; +import net.minecraft.world.World; + + +@Mixin(value = BlockEnchantmentTable.class) +public abstract class MixinBlockEnchantmentTable extends BlockContainer { + + protected MixinBlockEnchantmentTable(Material material) { + super(material); + } + + /** + * @author jss2a98aj + * @reason Makes anything with enchantment power cause enchantment particles. + */ + @Overwrite() + public void randomDisplayTick(World world, int x, int y, int z, Random rand) { + //Unneeded in vanilla as the super call is empty. + //super.randomDisplayTick(world, x, y, z, rand); + float particleChance = Settings.PARTICLES_ENC_TABLE.getValue(); + if(particleChance <= 0f) { + return; + } + for (int xPos = x - 2; xPos <= x + 2; ++xPos) { + for (int zPos = z - 2; zPos <= z + 2; ++zPos) { + if (xPos > x - 2 && xPos < x + 2 && zPos == z - 1) { + zPos = z + 2; + } + if (rand.nextInt(16) <= particleChance) { + for (int yPos = y; yPos <= y + 1; ++yPos) { + if (world.getBlock(xPos, yPos, zPos).getEnchantPowerBonus(world, xPos, yPos, zPos) > 0f) { + if (!world.isAirBlock((xPos - x) / 2 + x, yPos, (zPos - z) / 2 + z)) { + break; + } + world.spawnParticle( + "enchantmenttable", + (double)x + 0.5D, + (double)y + 2.0D, + (double)z + 0.5D, + (double)((float)(xPos - x) + rand.nextFloat()) - 0.5D, + (float)(yPos - y) - rand.nextFloat() - 1.0F, + (double)((float)(zPos - z) + rand.nextFloat()) - 0.5D + ); + } + } + } + } + } + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinEffectRenderer.java b/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinEffectRenderer.java new file mode 100644 index 000000000..f8d5b7a8e --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinEffectRenderer.java @@ -0,0 +1,94 @@ +package jss.notfine.mixins.early.minecraft.particles; + +import net.minecraft.client.particle.EffectRenderer; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.crash.CrashReport; +import net.minecraft.crash.CrashReportCategory; +import net.minecraft.entity.Entity; +import net.minecraft.util.ReportedException; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.List; + +@Mixin(value = EffectRenderer.class) +public abstract class MixinEffectRenderer { + + /** + * @author jss2a98aj + * @reason Makes most particles render with the expected depth. + */ + @Overwrite + public void renderParticles(Entity entity, float p_78874_2_) { + float f1 = ActiveRenderInfo.rotationX; + float f2 = ActiveRenderInfo.rotationZ; + float f3 = ActiveRenderInfo.rotationYZ; + float f4 = ActiveRenderInfo.rotationXY; + float f5 = ActiveRenderInfo.rotationXZ; + EntityFX.interpPosX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * (double)p_78874_2_; + EntityFX.interpPosY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * (double)p_78874_2_; + EntityFX.interpPosZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * (double)p_78874_2_; + + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glAlphaFunc(GL11.GL_GREATER, 0.003921569F); + Tessellator tessellator = Tessellator.instance; + + for (int k = 0; k < 3; ++k) { + final int i = k; + + if (!fxLayers[i].isEmpty()) { + switch(i) { + case 0: + default: + renderer.bindTexture(particleTextures); + break; + case 1: + renderer.bindTexture(TextureMap.locationBlocksTexture); + break; + case 2: + renderer.bindTexture(TextureMap.locationItemsTexture); + } + + tessellator.startDrawingQuads(); + + for (int j = 0; j < fxLayers[i].size(); ++j) { + final EntityFX entityfx = (EntityFX)fxLayers[i].get(j); + if (entityfx == null) continue; + tessellator.setBrightness(entityfx.getBrightnessForRender(p_78874_2_)); + + try { + entityfx.renderParticle(tessellator, p_78874_2_, f1, f5, f2, f3, f4); + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Rendering Particle"); + CrashReportCategory crashreportcategory = crashreport.makeCategory("Particle being rendered"); + crashreportcategory.addCrashSectionCallable("Particle", entityfx::toString); + crashreportcategory.addCrashSectionCallable( + "Particle Type", + () -> i == 0 ? "MISC_TEXTURE" : (i == 1 ? "TERRAIN_TEXTURE" : (i == 2 ? "ITEM_TEXTURE" : (i == 3 ? "ENTITY_PARTICLE_TEXTURE" : "Unknown - " + i))) + ); + throw new ReportedException(crashreport); + } + } + tessellator.draw(); + } + } + GL11.glDisable(GL11.GL_BLEND); + GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F); + } + + @Shadow @Final + private static ResourceLocation particleTextures; + @Shadow private List[] fxLayers; + @Shadow private TextureManager renderer; + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldClient.java b/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldClient.java new file mode 100644 index 000000000..c480d0f4f --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldClient.java @@ -0,0 +1,24 @@ +package jss.notfine.mixins.early.minecraft.particles; + +import java.util.Random; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import jss.util.RandomXoshiro256StarStar; +import net.minecraft.client.multiplayer.WorldClient; + +@Mixin(value = WorldClient.class) +public abstract class MixinWorldClient { + + /** + * @author jss2a98aj + * @reason Xoshiro256** is faster than Random. + */ + @Redirect(method = "doVoidFogParticles", at = @At(value = "NEW", target = "java/util/Random", ordinal = 0)) + private Random notFine$redirectDoVoidFogParticlesRandom() { + return new RandomXoshiro256StarStar(); + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldProvider.java b/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldProvider.java new file mode 100644 index 000000000..c73a61d31 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldProvider.java @@ -0,0 +1,25 @@ +package jss.notfine.mixins.early.minecraft.particles; + +import jss.notfine.core.Settings; +import net.minecraft.world.WorldProvider; +import net.minecraft.world.WorldType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(value = WorldProvider.class) +public class MixinWorldProvider { + + /** + * @author jss2a98aj + * @reason Toggle void particles. + */ + @Overwrite + public boolean getWorldHasVoidParticles() { + return Settings.PARTICLES_VOID.isValueBase() && terrainType.hasVoidParticles(hasNoSky); + } + + @Shadow public WorldType terrainType; + @Shadow public boolean hasNoSky; + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinEntityRenderer.java b/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinEntityRenderer.java new file mode 100644 index 000000000..8b5664791 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinEntityRenderer.java @@ -0,0 +1,27 @@ +package jss.notfine.mixins.early.minecraft.toggle; + +import jss.notfine.core.SettingsManager; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.settings.GameSettings; +import org.spongepowered.asm.lib.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(EntityRenderer.class) +abstract public class MixinEntityRenderer { + + @Redirect( + method = "renderWorld(FJ)V", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", + opcode = Opcodes.GETFIELD, + ordinal = 0 + ) + ) + private boolean notFine$toggleWaterDetail(GameSettings settings) { + return SettingsManager.waterDetail; + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinGuiIngame.java b/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinGuiIngame.java new file mode 100644 index 000000000..018970d5f --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinGuiIngame.java @@ -0,0 +1,24 @@ +package jss.notfine.mixins.early.minecraft.toggle; + +import jss.notfine.core.SettingsManager; +import net.minecraft.client.gui.GuiIngame; +import net.minecraftforge.client.GuiIngameForge; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = {GuiIngame.class, GuiIngameForge.class}) +public abstract class MixinGuiIngame { + + @Redirect( + method = "renderGameOverlay(FZII)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/Minecraft;isFancyGraphicsEnabled()Z" + ) + ) + private boolean notFine$toggleVignette(float whyAndHowIsThisAFloat) { + return SettingsManager.vignette; + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRender.java b/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRender.java new file mode 100644 index 000000000..0fc472430 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRender.java @@ -0,0 +1,27 @@ +package jss.notfine.mixins.early.minecraft.toggle; + +import jss.notfine.core.SettingsManager; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.settings.GameSettings; +import org.spongepowered.asm.lib.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = Render.class) +public abstract class MixinRender { + + @Redirect( + method = "doRenderShadowAndFire", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", + opcode = Opcodes.GETFIELD + ), + allow = 1 + ) + private boolean notFine$toggleEntityShadows(GameSettings settings) { + return SettingsManager.shadows; + } + +} diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRenderItem.java b/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRenderItem.java new file mode 100644 index 000000000..0311bfb39 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRenderItem.java @@ -0,0 +1,27 @@ +package jss.notfine.mixins.early.minecraft.toggle; + +import jss.notfine.core.SettingsManager; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.settings.GameSettings; +import org.spongepowered.asm.lib.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(RenderItem.class) +abstract public class MixinRenderItem { + + @Redirect( + method = "renderDroppedItem(Lnet/minecraft/entity/item/EntityItem;Lnet/minecraft/util/IIcon;IFFFFI)V", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", + opcode = Opcodes.GETFIELD + ), + allow = 1 + ) + private boolean notFine$toggleDroppedItemDetail(GameSettings settings) { + return SettingsManager.droppedItemDetail; + } + +} diff --git a/src/main/java/jss/notfine/mixins/late/thaumcraft/leaves/MixinBlockMagicalLeaves.java b/src/main/java/jss/notfine/mixins/late/thaumcraft/leaves/MixinBlockMagicalLeaves.java new file mode 100644 index 000000000..e23b5da83 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/late/thaumcraft/leaves/MixinBlockMagicalLeaves.java @@ -0,0 +1,59 @@ +package jss.notfine.mixins.late.thaumcraft.leaves; + +import jss.notfine.util.ILeafBlock; +import jss.notfine.core.Settings; +import jss.notfine.core.SettingsManager; +import jss.notfine.util.LeafRenderUtil; +import jss.util.DirectionHelper; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import thaumcraft.common.blocks.BlockMagicalLeaves; + +@Mixin(value = BlockMagicalLeaves.class) +public abstract class MixinBlockMagicalLeaves extends Block implements ILeafBlock { + + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + int renderMode = (int) Settings.MODE_LEAVES.getValue(); + int maskedMeta = world.getBlockMetadata(x, y, z) & 3; + switch(renderMode) { + case -1: + renderMode = SettingsManager.leavesOpaque ? 1 : 0; + break; + case 4: + renderMode = world.getBlock( + x + DirectionHelper.xDirectionalIncrease[side], + y + DirectionHelper.yDirectionalIncrease[side], + z + DirectionHelper.zDirectionalIncrease[side] + ) instanceof ILeafBlock ? 1 : 0; + break; + default: + renderMode = renderMode > 1 ? 0 : renderMode; + break; + } + maskedMeta = maskedMeta > 1 ? 0 : maskedMeta; + return icon[renderMode + maskedMeta * 2]; + } + + /** + * @author jss2a98aj + * @reason Support new leaf rendering modes on Thaumcraft leaves. + */ + @Overwrite + public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int side) { + return LeafRenderUtil.shouldSideBeRendered(world, x, y, z, side); + } + + protected MixinBlockMagicalLeaves(Material material) { + super(material); + } + + @Shadow(remap = false) + public IIcon[] icon; + +} diff --git a/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves.java b/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves.java new file mode 100644 index 000000000..a1f9f90de --- /dev/null +++ b/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves.java @@ -0,0 +1,40 @@ +package jss.notfine.mixins.late.twilightforest.leaves; + +import jss.notfine.core.Settings; +import jss.notfine.core.SettingsManager; +import jss.notfine.util.ILeafBlock; +import jss.util.DirectionHelper; +import net.minecraft.block.BlockLeaves; +import net.minecraft.init.Blocks; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Mixin; +import twilightforest.block.BlockTFLeaves; + +@Mixin(value = BlockTFLeaves.class) +public abstract class MixinBlockTFLeaves extends BlockLeaves { + + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + int renderMode = (int)Settings.MODE_LEAVES.getValue(); + int maskedMeta = world.getBlockMetadata(x, y, z) & 3; + switch(renderMode) { + case -1: + renderMode = SettingsManager.leavesOpaque ? 1 : 0; + break; + case 4: + renderMode = world.getBlock( + x + DirectionHelper.xDirectionalIncrease[side], + y + DirectionHelper.yDirectionalIncrease[side], + z + DirectionHelper.zDirectionalIncrease[side] + ) instanceof ILeafBlock ? 1 : 0; + break; + default: + renderMode = renderMode > 1 ? 0 : renderMode; + break; + } + maskedMeta = maskedMeta > 1 ? 0 : maskedMeta; + return Blocks.leaves.field_150129_M[renderMode][maskedMeta]; + } + +} diff --git a/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves3.java b/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves3.java new file mode 100644 index 000000000..dd4f75a17 --- /dev/null +++ b/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves3.java @@ -0,0 +1,38 @@ +package jss.notfine.mixins.late.twilightforest.leaves; + +import jss.notfine.core.Settings; +import jss.notfine.core.SettingsManager; +import jss.notfine.util.ILeafBlock; +import jss.util.DirectionHelper; +import net.minecraft.block.BlockLeaves; +import net.minecraft.init.Blocks; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Mixin; +import twilightforest.block.BlockTFLeaves3; + +@Mixin(value = BlockTFLeaves3.class) +public abstract class MixinBlockTFLeaves3 extends BlockLeaves { + + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + int renderMode = (int)Settings.MODE_LEAVES.getValue(); + switch(renderMode) { + case -1: + renderMode = SettingsManager.leavesOpaque ? 1 : 0; + break; + case 4: + renderMode = world.getBlock( + x + DirectionHelper.xDirectionalIncrease[side], + y + DirectionHelper.yDirectionalIncrease[side], + z + DirectionHelper.zDirectionalIncrease[side] + ) instanceof ILeafBlock ? 1 : 0; + break; + default: + renderMode = renderMode > 1 ? 0 : renderMode; + break; + } + return Blocks.leaves.field_150129_M[renderMode][0]; + } + +} diff --git a/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFMagicLeaves.java b/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFMagicLeaves.java new file mode 100644 index 000000000..2fd81ec6f --- /dev/null +++ b/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFMagicLeaves.java @@ -0,0 +1,59 @@ +package jss.notfine.mixins.late.twilightforest.leaves; + +import jss.notfine.core.Settings; +import jss.notfine.core.SettingsManager; +import jss.notfine.util.ILeafBlock; +import jss.util.DirectionHelper; +import net.minecraft.block.BlockLeaves; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import twilightforest.block.BlockTFMagicLeaves; + +@Mixin(value = BlockTFMagicLeaves.class) +public abstract class MixinBlockTFMagicLeaves extends BlockLeaves { + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + int renderMode = (int) Settings.MODE_LEAVES.getValue(); + int maskedMeta = world.getBlockMetadata(x, y, z) & 3; + switch(renderMode) { + case -1: + renderMode = SettingsManager.leavesOpaque ? 1 : 0; + break; + case 4: + renderMode = world.getBlock( + x + DirectionHelper.xDirectionalIncrease[side], + y + DirectionHelper.yDirectionalIncrease[side], + z + DirectionHelper.zDirectionalIncrease[side] + ) instanceof ILeafBlock ? 1 : 0; + break; + default: + renderMode = renderMode > 1 ? 0 : renderMode; + break; + } + maskedMeta = maskedMeta > 1 ? 0 : maskedMeta; + switch(maskedMeta) { + default: + return renderMode == 1 ? SPR_TIMELEAVES_OPAQUE : SPR_TIMELEAVES; + case 1: + return renderMode == 1 ? SPR_TRANSLEAVES_OPAQUE : SPR_TRANSLEAVES; + case 3: + return renderMode == 1 ? SPR_SORTLEAVES_OPAQUE : SPR_SORTLEAVES; + } + } + + @Shadow(remap = false) + public static IIcon SPR_TIMELEAVES; + @Shadow(remap = false) + public static IIcon SPR_TIMELEAVES_OPAQUE; + @Shadow(remap = false) + public static IIcon SPR_TRANSLEAVES; + @Shadow(remap = false) + public static IIcon SPR_TRANSLEAVES_OPAQUE; + @Shadow(remap = false) + public static IIcon SPR_SORTLEAVES; + @Shadow(remap = false) + public static IIcon SPR_SORTLEAVES_OPAQUE; + +} diff --git a/src/main/java/jss/notfine/mixins/late/witchery/leaves/MixinBlockWitchLeaves.java b/src/main/java/jss/notfine/mixins/late/witchery/leaves/MixinBlockWitchLeaves.java new file mode 100644 index 000000000..29d22da8a --- /dev/null +++ b/src/main/java/jss/notfine/mixins/late/witchery/leaves/MixinBlockWitchLeaves.java @@ -0,0 +1,58 @@ +package jss.notfine.mixins.late.witchery.leaves; + +import com.emoniph.witchery.blocks.BlockWitchLeaves; +import jss.notfine.core.Settings; +import jss.notfine.core.SettingsManager; +import jss.notfine.util.ILeafBlock; +import jss.util.DirectionHelper; +import net.minecraft.block.BlockLeavesBase; +import net.minecraft.block.material.Material; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(value = BlockWitchLeaves.class) +public abstract class MixinBlockWitchLeaves extends BlockLeavesBase { + + /** + * @author jss2a98aj + * @reason Support new leaf rendering modes on Witchery leaves. + */ + @Overwrite + public boolean isOpaqueCube() { + return SettingsManager.leavesOpaque; + } + + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + int renderMode = (int) Settings.MODE_LEAVES.getValue(); + int maskedMeta = world.getBlockMetadata(x, y, z) & 3; + switch(renderMode) { + case -1: + renderMode = SettingsManager.leavesOpaque ? 1 : 0; + break; + case 4: + renderMode = world.getBlock( + x + DirectionHelper.xDirectionalIncrease[side], + y + DirectionHelper.yDirectionalIncrease[side], + z + DirectionHelper.zDirectionalIncrease[side] + ) instanceof ILeafBlock ? 1 : 0; + break; + default: + renderMode = renderMode > 1 ? 0 : renderMode; + break; + } + maskedMeta = maskedMeta > 1 ? 0 : maskedMeta; + return iconsForModes[renderMode][maskedMeta]; + } + + @Shadow(remap = false) + private IIcon[][] iconsForModes; + + protected MixinBlockWitchLeaves(Material material, boolean unused) { + super(material, unused); + } + +} diff --git a/src/main/java/jss/notfine/render/RenderStars.java b/src/main/java/jss/notfine/render/RenderStars.java new file mode 100644 index 000000000..442ba7ec5 --- /dev/null +++ b/src/main/java/jss/notfine/render/RenderStars.java @@ -0,0 +1,72 @@ +package jss.notfine.render; + +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) { + GL11.glPushMatrix(); + GL11.glNewList(render.starGLCallList, GL11.GL_COMPILE); + renderStars(); + GL11.glEndList(); + GL11.glPopMatrix(); + } + + public static void renderStars() { + final int totalStars = (int) Settings.TOTAL_STARS.getValue(); + if(totalStars <= 0) { + return; + } + final RandomXoshiro256StarStar random = new RandomXoshiro256StarStar(10842L); + final Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + + for(int i = 0; i < totalStars; ++i) { + float starOnUnitSphereX = random.nextFloat() * 2.0F - 1.0F; + float starOnUnitSphereY = random.nextFloat() * 2.0F - 1.0F; + float starOnUnitSphereZ = random.nextFloat() * 2.0F - 1.0F; + double distanceNormalizer = starOnUnitSphereX * starOnUnitSphereX + starOnUnitSphereY * starOnUnitSphereY + starOnUnitSphereZ * starOnUnitSphereZ; + + if(distanceNormalizer < 1.0D && distanceNormalizer > 0.01D) { + distanceNormalizer = 1.0D / Math.sqrt(distanceNormalizer); + starOnUnitSphereX *= distanceNormalizer; + starOnUnitSphereY *= distanceNormalizer; + starOnUnitSphereZ *= distanceNormalizer; + final double starX = starOnUnitSphereX * 100.0D; + final double starY = starOnUnitSphereY * 100.0D; + final double starZ = starOnUnitSphereZ * 100.0D; + final double thetaXZ = Math.atan2(starOnUnitSphereX, starOnUnitSphereZ); + final double thetaXZSin = Math.sin(thetaXZ); + final double thetaXZCos = Math.cos(thetaXZ); + final double starAzimuth = Math.atan2(Math.sqrt(starOnUnitSphereX * starOnUnitSphereX + starOnUnitSphereZ * starOnUnitSphereZ), starOnUnitSphereY); + final double starAzimuthX = Math.sin(starAzimuth); + final double starAzimuthZ = Math.cos(starAzimuth); + + final float starSize = 0.15F + random.nextFloat() * 0.1F; + final double starRotation = random.nextDouble() * Math.PI * 2.0D; + final double starRotationSin = Math.sin(starRotation); + final double starRotationCos = Math.cos(starRotation); + + for(int starCorner = 0; starCorner < 4; ++starCorner) { + final double cornerOffsetU = (double)((starCorner & 2) - 1) * starSize; + final double cornerOffsetV = (double)((starCorner + 1 & 2) - 1) * starSize; + final double cornerVerticalOffset = cornerOffsetU * starRotationCos - cornerOffsetV * starRotationSin; + final double cornerHorizontalOffset = cornerOffsetV * starRotationCos + cornerOffsetU * starRotationSin; + final double cornerY = cornerVerticalOffset * starAzimuthX; + final double offsetAzimuthal = -cornerVerticalOffset * starAzimuthZ; + final double cornerX = offsetAzimuthal * thetaXZSin - cornerHorizontalOffset * thetaXZCos; + final double cornerZ = cornerHorizontalOffset * thetaXZSin + offsetAzimuthal * thetaXZCos; + tessellator.addVertex(starX + cornerX, starY + cornerY, starZ + cornerZ); + } + } + } + tessellator.draw(); + } + +} diff --git a/src/main/java/jss/notfine/util/ILeafBlock.java b/src/main/java/jss/notfine/util/ILeafBlock.java new file mode 100644 index 000000000..d946f84e9 --- /dev/null +++ b/src/main/java/jss/notfine/util/ILeafBlock.java @@ -0,0 +1,5 @@ +package jss.notfine.util; + +public interface ILeafBlock { + +} diff --git a/src/main/java/jss/notfine/util/LeafRenderUtil.java b/src/main/java/jss/notfine/util/LeafRenderUtil.java new file mode 100644 index 000000000..82ebb00ab --- /dev/null +++ b/src/main/java/jss/notfine/util/LeafRenderUtil.java @@ -0,0 +1,107 @@ +package jss.notfine.util; + +import jss.notfine.core.Settings; +import jss.notfine.core.SettingsManager; +import jss.util.DirectionHelper; +import net.minecraft.block.Block; +import net.minecraft.world.IBlockAccess; + +public class LeafRenderUtil { + + public static boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int side) { + Block otherBlock = world.getBlock(x, y, z); + if(otherBlock.isOpaqueCube()) { + return false; + } + switch((int)Settings.MODE_LEAVES.getValue()) { + case 1: + case 2: + return !(otherBlock instanceof ILeafBlock); + case 3: + case 4: + if(otherBlock instanceof ILeafBlock) { + x -= DirectionHelper.xDirectionalIncrease[side]; + y -= DirectionHelper.yDirectionalIncrease[side]; + z -= DirectionHelper.zDirectionalIncrease[side]; + int renderCheck = 0; + otherBlock = world.getBlock(x + 1, y, z); + if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + renderCheck++; + } + otherBlock = world.getBlock(x - 1, y, z); + if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + renderCheck++; + } + otherBlock = world.getBlock(x, y + 1, z); + if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + renderCheck++; + } + otherBlock = world.getBlock(x, y - 1, z); + if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + renderCheck++; + } + otherBlock = world.getBlock(x, y, z + 1); + if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + renderCheck++; + } + otherBlock = world.getBlock(x, y, z - 1); + if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + renderCheck++; + } + boolean renderSide = renderCheck == 6; + if(renderSide) { + x += 2 * DirectionHelper.xDirectionalIncrease[side]; + y += 2 * DirectionHelper.yDirectionalIncrease[side]; + z += 2 * DirectionHelper.zDirectionalIncrease[side]; + otherBlock = world.getBlock(x, y, z); + if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + renderSide = false; + } + x -= DirectionHelper.xDirectionalIncrease[side]; + y -= DirectionHelper.yDirectionalIncrease[side]; + z -= DirectionHelper.zDirectionalIncrease[side]; + int nextSide = DirectionHelper.relativeADirections[side]; + otherBlock = world.getBlock( + x + DirectionHelper.xDirectionalIncrease[nextSide], + y + DirectionHelper.yDirectionalIncrease[nextSide], + z + DirectionHelper.zDirectionalIncrease[nextSide] + ); + if(!((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + renderSide = true; + } + nextSide = DirectionHelper.relativeBDirections[side]; + otherBlock = world.getBlock( + x + DirectionHelper.xDirectionalIncrease[nextSide], + y + DirectionHelper.yDirectionalIncrease[nextSide], + z + DirectionHelper.zDirectionalIncrease[nextSide] + ); + if(!((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + renderSide = true; + } + nextSide = DirectionHelper.relativeCDirections[side]; + otherBlock = world.getBlock( + x + DirectionHelper.xDirectionalIncrease[nextSide], + y + DirectionHelper.yDirectionalIncrease[nextSide], + z + DirectionHelper.zDirectionalIncrease[nextSide] + ); + if(!((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + renderSide = true; + } + nextSide = DirectionHelper.relativeDDirections[side]; + otherBlock = world.getBlock( + x + DirectionHelper.xDirectionalIncrease[nextSide], + y + DirectionHelper.yDirectionalIncrease[nextSide], + z + DirectionHelper.zDirectionalIncrease[nextSide] + ); + if(!((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + renderSide = true; + } + } + return renderSide; + } + default: + return !SettingsManager.leavesOpaque || !(otherBlock instanceof ILeafBlock); + } + } + +} diff --git a/src/main/java/jss/util/DirectionHelper.java b/src/main/java/jss/util/DirectionHelper.java new file mode 100644 index 000000000..c051e931a --- /dev/null +++ b/src/main/java/jss/util/DirectionHelper.java @@ -0,0 +1,41 @@ +package jss.util; + +public class DirectionHelper { + + public static final int[] orderedDirections = { + 0, 1, 2, 3, 4, 5 + }; + + public static final int[] oppositeDirections = { + 1, 0, 3, 2, 5, 4 + }; + + public static final int[] yDirectionalIncrease = { + -1, 1, -0, 0, -0, 0 + }; + + public static final int[] zDirectionalIncrease = { + -0, 0, -1, 1, -0, 0 + }; + + public static final int[] xDirectionalIncrease = { + -0, 0, -0, 0, -1, 1 + }; + + public static final int[] relativeADirections = { + 2, 3, 4, 5, 0, 1 + }; + + public static final int[] relativeBDirections = { + 3, 2, 5, 4, 1, 0 + }; + + public static final int[] relativeCDirections = { + 4, 5, 0, 1, 2, 3 + }; + + public static final int[] relativeDDirections = { + 5, 4, 1, 0, 3, 2 + }; + +} diff --git a/src/main/java/jss/util/RandomXoshiro256StarStar.java b/src/main/java/jss/util/RandomXoshiro256StarStar.java new file mode 100644 index 000000000..ff86643c3 --- /dev/null +++ b/src/main/java/jss/util/RandomXoshiro256StarStar.java @@ -0,0 +1,190 @@ +/* + * To the extent possible under law, the author has dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * See + */ + +package jss.util; + +import java.io.IOException; +import java.util.Random; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Implementation of Random based on the xoshiro256** RNG. No-dependencies + * Java port of the original C code, + * which is public domain. This Java port is similarly dedicated to the public + * domain. + *

+ * Individual instances are not thread-safe. Each thread must have its own + * instance which is not shared. + * + * @see http://xoshiro.di.unimi.it/ + * @author David Blackman and Sebastiano Vigna <vigna@acm.org> (original C code) + * @author Una Thompson <una@unascribed.com> (Java port) + */ +public class RandomXoshiro256StarStar extends Random { + private static final long serialVersionUID = -2837799889588687855L; + + private static final AtomicLong uniq = new AtomicLong(System.nanoTime()); + + private static final long nextUniq() { + return splitmix64_2(uniq.addAndGet(SPLITMIX1_MAGIC)); + } + + public RandomXoshiro256StarStar() { + this(System.nanoTime()^nextUniq()); + } + + public RandomXoshiro256StarStar(long seed) { + super(seed); + // super will call setSeed + } + + public RandomXoshiro256StarStar(long s1, long s2, long s3, long s4) { + setState(s1, s2, s3, s4); + } + + // used to "stretch" seeds into a full 256-bit state; also makes + // it safe to pass in zero as a seed + //// + // what generator is used here is unimportant, as long as it's + // from a different family, but splitmix64 happens to be an + // incredibly simple high-quality generator of a completely + // different family (and is recommended by the xoshiro authors) + + private static final long SPLITMIX1_MAGIC = 0x9E3779B97F4A7C15L; + + private static long splitmix64_1(long x) { + return (x + SPLITMIX1_MAGIC); + } + + private static long splitmix64_2(long z) { + z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9L; + z = (z ^ (z >> 27)) * 0x94D049BB133111EBL; + return z ^ (z >> 31); + } + + @Override + public void setSeed(long seed) { + // update haveNextNextGaussian flag in super + super.setSeed(seed); + long sms = splitmix64_1(seed); + s0 = splitmix64_2(sms); + sms = splitmix64_1(sms); + s1 = splitmix64_2(sms); + sms = splitmix64_1(sms); + s2 = splitmix64_2(sms); + sms = splitmix64_1(sms); + s3 = splitmix64_2(sms); + } + + public void setState(long s0, long s1, long s2, long s4) { + if (s0 == 0 && s1 == 0 && s2 == 0 && s4 == 0) + throw new IllegalArgumentException("xoshiro256** state cannot be all zeroes"); + this.s0 = s0; + this.s1 = s1; + this.s2 = s2; + this.s3 = s4; + } + + // not called, implemented instead of just throwing for completeness + @Override + protected int next(int bits) { + return (int)(nextLong() & ((1L << bits) - 1)); + } + + @Override + public int nextInt() { + return (int)nextLong(); + } + + @Override + public int nextInt(int bound) { + return (int)nextLong(bound); + } + + public long nextLong(long bound) { + if (bound <= 0) throw new IllegalArgumentException("bound must be positive"); + // clear sign bit for positive-only, modulo to bound + return (nextLong() & Long.MAX_VALUE) % bound; + } + + @Override + public double nextDouble() { + return (nextLong() >>> 11) * 0x1.0P-53; + } + + @Override + public float nextFloat() { + return (nextLong() >>> 40) * 0x1.0P-24f; + } + + @Override + public boolean nextBoolean() { + return (nextLong() & 1) != 0; + } + + @Override + public void nextBytes(byte[] buf) { + nextBytes(buf, 0, buf.length); + } + + public void nextBytes(byte[] buf, int ofs, int len) { + if (ofs < 0) throw new ArrayIndexOutOfBoundsException("Offset "+ofs+" is negative"); + if (ofs >= buf.length) throw new ArrayIndexOutOfBoundsException("Offset "+ofs+" is greater than buffer length"); + if (ofs+len > buf.length) throw new ArrayIndexOutOfBoundsException("Length "+len+" with offset "+ofs+" is past end of buffer"); + int j = 8; + long l = 0; + for (int i = ofs; i < ofs+len; i++) { + if (j >= 8) { + l = nextLong(); + j = 0; + } + buf[i] = (byte)(l&0xFF); + l = l >>> 8L; + j++; + } + } + + /* This is xoshiro256** 1.0, our all-purpose, rock-solid generator. It has + excellent (sub-ns) speed, a state (256 bits) that is large enough for + any parallel application, and it passes all tests we are aware of. + + For generating just floating-point numbers, xoshiro256+ is even faster. + + The state must be seeded so that it is not everywhere zero. If you have + a 64-bit seed, we suggest to seed a splitmix64 generator and use its + output to fill s. */ + + private static long rotl(long x, int k) { + return (x << k) | (x >>> (64 - k)); + } + + + private long s0; + private long s1; + private long s2; + private long s3; + + @Override + public long nextLong() { + long result_starstar = rotl(s1 * 5, 7) * 9; + + long t = s1 << 17; + + s2 ^= s0; + s3 ^= s1; + s1 ^= s2; + s0 ^= s3; + + s2 ^= t; + + s3 = rotl(s3, 45); + + return result_starstar; + } + +} diff --git a/src/main/resources/META-INF/notfine_at.cfg b/src/main/resources/META-INF/notfine_at.cfg new file mode 100644 index 000000000..6ebee9470 --- /dev/null +++ b/src/main/resources/META-INF/notfine_at.cfg @@ -0,0 +1,8 @@ +# For changing gui background +public-f net.minecraft.client.gui.Gui field_110325_k #optionsBackground +# For regenerating the stars render list +public net.minecraft.client.renderer.RenderGlobal field_72772_v #starGLCallList +# For adjusting vanilla option enumerators +public-f net.minecraft.client.settings.GameSettings$Options field_148270_M #valueStep +# For supporting some strangely setup mods +public net.minecraft.block.BlockLeaves field_150129_M diff --git a/src/main/resources/assets/notfine/lang/de_DE.lang b/src/main/resources/assets/notfine/lang/de_DE.lang new file mode 100644 index 000000000..a35b5f6f9 --- /dev/null +++ b/src/main/resources/assets/notfine/lang/de_DE.lang @@ -0,0 +1,54 @@ +options.button.detail=Details... +options.button.other=Sonstige... +options.button.particle=Partikel... +options.button.sky=Atmosphäre... +options.off=Aus +options.on=An +options.cloud_height=Wolkenhöhe +options.cloud_scale=Wolkengröße +options.gui_background=Hintergrund +options.gui_background.-1=Standard +options.gui_background.0=Sand +options.gui_background.1=Myzel +options.gui_background.2=Steinziegel +options.gui_background.3=Bemooste Steinziegel +options.gui_background.4=Eichenholzbretter +options.gui_background.5=Birkenholzbretter +options.guiScale.massive=Riesig +options.mode_cloud_translucency=Wolkendurchlässigkeit +options.mode_cloud_translucency.-1=Standard +options.mode_cloud_translucency.0=Immer +options.mode_cloud_translucency.1=Niemals +options.mode_clouds=Wolken +options.mode_clouds.-1=Standard +options.mode_clouds.0=Schön +options.mode_clouds.1=Schnell +options.mode_clouds.2=Aus +options.mode_glint_inv=Inventar-Verzauberungseffekt +options.mode_glint_world=Welt-Verzauberungseffekt +options.mode_gui_background=Menühintergründe +options.mode_leaves=Laub +options.mode_leaves.-1=Standard +options.mode_leaves.0=Schön +options.mode_leaves.1=Schnell +options.mode_leaves.2=Schlau +options.mode_leaves.3=Schön [Hybrid] +options.mode_leaves.4=Schnell [Hybrid] +options.mode_shadows=Objektschatten +options.mode_shadows.-1=Standard +options.mode_shadows.0=An +options.mode_shadows.1=Aus +options.mode_sky=Himmel +options.mode_vignette=Vignette +options.mode_vignette.-1=Standard +options.mode_vignette.0=An +options.mode_vignette.1=Aus +options.particles_enc_table=Verzauberungspartikel +options.particles_void=Leerenpartikel +options.render_distance_clouds=Wolken-Renderdistanz +options.title.detail=Detaileinstellungen | NotFine alpha +options.title.other=Sonstige Einstellungen | NotFine alpha +options.title.particle=Partikeleinstellungen | NotFine alpha +options.title.sky=Atmosphäreneinstellungen | NotFine alpha +options.title.video=Grafikeinstellungen | NotFine alpha +options.total_stars=Sternendichte diff --git a/src/main/resources/assets/notfine/lang/en_US.lang b/src/main/resources/assets/notfine/lang/en_US.lang new file mode 100644 index 000000000..205d02009 --- /dev/null +++ b/src/main/resources/assets/notfine/lang/en_US.lang @@ -0,0 +1,62 @@ +options.button.detail=Details... +options.button.other=Other... +options.button.particle=Particles... +options.button.sky=Atmosphere... +options.off=Off +options.on=On +options.cloud_height=Cloud Height +options.cloud_scale=Cloud Scale +options.gui_background=Background +options.gui_background.-1=Default +options.gui_background.0=Sand +options.gui_background.1=Mycelium +options.gui_background.2=Stonebrick +options.gui_background.3=Mossy Stonebrick +options.gui_background.4=Oak Planks +options.gui_background.5=Birch Planks +options.guiScale.massive=Massive +options.mode_cloud_translucency=Cloud Translucency +options.mode_cloud_translucency.-1=Default +options.mode_cloud_translucency.0=Always +options.mode_cloud_translucency.1=Never +options.mode_clouds=Clouds +options.mode_clouds.-1=Default +options.mode_clouds.0=Fancy +options.mode_clouds.1=Fast +options.mode_clouds.2=Off +options.mode_dropped_items=Dropped Items +options.mode_dropped_items.-1=Default +options.mode_dropped_items.0=Fancy +options.mode_dropped_items.1=Fast +options.mode_glint_inv=GUI Enchant VFX +options.mode_glint_world=World Enchant VFX +options.mode_gui_background=Menu Backgrounds +options.mode_leaves=Foliage +options.mode_leaves.-1=Default +options.mode_leaves.0=Fancy +options.mode_leaves.1=Fast +options.mode_leaves.2=Smart +options.mode_leaves.3=Hybrid Fancy +options.mode_leaves.4=Hybrid Fast +options.mode_shadows=Entity Shadows +options.mode_shadows.-1=Default +options.mode_shadows.0=On +options.mode_shadows.1=Off +options.mode_sky=Sky +options.mode_water=Water +options.mode_water.-1=Default +options.mode_water.0=Fancy +options.mode_water.1=Fast +options.mode_vignette=Vignette +options.mode_vignette.-1=Default +options.mode_vignette.0=On +options.mode_vignette.1=Off +options.particles_enc_table=Enchantment Particles +options.particles_void=Void Particles +options.render_distance_clouds=Cloud Render Distance +options.title.detail=Detail Settings | NotFine alpha +options.title.other=Other Settings | NotFine alpha +options.title.particle=Particle Settings | NotFine alpha +options.title.sky=Atmosphere Settings | NotFine alpha +options.title.video=Video Settings | NotFine alpha +options.total_stars=Star Density diff --git a/src/main/resources/assets/notfine/lang/zh_CN.lang b/src/main/resources/assets/notfine/lang/zh_CN.lang new file mode 100644 index 000000000..5ed058622 --- /dev/null +++ b/src/main/resources/assets/notfine/lang/zh_CN.lang @@ -0,0 +1,54 @@ +options.button.detail=细节设置 +options.button.other=其他设置 +options.button.particle=粒子设置 +options.button.sky=大气设置 +options.off=关闭 +options.on=开启 +options.cloud_height=云高度 +options.cloud_scale=云优化 +options.gui_background=背景 +options.gui_background.-1=默认 +options.gui_background.0=沙子 +options.gui_background.1=菌丝 +options.gui_background.2=石砖 +options.gui_background.3=苔石砖 +options.gui_background.4=橡木木板 +options.gui_background.5=白桦木板 +options.guiScale.massive=巨大 +options.mode_cloud_translucency=云半透明 +options.mode_cloud_translucency.-1=默认 +options.mode_cloud_translucency.0=总是 +options.mode_cloud_translucency.1=从不 +options.mode_clouds=云 +options.mode_clouds.-1=默认 +options.mode_clouds.0=精致 +options.mode_clouds.1=快速 +options.mode_clouds.2=关闭 +options.mode_glint_inv=GUI附魔效果 +options.mode_glint_world=世界附魔效果 +options.mode_gui_background=菜单背景 +options.mode_leaves=树叶 +options.mode_leaves.-1=默认 +options.mode_leaves.0=精致 +options.mode_leaves.1=快速 +options.mode_leaves.2=智能 +options.mode_leaves.3=精致混合 +options.mode_leaves.4=快速混合 +options.mode_shadows=实体阴影 +options.mode_shadows.-1=默认 +options.mode_shadows.0=开启 +options.mode_shadows.1=关闭 +options.mode_sky=天空 +options.mode_vignette=晕影 +options.mode_vignette.-1=默认 +options.mode_vignette.0=开启 +options.mode_vignette.1=关闭 +options.particles_enc_table=附魔粒子 +options.particles_void=虚空粒子 +options.render_distance_clouds=云渲染距离 +options.title.detail=细节设置 | NotFine alpha +options.title.other=其他设置 | NotFine alpha +options.title.particle=粒子设置 | NotFine alpha +options.title.sky=大气设置 | NotFine alpha +options.title.video=视频设置 | NotFine alpha +options.total_stars=星星密度 diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index b14cd4c88..6718e4cb6 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -1,17 +1,51 @@ -[ { - "modid": "${modId}", - "name": "${modName}", - "description": "The little angle that supports shaders while saving your FPS from a certain death", - "version": "${modVersion}", - "mcversion": "1.7.10", - "url": "", - "updateUrl": "", - "authors": ["eigenraven","vlaetansky","karyonix","sonic ether","id_miner","daxnitro"], - "credits": "Based on daxnitro's GLSL Shaders Mod.", - "logoFile": "", - "screenshots": [], - "parent":"", - "dependencies": [] + "modListVersion": 2, + "modList": [ + { + "modid": "${modId}", + "name": "${modName}", + "description": "The little angle that supports shaders while saving your FPS from a certain death", + "version": "${modVersion}", + "mcversion": "1.7.10", + "url": "https://github.com/GTNewHorizons/angelica", + "updateUrl": "", + "authors": [ + "eigenraven", + "mitchej123", + "glowredman", + "caedis", + "vlaetansky", + "karyonix", + "sonic ether", + "id_miner", + "daxnitro" + ], + "credits": "Based on daxnitro's GLSL Shaders Mod.", + "logoFile": "", + "screenshots": [], + "parent": "", + "dependencies": [] + }, + { + "modid": "notfine", + "name": "NotFine", + "description": "Extra video settings for Minecraft 1.7.10 implemented with Mixins", + "version": "${modVersion}", + "mcversion": "${minecraftVersion}", + "url": "https://github.com/jss2a98aj/NotFine", + "updateUrl": "", + "authorList": [ + "jss2a98aj" + ], + "credits": "", + "logoFile": "", + "screenshots": [], + "parent": "", + "requiredMods": [], + "dependencies": [], + "dependants": [], + "useDependencyInformation": true + } + ] } -] + diff --git a/src/main/resources/mixins.notfine.early.json b/src/main/resources/mixins.notfine.early.json new file mode 100644 index 000000000..1972bac32 --- /dev/null +++ b/src/main/resources/mixins.notfine.early.json @@ -0,0 +1,8 @@ +{ + "required": true, + "minVersion": "0.7.11", + "package": "jss.notfine.mixins.early", + "refmap": "mixins.angelica.refmap.json", + "target": "@env(DEFAULT)", + "compatibilityLevel": "JAVA_8" +} diff --git a/src/main/resources/mixins.notfine.json b/src/main/resources/mixins.notfine.json new file mode 100644 index 000000000..ca3673361 --- /dev/null +++ b/src/main/resources/mixins.notfine.json @@ -0,0 +1,11 @@ +{ + "required": true, + "minVersion": "0.7.11", + "package": "jss.notfine.mixins", + "refmap": "mixins.angelica.refmap.json", + "target": "@env(DEFAULT)", + "compatibilityLevel": "JAVA_8", + "mixins": [], + "client": [], + "server": [] +} diff --git a/src/main/resources/mixins.notfine.late.json b/src/main/resources/mixins.notfine.late.json new file mode 100644 index 000000000..97b6700dd --- /dev/null +++ b/src/main/resources/mixins.notfine.late.json @@ -0,0 +1,8 @@ +{ + "required": true, + "minVersion": "0.7.11", + "package": "jss.notfine.mixins.late", + "refmap": "mixins.angelica.refmap.json", + "target": "@env(DEFAULT)", + "compatibilityLevel": "JAVA_8" +} From 542ffffe55a281c65bba679342bcd68164ce0dda Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 19 Sep 2023 19:27:12 -0700 Subject: [PATCH 002/301] Add Shaders button to NotFine's video options Small refactors --- .../gtnewhorizons/angelica/AngelicaMod.java | 16 + .../angelica/client/Shaders.java | 410 +++++++----------- .../angelica/client/ShadersTex.java | 2 +- .../client/gui/AngelicaVideoSettings.java | 26 ++ .../angelica/client/{ => gui}/GuiShaders.java | 174 +++----- .../angelica/client/gui/GuiShadersButton.java | 24 + .../client/{ => gui}/GuiSlotShaders.java | 5 +- .../early/settings/MixinGuiVideoSettings.java | 2 +- src/main/java/jss/notfine/NotFine.java | 3 +- .../jss/notfine/core/LoadMenuButtons.java | 2 + .../jss/notfine/core/SettingsManager.java | 2 +- .../java/jss/notfine/gui/GuiCustomMenu.java | 42 +- .../notfine/gui/GuiCustomSettingsRowList.java | 30 +- .../java/jss/notfine/gui/ISettingHandler.java | 7 + .../java/jss/notfine/gui/ISettingsEnum.java | 17 + .../java/jss/notfine/gui/MenuButtonLists.java | 57 ++- .../early/minecraft/MixinGameSettings.java | 3 +- .../resources/assets/angelica/lang/en_US.lang | 1 + 18 files changed, 412 insertions(+), 411 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java rename src/main/java/com/gtnewhorizons/angelica/client/{ => gui}/GuiShaders.java (63%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShadersButton.java rename src/main/java/com/gtnewhorizons/angelica/client/{ => gui}/GuiSlotShaders.java (93%) create mode 100644 src/main/java/jss/notfine/gui/ISettingHandler.java create mode 100644 src/main/java/jss/notfine/gui/ISettingsEnum.java create mode 100644 src/main/resources/assets/angelica/lang/en_US.lang diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index c15af07a2..dc345d6f4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -1,6 +1,12 @@ package com.gtnewhorizons.angelica; +import com.gtnewhorizons.angelica.client.gui.AngelicaVideoSettings; import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.relauncher.Side; +import jss.notfine.gui.GuiCustomMenu; +import jss.notfine.gui.ISettingsEnum; +import jss.notfine.gui.MenuButtonLists; @Mod( modid = "angelica", @@ -9,4 +15,14 @@ acceptedMinecraftVersions = "[1.7.10]", acceptableRemoteVersions = "*") public class AngelicaMod { + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent event) { + if (event.getSide() == Side.CLIENT) { + MenuButtonLists.addAdditionalEntry(MenuButtonLists.VIDEO, AngelicaVideoSettings.SHADERS); + GuiCustomMenu.addButtonHandler(AngelicaVideoSettings.class, (xPosition, yPosition, setting) -> { + ISettingsEnum settingsEnum = (ISettingsEnum) setting; + return settingsEnum.createButton(xPosition, yPosition, setting); + }); + } + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index 3728a27b1..51d24d951 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -445,16 +445,16 @@ public class Shaders { public static final int[] texMagFilValue = { GL11.GL_NEAREST, GL11.GL_LINEAR }; // shaderpack - static IShaderPack shaderPack = null; - static File currentshader; - static String currentshadername; - static String packNameNone = "(none)"; - static String packNameDefault = "(internal)"; - static String shaderpacksdirname = "shaderpacks"; - static String optionsfilename = "optionsshaders.txt"; - static File shadersdir = new File(Minecraft.getMinecraft().mcDataDir, "shaders"); - static File shaderpacksdir = new File(Minecraft.getMinecraft().mcDataDir, shaderpacksdirname); - static File configFile = new File(Minecraft.getMinecraft().mcDataDir, optionsfilename); + public static IShaderPack shaderPack = null; + public static File currentshader; + public static String currentshadername; + public static String packNameNone = "(none)"; + public static String packNameDefault = "(internal)"; + public static String shaderpacksdirname = "shaderpacks"; + public static String optionsfilename = "optionsshaders.txt"; + public static File shadersdir = new File(Minecraft.getMinecraft().mcDataDir, "shaders"); + public static File shaderpacksdir = new File(Minecraft.getMinecraft().mcDataDir, shaderpacksdirname); + public static File configFile = new File(Minecraft.getMinecraft().mcDataDir, optionsfilename); public static final boolean enableShadersOption = true; private static final boolean enableShadersDebug = true; @@ -516,15 +516,6 @@ public class Shaders { static final IntBuffer[] drawBuffersBuffer = nextIntBufferArray(ProgramCount, MaxDrawBuffers); - // static final String ofVersion = "OptiFine_x.x.x_HD_U_xx"; - // static final String ofVersion = Config.VERSION; - - // static int lastversion = version; - // static int updateinterval = 48; - // public static final String siteurl = "http://glslshadersof.no-ip.org"; - // public static final String updatecheckurl = "http:....../lastversion145.html"; - // static JFrame frame; - static { drawBuffersNone.limit(0); drawBuffersColorAtt0.put(GL_COLOR_ATTACHMENT0_EXT).position(0).limit(1); @@ -832,7 +823,7 @@ public static void loadShaderPack() { // else System.out.println("[Shaders] Shader loaded: " + currentshadername); // } - static List listofShaders() { + public static List listofShaders() { List list = new ArrayList<>(); list.add(packNameNone); list.add(packNameDefault); @@ -858,17 +849,6 @@ static String versiontostring(int vv) { + Integer.toString(Integer.parseInt(vs.substring(5))); } - static void checkOptifine() { - /* - * try { System.out.println("[Shaders] Required OptiFine version : " + ofVersion); String configVersion = - * (String)(Config.class.getDeclaredField("VERSION").get(null)); - * System.out.println("[Shaders] Detected OptiFine version : "+ configVersion); if - * (configVersion.equals(ofVersion) ) { System.out.println("[Shaders] ShadersMod loaded. version: " + - * versiontostring(version)); } else { System.err.println("[Shaders] Wrong OptiFine version!"); System.exit(-1); - * } } catch(Exception e) { System.err.println("[Shaders] OptiFine missing or wrong version! Install OptiFine " - * +ofVersion+" first and then the ShadersMod!"); System.exit(-1); } //Tessellator.shaders = true; - */ - } public static int checkFramebufferStatus(String location) { int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); @@ -1492,7 +1472,7 @@ private static int createFragShader(String filename) { // TODO: refactor this mess private static void processFragShaderLine(String line, String filename) { if (line.matches("#version .*")) { - + // Do nothing } else if (line.matches("uniform [ _a-zA-Z0-9]+ shadow;.*")) { if (usedShadowDepthBuffers < 1) usedShadowDepthBuffers = 1; } else if (line.matches("uniform [ _a-zA-Z0-9]+ watershadow;.*")) { @@ -1593,222 +1573,156 @@ private static void processFragShaderLine(String line, String filename) { AngelicaTweaker.LOGGER.debug("shadowHardwareFiltering1"); shadowHardwareFilteringEnabled[1] = true; - } else if (line - .matches("[ \t]*const[ \t]*bool[ \t]*(shadowtex0Mipmap|shadowtexMipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowtex0Mipmap"); - shadowMipmapEnabled[0] = true; - - } else - if (line.matches("[ \t]*const[ \t]*bool[ \t]*(shadowtex1Mipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowtex1Mipmap"); - shadowMipmapEnabled[1] = true; - - } else if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowcolor0Mipmap|shadowColor0Mipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowcolor0Mipmap"); - shadowColorMipmapEnabled[0] = true; - - } else - if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowcolor1Mipmap|shadowColor1Mipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowcolor1Mipmap"); - shadowColorMipmapEnabled[1] = true; - - } else - if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowtex0Nearest|shadowtexNearest|shadow0MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowtex0Nearest"); - shadowFilterNearest[0] = true; - - } else - if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowtex1Nearest|shadow1MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowtex1Nearest"); - shadowFilterNearest[1] = true; - - } else - if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowcolor0Nearest|shadowColor0Nearest|shadowColor0MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowcolor0Nearest"); - shadowColorFilterNearest[0] = true; - - } else - if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowcolor1Nearest|shadowColor1Nearest|shadowColor1MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowcolor1Nearest"); - shadowColorFilterNearest[1] = true; - - // Wetness half life - } else - if (line.matches("/\\* WETNESSHL:[0-9\\.]+ \\*/.*")) { - String[] parts = line.split("(:| )", 4); - AngelicaTweaker.LOGGER.debug("Wetness halflife: " + parts[2]); - wetnessHalfLife = Float.parseFloat(parts[2]); - - } else if (line.matches( - "[ \t]*const[ \t]*float[ \t]*wetnessHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("Wetness halflife: " + parts[1]); - wetnessHalfLife = Float.parseFloat(parts[1]); - - // Dryness halflife - } else - if (line.matches("/\\* DRYNESSHL:[0-9\\.]+ \\*/.*")) { - String[] parts = line.split("(:| )", 4); - AngelicaTweaker.LOGGER.debug("Dryness halflife: " + parts[2]); - drynessHalfLife = Float.parseFloat(parts[2]); - - } else if (line.matches( - "[ \t]*const[ \t]*float[ \t]*drynessHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("Dryness halflife: " + parts[1]); - drynessHalfLife = Float.parseFloat(parts[1]); - - // Eye brightness halflife - } else - if (line.matches( - "[ \t]*const[ \t]*float[ \t]*eyeBrightnessHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER - .debug("Eye brightness halflife: " + parts[1]); - eyeBrightnessHalflife = Float.parseFloat(parts[1]); - - // Center depth halflife - } else - if (line.matches( - "[ \t]*const[ \t]*float[ \t]*centerDepthHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER - .debug("Center depth halflife: " + parts[1]); - centerDepthSmoothHalflife = Float.parseFloat(parts[1]); - - // Sun path rotation - } else - if (line.matches( - "[ \t]*const[ \t]*float[ \t]*sunPathRotation[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER - .debug("Sun path rotation: " + parts[1]); - sunPathRotation = Float.parseFloat(parts[1]); - - // Ambient occlusion level - } else - if (line.matches( - "[ \t]*const[ \t]*float[ \t]*ambientOcclusionLevel[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER - .debug("AO Level: " + parts[1]); - aoLevel = Float.parseFloat(parts[1]); - blockAoLight = 1.0f - aoLevel; - - // super sampling - } else - if (line.matches( - "[ \t]*const[ \t]*int[ \t]*superSamplingLevel[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - int ssaa = Integer.parseInt(parts[1]); - if (ssaa > 1) { - AngelicaTweaker.LOGGER.debug( - "Super sampling level: " + ssaa - + "x"); - superSamplingLevel = ssaa; - } else { - superSamplingLevel = 1; - } - - // noise texture - } else - if (line.matches( - "[ \t]*const[ \t]*int[ \t]*noiseTextureResolution[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER - .debug("Noise texture enabled"); - AngelicaTweaker.LOGGER.debug( - "Noise texture resolution: " - + parts[1]); - noiseTextureResolution = Integer - .parseInt(parts[1]); - noiseTextureEnabled = true; - - } else - if (line.matches( - "[ \t]*const[ \t]*int[ \t]*\\w+Format[ \t]*=[ \t]*[RGBA81632F]*[ \t]*;.*")) { - Matcher m = gbufferFormatPattern - .matcher(line); - m.matches(); - String name = m.group(1); - String value = m.group(2); - int bufferindex = getBufferIndexFromString( - name); - int format = getTextureFormatFromString( - value); - if (bufferindex >= 0 && format != 0) { - gbuffersFormat[bufferindex] = format; - AngelicaTweaker.LOGGER.debug( - "{} format: {}", - name, - value); - } - // gaux4 - } else - if (line.matches( - "/\\* GAUX4FORMAT:RGBA32F \\*/.*")) { - AngelicaTweaker.LOGGER.debug( - "gaux4 format : RGB32AF"); - gbuffersFormat[7] = GL_RGBA32F; - } else - if (line.matches( - "/\\* GAUX4FORMAT:RGB32F \\*/.*")) { - AngelicaTweaker.LOGGER.debug( - "gaux4 format : RGB32F"); - gbuffersFormat[7] = GL_RGB32F; - } else - if (line.matches( - "/\\* GAUX4FORMAT:RGB16 \\*/.*")) { - AngelicaTweaker.LOGGER - .debug( - "gaux4 format : RGB16"); - gbuffersFormat[7] = GL_RGB16; - - // Mipmap stuff - } else - if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*\\w+MipmapEnabled[ \t]*=[ \t]*true[ \t]*;.*")) { - if (filename.matches( - ".*composite[0-9]?.fsh") - || filename - .matches( - ".*final.fsh")) { - Matcher m = gbufferMipmapEnabledPattern - .matcher( - line); - m.matches(); - String name = m - .group(1); - // String value - // =m.group(2); - int bufferindex = getBufferIndexFromString( - name); - if (bufferindex - >= 0) { - newCompositeMipmapSetting |= (1 - << bufferindex); - AngelicaTweaker.LOGGER - .debug( - "{} mipmap enabled for {}", - name, - filename); - } - } - } else - if (line.matches( - "/\\* DRAWBUFFERS:[0-7N]* \\*/.*")) { - String[] parts = line - .split( - "(:| )", - 4); - newDrawBufSetting = parts[2]; - } + } else if (line.matches( + "[ \t]*const[ \t]*bool[ \t]*(shadowtex0Mipmap|shadowtexMipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { + AngelicaTweaker.LOGGER.debug("shadowtex0Mipmap"); + shadowMipmapEnabled[0] = true; + + } else if (line.matches("[ \t]*const[ \t]*bool[ \t]*(shadowtex1Mipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { + AngelicaTweaker.LOGGER.debug("shadowtex1Mipmap"); + shadowMipmapEnabled[1] = true; + + } else if (line.matches( + "[ \t]*const[ \t]*bool[ \t]*(shadowcolor0Mipmap|shadowColor0Mipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { + AngelicaTweaker.LOGGER.debug("shadowcolor0Mipmap"); + shadowColorMipmapEnabled[0] = true; + + } else if (line.matches( + "[ \t]*const[ \t]*bool[ \t]*(shadowcolor1Mipmap|shadowColor1Mipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { + AngelicaTweaker.LOGGER.debug("shadowcolor1Mipmap"); + shadowColorMipmapEnabled[1] = true; + + } else if (line.matches( + "[ \t]*const[ \t]*bool[ \t]*(shadowtex0Nearest|shadowtexNearest|shadow0MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { + AngelicaTweaker.LOGGER.debug("shadowtex0Nearest"); + shadowFilterNearest[0] = true; + + } else if (line.matches( + "[ \t]*const[ \t]*bool[ \t]*(shadowtex1Nearest|shadow1MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { + AngelicaTweaker.LOGGER.debug("shadowtex1Nearest"); + shadowFilterNearest[1] = true; + + } else if (line.matches( + "[ \t]*const[ \t]*bool[ \t]*(shadowcolor0Nearest|shadowColor0Nearest|shadowColor0MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { + AngelicaTweaker.LOGGER.debug("shadowcolor0Nearest"); + shadowColorFilterNearest[0] = true; + + } else if (line.matches( + "[ \t]*const[ \t]*bool[ \t]*(shadowcolor1Nearest|shadowColor1Nearest|shadowColor1MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { + AngelicaTweaker.LOGGER.debug("shadowcolor1Nearest"); + shadowColorFilterNearest[1] = true; + + // Wetness half life + } else if (line.matches("/\\* WETNESSHL:[0-9\\.]+ \\*/.*")) { + String[] parts = line.split("(:| )", 4); + AngelicaTweaker.LOGGER.debug("Wetness halflife: " + parts[2]); + wetnessHalfLife = Float.parseFloat(parts[2]); + + } else if (line.matches("[ \t]*const[ \t]*float[ \t]*wetnessHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { + String[] parts = line.split("(=[ \t]*|;)"); + AngelicaTweaker.LOGGER.debug("Wetness halflife: " + parts[1]); + wetnessHalfLife = Float.parseFloat(parts[1]); + + // Dryness halflife + } else if (line.matches("/\\* DRYNESSHL:[0-9\\.]+ \\*/.*")) { + String[] parts = line.split("(:| )", 4); + AngelicaTweaker.LOGGER.debug("Dryness halflife: " + parts[2]); + drynessHalfLife = Float.parseFloat(parts[2]); + + } else if (line.matches("[ \t]*const[ \t]*float[ \t]*drynessHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { + String[] parts = line.split("(=[ \t]*|;)"); + AngelicaTweaker.LOGGER.debug("Dryness halflife: " + parts[1]); + drynessHalfLife = Float.parseFloat(parts[1]); + + // Eye brightness halflife + } else if (line.matches("[ \t]*const[ \t]*float[ \t]*eyeBrightnessHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { + String[] parts = line.split("(=[ \t]*|;)"); + AngelicaTweaker.LOGGER.debug("Eye brightness halflife: " + parts[1]); + eyeBrightnessHalflife = Float.parseFloat(parts[1]); + + // Center depth halflife + } else if (line.matches("[ \t]*const[ \t]*float[ \t]*centerDepthHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { + String[] parts = line.split("(=[ \t]*|;)"); + AngelicaTweaker.LOGGER.debug("Center depth halflife: " + parts[1]); + centerDepthSmoothHalflife = Float.parseFloat(parts[1]); + + // Sun path rotation + } else if (line.matches("[ \t]*const[ \t]*float[ \t]*sunPathRotation[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { + String[] parts = line.split("(=[ \t]*|;)"); + AngelicaTweaker.LOGGER.debug("Sun path rotation: " + parts[1]); + sunPathRotation = Float.parseFloat(parts[1]); + + // Ambient occlusion level + } else if (line.matches("[ \t]*const[ \t]*float[ \t]*ambientOcclusionLevel[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { + String[] parts = line.split("(=[ \t]*|;)"); + AngelicaTweaker.LOGGER.debug("AO Level: " + parts[1]); + aoLevel = Float.parseFloat(parts[1]); + blockAoLight = 1.0f - aoLevel; + + // super sampling + } else if (line.matches("[ \t]*const[ \t]*int[ \t]*superSamplingLevel[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { + String[] parts = line.split("(=[ \t]*|;)"); + int ssaa = Integer.parseInt(parts[1]); + if (ssaa > 1) { + AngelicaTweaker.LOGGER.debug("Super sampling level: " + ssaa + "x"); + superSamplingLevel = ssaa; + } else { + superSamplingLevel = 1; + } + + // noise texture + } else if (line.matches("[ \t]*const[ \t]*int[ \t]*noiseTextureResolution[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { + String[] parts = line.split("(=[ \t]*|;)"); + AngelicaTweaker.LOGGER.debug("Noise texture enabled"); + AngelicaTweaker.LOGGER.debug("Noise texture resolution: " + parts[1]); + noiseTextureResolution = Integer.parseInt(parts[1]); + noiseTextureEnabled = true; + + } else if (line.matches("[ \t]*const[ \t]*int[ \t]*\\w+Format[ \t]*=[ \t]*[RGBA81632F]*[ \t]*;.*")) { + Matcher m = gbufferFormatPattern.matcher(line); + m.matches(); + String name = m.group(1); + String value = m.group(2); + int bufferindex = getBufferIndexFromString(name); + int format = getTextureFormatFromString(value); + if (bufferindex >= 0 && format != 0) { + gbuffersFormat[bufferindex] = format; + AngelicaTweaker.LOGGER.debug("{} format: {}", name, value); + } + // gaux4 + } else if (line.matches("/\\* GAUX4FORMAT:RGBA32F \\*/.*")) { + AngelicaTweaker.LOGGER.debug("gaux4 format : RGB32AF"); + gbuffersFormat[7] = GL_RGBA32F; + } else if (line.matches("/\\* GAUX4FORMAT:RGB32F \\*/.*")) { + AngelicaTweaker.LOGGER.debug("gaux4 format : RGB32F"); + gbuffersFormat[7] = GL_RGB32F; + } else if (line.matches("/\\* GAUX4FORMAT:RGB16 \\*/.*")) { + AngelicaTweaker.LOGGER.debug("gaux4 format : RGB16"); + gbuffersFormat[7] = GL_RGB16; + + // Mipmap stuff + } else if (line.matches("[ \t]*const[ \t]*bool[ \t]*\\w+MipmapEnabled[ \t]*=[ \t]*true[ \t]*;.*")) { + if (filename.matches(".*composite[0-9]?.fsh") || filename.matches(".*final.fsh")) { + Matcher m = gbufferMipmapEnabledPattern.matcher(line); + m.matches(); + String name = m.group(1); + // String value + // =m.group(2); + int bufferindex = getBufferIndexFromString(name); + if (bufferindex >= 0) { + newCompositeMipmapSetting |= (1 << bufferindex); + AngelicaTweaker.LOGGER.debug( + "{} mipmap enabled for {}", + name, + filename); + } + } + } else if (line.matches("/\\* DRAWBUFFERS:[0-7N]* \\*/.*")) { + String[] parts = line.split( + "(:| )", + 4); + newDrawBufSetting = parts[2]; + } } private static boolean printLogInfo(int obj, String name) { diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java index f2d0aa357..d501a1529 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java @@ -926,7 +926,7 @@ public static void loadLayeredTexture(LayeredTexture tex, IResourceManager manag } /* update block texture filter +/- items texture */ - static void updateTextureMinMagFilter() { + public static void updateTextureMinMagFilter() { TextureManager texman = Minecraft.getMinecraft().getTextureManager(); ITextureObject texObj = texman.getTexture(TextureMap.locationBlocksTexture); if (texObj != null) { diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java new file mode 100644 index 000000000..b63fd1278 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java @@ -0,0 +1,26 @@ +package com.gtnewhorizons.angelica.client.gui; + +import jss.notfine.gui.ISettingsEnum; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.resources.I18n; + +public enum AngelicaVideoSettings implements ISettingsEnum { + SHADERS("options.button.shader"); + + private final String unlocalizedButton; + AngelicaVideoSettings(String unlocalizedButton) { + this.unlocalizedButton = unlocalizedButton; + } + public final String getButtonLabel() { + return I18n.format(unlocalizedButton); + } + + public final String getTitleLabel() { + return I18n.format("options.title." + name().toLowerCase()); + } + + public GuiButton createButton(int xPosition, int yPosition, Object setting) { + AngelicaVideoSettings angelicaVideoSettings = (AngelicaVideoSettings) setting; + return new GuiShadersButton(xPosition, yPosition, angelicaVideoSettings); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/GuiShaders.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShaders.java similarity index 63% rename from src/main/java/com/gtnewhorizons/angelica/client/GuiShaders.java rename to src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShaders.java index f707b25b8..cf31da1ea 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/GuiShaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShaders.java @@ -1,10 +1,12 @@ -package com.gtnewhorizons.angelica.client; +package com.gtnewhorizons.angelica.client.gui; import java.io.File; import java.io.IOException; import java.net.URI; import java.util.List; +import com.gtnewhorizons.angelica.client.Shaders; +import com.gtnewhorizons.angelica.client.ShadersTex; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; @@ -23,15 +25,33 @@ public class GuiShaders extends GuiScreen { public boolean needReinit; /* - * private class GuiListShaderpacks { int posX,posY,sizeX,sizeY; int viewPosY; int itemHeight = 20; int selection; - * ArrayList listShaderpacks; public void draw() { Tessellator tess = Tessellator.instance; int listSize = - * listShaderpacks.size(); int i,j; for (i=viewPosY/itemHeight, j=Math.min((viewPosY+sizeY)/itemHeight,listSize); - * i listShaderpacks; + public void draw() { + Tessellator tess = Tessellator.instance; + int listSize = listShaderpacks.size(); + int i,j; + for (i=viewPosY/itemHeight, j=Math.min((viewPosY+sizeY)/itemHeight,listSize); i buttonList = this.buttonList; int width = this.width; int height = this.height; - buttonList.add( - new GuiButton( - 17, - width * 3 / 4 - 60, - 30, - 160, - 18, - "NormalMap: " + toStringOnOff(Shaders.configNormalMap))); - buttonList.add( - new GuiButton( - 18, - width * 3 / 4 - 60, - 50, - 160, - 18, - "SpecularMap: " + toStringOnOff(Shaders.configSpecularMap))); - buttonList.add( - new GuiButton( - 15, - width * 3 / 4 - 60, - 70, - 160, - 18, - "RenderResMul: " + String.format("%.04f", Shaders.configRenderResMul))); - buttonList.add( - new GuiButton( - 16, - width * 3 / 4 - 60, - 90, - 160, - 18, - "ShadowResMul: " + String.format("%.04f", Shaders.configShadowResMul))); - buttonList.add( - new GuiButton( - 10, - width * 3 / 4 - 60, - 110, - 160, - 18, - "HandDepth: " + String.format("%.04f", Shaders.configHandDepthMul))); - buttonList.add( - new GuiButton( - 9, - width * 3 / 4 - 60, - 130, - 160, - 18, - "CloudShadow: " + toStringOnOff(Shaders.configCloudShadow))); - // buttonList.add(new GuiButton(14, width *3 /4 -60, 150, 160, 18, "ShadowClipFrustrum: " - // +toStringOnOff(Shaders.configShadowClipFrustrum))); - buttonList.add( - new GuiButton( - 4, - width * 3 / 4 - 60, - 170, - 160, - 18, - "tweakBlockDamage: " + toStringOnOff(Shaders.configTweakBlockDamage))); - buttonList.add( - new GuiButton( - 19, - width * 3 / 4 - 60, - 190, - 160, - 18, - "OldLighting: " + toStringOnOff(Shaders.configOldLighting))); - // buttonList.add(new GuiButton(11, width *3 /4 -60, 210, 160, 18, "Tex Min: " - // +Shaders.texMinFilDesc[Shaders.configTexMinFilB])); - // buttonList.add(new GuiButton(12, width *3 /4 -60, 230, 160, 18, "Tex_n Mag: " - // +Shaders.texMagFilDesc[Shaders.configTexMagFilN])); - // buttonList.add(new GuiButton(13, width *3 /4 -60, 250, 160, 18, "Tex_s Mag: " - // +Shaders.texMagFilDesc[Shaders.configTexMagFilS])); + buttonList.add(new GuiButton(17, width * 3 / 4 - 60, 30, 160, 18, "NormalMap: " + toStringOnOff(Shaders.configNormalMap))); + buttonList.add(new GuiButton(18, width * 3 / 4 - 60, 50, 160, 18, "SpecularMap: " + toStringOnOff(Shaders.configSpecularMap))); + buttonList.add(new GuiButton(15, width * 3 / 4 - 60, 70, 160, 18, "RenderResMul: " + String.format("%.04f", Shaders.configRenderResMul))); + buttonList.add(new GuiButton(16, width * 3 / 4 - 60, 90, 160, 18, "ShadowResMul: " + String.format("%.04f", Shaders.configShadowResMul))); + buttonList.add(new GuiButton(10, width * 3 / 4 - 60, 110, 160, 18, "HandDepth: " + String.format("%.04f", Shaders.configHandDepthMul))); + buttonList.add(new GuiButton(9, width * 3 / 4 - 60, 130, 160, 18, "CloudShadow: " + toStringOnOff(Shaders.configCloudShadow))); + // buttonList.add(new GuiButton(14, width *3 /4 -60, 150, 160, 18, "ShadowClipFrustrum: " +toStringOnOff(Shaders.configShadowClipFrustrum))); + buttonList.add(new GuiButton(4, width * 3 / 4 - 60, 170, 160, 18, "tweakBlockDamage: " + toStringOnOff(Shaders.configTweakBlockDamage))); + buttonList.add(new GuiButton(19, width * 3 / 4 - 60, 190, 160, 18, "OldLighting: " + toStringOnOff(Shaders.configOldLighting))); + // buttonList.add(new GuiButton(11, width *3 /4 -60, 210, 160, 18, "Tex Min: " +Shaders.texMinFilDesc[Shaders.configTexMinFilB])); + // buttonList.add(new GuiButton(12, width *3 /4 -60, 230, 160, 18, "Tex_n Mag: " +Shaders.texMagFilDesc[Shaders.configTexMagFilN])); + // buttonList.add(new GuiButton(13, width *3 /4 -60, 250, 160, 18, "Tex_s Mag: " +Shaders.texMagFilDesc[Shaders.configTexMagFilS])); buttonList.add(new GuiButton(6, width * 3 / 4 - 60, height - 25, 160, 20, "Done")); buttonList.add(new GuiButton(5, width / 4 - 80, height - 25, 160, 20, "Open shaderpacks folder")); this.shaderList = new GuiSlotShaders(this); @@ -139,20 +99,20 @@ public void initGui() { * actionPerformed Fired when a control is clicked. This is the equivalent of * ActionListener.actionPerformed(ActionEvent e). */ - protected void actionPerformed(GuiButton par1GuiButton) { - if (par1GuiButton.enabled) // enabled + protected void actionPerformed(GuiButton guiButton) { + if (guiButton.enabled) // enabled { - switch (par1GuiButton.id) // id + switch (guiButton.id) // id { case 4: /* New block breaking */ Shaders.configTweakBlockDamage = !Shaders.configTweakBlockDamage; // displayString - par1GuiButton.displayString = "tweakBlockDamage: " + toStringOnOff(Shaders.configTweakBlockDamage); + guiButton.displayString = "tweakBlockDamage: " + toStringOnOff(Shaders.configTweakBlockDamage); break; case 9: /* Cloud shadow */ Shaders.configCloudShadow = !Shaders.configCloudShadow; - par1GuiButton.displayString = "CloudShadow: " + toStringOnOff(Shaders.configCloudShadow); + guiButton.displayString = "CloudShadow: " + toStringOnOff(Shaders.configCloudShadow); break; case 10: /* Hand Depth */ { @@ -167,7 +127,7 @@ protected void actionPerformed(GuiButton par1GuiButton) { if (i < 0) i = choices.length - 1; } Shaders.configHandDepthMul = choices[i]; - par1GuiButton.displayString = "HandDepth: " + String.format("%.4f", Shaders.configHandDepthMul); + guiButton.displayString = "HandDepth: " + String.format("%.4f", Shaders.configHandDepthMul); break; } @@ -183,7 +143,7 @@ protected void actionPerformed(GuiButton par1GuiButton) { if (i < 0) i = choices.length - 1; } Shaders.configRenderResMul = choices[i]; - par1GuiButton.displayString = "RenderResMul: " + String.format("%.4f", Shaders.configRenderResMul); + guiButton.displayString = "RenderResMul: " + String.format("%.4f", Shaders.configRenderResMul); Shaders.scheduleResize(); break; } @@ -201,7 +161,7 @@ protected void actionPerformed(GuiButton par1GuiButton) { if (i < 0) i = choices.length - 1; } Shaders.configShadowResMul = choices[i]; - par1GuiButton.displayString = "ShadowResMul: " + String.format("%.4f", Shaders.configShadowResMul); + guiButton.displayString = "ShadowResMul: " + String.format("%.4f", Shaders.configShadowResMul); Shaders.scheduleResizeShadow(); break; } @@ -209,7 +169,7 @@ protected void actionPerformed(GuiButton par1GuiButton) { case 17: /* Normal Map */ { Shaders.configNormalMap = !Shaders.configNormalMap; // displayString - par1GuiButton.displayString = "NormapMap: " + toStringOnOff(Shaders.configNormalMap); + guiButton.displayString = "NormapMap: " + toStringOnOff(Shaders.configNormalMap); mc.scheduleResourcesRefresh(); // schedule refresh texture break; } @@ -217,7 +177,7 @@ protected void actionPerformed(GuiButton par1GuiButton) { case 18: /* Normal Map */ { Shaders.configSpecularMap = !Shaders.configSpecularMap; // displayString - par1GuiButton.displayString = "SpecularMap: " + toStringOnOff(Shaders.configSpecularMap); + guiButton.displayString = "SpecularMap: " + toStringOnOff(Shaders.configSpecularMap); mc.scheduleResourcesRefresh(); // schedule refresh texture break; } @@ -225,7 +185,7 @@ protected void actionPerformed(GuiButton par1GuiButton) { case 19: /* old Lighting */ { Shaders.configOldLighting = !Shaders.configOldLighting; // displayString - par1GuiButton.displayString = "OldLighting: " + toStringOnOff(Shaders.configOldLighting); + guiButton.displayString = "OldLighting: " + toStringOnOff(Shaders.configOldLighting); Shaders.updateBlockLightLevel(); mc.renderGlobal.loadRenderers(); break; @@ -234,29 +194,28 @@ protected void actionPerformed(GuiButton par1GuiButton) { case 11: /* texture filter */ { Shaders.configTexMinFilB = (Shaders.configTexMinFilB + 1) % Shaders.texMinFilRange; Shaders.configTexMinFilN = Shaders.configTexMinFilS = Shaders.configTexMinFilB; - par1GuiButton.displayString = "Tex Min: " + Shaders.texMinFilDesc[Shaders.configTexMinFilB]; + guiButton.displayString = "Tex Min: " + Shaders.texMinFilDesc[Shaders.configTexMinFilB]; ShadersTex.updateTextureMinMagFilter(); break; } case 12: /* texture filter */ { Shaders.configTexMagFilN = (Shaders.configTexMagFilN + 1) % Shaders.texMagFilRange; - par1GuiButton.displayString = "Tex_n Mag: " + Shaders.texMagFilDesc[Shaders.configTexMagFilN]; + guiButton.displayString = "Tex_n Mag: " + Shaders.texMagFilDesc[Shaders.configTexMagFilN]; ShadersTex.updateTextureMinMagFilter(); break; } case 13: /* texture filter */ { Shaders.configTexMagFilS = (Shaders.configTexMagFilS + 1) % Shaders.texMagFilRange; - par1GuiButton.displayString = "Tex_s Mag: " + Shaders.texMagFilDesc[Shaders.configTexMagFilS]; + guiButton.displayString = "Tex_s Mag: " + Shaders.texMagFilDesc[Shaders.configTexMagFilS]; ShadersTex.updateTextureMinMagFilter(); break; } case 14: /* shadow frustum clipping */ { Shaders.configShadowClipFrustrum = !Shaders.configShadowClipFrustrum; - par1GuiButton.displayString = "ShadowClipFrustrum: " - + toStringOnOff(Shaders.configShadowClipFrustrum); + guiButton.displayString = "ShadowClipFrustrum: " + toStringOnOff(Shaders.configShadowClipFrustrum); ShadersTex.updateTextureMinMagFilter(); break; } @@ -265,8 +224,7 @@ protected void actionPerformed(GuiButton par1GuiButton) { switch (net.minecraft.util.Util.getOSType()) { case OSX: { try { - Runtime.getRuntime().exec( - new String[] { "/usr/bin/open", Shaders.shaderpacksdir.getAbsolutePath() }); + Runtime.getRuntime().exec(new String[] { "/usr/bin/open", Shaders.shaderpacksdir.getAbsolutePath() }); return; } catch (IOException var7) { var7.printStackTrace(); @@ -293,10 +251,9 @@ protected void actionPerformed(GuiButton par1GuiButton) { try { Class var3 = Class.forName("java.awt.Desktop"); - Object var4 = var3.getMethod("getDesktop", new Class[0]).invoke((Object) null, new Object[0]); - var3.getMethod("browse", new Class[] { URI.class }).invoke( - var4, - new Object[] { (new File(mc.mcDataDir, Shaders.shaderpacksdirname)).toURI() }); + Object var4 = var3.getMethod("getDesktop").invoke((Object) null); + var3.getMethod("browse", URI.class).invoke( + var4, (new File(mc.mcDataDir, Shaders.shaderpacksdirname)).toURI()); } catch (Throwable var5) { var5.printStackTrace(); var8 = true; @@ -311,7 +268,7 @@ protected void actionPerformed(GuiButton par1GuiButton) { case 6: /* Done */ try { Shaders.storeConfig(); - } catch (Exception ex) {} + } catch (Exception ignored) {} if (needReinit) { needReinit = false; Shaders.loadShaderPack(); @@ -322,7 +279,7 @@ protected void actionPerformed(GuiButton par1GuiButton) { break; default: - this.shaderList.actionPerformed(par1GuiButton); // actionPerformed + this.shaderList.actionPerformed(guiButton); // actionPerformed } } } @@ -342,13 +299,12 @@ public void drawScreen(int par1, int par2, float par3) { this.drawCenteredString(this.fontRendererObj, "Shaders ", this.width / 2, 16, 0xffffff); this.drawCenteredString(this.fontRendererObj, " v" + Shaders.versionString, this.width - 40, 10, 0x808080); - // this.drawCenteredString(this.fontRenderer, "( Place zipped Shader files here. )", this.width / 4 + 10, - // this.height - 26, 0x808080); + // this.drawCenteredString(this.fontRenderer, "( Place zipped Shader files here. )", this.width / 4 + 10, this.height - 26, 0x808080); super.drawScreen(par1, par2, par3); } @Override - /** + /* * Called from the main game loop to update the screen. */ public void updateScreen() { diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShadersButton.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShadersButton.java new file mode 100644 index 000000000..c18faaaeb --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShadersButton.java @@ -0,0 +1,24 @@ +package com.gtnewhorizons.angelica.client.gui; + + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; + +public class GuiShadersButton extends GuiButton { + + public GuiShadersButton(int xPosition, int yPosition, AngelicaVideoSettings setting) { + super(setting.ordinal(), xPosition, yPosition, 150, 20, setting.getButtonLabel()); + } + + @Override + public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { + if(super.mousePressed(mc, mouseX, mouseY)) { + mc.gameSettings.saveOptions(); + mc.displayGuiScreen(new GuiShaders(mc.currentScreen, null)); + return true; + } else { + return false; + } + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/GuiSlotShaders.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiSlotShaders.java similarity index 93% rename from src/main/java/com/gtnewhorizons/angelica/client/GuiSlotShaders.java rename to src/main/java/com/gtnewhorizons/angelica/client/gui/GuiSlotShaders.java index 8f3c33a16..534b334a5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/GuiSlotShaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiSlotShaders.java @@ -1,11 +1,12 @@ -package com.gtnewhorizons.angelica.client; +package com.gtnewhorizons.angelica.client.gui; import java.util.List; +import com.gtnewhorizons.angelica.client.Shaders; import net.minecraft.client.gui.GuiSlot; import net.minecraft.client.renderer.Tessellator; -class GuiSlotShaders extends GuiSlot { +public class GuiSlotShaders extends GuiSlot { private List shaderslist; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/settings/MixinGuiVideoSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/settings/MixinGuiVideoSettings.java index 7beb640fc..007ce18c4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/settings/MixinGuiVideoSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/settings/MixinGuiVideoSettings.java @@ -11,7 +11,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.gtnewhorizons.angelica.client.GuiShaders; +import com.gtnewhorizons.angelica.client.gui.GuiShaders; @Mixin(GuiVideoSettings.class) public abstract class MixinGuiVideoSettings extends GuiScreen { diff --git a/src/main/java/jss/notfine/NotFine.java b/src/main/java/jss/notfine/NotFine.java index 642467e32..54d053578 100644 --- a/src/main/java/jss/notfine/NotFine.java +++ b/src/main/java/jss/notfine/NotFine.java @@ -1,5 +1,6 @@ package jss.notfine; +import com.gtnewhorizons.angelica.Tags; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.event.FMLPostInitializationEvent; @@ -23,7 +24,7 @@ public class NotFine { public static final String MODID = "notfine"; public static final String NAME = "NotFine"; - public static final String VERSION = "GRADLETOKEN_VERSION"; + public static final String VERSION = Tags.VERSION; public static final Logger logger = LogManager.getLogger(NAME); @Mod.EventHandler diff --git a/src/main/java/jss/notfine/core/LoadMenuButtons.java b/src/main/java/jss/notfine/core/LoadMenuButtons.java index 0ae773700..bac86ee3a 100644 --- a/src/main/java/jss/notfine/core/LoadMenuButtons.java +++ b/src/main/java/jss/notfine/core/LoadMenuButtons.java @@ -17,9 +17,11 @@ public class LoadMenuButtons { @SubscribeEvent(priority = EventPriority.LOWEST) public void onGui(InitGuiEvent.Post event) { if(event.gui instanceof GuiOptions) { + // Hide the vanilla video settings button GuiButton videoSettings = ((List)event.buttonList).stream().filter(button -> button.id == 101).findFirst().get(); videoSettings.visible = false; + // and add the custom one event.buttonList.add( new GuiCustomMenuButton( videoSettings.xPosition, videoSettings.yPosition, diff --git a/src/main/java/jss/notfine/core/SettingsManager.java b/src/main/java/jss/notfine/core/SettingsManager.java index 3d9cc939e..a2369ef22 100644 --- a/src/main/java/jss/notfine/core/SettingsManager.java +++ b/src/main/java/jss/notfine/core/SettingsManager.java @@ -37,7 +37,7 @@ public class SettingsManager { public static void backgroundUpdated() { int value = (int)Settings.GUI_BACKGROUND.getValue(); - if(value < 0 | value >= extraBackgrounds.length) { + if(value < 0 || value >= extraBackgrounds.length) { Gui.optionsBackground = defaultBackground; } else { Gui.optionsBackground = extraBackgrounds[(int)Settings.GUI_BACKGROUND.getValue()]; diff --git a/src/main/java/jss/notfine/gui/GuiCustomMenu.java b/src/main/java/jss/notfine/gui/GuiCustomMenu.java index 70843b11a..55c16ce2c 100644 --- a/src/main/java/jss/notfine/gui/GuiCustomMenu.java +++ b/src/main/java/jss/notfine/gui/GuiCustomMenu.java @@ -1,28 +1,68 @@ package jss.notfine.gui; +import jss.notfine.NotFine; +import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiListExtended; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.resources.I18n; +import net.minecraft.client.settings.GameSettings; import org.lwjgl.input.Keyboard; -import java.awt.event.KeyListener; +import java.util.HashMap; public class GuiCustomMenu extends GuiScreen { + private static final HashMap, ISettingHandler> buttonHandlers = new HashMap<>(); private final GuiScreen parentGuiScreen; private final MenuButtonLists buttonEnum; protected String screenTitle; private GuiListExtended optionsRowList; + static { + addButtonHandler(Settings.class, (xPosition, yPosition, setting) -> { + Settings customSetting = (Settings)setting; + if(customSetting.slider) + return (new GuiCustomSettingSlider(xPosition, yPosition, customSetting)); + else + return (new GuiCustomSettingButton(xPosition, yPosition, customSetting)); + }); + addButtonHandler(GameSettings.Options.class, (xPosition, yPosition, setting) -> { + GameSettings.Options vanillaSetting = (GameSettings.Options)setting; + if (vanillaSetting.getEnumFloat()) + return (new GuiVanillaSettingSlider(xPosition, yPosition, vanillaSetting)); + else + return (new GuiVanillaSettingButton(xPosition, yPosition, vanillaSetting)); + }); + addButtonHandler(MenuButtonLists.class, (xPosition, yPosition, setting) -> { + MenuButtonLists menuType = (MenuButtonLists)setting; + return new GuiCustomMenuButton(xPosition, yPosition, menuType); + }); + } + public GuiCustomMenu(GuiScreen parentGuiScreen, MenuButtonLists buttonEnum) { this.parentGuiScreen = parentGuiScreen; this.screenTitle = buttonEnum.getTitleLabel(); this.buttonEnum = buttonEnum; } + public static void addButtonHandler(Class cls, ISettingHandler handler) { + buttonHandlers.put(cls, handler); + } + + public static GuiButton createButton(int xPosition, int yPosition, Enum setting) { + if(setting == null) return null; + + final ISettingHandler buttonHandler = buttonHandlers.get((setting).getDeclaringClass()); + if (buttonHandler == null) { + NotFine.logger.debug("No handler for setting: " + setting.getClass().getName()); + return null; + } + return buttonHandler.createButton(xPosition, yPosition, setting); + } + @Override public void initGui() { buttonList.clear(); diff --git a/src/main/java/jss/notfine/gui/GuiCustomSettingsRowList.java b/src/main/java/jss/notfine/gui/GuiCustomSettingsRowList.java index 2c34c5c02..daa5e9247 100644 --- a/src/main/java/jss/notfine/gui/GuiCustomSettingsRowList.java +++ b/src/main/java/jss/notfine/gui/GuiCustomSettingsRowList.java @@ -3,12 +3,10 @@ import com.google.common.collect.Lists; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; -import jss.notfine.core.Settings; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiListExtended; import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.settings.GameSettings; import java.util.List; @@ -20,35 +18,17 @@ public GuiCustomSettingsRowList(Minecraft mc, int width, int height, int top, in super(mc, width, height, top, bottom, slotHeight); field_148163_i = false; - Object[] settings = buttonEnum.entries(); + Enum[] settings = MenuButtonLists.getEntries(buttonEnum); for(int i = 0; i < settings.length; i += 2) { - Object settingOne = settings[i]; - Object settingTwo = i < settings.length - 1 ? settings[i + 1] : null; - GuiButton buttonOne = createButton(width / 2 - 155, 0, settingOne); - GuiButton buttonTwo = createButton(width / 2 - 155 + 160, 0, settingTwo); + Enum settingOne = settings[i]; + Enum settingTwo = i < settings.length - 1 ? settings[i + 1] : null; + GuiButton buttonOne = GuiCustomMenu.createButton(width / 2 - 155, 0, settingOne); + GuiButton buttonTwo = GuiCustomMenu.createButton(width / 2 - 155 + 160, 0, settingTwo); settingsList.add(new Row(buttonOne, buttonTwo)); } } - private GuiButton createButton(int xPosition, int yPosition, Object setting) { - if(setting instanceof Settings) { - Settings customSetting = (Settings)setting; - return customSetting.slider ? - new GuiCustomSettingSlider(xPosition, yPosition, customSetting) : - new GuiCustomSettingButton(xPosition, yPosition, customSetting); - } else if(setting instanceof GameSettings.Options) { - GameSettings.Options vanillaSetting = (GameSettings.Options)setting; - return vanillaSetting.getEnumFloat() ? - new GuiVanillaSettingSlider(xPosition, yPosition, vanillaSetting) : - new GuiVanillaSettingButton(xPosition, yPosition, vanillaSetting); - } else if(setting instanceof MenuButtonLists) { - MenuButtonLists menuType = (MenuButtonLists)setting; - return new GuiCustomMenuButton(xPosition, yPosition, menuType); - } - return null; - } - @Override public Row getListEntry(int index) { return settingsList.get(index); diff --git a/src/main/java/jss/notfine/gui/ISettingHandler.java b/src/main/java/jss/notfine/gui/ISettingHandler.java new file mode 100644 index 000000000..e65eaca93 --- /dev/null +++ b/src/main/java/jss/notfine/gui/ISettingHandler.java @@ -0,0 +1,7 @@ +package jss.notfine.gui; + +import net.minecraft.client.gui.GuiButton; + +public interface ISettingHandler { + GuiButton createButton(int xPosition, int yPosition, Object setting); +} diff --git a/src/main/java/jss/notfine/gui/ISettingsEnum.java b/src/main/java/jss/notfine/gui/ISettingsEnum.java new file mode 100644 index 000000000..94c0190f1 --- /dev/null +++ b/src/main/java/jss/notfine/gui/ISettingsEnum.java @@ -0,0 +1,17 @@ +package jss.notfine.gui; + +import net.minecraft.client.gui.GuiButton; + +import java.util.Collections; +import java.util.List; + +public interface ISettingsEnum { + String getButtonLabel(); + String getTitleLabel(); + + // If this button has it's own page - Entries that go on this page - or Empty + default List> entries() { return Collections.emptyList(); } + + // If this button does something custom - create the button + default GuiButton createButton(int xPosition, int yPosition, Object setting) { return null; } +} diff --git a/src/main/java/jss/notfine/gui/MenuButtonLists.java b/src/main/java/jss/notfine/gui/MenuButtonLists.java index f8e229e99..b1003b880 100644 --- a/src/main/java/jss/notfine/gui/MenuButtonLists.java +++ b/src/main/java/jss/notfine/gui/MenuButtonLists.java @@ -1,5 +1,6 @@ package jss.notfine.gui; +import cpw.mods.fml.common.Loader; import jss.notfine.config.NotFineConfig; import jss.notfine.core.Settings; import net.minecraft.client.renderer.OpenGlHelper; @@ -7,13 +8,16 @@ import net.minecraft.client.settings.GameSettings; import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; -public enum MenuButtonLists { - //list.add(); list.add(); +import static com.gtnewhorizons.angelica.client.gui.AngelicaVideoSettings.SHADERS; + +public enum MenuButtonLists implements ISettingsEnum { VIDEO("options.video") { @Override - public Object[] entries() { - ArrayList list = new ArrayList<>(); + public List> entries() { + ArrayList> list = new ArrayList<>(); list.add(GameSettings.Options.GRAPHICS); list.add(GameSettings.Options.RENDER_DISTANCE); list.add(GameSettings.Options.ENABLE_VSYNC); list.add(GameSettings.Options.USE_FULLSCREEN); @@ -25,50 +29,50 @@ public Object[] entries() { list.add(DETAIL); list.add(SKY); list.add(PARTICLE); list.add(OTHER); - return list.toArray(); + return list; } }, DETAIL("options.button.detail") { @Override - public Object[] entries() { - ArrayList list = new ArrayList<>(); + public List> entries() { + ArrayList> list = new ArrayList<>(); list.add(Settings.MODE_LEAVES); list.add(Settings.MODE_WATER); list.add(Settings.MODE_SHADOWS); list.add(Settings.MODE_VIGNETTE); list.add(Settings.MODE_DROPPED_ITEMS); list.add(Settings.MODE_GLINT_WORLD); list.add(Settings.MODE_GLINT_INV); - return list.toArray(); + return list; } }, SKY("options.button.sky") { @Override - public Object[] entries() { - ArrayList list = new ArrayList<>(); + public List> entries() { + ArrayList> list = new ArrayList<>(); list.add(Settings.MODE_SKY); list.add(Settings.MODE_CLOUDS); list.add(Settings.RENDER_DISTANCE_CLOUDS); list.add(Settings.CLOUD_HEIGHT); list.add(Settings.CLOUD_SCALE); list.add(Settings.MODE_CLOUD_TRANSLUCENCY); list.add(Settings.TOTAL_STARS); - return list.toArray(); + return list; } }, PARTICLE("options.button.particle") { @Override - public Object[] entries() { - ArrayList list = new ArrayList<>(); + public List> entries() { + ArrayList> list = new ArrayList<>(); list.add(GameSettings.Options.PARTICLES); list.add(Settings.PARTICLES_VOID); list.add(Settings.PARTICLES_ENC_TABLE); - return list.toArray(); + return list; } }, OTHER("options.button.other") { @Override - public Object[] entries() { - ArrayList list = new ArrayList<>(); + public List> entries() { + ArrayList> list = new ArrayList<>(); if(OpenGlHelper.field_153197_d && NotFineConfig.allowAdvancedOpenGL) { list.add(GameSettings.Options.ADVANCED_OPENGL); } else { @@ -79,24 +83,37 @@ public Object[] entries() { list.add(null); list.add(GameSettings.Options.FBO_ENABLE); list.add(Settings.GUI_BACKGROUND); - return list.toArray(); + return list; } }; private final String unlocalizedButton; + private static final HashMap, List >> additionalEntries = new HashMap<>(); + public static void addAdditionalEntry(Enum entry, Enum button) { + List> list = additionalEntries.computeIfAbsent(entry, k -> new ArrayList<>()); + list.add(button); + } MenuButtonLists(String button) { unlocalizedButton = button; } - public final String getButtonLabel() { + public String getButtonLabel() { return I18n.format(unlocalizedButton); } - public final String getTitleLabel() { + public String getTitleLabel() { return I18n.format("options.title." + name().toLowerCase()); } - public abstract Object[] entries(); + public abstract List> entries(); + public static Enum[] getEntries(MenuButtonLists button) { + List> entries = button.entries(); + List> additional = additionalEntries.get(button); + if(additional != null) { + entries.addAll(additional); + } + return entries.toArray(new Enum[0]); + } } diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/MixinGameSettings.java b/src/main/java/jss/notfine/mixins/early/minecraft/MixinGameSettings.java index 676f6e99c..fd67ce224 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/MixinGameSettings.java +++ b/src/main/java/jss/notfine/mixins/early/minecraft/MixinGameSettings.java @@ -199,8 +199,7 @@ public void setOptionValue(GameSettings.Options option, int value) { } @Shadow - public void saveOptions() { - } + public void saveOptions() {} @Shadow protected Minecraft mc; diff --git a/src/main/resources/assets/angelica/lang/en_US.lang b/src/main/resources/assets/angelica/lang/en_US.lang new file mode 100644 index 000000000..14627599b --- /dev/null +++ b/src/main/resources/assets/angelica/lang/en_US.lang @@ -0,0 +1 @@ +options.button.shader=Shaders... From cb8551451a8a1003133646a7edf4fde3ffae120f Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 22 Sep 2023 20:40:55 -0700 Subject: [PATCH 003/301] First pass at merging ArchaicFix * start removing unsupported mods/non rendering fixes --- dependencies.gradle | 22 +- gradle.properties | 2 +- .../ca/fxco/memoryleakfix/MemoryLeakFix.java | 51 + .../org/embeddedt/archaicfix/ArchaicCore.java | 91 + .../org/embeddedt/archaicfix/ArchaicFix.java | 165 ++ .../embeddedt/archaicfix/ArchaicLogger.java | 8 + .../archaicfix/CommandDebugUpdateQueue.java | 39 + .../org/embeddedt/archaicfix/FixHelper.java | 72 + .../archaicfix/LeftClickEventHandler.java | 89 + .../archaicfix/asm/ArchaicTransformer.java | 22 + .../archaicfix/asm/LateMixinPlugin.java | 41 + .../org/embeddedt/archaicfix/asm/Mixin.java | 164 ++ .../embeddedt/archaicfix/asm/TargetedMod.java | 39 + .../transformer/ThreadedBlockTransformer.java | 88 + .../asm/transformer/VampirismTransformer.java | 56 + .../archaicfix/block/ThreadedBlockData.java | 34 + .../archaicfix/config/ArchaicConfig.java | 189 ++ .../archaicfix/config/ArchaicGuiConfig.java | 9 + .../config/ArchaicGuiConfigFactory.java | 10 + .../embeddedt/archaicfix/config/Config.java | 113 + .../archaicfix/config/ConfigException.java | 15 + .../config/ConfigurationManager.java | 268 ++ .../config/IConfigElementProxy.java | 157 + .../archaicfix/config/SimpleGuiConfig.java | 14 + .../archaicfix/config/SimpleGuiFactory.java | 26 + .../archaicfix/ducks/IAcceleratedRecipe.java | 12 + .../ducks/IArchaicNetworkManager.java | 7 + .../archaicfix/ducks/IArchaicWorld.java | 7 + .../ducks/ILazyChunkProviderServer.java | 5 + .../archaicfix/ducks/IPendingChunk.java | 9 + .../archaicfix/ducks/IWorldRenderer.java | 5 + .../helpers/BuiltInResourcePack.java | 186 ++ .../helpers/ChickenChunkHelper.java | 10 + .../archaicfix/helpers/ChunkQueueSorter.java | 31 + .../archaicfix/helpers/DragonAPIHelper.java | 29 + .../archaicfix/helpers/LetsEncryptHelper.java | 58 + .../helpers/LoadControllerHelper.java | 172 ++ .../archaicfix/helpers/NEISearchHelper.java | 13 + .../archaicfix/helpers/OreDictIterator.java | 110 + .../archaicfix/helpers/SoundDeviceThread.java | 64 + .../helpers/UnexpectionalObjectArrayList.java | 15 + .../helpers/WorldRendererDistanceHelper.java | 19 + .../lighting/api/IChunkLighting.java | 7 + .../lighting/api/IChunkLightingData.java | 13 + .../lighting/api/ILightingEngine.java | 11 + .../lighting/api/ILightingEngineProvider.java | 5 + .../lighting/collections/PooledLongQueue.java | 164 ++ .../lighting/world/WorldChunkSlice.java | 58 + .../world/lighting/AxisDirection.java | 16 + .../lighting/world/lighting/BlockPos.java | 41 + .../world/lighting/LightingEngine.java | 613 ++++ .../world/lighting/LightingEngineHelpers.java | 44 + .../world/lighting/LightingHooks.java | 438 +++ .../client/core/AccessorSplashProgress.java | 23 + .../mixins/client/core/MixinBlockFence.java | 24 + .../client/core/MixinChunkProviderClient.java | 18 + .../client/core/MixinEntityRenderer.java | 18 + .../client/core/MixinFMLClientHandler.java | 21 + .../client/core/MixinGuiBeaconButton.java | 22 + .../mixins/client/core/MixinGuiButton.java | 23 + .../core/MixinGuiContainerCreative.java | 127 + .../client/core/MixinGuiCreateWorld.java | 24 + .../client/core/MixinGuiIngameForge.java | 20 + .../client/core/MixinIntegratedServer.java | 23 + .../mixins/client/core/MixinMinecraft.java | 68 + .../core/MixinNetHandlerLoginClient.java | 22 + .../core/MixinNetHandlerPlayClient.java | 31 + .../mixins/client/core/MixinRenderItem.java | 19 + .../mixins/client/core/MixinSkinManager.java | 21 + .../client/core/MixinSplashProgress.java | 142 + .../core/MixinThreadDownloadImageData.java | 24 + .../client/core/MixinWorldRenderer.java | 59 + .../client/journeymap/MixinTileDrawStep.java | 15 + .../client/lighting/MixinChunkCache.java | 19 + .../client/lighting/MixinMinecraft.java | 33 + .../mixins/client/lighting/MixinWorld.java | 35 + .../mixins/client/occlusion/MixinChunk.java | 89 + .../client/occlusion/MixinEntityRenderer.java | 22 + .../occlusion/MixinGuiVideoSettings.java | 14 + .../client/occlusion/MixinRenderGlobal.java | 135 + .../client/occlusion/MixinWorldRenderer.java | 85 + .../optifine/MixinVersionCheckThread.java | 16 + .../renderdistance/MixinGameSettings.java | 16 + .../renderdistance/MixinRenderGlobal.java | 52 + .../threadedupdates/MixinRenderBlocks.java | 53 + .../threadedupdates/MixinTessellator.java | 86 + .../MixinTessellator_Debug.java | 34 + .../threadedupdates/MixinWorldRenderer.java | 57 + .../botania/MixinBlockSpecialFlower.java | 18 + .../MixinPlayerChunkViewerManager.java | 39 + .../common/core/AccessorEntityLiving.java | 13 + .../mixins/common/core/MixinASMData.java | 25 + .../common/core/MixinAxisAlignedBB.java | 32 + .../mixins/common/core/MixinBlock.java | 60 + .../mixins/common/core/MixinChunk.java | 101 + .../common/core/MixinChunkProviderHell.java | 20 + .../common/core/MixinChunkProviderServer.java | 43 + .../common/core/MixinEmbeddedChannel.java | 116 + .../common/core/MixinEnchantmentHelper.java | 40 + .../mixins/common/core/MixinEntity.java | 23 + .../mixins/common/core/MixinEntityItem.java | 55 + .../mixins/common/core/MixinEntityLiving.java | 102 + .../common/core/MixinEntityPlayerMP.java | 33 + .../common/core/MixinEntityTrackerEntry.java | 80 + .../common/core/MixinEntityVillager.java | 40 + .../mixins/common/core/MixinEntityXPOrb.java | 14 + .../common/core/MixinForgeChunkManager.java | 26 + .../mixins/common/core/MixinLongHashMap.java | 19 + .../common/core/MixinMapGenStructure.java | 26 + .../common/core/MixinMaterialLiquid.java | 18 + .../common/core/MixinMerchantRecipe.java | 24 + .../mixins/common/core/MixinModCandidate.java | 56 + .../core/MixinNetHandlerPlayServer.java | 18 + .../common/core/MixinNetworkDispatcher.java | 37 + .../common/core/MixinNetworkManager.java | 27 + .../common/core/MixinNextTickListEntry.java | 39 + .../core/MixinObjectIntIdentityMap.java | 35 + .../common/core/MixinOreDictionary.java | 41 + .../common/core/MixinShapedOreRecipe.java | 55 + .../common/core/MixinShapedRecipes.java | 36 + .../common/core/MixinShapelessOreRecipe.java | 52 + .../common/core/MixinShapelessRecipes.java | 44 + .../common/core/MixinSpawnerAnimals.java | 37 + .../common/core/MixinStructureStart.java | 21 + .../mixins/common/core/MixinWorld.java | 192 ++ .../common/core/MixinWorldChunkManager.java | 48 + .../mixins/common/core/MixinWorldServer.java | 39 + .../extrautils/MixinEventHandlerServer.java | 22 + .../extrautils/MixinEventHandlerSiege.java | 15 + .../extrautils/MixinItemDivisionSigil.java | 25 + .../extrautils/MixinTileEntityTrashCan.java | 19 + .../lighting/MixinAnvilChunkLoader.java | 53 + .../mixins/common/lighting/MixinChunk.java | 398 +++ .../lighting/MixinChunkProviderServer.java | 48 + .../common/lighting/MixinChunkVanilla.java | 79 + .../lighting/MixinExtendedBlockStorage.java | 97 + .../lighting/MixinSPacketChunkData.java | 23 + .../common/lighting/MixinWorld_Lighting.java | 53 + .../common/lighting/fastcraft/MixinChunk.java | 35 + .../fastcraft/MixinChunkProviderServer.java | 15 + .../common/lighting/fastcraft/MixinWorld.java | 14 + .../common/mrtjp/MixinBlockUpdateHandler.java | 21 + .../renderdistance/MixinPlayerManager.java | 16 + .../embeddedt/archaicfix/mixins/generate.sh | 16 + .../occlusion/BasicDistanceSorter.java | 20 + .../archaicfix/occlusion/CameraInfo.java | 45 + .../archaicfix/occlusion/ChunkThread.java | 56 + .../DefaultRendererUpdateOrderProvider.java | 31 + .../archaicfix/occlusion/ICulledChunk.java | 9 + .../occlusion/IRenderGlobalListener.java | 10 + .../IRendererUpdateOrderProvider.java | 21 + .../archaicfix/occlusion/IWorldRenderer.java | 10 + .../embeddedt/archaicfix/occlusion/LICENSE | 51 + .../occlusion/OcclusionHelpers.java | 49 + .../occlusion/OcclusionRenderer.java | 580 ++++ .../archaicfix/occlusion/OcclusionWorker.java | 426 +++ .../occlusion/PreviousActiveRenderInfo.java | 26 + .../archaicfix/occlusion/SetVisibility.java | 93 + .../archaicfix/occlusion/VisGraph.java | 222 ++ .../occlusion/util/ArrayHashList.java | 626 ++++ .../util/IdentityLinkedHashList.java | 48 + .../archaicfix/occlusion/util/IntStack.java | 282 ++ .../archaicfix/occlusion/util/IntVector.java | 403 +++ .../occlusion/util/LinkedHashList.java | 667 +++++ .../SynchronizedIdentityLinkedHashList.java | 137 + .../archaicfix/proxy/ClientProxy.java | 180 ++ .../archaicfix/proxy/CommonProxy.java | 18 + .../archaicfix/recipe/LastMatchedInfo.java | 70 + .../archaicfix/recipe/RecipeCacheLoader.java | 41 + .../archaicfix/recipe/RecipeWeigher.java | 14 + .../ICapturableTessellator.java | 16 + .../IRendererUpdateResultHolder.java | 7 + .../threadedupdates/RenderBlocksStack.java | 34 + .../ThreadedChunkUpdateHelper.java | 323 ++ .../api/ThreadedChunkUpdates.java | 17 + .../booleans/functions/BooleanComparator.java | 70 + .../booleans/functions/BooleanConsumer.java | 48 + .../booleans/functions/BooleanSupplier.java | 12 + .../consumer/BooleanBooleanConsumer.java | 49 + .../consumer/BooleanByteConsumer.java | 49 + .../consumer/BooleanCharConsumer.java | 49 + .../consumer/BooleanDoubleConsumer.java | 49 + .../consumer/BooleanFloatConsumer.java | 49 + .../consumer/BooleanIntConsumer.java | 49 + .../consumer/BooleanLongConsumer.java | 49 + .../consumer/BooleanObjectConsumer.java | 50 + .../consumer/BooleanShortConsumer.java | 49 + .../function/Boolean2ByteFunction.java | 17 + .../function/Boolean2CharFunction.java | 17 + .../function/Boolean2DoubleFunction.java | 17 + .../function/Boolean2FloatFunction.java | 17 + .../function/Boolean2IntFunction.java | 17 + .../function/Boolean2LongFunction.java | 17 + .../function/Boolean2ShortFunction.java | 17 + .../function/BooleanBooleanUnaryOperator.java | 22 + .../function/BooleanByteUnaryOperator.java | 22 + .../function/BooleanCharUnaryOperator.java | 22 + .../function/BooleanDoubleUnaryOperator.java | 22 + .../function/BooleanFloatUnaryOperator.java | 22 + .../functions/function/BooleanFunction.java | 18 + .../function/BooleanIntUnaryOperator.java | 22 + .../function/BooleanLongUnaryOperator.java | 22 + .../function/BooleanObjectUnaryOperator.java | 23 + .../functions/function/BooleanPredicate.java | 98 + .../function/BooleanShortUnaryOperator.java | 22 + .../bytes/functions/ByteComparator.java | 70 + .../bytes/functions/ByteConsumer.java | 48 + .../bytes/functions/ByteSupplier.java | 12 + .../consumer/ByteBooleanConsumer.java | 49 + .../functions/consumer/ByteByteConsumer.java | 49 + .../functions/consumer/ByteCharConsumer.java | 49 + .../consumer/ByteDoubleConsumer.java | 49 + .../functions/consumer/ByteFloatConsumer.java | 49 + .../functions/consumer/ByteIntConsumer.java | 49 + .../functions/consumer/ByteLongConsumer.java | 49 + .../consumer/ByteObjectConsumer.java | 50 + .../functions/consumer/ByteShortConsumer.java | 49 + .../functions/function/Byte2CharFunction.java | 17 + .../function/Byte2DoubleFunction.java | 17 + .../function/Byte2FloatFunction.java | 17 + .../functions/function/Byte2IntFunction.java | 17 + .../functions/function/Byte2LongFunction.java | 17 + .../function/Byte2ShortFunction.java | 17 + .../function/ByteBooleanUnaryOperator.java | 22 + .../function/ByteByteUnaryOperator.java | 22 + .../function/ByteCharUnaryOperator.java | 22 + .../function/ByteDoubleUnaryOperator.java | 22 + .../function/ByteFloatUnaryOperator.java | 22 + .../functions/function/ByteFunction.java | 18 + .../function/ByteIntUnaryOperator.java | 22 + .../function/ByteLongUnaryOperator.java | 22 + .../function/ByteObjectUnaryOperator.java | 23 + .../functions/function/BytePredicate.java | 62 + .../function/ByteShortUnaryOperator.java | 22 + .../functions/function/ByteUnaryOperator.java | 54 + .../chars/functions/CharComparator.java | 70 + .../chars/functions/CharConsumer.java | 48 + .../chars/functions/CharSupplier.java | 12 + .../consumer/CharBooleanConsumer.java | 49 + .../functions/consumer/CharByteConsumer.java | 49 + .../functions/consumer/CharCharConsumer.java | 49 + .../consumer/CharDoubleConsumer.java | 49 + .../functions/consumer/CharFloatConsumer.java | 49 + .../functions/consumer/CharIntConsumer.java | 49 + .../functions/consumer/CharLongConsumer.java | 49 + .../consumer/CharObjectConsumer.java | 50 + .../functions/consumer/CharShortConsumer.java | 49 + .../functions/function/Char2ByteFunction.java | 17 + .../function/Char2DoubleFunction.java | 17 + .../function/Char2FloatFunction.java | 17 + .../functions/function/Char2IntFunction.java | 17 + .../functions/function/Char2LongFunction.java | 17 + .../function/Char2ShortFunction.java | 17 + .../function/CharBooleanUnaryOperator.java | 22 + .../function/CharByteUnaryOperator.java | 22 + .../function/CharCharUnaryOperator.java | 22 + .../function/CharDoubleUnaryOperator.java | 22 + .../function/CharFloatUnaryOperator.java | 22 + .../functions/function/CharFunction.java | 18 + .../function/CharIntUnaryOperator.java | 22 + .../function/CharLongUnaryOperator.java | 22 + .../function/CharObjectUnaryOperator.java | 23 + .../functions/function/CharPredicate.java | 62 + .../function/CharShortUnaryOperator.java | 22 + .../functions/function/CharUnaryOperator.java | 54 + .../doubles/functions/DoubleComparator.java | 70 + .../doubles/functions/DoubleConsumer.java | 59 + .../doubles/functions/DoubleSupplier.java | 12 + .../consumer/DoubleBooleanConsumer.java | 49 + .../consumer/DoubleByteConsumer.java | 49 + .../consumer/DoubleCharConsumer.java | 49 + .../consumer/DoubleDoubleConsumer.java | 49 + .../consumer/DoubleFloatConsumer.java | 49 + .../functions/consumer/DoubleIntConsumer.java | 49 + .../consumer/DoubleLongConsumer.java | 49 + .../consumer/DoubleObjectConsumer.java | 50 + .../consumer/DoubleShortConsumer.java | 49 + .../function/Double2ByteFunction.java | 17 + .../function/Double2CharFunction.java | 17 + .../function/Double2FloatFunction.java | 17 + .../function/Double2IntFunction.java | 17 + .../function/Double2LongFunction.java | 17 + .../function/Double2ShortFunction.java | 17 + .../function/DoubleBooleanUnaryOperator.java | 22 + .../function/DoubleByteUnaryOperator.java | 22 + .../function/DoubleCharUnaryOperator.java | 22 + .../function/DoubleDoubleUnaryOperator.java | 13 + .../function/DoubleFloatUnaryOperator.java | 22 + .../functions/function/DoubleFunction.java | 18 + .../function/DoubleIntUnaryOperator.java | 22 + .../function/DoubleLongUnaryOperator.java | 22 + .../function/DoubleObjectUnaryOperator.java | 23 + .../functions/function/DoublePredicate.java | 72 + .../function/DoubleShortUnaryOperator.java | 22 + .../function/DoubleUnaryOperator.java | 54 + .../floats/functions/FloatComparator.java | 70 + .../floats/functions/FloatConsumer.java | 48 + .../floats/functions/FloatSupplier.java | 12 + .../consumer/FloatBooleanConsumer.java | 49 + .../functions/consumer/FloatByteConsumer.java | 49 + .../functions/consumer/FloatCharConsumer.java | 49 + .../consumer/FloatDoubleConsumer.java | 49 + .../consumer/FloatFloatConsumer.java | 49 + .../functions/consumer/FloatIntConsumer.java | 49 + .../functions/consumer/FloatLongConsumer.java | 49 + .../consumer/FloatObjectConsumer.java | 50 + .../consumer/FloatShortConsumer.java | 49 + .../function/Float2ByteFunction.java | 17 + .../function/Float2CharFunction.java | 17 + .../function/Float2DoubleFunction.java | 17 + .../functions/function/Float2IntFunction.java | 17 + .../function/Float2LongFunction.java | 17 + .../function/Float2ShortFunction.java | 17 + .../function/FloatBooleanUnaryOperator.java | 22 + .../function/FloatByteUnaryOperator.java | 22 + .../function/FloatCharUnaryOperator.java | 22 + .../function/FloatDoubleUnaryOperator.java | 22 + .../function/FloatFloatUnaryOperator.java | 22 + .../functions/function/FloatFunction.java | 18 + .../function/FloatIntUnaryOperator.java | 22 + .../function/FloatLongUnaryOperator.java | 22 + .../function/FloatObjectUnaryOperator.java | 23 + .../functions/function/FloatPredicate.java | 62 + .../function/FloatShortUnaryOperator.java | 22 + .../function/FloatUnaryOperator.java | 54 + .../collections/AbstractIntCollection.java | 252 ++ .../collections/IntBidirectionalIterator.java | 52 + .../ints/collections/IntCollection.java | 279 ++ .../ints/collections/IntIterable.java | 314 ++ .../ints/collections/IntIterator.java | 88 + .../ints/collections/IntSplititerator.java | 19 + .../ints/collections/IntStack.java | 62 + .../ints/functions/IntComparator.java | 70 + .../ints/functions/IntConsumer.java | 59 + .../ints/functions/IntSupplier.java | 12 + .../consumer/IntBooleanConsumer.java | 49 + .../functions/consumer/IntByteConsumer.java | 49 + .../functions/consumer/IntCharConsumer.java | 49 + .../functions/consumer/IntDoubleConsumer.java | 49 + .../functions/consumer/IntFloatConsumer.java | 49 + .../functions/consumer/IntIntConsumer.java | 49 + .../functions/consumer/IntLongConsumer.java | 49 + .../functions/consumer/IntObjectConsumer.java | 50 + .../functions/consumer/IntShortConsumer.java | 49 + .../functions/function/Int2ByteFunction.java | 17 + .../functions/function/Int2CharFunction.java | 17 + .../function/Int2DoubleFunction.java | 17 + .../functions/function/Int2FloatFunction.java | 17 + .../functions/function/Int2LongFunction.java | 17 + .../functions/function/Int2ShortFunction.java | 17 + .../function/IntBooleanUnaryOperator.java | 22 + .../function/IntByteUnaryOperator.java | 22 + .../function/IntCharUnaryOperator.java | 22 + .../function/IntDoubleUnaryOperator.java | 22 + .../function/IntFloatUnaryOperator.java | 22 + .../ints/functions/function/IntFunction.java | 18 + .../function/IntIntUnaryOperator.java | 13 + .../function/IntLongUnaryOperator.java | 22 + .../function/IntObjectUnaryOperator.java | 23 + .../ints/functions/function/IntPredicate.java | 72 + .../function/IntShortUnaryOperator.java | 22 + .../functions/function/IntUnaryOperator.java | 54 + .../ints/lists/IntListIterator.java | 65 + .../maps/abstracts/AbstractInt2ObjectMap.java | 451 +++ .../maps/impl/misc/Int2ObjectArrayMap.java | 1296 ++++++++ .../ints/maps/interfaces/Int2ObjectMap.java | 679 +++++ .../maps/interfaces/Int2ObjectOrderedMap.java | 115 + .../collections/ints/sets/AbstractIntSet.java | 41 + .../collections/ints/sets/IntOrderedSet.java | 88 + .../src/collections/ints/sets/IntSet.java | 58 + .../src/collections/ints/utils/IIntArray.java | 29 + .../src/collections/ints/utils/IntArrays.java | 1527 ++++++++++ .../ints/utils/IntCollections.java | 892 ++++++ .../collections/ints/utils/IntIterables.java | 485 +++ .../collections/ints/utils/IntIterators.java | 1003 +++++++ .../ints/utils/IntSplititerators.java | 461 +++ .../collections/AbstractLongCollection.java | 252 ++ .../LongBidirectionalIterator.java | 52 + .../longs/collections/LongCollection.java | 279 ++ .../longs/collections/LongIterable.java | 314 ++ .../longs/collections/LongIterator.java | 88 + .../longs/collections/LongSplititerator.java | 19 + .../longs/collections/LongStack.java | 62 + .../longs/functions/LongComparator.java | 70 + .../longs/functions/LongConsumer.java | 59 + .../longs/functions/LongSupplier.java | 12 + .../consumer/LongBooleanConsumer.java | 49 + .../functions/consumer/LongByteConsumer.java | 49 + .../functions/consumer/LongCharConsumer.java | 49 + .../consumer/LongDoubleConsumer.java | 49 + .../functions/consumer/LongFloatConsumer.java | 49 + .../functions/consumer/LongIntConsumer.java | 49 + .../functions/consumer/LongLongConsumer.java | 49 + .../consumer/LongObjectConsumer.java | 50 + .../functions/consumer/LongShortConsumer.java | 49 + .../functions/function/Long2ByteFunction.java | 17 + .../functions/function/Long2CharFunction.java | 17 + .../function/Long2DoubleFunction.java | 17 + .../function/Long2FloatFunction.java | 17 + .../functions/function/Long2IntFunction.java | 17 + .../function/Long2ShortFunction.java | 17 + .../function/LongBooleanUnaryOperator.java | 22 + .../function/LongByteUnaryOperator.java | 22 + .../function/LongCharUnaryOperator.java | 22 + .../function/LongDoubleUnaryOperator.java | 22 + .../function/LongFloatUnaryOperator.java | 22 + .../functions/function/LongFunction.java | 18 + .../function/LongIntUnaryOperator.java | 22 + .../function/LongLongUnaryOperator.java | 13 + .../function/LongObjectUnaryOperator.java | 23 + .../functions/function/LongPredicate.java | 72 + .../function/LongShortUnaryOperator.java | 22 + .../functions/function/LongUnaryOperator.java | 54 + .../longs/lists/LongListIterator.java | 65 + .../longs/sets/AbstractLongSet.java | 41 + .../longs/sets/LongOpenHashSet.java | 635 ++++ .../src/collections/longs/sets/LongSet.java | 58 + .../collections/longs/utils/LongArrays.java | 1527 ++++++++++ .../longs/utils/LongCollections.java | 892 ++++++ .../longs/utils/LongIterables.java | 485 +++ .../longs/utils/LongIterators.java | 1003 +++++++ .../longs/utils/LongSplititerators.java | 461 +++ .../collections/AbstractObjectCollection.java | 167 ++ .../ObjectBidirectionalIterator.java | 34 + .../objects/collections/ObjectCollection.java | 181 ++ .../objects/collections/ObjectIterable.java | 297 ++ .../objects/collections/ObjectIterator.java | 36 + .../collections/ObjectSplititerator.java | 15 + .../objects/functions/ObjectSupplier.java | 13 + .../consumer/ObjectBooleanConsumer.java | 50 + .../consumer/ObjectByteConsumer.java | 50 + .../consumer/ObjectCharConsumer.java | 50 + .../consumer/ObjectDoubleConsumer.java | 50 + .../consumer/ObjectFloatConsumer.java | 50 + .../functions/consumer/ObjectIntConsumer.java | 50 + .../consumer/ObjectLongConsumer.java | 50 + .../consumer/ObjectObjectConsumer.java | 33 + .../consumer/ObjectShortConsumer.java | 50 + .../function/ObjectBooleanUnaryOperator.java | 23 + .../function/ObjectByteUnaryOperator.java | 23 + .../function/ObjectCharUnaryOperator.java | 23 + .../function/ObjectDoubleUnaryOperator.java | 23 + .../function/ObjectFloatUnaryOperator.java | 23 + .../function/ObjectIntUnaryOperator.java | 23 + .../function/ObjectLongUnaryOperator.java | 23 + .../function/ObjectObjectUnaryOperator.java | 13 + .../function/ObjectShortUnaryOperator.java | 23 + .../objects/functions/function/Predicate.java | 75 + .../functions/function/ToByteFunction.java | 18 + .../functions/function/ToCharFunction.java | 18 + .../functions/function/ToDoubleFunction.java | 18 + .../functions/function/ToFloatFunction.java | 18 + .../functions/function/ToIntFunction.java | 18 + .../functions/function/ToLongFunction.java | 18 + .../functions/function/ToShortFunction.java | 18 + .../functions/function/UnaryOperator.java | 59 + .../objects/lists/AbstractObjectList.java | 493 ++++ .../objects/lists/ObjectArrayList.java | 888 ++++++ .../collections/objects/lists/ObjectList.java | 238 ++ .../objects/lists/ObjectListIterator.java | 13 + .../abstracts/AbstractObject2ObjectMap.java | 426 +++ .../impl/hash/Object2ObjectOpenHashMap.java | 1258 ++++++++ .../maps/interfaces/Object2ObjectMap.java | 534 ++++ .../objects/sets/AbstractObjectSet.java | 46 + .../objects/sets/ObjectOpenHashSet.java | 609 ++++ .../objects/sets/ObjectOrderedSet.java | 89 + .../collections/objects/sets/ObjectSet.java | 37 + .../objects/utils/ObjectArrays.java | 1571 ++++++++++ .../objects/utils/ObjectCollections.java | 802 +++++ .../objects/utils/ObjectIterables.java | 496 ++++ .../objects/utils/ObjectIterators.java | 1019 +++++++ .../objects/utils/ObjectSplititerators.java | 242 ++ .../shorts/functions/ShortComparator.java | 70 + .../shorts/functions/ShortConsumer.java | 48 + .../shorts/functions/ShortSupplier.java | 12 + .../consumer/ShortBooleanConsumer.java | 49 + .../functions/consumer/ShortByteConsumer.java | 49 + .../functions/consumer/ShortCharConsumer.java | 49 + .../consumer/ShortDoubleConsumer.java | 49 + .../consumer/ShortFloatConsumer.java | 49 + .../functions/consumer/ShortIntConsumer.java | 49 + .../functions/consumer/ShortLongConsumer.java | 49 + .../consumer/ShortObjectConsumer.java | 50 + .../consumer/ShortShortConsumer.java | 49 + .../function/Short2ByteFunction.java | 17 + .../function/Short2CharFunction.java | 17 + .../function/Short2DoubleFunction.java | 17 + .../function/Short2FloatFunction.java | 17 + .../functions/function/Short2IntFunction.java | 17 + .../function/Short2LongFunction.java | 17 + .../function/ShortBooleanUnaryOperator.java | 22 + .../function/ShortByteUnaryOperator.java | 22 + .../function/ShortCharUnaryOperator.java | 22 + .../function/ShortDoubleUnaryOperator.java | 22 + .../function/ShortFloatUnaryOperator.java | 22 + .../functions/function/ShortFunction.java | 18 + .../function/ShortIntUnaryOperator.java | 22 + .../function/ShortLongUnaryOperator.java | 22 + .../function/ShortObjectUnaryOperator.java | 23 + .../functions/function/ShortPredicate.java | 62 + .../function/ShortShortUnaryOperator.java | 22 + .../function/ShortUnaryOperator.java | 54 + .../src/collections/utils/HashUtil.java | 96 + .../speiger/src/collections/utils/IArray.java | 20 + .../src/collections/utils/ISizeProvider.java | 46 + .../src/collections/utils/ITrimmable.java | 37 + .../src/collections/utils/SanityChecks.java | 178 ++ .../speiger/src/collections/utils/Stack.java | 62 + .../zone/rong/rongasm/api/CaptureSet.java | 34 + .../java/zone/rong/rongasm/api/DummyMap.java | 50 + .../zone/rong/rongasm/api/LoliHelpers.java | 40 + .../zone/rong/rongasm/api/LoliReflector.java | 245 ++ .../zone/rong/rongasm/api/LoliStringPool.java | 142 + .../zone/rong/rongasm/api/ResourceCache.java | 15 + src/main/resources/META-INF/archaicfix_at.cfg | 71 + src/main/resources/ModulSettings.json | 2624 +++++++++++++++++ .../resources/letsencrypt/isrg-root-x2.pem | 14 + src/main/resources/letsencrypt/isrgrootx1.pem | 31 + .../resources/mixins.archaicfix.early.json | 8 + src/main/resources/mixins.archaicfix.json | 9 + .../resources/mixins.archaicfix.late.json | 9 + src/main/resources/pack.mcmeta | 6 + .../blocks/double_plant_grass_bottom.png | 0 .../blocks/double_plant_grass_top.png | 0 .../minecraft/textures/blocks/tallgrass.png | 0 525 files changed, 49370 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ca/fxco/memoryleakfix/MemoryLeakFix.java create mode 100644 src/main/java/org/embeddedt/archaicfix/ArchaicCore.java create mode 100644 src/main/java/org/embeddedt/archaicfix/ArchaicFix.java create mode 100644 src/main/java/org/embeddedt/archaicfix/ArchaicLogger.java create mode 100644 src/main/java/org/embeddedt/archaicfix/CommandDebugUpdateQueue.java create mode 100644 src/main/java/org/embeddedt/archaicfix/FixHelper.java create mode 100644 src/main/java/org/embeddedt/archaicfix/LeftClickEventHandler.java create mode 100644 src/main/java/org/embeddedt/archaicfix/asm/ArchaicTransformer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/asm/LateMixinPlugin.java create mode 100644 src/main/java/org/embeddedt/archaicfix/asm/Mixin.java create mode 100644 src/main/java/org/embeddedt/archaicfix/asm/TargetedMod.java create mode 100644 src/main/java/org/embeddedt/archaicfix/asm/transformer/ThreadedBlockTransformer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/asm/transformer/VampirismTransformer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java create mode 100644 src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java create mode 100644 src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfig.java create mode 100644 src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfigFactory.java create mode 100644 src/main/java/org/embeddedt/archaicfix/config/Config.java create mode 100644 src/main/java/org/embeddedt/archaicfix/config/ConfigException.java create mode 100644 src/main/java/org/embeddedt/archaicfix/config/ConfigurationManager.java create mode 100644 src/main/java/org/embeddedt/archaicfix/config/IConfigElementProxy.java create mode 100644 src/main/java/org/embeddedt/archaicfix/config/SimpleGuiConfig.java create mode 100644 src/main/java/org/embeddedt/archaicfix/config/SimpleGuiFactory.java create mode 100644 src/main/java/org/embeddedt/archaicfix/ducks/IAcceleratedRecipe.java create mode 100644 src/main/java/org/embeddedt/archaicfix/ducks/IArchaicNetworkManager.java create mode 100644 src/main/java/org/embeddedt/archaicfix/ducks/IArchaicWorld.java create mode 100644 src/main/java/org/embeddedt/archaicfix/ducks/ILazyChunkProviderServer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/ducks/IPendingChunk.java create mode 100644 src/main/java/org/embeddedt/archaicfix/ducks/IWorldRenderer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java create mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/ChickenChunkHelper.java create mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/ChunkQueueSorter.java create mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java create mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/LetsEncryptHelper.java create mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/LoadControllerHelper.java create mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/NEISearchHelper.java create mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java create mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/SoundDeviceThread.java create mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/UnexpectionalObjectArrayList.java create mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java create mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLighting.java create mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLightingData.java create mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngine.java create mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngineProvider.java create mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/collections/PooledLongQueue.java create mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/WorldChunkSlice.java create mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/AxisDirection.java create mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/BlockPos.java create mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngine.java create mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngineHelpers.java create mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/AccessorSplashProgress.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinBlockFence.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinChunkProviderClient.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinEntityRenderer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinFMLClientHandler.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiBeaconButton.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiButton.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiContainerCreative.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiCreateWorld.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiIngameForge.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinIntegratedServer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinMinecraft.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerLoginClient.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerPlayClient.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinRenderItem.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSkinManager.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSplashProgress.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinThreadDownloadImageData.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinWorldRenderer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/journeymap/MixinTileDrawStep.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinChunkCache.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinMinecraft.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinWorld.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinChunk.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinEntityRenderer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinGuiVideoSettings.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinRenderGlobal.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinWorldRenderer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/optifine/MixinVersionCheckThread.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinGameSettings.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinRenderGlobal.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinRenderBlocks.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator_Debug.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinWorldRenderer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/botania/MixinBlockSpecialFlower.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/chickenchunks/MixinPlayerChunkViewerManager.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/AccessorEntityLiving.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinASMData.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinAxisAlignedBB.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinBlock.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunk.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderHell.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderServer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEmbeddedChannel.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEnchantmentHelper.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntity.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityItem.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityLiving.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityPlayerMP.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityTrackerEntry.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityVillager.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityXPOrb.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinForgeChunkManager.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinLongHashMap.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMapGenStructure.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMaterialLiquid.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMerchantRecipe.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinModCandidate.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetHandlerPlayServer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkDispatcher.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkManager.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNextTickListEntry.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinObjectIntIdentityMap.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinOreDictionary.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedOreRecipe.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedRecipes.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessOreRecipe.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessRecipes.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinSpawnerAnimals.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinStructureStart.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorld.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldChunkManager.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldServer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerServer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerSiege.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinItemDivisionSigil.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinTileEntityTrashCan.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinAnvilChunkLoader.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunk.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkProviderServer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkVanilla.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinExtendedBlockStorage.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinSPacketChunkData.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinWorld_Lighting.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunk.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunkProviderServer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinWorld.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/mrtjp/MixinBlockUpdateHandler.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/renderdistance/MixinPlayerManager.java create mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/generate.sh create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/BasicDistanceSorter.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/ICulledChunk.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/IRenderGlobalListener.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/IRendererUpdateOrderProvider.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/IWorldRenderer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/LICENSE create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/PreviousActiveRenderInfo.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/ArrayHashList.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/IdentityLinkedHashList.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/IntStack.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/IntVector.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java create mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/SynchronizedIdentityLinkedHashList.java create mode 100644 src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java create mode 100644 src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java create mode 100644 src/main/java/org/embeddedt/archaicfix/recipe/LastMatchedInfo.java create mode 100644 src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java create mode 100644 src/main/java/org/embeddedt/archaicfix/recipe/RecipeWeigher.java create mode 100644 src/main/java/org/embeddedt/archaicfix/threadedupdates/ICapturableTessellator.java create mode 100644 src/main/java/org/embeddedt/archaicfix/threadedupdates/IRendererUpdateResultHolder.java create mode 100644 src/main/java/org/embeddedt/archaicfix/threadedupdates/RenderBlocksStack.java create mode 100644 src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java create mode 100644 src/main/java/org/embeddedt/archaicfix/threadedupdates/api/ThreadedChunkUpdates.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/BooleanComparator.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/BooleanConsumer.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/BooleanSupplier.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanBooleanConsumer.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanByteConsumer.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanCharConsumer.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanDoubleConsumer.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanFloatConsumer.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanIntConsumer.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanLongConsumer.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanObjectConsumer.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanShortConsumer.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ByteFunction.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2CharFunction.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2DoubleFunction.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2FloatFunction.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2IntFunction.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2LongFunction.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ShortFunction.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanBooleanUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanByteUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanCharUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanDoubleUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanFloatUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanFunction.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanIntUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanLongUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanObjectUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanPredicate.java create mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanShortUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/ByteComparator.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/ByteConsumer.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/ByteSupplier.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteBooleanConsumer.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteByteConsumer.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteCharConsumer.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteDoubleConsumer.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteFloatConsumer.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteIntConsumer.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteLongConsumer.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteObjectConsumer.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteShortConsumer.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2CharFunction.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2DoubleFunction.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2FloatFunction.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2IntFunction.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2LongFunction.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2ShortFunction.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteBooleanUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteByteUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteCharUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteDoubleUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteFloatUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteFunction.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteIntUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteLongUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteObjectUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/BytePredicate.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteShortUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/CharComparator.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/CharConsumer.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/CharSupplier.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharBooleanConsumer.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharByteConsumer.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharCharConsumer.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharDoubleConsumer.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharFloatConsumer.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharIntConsumer.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharLongConsumer.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharObjectConsumer.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharShortConsumer.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2ByteFunction.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2DoubleFunction.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2FloatFunction.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2IntFunction.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2LongFunction.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2ShortFunction.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharBooleanUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharByteUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharCharUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharDoubleUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharFloatUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharFunction.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharIntUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharLongUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharObjectUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharPredicate.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharShortUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/DoubleComparator.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/DoubleConsumer.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/DoubleSupplier.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleBooleanConsumer.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleByteConsumer.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleCharConsumer.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleDoubleConsumer.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleFloatConsumer.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleIntConsumer.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleLongConsumer.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleObjectConsumer.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleShortConsumer.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2ByteFunction.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2CharFunction.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2FloatFunction.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2IntFunction.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2LongFunction.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2ShortFunction.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleBooleanUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleByteUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleCharUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleDoubleUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleFloatUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleFunction.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleIntUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleLongUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleObjectUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoublePredicate.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleShortUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/FloatComparator.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/FloatConsumer.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/FloatSupplier.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatBooleanConsumer.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatByteConsumer.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatCharConsumer.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatDoubleConsumer.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatFloatConsumer.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatIntConsumer.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatLongConsumer.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatObjectConsumer.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatShortConsumer.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2ByteFunction.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2CharFunction.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2DoubleFunction.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2IntFunction.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2LongFunction.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2ShortFunction.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatBooleanUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatByteUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatCharUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatDoubleUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatFloatUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatFunction.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatIntUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatLongUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatObjectUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatPredicate.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatShortUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/ints/collections/AbstractIntCollection.java create mode 100644 src/main/java/speiger/src/collections/ints/collections/IntBidirectionalIterator.java create mode 100644 src/main/java/speiger/src/collections/ints/collections/IntCollection.java create mode 100644 src/main/java/speiger/src/collections/ints/collections/IntIterable.java create mode 100644 src/main/java/speiger/src/collections/ints/collections/IntIterator.java create mode 100644 src/main/java/speiger/src/collections/ints/collections/IntSplititerator.java create mode 100644 src/main/java/speiger/src/collections/ints/collections/IntStack.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/IntComparator.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/IntConsumer.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/IntSupplier.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntBooleanConsumer.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntByteConsumer.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntCharConsumer.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntDoubleConsumer.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntFloatConsumer.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntIntConsumer.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntLongConsumer.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntObjectConsumer.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntShortConsumer.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2ByteFunction.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2CharFunction.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2DoubleFunction.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2FloatFunction.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2LongFunction.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2ShortFunction.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntBooleanUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntByteUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntCharUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntDoubleUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntFloatUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntFunction.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntIntUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntLongUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntObjectUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntPredicate.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntShortUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/ints/lists/IntListIterator.java create mode 100644 src/main/java/speiger/src/collections/ints/maps/abstracts/AbstractInt2ObjectMap.java create mode 100644 src/main/java/speiger/src/collections/ints/maps/impl/misc/Int2ObjectArrayMap.java create mode 100644 src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectMap.java create mode 100644 src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectOrderedMap.java create mode 100644 src/main/java/speiger/src/collections/ints/sets/AbstractIntSet.java create mode 100644 src/main/java/speiger/src/collections/ints/sets/IntOrderedSet.java create mode 100644 src/main/java/speiger/src/collections/ints/sets/IntSet.java create mode 100644 src/main/java/speiger/src/collections/ints/utils/IIntArray.java create mode 100644 src/main/java/speiger/src/collections/ints/utils/IntArrays.java create mode 100644 src/main/java/speiger/src/collections/ints/utils/IntCollections.java create mode 100644 src/main/java/speiger/src/collections/ints/utils/IntIterables.java create mode 100644 src/main/java/speiger/src/collections/ints/utils/IntIterators.java create mode 100644 src/main/java/speiger/src/collections/ints/utils/IntSplititerators.java create mode 100644 src/main/java/speiger/src/collections/longs/collections/AbstractLongCollection.java create mode 100644 src/main/java/speiger/src/collections/longs/collections/LongBidirectionalIterator.java create mode 100644 src/main/java/speiger/src/collections/longs/collections/LongCollection.java create mode 100644 src/main/java/speiger/src/collections/longs/collections/LongIterable.java create mode 100644 src/main/java/speiger/src/collections/longs/collections/LongIterator.java create mode 100644 src/main/java/speiger/src/collections/longs/collections/LongSplititerator.java create mode 100644 src/main/java/speiger/src/collections/longs/collections/LongStack.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/LongComparator.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/LongConsumer.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/LongSupplier.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongBooleanConsumer.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongByteConsumer.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongCharConsumer.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongDoubleConsumer.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongFloatConsumer.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongIntConsumer.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongLongConsumer.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongObjectConsumer.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongShortConsumer.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2ByteFunction.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2CharFunction.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2DoubleFunction.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2FloatFunction.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2IntFunction.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2ShortFunction.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongBooleanUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongByteUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongCharUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongDoubleUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongFloatUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongFunction.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongIntUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongLongUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongObjectUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongPredicate.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongShortUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/longs/lists/LongListIterator.java create mode 100644 src/main/java/speiger/src/collections/longs/sets/AbstractLongSet.java create mode 100644 src/main/java/speiger/src/collections/longs/sets/LongOpenHashSet.java create mode 100644 src/main/java/speiger/src/collections/longs/sets/LongSet.java create mode 100644 src/main/java/speiger/src/collections/longs/utils/LongArrays.java create mode 100644 src/main/java/speiger/src/collections/longs/utils/LongCollections.java create mode 100644 src/main/java/speiger/src/collections/longs/utils/LongIterables.java create mode 100644 src/main/java/speiger/src/collections/longs/utils/LongIterators.java create mode 100644 src/main/java/speiger/src/collections/longs/utils/LongSplititerators.java create mode 100644 src/main/java/speiger/src/collections/objects/collections/AbstractObjectCollection.java create mode 100644 src/main/java/speiger/src/collections/objects/collections/ObjectBidirectionalIterator.java create mode 100644 src/main/java/speiger/src/collections/objects/collections/ObjectCollection.java create mode 100644 src/main/java/speiger/src/collections/objects/collections/ObjectIterable.java create mode 100644 src/main/java/speiger/src/collections/objects/collections/ObjectIterator.java create mode 100644 src/main/java/speiger/src/collections/objects/collections/ObjectSplititerator.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/ObjectSupplier.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectBooleanConsumer.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectByteConsumer.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectCharConsumer.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectDoubleConsumer.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectFloatConsumer.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectIntConsumer.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectLongConsumer.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectObjectConsumer.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectShortConsumer.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectBooleanUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectByteUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectCharUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectDoubleUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectFloatUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectIntUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectLongUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectObjectUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectShortUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/Predicate.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToByteFunction.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToCharFunction.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToDoubleFunction.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToFloatFunction.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToIntFunction.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToLongFunction.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToShortFunction.java create mode 100644 src/main/java/speiger/src/collections/objects/functions/function/UnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/objects/lists/AbstractObjectList.java create mode 100644 src/main/java/speiger/src/collections/objects/lists/ObjectArrayList.java create mode 100644 src/main/java/speiger/src/collections/objects/lists/ObjectList.java create mode 100644 src/main/java/speiger/src/collections/objects/lists/ObjectListIterator.java create mode 100644 src/main/java/speiger/src/collections/objects/maps/abstracts/AbstractObject2ObjectMap.java create mode 100644 src/main/java/speiger/src/collections/objects/maps/impl/hash/Object2ObjectOpenHashMap.java create mode 100644 src/main/java/speiger/src/collections/objects/maps/interfaces/Object2ObjectMap.java create mode 100644 src/main/java/speiger/src/collections/objects/sets/AbstractObjectSet.java create mode 100644 src/main/java/speiger/src/collections/objects/sets/ObjectOpenHashSet.java create mode 100644 src/main/java/speiger/src/collections/objects/sets/ObjectOrderedSet.java create mode 100644 src/main/java/speiger/src/collections/objects/sets/ObjectSet.java create mode 100644 src/main/java/speiger/src/collections/objects/utils/ObjectArrays.java create mode 100644 src/main/java/speiger/src/collections/objects/utils/ObjectCollections.java create mode 100644 src/main/java/speiger/src/collections/objects/utils/ObjectIterables.java create mode 100644 src/main/java/speiger/src/collections/objects/utils/ObjectIterators.java create mode 100644 src/main/java/speiger/src/collections/objects/utils/ObjectSplititerators.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/ShortComparator.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/ShortConsumer.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/ShortSupplier.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortBooleanConsumer.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortByteConsumer.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortCharConsumer.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortDoubleConsumer.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortFloatConsumer.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortIntConsumer.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortLongConsumer.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortObjectConsumer.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortShortConsumer.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2ByteFunction.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2CharFunction.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2DoubleFunction.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2FloatFunction.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2IntFunction.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2LongFunction.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortBooleanUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortByteUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortCharUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortDoubleUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortFloatUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortFunction.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortIntUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortLongUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortObjectUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortPredicate.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortShortUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortUnaryOperator.java create mode 100644 src/main/java/speiger/src/collections/utils/HashUtil.java create mode 100644 src/main/java/speiger/src/collections/utils/IArray.java create mode 100644 src/main/java/speiger/src/collections/utils/ISizeProvider.java create mode 100644 src/main/java/speiger/src/collections/utils/ITrimmable.java create mode 100644 src/main/java/speiger/src/collections/utils/SanityChecks.java create mode 100644 src/main/java/speiger/src/collections/utils/Stack.java create mode 100644 src/main/java/zone/rong/rongasm/api/CaptureSet.java create mode 100644 src/main/java/zone/rong/rongasm/api/DummyMap.java create mode 100644 src/main/java/zone/rong/rongasm/api/LoliHelpers.java create mode 100644 src/main/java/zone/rong/rongasm/api/LoliReflector.java create mode 100644 src/main/java/zone/rong/rongasm/api/LoliStringPool.java create mode 100644 src/main/java/zone/rong/rongasm/api/ResourceCache.java create mode 100644 src/main/resources/META-INF/archaicfix_at.cfg create mode 100644 src/main/resources/ModulSettings.json create mode 100644 src/main/resources/letsencrypt/isrg-root-x2.pem create mode 100644 src/main/resources/letsencrypt/isrgrootx1.pem create mode 100644 src/main/resources/mixins.archaicfix.early.json create mode 100644 src/main/resources/mixins.archaicfix.json create mode 100644 src/main/resources/mixins.archaicfix.late.json create mode 100644 src/main/resources/pack.mcmeta create mode 100644 src/main/resources/resourcepacks/vanilla_overrides/assets/minecraft/textures/blocks/double_plant_grass_bottom.png create mode 100644 src/main/resources/resourcepacks/vanilla_overrides/assets/minecraft/textures/blocks/double_plant_grass_top.png create mode 100644 src/main/resources/resourcepacks/vanilla_overrides/assets/minecraft/textures/blocks/tallgrass.png diff --git a/dependencies.gradle b/dependencies.gradle index 12c1009df..9e70962d1 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -41,10 +41,30 @@ dependencies { compileOnly("com.github.GTNewHorizons:ProjectRed:4.7.12-GTNH:dev") compileOnly(files("dependencies/SmartRender-1.7.10-2.1-dev.jar")) + // Because who doesn't want NEI + compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.3.55-GTNH:dev') + + // Notfine Deps compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev") runtimeOnly("com.github.GTNewHorizons:Baubles:1.0.1.16:dev") compileOnly("com.github.GTNewHorizons:twilightforest:2.3.8.18:dev") {transitive = false } devOnlyNonPublishable(rfg.deobf('curse.maven:witchery-69673:2234410')) - runtimeOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughItems:2.3.55-GTNH:dev") + + // ArchaicFix Deps + compileOnly("curse.maven:chickenchunks-229316:2233250") + compileOnly "thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev" + compileOnly('curse.maven:cofh-core-69162:2388751') + compileOnly('com.github.GTNewHorizons:Botania:1.9.19-GTNH:dev') {transitive = false } + compileOnly("org.projectlombok:lombok:1.18.22") {transitive = false } + annotationProcessor("org.projectlombok:lombok:1.18.22") + + compileOnly(rfg.deobf("curse.maven:extrautils-225561:2264383")) + compileOnly(rfg.deobf("curse.maven:dynamiclights-227874:2337326")) + + // HMMMMM + compileOnly(rfg.deobf("curse.maven:journeymap-32274:2367915")) + +// runtimeOnly(deobf("https://github.com/makamys/CoreTweaks/releases/download/0.3.0.4/CoreTweaks-1.7.10-0.3.0.4+nomixin.jar")) + } diff --git a/gradle.properties b/gradle.properties index c6f5bfb8c..a8c90c187 100644 --- a/gradle.properties +++ b/gradle.properties @@ -62,7 +62,7 @@ apiPackage = # Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/ # There can be multiple files in a comma-separated list. # Example value: mymodid_at.cfg,nei_at.cfg -accessTransformersFile = angelica_at.cfg,notfine_at.cfg +accessTransformersFile = angelica_at.cfg,notfine_at.cfg,archaicfix_at.cfg # Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! usesMixins = true diff --git a/src/main/java/ca/fxco/memoryleakfix/MemoryLeakFix.java b/src/main/java/ca/fxco/memoryleakfix/MemoryLeakFix.java new file mode 100644 index 000000000..92c3225e8 --- /dev/null +++ b/src/main/java/ca/fxco/memoryleakfix/MemoryLeakFix.java @@ -0,0 +1,51 @@ +package ca.fxco.memoryleakfix; + +import org.embeddedt.archaicfix.ArchaicLogger; +import org.spongepowered.asm.mixin.MixinEnvironment; +import org.spongepowered.asm.mixin.injection.struct.InjectorGroupInfo; +import org.spongepowered.asm.mixin.transformer.ClassInfo; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.List; +import java.util.Map; + +public class MemoryLeakFix { + public static void forceLoadAllMixinsAndClearSpongePoweredCache() { + ArchaicLogger.LOGGER.info("Forceloading mixins and clearing mixin cache"); + try { + Field noGroupField; + try { + noGroupField = InjectorGroupInfo.Map.class.getDeclaredField("NO_GROUP"); + } catch(NoSuchFieldException e) { + noGroupField = null; + } + if(noGroupField == null || !Modifier.isStatic(noGroupField.getModifiers())) { + ArchaicLogger.LOGGER.info("No need to forceload, this mixin version doesn't have the memory leak"); + return; + } + MixinEnvironment.getCurrentEnvironment().audit(); + noGroupField.setAccessible(true); + Object noGroup = noGroupField.get(null); + Field membersField = noGroup.getClass().getDeclaredField("members"); + membersField.setAccessible(true); + ((List) membersField.get(noGroup)).clear(); // Clear spongePoweredCache + emptyClassInfo(); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + ArchaicLogger.LOGGER.info("Finished clearing mixin cache"); + } + + private static final String OBJECT = "java/lang/Object"; + + private static void emptyClassInfo() throws NoSuchFieldException, IllegalAccessException { + Field cacheField = ClassInfo.class.getDeclaredField("cache"); + cacheField.setAccessible(true); + @SuppressWarnings("unchecked") + Map cache = ((Map)cacheField.get(null)); + ClassInfo jlo = cache.get(OBJECT); + cache.clear(); + cache.put(OBJECT, jlo); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/ArchaicCore.java b/src/main/java/org/embeddedt/archaicfix/ArchaicCore.java new file mode 100644 index 000000000..08f1489c8 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/ArchaicCore.java @@ -0,0 +1,91 @@ +package org.embeddedt.archaicfix; + +import com.google.common.collect.ImmutableMap; +import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader; +import cpw.mods.fml.relauncher.IFMLLoadingPlugin; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.embeddedt.archaicfix.asm.Mixin; +import org.embeddedt.archaicfix.asm.TargetedMod; +import org.embeddedt.archaicfix.asm.transformer.VampirismTransformer; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.embeddedt.archaicfix.config.ConfigException; +import org.embeddedt.archaicfix.config.ConfigurationManager; +import org.embeddedt.archaicfix.helpers.LetsEncryptHelper; + +import java.util.*; +import java.util.stream.Collectors; + +@IFMLLoadingPlugin.Name("ArchaicCore") +@IFMLLoadingPlugin.MCVersion("1.7.10") +public class ArchaicCore implements IFMLLoadingPlugin, IEarlyMixinLoader { + public static final Logger LOGGER = LogManager.getLogger("ArchaicCore"); + static { + VampirismTransformer.init(); + try { + ConfigurationManager.registerConfig(ArchaicConfig.class); + } catch(ConfigException e) { + throw new RuntimeException(e); + } + LetsEncryptHelper.replaceSSLContext(); + } + @Override + public String[] getASMTransformerClass() { + return new String[] { + "org.embeddedt.archaicfix.asm.ArchaicTransformer" + }; + } + + @Override + public String getModContainerClass() { + return null; + } + + @Override + public String getSetupClass() { + return null; + } + + @Override + public void injectData(Map data) { + + } + + @Override + public String getAccessTransformerClass() { + return null; + } + + @Override + public String getMixinConfig() { + return "mixins.archaicfix.early.json"; + } + + public static Set coreMods = new HashSet<>(); + + private static final ImmutableMap MODS_BY_CLASS = ImmutableMap.builder() + .put("optifine.OptiFineForgeTweaker", TargetedMod.OPTIFINE) + .put("fastcraft.Tweaker", TargetedMod.FASTCRAFT) + .put("cofh.asm.LoadingPlugin", TargetedMod.COFHCORE) + .build(); + + private static void detectCoreMods(Set loadedCoreMods) { + MODS_BY_CLASS.forEach((key, value) -> { + if (loadedCoreMods.contains(key)) + coreMods.add(value); + }); + } + + @Override + public List getMixins(Set loadedCoreMods) { + List mixins = new ArrayList<>(); + detectCoreMods(loadedCoreMods); + LOGGER.info("Detected coremods: [" + coreMods.stream().map(TargetedMod::name).collect(Collectors.joining(", ")) + "]"); + for(Mixin mixin : Mixin.values()) { + if(mixin.getPhase() == Mixin.Phase.EARLY && mixin.shouldLoadSide() && mixin.getFilter().test(coreMods)) { + mixins.add(mixin.getMixin()); + } + } + return mixins; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java b/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java new file mode 100644 index 000000000..e0fb581aa --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java @@ -0,0 +1,165 @@ +package org.embeddedt.archaicfix; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.*; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.Mod.EventHandler; +import cpw.mods.fml.common.network.NetworkCheckHandler; +import cpw.mods.fml.common.network.NetworkRegistry; +import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper; +import cpw.mods.fml.relauncher.ReflectionHelper; +import cpw.mods.fml.relauncher.Side; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.network.NetHandlerPlayServer; +import net.minecraftforge.common.MinecraftForge; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; +import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; +import org.embeddedt.archaicfix.proxy.CommonProxy; +import thaumcraft.api.ThaumcraftApi; + +import java.util.*; + +@Mod(modid = ArchaicFix.MODID, version = ArchaicFix.VERSION, dependencies = "required-after:gtnhmixins@[2.0.0,);", guiFactory = "org.embeddedt.archaicfix.config.ArchaicGuiConfigFactory") +public class ArchaicFix +{ + public static final String MODID = "archaicfix"; + public static final String VERSION = "ArchaicFix"; + + private FixHelper helper; + + public static final SimpleNetworkWrapper NETWORK = NetworkRegistry.INSTANCE.newSimpleChannel("archaicfix"); + public static volatile boolean IS_VANILLA_SERVER = false; + public static boolean NEI_INSTALLED = false; + + @SidedProxy(clientSide = "org.embeddedt.archaicfix.proxy.ClientProxy", serverSide = "org.embeddedt.archaicfix.proxy.CommonProxy") + public static CommonProxy proxy; + + @EventHandler + public void onConstruct(FMLConstructionEvent event) { + try { + Class.forName("com.gildedgames.util.threadedlighting.asm.TLTransformer"); + ArchaicLogger.LOGGER.fatal("=================== WARNING ==================="); + ArchaicLogger.LOGGER.fatal("A version of GG Util that includes threaded lighting was detected. ArchaicFix has prevented launching to avoid issues. Please download a fixed version of GG Util: https://www.curseforge.com/minecraft/mc-mods/gilded-game-utils-fix."); + ArchaicLogger.LOGGER.fatal("==============================================="); + throw new UnsupportedOperationException("Please download a fixed version of GG Util: https://www.curseforge.com/minecraft/mc-mods/gilded-game-utils-fix"); + } catch(ClassNotFoundException e) { + + } + } + + @EventHandler + public void preinit(FMLPreInitializationEvent event) + { + int nextID = ReflectionHelper.getPrivateValue(Entity.class, null, "field_70152_a", "nextEntityID"); + if(nextID == 0) { + ReflectionHelper.setPrivateValue(Entity.class, null, 1, "field_70152_a", "nextEntityID"); + ArchaicLogger.LOGGER.info("Fixed MC-111480"); + } + MinecraftForge.EVENT_BUS.register(new LeftClickEventHandler()); + helper = new FixHelper(); + MinecraftForge.EVENT_BUS.register(helper); + FMLCommonHandler.instance().bus().register(helper); + proxy.preinit(); + NEI_INSTALLED = Loader.isModLoaded("NotEnoughItems"); + //SoundSystemConfig.setNumberNormalChannels(1073741824); + //SoundSystemConfig.setNumberStreamingChannels(1073741823); + } + + @EventHandler + public void init(FMLInitializationEvent event) { + if(event.getSide() == Side.CLIENT) { + if(ArchaicConfig.enableThreadedChunkUpdates + && ArchaicConfig.enableOcclusionTweaks) { + ThreadedChunkUpdateHelper.instance = new ThreadedChunkUpdateHelper(); + ThreadedChunkUpdateHelper.instance.init(); + } + } + } + + @EventHandler + public void serverStart(FMLServerStartingEvent event) { + event.registerServerCommand(new CommandDebugUpdateQueue()); + } + + private void printRecipeDebug() { + if(!ArchaicConfig.cacheRecipes) + return; + HashMap, Integer> recipeTypeMap = new HashMap<>(); + for(Object o : CraftingManager.getInstance().getRecipeList()) { + recipeTypeMap.compute(((IRecipe)o).getClass(), (key, oldValue) -> { + if(oldValue == null) + return 1; + else + return oldValue + 1; + }); + } + recipeTypeMap.entrySet().stream() + .sorted(Comparator.comparingInt(pair -> pair.getValue())) + .forEach(pair -> { + String acceleratedSuffix = IAcceleratedRecipe.class.isAssignableFrom(pair.getKey()) ? " (accelerated)" : ""; + ArchaicLogger.LOGGER.info("There are " + pair.getValue() + " recipes of type " + pair.getKey().getName() + acceleratedSuffix); + }); + int totalRecipes = recipeTypeMap.values().stream().reduce(0, Integer::sum); + int acceleratedRecipes = recipeTypeMap.entrySet().stream().filter(pair -> IAcceleratedRecipe.class.isAssignableFrom(pair.getKey())).map(Map.Entry::getValue).reduce(0, Integer::sum); + ArchaicLogger.LOGGER.info(acceleratedRecipes + " / " + totalRecipes + " recipes are accelerated!"); + } + + private void removeThaumcraftLeak() { + if(!Loader.isModLoaded("Thaumcraft")) { + boolean thaumcraftGhostApiPresent = false; + try { + Class.forName("thaumcraft.api.ThaumcraftApi"); + thaumcraftGhostApiPresent = true; + } catch(Exception e) { + + } + if(thaumcraftGhostApiPresent) { + try { + ArchaicLogger.LOGGER.info("Cleared " + ThaumcraftApi.objectTags.size() + " unused Thaumcraft aspects"); + ThaumcraftApi.objectTags.clear(); + } catch (IncompatibleClassChangeError e) { + ArchaicLogger.LOGGER.info("Thaumcraft does not have an objectTags field"); + } + try { + ArchaicLogger.LOGGER.info("Cleared " + ThaumcraftApi.groupedObjectTags.size() + " unused Thaumcraft grouped aspects"); + ThaumcraftApi.groupedObjectTags.clear(); + } catch (IncompatibleClassChangeError e) { + ArchaicLogger.LOGGER.info("Thaumcraft does not have a groupedObjectTags field"); + } + } + } + } + + + + @EventHandler + public void loadComplete(FMLLoadCompleteEvent event) { + proxy.loadcomplete(); + printRecipeDebug(); + removeThaumcraftLeak(); + } + + @NetworkCheckHandler + public boolean doVersionCheck(Map mods, Side side) { + /* + if(mods.containsKey(Tags.MODID)) { + String otherVersion = mods.get(Tags.MODID); + if(!otherVersion.equals(Tags.VERSION)) { + ArchaicLogger.LOGGER.error("Remote side " + side + " has different version " + otherVersion); + return false; + } + } + */ + return true; + } + + public static boolean isArchaicConnection(NetHandlerPlayServer connection) { + return FixHelper.unmoddedNetHandlers.contains(connection); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/ArchaicLogger.java b/src/main/java/org/embeddedt/archaicfix/ArchaicLogger.java new file mode 100644 index 000000000..a8e54dba6 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/ArchaicLogger.java @@ -0,0 +1,8 @@ +package org.embeddedt.archaicfix; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class ArchaicLogger { + public static final Logger LOGGER = LogManager.getLogger("ArchaicFix"); +} diff --git a/src/main/java/org/embeddedt/archaicfix/CommandDebugUpdateQueue.java b/src/main/java/org/embeddedt/archaicfix/CommandDebugUpdateQueue.java new file mode 100644 index 000000000..ce964bf84 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/CommandDebugUpdateQueue.java @@ -0,0 +1,39 @@ +package org.embeddedt.archaicfix; + +import com.mojang.realmsclient.gui.ChatFormatting; +import cpw.mods.fml.relauncher.ReflectionHelper; +import net.minecraft.command.CommandBase; +import net.minecraft.command.ICommandSender; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.NextTickListEntry; +import net.minecraft.world.WorldServer; + +import java.util.TreeSet; + +public class CommandDebugUpdateQueue extends CommandBase { + @Override + public String getCommandName() { + return "debugupdatequeue"; + } + + @Override + public String getCommandUsage(ICommandSender p_71518_1_) { + return "/debugupdatequeue"; + } + + @Override + public void processCommand(ICommandSender sender, String[] p_71515_2_) { + MinecraftServer server = MinecraftServer.getServer(); + if(server != null) { + sender.addChatMessage(new ChatComponentText("Update queue sizes:")); + for(WorldServer world : server.worldServers) { + TreeSet ticks = ReflectionHelper.getPrivateValue(WorldServer.class, world, "field_73065_O", "pendingTickListEntriesTreeSet"); + if(ticks.size() > 0) + sender.addChatMessage(new ChatComponentText("Dimension " + world.provider.dimensionId + ": " + ticks.size())); + } + } else { + sender.addChatMessage(new ChatComponentText(ChatFormatting.RED + "No server found.")); + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/FixHelper.java b/src/main/java/org/embeddedt/archaicfix/FixHelper.java new file mode 100644 index 000000000..d04275984 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/FixHelper.java @@ -0,0 +1,72 @@ +package org.embeddedt.archaicfix; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.network.FMLNetworkEvent; +import cpw.mods.fml.common.network.handshake.IHandshakeState; +import io.netty.channel.ChannelHandlerContext; +import io.netty.util.Attribute; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.EntitySlime; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.network.NetHandlerPlayServer; +import net.minecraftforge.event.entity.living.LivingEvent; +import net.minecraftforge.oredict.OreDictionary; +import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; +import org.embeddedt.archaicfix.helpers.OreDictIterator; + +import java.util.*; + +public class FixHelper { + public static ArrayList recipesHoldingPotentialItems = new ArrayList<>(); + public static Set unmoddedNetHandlers = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>())); + + public static Map>> handshakeStateMap = Collections.synchronizedMap(new WeakHashMap<>()); + + @SubscribeEvent + public void onSizeUpdate(LivingEvent.LivingUpdateEvent event) { + EntityLivingBase entity = event.entityLiving; + if(entity.worldObj.isRemote && entity instanceof EntitySlime && entity.getAge() <= 1) { + EntitySlime slime = (EntitySlime)entity; + float newSize = 0.6F * (float)slime.getSlimeSize(); + slime.width = newSize; + slime.height = newSize; + slime.setPosition(slime.posX, slime.posY, slime.posZ); + } + } + + @SubscribeEvent + public void onOreRegister(OreDictionary.OreRegisterEvent event) { + for(IAcceleratedRecipe recipe : recipesHoldingPotentialItems) { + if(recipe != null) + recipe.invalidatePotentialItems(); + } + recipesHoldingPotentialItems.clear(); + OreDictIterator.clearCache(event.Name); + } + + @SubscribeEvent + public void onClientConnect(FMLNetworkEvent.ClientConnectedToServerEvent event) { + if(!event.connectionType.equals("MODDED")) { + ArchaicLogger.LOGGER.info("Connected to vanilla server"); + ArchaicFix.IS_VANILLA_SERVER = true; + } + } + + @SubscribeEvent + public void onNetworkRegister(FMLNetworkEvent.CustomPacketRegistrationEvent event) { + if(event.operation.equals("REGISTER")) { + boolean hasArchaic = event.registrations.contains("archaicfix"); + if(event.handler instanceof NetHandlerPlayServer) { + if(!hasArchaic) { + ArchaicLogger.LOGGER.info("Player is connecting without ArchaicFix installed"); + unmoddedNetHandlers.add(event.handler); + } + + } else { + ArchaicFix.IS_VANILLA_SERVER = !hasArchaic; + if(!hasArchaic) + ArchaicLogger.LOGGER.info("Connecting to server without ArchaicFix installed"); + } + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/LeftClickEventHandler.java b/src/main/java/org/embeddedt/archaicfix/LeftClickEventHandler.java new file mode 100644 index 000000000..daddaf3f3 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/LeftClickEventHandler.java @@ -0,0 +1,89 @@ +package org.embeddedt.archaicfix; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import net.minecraft.block.Block; +import net.minecraft.command.IEntitySelector; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; + +import javax.annotation.Nullable; +import java.util.List; + +public final class LeftClickEventHandler { + + public LeftClickEventHandler() {} + + @SubscribeEvent + public void onLeftClick(PlayerInteractEvent event) { + if(event.action == PlayerInteractEvent.Action.LEFT_CLICK_BLOCK) { + Block block = event.world.getBlock(event.x, event.y, event.z); + if(block.getCollisionBoundingBoxFromPool(event.world, event.x, event.y, event.z) != null) { + return; + } + + EntityPlayer entityPlayer = event.entityPlayer; + + float blockReachDistance = 4.5F; + + Vec3 from = Vec3.createVectorHelper(entityPlayer.posX, entityPlayer.posY + (double)entityPlayer.getEyeHeight(), entityPlayer.posZ); + Vec3 vec3d = entityPlayer.getLook(1.0F); + Vec3 to = from.addVector(vec3d.xCoord * blockReachDistance, vec3d.yCoord * blockReachDistance, vec3d.zCoord * blockReachDistance); + + Entity targetEntity = getEntityClosestToStartPos(entityPlayer, event.world, from, to); + + if(targetEntity != null) { + if (!event.world.isRemote) { + entityPlayer.attackTargetEntityWithCurrentItem(targetEntity); + } + event.setCanceled(true); + } + } + + + } + + private AxisAlignedBB safeGenBoundingBox(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { + return AxisAlignedBB.getBoundingBox( + Math.min(minX, maxX), + Math.min(minY, maxY), + Math.min(minZ, maxZ), + Math.max(minX, maxX), + Math.max(minY, maxY), + Math.max(minZ, maxZ) + ); + } + + private Entity getEntityClosestToStartPos(Entity entityIn, World world, Vec3 startPos, Vec3 endPos) { + Entity entity = null; + AxisAlignedBB searchBB = safeGenBoundingBox(startPos.xCoord,startPos.yCoord,startPos.zCoord, endPos.xCoord, endPos.yCoord, endPos.zCoord); + List list = world.getEntitiesWithinAABBExcludingEntity(entityIn, searchBB, new IEntitySelector() { + @Override + public boolean isEntityApplicable(Entity p_82704_1_) { + return p_82704_1_ != null && p_82704_1_.canBeCollidedWith(); + } + }); + + double d0 = 0.0D; + AxisAlignedBB axisAlignedBB; + + for(Entity entity1 : list) { + axisAlignedBB = entity1.boundingBox.expand(0.3D, 0.3D, 0.3D); + MovingObjectPosition raytraceResult = axisAlignedBB.calculateIntercept(startPos, endPos); + + if(raytraceResult != null) { + double d1 = startPos.squareDistanceTo(raytraceResult.hitVec); + + if(d1 < d0 || d0 == 0.0D) { + entity = entity1; + d0 = d1; + } + } + } + return entity; + } +} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/asm/ArchaicTransformer.java b/src/main/java/org/embeddedt/archaicfix/asm/ArchaicTransformer.java new file mode 100644 index 000000000..ea75fe222 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/asm/ArchaicTransformer.java @@ -0,0 +1,22 @@ +package org.embeddedt.archaicfix.asm; + +import net.minecraft.launchwrapper.IClassTransformer; +import org.embeddedt.archaicfix.asm.transformer.VampirismTransformer; + +import java.util.*; + +public class ArchaicTransformer implements IClassTransformer { + + private static final List transformers = Arrays.asList( + //new ThreadedBlockTransformer(), + new VampirismTransformer() + ); + + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) { + for(IClassTransformer transformer : transformers) { + basicClass = transformer.transform(name, transformedName, basicClass); + } + return basicClass; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/asm/LateMixinPlugin.java b/src/main/java/org/embeddedt/archaicfix/asm/LateMixinPlugin.java new file mode 100644 index 000000000..bf3790a27 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/asm/LateMixinPlugin.java @@ -0,0 +1,41 @@ +package org.embeddedt.archaicfix.asm; + +import com.gtnewhorizon.gtnhmixins.ILateMixinLoader; +import com.gtnewhorizon.gtnhmixins.LateMixin; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.embeddedt.archaicfix.ArchaicCore; + +import java.util.*; +import java.util.stream.Collectors; + +@LateMixin +public class LateMixinPlugin implements ILateMixinLoader { + private static final Logger LOGGER = LogManager.getLogger(); + @Override + public String getMixinConfig() { + return "mixins.archaicfix.late.json"; + } + + @Override + public List getMixins(Set loadedMods) { + List mixins = new ArrayList<>(); + Set validMods = new HashSet<>(ArchaicCore.coreMods); + HashMap modById = new HashMap<>(); + for(TargetedMod t : TargetedMod.values()) { + if(t.getModId() != null) + modById.put(t.getModId(), t); + } + for(String modId : loadedMods) { + TargetedMod t = modById.get(modId); + if(t != null) + validMods.add(t); + } + LOGGER.info("Detected mods: [" + validMods.stream().map(TargetedMod::name).collect(Collectors.joining(", ")) + "]"); + for(Mixin mixin : Mixin.values()) { + if(mixin.getPhase() == Mixin.Phase.LATE && mixin.shouldLoadSide() && mixin.getFilter().test(validMods)) + mixins.add(mixin.getMixin()); + } + return mixins; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/asm/Mixin.java b/src/main/java/org/embeddedt/archaicfix/asm/Mixin.java new file mode 100644 index 000000000..914941d36 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/asm/Mixin.java @@ -0,0 +1,164 @@ +package org.embeddedt.archaicfix.asm; + +import cpw.mods.fml.relauncher.FMLLaunchHandler; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.embeddedt.archaicfix.helpers.DragonAPIHelper; + +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.function.Predicate; + +@RequiredArgsConstructor +public enum Mixin { + // COMMON MIXINS + common_chickenchunks_MixinPlayerChunkViewerManager(Side.COMMON, Phase.EARLY, require(TargetedMod.CHICKENCHUNKS), "chickenchunks.MixinPlayerChunkViewerManager"), + common_core_AccessorEntityLiving(Side.COMMON, Phase.EARLY, always(), "core.AccessorEntityLiving"), + common_core_MixinEntityPlayerMP(Side.COMMON, Phase.EARLY, always(), "core.MixinEntityPlayerMP"), + common_core_MixinWorldServer(Side.COMMON, Phase.EARLY, always(), "core.MixinWorldServer"), + common_core_MixinMapGenStructure(Side.COMMON, Phase.EARLY, always(), "core.MixinMapGenStructure"), + common_core_MixinEntityVillager(Side.COMMON, Phase.EARLY, always(), "core.MixinEntityVillager"), + common_core_MixinMerchantRecipe(Side.COMMON, Phase.EARLY, always(), "core.MixinMerchantRecipe"), + common_core_MixinAxisAlignedBB(Side.COMMON, Phase.EARLY, always(), "core.MixinAxisAlignedBB"), + common_core_MixinMaterialLiquid(Side.COMMON, Phase.EARLY, always(), "core.MixinMaterialLiquid"), + common_core_MixinChunkProviderServer(Side.COMMON, Phase.EARLY, always(), "core.MixinChunkProviderServer"), + common_core_MixinSpawnerAnimals(Side.COMMON, Phase.EARLY, always(), "core.MixinSpawnerAnimals"), + common_core_MixinShapedOreRecipe(Side.COMMON, Phase.EARLY, always(), "core.MixinShapedOreRecipe"), + common_core_MixinLongHashMap(Side.COMMON, Phase.EARLY, always(), "core.MixinLongHashMap"), + common_core_MixinBlock(Side.COMMON, Phase.EARLY, always(), "core.MixinBlock"), + common_core_MixinEnchantmentHelper(Side.COMMON, Phase.EARLY, always(), "core.MixinEnchantmentHelper"), + common_core_MixinWorldChunkManager(Side.COMMON, Phase.EARLY, always(), "core.MixinWorldChunkManager"), + common_core_MixinShapedRecipes(Side.COMMON, Phase.EARLY, always(), "core.MixinShapedRecipes"), + common_core_MixinShapelessOreRecipe(Side.COMMON, Phase.EARLY, always(), "core.MixinShapelessOreRecipe"), + common_core_MixinShapelessRecipes(Side.COMMON, Phase.EARLY, always(), "core.MixinShapelessRecipes"), + common_core_MixinEntityLiving(Side.COMMON, Phase.EARLY, always(), "core.MixinEntityLiving"), + common_core_MixinWorld(Side.COMMON, Phase.EARLY, always(), "core.MixinWorld"), + common_core_MixinEntityTrackerEntry(Side.COMMON, Phase.EARLY, always(), "core.MixinEntityTrackerEntry"), + common_core_MixinEntityXPOrb(Side.COMMON, Phase.EARLY, always(), "core.MixinEntityXPOrb"), + common_core_MixinEntityItem(Side.COMMON, Phase.EARLY, avoid(TargetedMod.SHIPSMOD).and(m -> ArchaicConfig.itemLagReduction), "core.MixinEntityItem"), + common_core_MixinEntity(Side.COMMON, Phase.EARLY, always(), "core.MixinEntity"), + common_core_MixinForgeChunkManager(Side.COMMON, Phase.EARLY, always(), "core.MixinForgeChunkManager"), + common_core_MixinChunk(Side.COMMON, Phase.EARLY, always(), "core.MixinChunk"), + common_core_MixinStructureStart(Side.COMMON, Phase.EARLY, always(), "core.MixinStructureStart"), + common_core_MixinOreDictionary(Side.COMMON, Phase.EARLY, always(), "core.MixinOreDictionary"), + common_core_MixinChunkProviderHell(Side.COMMON, Phase.EARLY, always(), "core.MixinChunkProviderHell"), + common_core_MixinASMData(Side.COMMON, Phase.EARLY, always(), "core.MixinASMData"), + common_core_MixinModCandidate(Side.COMMON, Phase.EARLY, avoid(TargetedMod.COFHCORE), "core.MixinModCandidate"), + common_core_MixinNetworkDispatcher(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetworkDispatcher"), + common_core_MixinNetworkManager(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetworkManager"), + common_core_MixinEmbeddedChannel(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinEmbeddedChannel"), + common_core_MixinNetHandlerPlayServer(Side.COMMON, Phase.EARLY, always(), "core.MixinNetHandlerPlayServer"), + common_core_MixinObjectIntIdentityMap(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.optimizeObjectIntIdentityMap, "core.MixinObjectIntIdentityMap"), + common_gt6_MixinCR(Side.COMMON, Phase.LATE, require(TargetedMod.GREGTECH6), "gt6.MixinCR"), + common_lighting_MixinAnvilChunkLoader(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinAnvilChunkLoader"), + common_lighting_MixinChunk(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinChunk"), + common_lighting_MixinChunkProviderServer(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinChunkProviderServer"), + common_lighting_MixinChunkVanilla(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinChunkVanilla"), + common_lighting_MixinExtendedBlockStorage(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinExtendedBlockStorage"), + common_lighting_MixinSPacketChunkData(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinSPacketChunkData"), + common_lighting_MixinWorld(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinWorld_Lighting"), + common_mrtjp_MixinBlockUpdateHandler(Side.COMMON, Phase.LATE, require(TargetedMod.MRTJPCORE), "mrtjp.MixinBlockUpdateHandler"), + // CLIENT MIXINS + client_core_MixinThreadDownloadImageData(Side.CLIENT, Phase.EARLY, always(), "core.MixinThreadDownloadImageData"), + client_core_MixinBlockFence(Side.CLIENT, Phase.EARLY, always(), "core.MixinBlockFence"), + client_core_MixinEntityRenderer(Side.CLIENT, Phase.EARLY, always(), "core.MixinEntityRenderer"), + client_core_MixinGuiBeaconButton(Side.CLIENT, Phase.EARLY, always(), "core.MixinGuiBeaconButton"), + client_core_MixinGuiButton(Side.CLIENT, Phase.EARLY, always(), "core.MixinGuiButton"), + client_core_MixinGuiContainerCreative(Side.CLIENT, Phase.EARLY, always(), "core.MixinGuiContainerCreative"), + client_core_MixinIntegratedServer(Side.CLIENT, Phase.EARLY, always(), "core.MixinIntegratedServer"), + client_core_MixinSkinManager(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.fixSkinMemoryLeak, "core.MixinSkinManager"), + client_core_MixinChunkProviderClient(Side.CLIENT, Phase.EARLY, always(), "core.MixinChunkProviderClient"), + client_core_MixinWorldRenderer(Side.CLIENT, Phase.EARLY, m -> !Boolean.valueOf(System.getProperty("archaicFix.disableMC129", "false")), "core.MixinWorldRenderer"), + client_core_MixinMinecraft(Side.CLIENT, Phase.EARLY, always(), "core.MixinMinecraft"), + client_core_MixinNetHandlerPlayClient(Side.CLIENT, Phase.EARLY, always(), "core.MixinNetHandlerPlayClient"), + client_core_MixinGuiCreateWorld(Side.CLIENT, Phase.EARLY, always(), "core.MixinGuiCreateWorld"), + client_core_MixinGuiIngameForge(Side.CLIENT, Phase.EARLY, always(), "core.MixinGuiIngameForge"), + client_core_MixinFMLClientHandler(Side.CLIENT, Phase.EARLY, always(), "core.MixinFMLClientHandler"), + client_core_MixinNetHandlerLoginClient(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetHandlerLoginClient"), + client_core_MixinSplashProgress(Side.CLIENT, Phase.EARLY, always(), "core.MixinSplashProgress"), + client_core_AccessorSplashProgress(Side.CLIENT, Phase.EARLY, always(), "core.AccessorSplashProgress"), + client_core_MixinRenderItem(Side.CLIENT, Phase.EARLY, always(), "core.MixinRenderItem"), + client_lighting_MixinMinecraft(Side.CLIENT, Phase.EARLY, phosphor(), "lighting.MixinMinecraft"), + client_lighting_MixinWorld(Side.CLIENT, Phase.EARLY, phosphor(), "lighting.MixinWorld"), + client_lighting_MixinChunkCache(Side.CLIENT, Phase.EARLY, phosphor(), "lighting.MixinChunkCache"), + + client_optifine_MixinVersionCheckThread(Side.CLIENT, Phase.EARLY, require(TargetedMod.OPTIFINE).and(m -> ArchaicConfig.disableOFVersionCheck), "optifine.MixinVersionCheckThread"), + + client_occlusion_MixinChunk(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableOcclusionTweaks), "occlusion.MixinChunk"), + client_occlusion_MixinEntityRenderer(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableOcclusionTweaks), "occlusion.MixinEntityRenderer"), + client_occlusion_MixinRenderGlobal(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableOcclusionTweaks), "occlusion.MixinRenderGlobal"), + client_occlusion_MixinGuiVideoSettings(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableOcclusionTweaks), "occlusion.MixinGuiVideoSettings"), + client_occlusion_MixinWorldRenderer(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableOcclusionTweaks), "occlusion.MixinWorldRenderer"), + + client_renderdistance_MixinGameSettings(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.raiseMaxRenderDistance), "renderdistance.MixinGameSettings"), + client_renderdistance_MixinRenderGlobal(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.raiseMaxRenderDistance), "renderdistance.MixinRenderGlobal"), + common_renderdistance_MixinPlayerManager(Side.COMMON, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.raiseMaxRenderDistance), "renderdistance.MixinPlayerManager"), + + client_threadedupdates_MixinRenderBlocks(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks), "threadedupdates.MixinRenderBlocks"), + client_threadedupdates_MixinWorldRenderer(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks), "threadedupdates.MixinWorldRenderer"), + client_threadedupdates_MixinTessellator(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks), "threadedupdates.MixinTessellator"), + client_threadedupdates_MixinTessellator_Debug(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks && Boolean.parseBoolean(System.getProperty("archaicfix.debug.verifyTessellatorAccessThread"))), "threadedupdates.MixinTessellator_Debug"), + + // MOD-FILTERED MIXINS + common_lighting_fastcraft_MixinChunk(Side.COMMON, Phase.EARLY, require(TargetedMod.FASTCRAFT).and(phosphor()), "lighting.fastcraft.MixinChunk"), + common_lighting_fastcraft_MixinChunkProviderServer(Side.COMMON, Phase.EARLY, require(TargetedMod.FASTCRAFT).and(phosphor()), "lighting.fastcraft.MixinChunkProviderServer"), + common_lighting_fastcraft_MixinWorld(Side.COMMON, Phase.EARLY, require(TargetedMod.FASTCRAFT).and(phosphor()), "lighting.fastcraft.MixinWorld"), + + common_botania_MixinBlockSpecialFlower(Side.COMMON, Phase.LATE, require(TargetedMod.BOTANIA), "botania.MixinBlockSpecialFlower"), + + common_extrautils_MixinEventHandlerSiege(Side.COMMON, Phase.LATE, require(TargetedMod.EXTRAUTILS), "extrautils.MixinEventHandlerSiege"), + common_extrautils_MixinEventHandlerServer(Side.COMMON, Phase.LATE, require(TargetedMod.EXTRAUTILS), "extrautils.MixinEventHandlerServer"), + common_extrautils_MixinItemDivisionSigil(Side.COMMON, Phase.LATE, require(TargetedMod.EXTRAUTILS), "extrautils.MixinItemDivisionSigil"), + common_extrautils_MixinTileEntityTrashCan(Side.COMMON, Phase.LATE, require(TargetedMod.EXTRAUTILS), "extrautils.MixinTileEntityTrashCan"), + + client_journeymap_MixinTileDrawStep(Side.CLIENT, Phase.LATE, require(TargetedMod.JOURNEYMAP).and(m -> ArchaicConfig.removeJourneymapDebug), "journeymap.MixinTileDrawStep"), + + + // The modFilter argument is a predicate, so you can also use the .and(), .or(), and .negate() methods to mix and match multiple predicates. + ; + + @Getter + public final Side side; + @Getter + public final Phase phase; + @Getter + public final Predicate> filter; + private final String mixin; + + static Predicate> phosphor() { + return m -> ArchaicConfig.enablePhosphor; + } + + static Predicate> require(TargetedMod in) { + return modList -> modList.contains(in); + } + + static Predicate> avoid(TargetedMod in) { + return modList -> !modList.contains(in); + } + + static Predicate> always() { + return m -> true; + } + + enum Side { + COMMON, + CLIENT + } + + public enum Phase { + EARLY, + LATE + } + + public boolean shouldLoadSide() { + return (side == Side.COMMON + || (side == Side.CLIENT && FMLLaunchHandler.side().isClient())); + } + + public String getMixin() { + return side.name().toLowerCase(Locale.ROOT) + "." + mixin; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/asm/TargetedMod.java b/src/main/java/org/embeddedt/archaicfix/asm/TargetedMod.java new file mode 100644 index 000000000..ec8822361 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/asm/TargetedMod.java @@ -0,0 +1,39 @@ +package org.embeddedt.archaicfix.asm; + + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.function.Predicate; + +@RequiredArgsConstructor +public enum TargetedMod { + CHICKENCHUNKS("ChickenChunks", "ChickenChunks"), + MRTJPCORE("MrTJPCore", "MrTJPCoreMod"), + CHUNK_PREGENERATOR("ChunkPregenerator", "chunkpregenerator"), + THERMALEXPANSION("ThermalExpansion", "ThermalExpansion"), + THERMALFOUNDATION("ThermalFoundation", "ThermalFoundation"), + GREGTECH6("GregTech", "gregtech"), + MATTEROVERDRIVE("MatterOverdrive", "mo"), + PROJECTE("ProjectE", "ProjectE"), + TC4TWEAKS("TC4Tweaks", "tc4tweak"), + FASTCRAFT("FastCraft", null), + OPTIFINE("OptiFine", null), + MEKANISM("Mekanism", "Mekanism"), + BOTANIA("Botania", "Botania"), + COFHCORE("CoFHCore", "CoFHCore"), + EXTRAUTILS("ExtraUtilities", "ExtraUtilities"), + DIVINERPG("DivineRPG", "divinerpg"), + SHIPSMOD("ShipsMod", "cuchaz.ships"), + JOURNEYMAP("JourneyMap", "journeymap"), + AM2("ArsMagica2", "arsmagica2"), + FOODPLUS("FoodPlus", "FoodPlus"), + DIVERSITY("Diversity", "diversity"), + AOA("AdventOfAscension", "nevermine") + ; + + @Getter + private final String modName; + @Getter + private final String modId; +} diff --git a/src/main/java/org/embeddedt/archaicfix/asm/transformer/ThreadedBlockTransformer.java b/src/main/java/org/embeddedt/archaicfix/asm/transformer/ThreadedBlockTransformer.java new file mode 100644 index 000000000..57cb40018 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/asm/transformer/ThreadedBlockTransformer.java @@ -0,0 +1,88 @@ +package org.embeddedt.archaicfix.asm.transformer; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import net.minecraft.launchwrapper.IClassTransformer; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.*; + +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; + +import static org.objectweb.asm.Opcodes.ASM5; + +public class ThreadedBlockTransformer implements IClassTransformer { + private static final Set threadedFields = ImmutableSet.of( + "minX", + "minY", + "maxX", + "maxY", + "minZ", + "maxZ" + ); + private static final Map threadedObfFields = ImmutableMap.builder() + .put("field_149759_B", "minX") + .put("field_149760_C", "minY") + .put("field_149755_E", "maxX") + .put("field_149756_F", "maxY") + .put("field_149754_D", "minZ") + .put("field_149757_G", "maxZ") + .build(); + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) { + /* FIXME this doesn't work outside dev at the moment */ + if(true) + return basicClass; + if(!transformedName.startsWith("org.embeddedt.archaicfix")) { + final ClassReader cr = new ClassReader(basicClass); + final ClassWriter cw = new ClassWriter(0); + + final ClassNode cn = new ClassNode(ASM5); + cr.accept(cn, 0); + for (MethodNode m : cn.methods) { + ListIterator insns = m.instructions.iterator(); + boolean transformed = false; + while(insns.hasNext()) { + AbstractInsnNode node = insns.next(); + if(node.getOpcode() == Opcodes.GETFIELD || node.getOpcode() == Opcodes.PUTFIELD) { + boolean isSetter = node.getOpcode() == Opcodes.PUTFIELD; + FieldInsnNode f = (FieldInsnNode)node; + if(f.owner.equals("net/minecraft/block/Block")) { + boolean obfContains = threadedObfFields.containsKey(f.name); + boolean devContains = threadedFields.contains(f.name); + if(obfContains || devContains) { + transformed = true; + ArchaicLogger.LOGGER.info("Transforming threaded block data access in {}.{}()", transformedName, m.name); + f.owner = "org/embeddedt/archaicfix/block/ThreadedBlockData"; + if(obfContains) + f.name = threadedObfFields.get(f.name); + insns.previous(); + if(isSetter) { + /* FIXME: assumes a double is at the top of the stack */ + insns.add(new InsnNode(Opcodes.DUP2_X1)); + insns.add(new InsnNode(Opcodes.POP2)); + } + String m_name = "arch$getThreadedData"; + String m_desc = "()Lorg/embeddedt/archaicfix/block/ThreadedBlockData;"; + insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "net/minecraft/block/Block", m_name, m_desc, false)); + if(isSetter) { + insns.add(new InsnNode(Opcodes.DUP_X2)); + insns.add(new InsnNode(Opcodes.POP)); + } + insns.next(); + insns.next(); + } + } + } + } + } + cn.accept(cw); + return cw.toByteArray(); + } + return basicClass; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/asm/transformer/VampirismTransformer.java b/src/main/java/org/embeddedt/archaicfix/asm/transformer/VampirismTransformer.java new file mode 100644 index 000000000..788e65972 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/asm/transformer/VampirismTransformer.java @@ -0,0 +1,56 @@ +package org.embeddedt.archaicfix.asm.transformer; + +import cpw.mods.fml.relauncher.ReflectionHelper; +import net.minecraft.launchwrapper.IClassTransformer; +import net.minecraft.launchwrapper.Launch; +import net.minecraft.launchwrapper.LaunchClassLoader; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; + +import java.util.Set; + +import static org.objectweb.asm.Opcodes.ACC_TRANSIENT; +import static org.objectweb.asm.Opcodes.ASM5; +import static org.embeddedt.archaicfix.ArchaicLogger.LOGGER; + +public class VampirismTransformer implements IClassTransformer { + public static void init() { + try { + Set transformerExceptions = ReflectionHelper.getPrivateValue(LaunchClassLoader.class, Launch.classLoader, "transformerExceptions"); + transformerExceptions.remove("de.teamlapen.vampirism"); + } catch(Exception e) { + LOGGER.error("Failed to remove Vampirism from transformer exceptions."); + e.printStackTrace(); + } + } + + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) { + if(transformedName.equals("de.teamlapen.vampirism.generation.castle.BlockList")) { + LOGGER.info("Transforming " + transformedName + " to set Block field as transient"); + + try { + final ClassReader cr = new ClassReader(basicClass); + final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + + final ClassNode cn = new ClassNode(ASM5); + cr.accept(cn, 0); + + for (FieldNode fn : cn.fields) { + if (fn.name.equals("block") && fn.desc.equals("Lnet/minecraft/block/Block;")) { + fn.access |= ACC_TRANSIENT; + } + } + + cn.accept(cw); + return cw.toByteArray(); + } catch(Exception e) { + e.printStackTrace(); + } + } + + return basicClass; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java b/src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java new file mode 100644 index 000000000..0fee1293d --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java @@ -0,0 +1,34 @@ +package org.embeddedt.archaicfix.block; + +import net.minecraft.block.Block; + +public class ThreadedBlockData { + public double minX = 0; + public double minY = 0; + public double minZ = 0; + public double maxX = 0; + public double maxY = 0; + public double maxZ = 0; + + public ThreadedBlockData() { + + } + + public ThreadedBlockData(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { + this.minX = minX; + this.minY = minY; + this.minZ = minZ; + this.maxX = maxX; + this.maxY = maxY; + this.maxZ = maxZ; + } + + public ThreadedBlockData(ThreadedBlockData other) { + this.minX = other.minX; + this.minY = other.minY; + this.minZ = other.minZ; + this.maxX = other.maxX; + this.maxY = other.maxY; + this.maxZ = other.maxZ; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java b/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java new file mode 100644 index 000000000..e3bc2f361 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java @@ -0,0 +1,189 @@ +package org.embeddedt.archaicfix.config; + +@Config(modid = "archaicfix") +public class ArchaicConfig { + @Config.Comment("Enables the 1.8-style occlusion culling originally developed by CoFHTweaks. Not compatible with OptiFine or FastCraft.") + @Config.DefaultBoolean(false) + @Config.RequiresMcRestart + public static boolean enableOcclusionTweaks; + + @Config.Comment("EXPERIMENTAL: Enables multi-threaded chunk updating. At the moment it only works if enableOcclusionTweaks is turned on.") + @Config.DefaultBoolean(false) + @Config.RequiresMcRestart + public static boolean enableThreadedChunkUpdates; + + @Config.Comment("The number of threads to use for chunk building. The default is 1, which shouldn't be any laggier than vanilla but will reduce stutter. If you have a lot of cores increasing this may be beneficial.") + @Config.DefaultInt(1) + @Config.RangeInt(min = 1) + @Config.RequiresMcRestart + public static int numChunkUpdateThreads; + + @Config.Comment("Changes the enableThreadedChunkUpdates option to never wait for chunk updates. Improves framerate when blocks are placed or destroyed, at the cost of introducing visual delay. This is analogous to 1.18's 'Chunk Builder' option, false meaning 'Fully Blocking', and true meaning 'Threaded'.") + @Config.DefaultBoolean(false) + public static boolean disableBlockingChunkUpdates; + + @Config.DefaultBoolean(true) + public static boolean hideDownloadingTerrainScreen; + + @Config.Comment("Prevents buttons from showing a yellow text color when hovered, as was done in 1.14+.") + @Config.DefaultBoolean(false) + public static boolean enableNewButtonAppearance; + + @Config.Comment("Use a faster and asynchronous implementation of creative search.") + @Config.DefaultBoolean(true) + public static boolean asyncCreativeSearch; + + @Config.Comment("Cap the integrated server render distance at a minimum of 8 chunks, and adjust despawn ranges so mobs will always despawn properly on low render distances.") + @Config.DefaultBoolean(true) + public static boolean fixMobSpawnsAtLowRenderDist; + + @Config.Comment("Replace the regional difficulty calculation with a TMCW-style one that increases with playtime, not time per chunk.") + @Config.DefaultBoolean(false) + public static boolean betterRegionalDifficulty; + + @Config.Comment("Allow 65000 block updates to be performed per tick, rather than 1000.") + @Config.DefaultBoolean(true) + public static boolean increaseBlockUpdateLimit; + + @Config.Comment("EXPERIMENTAL: Cache matching crafting recipes to avoid needing to scan the whole list each time.") + @Config.DefaultBoolean(false) + public static boolean cacheRecipes; + + @Config.Comment("Disable spawn chunks") + @Config.DefaultBoolean(false) + public static boolean disableSpawnChunks; + + @Config.Comment("Reduce lag caused by item entities") + @Config.DefaultBoolean(true) + @Config.RequiresMcRestart + public static boolean itemLagReduction; + + @Config.Comment("Increase the amount of armor mobs wear on average. From TMCW.") + @Config.DefaultBoolean(false) + public static boolean increaseMobArmor; + + @Config.Comment("Increase the maximum render distance if OptiFine and FastCraft are not installed.") + @Config.DefaultBoolean(false) + public static boolean raiseMaxRenderDistance; + + @Config.Comment("What the maximum render distance should be if raiseMaxRenderDistance is enabled.") + @Config.DefaultInt(32) + @Config.RangeInt(min = 16, max = 128) + public static int newMaxRenderDistance; + + @Config.Comment("EXPERIMENTAL: Replace the Thaumcraft hashing implementation. This really hasn't been tested and probably breaks everything.") + @Config.DefaultBoolean(false) + public static boolean betterThaumcraftHashing; + + @Config.Comment("Log when cascading worldgen occurs.") + @Config.DefaultBoolean(true) + public static boolean logCascadingWorldgen; + + @Config.Comment("Print a stacktrace when cascading worldgen occurs. Use only for development as this will add more lag in game.") + @Config.DefaultBoolean(false) + public static boolean logCascadingWorldgenStacktrace; + + @Config.Comment("Fix instances of cascading worldgen in Mekanism.") + @Config.DefaultBoolean(true) + public static boolean fixMekanismCascadingWorldgen; + + @Config.Comment("Fix instances of cascading worldgen in vanilla Minecraft. Turn this option off if you require 100% seed parity.") + @Config.DefaultBoolean(true) + public static boolean fixVanillaCascadingWorldgen; + + @Config.Comment("Force all mixins to be loaded and the cache to be cleared. This saves RAM, but may reveal bugs in mods' mixin configs. Based on MemoryLeakFix.") + @Config.DefaultBoolean(false) + public static boolean clearMixinCache; + + @Config.Comment("Clean up LaunchClassLoader cache.") + @Config.DefaultBoolean(true) + public static boolean clearLaunchLoaderCache; + + @Config.Comment("Only show GT6 tooltip data when Shift is pressed.") + @Config.DefaultBoolean(true) + public static boolean hideGT6TooltipDataBehindKey; + + @Config.Comment("Fix the 'TickNextTick list out of synch' error.") + @Config.DefaultBoolean(true) + public static boolean fixTickListSynchronization; + + @Config.Comment("Make sure entities don't spawn inside blocks that would make them suffocate. Off by default because it might reduce the number of passive entities that spawn during worldgen.") + @Config.DefaultBoolean(false) + public static boolean preventEntitySuffocationWorldgen; + + @Config.Comment("Show block registry name and meta value in F3, similar to 1.8+.") + @Config.DefaultBoolean(false) + public static boolean showBlockDebugInfo; + + @Config.Comment("Prevent entities outside a certain distance from being ticked. This does not affect tile entities, and is essentially another view distance slider.") + @Config.DefaultBoolean(false) + public static boolean optimizeEntityTicking; + + @Config.Comment("Squared distance outside which most entities aren't ticked, default is 64 blocks.") + @Config.DefaultInt(4096) + public static int optimizeEntityTickingDistance; + + @Config.Comment("Distance in chunks at which blocks are ticked, the default value of 0 means to use the render distance.") + @Config.DefaultInt(0) + public static int optimizeBlockTickingDistance; + + @Config.Comment("List of entities to ignore for entity ticking optimization.") + @Config.DefaultStringList({ "Wither", "EnderDragon" }) + public static String[] optimizeEntityTickingIgnoreList; + + @Config.Comment("Disable OptiFine's version checker.") + @Config.DefaultBoolean(true) + public static boolean disableOFVersionCheck; + + @Config.Comment("Fix TileEntity unloading being laggy.") + @Config.DefaultBoolean(true) + public static boolean fixTEUnloadLag; + + @Config.Comment("Attempt to fix hanging in SP when logging in.") + @Config.DefaultBoolean(true) + public static boolean fixLoginRaceCondition; + + @Config.Comment("Fix MC-1406.") + @Config.DefaultBoolean(true) + public static boolean fixPlacementFlicker; + + @Config.Comment("Optimize vanilla's ID-to-object map.") + @Config.DefaultBoolean(true) + public static boolean optimizeObjectIntIdentityMap; + + @Config.Comment("Fix the client leaking memory by holding on to skins and player instances that aren't needed.") + @Config.DefaultBoolean(true) + public static boolean fixSkinMemoryLeak; + + @Config.Comment("Show memory usage during game load.") + @Config.DefaultBoolean(true) + public static boolean showSplashMemoryBar; + + @Config.Comment("Tweak F3 screen to be closer to modern versions.") + @Config.DefaultBoolean(true) + public static boolean modernizeF3Screen; + + @Config.Comment("Replace tall grass texture with modern version.") + @Config.DefaultBoolean(false) + public static boolean modernizeTextures; + + @Config.Comment("Remove JourneyMap debug feature.") + @Config.DefaultBoolean(false) + public static boolean removeJourneymapDebug; + + @Config.Comment("When true, the Phosphor backport is enabled. Disabling is not recommended as it will generally add lag.") + @Config.DefaultBoolean(true) + public static boolean enablePhosphor; + + @Config.Comment("When true, dropped items will always render as though fancy graphics are enabled.") + @Config.DefaultBoolean(false) + public static boolean forceFancyItems; + + @Config.Comment("Disable Food Plus' update message.") + @Config.DefaultBoolean(true) + public static boolean disableFoodPlusUpdates; + + @Config.Comment("Add the Let's Encrypt root certificates to the default trust store.") + @Config.DefaultBoolean(false) + public static boolean enableLetsEncryptRoot; +} diff --git a/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfig.java b/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfig.java new file mode 100644 index 000000000..576366f1f --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfig.java @@ -0,0 +1,9 @@ +package org.embeddedt.archaicfix.config; + +import net.minecraft.client.gui.GuiScreen; + +public class ArchaicGuiConfig extends SimpleGuiConfig { + public ArchaicGuiConfig(GuiScreen parent) throws ConfigException { + super(parent, ArchaicConfig.class, "archaicfix", "ArchaicFix"); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfigFactory.java b/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfigFactory.java new file mode 100644 index 000000000..94b44c05d --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfigFactory.java @@ -0,0 +1,10 @@ +package org.embeddedt.archaicfix.config; + +import net.minecraft.client.gui.GuiScreen; + +public class ArchaicGuiConfigFactory implements SimpleGuiFactory { + @Override + public Class mainConfigGuiClass() { + return ArchaicGuiConfig.class; + } +} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/config/Config.java b/src/main/java/org/embeddedt/archaicfix/config/Config.java new file mode 100644 index 000000000..320bca568 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/config/Config.java @@ -0,0 +1,113 @@ +package org.embeddedt.archaicfix.config; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Config { + /** + * The mod id that this configuration is associated with. + */ + String modid(); + + /** + * Root element category, defaults to "general". You must not specify an empty string. + */ + String category() default "general"; + + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.TYPE}) + @interface LangKey { + String value(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface Comment { + String[] value(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface Ignore { + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface DefaultBoolean { + boolean value(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface RangeInt { + int min() default Integer.MIN_VALUE; + + int max() default Integer.MAX_VALUE; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface DefaultInt { + int value(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface RangeFloat { + float min() default Float.MIN_VALUE; + + float max() default Float.MAX_VALUE; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface DefaultFloat { + float value(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface DefaultString { + String value(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface Pattern { + String value(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface DefaultEnum { + String value(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface DefaultStringList { + String[] value(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface Name { + String value(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.TYPE}) + @interface RequiresMcRestart { + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD, ElementType.TYPE}) + @interface RequiresWorldRestart { + } +} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/config/ConfigException.java b/src/main/java/org/embeddedt/archaicfix/config/ConfigException.java new file mode 100644 index 000000000..64b221797 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/config/ConfigException.java @@ -0,0 +1,15 @@ +package org.embeddedt.archaicfix.config; + +/** + * A really basic wrapper for config to simplify handling them in external code. + */ +public class ConfigException extends Exception { + + public ConfigException(String message) { + super(message); + } + + public ConfigException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/config/ConfigurationManager.java b/src/main/java/org/embeddedt/archaicfix/config/ConfigurationManager.java new file mode 100644 index 000000000..138fe9f86 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/config/ConfigurationManager.java @@ -0,0 +1,268 @@ +package org.embeddedt.archaicfix.config; + +import cpw.mods.fml.client.config.IConfigElement; +import cpw.mods.fml.client.event.ConfigChangedEvent; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; + +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; +import lombok.val; +import lombok.var; +import net.minecraft.launchwrapper.Launch; +import net.minecraftforge.common.config.ConfigElement; +import net.minecraftforge.common.config.Configuration; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * Class for controlling the loading of configuration files. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ConfigurationManager { + private static final Logger LOGGER = LogManager.getLogger("ArchaicConfig"); + private static final Map configs = new HashMap<>(); + + private static final Map>> configToClassMap = new HashMap<>(); + + private static final ConfigurationManager instance = new ConfigurationManager(); + + private static boolean initialized = false; + + private static Path configDir; + + /** + * Registers a configuration class to be loaded. This should be done in preInit. + * + * @param configClass The class to register. + */ + public static void registerConfig(Class configClass) throws ConfigException { + init(); + val cfg = Optional.ofNullable(configClass.getAnnotation(Config.class)) + .orElseThrow(() -> new ConfigException( + "Class " + configClass.getName() + " does not have a @Config annotation!")); + val category = Optional.of(cfg.category().trim()) + .map((cat) -> cat.length() == 0 ? null : cat) + .orElseThrow(() -> new ConfigException( + "Config class " + configClass.getName() + " has an empty category!")); + val rawConfig = configs.computeIfAbsent(cfg.modid(), (ignored) -> { + val c = new Configuration(configDir.resolve(cfg.modid() + ".cfg").toFile()); + c.load(); + return c; + }); + configToClassMap.computeIfAbsent(rawConfig, (ignored) -> new HashSet<>()).add(configClass); + try { + processConfigInternal(configClass, category, rawConfig); + rawConfig.save(); + } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException | NoSuchFieldException e) { + throw new ConfigException(e); + } + } + + private static void processConfigInternal(Class configClass, String category, Configuration rawConfig) + throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException, + ConfigException { + val cat = rawConfig.getCategory(category); + for (val field : configClass.getDeclaredFields()) { + if (field.getAnnotation(Config.Ignore.class) != null) { + continue; + } + field.setAccessible(true); + val comment = Optional.ofNullable(field.getAnnotation(Config.Comment.class)) + .map(Config.Comment::value) + .map((lines) -> String.join("\n", lines)) + .orElse(""); + val name = Optional.ofNullable(field.getAnnotation(Config.Name.class)) + .map(Config.Name::value) + .orElse(field.getName()); + val langKey = Optional.ofNullable(field.getAnnotation(Config.LangKey.class)) + .map(Config.LangKey::value) + .orElse(name); + val fieldClass = field.getType(); + var boxed = false; + if ((boxed = fieldClass.equals(Boolean.class)) || fieldClass.equals(boolean.class)) { + val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultBoolean.class)) + .map(Config.DefaultBoolean::value) + .orElse(boxed ? (Boolean) field.get(null) : field.getBoolean(null)); + field.setBoolean(null, rawConfig.getBoolean(name, category, defaultValue, comment, langKey)); + } else if ((boxed = fieldClass.equals(Integer.class)) || fieldClass.equals(int.class)) { + val range = Optional.ofNullable(field.getAnnotation(Config.RangeInt.class)); + val min = range.map(Config.RangeInt::min).orElse(Integer.MIN_VALUE); + val max = range.map(Config.RangeInt::max).orElse(Integer.MAX_VALUE); + val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultInt.class)) + .map(Config.DefaultInt::value) + .orElse(boxed ? (Integer) field.get(null) : field.getInt(null)); + field.setInt(null, rawConfig.getInt(name, category, defaultValue, min, max, comment, langKey)); + } else if ((boxed = fieldClass.equals(Float.class)) || fieldClass.equals(float.class)) { + val range = Optional.ofNullable(field.getAnnotation(Config.RangeFloat.class)); + val min = range.map(Config.RangeFloat::min).orElse(Float.MIN_VALUE); + val max = range.map(Config.RangeFloat::max).orElse(Float.MAX_VALUE); + val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultFloat.class)) + .map(Config.DefaultFloat::value) + .orElse(boxed ? (Float) field.get(null) : field.getFloat(null)); + field.setFloat(null, rawConfig.getFloat(name, category, defaultValue, min, max, comment, langKey)); + } else if (fieldClass.equals(String.class)) { + val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultString.class)) + .map(Config.DefaultString::value) + .orElse((String) field.get(null)); + val pattern = Optional.ofNullable(field.getAnnotation(Config.Pattern.class)) + .map(Config.Pattern::value) + .map(Pattern::compile) + .orElse(null); + field.set(null, rawConfig.getString(name, category, defaultValue, comment, langKey, pattern)); + } else if (fieldClass.isEnum()) { + val enumValues = Arrays.stream((Object[]) fieldClass.getDeclaredMethod("values").invoke(null)) + .map((obj) -> (Enum) obj) + .collect(Collectors.toList()); + val defaultValue = (Enum) Optional.ofNullable(field.getAnnotation(Config.DefaultEnum.class)) + .map(Config.DefaultEnum::value) + .map((defName) -> extractField(fieldClass, defName)) + .map(ConfigurationManager::extractValue) + .orElse(field.get(null)); + val possibleValues = enumValues.stream().map(Enum::name).toArray(String[]::new); + var value = rawConfig.getString(name, + category, + defaultValue.name(), + comment + "\nPossible values: " + Arrays.toString(possibleValues) + + "\n", + possibleValues, + langKey); + + try { + if (!Arrays.asList(possibleValues).contains(value)) { + throw new NoSuchFieldException(); + } + val enumField = fieldClass.getDeclaredField(value); + if (!enumField.isEnumConstant()) { + throw new NoSuchFieldException(); + } + field.set(null, enumField.get(null)); + } catch (NoSuchFieldException e) { + LOGGER + .warn("Invalid value " + value + " for enum configuration field " + field.getName() + + " of type " + fieldClass.getName() + " in config class " + + configClass.getName() + "! Using default value of " + defaultValue + "!"); + field.set(null, defaultValue); + } + } else if (fieldClass.isArray() && fieldClass.getComponentType().equals(String.class)) { + val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultStringList.class)).map(Config.DefaultStringList::value).orElse((String[])field.get(null)); + var value = rawConfig.getStringList(name, category, defaultValue, comment, null, langKey); + field.set(null, value); + } else { + throw new ConfigException("Illegal config field: " + field.getName() + " in " + configClass.getName() + + ": Unsupported type " + fieldClass.getName() + + "! Did you forget an @Ignore annotation?"); + } + if (field.isAnnotationPresent(Config.RequiresMcRestart.class)) { + cat.setRequiresMcRestart(true); + } + if (field.isAnnotationPresent(Config.RequiresWorldRestart.class)) { + cat.setRequiresWorldRestart(true); + } + } + } + + @SneakyThrows + private static Field extractField(Class clazz, String field) { + return clazz.getDeclaredField(field); + } + + @SneakyThrows + private static Object extractValue(Field field) { + return field.get(null); + } + + /** + * Process the configuration into a list of config elements usable in config GUI code. + * + * @param configClass The class to process. + * + * @return The configuration elements. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static List getConfigElements(Class configClass) throws ConfigException { + init(); + val cfg = Optional.ofNullable(configClass.getAnnotation(Config.class)) + .orElseThrow(() -> new ConfigException( + "Class " + configClass.getName() + " does not have a @Config annotation!")); + val rawConfig = Optional.ofNullable(configs.get(cfg.modid())) + .map((conf) -> Optional.ofNullable(configToClassMap.get(conf)) + .map((l) -> l.contains(configClass)) + .orElse(false) ? conf : null) + .orElseThrow(() -> new ConfigException( + "Tried to get config elements for non-registered config class!")); + val category = cfg.category(); + val elements = new ConfigElement<>(rawConfig.getCategory(category)).getChildElements(); + return elements.stream().map((element) -> new IConfigElementProxy(element, () -> { + try { + processConfigInternal(configClass, category, rawConfig); + rawConfig.save(); + } catch (IllegalAccessException | + NoSuchMethodException | + InvocationTargetException | + NoSuchFieldException | + ConfigException e) { + e.printStackTrace(); + } + })).collect(Collectors.toList()); + } + + private static File minecraftHome() { + return Launch.minecraftHome != null ? Launch.minecraftHome : new File("."); + } + + private static void init() { + if (initialized) { + return; + } + configDir = minecraftHome().toPath().resolve("config"); + initialized = true; + } + + /** + * Internal, do not use. + */ + public static void registerBus() { + FMLCommonHandler.instance().bus().register(instance); + } + + /** + * Internal, do not use. + * + * @param event The event. + */ + @SubscribeEvent + public void onConfigChanged(ConfigChangedEvent.OnConfigChangedEvent event) { + init(); + val config = configs.get(event.modID); + if (config == null) { + return; + } + val configClasses = configToClassMap.get(config); + configClasses.forEach((configClass) -> { + try { + val category = Optional.ofNullable(configClass.getAnnotation(Config.class)) + .map(Config::category) + .orElseThrow(() -> new ConfigException( + "Failed to get config category for class " + configClass.getName())); + processConfigInternal(configClass, category, config); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/config/IConfigElementProxy.java b/src/main/java/org/embeddedt/archaicfix/config/IConfigElementProxy.java new file mode 100644 index 000000000..b7385d744 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/config/IConfigElementProxy.java @@ -0,0 +1,157 @@ +package org.embeddedt.archaicfix.config; + +import cpw.mods.fml.client.config.ConfigGuiType; +import cpw.mods.fml.client.config.GuiConfigEntries; +import cpw.mods.fml.client.config.GuiEditArrayEntries; +import cpw.mods.fml.client.config.IConfigElement; +import java.util.List; +import java.util.regex.Pattern; + +public class IConfigElementProxy implements IConfigElement { + private final IConfigElement proxied; + private final Runnable onUpdate; + + public IConfigElementProxy(IConfigElement proxied, Runnable onUpdate) { + this.proxied = proxied; + this.onUpdate = onUpdate; + } + + @Override + public boolean isProperty() { + return proxied.isProperty(); + } + + @SuppressWarnings("rawtypes") + @Override + public Class getConfigEntryClass() { + return proxied.getConfigEntryClass(); + } + + @Override + public Class getArrayEntryClass() { + return proxied.getArrayEntryClass(); + } + + @Override + public String getName() { + return proxied.getName(); + } + + @Override + public String getQualifiedName() { + return proxied.getQualifiedName(); + } + + @Override + public String getLanguageKey() { + return proxied.getLanguageKey(); + } + + @Override + public String getComment() { + return proxied.getComment(); + } + + @SuppressWarnings("rawtypes") + @Override + public List getChildElements() { + return proxied.getChildElements(); + } + + @Override + public ConfigGuiType getType() { + return proxied.getType(); + } + + @Override + public boolean isList() { + return proxied.isList(); + } + + @Override + public boolean isListLengthFixed() { + return proxied.isListLengthFixed(); + } + + @Override + public int getMaxListLength() { + return proxied.getMaxListLength(); + } + + @Override + public boolean isDefault() { + return proxied.isDefault(); + } + + @Override + public Object getDefault() { + return proxied.getDefault(); + } + + @Override + public Object[] getDefaults() { + return proxied.getDefaults(); + } + + @Override + public void setToDefault() { + proxied.setToDefault(); + } + + @Override + public boolean requiresWorldRestart() { + return proxied.requiresWorldRestart(); + } + + @Override + public boolean showInGui() { + return proxied.showInGui(); + } + + @Override + public boolean requiresMcRestart() { + return proxied.requiresMcRestart(); + } + + @Override + public Object get() { + return proxied.get(); + } + + @Override + public Object[] getList() { + return proxied.getList(); + } + + @Override + public void set(T value) { + proxied.set(value); + onUpdate.run(); + } + + @Override + public void set(T[] aVal) { + proxied.set(aVal); + onUpdate.run(); + } + + @Override + public String[] getValidValues() { + return proxied.getValidValues(); + } + + @Override + public T getMinValue() { + return proxied.getMinValue(); + } + + @Override + public T getMaxValue() { + return proxied.getMaxValue(); + } + + @Override + public Pattern getValidationPattern() { + return proxied.getValidationPattern(); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiConfig.java b/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiConfig.java new file mode 100644 index 000000000..fcc5fadeb --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiConfig.java @@ -0,0 +1,14 @@ +package org.embeddedt.archaicfix.config; + +import cpw.mods.fml.client.config.GuiConfig; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; + +@SideOnly(Side.CLIENT) +public class SimpleGuiConfig extends GuiConfig { + public SimpleGuiConfig(GuiScreen parent, Class configClass, String modID, String modName) throws ConfigException { + super(parent, ConfigurationManager.getConfigElements(configClass), modID, false, false, modName + " Configuration", I18n.format("falsepatternlib.gui.config.description")); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiFactory.java b/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiFactory.java new file mode 100644 index 000000000..ee9b9cac3 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiFactory.java @@ -0,0 +1,26 @@ +package org.embeddedt.archaicfix.config; + +import cpw.mods.fml.client.IModGuiFactory; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.Minecraft; + +import java.util.Set; + +@SideOnly(Side.CLIENT) +public interface SimpleGuiFactory extends IModGuiFactory { + @Override + default void initialize(Minecraft minecraftInstance) { + + } + + @Override + default Set runtimeGuiCategories() { + return null; + } + + @Override + default RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) { + return null; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/IAcceleratedRecipe.java b/src/main/java/org/embeddedt/archaicfix/ducks/IAcceleratedRecipe.java new file mode 100644 index 000000000..4b51b2ddc --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/ducks/IAcceleratedRecipe.java @@ -0,0 +1,12 @@ +package org.embeddedt.archaicfix.ducks; + +import net.minecraft.item.Item; + +import java.util.Collection; +import java.util.Set; + +public interface IAcceleratedRecipe { + Set getPotentialItems(); + + void invalidatePotentialItems(); +} diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/IArchaicNetworkManager.java b/src/main/java/org/embeddedt/archaicfix/ducks/IArchaicNetworkManager.java new file mode 100644 index 000000000..6f998d3ae --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/ducks/IArchaicNetworkManager.java @@ -0,0 +1,7 @@ +package org.embeddedt.archaicfix.ducks; + +import net.minecraft.network.EnumConnectionState; + +public interface IArchaicNetworkManager { + void setConnectionStateWithoutAutoRead(EnumConnectionState state); +} diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/IArchaicWorld.java b/src/main/java/org/embeddedt/archaicfix/ducks/IArchaicWorld.java new file mode 100644 index 000000000..1f708af86 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/ducks/IArchaicWorld.java @@ -0,0 +1,7 @@ +package org.embeddedt.archaicfix.ducks; + +import net.minecraft.world.chunk.Chunk; + +public interface IArchaicWorld { + void arch$markTileEntitiesInChunkForRemoval(Chunk chunk); +} diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/ILazyChunkProviderServer.java b/src/main/java/org/embeddedt/archaicfix/ducks/ILazyChunkProviderServer.java new file mode 100644 index 000000000..abe3d5bb8 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/ducks/ILazyChunkProviderServer.java @@ -0,0 +1,5 @@ +package org.embeddedt.archaicfix.ducks; + +public interface ILazyChunkProviderServer { + boolean dropLazyChunk(int x, int z, Runnable runnable); +} diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/IPendingChunk.java b/src/main/java/org/embeddedt/archaicfix/ducks/IPendingChunk.java new file mode 100644 index 000000000..57c69af82 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/ducks/IPendingChunk.java @@ -0,0 +1,9 @@ +package org.embeddedt.archaicfix.ducks; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.ChunkCoordIntPair; + +public interface IPendingChunk { + NBTTagCompound arch$getNbt(); + ChunkCoordIntPair arch$getPos(); +} diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/IWorldRenderer.java b/src/main/java/org/embeddedt/archaicfix/ducks/IWorldRenderer.java new file mode 100644 index 000000000..91583d172 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/ducks/IWorldRenderer.java @@ -0,0 +1,5 @@ +package org.embeddedt.archaicfix.ducks; + +public interface IWorldRenderer { + boolean arch$isInView(); +} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java b/src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java new file mode 100644 index 000000000..8fff01301 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java @@ -0,0 +1,186 @@ +package org.embeddedt.archaicfix.helpers; + +import java.awt.image.BufferedImage; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import cpw.mods.fml.relauncher.ReflectionHelper; +import org.apache.commons.io.filefilter.DirectoryFileFilter; + +import com.google.common.base.Splitter; +import com.google.common.collect.Lists; + +import cpw.mods.fml.common.Loader; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.AbstractResourcePack; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.client.resources.IResourcePack; +import net.minecraft.client.resources.SimpleReloadableResourceManager; +import net.minecraft.client.resources.data.IMetadataSection; +import net.minecraft.client.resources.data.IMetadataSerializer; + +// Inspired by ResourceManagerHelper in fabric-resource-loader-v0 + +public abstract class BuiltInResourcePack extends AbstractResourcePack { + + private static final Splitter entryNameSplitter = Splitter.on('/').omitEmptyStrings().limit(5); + + private String modid; + private final String id; + protected boolean enabled = true; + + /** + *

Register a built-in resource pack. This is a resource pack located in the JAR at {@code "resourcepacks/"}. + * + *

The resource pack is "invisible", it will not show up in the resource pack GUI. + * + * @param id The name of the resource pack. + */ + public static BuiltInResourcePack register(String id) { + BuiltInResourcePack rp = BuiltInResourcePack.of(Loader.instance().activeModContainer().getSource(), Loader.instance().activeModContainer().getModId(), id); + inject(rp); + return rp; + } + + private static BuiltInResourcePack of(File file, String modid, String id) { + if(file.isDirectory()) { + return new BuiltInFolderResourcePack(file, modid, id); + } else { + return new BuiltInFileResourcePack(file, modid, id); + } + } + + public BuiltInResourcePack(File file, String modid, String id) { + super(file); + this.modid = modid; + this.id = id; + } + + @Override + public String getPackName() { + return modid + "/" + id; + } + + @Override + public IMetadataSection getPackMetadata(IMetadataSerializer p_135058_1_, String p_135058_2_) throws IOException { + return null; + } + + @Override + public BufferedImage getPackImage() throws IOException { + return null; + } + + protected String getRootPath() { + return "resourcepacks/" + id + "/"; + } + + protected void addNamespaceIfLowerCase(Set set, String ns) { + if (!ns.equals(ns.toLowerCase())) { + this.logNameNotLowercase(ns); + } else { + set.add(ns); + } + } + + public BuiltInResourcePack setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + @SuppressWarnings("unchecked") + private static void inject(IResourcePack resourcePack) { + List defaultResourcePacks = ReflectionHelper.getPrivateValue(Minecraft.class, Minecraft.getMinecraft(), "defaultResourcePacks", "field_110449_ao"); + defaultResourcePacks.add(resourcePack); + IResourceManager resMan = Minecraft.getMinecraft().getResourceManager(); + if(resMan instanceof SimpleReloadableResourceManager) { + ((SimpleReloadableResourceManager)resMan).reloadResourcePack(resourcePack); + } + } + + private static class BuiltInFileResourcePack extends BuiltInResourcePack { + + private final ZipFile zipFile; + + public BuiltInFileResourcePack(File file, String modid, String id) { + super(file, modid, id); + try { + this.zipFile = new ZipFile(file); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public Set getResourceDomains() { + Set domains = new HashSet<>(); + + Enumeration en = zipFile.entries(); + while(en.hasMoreElements()) { + ZipEntry entry = en.nextElement(); + if(entry.getName().startsWith(getRootPath() + "assets/")) { + List nameParts = Lists.newArrayList(entryNameSplitter.split(entry.getName())); + if(nameParts.size() > 3) { + addNamespaceIfLowerCase(domains, nameParts.get(3)); + } + } + } + return domains; + } + + @Override + protected InputStream getInputStreamByName(String name) throws IOException { + return zipFile.getInputStream(zipFile.getEntry(getRootPath() + name)); + } + + @Override + protected boolean hasResourceName(String name) { + return enabled && zipFile.getEntry(getRootPath() + name) != null; + } + + } + + private static class BuiltInFolderResourcePack extends BuiltInResourcePack { + + public BuiltInFolderResourcePack(File file, String modid, String id) { + super(file, modid, id); + } + + @Override + public Set getResourceDomains() { + Set domains = new HashSet<>(); + + File assetsDir = new File(this.resourcePackFile, getRootPath() + "assets/"); + if(assetsDir.isDirectory()) { + File[] files = assetsDir.listFiles((FileFilter)DirectoryFileFilter.DIRECTORY); + for(File file : files) { + addNamespaceIfLowerCase(domains, file.getName()); + } + } + + return domains; + } + + @Override + protected InputStream getInputStreamByName(String name) throws IOException { + return new BufferedInputStream(new FileInputStream(new File(this.resourcePackFile, getRootPath() + "/" + name))); + } + + @Override + protected boolean hasResourceName(String name) { + return enabled && new File(this.resourcePackFile, getRootPath() + "/" + name).isFile(); + } + + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/ChickenChunkHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/ChickenChunkHelper.java new file mode 100644 index 000000000..1beb125fd --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/helpers/ChickenChunkHelper.java @@ -0,0 +1,10 @@ +package org.embeddedt.archaicfix.helpers; + +import codechicken.chunkloader.ChunkLoaderManager; +import net.minecraft.world.WorldServer; + +public class ChickenChunkHelper { + public static void load(WorldServer world) { + ChunkLoaderManager.load(world); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/ChunkQueueSorter.java b/src/main/java/org/embeddedt/archaicfix/helpers/ChunkQueueSorter.java new file mode 100644 index 000000000..c2d55d291 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/helpers/ChunkQueueSorter.java @@ -0,0 +1,31 @@ +package org.embeddedt.archaicfix.helpers; + +import net.minecraft.world.ChunkCoordIntPair; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.Comparator; + +public class ChunkQueueSorter implements Comparator> { + private final ChunkCoordIntPair[] playerChunks; + + public ChunkQueueSorter(ChunkCoordIntPair[] playerChunks) { + this.playerChunks = playerChunks; + } + + private int averagePlayerDistance(ChunkCoordIntPair pair) { + int shortestDistance = Integer.MAX_VALUE; + for(ChunkCoordIntPair p : playerChunks) { + int xDist = p.chunkXPos - pair.chunkXPos; + int zDist = p.chunkZPos - pair.chunkZPos; + shortestDistance = Math.min(shortestDistance, (xDist * xDist) + (zDist * zDist)); + } + return shortestDistance; + } + + @Override + public int compare(Pair c1, Pair c2) { + int d1 = averagePlayerDistance(c1.getLeft()); + int d2 = averagePlayerDistance(c2.getLeft()); + return d1 - d2; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java new file mode 100644 index 000000000..a1a87c1d7 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java @@ -0,0 +1,29 @@ +package org.embeddedt.archaicfix.helpers; + +import org.apache.commons.lang3.tuple.Pair; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class DragonAPIHelper { + public static boolean isVersionInInclusiveRange(int minMajor, char minMinor, int maxMajor, char maxMinor) { + try(InputStream is = DragonAPIHelper.class.getResourceAsStream("/version_dragonapi.properties")) { + if (is != null) { + Properties props = new Properties(); + props.load(is); + int major = Integer.parseInt(props.getProperty("Major")); + char minor = props.getProperty("Minor").charAt(0); + + Pair min = Pair.of(minMajor, minMinor); + Pair max = Pair.of(maxMajor, maxMinor); + Pair ver = Pair.of(major, minor); + + return min.compareTo(ver) <= 0 && ver.compareTo(max) <= 0; + } + } catch(Exception e) { + e.printStackTrace(); + } + return false; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/LetsEncryptHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/LetsEncryptHelper.java new file mode 100644 index 000000000..f51dd7f27 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/helpers/LetsEncryptHelper.java @@ -0,0 +1,58 @@ +package org.embeddedt.archaicfix.helpers; + +import org.embeddedt.archaicfix.ArchaicLogger; +import org.embeddedt.archaicfix.config.ArchaicConfig; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; + +/** + * Add Let's Encrypt root certificates to the default SSLContext. + * CurseForge launcher uses the vanilla JDK for 1.7.10, which is version 8u51. + * This version does not include these certificates, support for ISRG Root X1 was added in 8u141. + * Based on LetsEncryptCraft by Cloudhunter (MIT) + */ +public class LetsEncryptHelper { + private LetsEncryptHelper() {} + @SuppressWarnings("java:S6437") + public static void replaceSSLContext() { + if (!ArchaicConfig.enableLetsEncryptRoot) { + return; + } + + try (InputStream x1 = LetsEncryptHelper.class.getResourceAsStream("/letsencrypt/isrgrootx1.pem"); + InputStream x2 = LetsEncryptHelper.class.getResourceAsStream("/letsencrypt/isrg-root-x2.pem")) { + KeyStore merged = KeyStore.getInstance(KeyStore.getDefaultType()); + Path cacerts = Paths.get(System.getProperty("java.home"),"lib", "security", "cacerts"); + merged.load(Files.newInputStream(cacerts), "changeit".toCharArray()); + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + Certificate cx1 = cf.generateCertificate(x1); + merged.setCertificateEntry("archaicfix-isrgx1", cx1); + + Certificate cx2 = cf.generateCertificate(x2); + merged.setCertificateEntry("archaicfix-isrgx2", cx2); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(merged); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, tmf.getTrustManagers(), null); + SSLContext.setDefault(sslContext); + ArchaicLogger.LOGGER.info("[LetsEncryptHelper] Added certificates to trust store."); + } catch (IOException e) { + ArchaicLogger.LOGGER.error("[LetsEncryptHelper] Failed to load certificates from classpath.", e); + } catch (GeneralSecurityException e) { + ArchaicLogger.LOGGER.error("[LetsEncryptHelper] Failed to load default keystore.", e); + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/LoadControllerHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/LoadControllerHelper.java new file mode 100644 index 000000000..cafad649a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/helpers/LoadControllerHelper.java @@ -0,0 +1,172 @@ +package org.embeddedt.archaicfix.helpers; + +import com.google.common.collect.ListMultimap; +import com.google.common.eventbus.EventBus; +import cpw.mods.fml.common.*; +import cpw.mods.fml.common.versioning.ArtifactVersion; +import cpw.mods.fml.common.versioning.VersionRange; + +import java.io.File; +import java.security.cert.Certificate; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class LoadControllerHelper { + private static LoadController loadController; + private static ListMultimap packageOwners; + + static { + loadController = ObfuscationReflectionHelper.getPrivateValue(Loader.class, Loader.instance(), "modController"); + packageOwners = ObfuscationReflectionHelper.getPrivateValue(LoadController.class, loadController, "packageOwners"); + } + + private static ConcurrentHashMap, ModContainer> owningModForClass = new ConcurrentHashMap<>(); + + public static ModContainer getOwningMod(Class clz) { + ModContainer container = owningModForClass.computeIfAbsent(clz, c -> { + if(clz.getName().startsWith("net.minecraft.")) + return Loader.instance().getMinecraftModContainer(); + int lastDot = clz.getName().lastIndexOf('.'); + if(lastDot == -1) + return NONE; + String pkgName = clz.getName().substring(0, lastDot); + if(packageOwners.containsKey(pkgName)) + return packageOwners.get(pkgName).get(0); + else + return NONE; + }); + if(container == NONE) + return null; + return container; + } + + private static final ModContainer NONE = new ModContainer() { + @Override + public String getModId() { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public String getVersion() { + return null; + } + + @Override + public File getSource() { + return null; + } + + @Override + public ModMetadata getMetadata() { + return null; + } + + @Override + public void bindMetadata(MetadataCollection mc) { + + } + + @Override + public void setEnabledState(boolean enabled) { + + } + + @Override + public Set getRequirements() { + return null; + } + + @Override + public List getDependencies() { + return null; + } + + @Override + public List getDependants() { + return null; + } + + @Override + public String getSortingRules() { + return null; + } + + @Override + public boolean registerBus(EventBus bus, LoadController controller) { + return false; + } + + @Override + public boolean matches(Object mod) { + return false; + } + + @Override + public Object getMod() { + return null; + } + + @Override + public ArtifactVersion getProcessedVersion() { + return null; + } + + @Override + public boolean isImmutable() { + return false; + } + + @Override + public String getDisplayVersion() { + return null; + } + + @Override + public VersionRange acceptableMinecraftVersionRange() { + return null; + } + + @Override + public Certificate getSigningCertificate() { + return null; + } + + @Override + public Map getCustomModProperties() { + return null; + } + + @Override + public Class getCustomResourcePackClass() { + return null; + } + + @Override + public Map getSharedModDescriptor() { + return null; + } + + @Override + public Disableable canBeDisabled() { + return null; + } + + @Override + public String getGuiClassName() { + return null; + } + + @Override + public List getOwnedPackages() { + return null; + } + }; + +} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/NEISearchHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/NEISearchHelper.java new file mode 100644 index 000000000..2694b0753 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/helpers/NEISearchHelper.java @@ -0,0 +1,13 @@ +package org.embeddedt.archaicfix.helpers; + +import codechicken.nei.api.ItemInfo; +import net.minecraft.item.ItemStack; + +import java.util.function.Function; + +public class NEISearchHelper implements Function { + @Override + public String apply(ItemStack itemStack) { + return ItemInfo.getSearchName(itemStack); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java b/src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java new file mode 100644 index 000000000..272a40560 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java @@ -0,0 +1,110 @@ +package org.embeddedt.archaicfix.helpers; + +import gnu.trove.map.hash.TIntObjectHashMap; +import lombok.var; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.*; + +/** + * Provides a facility to iterate over a subset of the accelerated ore dictionary. + */ +public class OreDictIterator { + private static final IdentityHashMap, IdentityHashMap>> ITERATOR_CACHE = new IdentityHashMap<>(); + + private static int findStartingIndex(List oreList, Item target) { + int low = 0; + int high = oreList.size() - 1; + int targetId = Item.getIdFromItem(target); + while(low <= high) { + int mid = (low + high) / 2; + ItemStack option = oreList.get(mid); + int comparisonResult; + if(option.getItem() == target) { + ItemStack previous = mid > 0 ? oreList.get(mid-1) : null; + if(previous != null && previous.getItem() == target) { + comparisonResult = 1; + } else { + return mid; + } + } else { + int optionId = Item.getIdFromItem(option.getItem()); + if(optionId < targetId) + comparisonResult = -1; + else if(optionId > targetId) + comparisonResult = 1; + else + throw new IllegalStateException(); + } + if (comparisonResult < 0) + low = mid + 1; + else + high = mid - 1; + } + return low; + } + public static Item getItemFromStack(ItemStack stack) { + if(stack == null) + return null; + else + return stack.getItem(); + } + public static Iterator get(String oreName, Item target) { + if(target == null) + return Collections.emptyIterator(); + List oreList = OreDictionary.getOres(oreName, false); + if (oreList == null) + return Collections.emptyIterator(); + if(oreList.size() < 10) + return oreList.iterator(); + return get(oreList, target); + } + public static Iterator get(List oreList, Item target) { + if(target == null) + return Collections.emptyIterator(); + var targetMap = ITERATOR_CACHE.get(oreList); + if(targetMap == null) { + targetMap = new IdentityHashMap<>(); + ITERATOR_CACHE.put(oreList, targetMap); + } + int startIndex, endIndex; + Pair indices = targetMap.get(target); + if(indices != null) { + startIndex = indices.getLeft(); + endIndex = indices.getRight(); + } else { + int potentialStartIndex = findStartingIndex(oreList, target); + if(potentialStartIndex < 0 || potentialStartIndex >= oreList.size() || oreList.get(potentialStartIndex).getItem() != target) { + startIndex = -1; + endIndex = -1; + } else { + startIndex = potentialStartIndex; + int end = -1; + for(int i = startIndex; i < oreList.size(); i++) { + if(oreList.get(i).getItem() != target) { + end = i; + break; + } + } + if(end == -1) + end = oreList.size(); + endIndex = end; + } + targetMap.put(target, Pair.of(startIndex, endIndex)); + } + if(startIndex == -1 || endIndex == -1) + return Collections.emptyIterator(); + else { + return oreList.subList(startIndex, endIndex).iterator(); + } + } + + public static void clearCache(String oreName) { + List theList = OreDictionary.getOres(oreName, false); + if(theList != null) + ITERATOR_CACHE.remove(theList); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/SoundDeviceThread.java b/src/main/java/org/embeddedt/archaicfix/helpers/SoundDeviceThread.java new file mode 100644 index 000000000..c1a573716 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/helpers/SoundDeviceThread.java @@ -0,0 +1,64 @@ +package org.embeddedt.archaicfix.helpers; + +import cpw.mods.fml.relauncher.ReflectionHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.SoundHandler; +import net.minecraft.client.audio.SoundManager; +import net.minecraft.client.renderer.GLAllocation; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.embeddedt.archaicfix.proxy.ClientProxy; +import org.lwjgl.openal.AL; +import org.lwjgl.openal.ALC10; +import org.lwjgl.openal.ALCdevice; + +import java.nio.IntBuffer; + +public class SoundDeviceThread extends Thread { + private static final int ALC_CONNECTED = 0x313; + public SoundDeviceThread() { + setName("Default Sound Device Checker"); + setDaemon(true); + } + private String getDefault() { + return ALC10.alcGetString(null, ALC10.ALC_DEFAULT_DEVICE_SPECIFIER); + } + + private IntBuffer connectionBuffer = GLAllocation.createDirectIntBuffer(1); + + private boolean isDisconnected(ALCdevice device) { + if(!ALC10.alcIsExtensionPresent(device, "ALC_EXT_disconnect")) + return false; + ALC10.alcGetInteger(device, ALC_CONNECTED, connectionBuffer); + return connectionBuffer.get(0) == ALC10.ALC_FALSE; + } + + public void run() { + try { + String previousDefault = null; + SoundManager manager = ReflectionHelper.getPrivateValue(SoundHandler.class, Minecraft.getMinecraft().getSoundHandler(), "sndManager", "field_147694_f"); + while(!Thread.interrupted()) { + boolean managerLoaded = ReflectionHelper.getPrivateValue(SoundManager.class, manager, "loaded", "field_148617_f"); + if(managerLoaded && !ClientProxy.soundSystemReloadLock) { + if(previousDefault == null) { + previousDefault = getDefault(); + continue; + } + ALCdevice device = AL.getDevice(); + if((device != null && !device.isValid()) || isDisconnected(device) || !previousDefault.equals(getDefault())) { + ArchaicLogger.LOGGER.info("Sound device is not valid anymore, reloading sound system"); + previousDefault = getDefault(); + ClientProxy.soundSystemReloadLock = true; + Minecraft.getMinecraft().func_152344_a(manager::reloadSoundSystem); + } + } + try { + Thread.sleep(1000); + } catch(InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } catch(Throwable e) { + ArchaicLogger.LOGGER.error("An exception occured while checking sound device status", e); + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/UnexpectionalObjectArrayList.java b/src/main/java/org/embeddedt/archaicfix/helpers/UnexpectionalObjectArrayList.java new file mode 100644 index 000000000..20da59516 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/helpers/UnexpectionalObjectArrayList.java @@ -0,0 +1,15 @@ +package org.embeddedt.archaicfix.helpers; + +import speiger.src.collections.objects.lists.ObjectArrayList; + +/** An ObjectArrayList that has a getter that returns null instead of throwing an exception when the index is out of + * bounds. */ +public class UnexpectionalObjectArrayList extends ObjectArrayList { + public T getOrNull(int index) { + if(index >= 0 && index < size()) { + return data[index]; + } else { + return null; + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java new file mode 100644 index 000000000..2a4fe76b5 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java @@ -0,0 +1,19 @@ +package org.embeddedt.archaicfix.helpers; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.entity.Entity; +import org.embeddedt.archaicfix.config.ArchaicConfig; + +public class WorldRendererDistanceHelper { + /** + * Get the squared distance of this world renderer, adjusted to favor the XZ axes over the Y one. + * @author embeddedt, makamys + * @param e render view entity + * @param instance world renderer + * @return an adjusted squared distance of this renderer from the entity + */ + public static double betterDistanceSquared(Entity e, WorldRenderer instance) { + return instance.distanceToEntitySquared(e); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLighting.java b/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLighting.java new file mode 100644 index 000000000..8d93d38fb --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLighting.java @@ -0,0 +1,7 @@ +package org.embeddedt.archaicfix.lighting.api; + +import net.minecraft.world.EnumSkyBlock; + +public interface IChunkLighting { + int getCachedLightFor(EnumSkyBlock enumSkyBlock, int xIn, int yIn, int zIn); +} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLightingData.java b/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLightingData.java new file mode 100644 index 000000000..c8397decb --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLightingData.java @@ -0,0 +1,13 @@ +package org.embeddedt.archaicfix.lighting.api; + +public interface IChunkLightingData { + short[] getNeighborLightChecks(); + + void setNeighborLightChecks(short[] data); + + boolean isLightInitialized(); + + void setLightInitialized(boolean val); + + void setSkylightUpdatedPublic(); +} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngine.java b/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngine.java new file mode 100644 index 000000000..7510d9ca5 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngine.java @@ -0,0 +1,11 @@ +package org.embeddedt.archaicfix.lighting.api; + +import net.minecraft.world.EnumSkyBlock; + +public interface ILightingEngine { + void scheduleLightUpdate(EnumSkyBlock lightType, int xIn, int yIn, int zIn); + + void processLightUpdates(); + + void processLightUpdatesForType(EnumSkyBlock lightType); +} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngineProvider.java b/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngineProvider.java new file mode 100644 index 000000000..7ceeec091 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngineProvider.java @@ -0,0 +1,5 @@ +package org.embeddedt.archaicfix.lighting.api; + +public interface ILightingEngineProvider { + ILightingEngine getLightingEngine(); +} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/collections/PooledLongQueue.java b/src/main/java/org/embeddedt/archaicfix/lighting/collections/PooledLongQueue.java new file mode 100644 index 000000000..1fc389877 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/lighting/collections/PooledLongQueue.java @@ -0,0 +1,164 @@ +package org.embeddedt.archaicfix.lighting.collections; + +import java.util.ArrayDeque; +import java.util.Deque; + +//Implement own queue with pooled segments to reduce allocation costs and reduce idle memory footprint +public class PooledLongQueue { + private static final int CACHED_QUEUE_SEGMENTS_COUNT = 1 << 12; // 4096 + private static final int QUEUE_SEGMENT_SIZE = 1 << 10; // 1024 + + private final Pool pool; + + private Segment cur, last; + + private int size = 0; + + // Stores whether or not the queue is empty. Updates to this field will be seen by all threads immediately. Writes + // to volatile fields are generally quite a bit more expensive, so we avoid repeatedly setting this flag to true. + private volatile boolean empty; + + public PooledLongQueue(Pool pool) { + this.pool = pool; + } + + /** + * Not thread-safe! If you must know whether or not the queue is empty, please use {@link PooledLongQueue#isEmpty()}. + * + * @return The number of encoded values present in this queue + */ + public int size() { + return this.size; + } + + /** + * Thread-safe method to check whether or not this queue has work to do. Significantly cheaper than acquiring a lock. + * @return True if the queue is empty, otherwise false + */ + public boolean isEmpty() { + return this.empty; + } + + /** + * Not thread-safe! Adds an encoded long value into this queue. + * @param val The encoded value to add + */ + public void add(final long val) { + if (this.cur == null) { + this.empty = false; + this.cur = this.last = this.pool.acquire(); + } + + if (this.last.index == QUEUE_SEGMENT_SIZE) { + Segment ret = this.last.next = this.last.pool.acquire(); + ret.longArray[ret.index++] = val; + + this.last = ret; + } else { + this.last.longArray[this.last.index++] = val; + } + + ++this.size; + } + + /** + * Not thread safe! Creates an iterator over the values in this queue. Values will be returned in a FIFO fashion. + * @return The iterator + */ + public LongQueueIterator iterator() { + return new LongQueueIterator(this.cur); + } + + private void clear() { + Segment segment = this.cur; + + while (segment != null) { + Segment next = segment.next; + segment.release(); + segment = next; + } + + this.size = 0; + this.cur = null; + this.last = null; + this.empty = true; + } + + public class LongQueueIterator { + private Segment cur; + private long[] curArray; + + private int index, capacity; + + private LongQueueIterator(Segment cur) { + this.cur = cur; + + if (this.cur != null) { + this.curArray = cur.longArray; + this.capacity = cur.index; + } + } + + public boolean hasNext() { + return this.cur != null; + } + + public long next() { + final long ret = this.curArray[this.index++]; + + if (this.index == this.capacity) { + this.index = 0; + + this.cur = this.cur.next; + + if (this.cur != null) { + this.curArray = this.cur.longArray; + this.capacity = this.cur.index; + } + } + + return ret; + } + + public void finish() { + PooledLongQueue.this.clear(); + } + } + + public static class Pool { + private final Deque segmentPool = new ArrayDeque<>(); + + private Segment acquire() { + if (this.segmentPool.isEmpty()) { + return new Segment(this); + } + + return this.segmentPool.pop(); + } + + private void release(Segment segment) { + if (this.segmentPool.size() < CACHED_QUEUE_SEGMENTS_COUNT) { + this.segmentPool.push(segment); + } + } + } + + private static class Segment { + private final long[] longArray = new long[QUEUE_SEGMENT_SIZE]; + private int index = 0; + private Segment next; + private final Pool pool; + + private Segment(Pool pool) { + this.pool = pool; + } + + private void release() { + this.index = 0; + this.next = null; + + this.pool.release(this); + } + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/WorldChunkSlice.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/WorldChunkSlice.java new file mode 100644 index 000000000..899a3c268 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/lighting/world/WorldChunkSlice.java @@ -0,0 +1,58 @@ +package org.embeddedt.archaicfix.lighting.world; + +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngineHelpers; + +public class WorldChunkSlice { + private static final int DIAMETER = 5; + + private final Chunk[] chunks; + + private final int x, z; + + public WorldChunkSlice(World world, int x, int z) { + this.chunks = new Chunk[DIAMETER * DIAMETER]; + + int radius = DIAMETER / 2; + + for (int xDiff = -radius; xDiff <= radius; xDiff++) { + for (int zDiff = -radius; zDiff <= radius; zDiff++) { + Chunk chunk = LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(), x + xDiff, z + zDiff); + this.chunks[((xDiff + radius) * DIAMETER) + (zDiff + radius)] = chunk; + } + } + + this.x = x - radius; + this.z = z - radius; + } + + public Chunk getChunk(int x, int z) { + return this.chunks[(x * DIAMETER) + z]; + } + + public Chunk getChunkFromWorldCoords(int x, int z) { + return this.getChunk((x >> 4) - this.x, (z >> 4) - this.z); + } + + public boolean isLoaded(int x, int z, int radius) { + return this.isLoaded(x - radius, z - radius, x + radius, z + radius); + } + + public boolean isLoaded(int xStart, int zStart, int xEnd, int zEnd) { + xStart = (xStart >> 4) - this.x; + zStart = (zStart >> 4) - this.z; + xEnd = (xEnd >> 4) - this.x; + zEnd = (zEnd >> 4) - this.z; + + for (int i = xStart; i <= xEnd; ++i) { + for (int j = zStart; j <= zEnd; ++j) { + if (this.getChunk(i, j) == null) { + return false; + } + } + } + + return true; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/AxisDirection.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/AxisDirection.java new file mode 100644 index 000000000..c39c71e42 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/AxisDirection.java @@ -0,0 +1,16 @@ +package org.embeddedt.archaicfix.lighting.world.lighting; + +public enum AxisDirection { + POSITIVE(1), + NEGATIVE(-1); + + private final int off; + AxisDirection(int off) { + this.off = off; + } + + public int getOffset() { + return off; + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/BlockPos.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/BlockPos.java new file mode 100644 index 000000000..d1779aa4e --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/BlockPos.java @@ -0,0 +1,41 @@ +package org.embeddedt.archaicfix.lighting.world.lighting; + +/** + * Stub for aiding in porting Phosphor. DO NOT USE in other code. + */ +public class BlockPos { + protected int x, y, z; + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getZ() { + return z; + } + + BlockPos() { + + } + + public static class MutableBlockPos extends BlockPos { + public MutableBlockPos() { + this(0, 0, 0); + } + + public MutableBlockPos(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + public MutableBlockPos setPos(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + return this; + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngine.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngine.java new file mode 100644 index 000000000..1a3d2f40a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngine.java @@ -0,0 +1,613 @@ +package org.embeddedt.archaicfix.lighting.world.lighting; + +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.profiler.Profiler; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.MathHelper; +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.embeddedt.archaicfix.lighting.api.IChunkLighting; +import org.embeddedt.archaicfix.lighting.api.ILightingEngine; +import org.embeddedt.archaicfix.lighting.collections.PooledLongQueue; + +import java.util.concurrent.locks.ReentrantLock; + +public class LightingEngine implements ILightingEngine { + private static final boolean ENABLE_ILLEGAL_THREAD_ACCESS_WARNINGS = true; + private static final int MAX_SCHEDULED_COUNT = 1 << 22; + + private static final int MAX_LIGHT = 15; + + private final Thread ownedThread = Thread.currentThread(); + + private final World world; + + private final Profiler profiler; + + //Layout of longs: [padding(4)] [y(8)] [x(26)] [z(26)] + private final PooledLongQueue[] queuedLightUpdates = new PooledLongQueue[EnumSkyBlock.values().length]; + + //Layout of longs: see above + private final PooledLongQueue[] queuedDarkenings = new PooledLongQueue[MAX_LIGHT + 1]; + private final PooledLongQueue[] queuedBrightenings = new PooledLongQueue[MAX_LIGHT + 1]; + + //Layout of longs: [newLight(4)] [pos(60)] + private final PooledLongQueue initialBrightenings; + //Layout of longs: [padding(4)] [pos(60)] + private final PooledLongQueue initialDarkenings; + + private boolean updating = false; + + //Layout parameters + //Length of bit segments + private static final int + lX = 26, + lY = 8, + lZ = 26, + lL = 4; + + //Bit segment shifts/positions + private static final int + sZ = 0, + sX = sZ + lZ, + sY = sX + lX, + sL = sY + lY; + + //Bit segment masks + private static final long + mX = (1L << lX) - 1, + mY = (1L << lY) - 1, + mZ = (1L << lZ) - 1, + mL = (1L << lL) - 1, + mPos = (mY << sY) | (mX << sX) | (mZ << sZ); + + //Bit to check whether y had overflow + private static final long yCheck = 1L << (sY + lY); + + private static final long[] neighborShifts = new long[6]; + + static { + EnumFacing[] values = new EnumFacing[] { EnumFacing.DOWN, EnumFacing.UP, EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.WEST, EnumFacing.EAST }; + for (int i = 0; i < 6; ++i) { + neighborShifts[i] = ((long) values[i].getFrontOffsetY() << sY) | ((long) values[i].getFrontOffsetX() << sX) | ((long) values[i].getFrontOffsetZ() << sZ); + } + } + + //Mask to extract chunk identifier + private static final long mChunk = ((mX >> 4) << (4 + sX)) | ((mZ >> 4) << (4 + sZ)); + + //Iteration state data + //Cache position to avoid allocation of new object each time + private final BlockPos.MutableBlockPos curPos = new BlockPos.MutableBlockPos(); + private Chunk curChunk; + private long curChunkIdentifier; + private long curData; + static boolean isDynamicLightsLoaded; + + //Cached data about neighboring blocks (of tempPos) + private boolean isNeighborDataValid = false; + + private final NeighborInfo[] neighborInfos = new NeighborInfo[6]; + private PooledLongQueue.LongQueueIterator queueIt; + + private final ReentrantLock lock = new ReentrantLock(); + + public LightingEngine(final World world) { + this.world = world; + this.profiler = world.theProfiler; + isDynamicLightsLoaded = Loader.isModLoaded("DynamicLights"); + + PooledLongQueue.Pool pool = new PooledLongQueue.Pool(); + + this.initialBrightenings = new PooledLongQueue(pool); + this.initialDarkenings = new PooledLongQueue(pool); + + for (int i = 0; i < EnumSkyBlock.values().length; ++i) { + this.queuedLightUpdates[i] = new PooledLongQueue(pool); + } + + for (int i = 0; i < this.queuedDarkenings.length; ++i) { + this.queuedDarkenings[i] = new PooledLongQueue(pool); + } + + for (int i = 0; i < this.queuedBrightenings.length; ++i) { + this.queuedBrightenings[i] = new PooledLongQueue(pool); + } + + for (int i = 0; i < this.neighborInfos.length; ++i) { + this.neighborInfos[i] = new NeighborInfo(); + } + } + + /** + * Schedules a light update for the specified light type and position to be processed later by {@link ILightingEngine#processLightUpdatesForType(EnumSkyBlock)} + */ + @Override + public void scheduleLightUpdate(final EnumSkyBlock lightType, final int xIn, final int yIn, final int zIn) { + this.acquireLock(); + + try { + this.scheduleLightUpdate(lightType, encodeWorldCoord(xIn, yIn, zIn)); + } finally { + this.releaseLock(); + } + } + + /** + * Schedules a light update for the specified light type and position to be processed later by {@link ILightingEngine#processLightUpdates()} + */ + private void scheduleLightUpdate(final EnumSkyBlock lightType, final long pos) { + final PooledLongQueue queue = this.queuedLightUpdates[lightType.ordinal()]; + + queue.add(pos); + + //make sure there are not too many queued light updates + if (queue.size() >= MAX_SCHEDULED_COUNT) { + this.processLightUpdatesForType(lightType); + } + } + + /** + * Calls {@link ILightingEngine#processLightUpdatesForType(EnumSkyBlock)} for both light types + * + */ + @Override + public void processLightUpdates() { + this.processLightUpdatesForType(EnumSkyBlock.Sky); + this.processLightUpdatesForType(EnumSkyBlock.Block); + } + + /** + * Processes light updates of the given light type + */ + @Override + public void processLightUpdatesForType(final EnumSkyBlock lightType) { + // We only want to perform updates if we're being called from a tick event on the client + // There are many locations in the client code which will end up making calls to this method, usually from + // other threads. + if (this.world.isRemote && !this.isCallingFromMainThread()) { + return; + } + + final PooledLongQueue queue = this.queuedLightUpdates[lightType.ordinal()]; + + // Quickly check if the queue is empty before we acquire a more expensive lock. + if (queue.isEmpty()) { + return; + } + + this.acquireLock(); + + try { + this.processLightUpdatesForTypeInner(lightType, queue); + } finally { + this.releaseLock(); + } + } + + @SideOnly(Side.CLIENT) + private boolean isCallingFromMainThread() { + return Minecraft.getMinecraft().func_152345_ab(); + } + + private void acquireLock() { + if (!this.lock.tryLock()) { + // If we cannot lock, something has gone wrong... Only one thread should ever acquire the lock. + // Validate that we're on the right thread immediately so we can gather information. + // It is NEVER valid to call World methods from a thread other than the owning thread of the world instance. + // Users can safely disable this warning, however it will not resolve the issue. + if (ENABLE_ILLEGAL_THREAD_ACCESS_WARNINGS) { + Thread current = Thread.currentThread(); + + if (current != this.ownedThread) { + IllegalAccessException e = new IllegalAccessException(String.format("World is owned by '%s' (ID: %s)," + + " but was accessed from thread '%s' (ID: %s)", + this.ownedThread.getName(), this.ownedThread.getId(), current.getName(), current.getId())); + + ArchaicLogger.LOGGER.warn( + "Something (likely another mod) has attempted to modify the world's state from the wrong thread!\n" + + "This is *bad practice* and can cause severe issues in your game. Phosphor has done as best as it can to mitigate this violation," + + " but it may negatively impact performance or introduce stalls.\nIn a future release, this violation may result in a hard crash instead" + + " of the current soft warning. You should report this issue to our issue tracker with the following stacktrace information.\n(If you are" + + " aware you have misbehaving mods and cannot resolve this issue, you can safely disable this warning by setting" + + " `enable_illegal_thread_access_warnings` to `false` in Phosphor's configuration file for the time being.)", e); + + } + + } + + // Wait for the lock to be released. This will likely introduce unwanted stalls, but will mitigate the issue. + this.lock.lock(); + } + } + + private void releaseLock() { + this.lock.unlock(); + } + + private void processLightUpdatesForTypeInner(final EnumSkyBlock lightType, final PooledLongQueue queue) { + //avoid nested calls + if (this.updating) { + throw new IllegalStateException("Already processing updates!"); + } + + this.updating = true; + + this.curChunkIdentifier = -1; //reset chunk cache + + this.profiler.startSection("lighting"); + + this.profiler.startSection("checking"); + + this.queueIt = queue.iterator(); + + //process the queued updates and enqueue them for further processing + while (this.nextItem()) { + if (this.curChunk == null) { + continue; + } + + final int oldLight = this.getCursorCachedLight(lightType); + final int newLight = this.calculateNewLightFromCursor(lightType); + + if (oldLight < newLight) { + //don't enqueue directly for brightening in order to avoid duplicate scheduling + this.initialBrightenings.add(((long) newLight << sL) | this.curData); + } else if (oldLight > newLight) { + //don't enqueue directly for darkening in order to avoid duplicate scheduling + this.initialDarkenings.add(this.curData); + } + } + + this.queueIt = this.initialBrightenings.iterator(); + + while (this.nextItem()) { + final int newLight = (int) (this.curData >> sL & mL); + + if (newLight > this.getCursorCachedLight(lightType)) { + //Sets the light to newLight to only schedule once. Clear leading bits of curData for later + this.enqueueBrightening(this.curPos, this.curData & mPos, newLight, this.curChunk, lightType); + } + } + + this.queueIt = this.initialDarkenings.iterator(); + + while (this.nextItem()) { + final int oldLight = this.getCursorCachedLight(lightType); + + if (oldLight != 0) { + //Sets the light to 0 to only schedule once + this.enqueueDarkening(this.curPos, this.curData, oldLight, this.curChunk, lightType); + } + } + + this.profiler.endSection(); + + //Iterate through enqueued updates (brightening and darkening in parallel) from brightest to darkest so that we only need to iterate once + for (int curLight = MAX_LIGHT; curLight >= 0; --curLight) { + this.profiler.startSection("darkening"); + + this.queueIt = this.queuedDarkenings[curLight].iterator(); + + while (this.nextItem()) { + if (this.getCursorCachedLight(lightType) >= curLight) //don't darken if we got brighter due to some other change + { + continue; + } + + final Block state = LightingEngineHelpers.posToState(this.curPos, this.curChunk); + final int luminosity = this.getCursorLuminosity(state, lightType); + final int opacity; //if luminosity is high enough, opacity is irrelevant + + if (luminosity >= MAX_LIGHT - 1) { + opacity = 1; + } else { + opacity = this.getPosOpacity(this.curPos, state); + } + + //only darken neighbors if we indeed became darker + if (this.calculateNewLightFromCursor(luminosity, opacity, lightType) < curLight) { + //need to calculate new light value from neighbors IGNORING neighbors which are scheduled for darkening + int newLight = luminosity; + + this.fetchNeighborDataFromCursor(lightType); + + for (NeighborInfo info : this.neighborInfos) { + final Chunk nChunk = info.chunk; + + if (nChunk == null) { + continue; + } + + final int nLight = info.light; + + if (nLight == 0) { + continue; + } + + final BlockPos.MutableBlockPos nPos = info.pos; + + if (curLight - this.getPosOpacity(nPos, LightingEngineHelpers.posToState(nPos, info.section)) >= nLight) //schedule neighbor for darkening if we possibly light it + { + this.enqueueDarkening(nPos, info.key, nLight, nChunk, lightType); + } else //only use for new light calculation if not + { + //if we can't darken the neighbor, no one else can (because of processing order) -> safe to let us be illuminated by it + newLight = Math.max(newLight, nLight - opacity); + } + } + + //schedule brightening since light level was set to 0 + this.enqueueBrighteningFromCursor(newLight, lightType); + } else //we didn't become darker, so we need to re-set our initial light value (was set to 0) and notify neighbors + { + this.enqueueBrighteningFromCursor(curLight, lightType); //do not spread to neighbors immediately to avoid scheduling multiple times + } + } + + this.profiler.endStartSection("brightening"); + + this.queueIt = this.queuedBrightenings[curLight].iterator(); + + while (this.nextItem()) { + final int oldLight = this.getCursorCachedLight(lightType); + + if (oldLight == curLight) //only process this if nothing else has happened at this position since scheduling + { + this.world.func_147479_m(this.curPos.getX(), this.curPos.getY(), this.curPos.getZ()); + + if (curLight > 1) { + this.spreadLightFromCursor(curLight, lightType); + } + } + } + + this.profiler.endSection(); + } + + this.profiler.endSection(); + + this.updating = false; + } + + /** + * Gets data for neighbors of curPos and saves the results into neighbor state data members. If a neighbor can't be accessed/doesn't exist, the corresponding entry in neighborChunks is null - others are not reset + */ + private void fetchNeighborDataFromCursor(final EnumSkyBlock lightType) { + //only update if curPos was changed + if (this.isNeighborDataValid) { + return; + } + + this.isNeighborDataValid = true; + + for (int i = 0; i < this.neighborInfos.length; ++i) { + NeighborInfo info = this.neighborInfos[i]; + + final long nLongPos = info.key = this.curData + neighborShifts[i]; + + if ((nLongPos & yCheck) != 0) { + info.chunk = null; + info.section = null; + continue; + } + + final BlockPos.MutableBlockPos nPos = decodeWorldCoord(info.pos, nLongPos); + + final Chunk nChunk; + + if ((nLongPos & mChunk) == this.curChunkIdentifier) { + nChunk = info.chunk = this.curChunk; + } else { + nChunk = info.chunk = this.getChunk(nPos); + } + + if (nChunk != null) { + ExtendedBlockStorage nSection = nChunk.getBlockStorageArray()[nPos.getY() >> 4]; + + info.light = getCachedLightFor(nChunk, nSection, nPos, lightType); + info.section = nSection; + } + } + } + + + private static int getCachedLightFor(Chunk chunk, ExtendedBlockStorage storage, BlockPos pos, EnumSkyBlock type) { + int i = pos.getX() & 15; + int j = pos.getY(); + int k = pos.getZ() & 15; + + if (storage == null) { + if (type == EnumSkyBlock.Sky && chunk.canBlockSeeTheSky(i, j, k)) { + return type.defaultLightValue; + } else { + return 0; + } + } else if (type == EnumSkyBlock.Sky) { + if (chunk.worldObj.provider.hasNoSky) { + return 0; + } else { + return storage.getExtSkylightValue(i, j & 15, k); + } + } else { + if (type == EnumSkyBlock.Block) { + return storage.getExtBlocklightValue(i, j & 15, k); + } else { + return type.defaultLightValue; + } + } + } + + + private int calculateNewLightFromCursor(final EnumSkyBlock lightType) { + final Block state = LightingEngineHelpers.posToState(this.curPos, this.curChunk); + + final int luminosity = this.getCursorLuminosity(state, lightType); + final int opacity; + + if (luminosity >= MAX_LIGHT - 1) { + opacity = 1; + } else { + opacity = this.getPosOpacity(this.curPos, state); + } + + return this.calculateNewLightFromCursor(luminosity, opacity, lightType); + } + + private int calculateNewLightFromCursor(final int luminosity, final int opacity, final EnumSkyBlock lightType) { + if (luminosity >= MAX_LIGHT - opacity) { + return luminosity; + } + + int newLight = luminosity; + + this.fetchNeighborDataFromCursor(lightType); + + for (NeighborInfo info : this.neighborInfos) { + if (info.chunk == null) { + continue; + } + + final int nLight = info.light; + + newLight = Math.max(nLight - opacity, newLight); + } + + return newLight; + } + + private void spreadLightFromCursor(final int curLight, final EnumSkyBlock lightType) { + this.fetchNeighborDataFromCursor(lightType); + + for (NeighborInfo info : this.neighborInfos) { + final Chunk nChunk = info.chunk; + + if (nChunk == null) { + continue; + } + + final int newLight = curLight - this.getPosOpacity(info.pos, LightingEngineHelpers.posToState(info.pos, info.section)); + + if (newLight > info.light) { + this.enqueueBrightening(info.pos, info.key, newLight, nChunk, lightType); + } + } + } + + private void enqueueBrighteningFromCursor(final int newLight, final EnumSkyBlock lightType) { + this.enqueueBrightening(this.curPos, this.curData, newLight, this.curChunk, lightType); + } + + /** + * Enqueues the pos for brightening and sets its light value to newLight + */ + private void enqueueBrightening(final BlockPos pos, final long longPos, final int newLight, final Chunk chunk, final EnumSkyBlock lightType) { + this.queuedBrightenings[newLight].add(longPos); + + chunk.setLightValue(lightType, pos.getX() & 15, pos.getY(), pos.getZ() & 15, newLight); + } + + /** + * Enqueues the pos for darkening and sets its light value to 0 + */ + private void enqueueDarkening(final BlockPos pos, final long longPos, final int oldLight, final Chunk chunk, final EnumSkyBlock lightType) { + this.queuedDarkenings[oldLight].add(longPos); + + chunk.setLightValue(lightType, pos.getX() & 15, pos.getY(), pos.getZ() & 15, 0); + } + + private static BlockPos.MutableBlockPos decodeWorldCoord(final BlockPos.MutableBlockPos pos, final long longPos) { + final int posX = (int) (longPos >> sX & mX) - (1 << lX - 1); + final int posY = (int) (longPos >> sY & mY); + final int posZ = (int) (longPos >> sZ & mZ) - (1 << lZ - 1); + + return pos.setPos(posX, posY, posZ); + } + + private static long encodeWorldCoord(final long x, final long y, final long z) { + return (y << sY) | (x + (1 << lX - 1) << sX) | (z + (1 << lZ - 1) << sZ); + } + + private static int ITEMS_PROCESSED = 0, CHUNKS_FETCHED = 0; + + /** + * Polls a new item from curQueue and fills in state data members + * + * @return If there was an item to poll + */ + private boolean nextItem() { + if (!this.queueIt.hasNext()) { + this.queueIt.finish(); + this.queueIt = null; + + return false; + } + + this.curData = this.queueIt.next(); + this.isNeighborDataValid = false; + + decodeWorldCoord(this.curPos, this.curData); + + final long chunkIdentifier = this.curData & mChunk; + + if (this.curChunkIdentifier != chunkIdentifier) { + this.curChunk = this.getChunk(this.curPos); + this.curChunkIdentifier = chunkIdentifier; + CHUNKS_FETCHED++; + } + + ITEMS_PROCESSED++; + + return true; + } + + private int getCursorCachedLight(final EnumSkyBlock lightType) { + return ((IChunkLighting) this.curChunk).getCachedLightFor(lightType, this.curPos.getX(), this.curPos.getY(), this.curPos.getZ()); + } + + /** + * Calculates the luminosity for curPos, taking into account lightType + */ + private int getCursorLuminosity(final Block state, final EnumSkyBlock lightType) { + if (lightType == EnumSkyBlock.Sky) { + if (this.curChunk.canBlockSeeTheSky(this.curPos.getX() & 15, this.curPos.getY(), this.curPos.getZ() & 15)) { + return EnumSkyBlock.Sky.defaultLightValue; + } else { + return 0; + } + } + + return MathHelper.clamp_int(LightingEngineHelpers.getLightValueForState(state, this.world, this.curPos.getX(), this.curPos.getY(), this.curPos.getZ()), 0, MAX_LIGHT); + } + + private int getPosOpacity(final BlockPos pos, final Block state) { + return MathHelper.clamp_int(state.getLightOpacity(world, pos.getX(), pos.getY(), pos.getZ()), 1, MAX_LIGHT); + } + + private Chunk getChunk(final BlockPos pos) { + IChunkProvider prov = this.world.getChunkProvider(); + int chunkX = pos.getX() >> 4; + int chunkZ = pos.getZ() >> 4; + return LightingEngineHelpers.getLoadedChunk(prov, chunkX, chunkZ); + } + + private static class NeighborInfo { + Chunk chunk; + ExtendedBlockStorage section; + + int light; + + long key; + + final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); + } +} + diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngineHelpers.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngineHelpers.java new file mode 100644 index 000000000..b758467ee --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngineHelpers.java @@ -0,0 +1,44 @@ +package org.embeddedt.archaicfix.lighting.world.lighting; + +import atomicstryker.dynamiclights.client.DynamicLights; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; + +public class LightingEngineHelpers { + private static final Block DEFAULT_BLOCK_STATE = Blocks.air; + + // Avoids some additional logic in Chunk#getBlockState... 0 is always air + static Block posToState(final BlockPos pos, final Chunk chunk) { + return posToState(pos, chunk.getBlockStorageArray()[pos.getY() >> 4]); + } + + static Block posToState(final BlockPos pos, final ExtendedBlockStorage section) { + final int x = pos.getX(); + final int y = pos.getY(); + final int z = pos.getZ(); + + if (section != null) + { + return section.getBlockByExtId(x & 15, y & 15, z & 15); + } + + return DEFAULT_BLOCK_STATE; + } + + static int getLightValueForState(final Block state, final IBlockAccess world, final int x, final int y, final int z) { + if(LightingEngine.isDynamicLightsLoaded) { + return DynamicLights.getLightValue(world, state, x, y, z); + } else + return state.getLightValue(world, x, y, z); + } + + public static Chunk getLoadedChunk(final IChunkProvider provider, int chunkX, int chunkZ) { + if(!provider.chunkExists(chunkX, chunkZ)) + return null; + return provider.provideChunk(chunkX, chunkZ); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java new file mode 100644 index 000000000..536f091fe --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java @@ -0,0 +1,438 @@ +package org.embeddedt.archaicfix.lighting.world.lighting; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTTagShort; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.embeddedt.archaicfix.lighting.api.IChunkLighting; +import org.embeddedt.archaicfix.lighting.api.IChunkLightingData; +import org.embeddedt.archaicfix.lighting.api.ILightingEngine; +import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; + +@SuppressWarnings("unused") +public class LightingHooks { + private static final EnumSkyBlock[] ENUM_SKY_BLOCK_VALUES = EnumSkyBlock.values(); + + private static final AxisDirection[] ENUM_AXIS_DIRECTION_VALUES = AxisDirection.values(); + + public static final EnumFacing[] HORIZONTAL_FACINGS = new EnumFacing[] { EnumFacing.SOUTH, EnumFacing.WEST, EnumFacing.NORTH, EnumFacing.EAST }; + + private static final int FLAG_COUNT = 32; //2 light types * 4 directions * 2 halves * (inwards + outwards) + + public static void relightSkylightColumn(final World world, final Chunk chunk, final int x, final int z, final int height1, final int height2) { + final int yMin = Math.min(height1, height2); + final int yMax = Math.max(height1, height2) - 1; + + final ExtendedBlockStorage[] sections = chunk.getBlockStorageArray(); + + final int xBase = (chunk.xPosition << 4) + x; + final int zBase = (chunk.zPosition << 4) + z; + + scheduleRelightChecksForColumn(world, EnumSkyBlock.Sky, xBase, zBase, yMin, yMax); + + if (sections[yMin >> 4] == null && yMin > 0) { + world.updateLightByType(EnumSkyBlock.Sky, xBase, yMin - 1, zBase); + } + + short emptySections = 0; + + for (int sec = yMax >> 4; sec >= yMin >> 4; --sec) { + if (sections[sec] == null) { + emptySections |= 1 << sec; + } + } + + if (emptySections != 0) { + for (final EnumFacing dir : HORIZONTAL_FACINGS) { + final int xOffset = dir.getFrontOffsetX(); + final int zOffset = dir.getFrontOffsetZ(); + + final boolean neighborColumnExists = + (((x + xOffset) | (z + zOffset)) & 16) == 0 + //Checks whether the position is at the specified border (the 16 bit is set for both 15+1 and 0-1) + || LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(), chunk.xPosition + xOffset, chunk.zPosition + zOffset) != null; + + if (neighborColumnExists) { + for (int sec = yMax >> 4; sec >= yMin >> 4; --sec) { + if ((emptySections & (1 << sec)) != 0) { + scheduleRelightChecksForColumn(world, EnumSkyBlock.Sky, xBase + xOffset, zBase + zOffset, sec << 4, (sec << 4) + 15); + } + } + } else { + flagChunkBoundaryForUpdate(chunk, emptySections, EnumSkyBlock.Sky, dir, getAxisDirection(dir, x, z), EnumBoundaryFacing.OUT); + } + } + } + } + + public static void scheduleRelightChecksForArea(final World world, final EnumSkyBlock lightType, final int xMin, final int yMin, final int zMin, + final int xMax, final int yMax, final int zMax) { + for (int x = xMin; x <= xMax; ++x) { + for (int z = zMin; z <= zMax; ++z) { + scheduleRelightChecksForColumn(world, lightType, x, z, yMin, yMax); + } + } + } + + private static void scheduleRelightChecksForColumn(final World world, final EnumSkyBlock lightType, final int x, final int z, final int yMin, final int yMax) { + for (int y = yMin; y <= yMax; ++y) { + world.updateLightByType(lightType, x, y, z); + } + } + + public enum EnumBoundaryFacing { + IN, OUT; + + public EnumBoundaryFacing getOpposite() { + return this == IN ? OUT : IN; + } + } + + public static void flagSecBoundaryForUpdate(final Chunk chunk, final BlockPos pos, final EnumSkyBlock lightType, final EnumFacing dir, + final EnumBoundaryFacing boundaryFacing) { + flagChunkBoundaryForUpdate(chunk, (short) (1 << (pos.getY() >> 4)), lightType, dir, getAxisDirection(dir, pos.getX(), pos.getZ()), boundaryFacing); + } + + public static void flagChunkBoundaryForUpdate(final Chunk chunk, final short sectionMask, final EnumSkyBlock lightType, final EnumFacing dir, + final AxisDirection axisDirection, final EnumBoundaryFacing boundaryFacing) { + initNeighborLightChecks(chunk); + ((IChunkLightingData) chunk).getNeighborLightChecks()[getFlagIndex(lightType, dir, axisDirection, boundaryFacing)] |= sectionMask; + chunk.setChunkModified(); + } + + public static int getFlagIndex(final EnumSkyBlock lightType, final int xOffset, final int zOffset, final AxisDirection axisDirection, + final EnumBoundaryFacing boundaryFacing) { + return (lightType == EnumSkyBlock.Block ? 0 : 16) | ((xOffset + 1) << 2) | ((zOffset + 1) << 1) | (axisDirection.getOffset() + 1) | boundaryFacing + .ordinal(); + } + + public static int getFlagIndex(final EnumSkyBlock lightType, final EnumFacing dir, final AxisDirection axisDirection, + final EnumBoundaryFacing boundaryFacing) { + return getFlagIndex(lightType, dir.getFrontOffsetX(), dir.getFrontOffsetZ(), axisDirection, boundaryFacing); + } + + private static AxisDirection getAxisDirection(final EnumFacing dir, final int x, final int z) { + return (((dir == EnumFacing.EAST || dir == EnumFacing.WEST) ? z : x) & 15) < 8 ? AxisDirection.NEGATIVE : AxisDirection.POSITIVE; + } + + private static EnumFacing getOpposite(EnumFacing in) { + switch(in) { + case NORTH: + return EnumFacing.SOUTH; + case SOUTH: + return EnumFacing.NORTH; + case EAST: + return EnumFacing.WEST; + case WEST: + return EnumFacing.EAST; + case DOWN: + return EnumFacing.UP; + case UP: + return EnumFacing.DOWN; + default: + throw new IllegalArgumentException(); + } + } + + private static AxisDirection getAxisDirection(EnumFacing in) { + switch (in) { + case DOWN: + case NORTH: + case WEST: + return AxisDirection.NEGATIVE; + default: + return AxisDirection.POSITIVE; + } + } + + public static void scheduleRelightChecksForChunkBoundaries(final World world, final Chunk chunk) { + for (final EnumFacing dir : HORIZONTAL_FACINGS) { + final int xOffset = dir.getFrontOffsetX(); + final int zOffset = dir.getFrontOffsetZ(); + + final Chunk nChunk = LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(), chunk.xPosition + xOffset, chunk.zPosition + zOffset); + + if(nChunk == null) + continue; + + for (final EnumSkyBlock lightType : ENUM_SKY_BLOCK_VALUES) { + for (final AxisDirection axisDir : ENUM_AXIS_DIRECTION_VALUES) { + //Merge flags upon loading of a chunk. This ensures that all flags are always already on the IN boundary below + mergeFlags(lightType, chunk, nChunk, dir, axisDir); + mergeFlags(lightType, nChunk, chunk, getOpposite(dir), axisDir); + + //Check everything that might have been canceled due to this chunk not being loaded. + //Also, pass in chunks if already known + //The boundary to the neighbor chunk (both ways) + scheduleRelightChecksForBoundary(world, chunk, nChunk, null, lightType, xOffset, zOffset, axisDir); + scheduleRelightChecksForBoundary(world, nChunk, chunk, null, lightType, -xOffset, -zOffset, axisDir); + //The boundary to the diagonal neighbor (since the checks in that chunk were aborted if this chunk wasn't loaded, see scheduleRelightChecksForBoundary) + scheduleRelightChecksForBoundary(world, nChunk, null, chunk, lightType, (zOffset != 0 ? axisDir.getOffset() : 0), + (xOffset != 0 ? axisDir.getOffset() : 0), getAxisDirection(dir) == AxisDirection.POSITIVE ? + AxisDirection.NEGATIVE : + AxisDirection.POSITIVE); + } + } + } + } + + private static void mergeFlags(final EnumSkyBlock lightType, final Chunk inChunk, final Chunk outChunk, final EnumFacing dir, + final AxisDirection axisDir) { + IChunkLightingData outChunkLightingData = (IChunkLightingData) outChunk; + + if (outChunkLightingData.getNeighborLightChecks() == null) { + return; + } + + IChunkLightingData inChunkLightingData = (IChunkLightingData) inChunk; + + initNeighborLightChecks(inChunk); + + final int inIndex = getFlagIndex(lightType, dir, axisDir, EnumBoundaryFacing.IN); + final int outIndex = getFlagIndex(lightType, getOpposite(dir), axisDir, EnumBoundaryFacing.OUT); + + inChunkLightingData.getNeighborLightChecks()[inIndex] |= outChunkLightingData.getNeighborLightChecks()[outIndex]; + //no need to call Chunk.setModified() since checks are not deleted from outChunk + } + + private static void scheduleRelightChecksForBoundary(final World world, final Chunk chunk, Chunk nChunk, Chunk sChunk, final EnumSkyBlock lightType, + final int xOffset, final int zOffset, final AxisDirection axisDir) { + IChunkLightingData chunkLightingData = (IChunkLightingData) chunk; + + if (chunkLightingData.getNeighborLightChecks() == null) { + return; + } + + final int flagIndex = getFlagIndex(lightType, xOffset, zOffset, axisDir, EnumBoundaryFacing.IN); //OUT checks from neighbor are already merged + + final int flags = chunkLightingData.getNeighborLightChecks()[flagIndex]; + + if (flags == 0) { + return; + } + + if (nChunk == null) { + nChunk = LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(),chunk.xPosition + xOffset, chunk.zPosition + zOffset); + if(nChunk == null) + return; + } + + if (sChunk == null) { + int theX = chunk.xPosition + (zOffset != 0 ? axisDir.getOffset() : 0); + int theZ = chunk.zPosition + (xOffset != 0 ? axisDir.getOffset() : 0); + + sChunk = LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(), theX, theZ); + if(sChunk == null) + return; + } + + final int reverseIndex = getFlagIndex(lightType, -xOffset, -zOffset, axisDir, EnumBoundaryFacing.OUT); + + chunkLightingData.getNeighborLightChecks()[flagIndex] = 0; + + IChunkLightingData nChunkLightingData = (IChunkLightingData) nChunk; + + if (nChunkLightingData.getNeighborLightChecks() != null) { + nChunkLightingData.getNeighborLightChecks()[reverseIndex] = 0; //Clear only now that it's clear that the checks are processed + } + + chunk.setChunkModified(); + nChunk.setChunkModified(); + + //Get the area to check + //Start in the corner... + int xMin = chunk.xPosition << 4; + int zMin = chunk.zPosition << 4; + + //move to other side of chunk if the direction is positive + if ((xOffset | zOffset) > 0) { + xMin += 15 * xOffset; + zMin += 15 * zOffset; + } + + //shift to other half if necessary (shift perpendicular to dir) + if (axisDir == AxisDirection.POSITIVE) { + xMin += 8 * (zOffset & 1); //x & 1 is same as abs(x) for x=-1,0,1 + zMin += 8 * (xOffset & 1); + } + + //get maximal values (shift perpendicular to dir) + final int xMax = xMin + 7 * (zOffset & 1); + final int zMax = zMin + 7 * (xOffset & 1); + + for (int y = 0; y < 16; ++y) { + if ((flags & (1 << y)) != 0) { + scheduleRelightChecksForArea(world, lightType, xMin, y << 4, zMin, xMax, (y << 4) + 15, zMax); + } + } + } + + public static void initNeighborLightChecks(final Chunk chunk) { + IChunkLightingData lightingData = (IChunkLightingData) chunk; + + if (lightingData.getNeighborLightChecks() == null) { + lightingData.setNeighborLightChecks(new short[FLAG_COUNT]); + } + } + + public static final String neighborLightChecksKey = "NeighborLightChecks"; + + public static void writeNeighborLightChecksToNBT(final Chunk chunk, final NBTTagCompound nbt) { + short[] neighborLightChecks = ((IChunkLightingData) chunk).getNeighborLightChecks(); + + if (neighborLightChecks == null) { + return; + } + + boolean empty = true; + + final NBTTagList list = new NBTTagList(); + + for (final short flags : neighborLightChecks) { + list.appendTag(new NBTTagShort(flags)); + + if (flags != 0) { + empty = false; + } + } + + if (!empty) { + nbt.setTag(neighborLightChecksKey, list); + } + } + + public static void readNeighborLightChecksFromNBT(final Chunk chunk, final NBTTagCompound nbt) { + if (nbt.hasKey(neighborLightChecksKey, 9)) { + final NBTTagList list = nbt.getTagList(neighborLightChecksKey, 2); + + if (list.tagCount() == FLAG_COUNT) { + initNeighborLightChecks(chunk); + + short[] neighborLightChecks = ((IChunkLightingData) chunk).getNeighborLightChecks(); + + for (int i = 0; i < FLAG_COUNT; ++i) { + neighborLightChecks[i] = ((NBTTagShort) list.tagList.get(i)).func_150289_e(); + } + } else { + ArchaicLogger.LOGGER.warn("Chunk field {} had invalid length, ignoring it (chunk coordinates: {} {})", neighborLightChecksKey, chunk.xPosition, chunk.zPosition); + } + } + } + + public static void initChunkLighting(final Chunk chunk, final World world) { + final int xBase = chunk.xPosition << 4; + final int zBase = chunk.zPosition << 4; + + final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(xBase, 0, zBase); + + if (world.checkChunksExist(xBase - 16, 0, zBase - 16, xBase + 31, 255, zBase + 31)) { + final ExtendedBlockStorage[] extendedBlockStorage = chunk.getBlockStorageArray(); + + for (int j = 0; j < extendedBlockStorage.length; ++j) { + final ExtendedBlockStorage storage = extendedBlockStorage[j]; + + if (storage == null) { + continue; + } + + int yBase = j * 16; + + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + for (int x = 0; x < 16; x++) { + Block block = storage.getBlockByExtId(x, y, z); + if(block != Blocks.air) { + pos.setPos(xBase + x, yBase + y, zBase + z); + int light = LightingEngineHelpers.getLightValueForState(block, world, pos.getX(), pos.getY(), pos.getZ()); + + if (light > 0) { + world.updateLightByType(EnumSkyBlock.Block, pos.getX(), pos.getY(), pos.getZ()); + } + } + } + } + } + } + + if (!world.provider.hasNoSky) { + ((IChunkLightingData) chunk).setSkylightUpdatedPublic(); + } + + ((IChunkLightingData) chunk).setLightInitialized(true); + } + } + + public static void checkChunkLighting(final Chunk chunk, final World world) { + if (!((IChunkLightingData) chunk).isLightInitialized()) { + initChunkLighting(chunk, world); + } + + for (int x = -1; x <= 1; ++x) { + for (int z = -1; z <= 1; ++z) { + if (x != 0 || z != 0) { + Chunk nChunk = LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(), chunk.xPosition + x, chunk.zPosition + z); + + if (nChunk == null || !((IChunkLightingData) nChunk).isLightInitialized()) { + return; + } + } + } + } + + chunk.isLightPopulated = true; + } + + public static void initSkylightForSection(final World world, final Chunk chunk, final ExtendedBlockStorage section) { + if (!world.provider.hasNoSky) { + for (int x = 0; x < 16; ++x) { + for (int z = 0; z < 16; ++z) { + if (chunk.getHeightValue(x, z) <= section.getYLocation()) { + for (int y = 0; y < 16; ++y) { + section.setExtSkylightValue(x, y, z, EnumSkyBlock.Sky.defaultLightValue); + } + } + } + } + } + } + + private static short[] getNeighborLightChecks(Chunk chunk) { + return ((IChunkLightingData) chunk).getNeighborLightChecks(); + } + + private static void setNeighborLightChecks(Chunk chunk, short[] table) { + ((IChunkLightingData) chunk).setNeighborLightChecks(table); + } + + public static int getCachedLightFor(Chunk chunk, EnumSkyBlock type, int x, int y, int z) { + return ((IChunkLighting) chunk).getCachedLightFor(type, x, y, z); + } + + public static ILightingEngine getLightingEngine(World world) { + return ((ILightingEngineProvider) world).getLightingEngine(); + } + + /** + * Get the intrinsic or saved block light value in a chunk. + * @param chunk the chunk + * @param x X coordinate (0-15) + * @param y Y coordinate (0-255) + * @param z Z coordinate (0-15) + * @return light level + */ + public static int getIntrinsicOrSavedBlockLightValue(Chunk chunk, int x, int y, int z) { + int savedLightValue = chunk.getSavedLightValue(EnumSkyBlock.Block, x, y, z); + int bx = x + (chunk.xPosition * 16); + int bz = z + (chunk.zPosition * 16); + Block block = chunk.getBlock(x, y, z); + int lightValue = LightingEngineHelpers.getLightValueForState(block, chunk.worldObj, bx, y, bz); + return Math.max(savedLightValue, lightValue); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/AccessorSplashProgress.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/AccessorSplashProgress.java new file mode 100644 index 000000000..87ca659ce --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/AccessorSplashProgress.java @@ -0,0 +1,23 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import cpw.mods.fml.client.SplashProgress; +import net.minecraft.client.gui.FontRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(SplashProgress.class) +public interface AccessorSplashProgress { + @Accessor("barBorderColor") + static int getBarBorderColor() { + throw new AssertionError(); + } + @Accessor("barBackgroundColor") + static int getBarBackgroundColor() { + throw new AssertionError(); + } + @Accessor("fontColor") + static int getFontColor() { + throw new AssertionError(); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinBlockFence.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinBlockFence.java new file mode 100644 index 000000000..f0734996c --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinBlockFence.java @@ -0,0 +1,24 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockFence; +import net.minecraft.block.material.Material; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(BlockFence.class) +public abstract class MixinBlockFence extends Block { + protected MixinBlockFence(Material p_i45394_1_) { + super(p_i45394_1_); + } + + /** + * Fix a smooth lighting glitch with fences against solid blocks. + */ + @Inject(method = "", at = @At("RETURN")) + private void makeTransparent(String s, Material m, CallbackInfo ci) { + this.canBlockGrass = true; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinChunkProviderClient.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinChunkProviderClient.java new file mode 100644 index 000000000..758eafc3f --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinChunkProviderClient.java @@ -0,0 +1,18 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ChunkProviderClient; +import net.minecraft.world.chunk.Chunk; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ChunkProviderClient.class) +public class MixinChunkProviderClient { + @Inject(method = "loadChunk", at = @At("HEAD")) + private void onChunkLoad(int x, int z, CallbackInfoReturnable cir) { + if(!Minecraft.getMinecraft().func_152345_ab()) + throw new IllegalStateException("Attempted to load a chunk off-thread!"); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinEntityRenderer.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinEntityRenderer.java new file mode 100644 index 000000000..4371178aa --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinEntityRenderer.java @@ -0,0 +1,18 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = EntityRenderer.class, priority = 1500) +public abstract class MixinEntityRenderer { + /** @reason Makes the third-person view camera pass through non-solid blocks (fixes https://bugs.mojang.com/browse/MC-30845) */ + @Redirect(method = "orientCamera", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;rayTraceBlocks(Lnet/minecraft/util/Vec3;Lnet/minecraft/util/Vec3;)Lnet/minecraft/util/MovingObjectPosition;")) + private MovingObjectPosition rayTraceBlocks(WorldClient world, Vec3 from, Vec3 to) { + return world.func_147447_a(from, to, false, true, true); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinFMLClientHandler.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinFMLClientHandler.java new file mode 100644 index 000000000..bacd69d92 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinFMLClientHandler.java @@ -0,0 +1,21 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.client.GuiModList; +import net.minecraft.client.gui.GuiIngameMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(FMLClientHandler.class) +public abstract class MixinFMLClientHandler { + @Shadow(remap = false) public abstract void showGuiScreen(Object clientGuiElement); + + @Inject(method = "showInGameModOptions", at = @At("HEAD"), cancellable = true, remap = false) + private void showModsList(GuiIngameMenu guiIngameMenu, CallbackInfo ci) { + showGuiScreen(new GuiModList(guiIngameMenu)); + ci.cancel(); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiBeaconButton.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiBeaconButton.java new file mode 100644 index 000000000..d64462f07 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiBeaconButton.java @@ -0,0 +1,22 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.inventory.GuiBeacon; +import net.minecraft.client.renderer.OpenGlHelper; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(targets = { "net/minecraft/client/gui/inventory/GuiBeacon$Button" }) +public class MixinGuiBeaconButton { + /** + * Make transparent beacon buttons look right (e.g. with Modernity). + */ + @Inject(method = "func_146112_a", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/inventory/GuiBeacon$Button;func_73729_b(IIIIII)V", ordinal = 1), require = 0) + private void enableTransparency(Minecraft p_146112_1_, int p_146112_2_, int p_146112_3_, CallbackInfo ci) { + GL11.glEnable(GL11.GL_BLEND); + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiButton.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiButton.java new file mode 100644 index 000000000..2c6873014 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiButton.java @@ -0,0 +1,23 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiOptionSlider; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(GuiButton.class) +public class MixinGuiButton { + /** + * Make buttons render without yellow text (like in 1.14). + */ + @Redirect(method = "drawButton", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/gui/GuiButton;field_146123_n:Z", ordinal = 1)) + private boolean isHovered(GuiButton button) { + if(!ArchaicConfig.enableNewButtonAppearance || button instanceof GuiOptionSlider) + return button.field_146123_n; + else + return false; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiContainerCreative.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiContainerCreative.java new file mode 100644 index 000000000..531e3b653 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiContainerCreative.java @@ -0,0 +1,127 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import com.google.common.collect.ImmutableList; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiTextField; +import net.minecraft.client.gui.inventory.GuiContainerCreative; +import net.minecraft.client.renderer.InventoryEffectRenderer; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.init.Items; +import net.minecraft.inventory.Container; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import org.embeddedt.archaicfix.ArchaicFix; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.embeddedt.archaicfix.helpers.NEISearchHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Mixin(GuiContainerCreative.class) +public abstract class MixinGuiContainerCreative extends InventoryEffectRenderer { + private static List initialCreativeItems = null; + private static final ForkJoinPool creativeSearchPool = new ForkJoinPool(); + private static final Function VANILLA_SUPPLIER = stack -> String.join("", stack.getTooltip(Minecraft.getMinecraft().thePlayer, Minecraft.getMinecraft().gameSettings.advancedItemTooltips)).toLowerCase(); + + @Shadow private static int selectedTabIndex; + + @Shadow private GuiTextField searchField; + + @Shadow private float currentScroll; + + private int debounceTicks = 0; + private boolean needSearchUpdate = false; + private boolean firstSearch = true; + + public MixinGuiContainerCreative(Container p_i1089_1_) { + super(p_i1089_1_); + } + + @Inject(method = "updateCreativeSearch", at = @At(value = "HEAD"), cancellable = true) + private void asyncSearch(CallbackInfo ci) { + if(ArchaicConfig.asyncCreativeSearch) { + ci.cancel(); + needSearchUpdate = true; + if(firstSearch) { + debounceTicks = 0; + firstSearch = false; + } else + debounceTicks = 5; + } + } + + @Inject(method = "updateScreen", at = @At(value = "TAIL")) + private void performRealSearch(CallbackInfo ci) { + if(ArchaicConfig.asyncCreativeSearch && needSearchUpdate) { + String search = this.searchField.getText().toLowerCase(); + if(search.length() == 0) + debounceTicks = 0; + debounceTicks--; + if(debounceTicks <= 0) { + needSearchUpdate = false; + GuiContainerCreative.ContainerCreative containercreative = (GuiContainerCreative.ContainerCreative)this.inventorySlots; + CreativeTabs tab = CreativeTabs.creativeTabArray[selectedTabIndex]; + if (tab.hasSearchBar() && tab != CreativeTabs.tabAllSearch) { + tab.displayAllReleventItems(containercreative.itemList); + } else { + List filteredItems; + if(initialCreativeItems == null) { + initialCreativeItems = new ArrayList<>(); + for (Object o : Item.itemRegistry) { + Item item = (Item) o; + + if (item != null && item.getCreativeTab() != null) { + try { + item.getSubItems(item, null, initialCreativeItems); + } catch(Exception e) { + ArchaicLogger.LOGGER.error("Item " + item + " threw an error while populating the creative item list!", e); + } + } + } + for(Enchantment enchantment : Enchantment.enchantmentsList) { + if (enchantment != null && enchantment.type != null) + { + Items.enchanted_book.func_92113_a(enchantment, initialCreativeItems); + } + } + } + if(search.length() > 0) { + try { + Function nameSupplier = ArchaicFix.NEI_INSTALLED ? new NEISearchHelper() : VANILLA_SUPPLIER; + filteredItems = creativeSearchPool.submit(() -> + initialCreativeItems.parallelStream() + .filter(stack -> { + String s = nameSupplier.apply(stack); + if(s != null) + return s.contains(search); + else + return false; + }) + .collect(Collectors.toList()) + ).get(); + } catch (ExecutionException | InterruptedException e) { + e.printStackTrace(); + filteredItems = ImmutableList.of(); + } + } else + filteredItems = initialCreativeItems; + containercreative.itemList.clear(); + containercreative.itemList.addAll(filteredItems); + containercreative.scrollTo(0.0F); + this.currentScroll = 0.0F; + } + } + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiCreateWorld.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiCreateWorld.java new file mode 100644 index 000000000..41b0c44d3 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiCreateWorld.java @@ -0,0 +1,24 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.gui.GuiCreateWorld; +import net.minecraft.world.storage.ISaveFormat; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(GuiCreateWorld.class) +public class MixinGuiCreateWorld { + @Inject(method = "func_146317_a", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/storage/ISaveFormat;getWorldInfo(Ljava/lang/String;)Lnet/minecraft/world/storage/WorldInfo;"), cancellable = true) + private static void useNumberForCopies(ISaveFormat format, String worldName, CallbackInfoReturnable cir) { + int index = 1; + String finalWorldName = worldName; + while (format.getWorldInfo(finalWorldName) != null) + { + finalWorldName = worldName + " (" + index + ")"; + index++; + } + cir.setReturnValue(finalWorldName); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiIngameForge.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiIngameForge.java new file mode 100644 index 000000000..e008cea40 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiIngameForge.java @@ -0,0 +1,20 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import cpw.mods.fml.common.ModContainer; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraftforge.client.GuiIngameForge; +import org.embeddedt.archaicfix.helpers.LoadControllerHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(GuiIngameForge.class) +public class MixinGuiIngameForge { + @Redirect(method = "renderHUDText", at = @At(value = "FIELD", target = "Lnet/minecraft/world/biome/BiomeGenBase;biomeName:Ljava/lang/String;")) + private String getModNameWithBiome(BiomeGenBase biome) { + ModContainer theMod = LoadControllerHelper.getOwningMod(biome.getClass()); + if(theMod == null) + return biome.biomeName; + return biome.biomeName + " [" + theMod.getName() + "]"; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinIntegratedServer.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinIntegratedServer.java new file mode 100644 index 000000000..56eb029db --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinIntegratedServer.java @@ -0,0 +1,23 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.settings.GameSettings; +import net.minecraft.server.integrated.IntegratedServer; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(IntegratedServer.class) +public class MixinIntegratedServer { + /** + * Force the integrated server to have a minimum view distance of 8, so mob spawning works correctly. + */ + @Redirect(method = "tick", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/settings/GameSettings;renderDistanceChunks:I")) + private int getRealRenderDistance(GameSettings settings) { + if(ArchaicConfig.fixMobSpawnsAtLowRenderDist) + return Math.max(settings.renderDistanceChunks, 8); + else + return settings.renderDistanceChunks; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinMinecraft.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinMinecraft.java new file mode 100644 index 000000000..60bbf489e --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinMinecraft.java @@ -0,0 +1,68 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiScreenWorking; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.settings.GameSettings; +import net.minecraft.server.integrated.IntegratedServer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +public abstract class MixinMinecraft { + @Shadow private IntegratedServer theIntegratedServer; + + @Shadow public abstract void loadWorld(WorldClient p_71403_1_); + + @Shadow public abstract void displayGuiScreen(GuiScreen p_147108_1_); + + @Shadow public GuiScreen currentScreen; + + /** @reason Makes grass display as fancy regardless of the graphics setting. Matches the appearance of 1.8+ */ + @Redirect(method = "runGameLoop", at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z")) + private boolean getFancyGrass(GameSettings gameSettings) { + return true; + } + /** @reason Removes a call to {@link System#gc()} to make world loading as fast as possible */ + @Inject(method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V", at = @At(value = "INVOKE", target = "Ljava/lang/System;gc()V"), cancellable = true) + private void onSystemGC(WorldClient worldClient, String reason, CallbackInfo ci) { + ci.cancel(); + } + + @Inject(method = "checkGLError", at = @At("HEAD"), cancellable = true) + private void skipErrorCheck(String msg, CallbackInfo ci) { + ci.cancel(); + } + + @Redirect(method = "launchIntegratedServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;displayGuiScreen(Lnet/minecraft/client/gui/GuiScreen;)V", ordinal = 1)) + private void displayWorkingScreen(Minecraft mc, GuiScreen in) { + mc.displayGuiScreen(new GuiScreenWorking()); + } + + @Inject(method = "launchIntegratedServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/integrated/IntegratedServer;func_147137_ag()Lnet/minecraft/network/NetworkSystem;", ordinal = 0), cancellable = true) + private void checkServerStopped(CallbackInfo ci) { + try + { + Thread.sleep(200L); + } + catch (InterruptedException interruptedexception) + { + ; + } + if(this.theIntegratedServer.isServerStopped()) { + loadWorld(null); + displayGuiScreen(null); + ci.cancel(); + } + } + + @Redirect(method = "runGameLoop", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/Display;isActive()Z", remap = false)) + private boolean alwaysHaveDisplayActive() { + return true; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerLoginClient.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerLoginClient.java new file mode 100644 index 000000000..6e97f2c0a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerLoginClient.java @@ -0,0 +1,22 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.network.NetHandlerLoginClient; +import net.minecraft.network.NetworkManager; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(NetHandlerLoginClient.class) +public class MixinNetHandlerLoginClient { + @Shadow @Final private NetworkManager field_147393_d; + + @Inject(method = "handleLoginSuccess", at=@At("RETURN")) + public void archaic_raceConditionWorkAround(CallbackInfo cb) { + if(ArchaicConfig.fixLoginRaceCondition) + field_147393_d.channel().config().setAutoRead(true); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerPlayClient.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerPlayClient.java new file mode 100644 index 000000000..ab136a039 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerPlayClient.java @@ -0,0 +1,31 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.network.play.INetHandlerPlayClient; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +/** + * Makes interdimensional teleportation nearly as fast as same-dimension + * teleportation by removing the "Downloading terrain..." screen. This will cause + * the player to see partially loaded terrain rather than waiting for the whole + * render distance to load, but that's also the vanilla behaviour for same-dimension + * teleportation. + */ +@Mixin(value = NetHandlerPlayClient.class, priority = 500) +public abstract class MixinNetHandlerPlayClient implements INetHandlerPlayClient { + + @Redirect(method = "handleJoinGame", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;displayGuiScreen(Lnet/minecraft/client/gui/GuiScreen;)V")) + private void onGuiDisplayJoin(Minecraft mc, GuiScreen guiScreenIn) { + mc.displayGuiScreen(ArchaicConfig.hideDownloadingTerrainScreen ? null : guiScreenIn); + } + + @Redirect(method = "handleRespawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;displayGuiScreen(Lnet/minecraft/client/gui/GuiScreen;)V")) + private void onGuiDisplayRespawn(Minecraft mc, GuiScreen guiScreenIn) { + mc.displayGuiScreen(ArchaicConfig.hideDownloadingTerrainScreen ? null : guiScreenIn); + } +} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinRenderItem.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinRenderItem.java new file mode 100644 index 000000000..85249f939 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinRenderItem.java @@ -0,0 +1,19 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.settings.GameSettings; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(RenderItem.class) +public class MixinRenderItem { + @Redirect(method = "renderDroppedItem(Lnet/minecraft/entity/item/EntityItem;Lnet/minecraft/util/IIcon;IFFFFI)V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z")) + private boolean forceFancyGraphics(GameSettings settings) { + if(ArchaicConfig.forceFancyItems) + return true; + else + return settings.fancyGraphics; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSkinManager.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSkinManager.java new file mode 100644 index 000000000..51ae4892a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSkinManager.java @@ -0,0 +1,21 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.resources.SkinManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(targets = { "net/minecraft/client/resources/SkinManager$2" }) +public class MixinSkinManager { + @Shadow private SkinManager.SkinAvailableCallback field_152636_b; + + /** + * Avoid leaking an EntityClientPlayerMP instance. + */ + @Inject(method = "func_152634_a", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/SkinManager$SkinAvailableCallback;func_152121_a(Lcom/mojang/authlib/minecraft/MinecraftProfileTexture$Type;Lnet/minecraft/util/ResourceLocation;)V", shift = At.Shift.AFTER)) + private void onMakeCallback(CallbackInfo ci) { + field_152636_b = null; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSplashProgress.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSplashProgress.java new file mode 100644 index 000000000..48e93bc40 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSplashProgress.java @@ -0,0 +1,142 @@ +/* + * Based off SplashProgress from Forge 14.23.5.2860. + */ +package org.embeddedt.archaicfix.mixins.client.core; + +import static org.lwjgl.opengl.GL11.*; + +import com.gtnewhorizons.angelica.Tags; +import cpw.mods.fml.client.SplashProgress; +import net.minecraft.client.gui.FontRenderer; +import org.apache.commons.lang3.StringUtils; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.lwjgl.opengl.Display; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.lang.reflect.Field; + +@Mixin(targets = { "cpw/mods/fml/client/SplashProgress$3" }) +public class MixinSplashProgress { + private static final int memoryGoodColor = 0x78CB34; + private static final int memoryWarnColor = 0xE6E84A; + private static final int memoryLowColor = 0xE42F2F; + private static float memoryColorPercent; + private static long memoryColorChangeTime; + private static FontRenderer fontRenderer = null; + @Inject(method = "run", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", ordinal = 1, remap = false, shift = At.Shift.AFTER), remap = false, require = 0) + private void injectDrawMemoryBar(CallbackInfo ci) { + if(fontRenderer == null) { + try { + Field f = SplashProgress.class.getDeclaredField("fontRenderer"); + f.setAccessible(true); + fontRenderer = (FontRenderer)f.get(null); + } catch(ReflectiveOperationException e) { + ArchaicLogger.LOGGER.error(e); + return; + } + } + glPushMatrix(); + glTranslatef(320 - Display.getWidth() / 2 + 4, 240 + Display.getHeight() / 2 - textHeight2, 0); + glScalef(2, 2, 1); + glEnable(GL_TEXTURE_2D); + fontRenderer.drawString("ArchaicFix " + Tags.VERSION, 0, 0, 0x000000); + glDisable(GL_TEXTURE_2D); + glPopMatrix(); + if(ArchaicConfig.showSplashMemoryBar) { + glPushMatrix(); + glTranslatef(320 - (float) barWidth / 2, 20, 0); + drawMemoryBar(); + glPopMatrix(); + } + } + + @Shadow + private void setColor(int color) { + + } + + @Shadow + private void drawBox(int w, int h) { + + } + @Shadow + private int barWidth, barHeight, textHeight2; + + private void drawMemoryBar() { + int maxMemory = bytesToMb(Runtime.getRuntime().maxMemory()); + int totalMemory = bytesToMb(Runtime.getRuntime().totalMemory()); + int freeMemory = bytesToMb(Runtime.getRuntime().freeMemory()); + int usedMemory = totalMemory - freeMemory; + float usedMemoryPercent = usedMemory / (float) maxMemory; + + glPushMatrix(); + // title - message + setColor(AccessorSplashProgress.getFontColor()); + glScalef(2, 2, 1); + glEnable(GL_TEXTURE_2D); + fontRenderer.drawString("Memory Used / Total", 0, 0, 0x000000); + glDisable(GL_TEXTURE_2D); + glPopMatrix(); + // border + glPushMatrix(); + glTranslatef(0, textHeight2, 0); + setColor(AccessorSplashProgress.getBarBorderColor()); + drawBox(barWidth, barHeight); + // interior + setColor(AccessorSplashProgress.getBarBackgroundColor()); + glTranslatef(1, 1, 0); + drawBox(barWidth - 2, barHeight - 2); + // slidy part + + long time = System.currentTimeMillis(); + if (usedMemoryPercent > memoryColorPercent || (time - memoryColorChangeTime > 1000)) + { + memoryColorChangeTime = time; + memoryColorPercent = usedMemoryPercent; + } + + int memoryBarColor; + if (memoryColorPercent < 0.75f) + { + memoryBarColor = memoryGoodColor; + } + else if (memoryColorPercent < 0.85f) + { + memoryBarColor = memoryWarnColor; + } + else + { + memoryBarColor = memoryLowColor; + } + setColor(memoryLowColor); + glPushMatrix(); + glTranslatef((barWidth - 2) * (totalMemory) / (maxMemory) - 2, 0, 0); + drawBox(2, barHeight - 2); + glPopMatrix(); + setColor(memoryBarColor); + drawBox((barWidth - 2) * (usedMemory) / (maxMemory), barHeight - 2); + + // progress text + String progress = getMemoryString(usedMemory) + " / " + getMemoryString(maxMemory); + glTranslatef(((float)barWidth - 2) / 2 - fontRenderer.getStringWidth(progress), 2, 0); + setColor(AccessorSplashProgress.getFontColor()); + glScalef(2, 2, 1); + glEnable(GL_TEXTURE_2D); + fontRenderer.drawString(progress, 0, 0, 0x000000); + glPopMatrix(); + } + + private String getMemoryString(int memory) + { + return StringUtils.leftPad(Integer.toString(memory), 4, ' ') + " MB"; + } + private static int bytesToMb(long bytes) + { + return (int) (bytes / 1024L / 1024L); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinThreadDownloadImageData.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinThreadDownloadImageData.java new file mode 100644 index 000000000..d4fbeed9e --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinThreadDownloadImageData.java @@ -0,0 +1,24 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import net.minecraft.client.renderer.ThreadDownloadImageData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +/** + * Removes a start of tons new threads + * for skins loading + */ +@Mixin(ThreadDownloadImageData.class) +public final class MixinThreadDownloadImageData { + private static final Executor EXECUTOR = Executors.newFixedThreadPool(Math.max(2, Runtime.getRuntime().availableProcessors() / 2), new ThreadFactoryBuilder().setNameFormat("Skin Downloader #%d").setDaemon(true).setPriority(Thread.MIN_PRIORITY).build()); + + @Redirect(method = "func_152433_a", at = @At(value = "INVOKE", target = "Ljava/lang/Thread;start()V")) + private void onThreadStart(Thread thread) { + EXECUTOR.execute(thread); + } +} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinWorldRenderer.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinWorldRenderer.java new file mode 100644 index 000000000..3d7e1d228 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinWorldRenderer.java @@ -0,0 +1,59 @@ +package org.embeddedt.archaicfix.mixins.client.core; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.entity.Entity; +import org.embeddedt.archaicfix.ducks.IWorldRenderer; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/* MC-129 */ +@Mixin(WorldRenderer.class) +public abstract class MixinWorldRenderer implements IWorldRenderer { + @Shadow private boolean isInitialized; + @Shadow public boolean needsUpdate; + + @Shadow public abstract float distanceToEntitySquared(Entity p_78912_1_); + + @Shadow public boolean[] skipRenderPass; + + @Shadow private int glRenderList; + + @Shadow private int bytesDrawn; + + public boolean arch$isInView() { + if(Minecraft.getMinecraft().renderViewEntity == null) + return true; + float distance = this.distanceToEntitySquared(Minecraft.getMinecraft().renderViewEntity); + int renderDistanceBlocks = (Minecraft.getMinecraft().gameSettings.renderDistanceChunks) * 16; + return distance <= (renderDistanceBlocks * renderDistanceBlocks); + } + + /** + * Make sure chunks re-render immediately (MC-129). + */ + @Inject(method = "markDirty", at = @At("TAIL")) + private void forceRender(CallbackInfo ci) { + for(int i = 0; i < this.skipRenderPass.length; i++) { + this.skipRenderPass[i] = false; + } + } + + /** + * When switching worlds/dimensions, clear out the old render lists for old chunks. This prevents old dimension + * content from being visible in the new world. + */ + @Inject(method = "setDontDraw", at = @At("TAIL")) + private void clearOldRenderList(CallbackInfo ci) { + if(this.glRenderList == -1 || this.bytesDrawn <= 0) + return; + for(int pass = 0; pass < 2; pass++) { + GL11.glNewList(this.glRenderList + pass, GL11.GL_COMPILE); + GL11.glEndList(); + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/journeymap/MixinTileDrawStep.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/journeymap/MixinTileDrawStep.java new file mode 100644 index 000000000..f1f6dcc3a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/journeymap/MixinTileDrawStep.java @@ -0,0 +1,15 @@ +package org.embeddedt.archaicfix.mixins.client.journeymap; + +import journeymap.client.render.map.TileDrawStep; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(TileDrawStep.class) +public class MixinTileDrawStep { + @Redirect(method = "*", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Ljourneymap/client/render/map/TileDrawStep;debug:Z")) + private boolean getDebug(TileDrawStep instance) { + return false; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinChunkCache.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinChunkCache.java new file mode 100644 index 000000000..5849765ab --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinChunkCache.java @@ -0,0 +1,19 @@ +package org.embeddedt.archaicfix.mixins.client.lighting; + +import net.minecraft.world.ChunkCache; +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.chunk.Chunk; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ChunkCache.class) +public class MixinChunkCache { + @Redirect(method = "getSpecialBlockBrightness", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;getSavedLightValue(Lnet/minecraft/world/EnumSkyBlock;III)I")) + private int getIntrinsicValue(Chunk instance, EnumSkyBlock p_76614_1_, int p_76614_2_, int p_76614_3_, int p_76614_4_) { + return p_76614_1_ == EnumSkyBlock.Sky ? + instance.getSavedLightValue(p_76614_1_, p_76614_2_, p_76614_3_, p_76614_4_) : + LightingHooks.getIntrinsicOrSavedBlockLightValue(instance, p_76614_2_, p_76614_3_, p_76614_4_); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinMinecraft.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinMinecraft.java new file mode 100644 index 000000000..c57732b4d --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinMinecraft.java @@ -0,0 +1,33 @@ +package org.embeddedt.archaicfix.mixins.client.lighting; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.profiler.Profiler; +import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +public abstract class MixinMinecraft { + + @Shadow @Final public Profiler mcProfiler; + + @Shadow public WorldClient theWorld; + + /** + * @author Angeline + * Forces the client to process light updates before rendering the world. We inject before the call to the profiler + * which designates the start of world rendering. This is a rather injection site. + */ + @Inject(method = "runTick", at = @At(value = "CONSTANT", args = "stringValue=levelRenderer", shift = At.Shift.BY, by = -3)) + private void onRunTick(CallbackInfo ci) { + this.mcProfiler.endStartSection("lighting"); + + ((ILightingEngineProvider) this.theWorld).getLightingEngine().processLightUpdates(); + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinWorld.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinWorld.java new file mode 100644 index 000000000..5f754691b --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinWorld.java @@ -0,0 +1,35 @@ +package org.embeddedt.archaicfix.mixins.client.lighting; + +import net.minecraft.block.Block; +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngine; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(World.class) +public abstract class MixinWorld { + @Shadow public abstract Block getBlock(int p_147439_1_, int p_147439_2_, int p_147439_3_); + + private LightingEngine lightingEngine; + + @Inject(method = "finishSetup", at = @At("RETURN"), remap = false) + private void onConstructed(CallbackInfo ci) { + this.lightingEngine = new LightingEngine((World) (Object) this); + } + + @Redirect(method = { "getSkyBlockTypeBrightness", "getSavedLightValue" }, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;getSavedLightValue(Lnet/minecraft/world/EnumSkyBlock;III)I")) + private int useBlockIntrinsicBrightness(Chunk instance, EnumSkyBlock type, int x, int y, int z) { + if(type == EnumSkyBlock.Block) + return LightingHooks.getIntrinsicOrSavedBlockLightValue(instance, x, y, z); + else + return instance.getSavedLightValue(type, x, y, z); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinChunk.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinChunk.java new file mode 100644 index 000000000..bbe0d27d7 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinChunk.java @@ -0,0 +1,89 @@ +package org.embeddedt.archaicfix.mixins.client.occlusion; + +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import org.embeddedt.archaicfix.occlusion.ICulledChunk; +import org.embeddedt.archaicfix.occlusion.ChunkThread; +import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; +import org.embeddedt.archaicfix.occlusion.VisGraph; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Chunk.class) +public abstract class MixinChunk implements ICulledChunk { + @Shadow public abstract Block getBlock(int p_150810_1_, int p_150810_2_, int p_150810_3_); + + @Shadow public World worldObj; + @Shadow @Final public int xPosition; + @Shadow @Final public int zPosition; + private VisGraph[] visibility; + + private static ChunkThread worker = new ChunkThread(); + static { + worker.start(); + } + + public Chunk buildCulledSides() { + if (!this.worldObj.getChunkProvider().chunkExists(xPosition, zPosition)) { + return null; + } + for (int i = 0; i < 16; ++i) { + for (int j = 0; j < 16; ++j) { + for (int y = 0; y < 256; ++y) { + checkPosSolid(i, y, j, null); + } + } + } + OcclusionHelpers.updateArea(xPosition * 16 - 1, 0, zPosition * 16 - 1, xPosition * 16 + 16, 255, zPosition * 16 + 16); + return (Chunk)(Object)this; + } + + + + @Inject(method = "(Lnet/minecraft/world/World;II)V", at = @At("RETURN")) + private void onInit(World p_i1995_1_, int p_i1995_2_, int p_i1995_3_, CallbackInfo ci) { + visibility = new VisGraph[16]; + for (int i = 0; i < 16; ++i) { + visibility[i] = new VisGraph(); + } + } + + @Override + public VisGraph[] getVisibility() { + return visibility; + } + + boolean checkPosSolid(int x, int y, int z, Block block) { + + if (y > 255 || y < 0) + return false; + if (block == null) { + block = getBlock(x, y, z); + } + VisGraph chunk = this.visibility[y >> 4]; + y &= 15; + + chunk.setOpaque(x, y, z, block.isOpaqueCube()); + return chunk.isDirty(); + } + + @Inject(method = "func_150807_a", at = @At("RETURN")) + private void onSetBlock(int x, int y, int z, Block block, int meta, CallbackInfoReturnable cir) { + if(cir.getReturnValue() && this.worldObj.isRemote && checkPosSolid(x & 15, y, z & 15, block)) { + worker.modified.add((Chunk)(Object)this); + } + } + + @Inject(method = "fillChunk", at = @At("RETURN")) + private void onFillChunk(byte[] p_76607_1_, int p_76607_2_, int p_76607_3_, boolean p_76607_4_, CallbackInfo ci) { + worker.loaded.add((Chunk)(Object)this); + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinEntityRenderer.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinEntityRenderer.java new file mode 100644 index 000000000..779f419d8 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinEntityRenderer.java @@ -0,0 +1,22 @@ +package org.embeddedt.archaicfix.mixins.client.occlusion; + +import net.minecraft.client.renderer.EntityRenderer; +import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = EntityRenderer.class) +public class MixinEntityRenderer { + + /** + * @reason MixinRenderGlobal#performCullingUpdates needs to know the chunk update deadline and the partial tick time + */ + @Inject(method = "renderWorld", at = @At("HEAD")) + private void getRendererUpdateDeadline(float partialTickTime, long chunkUpdateDeadline, CallbackInfo ci) { + OcclusionHelpers.chunkUpdateDeadline = chunkUpdateDeadline; + OcclusionHelpers.partialTickTime = partialTickTime; + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinGuiVideoSettings.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinGuiVideoSettings.java new file mode 100644 index 000000000..2d7b4ff35 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinGuiVideoSettings.java @@ -0,0 +1,14 @@ +package org.embeddedt.archaicfix.mixins.client.occlusion; + +import net.minecraft.client.gui.GuiVideoSettings; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(GuiVideoSettings.class) +public class MixinGuiVideoSettings { + @Redirect(method = "initGui", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/OpenGlHelper;field_153197_d:Z")) + private boolean neverUseAdvancedGl() { + return false; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinRenderGlobal.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinRenderGlobal.java new file mode 100644 index 000000000..bf9ee8ede --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinRenderGlobal.java @@ -0,0 +1,135 @@ +package org.embeddedt.archaicfix.mixins.client.occlusion; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.culling.ICamera; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import org.embeddedt.archaicfix.occlusion.*; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.*; + +@Mixin(value = RenderGlobal.class, priority = -2) +public abstract class MixinRenderGlobal { + /** + * Queue a renderer to be updated. + */ + @Inject(method = "markBlocksForUpdate", at = @At("HEAD"), cancellable = true) + private void handleOffthreadUpdate(int x1, int y1, int z1, int x2, int y2, int z2, CallbackInfo ci) { + ci.cancel(); + OcclusionHelpers.renderer.handleOffthreadUpdate(x1, y1, z1, x2, y2, z2); + } + + @Redirect(method = "renderEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)Z")) + private boolean skipRenderingIfNotVisible(RenderManager instance, Entity entity, float tick) { + return OcclusionHelpers.renderer.skipRenderingIfNotVisible(instance, entity, tick); + } + + /** + * @author skyboy, embeddedt + * @reason Include information on occlusion + */ + @Overwrite + public String getDebugInfoRenders() { + return OcclusionHelpers.renderer.getDebugInfoRenders(); + } + + @Inject(method = "", at = @At("RETURN")) + private void initBetterLists(Minecraft p_i1249_1_, CallbackInfo ci) { + OcclusionHelpers.renderer = new OcclusionRenderer((RenderGlobal)(Object)this); + OcclusionHelpers.renderer.initBetterLists(); + } + + @Redirect(method = "loadRenderers", at = @At(value = "INVOKE", target = "Ljava/util/List;clear()V", ordinal = 0)) + private void clearRendererUpdateQueue(List instance) { + OcclusionHelpers.renderer.clearRendererUpdateQueue(instance); + } + + @Redirect(method = { "loadRenderers", "markRenderersForNewPosition" }, at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", ordinal = 0)) + private boolean sortAndAddRendererUpdateQueue(List instance, Object renderer) { + return OcclusionHelpers.renderer.sortAndAddRendererUpdateQueue(instance, renderer); + } + + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/OpenGlCapsChecker;checkARBOcclusion()Z")) + private boolean neverEnableOcclusion() { + return false; + } + + @Inject(method = "updateRenderers", at = @At("HEAD"), cancellable = true) + private void performCullingUpdates(EntityLivingBase view, boolean p_72716_2_, CallbackInfoReturnable cir) { + OcclusionHelpers.renderer.performCullingUpdates(view, p_72716_2_); + cir.setReturnValue(true); + } + + @Inject(method = "setWorldAndLoadRenderers", at = @At("HEAD")) + private void setWorkerWorld(WorldClient world, CallbackInfo ci) { + OcclusionHelpers.worker.setWorld((RenderGlobal)(Object)this, world); + } + + @Inject(method = "loadRenderers", at = @At("HEAD")) + private void resetLoadedRenderers(CallbackInfo ci) { + OcclusionHelpers.renderer.resetLoadedRenderers(); + } + + @Inject(method = "loadRenderers", at = @At("TAIL")) + private void resetOcclusionWorker(CallbackInfo ci) { + OcclusionHelpers.renderer.resetOcclusionWorker(); + } + + @Redirect(method = "loadRenderers", at = @At(value = "INVOKE", target = "Ljava/util/Arrays;sort([Ljava/lang/Object;Ljava/util/Comparator;)V", ordinal = 0)) + private void skipSort2(Object[] ts, Comparator comparator) { + + } + + @Redirect(method = "loadRenderers", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/WorldRenderer;markDirty()V", ordinal = 0)) + private void markRendererInvisible(WorldRenderer instance) { + OcclusionHelpers.renderer.markRendererInvisible(instance); + } + + @Redirect(method = "markRenderersForNewPosition", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/WorldRenderer;setPosition(III)V")) + private void setPositionAndMarkInvisible(WorldRenderer wr, int x, int y, int z) { + OcclusionHelpers.renderer.setPositionAndMarkInvisible(wr, x, y, z); + } + + @Inject(method = "markRenderersForNewPosition", at = @At("TAIL")) + private void runWorker(int p_72722_1_, int p_72722_2_, int p_72722_3_, CallbackInfo ci) { + OcclusionHelpers.renderer.runWorker(p_72722_1_, p_72722_2_, p_72722_3_); + } + + /** + * @author skyboy, embeddedt + * @reason Update logic + */ + @Overwrite + public int sortAndRender(EntityLivingBase view, int pass, double tick) { + return OcclusionHelpers.renderer.sortAndRender(view, pass, tick); + } + + /** + * @author embeddedt, skyboy + * @reason occlusion culling + */ + @Overwrite + @SuppressWarnings("unchecked") + public int renderSortedRenderers(int start, int end, int pass, double tick) { + return OcclusionHelpers.renderer.sortAndRender(start, end, pass, tick); + } + + /** + * @author makamys + * @reason Integrate with the logic in {@link OcclusionWorker#run(boolean)}. + */ + @Overwrite + public void clipRenderersByFrustum(ICamera p_72729_1_, float p_72729_2_) { + OcclusionHelpers.renderer.clipRenderersByFrustum(p_72729_1_, p_72729_2_); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinWorldRenderer.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinWorldRenderer.java new file mode 100644 index 000000000..ff67550d1 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinWorldRenderer.java @@ -0,0 +1,85 @@ +package org.embeddedt.archaicfix.mixins.client.occlusion; + +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.shader.TesselatorVertexState; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.world.World; +import net.minecraft.world.chunk.EmptyChunk; +import org.embeddedt.archaicfix.occlusion.IWorldRenderer; +import org.embeddedt.archaicfix.occlusion.OcclusionWorker; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; + +@Mixin(WorldRenderer.class) +public class MixinWorldRenderer implements IWorldRenderer { + @Shadow public boolean isWaitingOnOcclusionQuery; + + @Shadow public World worldObj; + + @Shadow public int posX; + + @Shadow public int posZ; + + @Shadow public List tileEntityRenderers; + + @Shadow private List tileEntities; + + @Shadow public boolean needsUpdate; + + @Shadow public boolean isInitialized; + + @Shadow private int bytesDrawn; + + @Shadow private TesselatorVertexState vertexState; + + private boolean arch$isInUpdateList; + private boolean arch$isFrustumCheckPending; + + private OcclusionWorker.CullInfo arch$cullInfo; + + @Inject(method = "*", at = @At("RETURN")) + private void init(CallbackInfo ci) { + this.arch$cullInfo = new OcclusionWorker.CullInfo(); + } + + @Inject(method = "markDirty", at = @At("TAIL")) + private void resetOcclusionFlag(CallbackInfo ci) { + this.isWaitingOnOcclusionQuery = false; + } + + @Inject(method = "updateRenderer", at = @At(value = "FIELD", opcode = Opcodes.PUTSTATIC, target = "Lnet/minecraft/world/chunk/Chunk;isLit:Z", ordinal = 0), cancellable = true) + private void bailOnEmptyChunk(EntityLivingBase view, CallbackInfo ci) { + if(worldObj.getChunkFromBlockCoords(posX, posZ) instanceof EmptyChunk) { + if (tileEntityRenderers.size() > 0) { + tileEntities.removeAll(tileEntityRenderers); + tileEntityRenderers.clear(); + } + needsUpdate = true; + isInitialized = false; + bytesDrawn = 0; + vertexState = null; + ci.cancel(); + } + } + + @Override + public boolean arch$isInUpdateList() { + return arch$isInUpdateList; + } + + @Override + public void arch$setInUpdateList(boolean b) { + arch$isInUpdateList = b; + } + + @Override + public OcclusionWorker.CullInfo arch$getCullInfo() { + return arch$cullInfo; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/optifine/MixinVersionCheckThread.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/optifine/MixinVersionCheckThread.java new file mode 100644 index 000000000..a36bd31c1 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/optifine/MixinVersionCheckThread.java @@ -0,0 +1,16 @@ +package org.embeddedt.archaicfix.mixins.client.optifine; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Pseudo +@Mixin(targets = {"VersionCheckThread"}, remap = false) +public abstract class MixinVersionCheckThread extends Thread { + @Inject(method = "run", at = @At("HEAD"), cancellable = true) + private void skipCheck(CallbackInfo ci) { + ci.cancel(); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinGameSettings.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinGameSettings.java new file mode 100644 index 000000000..ec56ad989 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinGameSettings.java @@ -0,0 +1,16 @@ +package org.embeddedt.archaicfix.mixins.client.renderdistance; + +import net.minecraft.client.settings.GameSettings; +import org.embeddedt.archaicfix.ArchaicFix; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(GameSettings.class) +public class MixinGameSettings { + @ModifyConstant(method = "(Lnet/minecraft/client/Minecraft;Ljava/io/File;)V", constant = @Constant(floatValue = 16.0f)) + private float increaseMaxDistance(float old) { + return ArchaicConfig.newMaxRenderDistance; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinRenderGlobal.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinRenderGlobal.java new file mode 100644 index 000000000..be865da8f --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinRenderGlobal.java @@ -0,0 +1,52 @@ +package org.embeddedt.archaicfix.mixins.client.renderdistance; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.RenderList; +import org.embeddedt.archaicfix.ArchaicFix; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.nio.Buffer; +import java.nio.IntBuffer; + +@Mixin(value = RenderGlobal.class, priority = -10) +public class MixinRenderGlobal { + @Shadow private RenderList[] allRenderLists; + + @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GLAllocation;generateDisplayLists(I)I"), index = 0) + private int generateDisplayLists(int original) { + int chunkNum = (ArchaicConfig.newMaxRenderDistance * 2) + 2; + return chunkNum * chunkNum * 16 * 3; + } + + @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GLAllocation;createDirectIntBuffer(I)Ljava/nio/IntBuffer;"), index = 0) + private int createOcclusionBuffer(int original) { + int chunkNum = (ArchaicConfig.newMaxRenderDistance * 2) + 2; + return chunkNum * chunkNum * 16; + } + + @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Ljava/nio/IntBuffer;limit(I)Ljava/nio/Buffer;"), index = 0) + private int limitOcclusionBuffer(int i) { + int chunkNum = (ArchaicConfig.newMaxRenderDistance * 2) + 2; + return chunkNum * chunkNum * 16; + } + + @Inject(method = "", at = @At("RETURN")) + private void resizeAllRenderLists(Minecraft p_i1249_1_, CallbackInfo ci) { + int sideLength = Math.max(2, ArchaicConfig.newMaxRenderDistance / 16); + if(allRenderLists.length >= (sideLength * sideLength)) + return; + allRenderLists = new RenderList[sideLength*sideLength]; + for(int i = 0; i < allRenderLists.length; i++) { + allRenderLists[i] = new RenderList(); + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinRenderBlocks.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinRenderBlocks.java new file mode 100644 index 000000000..386b87032 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinRenderBlocks.java @@ -0,0 +1,53 @@ +package org.embeddedt.archaicfix.mixins.client.threadedupdates; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraftforge.client.ForgeHooksClient; +import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; +import org.embeddedt.archaicfix.threadedupdates.IRendererUpdateResultHolder; +import org.embeddedt.archaicfix.threadedupdates.api.ThreadedChunkUpdates; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(RenderBlocks.class) +public class MixinRenderBlocks { + + @Inject(method = "renderBlockByRenderType", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;setBlockBoundsBasedOnState(Lnet/minecraft/world/IBlockAccess;III)V"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) + private void cancelRenderDelegatedToDifferentThread(Block block, int x, int y, int z, CallbackInfoReturnable cir, int renderType) { + int pass = ForgeHooksClient.getWorldRenderPass(); + boolean mainThread = Thread.currentThread() == ThreadedChunkUpdateHelper.MAIN_THREAD; + + ThreadedChunkUpdateHelper.UpdateTask task = mainThread + ? ((IRendererUpdateResultHolder)ThreadedChunkUpdateHelper.lastWorldRenderer).arch$getRendererUpdateTask() + : null; + + boolean offThreadBlock = ThreadedChunkUpdateHelper.canBlockBeRenderedOffThread(block, pass, renderType) + && !(task != null && task.cancelled) + && (!mainThread || ThreadedChunkUpdateHelper.renderBlocksStack.getLevel() == 1); + if ((mainThread ? pass >= 0 : true) && (mainThread ? offThreadBlock : !offThreadBlock)) { + // Cancel rendering block if it's delegated to a different thread. + cir.setReturnValue(mainThread ? task.result[pass].renderedSomething : false); + } + } + + @Inject(method = "renderBlockByRenderType", at = @At("HEAD")) + private void pushStack(CallbackInfoReturnable cir) { + ThreadedChunkUpdateHelper.renderBlocksStack.push(); + } + + @Inject(method = "renderBlockByRenderType", at = @At("RETURN")) + private void popStack(CallbackInfoReturnable cir) { + ThreadedChunkUpdateHelper.renderBlocksStack.pop(); + } + + @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;instance:Lnet/minecraft/client/renderer/Tessellator;")) + private Tessellator modifyTessellatorAccess() { + return ThreadedChunkUpdates.getThreadTessellator(); + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator.java new file mode 100644 index 000000000..aa79c87ec --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator.java @@ -0,0 +1,86 @@ +package org.embeddedt.archaicfix.mixins.client.threadedupdates; + +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.shader.TesselatorVertexState; +import org.embeddedt.archaicfix.threadedupdates.ICapturableTessellator; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.util.Arrays; + +@Mixin(Tessellator.class) +public abstract class MixinTessellator implements ICapturableTessellator { + + @Shadow + private int[] rawBuffer; + + @Shadow + private int rawBufferIndex; + + @Shadow + private int vertexCount; + + @Shadow protected abstract void reset(); + + @Shadow private boolean isDrawing; + + @Shadow private int rawBufferSize; + + @Shadow private boolean hasTexture; + + @Shadow private boolean hasBrightness; + + @Shadow private boolean hasColor; + + @Shadow private boolean hasNormals; + + @Override + public TesselatorVertexState arch$getUnsortedVertexState() { + if(vertexCount < 1) { + return null; + } + return new TesselatorVertexState(Arrays.copyOf(rawBuffer, rawBufferIndex), this.rawBufferIndex, this.vertexCount, this.hasTexture, this.hasBrightness, this.hasNormals, this.hasColor); + } + + @Override + public void arch$addTessellatorVertexState(TesselatorVertexState state) throws IllegalStateException { + if(state == null) return; + // TODO check if draw mode is the same + + hasTexture |= state.getHasTexture(); + hasBrightness |= state.getHasBrightness(); + hasColor |= state.getHasColor(); + hasNormals |= state.getHasNormals(); + + while(rawBufferSize < rawBufferIndex + state.getRawBuffer().length) { + rawBufferSize *= 2; + } + if(rawBufferSize > rawBuffer.length) { + rawBuffer = Arrays.copyOf(rawBuffer, rawBufferSize); + } + + System.arraycopy(state.getRawBuffer(), 0, rawBuffer, rawBufferIndex, state.getRawBufferIndex()); + rawBufferIndex += state.getRawBufferIndex(); + vertexCount += state.getVertexCount(); + } + + @Override + public void discard() { + isDrawing = false; + reset(); + } + + /** @reason Allow using multiple tessellator instances concurrently by removing static field access in alternate + * instances. */ + @Redirect(method = "reset", at = @At(value = "INVOKE", target = "Ljava/nio/ByteBuffer;clear()Ljava/nio/Buffer;")) + private Buffer removeStaticBufferAccessOutsideSingleton(ByteBuffer buffer) { + if(((Object)this) == Tessellator.instance) { + return buffer.clear(); + } + return buffer; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator_Debug.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator_Debug.java new file mode 100644 index 000000000..cc519a891 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator_Debug.java @@ -0,0 +1,34 @@ +package org.embeddedt.archaicfix.mixins.client.threadedupdates; + +import net.minecraft.client.renderer.Tessellator; +import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; +import org.spongepowered.asm.mixin.Mixin; +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.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(value = Tessellator.class) +public abstract class MixinTessellator_Debug { + + @Inject(method = {"setVertexState", "func_154352_a", "setColorRGBA_F", "setColorRGBA", "startDrawing", "addTranslation", "setTranslation", "addVertexWithUV", "setNormal", "setColorOpaque", "addVertex", "setColorOpaque_I", "reset", "setBrightness", "startDrawingQuads", "disableColor", "setColorRGBA_I", "setTextureUV", "setColorOpaque_F"}, at = @At("HEAD")) + private void verifyThreadIsCorrect(CallbackInfo ci) { + verifyThreadIsCorrect(); + } + + @Inject(method = {"getVertexState", "draw"}, at = @At("HEAD")) + private void verifyThreadIsCorrect(CallbackInfoReturnable cir) { + verifyThreadIsCorrect(); + } + + @Unique + private void verifyThreadIsCorrect() { + if(((Object)this) == Tessellator.instance) { + if(ThreadedChunkUpdateHelper.MAIN_THREAD != null && Thread.currentThread() != ThreadedChunkUpdateHelper.MAIN_THREAD) { + throw new IllegalStateException("Tried to access main tessellator from non-main thread " + Thread.currentThread().getName()); + } + } + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinWorldRenderer.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinWorldRenderer.java new file mode 100644 index 000000000..c77099a57 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinWorldRenderer.java @@ -0,0 +1,57 @@ +package org.embeddedt.archaicfix.mixins.client.threadedupdates; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.world.ChunkCache; +import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; +import org.embeddedt.archaicfix.threadedupdates.ICapturableTessellator; +import org.embeddedt.archaicfix.threadedupdates.IRendererUpdateResultHolder; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.HashSet; + +@Mixin(WorldRenderer.class) +public class MixinWorldRenderer implements IRendererUpdateResultHolder { + + private ThreadedChunkUpdateHelper.UpdateTask arch$updateTask; + + @Inject(method = "updateRenderer", at = @At("HEAD")) + private void setLastWorldRendererSingleton(CallbackInfo ci) { + ThreadedChunkUpdateHelper.lastWorldRenderer = ((WorldRenderer)(Object)this); + } + + @Inject(method = "updateRenderer", at = @At(value="INVOKE", target = "Lnet/minecraft/client/renderer/WorldRenderer;postRenderBlocks(ILnet/minecraft/entity/EntityLivingBase;)V"), locals=LocalCapture.CAPTURE_FAILHARD) + private void loadTessellationResult(EntityLivingBase cameraEntity, CallbackInfo ci, int i, int j, int k, int l, int i1, int j1, HashSet hashset, Minecraft minecraft, EntityLivingBase entitylivingbase1, int l1, int i2, int j2, byte b0, ChunkCache chunkcache, RenderBlocks renderblocks, int k2) { + int pass = k2; + if(!arch$getRendererUpdateTask().cancelled) { + ((ICapturableTessellator) Tessellator.instance).arch$addTessellatorVertexState(arch$getRendererUpdateTask().result[pass].renderedQuads); + } + } + + @Inject(method = "updateRenderer", at = @At(value="INVOKE", target = "Lnet/minecraft/client/renderer/RenderBlocks;renderBlockByRenderType(Lnet/minecraft/block/Block;III)Z")) + private void resetStack(CallbackInfo ci) { + // Make sure the stack doesn't leak + ThreadedChunkUpdateHelper.renderBlocksStack.reset(); + } + + @Override + public ThreadedChunkUpdateHelper.UpdateTask arch$getRendererUpdateTask() { + if(arch$updateTask == null) { + arch$updateTask = new ThreadedChunkUpdateHelper.UpdateTask(); + } + return arch$updateTask; + } + + @Inject(method = "markDirty", at = @At("RETURN")) + private void notifyDirty(CallbackInfo ci) { + ThreadedChunkUpdateHelper.instance.onWorldRendererDirty((WorldRenderer)(Object)this); + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/botania/MixinBlockSpecialFlower.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/botania/MixinBlockSpecialFlower.java new file mode 100644 index 000000000..bdae2023e --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/botania/MixinBlockSpecialFlower.java @@ -0,0 +1,18 @@ +package org.embeddedt.archaicfix.mixins.common.botania; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import vazkii.botania.common.block.BlockSpecialFlower; +import vazkii.botania.common.block.tile.TileSpecialFlower; + +@Mixin(BlockSpecialFlower.class) +public class MixinBlockSpecialFlower { + @Redirect(method = "getLightValue", at = @At(value = "INVOKE", target = "Lvazkii/botania/common/block/tile/TileSpecialFlower;getLightValue()I", remap = false), remap = false) + private int archaic$avoidNullCrash(TileSpecialFlower instance) { + if(instance == null) + return -1; + else + return instance.getLightValue(); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/chickenchunks/MixinPlayerChunkViewerManager.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/chickenchunks/MixinPlayerChunkViewerManager.java new file mode 100644 index 000000000..93b84739c --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/chickenchunks/MixinPlayerChunkViewerManager.java @@ -0,0 +1,39 @@ +package org.embeddedt.archaicfix.mixins.common.chickenchunks; + +import codechicken.chunkloader.PlayerChunkViewerManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; + +@Mixin(PlayerChunkViewerManager.class) +public class MixinPlayerChunkViewerManager { + @Shadow(remap = false) public LinkedList ticketChanges; + + private ArrayList oldTicketChanges; + + @Redirect(method = "update", at = @At(value = "INVOKE", target = "Ljava/util/LinkedList;iterator()Ljava/util/Iterator;"), remap = false) + private Iterator getSafeIterator(LinkedList list) { + if(list == this.ticketChanges) { + oldTicketChanges = new ArrayList<>((LinkedList)list); + return oldTicketChanges.iterator(); + } else { + return list.iterator(); + } + } + + @Redirect(method = "update", at = @At(value = "INVOKE", target = "Ljava/util/LinkedList;clear()V"), remap = false) + private void clearListSafely(LinkedList list) { + if(list == this.ticketChanges) { + this.ticketChanges.removeAll(oldTicketChanges); + oldTicketChanges = null; + } else { + list.clear(); + } + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/AccessorEntityLiving.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/AccessorEntityLiving.java new file mode 100644 index 000000000..60dce2c7d --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/AccessorEntityLiving.java @@ -0,0 +1,13 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.entity.EntityLiving; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(EntityLiving.class) +public interface AccessorEntityLiving { + @Invoker + public boolean invokeCanDespawn(); + @Invoker + public void invokeDespawnEntity(); +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinASMData.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinASMData.java new file mode 100644 index 000000000..971edb482 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinASMData.java @@ -0,0 +1,25 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import cpw.mods.fml.common.discovery.ASMDataTable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import zone.rong.rongasm.api.LoliStringPool; + +@Mixin(value = ASMDataTable.ASMData.class, remap = false) +public class MixinASMData { + @Shadow private String annotationName; + + @Shadow private String className; + + @Redirect(method = "", at = @At(value = "FIELD", target = "Lcpw/mods/fml/common/discovery/ASMDataTable$ASMData;annotationName:Ljava/lang/String;")) + private void canonicalizeAnnotation(ASMDataTable.ASMData instance, String value) { + this.annotationName = value == null ? null : LoliStringPool.canonicalize(value); + } + + @Redirect(method = "", at = @At(value = "FIELD", target = "Lcpw/mods/fml/common/discovery/ASMDataTable$ASMData;className:Ljava/lang/String;")) + private void canonicalizeClassName(ASMDataTable.ASMData instance, String value) { + this.className = value == null ? null : LoliStringPool.canonicalize(value); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinAxisAlignedBB.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinAxisAlignedBB.java new file mode 100644 index 000000000..b59bd5a1a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinAxisAlignedBB.java @@ -0,0 +1,32 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.util.AxisAlignedBB; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(AxisAlignedBB.class) +public class MixinAxisAlignedBB { + private final double XZ_MARGIN = 1E-6; + private final double Y_MARGIN = 0.000000001; + + @ModifyVariable(method = "calculateXOffset", at = @At(value = "STORE", ordinal = 0), index = 2, argsOnly = true) + private double subXMargin(double old) { + return old - XZ_MARGIN; + } + + @ModifyVariable(method = "calculateXOffset", at = @At(value = "STORE", ordinal = 1), index = 2, argsOnly = true) + private double addXMargin(double old) { + return old + XZ_MARGIN; + } + + @ModifyVariable(method = "calculateZOffset", at = @At(value = "STORE", ordinal = 0), index = 2, argsOnly = true) + private double subZMargin(double old) { + return old - XZ_MARGIN; + } + + @ModifyVariable(method = "calculateZOffset", at = @At(value = "STORE", ordinal = 1), index = 2, argsOnly = true) + private double addZMargin(double old) { + return old + XZ_MARGIN; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinBlock.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinBlock.java new file mode 100644 index 000000000..d5db2c59a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinBlock.java @@ -0,0 +1,60 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.relauncher.Side; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.server.MinecraftServer; +import org.embeddedt.archaicfix.block.ThreadedBlockData; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.lang.ref.WeakReference; +import java.util.WeakHashMap; + +@Mixin(Block.class) +public class MixinBlock { + @Shadow public Block.SoundType stepSound; + private WeakReference lastServer = new WeakReference<>(null); + private ThreadedBlockData arch$serverThreadedData = null; + private ThreadedBlockData arch$clientThreadedData = new ThreadedBlockData(); + + private final ThreadLocal arch$threadBlockData = new ThreadLocal<>(); + + @Redirect(method = "", at = @At(opcode = Opcodes.PUTFIELD, value = "FIELD", target = "Lnet/minecraft/block/Block;stepSound:Lnet/minecraft/block/Block$SoundType;", ordinal = 0)) + private void onConstruct(Block block, Block.SoundType sound) { + stepSound = sound; + } + + private ThreadedBlockData arch$calculateThreadedData() { + FMLCommonHandler inst = FMLCommonHandler.instance(); + Side trueSide; + if(inst.getSidedDelegate() == null) { + trueSide = inst.getEffectiveSide(); + } else { + trueSide = inst.getSide(); + } + if(trueSide == Side.SERVER || inst.getEffectiveSide() == Side.SERVER) { + if(lastServer.get() != inst.getMinecraftServerInstance()) { + lastServer = new WeakReference<>(inst.getMinecraftServerInstance()); + arch$serverThreadedData = new ThreadedBlockData(arch$clientThreadedData); + } + return arch$serverThreadedData; + } + return arch$clientThreadedData; + } + + public ThreadedBlockData arch$getThreadedData() { + ThreadedBlockData calculated = arch$threadBlockData.get(); + if(calculated == null) { + calculated = arch$calculateThreadedData(); + arch$threadBlockData.set(calculated); + } + return calculated; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunk.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunk.java new file mode 100644 index 000000000..46f9b7be2 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunk.java @@ -0,0 +1,101 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import com.google.common.collect.Iterators; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.ModContainer; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.biome.WorldChunkManager; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.embeddedt.archaicfix.ducks.IArchaicWorld; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.*; + +@Mixin(value = Chunk.class, priority = 1100) +public class MixinChunk { + @Shadow @Final private List[] entityLists; + @Shadow @Final private World worldObj; + + @Shadow @Final public int xPosition; + + @Shadow @Final public int zPosition; + + @Shadow public Map chunkTileEntityMap; + + @Inject(method = "onChunkUnload", at = @At("HEAD")) + public void handlePlayerChunkUnload(CallbackInfo ci) { + final List players = new ArrayList<>(); + for (final List list : entityLists) { + for(final Entity entity : list) { + if(entity instanceof EntityPlayer) + players.add((EntityPlayer)entity); + } + } + for (final EntityPlayer player : players) { + worldObj.updateEntityWithOptionalForce(player, false); + } + } + + @Redirect(method = "onChunkUnload", at = @At(value = "INVOKE", target = "Ljava/util/Collection;iterator()Ljava/util/Iterator;", ordinal = 0)) + private Iterator markTEForUnload(Collection instance) { + if(ArchaicConfig.fixTEUnloadLag) { + ((IArchaicWorld)this.worldObj).arch$markTileEntitiesInChunkForRemoval((Chunk)(Object)this); + return Iterators.emptyIterator(); + } + return instance.iterator(); + } + + @Inject(method = "getBiomeGenForWorldCoords", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/biome/WorldChunkManager;getBiomeGenAt(II)Lnet/minecraft/world/biome/BiomeGenBase;"), cancellable = true) + private void avoidBiomeGenOnClient(int p_76591_1_, int p_76591_2_, WorldChunkManager p_76591_3_, CallbackInfoReturnable cir) { + if(this.worldObj.isRemote) { + cir.setReturnValue(BiomeGenBase.ocean); + } + } + + private static LinkedList arch$populatingChunk = new LinkedList<>(); // keep track of cascading chunk generation during chunk population + + private void logCascadingWorldGeneration() + { + ModContainer activeModContainer = Loader.instance().activeModContainer(); + String format = "{} loaded a new chunk {} in dimension {} ({}) while populating chunk {}, causing cascading worldgen lag."; + + ChunkCoordIntPair pos = new ChunkCoordIntPair(this.xPosition, this.zPosition); + + if (activeModContainer == null) { + ArchaicLogger.LOGGER.warn(format, "Minecraft", pos, this.worldObj.provider.dimensionId, this.worldObj.provider.getDimensionName(), arch$populatingChunk.peek()); + } else { + ArchaicLogger.LOGGER.warn(format, activeModContainer.getName(), pos, this.worldObj.provider.dimensionId, this.worldObj.provider.getDimensionName(), arch$populatingChunk.peek()); + ArchaicLogger.LOGGER.warn("Please report this to the mod's issue tracker. This log can be disabled in the ArchaicFix config."); + } + + if(ArchaicConfig.logCascadingWorldgenStacktrace) { + ArchaicLogger.LOGGER.warn("Stacktrace", new Exception("Cascading world generation")); + } + } + + @Inject(method = "populateChunk", at = @At("HEAD")) + private void savePopulatingChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int x, int z, CallbackInfo ci) { + if(arch$populatingChunk.size() > 0 && ArchaicConfig.logCascadingWorldgen) logCascadingWorldGeneration(); + arch$populatingChunk.push(new ChunkCoordIntPair(x, z)); + } + + @Inject(method = "populateChunk", at = @At("TAIL")) + private void restorePopulatingChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int p_76624_3_, int p_76624_4_, CallbackInfo ci) { + arch$populatingChunk.pop(); + } + +} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderHell.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderHell.java new file mode 100644 index 000000000..c890f5e51 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderHell.java @@ -0,0 +1,20 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.world.World; +import net.minecraft.world.gen.ChunkProviderHell; +import net.minecraft.world.gen.feature.WorldGenHellLava; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Random; + +@Mixin(ChunkProviderHell.class) +public class MixinChunkProviderHell { + @Redirect(method = "populate", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/gen/feature/WorldGenHellLava;generate(Lnet/minecraft/world/World;Ljava/util/Random;III)Z", ordinal = 1)) + private boolean applyOffsetIfConfigured(WorldGenHellLava gen, World world, Random random, int x, int y, int z) { + int offset = ArchaicConfig.fixVanillaCascadingWorldgen ? 8 : 0; + return gen.generate(world, random, x + offset, y, z + offset); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderServer.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderServer.java new file mode 100644 index 000000000..2dbcdde6a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderServer.java @@ -0,0 +1,43 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.world.WorldServer; +import net.minecraft.world.biome.WorldChunkManager; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.gen.ChunkProviderServer; +import net.minecraftforge.common.DimensionManager; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Mixin(ChunkProviderServer.class) +public abstract class MixinChunkProviderServer { + + @Shadow public WorldServer worldObj; + + @Redirect(method = "unloadChunksIfNotNearSpawn", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/common/DimensionManager;shouldLoadSpawn(I)Z", remap = false)) + private boolean neverLoadSpawn(int dim) { + return !ArchaicConfig.disableSpawnChunks && DimensionManager.shouldLoadSpawn(dim); + } + + @Redirect(method = "originalLoadChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/IChunkProvider;provideChunk(II)Lnet/minecraft/world/chunk/Chunk;", remap = true), remap = false) + private Chunk populateChunkWithBiomes(IChunkProvider instance, int chunkX, int chunkZ) { + Chunk chunk = instance.provideChunk(chunkX, chunkZ); + if(chunk != null) { + WorldChunkManager manager = chunk.worldObj.getWorldChunkManager(); + for(int z = 0; z < 16; z++) { + for(int x = 0; x < 16; x++) { + chunk.getBiomeGenForWorldCoords(x, z, manager); + } + } + } + return chunk; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEmbeddedChannel.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEmbeddedChannel.java new file mode 100644 index 000000000..8003eaeab --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEmbeddedChannel.java @@ -0,0 +1,116 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import io.netty.channel.*; +import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.util.ReferenceCountUtil; +import io.netty.util.internal.PlatformDependent; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.nio.channels.ClosedChannelException; +import java.util.AbstractMap; +import java.util.ArrayDeque; +import java.util.Queue; + +@Mixin(EmbeddedChannel.class) +public abstract class MixinEmbeddedChannel extends AbstractChannel { + protected MixinEmbeddedChannel(Channel parent) { + super(parent); + } + + @Shadow public abstract ChannelConfig config(); + + @Shadow private Throwable lastException; + /** + * Used to simulate socket buffers. When autoRead is false, all inbound information will be temporarily stored here. + */ + private Queue> tempInboundMessages; + + private Queue> tempInboundMessages() { + if (tempInboundMessages == null) { + tempInboundMessages = new ArrayDeque<>(); + } + return tempInboundMessages; + } + + @Inject(method = "writeInbound", at = @At(value = "INVOKE", target = "Lio/netty/channel/embedded/EmbeddedChannel;pipeline()Lio/netty/channel/ChannelPipeline;"), cancellable = true, remap = false) + private void storeMsgs(Object[] msgs, CallbackInfoReturnable cir) { + if (!config().isAutoRead()) { + Queue> tempInboundMessages = tempInboundMessages(); + for (Object msg : msgs) { + tempInboundMessages.add(new AbstractMap.SimpleEntry<>(msg, null)); + } + cir.setReturnValue(false); + } + } + + private static boolean isNotEmpty(Queue queue) { + return queue != null && !queue.isEmpty(); + } + + @Inject(method = "doClose", at = @At("RETURN"), remap = false) + private void handleInboundClosing(CallbackInfo ci) { + if (isNotEmpty(tempInboundMessages)) { + ClosedChannelException exception = null; + for (;;) { + AbstractMap.SimpleEntry entry = tempInboundMessages.poll(); + if (entry == null) { + break; + } + Object value = entry.getKey(); + if (value != null) { + ReferenceCountUtil.release(value); + } + ChannelPromise promise = entry.getValue(); + if (promise != null) { + if (exception == null) { + exception = new ClosedChannelException(); + } + promise.tryFailure(exception); + } + } + } + } + + private ChannelFuture checkException(ChannelPromise promise) { + Throwable t = lastException; + if (t != null) { + lastException = null; + + return promise.setFailure(t); + } + + return promise.setSuccess(); + } + + @Inject(method = "doBeginRead", at = @At("HEAD"), remap = false) + private void readTmpInbounds(CallbackInfo ci) { + // read from tempInboundMessages and fire channelRead. + if (isNotEmpty(tempInboundMessages)) { + for (;;) { + AbstractMap.SimpleEntry pair = tempInboundMessages.poll(); + if (pair == null) { + break; + } + + Object msg = pair.getKey(); + if (msg != null) { + pipeline().fireChannelRead(msg); + } + + ChannelPromise promise = pair.getValue(); + if (promise != null) { + checkException(promise); + } + } + + // fire channelReadComplete. + flush(); + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEnchantmentHelper.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEnchantmentHelper.java new file mode 100644 index 000000000..a1a766760 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEnchantmentHelper.java @@ -0,0 +1,40 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(EnchantmentHelper.class) +public class MixinEnchantmentHelper { + @Shadow @Final private static EnchantmentHelper.ModifierDamage enchantmentModifierDamage; + + @Shadow @Final private static EnchantmentHelper.HurtIterator field_151388_d; + + @Shadow @Final private static EnchantmentHelper.DamageIterator field_151389_e; + + @Inject(method = "getEnchantmentModifierDamage", at = @At("RETURN")) + private static void clearWorldReference1(ItemStack[] p_77508_0_, DamageSource p_77508_1_, CallbackInfoReturnable cir) { + enchantmentModifierDamage.source = null; + } + + @Inject(method = "func_151384_a", at = @At("RETURN")) + private static void clearWorldReference2(EntityLivingBase p_151384_0_, Entity p_151384_1_, CallbackInfo ci) { + field_151388_d.field_151363_b = null; + field_151388_d.field_151364_a = null; + } + + @Inject(method = "func_151385_b", at = @At("RETURN")) + private static void clearWorldReference3(EntityLivingBase p_151385_0_, Entity p_151385_1_, CallbackInfo ci) { + field_151389_e.field_151366_a = null; + field_151389_e.field_151365_b = null; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntity.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntity.java new file mode 100644 index 000000000..e3af7f62c --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntity.java @@ -0,0 +1,23 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Entity.class) +public abstract class MixinEntity { + @Shadow public float fallDistance; + + /** + * @reason Fixes a vanilla bug where the entity's fall distance is not updated before invoking the + * block's onFallenUpon when it falls on the ground, meaning that the last fall state update won't + * be included in the fall distance. + */ + @Inject(method = "updateFallState", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;fall(F)V")) + private void beforeOnFallenUpon(double distanceFallenThisTick, boolean isOnGround, CallbackInfo ci) { + if (distanceFallenThisTick < 0) fallDistance -= distanceFallenThisTick; + } +} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityItem.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityItem.java new file mode 100644 index 000000000..eca548f03 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityItem.java @@ -0,0 +1,55 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.world.World; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityItem.class) +public abstract class MixinEntityItem extends Entity { + @Shadow public int age; + + private double arch$oldMotionX, arch$oldMotionY, arch$oldMotionZ; + + private boolean arch$movedThisTick; + + public MixinEntityItem(World p_i1582_1_) { + super(p_i1582_1_); + } + + private boolean arch$shouldItemMove() { + if(!this.onGround) + return true; + double horzMotion = this.motionX * this.motionX + this.motionZ * this.motionZ; + if(horzMotion > 1.0e-5f) + return true; + return (this.age + this.getEntityId()) % 4 == 0; + } + + @Redirect(method = "onUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/item/EntityItem;moveEntity(DDD)V", ordinal = 0)) + private void moveIfNecessary(EntityItem item, double x, double y, double z) { + arch$movedThisTick = arch$shouldItemMove(); + if(arch$movedThisTick) + item.moveEntity(x, y, z); + else { + arch$oldMotionX = item.motionX; + arch$oldMotionY = item.motionY; + arch$oldMotionZ = item.motionZ; + } + } + + @Inject(method = "onUpdate", at = @At(value = "FIELD", target = "Lnet/minecraft/entity/item/EntityItem;age:I", opcode = Opcodes.PUTFIELD)) + private void restoreVelocityIfNotMoving(CallbackInfo ci) { + if(!arch$movedThisTick) { + this.motionX = arch$oldMotionX; + this.motionY = arch$oldMotionY; + this.motionZ = arch$oldMotionZ; + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityLiving.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityLiving.java new file mode 100644 index 000000000..860dce8cd --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityLiving.java @@ -0,0 +1,102 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityLiving.class) +public abstract class MixinEntityLiving extends EntityLivingBase { + @Shadow public static Item getArmorItemForSlot(int p_82161_0_, int p_82161_1_) { + throw new AssertionError(); + } + + @Shadow public abstract ItemStack func_130225_q(int p_130225_1_); + + @Shadow protected float[] equipmentDropChances; + + public MixinEntityLiving(World p_i1594_1_) { + super(p_i1594_1_); + } + + @ModifyConstant(method = "despawnEntity", constant = @Constant(doubleValue = 16384.0D)) + private double lowerHardRange(double old) { + if(!ArchaicConfig.fixMobSpawnsAtLowRenderDist) + return old; + if(worldObj.isRemote) + return old; + if(((WorldServer)worldObj).func_73046_m().getConfigurationManager().getViewDistance() < 10) + return 96 * 96; + return old; + } + + /** + * @reason Higher armor chances (from TMCW). + * @author embeddedt + */ + @Inject(method = "addRandomArmor", at = @At("HEAD"), cancellable = true) + public void addRandomArmor(CallbackInfo ci) + { + if(!ArchaicConfig.increaseMobArmor) + return; + float var1 = this.worldObj.func_147462_b(this.posX, this.posY, this.posZ); + + if (this.rand.nextFloat() < var1 * 0.2F) + { + float var2 = 0.4F / (var1 * 2.0F + 1.0F); + int var3 = this.rand.nextInt(2); + + if (this.rand.nextFloat() < 0.2F) + { + ++var3; + } + + if (this.rand.nextFloat() < 0.2F) + { + ++var3; + } + + if (this.rand.nextFloat() < 0.2F) + { + ++var3; + } + + for (int var4 = 3; var4 >= 0; --var4) + { + ItemStack var5 = this.func_130225_q(var4); + + if (var4 < 3 && this.rand.nextFloat() < var2) + { + break; + } + + if (var5 == null) + { + Item var6 = getArmorItemForSlot(var4 + 1, var3); + + if (var6 != null) + { + this.setCurrentItemOrArmor(var4 + 1, new ItemStack(var6)); + + if (var3 == 5) + { + this.equipmentDropChances[var4 + 1] = 0.1F; + } + } + } + } + } + ci.cancel(); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityPlayerMP.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityPlayerMP.java new file mode 100644 index 000000000..32a28df44 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityPlayerMP.java @@ -0,0 +1,33 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import com.mojang.authlib.GameProfile; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.management.ItemInWorldManager; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityPlayerMP.class) +public abstract class MixinEntityPlayerMP extends EntityPlayer { + + public MixinEntityPlayerMP(World worldIn, GameProfile gameProfileIn) {super(worldIn, gameProfileIn);} + + /** + * @reason This is incorrectly set to 1, but not noticable in vanilla since the move logic + * trusts the client about its y position after a move due to a bug: (y > -0.5 || y + * < 0.5) rather than &&. If this is fixed, a player standing in moving water at the + * edge of a block is considered to have "moved wrongly" and teleported onto the block. + *

+ * Leaving this to 1 would also allow hacked clients to step up blocks without having + * to jump (not increasing hunger). + */ + @Inject(method = "", at = @At("RETURN")) + private void afterInit(MinecraftServer server, WorldServer worldIn, GameProfile profile, ItemInWorldManager interactionManagerIn, CallbackInfo ci) { + stepHeight = 0.7F; + } +} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityTrackerEntry.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityTrackerEntry.java new file mode 100644 index 000000000..3875d6a91 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityTrackerEntry.java @@ -0,0 +1,80 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLeashKnot; +import net.minecraft.entity.EntityTrackerEntry; +import net.minecraft.entity.item.EntityItemFrame; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.*; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.List; + +@Mixin(EntityTrackerEntry.class) +public class MixinEntityTrackerEntry { + @Shadow public int lastScaledXPosition, lastScaledYPosition, lastScaledZPosition; + + @Shadow public int lastYaw; + + @Shadow public int lastPitch; + + @Shadow public Entity myEntity; + + @Shadow public int ticks; + + @Inject(method = "sendLocationToAllClients", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/EntityTrackerEntry;sendMetadataToAllAssociatedPlayers()V", ordinal = 1, shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD) + private void saveIfTeleported(List clientList, CallbackInfo ci, int i, int j, int k, int l, int i1, int j1, int k1, int l1, Object object) { + if(object instanceof S18PacketEntityTeleport) { + this.lastScaledXPosition = i; + this.lastScaledYPosition = j; + this.lastScaledZPosition = k; + this.lastYaw = l; + this.lastPitch = i1; + } + } + + @Inject(method = "func_151260_c", at = @At("RETURN"), cancellable = true) + private void useCorrectSpawnPosition(CallbackInfoReturnable cir) { + if (!(this.myEntity instanceof EntityItemFrame) && !(this.myEntity instanceof EntityLeashKnot)) { + Packet packet = cir.getReturnValue(); + if(packet instanceof S0EPacketSpawnObject) { + S0EPacketSpawnObject spawnObject = (S0EPacketSpawnObject)packet; + spawnObject.func_148996_a(this.lastScaledXPosition); + spawnObject.func_148995_b(this.lastScaledYPosition); + spawnObject.func_149005_c(this.lastScaledZPosition); + } else if(packet instanceof S0CPacketSpawnPlayer) { + S0CPacketSpawnPlayer spawnPlayer = (S0CPacketSpawnPlayer)packet; + spawnPlayer.field_148956_c = this.lastScaledXPosition; + spawnPlayer.field_148953_d = this.lastScaledYPosition; + spawnPlayer.field_148954_e = this.lastScaledZPosition; + } else if(packet instanceof S11PacketSpawnExperienceOrb) { + S11PacketSpawnExperienceOrb spawnXpOrb = (S11PacketSpawnExperienceOrb)packet; + spawnXpOrb.field_148990_b = this.lastScaledXPosition; + spawnXpOrb.field_148991_c = this.lastScaledYPosition; + spawnXpOrb.field_148988_d = this.lastScaledZPosition; + } + } + } + + private boolean arch$wouldSendPacket() { + return (this.ticks > 0 || this.myEntity instanceof EntityArrow); + } + + @ModifyVariable(method = "sendLocationToAllClients", at = @At("STORE"), index = 11, name = "flag") + private boolean avoidSavingIfPacketNotSent1(boolean incoming) { + return incoming && arch$wouldSendPacket(); + } + + @ModifyVariable(method = "sendLocationToAllClients", at = @At("STORE"), index = 12, name = "flag1") + private boolean avoidSavingIfPacketNotSent2(boolean incoming) { + return incoming && arch$wouldSendPacket(); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityVillager.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityVillager.java new file mode 100644 index 000000000..aed1415d7 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityVillager.java @@ -0,0 +1,40 @@ +package org.embeddedt.archaicfix.mixins.common.core; + + +import net.minecraft.entity.passive.EntityVillager; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.village.MerchantRecipe; +import net.minecraft.village.MerchantRecipeList; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityVillager.class) +public class MixinEntityVillager { + @Shadow private MerchantRecipeList buyingList; + + @Shadow private int timeUntilReset; + + @Shadow private boolean needsInitilization; + + @Inject(method = "readEntityFromNBT", at = @At("TAIL")) + private void handleLockedVillager(NBTTagCompound compound, CallbackInfo ci) { + if(compound.hasKey("archTimeToReset")) { + this.timeUntilReset = compound.getInteger("archTimeToReset"); + this.needsInitilization = this.timeUntilReset > 0; + } else if(this.buyingList != null) { + // FIX: Robustness, and fixes accumulated bugged merchants: + if (((MerchantRecipe) this.buyingList.get(this.buyingList.size() - 1)).isRecipeDisabled()) { + this.timeUntilReset = 40; + this.needsInitilization = true; + } + } + } + + @Inject(method = "writeEntityToNBT", at = @At("TAIL")) + private void persistResetTime(NBTTagCompound compound, CallbackInfo ci) { + compound.setInteger("archTimeToReset", this.timeUntilReset); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityXPOrb.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityXPOrb.java new file mode 100644 index 000000000..12fb48bfa --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityXPOrb.java @@ -0,0 +1,14 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.entity.item.EntityXPOrb; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(EntityXPOrb.class) +public class MixinEntityXPOrb { + @ModifyConstant(method = "(Lnet/minecraft/world/World;DDDI)V", constant = @Constant(floatValue = 0.5f)) + private float useSmallerSizeAlways(float old) { + return 0.25f; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinForgeChunkManager.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinForgeChunkManager.java new file mode 100644 index 000000000..ec0ee71d4 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinForgeChunkManager.java @@ -0,0 +1,26 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import cpw.mods.fml.common.Loader; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraftforge.common.ForgeChunkManager; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.embeddedt.archaicfix.helpers.ChickenChunkHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ForgeChunkManager.class) +public class MixinForgeChunkManager { + @Inject(method = "loadWorld", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ArrayListMultimap;keySet()Ljava/util/Set;", ordinal = 0), cancellable = true, remap = false) + private static void callCCLoadHandler(World world, CallbackInfo ci) { + if(!world.isRemote && Loader.isModLoaded("ChickenChunks")) { + try { + ChickenChunkHelper.load((WorldServer)world); + } catch (Exception e) { + ArchaicLogger.LOGGER.error("An exception occured while loading CC data", e); + } + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinLongHashMap.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinLongHashMap.java new file mode 100644 index 000000000..6541b3246 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinLongHashMap.java @@ -0,0 +1,19 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.util.LongHashMap; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(LongHashMap.class) +public abstract class MixinLongHashMap { + /** + * @author embeddedt + * @reason Use a better hash (from TMCW) that avoids collisions. + */ + @Overwrite + private static int getHashedKey(long par0) + { + return (int)par0 + (int)(par0 >>> 32) * 92821; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMapGenStructure.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMapGenStructure.java new file mode 100644 index 000000000..6a7a3a6e4 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMapGenStructure.java @@ -0,0 +1,26 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import com.google.common.collect.ImmutableList; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.MapGenStructure; +import net.minecraft.world.gen.structure.StructureBoundingBox; +import net.minecraft.world.gen.structure.StructureStart; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +@Mixin(MapGenStructure.class) +public abstract class MixinMapGenStructure { + + @Redirect(method = { "func_143028_c", "func_142038_b", "func_151545_a", "generateStructuresInChunk" }, at = @At(value = "INVOKE", target = "Ljava/util/Map;values()Ljava/util/Collection;")) + private Collection getStructureMapValues(Map structureMap) { + return ImmutableList.copyOf(structureMap.values()); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMaterialLiquid.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMaterialLiquid.java new file mode 100644 index 000000000..411057068 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMaterialLiquid.java @@ -0,0 +1,18 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.block.material.MapColor; +import net.minecraft.block.material.Material; +import net.minecraft.block.material.MaterialLiquid; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(MaterialLiquid.class) +public abstract class MixinMaterialLiquid extends Material { + public MixinMaterialLiquid(MapColor p_i2116_1_) { + super(p_i2116_1_); + } + + @Override + public boolean getCanBlockGrass() { + return false; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMerchantRecipe.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMerchantRecipe.java new file mode 100644 index 000000000..ae0ffca89 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMerchantRecipe.java @@ -0,0 +1,24 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.item.ItemStack; +import net.minecraft.village.MerchantRecipe; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(MerchantRecipe.class) +public class MixinMerchantRecipe { + @Shadow private ItemStack itemToBuy; + + @Shadow private ItemStack secondItemToBuy; + + @Inject(method = "(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;)V", at = @At("RETURN")) + private void capItemAmounts(ItemStack p_i1941_1_, ItemStack p_i1941_2_, ItemStack p_i1941_3_, CallbackInfo ci) { + if(this.itemToBuy != null) + this.itemToBuy.stackSize = Math.min(this.itemToBuy.stackSize, this.itemToBuy.getMaxStackSize()); + if(this.secondItemToBuy != null) + this.secondItemToBuy.stackSize = Math.min(this.secondItemToBuy.stackSize, this.secondItemToBuy.getMaxStackSize()); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinModCandidate.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinModCandidate.java new file mode 100644 index 000000000..fc7186399 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinModCandidate.java @@ -0,0 +1,56 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import cpw.mods.fml.common.discovery.ASMDataTable; +import cpw.mods.fml.common.discovery.ModCandidate; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import speiger.src.collections.objects.sets.ObjectOpenHashSet; +import zone.rong.rongasm.api.LoliStringPool; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/* based on LoliASM */ +@Mixin(ModCandidate.class) +public class MixinModCandidate { + @Shadow(remap = false) private List packages; + @Shadow(remap = false) private Set foundClasses; + @Shadow(remap = false) private ASMDataTable table; + private Set packageSet; + + @Redirect(method = "(Ljava/io/File;Ljava/io/File;Lcpw/mods/fml/common/discovery/ContainerType;ZZ)V", at = @At(value = "FIELD", target = "Lcpw/mods/fml/common/discovery/ModCandidate;packages:Ljava/util/List;", remap = false), remap = false) + private void avoidPackageList(ModCandidate instance, List value) { + this.packages = null; + packageSet = new ObjectOpenHashSet<>(); + } + + /** + * @author embeddedt + * @reason more efficient storage + */ + @Overwrite(remap = false) + public void addClassEntry(String name) { + String className = name.substring(0, name.lastIndexOf('.')); + this.foundClasses.add(className); + className = className.replace('/','.'); + int pkgIdx = className.lastIndexOf('.'); + if (pkgIdx > -1) { + String pkg = LoliStringPool.canonicalize(className.substring(0, pkgIdx)); + packageSet.add(pkg); + table.registerPackage((ModCandidate)(Object)this, pkg); + } + } + + /** + * @author embeddedt + * @reason avoid storing packages as a list + */ + @Overwrite(remap = false) + public List getContainedPackages() { + return new ArrayList<>(packageSet); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetHandlerPlayServer.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetHandlerPlayServer.java new file mode 100644 index 000000000..bc34f7478 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetHandlerPlayServer.java @@ -0,0 +1,18 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.network.NetHandlerPlayServer; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(NetHandlerPlayServer.class) +public class MixinNetHandlerPlayServer { + @ModifyArg(method = "processPlayerBlockPlacement", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/EntityPlayerMP;getDistanceSq(DDD)D", ordinal = 0), index = 1) + private double adjustForEyeHeight(double y) { + if(ArchaicConfig.fixPlacementFlicker) + return y - 1.5; + else + return y; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkDispatcher.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkDispatcher.java new file mode 100644 index 000000000..5b69f9038 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkDispatcher.java @@ -0,0 +1,37 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import cpw.mods.fml.common.network.handshake.NetworkDispatcher; +import cpw.mods.fml.relauncher.Side; +import io.netty.channel.ChannelConfig; +import net.minecraft.network.EnumConnectionState; +import net.minecraft.network.NetworkManager; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.embeddedt.archaicfix.ducks.IArchaicNetworkManager; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(NetworkDispatcher.class) +public class MixinNetworkDispatcher { + @Shadow @Final private Side side; + + @Redirect(method = "clientListenForServerHandshake", at = @At(value = "INVOKE", remap = true, target = + "Lnet/minecraft/network/NetworkManager;setConnectionState(Lnet/minecraft/network/EnumConnectionState;)V")) + public void archaic_raceConditionWorkAround1(NetworkManager self, EnumConnectionState state) { + if(ArchaicConfig.fixLoginRaceCondition) + ((IArchaicNetworkManager)self).setConnectionStateWithoutAutoRead(state); + else + self.setConnectionState(state); + } + + @Redirect(method = "handlerAdded", at = @At(value = "INVOKE", target = + "Lio/netty/channel/ChannelConfig;setAutoRead(Z)Lio/netty/channel/ChannelConfig;"), remap = false) + public ChannelConfig archaic_raceConditionWorkAround2(ChannelConfig self, boolean autoRead) { + if (ArchaicConfig.fixLoginRaceCondition && side == Side.CLIENT) { + autoRead = false; + } + return self.setAutoRead(autoRead); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkManager.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkManager.java new file mode 100644 index 000000000..7c520bab0 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkManager.java @@ -0,0 +1,27 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import io.netty.channel.Channel; +import io.netty.util.AttributeKey; +import net.minecraft.network.EnumConnectionState; +import net.minecraft.network.NetworkManager; +import org.embeddedt.archaicfix.ducks.IArchaicNetworkManager; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(NetworkManager.class) +public class MixinNetworkManager implements IArchaicNetworkManager { + + @Shadow private EnumConnectionState connectionState; + + @Shadow private Channel channel; + + @Shadow @Final private boolean isClientSide; + + @Override + public void setConnectionStateWithoutAutoRead(EnumConnectionState state) { + this.connectionState = (EnumConnectionState)this.channel.attr(NetworkManager.attrKeyConnectionState).getAndSet(state); + this.channel.attr(NetworkManager.attrKeyReceivable).set(state.func_150757_a(this.isClientSide)); + this.channel.attr(NetworkManager.attrKeySendable).set(state.func_150754_b(this.isClientSide)); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNextTickListEntry.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNextTickListEntry.java new file mode 100644 index 000000000..3b58110c6 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNextTickListEntry.java @@ -0,0 +1,39 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.block.Block; +import net.minecraft.world.NextTickListEntry; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(NextTickListEntry.class) +public class MixinNextTickListEntry { + @Shadow public int xCoord; + + @Shadow public int yCoord; + + @Shadow public int zCoord; + + @Shadow @Final private Block field_151352_g; + + @Inject(method = "compareTo(Lnet/minecraft/world/NextTickListEntry;)I", at = @At("RETURN")) + private void considerCoordinatesForEquality(NextTickListEntry other, CallbackInfoReturnable cir) { + if(ArchaicConfig.fixTickListSynchronization && cir.getReturnValue() == 0) { + int myCoords = this.xCoord + this.yCoord + this.zCoord; + int theirCoords = other.xCoord + other.yCoord + other.zCoord; + int diff = theirCoords - myCoords; + if(diff != 0) + cir.setReturnValue(diff); + else { + Block b1 = other.func_151351_a(); + Block b2 = this.field_151352_g; + if(b1 != b2) + cir.setReturnValue(Block.getIdFromBlock(b1) - Block.getIdFromBlock(b2)); + } + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinObjectIntIdentityMap.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinObjectIntIdentityMap.java new file mode 100644 index 000000000..57b566272 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinObjectIntIdentityMap.java @@ -0,0 +1,35 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.util.ObjectIntIdentityMap; +import org.embeddedt.archaicfix.helpers.UnexpectionalObjectArrayList; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; + +@SuppressWarnings("rawtypes") +@Mixin(ObjectIntIdentityMap.class) +public class MixinObjectIntIdentityMap { + + @Shadow protected List field_148748_b; + + @Inject(method = "", at = @At("RETURN")) + private void initIdArray(CallbackInfo ci) { + this.field_148748_b = new UnexpectionalObjectArrayList(); + } + + /** + * @author embeddedt + * @reason Avoid unnecessary range checks + * @param id ID + * @return object if ID is valid, else null + */ + @Overwrite + public Object func_148745_a(int id) { + return ((UnexpectionalObjectArrayList)field_148748_b).getOrNull(id); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinOreDictionary.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinOreDictionary.java new file mode 100644 index 000000000..2e1dd9b0d --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinOreDictionary.java @@ -0,0 +1,41 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.ArrayList; + +@Mixin(OreDictionary.class) +public class MixinOreDictionary { + /* + @Redirect(method = "registerOreImpl", at = @At(value = "INVOKE", target = "Ljava/util/ArrayList;add(Ljava/lang/Object;)Z"), remap = false) + private static boolean addOreSorted(ArrayList list, Object o) { + ItemStack stack = (ItemStack)o; + int low = 0; + int high = list.size() - 1; + int targetId = Item.getIdFromItem(stack.getItem()); + Integer finalIndex = null; + while(low <= high) { + int mid = (low + high) / 2; + ItemStack option = list.get(mid); + int id = Item.getIdFromItem(option.getItem()); + if(id < targetId) + low = mid + 1; + else if(id > targetId) + high = mid - 1; + else { + finalIndex = mid; + break; + } + } + if(finalIndex == null) + finalIndex = low; + list.add(finalIndex, stack); + return true; + } + */ +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedOreRecipe.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedOreRecipe.java new file mode 100644 index 000000000..a258c51ba --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedOreRecipe.java @@ -0,0 +1,55 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import com.google.common.collect.ImmutableSet; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.ShapedOreRecipe; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.embeddedt.archaicfix.FixHelper; +import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.*; + +/** + * Enhances ShapedOreRecipe to support recipe acceleration. This benefits a lot of mods which make use of this class + * or a subclass. + */ +@Mixin(ShapedOreRecipe.class) +public class MixinShapedOreRecipe implements IAcceleratedRecipe { + @Shadow(remap = false) private Object[] input; + private Set allPossibleInputs = null; + + private void genMatchCache() { + ImmutableSet.Builder builder = ImmutableSet.builder(); + for(Object o : input) { + if(o instanceof ItemStack) { + if(((ItemStack)o).getItem() != null) + builder.add(((ItemStack) o).getItem()); + } else if(o instanceof ArrayList) { + for(ItemStack stack : ((ArrayList)o)) { + if(stack.getItem() != null) + builder.add(stack.getItem()); + } + } else if(o != null) { + ArchaicLogger.LOGGER.warn("Couldn't optimize input value: " + o); + return; + } + } + allPossibleInputs = builder.build(); + FixHelper.recipesHoldingPotentialItems.add(this); + } + + @Override + public Set getPotentialItems() { + if(allPossibleInputs == null) + genMatchCache(); + return allPossibleInputs; + } + + @Override + public void invalidatePotentialItems() { + allPossibleInputs = null; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedRecipes.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedRecipes.java new file mode 100644 index 000000000..ec0d29962 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedRecipes.java @@ -0,0 +1,36 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import com.google.common.collect.ImmutableSet; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.ShapedRecipes; +import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Set; + +@Mixin(ShapedRecipes.class) +public class MixinShapedRecipes implements IAcceleratedRecipe { + private Set allPossibleItems; + @Inject(method = "", at = @At("RETURN")) + private void collectItems(int w, int h, ItemStack[] stacks, ItemStack out, CallbackInfo ci) { + ImmutableSet.Builder builder = ImmutableSet.builder(); + for(ItemStack stack : stacks) { + if(stack != null && stack.getItem() != null) + builder.add(stack.getItem()); + } + allPossibleItems = builder.build(); + } + @Override + public Set getPotentialItems() { + return allPossibleItems; + } + + @Override + public void invalidatePotentialItems() { + /* No-op, the set of items is fixed for this recipe */ + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessOreRecipe.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessOreRecipe.java new file mode 100644 index 000000000..2671e2c24 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessOreRecipe.java @@ -0,0 +1,52 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import com.google.common.collect.ImmutableSet; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.ShapelessOreRecipe; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.embeddedt.archaicfix.FixHelper; +import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.ArrayList; +import java.util.Set; + +@Mixin(ShapelessOreRecipe.class) +public class MixinShapelessOreRecipe implements IAcceleratedRecipe { + @Shadow(remap = false) private ArrayList input; + private Set allPossibleInputs = null; + + private void genMatchCache() { + allPossibleInputs = null; + ImmutableSet.Builder builder = ImmutableSet.builder(); + for(Object o : input) { + if(o instanceof ItemStack) { + if(((ItemStack)o).getItem() != null) + builder.add(((ItemStack) o).getItem()); + } else if(o instanceof ArrayList) { + for(ItemStack stack : ((ArrayList)o)) { + if(stack.getItem() != null) + builder.add(stack.getItem()); + } + } else if(o != null) { + ArchaicLogger.LOGGER.warn("Couldn't optimize input value: " + o); + return; + } + } + allPossibleInputs = builder.build(); + FixHelper.recipesHoldingPotentialItems.add(this); + } + + @Override + public Set getPotentialItems() { + if(allPossibleInputs == null) + genMatchCache(); + return allPossibleInputs; + } + + public void invalidatePotentialItems() { + allPossibleInputs = null; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessRecipes.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessRecipes.java new file mode 100644 index 000000000..f51e7570c --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessRecipes.java @@ -0,0 +1,44 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import com.google.common.collect.ImmutableSet; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.ShapelessRecipes; +import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; +import java.util.Set; + +@Mixin(ShapelessRecipes.class) +public class MixinShapelessRecipes implements IAcceleratedRecipe { + @Shadow @Final public List recipeItems; + + private Set allPossibleItems; + + @Inject(method = "", at = @At("RETURN")) + public void buildItemCache(ItemStack p_i1918_1_, List p_i1918_2_, CallbackInfo ci) + { + ImmutableSet.Builder builder = ImmutableSet.builder(); + for(Object stack : recipeItems) { + if(stack != null && ((ItemStack)stack).getItem() != null) + builder.add(((ItemStack)stack).getItem()); + } + allPossibleItems = builder.build(); + } + + @Override + public Set getPotentialItems() { + return allPossibleItems; + } + + @Override + public void invalidatePotentialItems() { + /* No-op, fixed set of items */ + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinSpawnerAnimals.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinSpawnerAnimals.java new file mode 100644 index 000000000..a0c3d8474 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinSpawnerAnimals.java @@ -0,0 +1,37 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.SpawnerAnimals; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.IChunkProvider; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngineHelpers; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.HashMap; +import java.util.Iterator; + +@Mixin(SpawnerAnimals.class) +public class MixinSpawnerAnimals { + @Shadow private HashMap eligibleChunksForSpawning; + + @ModifyConstant(method = "findChunksForSpawning", constant = @Constant(doubleValue = 24.0D)) + private double lowerSpawnRange(double old) { + return ArchaicConfig.fixMobSpawnsAtLowRenderDist ? 16 : old; + } + + @Redirect(method = "performWorldGenSpawning", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;spawnEntityInWorld(Lnet/minecraft/entity/Entity;)Z")) + private static boolean checkForCollision(World world, Entity instance) { + if(!ArchaicConfig.preventEntitySuffocationWorldgen || world.getCollidingBoundingBoxes(instance, instance.boundingBox).isEmpty()) { + return world.spawnEntityInWorld(instance); + } + return false; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinStructureStart.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinStructureStart.java new file mode 100644 index 000000000..b48081314 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinStructureStart.java @@ -0,0 +1,21 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.StructureBoundingBox; +import net.minecraft.world.gen.structure.StructureComponent; +import net.minecraft.world.gen.structure.StructureStart; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.LinkedList; +import java.util.Random; + +@Mixin(StructureStart.class) +public class MixinStructureStart { + @Redirect(method = "generateStructure", at = @At(value = "FIELD", target = "Lnet/minecraft/world/gen/structure/StructureStart;components:Ljava/util/LinkedList;", ordinal = 0)) + private LinkedList debugStructureCME(StructureStart instance) { + return new LinkedList<>((LinkedList)instance.getComponents()); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorld.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorld.java new file mode 100644 index 000000000..07ec0be73 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorld.java @@ -0,0 +1,192 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import com.google.common.collect.ImmutableSet; +import cpw.mods.fml.common.FMLCommonHandler; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MathHelper; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.EnumDifficulty; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.biome.WorldChunkManager; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.storage.WorldInfo; +import net.minecraftforge.common.ForgeChunkManager; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.embeddedt.archaicfix.ducks.IArchaicWorld; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngineHelpers; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import speiger.src.collections.longs.collections.LongCollection; +import speiger.src.collections.longs.sets.LongOpenHashSet; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Mixin(World.class) +public abstract class MixinWorld implements IArchaicWorld { + @Shadow public boolean isRemote; + + @Shadow public EnumDifficulty difficultySetting; + + @Shadow public abstract float getCurrentMoonPhaseFactor(); + + @Shadow protected WorldInfo worldInfo; + + @Shadow public List playerEntities; + + @Shadow public abstract Chunk getChunkFromChunkCoords(int p_72964_1_, int p_72964_2_); + + @Shadow protected IChunkProvider chunkProvider; + + @Shadow public List loadedTileEntityList; + private LongCollection tileEntitiesChunkToBeRemoved = new LongOpenHashSet(); + + @Redirect(method = "getBiomeGenForCoordsBody", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/biome/WorldChunkManager;getBiomeGenAt(II)Lnet/minecraft/world/biome/BiomeGenBase;")) + private BiomeGenBase skipBiomeGenOnClient(WorldChunkManager manager, int x, int z) { + if(this.isRemote) + return BiomeGenBase.ocean; + else + return manager.getBiomeGenAt(x, z); + } + + /** + * @reason Remove regional difficulty and make it based on overall world time instead. (From TMCW) + * @author embeddedt + */ + @Inject(method = "func_147473_B", at = @At("HEAD"), cancellable = true) + public void func_147473_B(int p_147473_1_, int p_147473_2_, int p_147473_3_, CallbackInfoReturnable cir) { + if(!ArchaicConfig.betterRegionalDifficulty) + return; + float factor = this.worldInfo != null ? ((float)this.worldInfo.getWorldTotalTime() / 7200000.0F) : 0; + factor += this.getCurrentMoonPhaseFactor() * 0.25F; + + EnumDifficulty difficulty = this.difficultySetting; + if(difficulty == null) + difficulty = EnumDifficulty.NORMAL; + + if (difficulty == EnumDifficulty.EASY || difficulty == EnumDifficulty.PEACEFUL) + { + factor *= 0.5F; + } + else if (difficulty == EnumDifficulty.HARD) + { + factor *= 2.0F; + } + + cir.setReturnValue(MathHelper.clamp_float(factor, 0.0F, (float)difficulty.getDifficultyId() * 0.5F)); + } + + private Set entityOptimizationIgnoreSet = null; + + @Inject(method = "updateEntityWithOptionalForce", at = @At(value = "FIELD", target = "Lnet/minecraft/entity/Entity;lastTickPosX:D", ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) + private void skipUpdateIfOptimizing(Entity entity, boolean force, CallbackInfo ci, int chunkX, int chunkZ, boolean isInForcedChunk) { + if(!ArchaicConfig.optimizeEntityTicking) + return; + if (isRemote || isInForcedChunk || !(entity instanceof EntityLivingBase) || entity instanceof EntityPlayer || !entity.addedToChunk) { + return; + } + if(entityOptimizationIgnoreSet == null) + entityOptimizationIgnoreSet = ImmutableSet.copyOf(ArchaicConfig.optimizeEntityTickingIgnoreList); + if(entityOptimizationIgnoreSet.contains(EntityList.getEntityString(entity))) + return; + double finalDist = Double.MAX_VALUE; + for(EntityPlayer player : (List)entity.worldObj.playerEntities) { + finalDist = Math.min(finalDist, player.getDistanceSq(entity.posX, entity.posY, entity.posZ)); + if(finalDist <= ArchaicConfig.optimizeEntityTickingDistance) + break; + } + if(((EntityLivingBase)entity).deathTime <= 0 && finalDist > ArchaicConfig.optimizeEntityTickingDistance) { + if(entity instanceof EntityLiving && ((AccessorEntityLiving)entity).invokeCanDespawn()) { + /* Despawn even if outside the ticking range */ + ((AccessorEntityLiving)entity).invokeDespawnEntity(); + } + ci.cancel(); + } + } + + @Inject(method = "setActivePlayerChunksAndCheckLight", at = @At("TAIL")) + private void saveInactiveChunks(CallbackInfo ci) { + if(this.isRemote || ArchaicConfig.optimizeBlockTickingDistance <= 0) + return; + int renderDistance = FMLCommonHandler.instance().getMinecraftServerInstance().getConfigurationManager().getViewDistance(); + if(renderDistance <= ArchaicConfig.optimizeBlockTickingDistance) + return; + EntityPlayer entityplayer; + int j; + int k; + + int activeDistance = ArchaicConfig.optimizeBlockTickingDistance; + + for (int i = 0; i < this.playerEntities.size(); ++i) + { + entityplayer = (EntityPlayer)this.playerEntities.get(i); + j = MathHelper.floor_double(entityplayer.posX / 16.0D); + k = MathHelper.floor_double(entityplayer.posZ / 16.0D); + + for (int offX = -renderDistance; offX <= renderDistance; ++offX) + { + for (int offZ = -renderDistance; offZ <= renderDistance; ++offZ) + { + if(Math.abs(offX) <= activeDistance && Math.abs(offZ) <= activeDistance) + continue; + Chunk chunk = LightingEngineHelpers.getLoadedChunk(this.chunkProvider, offX + j, offZ + k); + if(chunk != null && !chunk.func_150802_k()) { + chunk.func_150804_b(false); + } + } + } + } + } + + @Override + public void arch$markTileEntitiesInChunkForRemoval(Chunk chunk) + { + if (!chunk.chunkTileEntityMap.isEmpty()) + { + long pos = ChunkCoordIntPair.chunkXZ2Int(chunk.xPosition, chunk.zPosition); + this.tileEntitiesChunkToBeRemoved.add(pos); + } + } + + @Inject(method = "updateEntities", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/world/World;field_147481_N:Z", ordinal = 1)) + private void removeInUnloaded(CallbackInfo ci) { + if (ArchaicConfig.fixTEUnloadLag && !this.tileEntitiesChunkToBeRemoved.isEmpty()) + { + java.util.function.Predicate isInChunk = (tileEntity) -> + { + long tileChunkPos = ChunkCoordIntPair.chunkXZ2Int(tileEntity.xCoord >> 4, tileEntity.zCoord >> 4); + return this.tileEntitiesChunkToBeRemoved.contains(tileChunkPos); + }; + java.util.function.Predicate isInChunkDoUnload = (tileEntity) -> + { + boolean inChunk = isInChunk.test(tileEntity); + if (inChunk) + { + tileEntity.onChunkUnload(); + } + return inChunk; + }; + this.loadedTileEntityList.removeIf(isInChunkDoUnload); + this.tileEntitiesChunkToBeRemoved.clear(); + } + } + + +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldChunkManager.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldChunkManager.java new file mode 100644 index 000000000..f468d4698 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldChunkManager.java @@ -0,0 +1,48 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeCache; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.biome.WorldChunkManager; +import net.minecraft.world.gen.layer.GenLayer; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(WorldChunkManager.class) +public class MixinWorldChunkManager { + @Shadow private BiomeCache biomeCache; + + @Shadow private GenLayer genBiomes; + + @Shadow private GenLayer biomeIndexLayer; + + private World clientWorld = null; + + @Inject(method = "(Lnet/minecraft/world/World;)V", at = @At("RETURN")) + private void noCacheOnClient(World world, CallbackInfo ci) { + if(world.isRemote) { + /* Make sure the client NEVER uses these */ + this.biomeCache = null; + this.genBiomes = null; + this.biomeIndexLayer = null; + clientWorld = world; + } + } + + @Inject(method = "getBiomeGenAt(II)Lnet/minecraft/world/biome/BiomeGenBase;", at = @At("HEAD"), cancellable = true) + private void safelyGetClientBiome(int x, int z, CallbackInfoReturnable cir) { + if(this.biomeCache == null) { + if(clientWorld != null) + cir.setReturnValue(clientWorld.getBiomeGenForCoords(x, z)); + else { + ArchaicLogger.LOGGER.warn("A mod attempted to retrieve a biome client-side via a WorldChunkManager without a client world reference. This is not safe. ArchaicFix has prevented a crash but some things may not work properly."); + cir.setReturnValue(BiomeGenBase.ocean); + } + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldServer.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldServer.java new file mode 100644 index 000000000..e6688567a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldServer.java @@ -0,0 +1,39 @@ +package org.embeddedt.archaicfix.mixins.common.core; + +import com.google.common.collect.Iterators; +import net.minecraft.profiler.Profiler; +import net.minecraft.world.*; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import net.minecraft.world.gen.ChunkProviderServer; +import net.minecraft.world.storage.ISaveHandler; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.Iterator; +import java.util.Set; + +@Mixin(WorldServer.class) +public abstract class MixinWorldServer extends World { + @Shadow public ChunkProviderServer theChunkProviderServer; + + public MixinWorldServer(ISaveHandler p_i45368_1_, String p_i45368_2_, WorldProvider p_i45368_3_, WorldSettings p_i45368_4_, Profiler p_i45368_5_) { + super(p_i45368_1_, p_i45368_2_, p_i45368_3_, p_i45368_4_, p_i45368_5_); + } + + @ModifyConstant(method = "tickUpdates", constant = @Constant(intValue = 1000), expect = 2, require = 0) + private int increaseUpdateLimit(int old) { + return ArchaicConfig.increaseBlockUpdateLimit ? 65000 : old; + } + + @Inject(method = "func_152379_p", at = @At("RETURN"), cancellable = true) + private void shortenBlockUpdateDistance(CallbackInfoReturnable cir) { + if(ArchaicConfig.optimizeBlockTickingDistance > 0) { + cir.setReturnValue(Math.min(cir.getReturnValue(), ArchaicConfig.optimizeBlockTickingDistance)); + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerServer.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerServer.java new file mode 100644 index 000000000..8e318fdb1 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerServer.java @@ -0,0 +1,22 @@ +package org.embeddedt.archaicfix.mixins.common.extrautils; + +import com.rwtema.extrautils.EventHandlerServer; +import net.minecraft.block.Block; +import net.minecraft.block.BlockEnchantmentTable; +import net.minecraft.init.Blocks; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(EventHandlerServer.class) +public class MixinEventHandlerServer { + @Redirect(method = "ActivationRitual", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getBlock(III)Lnet/minecraft/block/Block;", remap = true), remap = false) + private Block getSpecialBlock(World world, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + if(block instanceof BlockEnchantmentTable) + return Blocks.enchanting_table; + else + return block; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerSiege.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerSiege.java new file mode 100644 index 000000000..f0d992b0a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerSiege.java @@ -0,0 +1,15 @@ +package org.embeddedt.archaicfix.mixins.common.extrautils; + +import com.rwtema.extrautils.EventHandlerSiege; +import net.minecraft.tileentity.TileEntityBeacon; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = EventHandlerSiege.class, remap = false) +public class MixinEventHandlerSiege { + @Redirect(method = "golemDeath", at = @At(value = "INVOKE", target = "Ljava/lang/Object;equals(Ljava/lang/Object;)Z")) + private boolean checkSubclassofBeacon(Object subject, Object teBeaconClass) { + return ((Class)teBeaconClass).isAssignableFrom((Class)subject); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinItemDivisionSigil.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinItemDivisionSigil.java new file mode 100644 index 000000000..4366282a5 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinItemDivisionSigil.java @@ -0,0 +1,25 @@ +package org.embeddedt.archaicfix.mixins.common.extrautils; + +import com.rwtema.extrautils.item.ItemDivisionSigil; +import net.minecraft.block.Block; +import net.minecraft.block.BlockBeacon; +import net.minecraft.block.BlockEnchantmentTable; +import net.minecraft.init.Blocks; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ItemDivisionSigil.class) +public class MixinItemDivisionSigil { + @Redirect(method = "onItemUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getBlock(III)Lnet/minecraft/block/Block;")) + private Block checkIsSpecialBlock(World world, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + if(block instanceof BlockEnchantmentTable) + return Blocks.enchanting_table; + else if(block instanceof BlockBeacon) + return Blocks.beacon; + else + return block; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinTileEntityTrashCan.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinTileEntityTrashCan.java new file mode 100644 index 000000000..9cc5b4db2 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinTileEntityTrashCan.java @@ -0,0 +1,19 @@ +package org.embeddedt.archaicfix.mixins.common.extrautils; + +import com.rwtema.extrautils.tileentity.TileEntityTrashCan; +import net.minecraft.nbt.NBTTagCompound; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(TileEntityTrashCan.class) +public class MixinTileEntityTrashCan { + @Shadow(remap = false) private boolean added; + + @Inject(method = "readFromNBT", at = @At("TAIL"), remap = false) + private void forceRescan(NBTTagCompound par1NBTTagCompound, CallbackInfo ci) { + this.added = true; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinAnvilChunkLoader.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinAnvilChunkLoader.java new file mode 100644 index 000000000..e84f9c8b6 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinAnvilChunkLoader.java @@ -0,0 +1,53 @@ +package org.embeddedt.archaicfix.mixins.common.lighting; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.AnvilChunkLoader; +import org.embeddedt.archaicfix.lighting.api.IChunkLightingData; +import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(AnvilChunkLoader.class) +public abstract class MixinAnvilChunkLoader { + /** + * Injects into the head of saveChunk() to forcefully process all pending light updates. Fail-safe. + * + * @author Angeline + */ + @Inject(method = "saveChunk", at = @At("HEAD")) + private void onConstructed(World world, Chunk chunkIn, CallbackInfo callbackInfo) { + ((ILightingEngineProvider) world).getLightingEngine().processLightUpdates(); + } + + /** + * Injects the deserialization logic for chunk data on load so we can extract whether or not we've populated light yet. + * + * @author Angeline + */ + @Inject(method = "readChunkFromNBT", at = @At("RETURN")) + private void onReadChunkFromNBT(World world, NBTTagCompound compound, CallbackInfoReturnable cir) { + Chunk chunk = cir.getReturnValue(); + + LightingHooks.readNeighborLightChecksFromNBT(chunk, compound); + + ((IChunkLightingData) chunk).setLightInitialized(compound.getBoolean("LightPopulated")); + + } + + /** + * Injects the serialization logic for chunk data on save so we can store whether or not we've populated light yet. + * @author Angeline + */ + @Inject(method = "writeChunkToNBT", at = @At("RETURN")) + private void onWriteChunkToNBT(Chunk chunk, World world, NBTTagCompound compound, CallbackInfo ci) { + LightingHooks.writeNeighborLightChecksToNBT(chunk, compound); + + compound.setBoolean("LightPopulated", ((IChunkLightingData) chunk).isLightInitialized()); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunk.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunk.java new file mode 100644 index 000000000..5ea219cf6 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunk.java @@ -0,0 +1,398 @@ +package org.embeddedt.archaicfix.mixins.common.lighting; + +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import org.embeddedt.archaicfix.lighting.api.IChunkLighting; +import org.embeddedt.archaicfix.lighting.api.IChunkLightingData; +import org.embeddedt.archaicfix.lighting.api.ILightingEngine; +import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; +import org.embeddedt.archaicfix.lighting.world.WorldChunkSlice; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@SuppressWarnings("UnnecessaryQualifiedMemberReference") +@Mixin(value = Chunk.class) +public abstract class MixinChunk implements IChunkLighting, IChunkLightingData, ILightingEngineProvider { + private static final EnumFacing[] HORIZONTAL = LightingHooks.HORIZONTAL_FACINGS; + + /** + * Callback injected to the head of getLightSubtracted(BlockPos, int) to force deferred light updates to be processed. + * + * @author Angeline + */ + @Inject(method = "getBlockLightValue", at = @At("HEAD")) + private void onGetLightSubtracted(int x, int y, int z, int amount, CallbackInfoReturnable cir) { + this.getLightingEngine().processLightUpdates(); + } + + /** + * Callback injected at the end of onLoad() to have previously scheduled light updates scheduled again. + * + * @author Angeline + */ + @Inject(method = "onChunkLoad", at = @At("RETURN")) + private void onLoad(CallbackInfo ci) { + LightingHooks.scheduleRelightChecksForChunkBoundaries(this.worldObj, (Chunk) (Object) this); + } + + // === REPLACEMENTS === + + /** + * Replaces the call in setLightFor(Chunk, EnumSkyBlock, BlockPos) with our hook. + * + * @author Angeline + */ + @Redirect( + method = "setLightValue", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/chunk/Chunk;generateSkylightMap()V" + ), + expect = 0 + ) + private void setLightForRedirectGenerateSkylightMap(Chunk chunk, EnumSkyBlock type, int x, int y, int z, int value) { + LightingHooks.initSkylightForSection(this.worldObj, (Chunk) (Object) this, this.storageArrays[y >> 4]); + } + + private int getBlockLightOpacity(int x, int y, int z) { + return this.getBlock(x, y, z).getLightOpacity(this.worldObj, x, y, z); + } + + /** + * @reason Overwrites relightBlock with a more efficient implementation. + * @author Angeline + */ + @Overwrite + public void relightBlock(int x, int y, int z) { + int i = this.heightMap[z << 4 | x] & 255; + int j = i; + + if (y > i) { + j = y; + } + + while (j > 0 && this.getBlockLightOpacity(x, j - 1, z) == 0) { + --j; + } + + if (j != i) { + this.heightMap[z << 4 | x] = j; + + if (!this.worldObj.provider.hasNoSky) { + LightingHooks.relightSkylightColumn(this.worldObj, (Chunk) (Object) this, x, z, i, j); + } + + int l1 = this.heightMap[z << 4 | x]; + + if (l1 < this.heightMapMinimum) { + this.heightMapMinimum = l1; + } + } + } + + /** + * @reason Hook for calculating light updates only as needed. {@link MixinChunk#getCachedLightFor(EnumSkyBlock, int, int, int)} does not + * call this hook. + * + * @author Angeline + */ + @Overwrite + public int getSavedLightValue(EnumSkyBlock type, int x, int y, int z) { + getLightingEngine().processLightUpdatesForType(type); + + return this.getCachedLightFor(type, x, y, z); + } + + /** + * @reason Hooks into checkLight() to check chunk lighting and returns immediately after, voiding the rest of the function. + * + * @author Angeline + */ + @Overwrite + public void func_150809_p() { + this.isTerrainPopulated = true; + + LightingHooks.checkChunkLighting((Chunk) (Object) this, this.worldObj); + } + + /** + * @reason Optimized version of recheckGaps. Avoids chunk fetches as much as possible. + * + * @author Angeline + */ + @Overwrite + public void recheckGaps(boolean onlyOne) { + this.worldObj.theProfiler.startSection("recheckGaps"); + + WorldChunkSlice slice = new WorldChunkSlice(this.worldObj, this.xPosition, this.zPosition); + + if (this.worldObj.doChunksNearChunkExist(this.xPosition * 16 + 8, 0, this.zPosition * 16 + 8, 16)) { + for (int x = 0; x < 16; ++x) { + for (int z = 0; z < 16; ++z) { + if (this.recheckGapsForColumn(slice, x, z)) { + if (onlyOne) { + this.worldObj.theProfiler.endSection(); + + return; + } + } + } + } + + this.isGapLightingUpdated = false; + } + + this.worldObj.theProfiler.endSection(); + } + + private boolean recheckGapsForColumn(WorldChunkSlice slice, int x, int z) { + int i = x + z * 16; + + if (this.updateSkylightColumns[i]) { + this.updateSkylightColumns[i] = false; + + int height = this.getHeightValue(x, z); + + int x1 = this.xPosition * 16 + x; + int z1 = this.zPosition * 16 + z; + + int max = this.recheckGapsGetLowestHeight(slice, x1, z1); + + this.recheckGapsSkylightNeighborHeight(slice, x1, z1, height, max); + + return true; + } + + return false; + } + + private int recheckGapsGetLowestHeight(WorldChunkSlice slice, int x, int z) { + int max = Integer.MAX_VALUE; + + for (EnumFacing facing : HORIZONTAL) { + int j = x + facing.getFrontOffsetX(); + int k = z + facing.getFrontOffsetZ(); + + max = Math.min(max, slice.getChunkFromWorldCoords(j, k).heightMapMinimum); + } + + return max; + } + + private void recheckGapsSkylightNeighborHeight(WorldChunkSlice slice, int x, int z, int height, int max) { + this.checkSkylightNeighborHeight(slice, x, z, max); + + for (EnumFacing facing : HORIZONTAL) { + int j = x + facing.getFrontOffsetX(); + int k = z + facing.getFrontOffsetZ(); + + this.checkSkylightNeighborHeight(slice, j, k, height); + } + } + + private void checkSkylightNeighborHeight(WorldChunkSlice slice, int x, int z, int maxValue) { + int i = slice.getChunkFromWorldCoords(x, z).getHeightValue(x & 15, z & 15); + + if (i > maxValue) { + this.updateSkylightNeighborHeight(slice, x, z, maxValue, i + 1); + } else if (i < maxValue) { + this.updateSkylightNeighborHeight(slice, x, z, i, maxValue + 1); + } + } + + private void updateSkylightNeighborHeight(WorldChunkSlice slice, int x, int z, int startY, int endY) { + if (endY > startY) { + if (!slice.isLoaded(x, z, 16)) { + return; + } + + for (int i = startY; i < endY; ++i) { + this.worldObj.updateLightByType(EnumSkyBlock.Sky, x, i, z); + } + + this.isModified = true; + } + } + + /** + * @author embeddedt + * @reason optimize random light checks so they complete faster + */ + @Overwrite + public void enqueueRelightChecks() + { + /* Skip object allocation if we weren't going to run checks anyway */ + if (this.queuedLightChecks >= 4096) + return; + boolean isActiveChunk = worldObj.activeChunkSet.contains(new ChunkCoordIntPair(this.xPosition, this.zPosition)); + int lightRecheckSpeed; + if(worldObj.isRemote && isActiveChunk) { + lightRecheckSpeed = 256; + } else if(worldObj.isRemote) + lightRecheckSpeed = 64; + else + lightRecheckSpeed = 32; + for (int i = 0; i < lightRecheckSpeed; ++i) + { + if (this.queuedLightChecks >= 4096) + { + return; + } + + int section = this.queuedLightChecks % 16; + int x = this.queuedLightChecks / 16 % 16; + int z = this.queuedLightChecks / 256; + ++this.queuedLightChecks; + int bx = (this.xPosition << 4) + x; + int bz = (this.zPosition << 4) + z; + + for (int y = 0; y < 16; ++y) + { + int by = (section << 4) + y; + ExtendedBlockStorage storage = this.storageArrays[section]; + + boolean performFullLightUpdate = false; + if (storage == null && (y == 0 || y == 15 || x == 0 || x == 15 || z == 0 || z == 15)) + performFullLightUpdate = true; + else if(storage != null) { + Block block = storage.getBlockByExtId(x, y, z); + if(block.getLightOpacity(this.worldObj, bx, by, bz) >= 255 && block.getLightValue(this.worldObj, bx, by, bz) <= 0) { + int prevLight = storage.getExtBlocklightValue(x, y, z); + if(prevLight != 0) { + storage.setExtBlocklightValue(x, y, z, 0); + this.worldObj.markBlockRangeForRenderUpdate(bx, by, bz, bx, by, bz); + } + } else + performFullLightUpdate = true; + } + if (performFullLightUpdate) + { + this.worldObj.func_147451_t(bx, by, bz); + } + } + } + } + + @Shadow + public abstract int getHeightValue(int i, int j); + + // === INTERFACE IMPL === + + private short[] neighborLightChecks; + + private boolean isLightInitialized; + + private ILightingEngine lightingEngine; + + @Override + public short[] getNeighborLightChecks() { + return this.neighborLightChecks; + } + + @Override + public void setNeighborLightChecks(short[] data) { + this.neighborLightChecks = data; + } + + @Override + public ILightingEngine getLightingEngine() { + if(this.lightingEngine == null) { + this.lightingEngine = ((ILightingEngineProvider) this.worldObj).getLightingEngine(); + if(this.lightingEngine == null) + throw new IllegalStateException(); + } + return this.lightingEngine; + } + + @Override + public boolean isLightInitialized() { + return this.isLightInitialized; + } + + @Override + public void setLightInitialized(boolean lightInitialized) { + this.isLightInitialized = lightInitialized; + } + + @Shadow public World worldObj; + + @Shadow private ExtendedBlockStorage[] storageArrays; + + @Shadow public abstract boolean canBlockSeeTheSky(int p_76619_1_, int p_76619_2_, int p_76619_3_); + + @Shadow public int[] heightMap; + + @Shadow public abstract Block getBlock(int p_150810_1_, int p_150810_2_, int p_150810_3_); + + @Shadow public int heightMapMinimum; + + @Shadow public boolean isTerrainPopulated; + + @Shadow @Final public int xPosition; + + @Shadow @Final public int zPosition; + + @Shadow private boolean isGapLightingUpdated; + + @Shadow public boolean[] updateSkylightColumns; + + @Shadow public boolean isModified; + + @Shadow private int queuedLightChecks; + + @Override + public void setSkylightUpdatedPublic() { + for (int i = 0; i < this.updateSkylightColumns.length; ++i) + { + this.updateSkylightColumns[i] = true; + } + + this.recheckGaps(false); + } + + @Override + public int getCachedLightFor(EnumSkyBlock type, int xIn, int yIn, int zIn) { + int i = xIn & 15; + int j = yIn; + int k = zIn & 15; + + ExtendedBlockStorage extendedblockstorage = this.storageArrays[j >> 4]; + + if (extendedblockstorage == null) { + if (this.canBlockSeeTheSky(i, j, k)) { + return type.defaultLightValue; + } else { + return 0; + } + } else if (type == EnumSkyBlock.Sky) { + if (this.worldObj.provider.hasNoSky) { + return 0; + } else { + return extendedblockstorage.getExtSkylightValue(i, j & 15, k); + } + } else { + if (type == EnumSkyBlock.Block) { + return extendedblockstorage.getExtBlocklightValue(i, j & 15, k); + } else { + return type.defaultLightValue; + } + } + } + + + // === END OF INTERFACE IMPL === +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkProviderServer.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkProviderServer.java new file mode 100644 index 000000000..f5dfbeed9 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkProviderServer.java @@ -0,0 +1,48 @@ +package org.embeddedt.archaicfix.mixins.common.lighting; + +import net.minecraft.util.IProgressUpdate; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.gen.ChunkProviderServer; +import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Set; + +@Mixin(ChunkProviderServer.class) +public abstract class MixinChunkProviderServer { + @Shadow private Set chunksToUnload; + + @Shadow public WorldServer worldObj; + + /** + * Injects a callback into the start of saveChunks(boolean) to force all light updates to be processed before saving. + * + * @author Angeline + */ + @Inject(method = "saveChunks", at = @At("HEAD")) + private void onSaveChunks(boolean all, IProgressUpdate update, CallbackInfoReturnable cir) { + ((ILightingEngineProvider) this.worldObj).getLightingEngine().processLightUpdates(); + } + + /** + * Injects a callback into the start of the onTick() method to process all pending light updates. This is not necessarily + * required, but we don't want our work queues getting too large. + * + * @author Angeline + */ + @Inject(method = "unloadQueuedChunks", at = @At("HEAD")) + private void onTick(CallbackInfoReturnable cir) { + if (!this.worldObj.levelSaving) { + if (!this.chunksToUnload.isEmpty()) { + ((ILightingEngineProvider) this.worldObj).getLightingEngine().processLightUpdates(); + } + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkVanilla.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkVanilla.java new file mode 100644 index 000000000..958a0cd2b --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkVanilla.java @@ -0,0 +1,79 @@ +package org.embeddedt.archaicfix.mixins.common.lighting; + +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.*; + +@Mixin(value = Chunk.class) +public abstract class MixinChunkVanilla { + @Shadow public World worldObj; + private static final String SET_BLOCK_STATE_VANILLA = "func_150807_a(IIILnet/minecraft/block/Block;I)Z"; + + /** + * Redirects the construction of the ExtendedBlockStorage in setBlockState(BlockPos, IBlockState). We need to initialize + * the skylight data for the constructed section as soon as possible. + * + * @author Angeline + */ + @Redirect( + method = SET_BLOCK_STATE_VANILLA, + at = @At( + value = "NEW", + args = "class=net/minecraft/world/chunk/storage/ExtendedBlockStorage" + ), + expect = 0 + ) + private ExtendedBlockStorage setBlockStateCreateSectionVanilla(int y, boolean storeSkylight) { + return this.initSection(y, storeSkylight); + } + + private ExtendedBlockStorage initSection(int y, boolean storeSkylight) { + ExtendedBlockStorage storage = new ExtendedBlockStorage(y, storeSkylight); + + LightingHooks.initSkylightForSection(this.worldObj, (Chunk) (Object) this, storage); + + return storage; + } + + /** + * Modifies the flag variable of setBlockState(BlockPos, IBlockState) to always be false after it is set. + * + * @author Angeline + */ + @ModifyVariable( + method = SET_BLOCK_STATE_VANILLA, + at = @At( + value = "STORE", + ordinal = 1 + ), + name = "flag", + index = 11, + allow = 1 + ) + private boolean setBlockStateInjectGenerateSkylightMapVanilla(boolean generateSkylight) { + return false; + } + + /** + * Prevent propagateSkylightOcclusion from being called. + * @author embeddedt + */ + @Redirect(method = SET_BLOCK_STATE_VANILLA, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;propagateSkylightOcclusion(II)V")) + private void doPropagateSkylight(Chunk chunk, int i1, int i2) { + /* No-op, we don't want skylight propagated */ + } + + /** + * Prevent getLightFor from being called. + * @author embeddedt + */ + @Redirect(method = SET_BLOCK_STATE_VANILLA, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;getSavedLightValue(Lnet/minecraft/world/EnumSkyBlock;III)I")) + private int getFakeLightFor(Chunk chunk, EnumSkyBlock skyBlock, int x, int y, int z) { + return 0; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinExtendedBlockStorage.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinExtendedBlockStorage.java new file mode 100644 index 000000000..6091c2560 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinExtendedBlockStorage.java @@ -0,0 +1,97 @@ +package org.embeddedt.archaicfix.mixins.common.lighting; + +import net.minecraft.world.chunk.NibbleArray; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(ExtendedBlockStorage.class) +public class MixinExtendedBlockStorage { + @Shadow + private int blockRefCount; + + @Shadow private NibbleArray skylightArray; + @Shadow private NibbleArray blocklightArray; + private int lightRefCount = -1; + + /** + * @author Angeline + * @reason Reset lightRefCount on call + */ + @Overwrite + public void setExtSkylightValue(int x, int y, int z, int value) { + this.skylightArray.set(x, y, z, value); + this.lightRefCount = -1; + } + + /** + * @author Angeline + * @reason Reset lightRefCount on call + */ + @Overwrite + public void setExtBlocklightValue(int x, int y, int z, int value) { + this.blocklightArray.set(x, y, z, value); + this.lightRefCount = -1; + } + + /** + * @author Angeline + * @reason Reset lightRefCount on call + */ + @Overwrite + public void setBlocklightArray(NibbleArray array) { + this.blocklightArray = array; + this.lightRefCount = -1; + } + + /** + * @author Angeline + * @reason Reset lightRefCount on call + */ + @Overwrite + public void setSkylightArray(NibbleArray array) { + this.skylightArray = array; + this.lightRefCount = -1; + } + + + /** + * @author Angeline + * @reason Send light data to clients when lighting is non-trivial + */ + @Overwrite + public boolean isEmpty() { + if (this.blockRefCount != 0) { + return false; + } + + // -1 indicates the lightRefCount needs to be re-calculated + if (this.lightRefCount == -1) { + if (this.checkLightArrayEqual(this.skylightArray, (byte) 0xFF) + && this.checkLightArrayEqual(this.blocklightArray, (byte) 0x00)) { + this.lightRefCount = 0; // Lighting is trivial, don't send to clients + } else { + this.lightRefCount = 1; // Lighting is not trivial, send to clients + } + } + + return this.lightRefCount == 0; + } + + private boolean checkLightArrayEqual(NibbleArray storage, byte val) { + if (storage == null) { + return true; + } + + byte[] arr = storage.data; + + for (byte b : arr) { + if (b != val) { + return false; + } + } + + return true; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinSPacketChunkData.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinSPacketChunkData.java new file mode 100644 index 000000000..cfd3b849d --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinSPacketChunkData.java @@ -0,0 +1,23 @@ +package org.embeddedt.archaicfix.mixins.common.lighting; + +import net.minecraft.network.play.server.S21PacketChunkData; +import net.minecraft.world.chunk.Chunk; +import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(S21PacketChunkData.class) +public abstract class MixinSPacketChunkData { + /** + * @author Angeline + * Injects a callback into SPacketChunkData#calculateChunkSize(Chunk, booolean, int) to force light updates to be + * processed before creating the client payload. We use this method rather than the constructor as it is not valid + * to inject elsewhere other than the RETURN of a ctor, which is too late for our needs. + */ + @Inject(method = "func_149269_a", at = @At("HEAD")) + private static void onCalculateChunkSize(Chunk chunkIn, boolean hasSkyLight, int changedSectionFilter, CallbackInfoReturnable cir) { + ((ILightingEngineProvider) chunkIn).getLightingEngine().processLightUpdates(); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinWorld_Lighting.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinWorld_Lighting.java new file mode 100644 index 000000000..3d553f0cf --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinWorld_Lighting.java @@ -0,0 +1,53 @@ +package org.embeddedt.archaicfix.mixins.common.lighting; + +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.World; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.storage.ISaveHandler; +import net.minecraft.world.storage.WorldInfo; +import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngine; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Set; + +@Mixin(World.class) +public abstract class MixinWorld_Lighting implements ILightingEngineProvider { + @Shadow protected Set activeChunkSet; + + @Shadow public abstract IChunkProvider getChunkProvider(); + + private LightingEngine lightingEngine; + + /** + * @author Angeline + * Initialize the lighting engine on world construction. + */ + @Redirect(method = "(Lnet/minecraft/world/storage/ISaveHandler;Ljava/lang/String;Lnet/minecraft/world/WorldSettings;Lnet/minecraft/world/WorldProvider;Lnet/minecraft/profiler/Profiler;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/storage/ISaveHandler;loadWorldInfo()Lnet/minecraft/world/storage/WorldInfo;")) + private WorldInfo onConstructed(ISaveHandler handler) { + this.lightingEngine = new LightingEngine((World) (Object) this); + return handler.loadWorldInfo(); + } + + + /** + * Directs the light update to the lighting engine and always returns a success value. + * @author Angeline + * @reason Phosphor replaces the lighting engine with a more efficient implementation. + */ + @Overwrite + public boolean updateLightByType(EnumSkyBlock type, int x, int y, int z) { + this.lightingEngine.scheduleLightUpdate(type, x, y, z); + + return true; + } + + @Override + public LightingEngine getLightingEngine() { + return this.lightingEngine; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunk.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunk.java new file mode 100644 index 000000000..7e8400305 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunk.java @@ -0,0 +1,35 @@ +package org.embeddedt.archaicfix.mixins.common.lighting.fastcraft; + +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(Chunk.class) +public abstract class MixinChunk { + @Shadow protected abstract void relightBlock(int p_76615_1_, int p_76615_2_, int p_76615_3_); + + @Shadow protected abstract void recheckGaps(boolean p_150803_1_); + + @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;c(Lnet/minecraft/world/chunk/Chunk;III)V", remap = false), require = 0) + private void doBlockLight(Chunk chunk, int x, int y, int z) { + this.relightBlock(x, y, z); + } + + @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;a(Lnet/minecraft/world/chunk/Chunk;)V", remap = false), require = 0) + private void usePhosphorLightPopulation(Chunk chunk) { + chunk.func_150809_p(); + } + + @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;b(Lnet/minecraft/world/chunk/Chunk;Z)V", remap = false), require = 0) + private void usePhosphorRecheckGaps(Chunk chunk, boolean isRemote) { + this.recheckGaps(isRemote); + } + + @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;d(Lnet/minecraft/world/World;III)Z", remap = false), require = 0) + private boolean updateLightUsingPhosphor(World world, int x, int y, int z) { + return world.func_147451_t(x, y, z); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunkProviderServer.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunkProviderServer.java new file mode 100644 index 000000000..87d538073 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunkProviderServer.java @@ -0,0 +1,15 @@ +package org.embeddedt.archaicfix.mixins.common.lighting.fastcraft; + +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.gen.ChunkProviderServer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ChunkProviderServer.class) +public class MixinChunkProviderServer { + @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;a(Lnet/minecraft/world/chunk/Chunk;)V", remap = false), require = 0) + private void usePhosphorLightPopulation(Chunk chunk) { + chunk.func_150809_p(); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinWorld.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinWorld.java new file mode 100644 index 000000000..dcc0a76cd --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinWorld.java @@ -0,0 +1,14 @@ +package org.embeddedt.archaicfix.mixins.common.lighting.fastcraft; + +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(World.class) +public class MixinWorld { + @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;d(Lnet/minecraft/world/World;III)Z", remap = false), require = 0) + private boolean updateLightUsingPhosphor(World world, int x, int y, int z) { + return world.func_147451_t(x, y, z); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/mrtjp/MixinBlockUpdateHandler.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/mrtjp/MixinBlockUpdateHandler.java new file mode 100644 index 000000000..41e210f32 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/mrtjp/MixinBlockUpdateHandler.java @@ -0,0 +1,21 @@ +package org.embeddedt.archaicfix.mixins.common.mrtjp; + +import mrtjp.core.world.BlockUpdateHandler$; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.HashSet; + +@Mixin(BlockUpdateHandler$.class) +public class MixinBlockUpdateHandler { + @Redirect(method = "getActiveChunkSet", at = @At(value = "INVOKE", target = "Ljava/util/HashSet;add(Ljava/lang/Object;)Z"), remap = false) + private boolean addChunkIfLoaded(HashSet chunkSet, Object o, World world) { + ChunkCoordIntPair pair = (ChunkCoordIntPair)o; + if(world.getChunkProvider().chunkExists(pair.chunkXPos, pair.chunkZPos)) + return chunkSet.add(o); + return false; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/renderdistance/MixinPlayerManager.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/renderdistance/MixinPlayerManager.java new file mode 100644 index 000000000..285196a52 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/common/renderdistance/MixinPlayerManager.java @@ -0,0 +1,16 @@ +package org.embeddedt.archaicfix.mixins.common.renderdistance; + +import net.minecraft.server.management.PlayerManager; +import org.embeddedt.archaicfix.ArchaicFix; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(PlayerManager.class) +public class MixinPlayerManager { + @ModifyConstant(method = "func_152622_a", constant = @Constant(intValue = 20)) + private int increaseSendDistance(int constant) { + return ArchaicConfig.newMaxRenderDistance; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/generate.sh b/src/main/java/org/embeddedt/archaicfix/mixins/generate.sh new file mode 100644 index 000000000..8e36c5cb2 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/mixins/generate.sh @@ -0,0 +1,16 @@ +#!/bin/bash +perform_generation() { +pushd $1 &>/dev/null +side=$(echo $1 | awk '{ print toupper($0) }') +find * -name \*.java | while read -r line; do +pkgname=$(echo $line | sed 's;/;.;g' | sed 's/.java$//g') +enumname=$(echo $pkgname | sed 's/\./_/g') +echo " ${1}_${enumname}(Side.$side, always(), \"$pkgname\")," +done +popd &>/dev/null +} + +echo " // COMMON MIXINS" +perform_generation common +echo " // CLIENT MIXINS" +perform_generation client diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/BasicDistanceSorter.java b/src/main/java/org/embeddedt/archaicfix/occlusion/BasicDistanceSorter.java new file mode 100644 index 000000000..44d3eac7a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/BasicDistanceSorter.java @@ -0,0 +1,20 @@ +package org.embeddedt.archaicfix.occlusion; + +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.entity.EntityLivingBase; +import org.embeddedt.archaicfix.helpers.WorldRendererDistanceHelper; + +import java.util.Comparator; + +public class BasicDistanceSorter implements Comparator { + private final EntityLivingBase renderViewEntity; + + public BasicDistanceSorter(EntityLivingBase renderViewEntity) { + this.renderViewEntity = renderViewEntity; + } + + @Override + public int compare(WorldRenderer wr1, WorldRenderer wr2) { + return (int)((WorldRendererDistanceHelper.betterDistanceSquared(renderViewEntity, wr1) - WorldRendererDistanceHelper.betterDistanceSquared(renderViewEntity, wr2)) * 1024D); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java b/src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java new file mode 100644 index 000000000..00985c753 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java @@ -0,0 +1,45 @@ +package org.embeddedt.archaicfix.occlusion; + +import lombok.Getter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.MathHelper; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.vector.Matrix4f; +import org.lwjgl.util.vector.Vector3f; +import org.lwjgl.util.vector.Vector4f; + +import java.nio.FloatBuffer; + +public class CameraInfo { + + @Getter + private static CameraInfo instance = new CameraInfo(); + + /** The transformed eye position, which takes the third person camera offset into account. */ + @Getter + private double x, y, z; + /** The untransformed eye position, which is not affected by the third person camera. It's always at the player character's eyes. */ + @Getter + private double eyeX, eyeY, eyeZ; + /** The chunk coordinates of the transformed eye position, which takes the third person camera offset into account. */ + @Getter + private int chunkCoordX, chunkCoordY, chunkCoordZ; + + public void update(EntityLivingBase view, double tick) { + eyeX = view.lastTickPosX + (view.posX - view.lastTickPosX) * tick; + eyeY = view.lastTickPosY + (view.posY - view.lastTickPosY) * tick; + eyeZ = view.lastTickPosZ + (view.posZ - view.lastTickPosZ) * tick; + + x = eyeX + ActiveRenderInfo.objectX; + y = eyeY + ActiveRenderInfo.objectY; + z = eyeZ + ActiveRenderInfo.objectZ; + + chunkCoordX = MathHelper.floor_double(x / 16.0); + chunkCoordY = MathHelper.floor_double(y / 16.0); + chunkCoordZ = MathHelper.floor_double(z / 16.0); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java b/src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java new file mode 100644 index 000000000..8ee9d56e4 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java @@ -0,0 +1,56 @@ +package org.embeddedt.archaicfix.occlusion; + +import net.minecraft.world.chunk.Chunk; +import org.embeddedt.archaicfix.occlusion.util.LinkedHashList; +import org.embeddedt.archaicfix.occlusion.util.SynchronizedIdentityLinkedHashList; + +public class ChunkThread extends Thread { + + public ChunkThread() { + + super("Chunk Worker"); + } + + public LinkedHashList loaded = new SynchronizedIdentityLinkedHashList(); + public LinkedHashList modified = new SynchronizedIdentityLinkedHashList(); + + @Override + public void run() { + + for (;;) { + int i = 0; + boolean work = false; + for (; loaded.size() > 0; ++i) { + Chunk chunk = ((ICulledChunk)loaded.shift()).buildCulledSides(); + if (chunk != null) { + modified.add(chunk); + work = true; + } + if ((i & 3) == 0) { + Thread.yield(); + } + } + for (i = 0; modified.size() > 0; ++i) { + Chunk chunk = modified.shift(); + if (loaded.contains(chunk)) { + continue; + } + for (VisGraph graph : ((ICulledChunk)chunk).getVisibility()) { + if (graph.isDirty()) { + long a = graph.getVisibility(); + graph.computeVisibility(); + work |= a != graph.getVisibility(); + } + } + if ((i & 7) == 0) { + Thread.yield(); + } + } + OcclusionHelpers.worker.dirty = work; + try { + Thread.sleep(30); + } catch (InterruptedException e) { + } + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java b/src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java new file mode 100644 index 000000000..2d756cfb8 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java @@ -0,0 +1,31 @@ +package org.embeddedt.archaicfix.occlusion; + +import net.minecraft.client.renderer.WorldRenderer; + +import java.util.List; + +public class DefaultRendererUpdateOrderProvider implements IRendererUpdateOrderProvider { + + private int lastUpdatedIndex = 0; + + @Override + public void prepare(List worldRenderersToUpdateList) { + lastUpdatedIndex = 0; + } + + @Override + public boolean hasNext(List worldRenderersToUpdateList) { + return lastUpdatedIndex < worldRenderersToUpdateList.size(); + } + + @Override + public WorldRenderer next(List worldRenderersToUpdateList) { + return worldRenderersToUpdateList.get(lastUpdatedIndex++); + } + + @Override + public void cleanup(List worldRenderersToUpdateList) { + worldRenderersToUpdateList.subList(0, lastUpdatedIndex).clear(); + } + +} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/ICulledChunk.java b/src/main/java/org/embeddedt/archaicfix/occlusion/ICulledChunk.java new file mode 100644 index 000000000..44bfa9448 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/ICulledChunk.java @@ -0,0 +1,9 @@ +package org.embeddedt.archaicfix.occlusion; + +import net.minecraft.world.chunk.Chunk; +import org.embeddedt.archaicfix.occlusion.VisGraph; + +public interface ICulledChunk { + VisGraph[] getVisibility(); + Chunk buildCulledSides(); +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/IRenderGlobalListener.java b/src/main/java/org/embeddedt/archaicfix/occlusion/IRenderGlobalListener.java new file mode 100644 index 000000000..b7877789f --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/IRenderGlobalListener.java @@ -0,0 +1,10 @@ +package org.embeddedt.archaicfix.occlusion; + +import net.minecraft.client.renderer.WorldRenderer; + +public interface IRenderGlobalListener { + + /** Called when a world renderer changes while it's already dirty. */ + void onDirtyRendererChanged(WorldRenderer wr); + +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/IRendererUpdateOrderProvider.java b/src/main/java/org/embeddedt/archaicfix/occlusion/IRendererUpdateOrderProvider.java new file mode 100644 index 000000000..52a3785e2 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/IRendererUpdateOrderProvider.java @@ -0,0 +1,21 @@ +package org.embeddedt.archaicfix.occlusion; + +import net.minecraft.client.renderer.WorldRenderer; + +import java.util.List; + +/** Provides a traversal order of the elements of RenderGlobal#worldRenderersToUpdate. Ideally, the order should be from + * the closest renderer to the farthest. */ +public interface IRendererUpdateOrderProvider { + + /** Prepare providing a batch of renderers. */ + void prepare(List worldRenderersToUpdateList); + + boolean hasNext(List worldRenderersToUpdateList); + + WorldRenderer next(List worldRenderersToUpdateList); + + /** End the batch. Remove the renderers that were provided during the batch from worldRenderersToUpdate */ + void cleanup(List worldRenderersToUpdateList); + +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/IWorldRenderer.java b/src/main/java/org/embeddedt/archaicfix/occlusion/IWorldRenderer.java new file mode 100644 index 000000000..a80592260 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/IWorldRenderer.java @@ -0,0 +1,10 @@ +package org.embeddedt.archaicfix.occlusion; + +public interface IWorldRenderer { + + boolean arch$isInUpdateList(); + void arch$setInUpdateList(boolean b); + + OcclusionWorker.CullInfo arch$getCullInfo(); + +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/LICENSE b/src/main/java/org/embeddedt/archaicfix/occlusion/LICENSE new file mode 100644 index 000000000..b31b92c8b --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/LICENSE @@ -0,0 +1,51 @@ +CoFH "Don't Be a Jerk" License +==================================== +#### Okay, so here's the deal. + +You'll notice that this repository does not have a license! By default, that means "All Rights Reserved." + +That is indeed the case. All rights reserved, as far as the code is concerned. + +Art and sound assets are released under the Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0), a summary of which can be found at: https://creativecommons.org/licenses/by-sa/4.0/ + +©2012-2015 Cult of the Full Hub / Team CoFH / CoFH + +#### Homepage + +[TeamCoFH Home Page](http://teamcofh.com/) + +[IRC #ThermalExpansion on esper.net](http://webchat.esper.net/?nick=ThermalWiki....&channels=ThermalExpansion) + +#### Notice + +Contribution to this repository means that you are granting us rights over the code that you choose to contribute. If you do not agree with that, do not contribute. + +So, why is this here? Well, the rights are reserved, but what that really means is that we choose what to do with the rights. So here you go. + +#### You CAN +- Fork and modify the code. +- Submit Pull Requests to this repository. +- Copy portions of this code for use in other projects. +- Write your own code that uses this code as a dependency. (addon mods!) + +#### You CANNOT +- Redistribute this in its entirety as source or compiled code. +- Create or distribute code which contains 50% or more Functionally Equivalent Statements* from this repository. + +#### You MUST +- Maintain a visible repository of your code which is inspired by, derived from, or copied from this code. Basically, if you use it, pay it forward. You keep rights to your OWN code, but you still must make your source visible. +- Not be a jerk**. Seriously, if you're a jerk, you can't use this code. That's part of the agreement. + +#### Notes, License & Copyright + +*A Functionally Equivalent Statement is a code fragment which, regardless of whitespace and object names, achieves the same result. Basically you can't copy the code, rename the variables, add whitespace and say it's different. It's not. + +**A jerk is anyone who attempts to or intends to claim partial or total ownership of the original or repackaged code and/or attempts to or intends to redistribute original or repackaged code without prior express written permission from the owners (CoFH). + +Essentially, take this and learn from it! Create addon mods that depend on it! If you see something we can improve, tell us. Submit a Pull Request. The one catch: don't steal! A lot of effort has gone into this, and if you were to take this and call it your own, you'd basically be a big jerk. + +Don't be a jerk. + +See LICENSE-CODE.txt and LICENSE-ART.txt for license information. + +©2012-2015 Cult of the Full Hub / Team CoFH / CoFH \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java new file mode 100644 index 000000000..896f3b913 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java @@ -0,0 +1,49 @@ +package org.embeddedt.archaicfix.occlusion; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.chunk.Chunk; +import org.embeddedt.archaicfix.occlusion.util.IntStack; + +public class OcclusionHelpers { + public static OcclusionWorker worker; + public static OcclusionRenderer renderer; + public static long chunkUpdateDeadline; + public static float partialTickTime; + + public static final boolean DEBUG_ALWAYS_RUN_OCCLUSION = Boolean.parseBoolean(System.getProperty("archaicfix.debug.alwaysRunOcclusion", "false")); + public static final boolean DEBUG_PRINT_QUEUE_ITERATIONS = Boolean.parseBoolean(System.getProperty("archaicfix.debug.printQueueIterations", "false")); + /** Update up to 1 chunk per frame when the framerate is uncapped, vanilla-style. */ + public static final boolean DEBUG_LAZY_CHUNK_UPDATES = Boolean.parseBoolean(System.getProperty("archaicfix.debug.lazyChunkUpdates", "false")); + /** Disable speeding up chunk updates when the camera is static. */ + public static final boolean DEBUG_NO_UPDATE_ACCELERATION = Boolean.parseBoolean(System.getProperty("archaicfix.debug.noUpdateAcceleration", "false")); + + public static void init() { + worker = new OcclusionWorker(); + } + + public static IntStack deferredAreas = new IntStack(6 * 1024); + + public static synchronized void updateArea(int x, int y, int z, int x2, int y2, int z2) { + + // backwards so it's more logical to extract + deferredAreas.add(z2); + deferredAreas.add(y2); + deferredAreas.add(x2); + deferredAreas.add(z); + deferredAreas.add(y); + deferredAreas.add(x); + } + + public static synchronized void processUpdate(OcclusionRenderer render) { + if (deferredAreas.isEmpty()) { + return; // guard against multiple instances (no compatibility with mods that do this to us) + } + + int x = deferredAreas.pop(), y = deferredAreas.pop(), z = deferredAreas.pop(); + int x2 = deferredAreas.pop(), y2 = deferredAreas.pop(), z2 = deferredAreas.pop(); + render.internalMarkBlockUpdate(x, y, z, x2, y2, z2); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java new file mode 100644 index 000000000..247199a19 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java @@ -0,0 +1,580 @@ +package org.embeddedt.archaicfix.occlusion; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.embeddedt.archaicfix.helpers.WorldRendererDistanceHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiVideoSettings; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.RenderList; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.culling.ICamera; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.util.RenderDistanceSorter; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.MathHelper; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.EmptyChunk; + +public class OcclusionRenderer { + + private final Minecraft mc; + private final RenderGlobal rg; + + private Thread clientThread; + + private ArrayList worldRenderersToUpdateList; + + private double prevRenderX, prevRenderY, prevRenderZ; + private int cameraStaticTime; + + private short alphaSortProgress = 0; + private byte frameCounter, frameTarget; + + private int renderersNeedUpdate; + + private boolean resortUpdateList; + + private IRendererUpdateOrderProvider rendererUpdateOrderProvider; + private List eventListeners; + + /* Make sure other threads can see changes to this */ + private volatile boolean deferNewRenderUpdates; + + public OcclusionRenderer(RenderGlobal renderGlobal) { + this.rg = renderGlobal; + this.mc = renderGlobal.mc; + } + + public RenderGlobal getRenderGlobal() { + return rg; + } + + /** + * If the update list is not queued for a full resort (e.g. when the player moves or renderers have their positions + * changed), uses binary search to add the renderer in the update queue at the appropriate place. Otherwise, + * the renderer is just added to the end of the list. + * @param wr renderer to add to the list + */ + private void addRendererToUpdateQueue(WorldRenderer wr) { + if(!((IWorldRenderer)wr).arch$isInUpdateList()) { + ((IWorldRenderer)wr).arch$setInUpdateList(true); + if(mc.renderViewEntity == null || resortUpdateList) { + worldRenderersToUpdateList.add(wr); + resortUpdateList = true; + return; + } + if(worldRenderersToUpdateList.size() > 0) { + double targetDistance = WorldRendererDistanceHelper.betterDistanceSquared(mc.renderViewEntity, wr); + int low = 0; + int high = worldRenderersToUpdateList.size() - 1; + int finalIndex = -1; + while(low <= high) { + int mid = low + (high - low) / 2; + WorldRenderer other = worldRenderersToUpdateList.get(mid); + double otherDistance = WorldRendererDistanceHelper.betterDistanceSquared(mc.renderViewEntity, other); + if(otherDistance < targetDistance) { + low = mid + 1; + } else if(otherDistance > targetDistance) { + high = mid - 1; + } else { + finalIndex = mid; + break; + } + } + if(finalIndex == -1) + finalIndex = high; + worldRenderersToUpdateList.add(finalIndex+1, wr); + } else { + worldRenderersToUpdateList.add(wr); + } + } + } + + public void handleOffthreadUpdate(int x1, int y1, int z1, int x2, int y2, int z2) { + if(deferNewRenderUpdates || Thread.currentThread() != clientThread) { + OcclusionHelpers.updateArea(x1, y1, z1, x2, y2, z2); + } else { + internalMarkBlockUpdate(x1, y1, z1, x2, y2, z2); + } + } + + public void internalMarkBlockUpdate(int x1, int y1, int z1, int x2, int y2, int z2) { + int xStart = MathHelper.bucketInt(x1, 16); + int yStart = MathHelper.bucketInt(y1, 16); + int zStart = MathHelper.bucketInt(z1, 16); + int xEnd = MathHelper.bucketInt(x2, 16); + int yEnd = MathHelper.bucketInt(y2, 16); + int zEnd = MathHelper.bucketInt(z2, 16); + + final int width = rg.renderChunksWide; + final int height = rg.renderChunksTall; + final int depth = rg.renderChunksDeep; + final WorldRenderer[] worldRenderers = rg.worldRenderers; + boolean rebuild = false; + + for (int i = xStart; i <= xEnd; ++i) { + int x = i % width; + x += width & (x >> 31); + + for (int j = yStart; j <= yEnd; ++j) { + int y = j % height; + y += height & (y >> 31); + + for (int k = zStart; k <= zEnd; ++k) { + int z = k % depth; + z += depth & (z >> 31); + + int k4 = (z * height + y) * width + x; + WorldRenderer worldrenderer = worldRenderers[k4]; + + if (!worldrenderer.needsUpdate || (worldrenderer.isVisible && !((IWorldRenderer)worldrenderer).arch$isInUpdateList())) { + worldrenderer.markDirty(); + //if (worldrenderer.distanceToEntitySquared(mc.renderViewEntity) <= 2883.0F) { + Chunk chunk = rg.theWorld.getChunkFromBlockCoords(worldrenderer.posX, worldrenderer.posZ); + if (((ICulledChunk) chunk).getVisibility()[worldrenderer.posY >> 4].isRenderDirty()) { + rebuild = true; + } + //} + addRendererToUpdateQueue(worldrenderer); + } else { + for(IRenderGlobalListener l : eventListeners) l.onDirtyRendererChanged(worldrenderer); + } + } + } + } + + if (rebuild) { + OcclusionHelpers.worker.dirty = true; + } + } + + public boolean skipRenderingIfNotVisible(RenderManager instance, Entity entity, float tick) { + WorldRenderer rend = getRenderer(entity.posX, entity.posY, entity.posZ); + if (rend != null && !rend.isVisible) { + --rg.countEntitiesRendered; + ++rg.countEntitiesHidden; + return false; + } + return RenderManager.instance.renderEntitySimple(entity, tick); + } + + public String getDebugInfoRenders() { + StringBuilder r = new StringBuilder(3 + 4 + 1 + 4 + 1 + 6 + 5 + 4 + 5 + 4 + 5 + 4 + 5 + 4 + 5 + 3 + 5 + 3 + 5 + 4); + r.append("C: ").append(rg.renderersBeingRendered).append('/').append(rg.renderersLoaded).append('/').append(rg.worldRenderers.length); + r.append(". F: ").append(rg.renderersBeingClipped); + r.append(", O: ").append(rg.renderersBeingOccluded); + r.append(", E: ").append(rg.renderersSkippingRenderPass); + r.append(", I: ").append(rg.dummyRenderInt); + r.append("; U: ").append(renderersNeedUpdate); + r.append(", N: ").append(rg.worldRenderersToUpdate.size()); + return r.toString(); + } + + public void initBetterLists() { + worldRenderersToUpdateList = new ArrayList<>(); + /* Make sure any vanilla code modifying the update queue crashes */ + rg.worldRenderersToUpdate = Collections.unmodifiableList(worldRenderersToUpdateList); + clientThread = Thread.currentThread(); + rendererUpdateOrderProvider = new DefaultRendererUpdateOrderProvider(); + eventListeners = new ArrayList<>(); + } + + public void clearRendererUpdateQueue(List instance) { + if(instance == rg.worldRenderersToUpdate) { + for(WorldRenderer wr : worldRenderersToUpdateList) { + ((IWorldRenderer)wr).arch$setInUpdateList(false); + } + worldRenderersToUpdateList.clear(); + } else { + throw new AssertionError("Transformer applied to the wrong List.clear method"); + } + } + + public boolean sortAndAddRendererUpdateQueue(List instance, Object renderer) { + if(instance == rg.worldRenderersToUpdate) { + addRendererToUpdateQueue((WorldRenderer)renderer); + return true; + } else { + throw new AssertionError("Transformer applied to the wrong List.clear method"); + } + } + + private static int fixPos(int pos, int amt) { + int r = Math.floorDiv(pos, 16) % amt; + if(r < 0) { + r += amt; + } + return r; + } + + public WorldRenderer getRenderer(int x, int y, int z) { + if ((y - 15) > rg.maxBlockY || y < rg.minBlockY || (x - 15) > rg.maxBlockX || x < rg.minBlockX || (z - 15) > rg.maxBlockZ || z < rg.minBlockZ) + return null; + + x = fixPos(x, rg.renderChunksWide); + y = fixPos(y, rg.renderChunksTall); + z = fixPos(z, rg.renderChunksDeep); + + return rg.worldRenderers[(z * rg.renderChunksTall + y) * rg.renderChunksWide + x]; + } + + public WorldRenderer getRenderer(double x, double y, double z) { + int X = MathHelper.floor_double(x); + int Y = MathHelper.floor_double(y); + int Z = MathHelper.floor_double(z); + return getRenderer(X, Y, Z); + } + + private boolean rebuildChunks(EntityLivingBase view, long deadline) { + int updateLimit = deadline == 0 ? 5 : Integer.MAX_VALUE; + int updates = 0; + + boolean spareTime = true; + deferNewRenderUpdates = true; + rendererUpdateOrderProvider.prepare(worldRenderersToUpdateList); + for (int c = 0; updates < updateLimit && rendererUpdateOrderProvider.hasNext(worldRenderersToUpdateList); ++c) { + WorldRenderer worldrenderer = rendererUpdateOrderProvider.next(worldRenderersToUpdateList); + + ((IWorldRenderer)worldrenderer).arch$setInUpdateList(false); + + if (!(worldrenderer.isInFrustum & worldrenderer.isVisible) && !OcclusionHelpers.DEBUG_LAZY_CHUNK_UPDATES) { + continue; + } + + boolean e = worldrenderer.isWaitingOnOcclusionQuery; + worldrenderer.updateRenderer(view); + worldrenderer.isVisible &= !e; + worldrenderer.isWaitingOnOcclusionQuery = worldrenderer.skipAllRenderPasses() || (mc.theWorld.getChunkFromBlockCoords(worldrenderer.posX, worldrenderer.posZ) instanceof EmptyChunk); + // can't add fields, re-use + + if(worldrenderer.distanceToEntitySquared(view) > 272f) { + updates++; + if(!worldrenderer.isWaitingOnOcclusionQuery || deadline != 0 || OcclusionHelpers.DEBUG_LAZY_CHUNK_UPDATES) { + long t = System.nanoTime(); + if (t > deadline) { + spareTime = false; + break; + } + } + } + } + rendererUpdateOrderProvider.cleanup(worldRenderersToUpdateList); + deferNewRenderUpdates = false; + return spareTime; + } + + public void performCullingUpdates(EntityLivingBase view, boolean p_72716_2_) { + rg.theWorld.theProfiler.startSection("deferred_updates"); + while(OcclusionHelpers.deferredAreas.size() > 0) { + OcclusionHelpers.processUpdate(this); + } + rg.theWorld.theProfiler.endStartSection("rebuild"); + + CameraInfo cam = CameraInfo.getInstance(); + + boolean cameraMoved = cam.getEyeX() != prevRenderX || cam.getEyeY() != prevRenderY || cam.getEyeZ() != prevRenderZ; + + prevRenderX = cam.getEyeX(); + prevRenderY = cam.getEyeY(); + prevRenderZ = cam.getEyeZ(); + + boolean cameraRotated = PreviousActiveRenderInfo.changed(); + + if(!cameraRotated && !cameraMoved) { + cameraStaticTime++; + } else { + cameraStaticTime = 0; + } + + /* + * Under certain scenarios (such as renderer.setPosition being called, or the player moving), renderers will] + * have their distance from the player change. We address that here by sorting the list. + */ + if(resortUpdateList) { + worldRenderersToUpdateList.sort(new BasicDistanceSorter(mc.renderViewEntity)); + resortUpdateList = false; + } + if (!rg.worldRenderersToUpdate.isEmpty()) { + ++frameCounter; + boolean doUpdateAcceleration = cameraStaticTime > 2 && !OcclusionHelpers.DEBUG_LAZY_CHUNK_UPDATES + && !OcclusionHelpers.DEBUG_NO_UPDATE_ACCELERATION; + /* If the camera is not moving, assume a deadline of 30 FPS. */ + rebuildChunks(view, !doUpdateAcceleration ? OcclusionHelpers.chunkUpdateDeadline + : mc.entityRenderer.renderEndNanoTime + (1_000_000_000L / 30L)); + } + + rg.theWorld.theProfiler.endStartSection("scan"); + int yaw = MathHelper.floor_float(view.rotationYaw + 45) >> 4; + int pitch = MathHelper.floor_float(view.rotationPitch + 45) >> 4; + if (OcclusionHelpers.worker.dirty || cameraRotated || OcclusionHelpers.DEBUG_ALWAYS_RUN_OCCLUSION) { + OcclusionHelpers.worker.run(true); + PreviousActiveRenderInfo.update(); + } + rg.theWorld.theProfiler.endSection(); + } + + public void resetLoadedRenderers() { + if(rg.theWorld != null) { + rg.renderersLoaded = 0; + } + } + + public void resetOcclusionWorker() { + updateRendererNeighbors(); + if(OcclusionHelpers.worker != null) { + OcclusionHelpers.worker.dirty = true; + } + } + + public void updateRendererNeighbors() { + if(rg.worldRenderers == null) return; + for(int i = 0; i < rg.worldRenderers.length; i++) { + WorldRenderer rend = rg.worldRenderers[i]; + OcclusionWorker.CullInfo ci = ((IWorldRenderer) rend).arch$getCullInfo(); + ci.wrIdx = i; + Chunk o = rend.worldObj.getChunkFromBlockCoords(rend.posX, rend.posZ); + VisGraph oSides = isChunkEmpty(o) ? OcclusionWorker.DUMMY : ((ICulledChunk)o).getVisibility()[rend.posY >> 4]; + ci.visGraph = oSides; + ci.vis = oSides.getVisibilityArray(); + for(EnumFacing dir : EnumFacing.values()) { + WorldRenderer neighbor = getRenderer( + rend.posX + dir.getFrontOffsetX() * 16, + rend.posY + dir.getFrontOffsetY() * 16, + rend.posZ + dir.getFrontOffsetZ() * 16 + ); + ci.setNeighbor(dir, neighbor == null ? null : ((IWorldRenderer)neighbor).arch$getCullInfo()); + } + } + } + + public void pushWorkerRenderer(WorldRenderer wr) { + if(!(mc.theWorld.getChunkFromBlockCoords(wr.posX, wr.posZ) instanceof EmptyChunk)) + addRendererToUpdateQueue(wr); + } + + public void markRendererInvisible(WorldRenderer instance) { + instance.isVisible = false; + instance.isInFrustum = false; + instance.markDirty(); + } + + public void setPositionAndMarkInvisible(WorldRenderer wr, int x, int y, int z) { + wr.setPosition(x, y, z); + if(((IWorldRenderer)wr).arch$isInUpdateList()) + resortUpdateList = true; + if(!wr.isInitialized) { + wr.isWaitingOnOcclusionQuery = false; + wr.isVisible = false; + } + } + + public void runWorker(int p_72722_1_, int p_72722_2_, int p_72722_3_) { + updateRendererNeighbors(); + OcclusionHelpers.worker.run(true); + } + + public int sortAndRender(EntityLivingBase view, int pass, double tick) { + CameraInfo cam = CameraInfo.getInstance(); + cam.update(view, tick); + + rg.theWorld.theProfiler.startSection("sortchunks"); + + if (this.mc.gameSettings.renderDistanceChunks != rg.renderDistanceChunks && !(this.mc.currentScreen instanceof GuiVideoSettings)) + { + rg.loadRenderers(); + } + + WorldRenderer[] sortedWorldRenderers = rg.sortedWorldRenderers; + if (rg.renderersLoaded > 0) { + int e = rg.renderersLoaded - 10; + e &= e >> 31; + e += 10; + for (int j = 0; j < e; ++j) { + rg.worldRenderersCheckIndex = (rg.worldRenderersCheckIndex + 1) % rg.renderersLoaded; + WorldRenderer rend = sortedWorldRenderers[rg.worldRenderersCheckIndex]; + + if ((rend.isInFrustum & rend.isVisible) & (rend.needsUpdate || !rend.isInitialized) & !(this.mc.theWorld.getChunkFromBlockCoords(rend.posX, rend.posZ) instanceof EmptyChunk)) { + addRendererToUpdateQueue(rend); + } + } + } + + rg.theWorld.theProfiler.startSection("reposition_chunks"); + if (rg.prevChunkSortX != cam.getChunkCoordX() || rg.prevChunkSortY != cam.getChunkCoordY() || rg.prevChunkSortZ != cam.getChunkCoordZ()) { + rg.prevChunkSortX = cam.getChunkCoordX(); + rg.prevChunkSortY = cam.getChunkCoordY(); + rg.prevChunkSortZ = cam.getChunkCoordZ(); + rg.markRenderersForNewPosition(MathHelper.floor_double(cam.getX()), MathHelper.floor_double(cam.getY()), MathHelper.floor_double(cam.getZ())); + resortUpdateList = true; + } + rg.theWorld.theProfiler.endSection(); + + if(pass == 1){ + rg.theWorld.theProfiler.startSection("alpha_sort"); + if(distanceSquared(cam.getX(), cam.getY(), cam.getZ(), rg.prevRenderSortX, rg.prevRenderSortY, rg.prevRenderSortZ) > 1) { + rg.prevRenderSortX = cam.getX(); + rg.prevRenderSortY = cam.getY(); + rg.prevRenderSortZ = cam.getZ(); + + alphaSortProgress = 0; + } + + int amt = rg.renderersLoaded < 27 ? rg.renderersLoaded : Math.max(rg.renderersLoaded >> 1, 27); + if (alphaSortProgress < amt) { + int amountPerFrame = 1; + for (int i = 0; i < amountPerFrame && alphaSortProgress < amt; ++i) { + WorldRenderer r = sortedWorldRenderers[alphaSortProgress++]; + r.updateRendererSort(view); + } + } + rg.theWorld.theProfiler.endSection(); + } + + rg.theWorld.theProfiler.endStartSection("render"); + RenderHelper.disableStandardItemLighting(); + int k = rg.renderSortedRenderers(0, rg.renderersLoaded, pass, tick); + + rg.theWorld.theProfiler.endSection(); + return k; + } + + public int sortAndRender(int start, int end, int pass, double tick) { + CameraInfo cam = CameraInfo.getInstance(); + + RenderList[] allRenderLists = rg.allRenderLists; + for (int i = 0; i < allRenderLists.length; ++i) { + allRenderLists[i].resetList(); + } + + int loopStart = start; + int loopEnd = end; + byte dir = 1; + + if (pass == 1) { + loopStart = end - 1; + loopEnd = start - 1; + dir = -1; + } + + if (pass == 0 && mc.gameSettings.showDebugInfo) { + + mc.theWorld.theProfiler.startSection("debug_info"); + int renderersNotInitialized = 0, renderersBeingClipped = 0, renderersBeingOccluded = 0; + int renderersBeingRendered = 0, renderersSkippingRenderPass = 0, renderersNeedUpdate = 0; + WorldRenderer[] worldRenderers = rg.worldRenderers; + for (int i = 0, e = worldRenderers.length; i < e; ++i) { + WorldRenderer rend = worldRenderers[i]; + if (!rend.isInitialized) { + ++renderersNotInitialized; + } else if (!rend.isInFrustum) { + ++renderersBeingClipped; + } else if (!rend.isVisible) { + ++renderersBeingOccluded; + } else if (rend.isWaitingOnOcclusionQuery) { + ++renderersSkippingRenderPass; + } else { + ++renderersBeingRendered; + } + if (rend.needsUpdate) { + ++renderersNeedUpdate; + } + } + + rg.dummyRenderInt = renderersNotInitialized; + rg.renderersBeingClipped = renderersBeingClipped; + rg.renderersBeingOccluded = renderersBeingOccluded; + rg.renderersBeingRendered = renderersBeingRendered; + rg.renderersSkippingRenderPass = renderersSkippingRenderPass; + this.renderersNeedUpdate = renderersNeedUpdate; + mc.theWorld.theProfiler.endSection(); + } + + mc.theWorld.theProfiler.startSection("setup_lists"); + int glListsRendered = 0, allRenderListsLength = 0; + WorldRenderer[] sortedWorldRenderers = rg.sortedWorldRenderers; + + for (int i = loopStart; i != loopEnd; i += dir) { + WorldRenderer rend = sortedWorldRenderers[i]; + + if (rend.isVisible && rend.isInFrustum & !rend.skipRenderPass[pass]) { + + int renderListIndex; + + l: { + for (int j = 0; j < allRenderListsLength; ++j) { + if (allRenderLists[j].rendersChunk(rend.posXMinus, rend.posYMinus, rend.posZMinus)) { + renderListIndex = j; + break l; + } + } + renderListIndex = allRenderListsLength++; + allRenderLists[renderListIndex].setupRenderList(rend.posXMinus, rend.posYMinus, rend.posZMinus, cam.getEyeX(), cam.getEyeY(), cam.getEyeZ()); + } + + allRenderLists[renderListIndex].addGLRenderList(rend.getGLCallListForPass(pass)); + ++glListsRendered; + } + } + + mc.theWorld.theProfiler.endStartSection("call_lists"); + + { + int xSort = MathHelper.floor_double(cam.getX()); + int zSort = MathHelper.floor_double(cam.getZ()); + xSort -= xSort & 1023; + zSort -= zSort & 1023; + Arrays.sort(allRenderLists, new RenderDistanceSorter(xSort, zSort)); + rg.renderAllRenderLists(pass, tick); + } + mc.theWorld.theProfiler.endSection(); + + return glListsRendered; + } + + public void clipRenderersByFrustum(ICamera p_72729_1_, float p_72729_2_) { + for (int i = 0; i < rg.worldRenderers.length; ++i) { + if((i + rg.frustumCheckOffset & 15) == 0) { + WorldRenderer wr = rg.worldRenderers[i]; + IWorldRenderer iwr = (IWorldRenderer) wr; + if (wr.isInFrustum && iwr.arch$getCullInfo().isFrustumCheckPending) { + wr.updateInFrustum(p_72729_1_); + iwr.arch$getCullInfo().isFrustumCheckPending = false; + if (!wr.isInFrustum) { + OcclusionHelpers.worker.dirtyFrustumRenderers++; + } + } + } + } + + ++rg.frustumCheckOffset; + + if(rg.frustumCheckOffset % 15 == 0 && OcclusionHelpers.worker.dirtyFrustumRenderers > 0) { + OcclusionHelpers.worker.dirty = true; + OcclusionHelpers.worker.dirtyFrustumRenderers = 0; + } + } + + public void arch$setRendererUpdateOrderProvider(IRendererUpdateOrderProvider orderProvider) { + this.rendererUpdateOrderProvider = orderProvider; + } + + public void arch$addRenderGlobalListener(IRenderGlobalListener listener) { + this.eventListeners.add(listener); + } + + private static double distanceSquared(double x1, double y1, double z1, double x2, double y2, double z2) { + return Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2); + } + + private static boolean isChunkEmpty(Chunk chunk) { + return chunk == null || chunk.isEmpty(); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java new file mode 100644 index 000000000..8b2ed300e --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java @@ -0,0 +1,426 @@ +package org.embeddedt.archaicfix.occlusion; + +import static org.embeddedt.archaicfix.occlusion.OcclusionHelpers.DEBUG_PRINT_QUEUE_ITERATIONS; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.culling.Frustrum; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.MathHelper; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Stream; + +public class OcclusionWorker { + + public OcclusionWorker() { + + /*for (int i = 0; i < fStack.length; ++i) { + fStack[i] = new Frustrum(); + }//*/ + } + + public void setWorld(RenderGlobal rg, WorldClient world) { + theWorld = world; + } + + public static final VisGraph DUMMY = new VisGraph(); + + static { + DUMMY.computeVisibility(); + } + + public volatile boolean dirty = false; + public int dirtyFrustumRenderers; + private int frame = 0; + private final List queue = new ArrayList<>(); + @SuppressWarnings("unused") + private Frustrum fStack = new Frustrum(); + private WorldClient theWorld; + + /** + * We cache the values of WorldRenderer#isInFrustum here to avoid the overhead of accessing the field. + */ + private boolean[] isWRInFrustum; + + private final Minecraft mc = Minecraft.getMinecraft(); + + private RenderGlobal getRender() { + return getExtendedRender().getRenderGlobal(); + } + + private OcclusionRenderer getExtendedRender() { + return OcclusionHelpers.renderer; + } + + public void run(boolean immediate) { + frame++; + queue.clear(); + int queueIterations = 0; + + if (getRender() == null) { + return; + } + EntityLivingBase view = mc.renderViewEntity; + if (theWorld == null || view == null) { + return; + } + long t0 = DEBUG_PRINT_QUEUE_ITERATIONS ? System.nanoTime() : 0; + + Frustrum frustum = getFrustum(); + + theWorld.theProfiler.startSection("prep"); + + prepareRenderers(); + + seedQueue(frustum); + + long t1 = DEBUG_PRINT_QUEUE_ITERATIONS ? System.nanoTime() : 0; + + theWorld.theProfiler.endStartSection("process_queue"); + for (int i = 0; i < queue.size(); i++) { + queueIterations++; + CullInfo ci = queue.get(i); + + for (StepDirection stepPos : CullInfo.ALLOWED_STEPS[ci.facings & 0b111111]) { + if (canStep(ci, stepPos)) { + maybeEnqueueNeighbor(ci, stepPos, queue, frustum); + } + } + } + theWorld.theProfiler.endStartSection("cleanup"); + + long t2 = DEBUG_PRINT_QUEUE_ITERATIONS ? System.nanoTime() : 0; + + for (CullInfo ci : queue) { + markRenderer(ci, view); + } + + if (DEBUG_PRINT_QUEUE_ITERATIONS) { + if (queueIterations != 0) { + System.out.println("queue iterations: " + queueIterations); + } + long t3 = System.nanoTime(); + System.out.println(((t1 - t0) / 1000000.0) + " ms prepare + " + (t2 - t1) / 1000000.0 + " ms queue + " + (t3 - t2) / 1000000.0 + " ms mark"); + } + + dirty = false; + queue.clear(); + theWorld.theProfiler.endSection(); + } + + private void prepareRenderers() { + RenderGlobal render = getRender(); + if (isWRInFrustum == null || isWRInFrustum.length != render.worldRenderers.length) { + isWRInFrustum = new boolean[render.worldRenderers.length]; + } + + for (int i = 0; i < render.worldRenderers.length; ++i) { + WorldRenderer wr = render.worldRenderers[i]; + wr.isVisible = false; + isWRInFrustum[i] = wr.isInFrustum; + } + render.renderersLoaded = 0; + } + + private Frustrum getFrustum() { + EntityLivingBase view = mc.renderViewEntity; + + Frustrum frustum = new Frustrum(); + // TODO: interpolate using partial tick time + frustum.setPosition(view.posX, view.posY, view.posZ); + return frustum; + } + + private void seedQueue(Frustrum frustum) { + CameraInfo cam = CameraInfo.getInstance(); + + int viewX = MathHelper.floor_double(cam.getX()); + int viewY = MathHelper.floor_double(cam.getY()); + int viewZ = MathHelper.floor_double(cam.getZ()); + + theWorld.theProfiler.endStartSection("gather_chunks"); + + OcclusionRenderer extendedRender = getExtendedRender(); + + theWorld.theProfiler.endStartSection("seed_queue"); + + WorldRenderer center = extendedRender.getRenderer(viewX, viewY, viewZ); + if (center != null) { + CullInfo ci = ((IWorldRenderer) center).arch$getCullInfo(); + isInFrustum(ci, frustum); // make sure frustum status gets updated for the starting renderer + ci.init(StepDirection.NONE, (byte) 0); + queue.add(ci); + } else { + int level = viewY > 5 ? 250 : 5; + center = extendedRender.getRenderer(viewX, level, viewZ); + if (center != null) { + StepDirection pos = viewY < 5 ? StepDirection.UP : StepDirection.DOWN; + { + CullInfo ci = ((IWorldRenderer) center).arch$getCullInfo(); + ci.init(StepDirection.NONE, (byte) 0); + queue.add(ci); + } + boolean allNull = false; + theWorld.theProfiler.startSection("gather_world"); + for (int size = 1; !allNull; ++size) { + allNull = true; + for (int i = 0, j = size; i < size; ) { + for (int k = 0; k < 4; ++k) { + int xm = (k & 1) == 0 ? -1 : 1; + int zm = (k & 2) == 0 ? -1 : 1; + center = extendedRender.getRenderer(viewX + i * 16 * xm, level, viewZ + j * 16 * zm); + if (center != null) { + CullInfo ci = ((IWorldRenderer) center).arch$getCullInfo(); + if (isInFrustum(ci, frustum)) { + allNull = false; + ci.init(StepDirection.NONE, (byte) 0); + queue.add(ci); + } + } + } + ++i; + --j; + } + } + theWorld.theProfiler.endSection(); + } + } + } + + private boolean canStep(CullInfo info, StepDirection stepPos) { + boolean allVis = mc.playerController.currentGameType.getID() == 3; + + if (!allVis && !SetVisibility.isVisible(info.vis[0], info.dir.getOpposite().facing, stepPos.facing)) { + return false; + } + + return true; + } + + private void maybeEnqueueNeighbor(CullInfo info, StepDirection stepPos, Collection queue, Frustrum frustum) { + CullInfo neighbor = info.getNeighbor(stepPos.facing); + + if (neighbor == null || !neighbor.setLastCullUpdateFrame(frame) || !isInFrustum(neighbor, frustum)) + return; + + neighbor.init(stepPos, info.facings); + + queue.add(neighbor); + } + + private void markRenderer(CullInfo info, EntityLivingBase view) { + RenderGlobal render = getRender(); + WorldRenderer rend = render.worldRenderers[info.wrIdx]; + if (!rend.isVisible) { + rend.isVisible = true; + if (!rend.isWaitingOnOcclusionQuery) { + // only add it to the list of sorted renderers if it's not skipping all passes (re-used field) + render.sortedWorldRenderers[render.renderersLoaded++] = rend; + } + } + if (rend.needsUpdate || !rend.isInitialized || info.visGraph.isRenderDirty()) { + rend.needsUpdate = true; + if (!rend.isInitialized || (rend.needsUpdate && rend.distanceToEntitySquared(view) <= 1128.0F)) { + getExtendedRender().pushWorkerRenderer(rend); + } + } + } + + private boolean isInFrustum(CullInfo ci, Frustrum frustum) { + if (isWRInFrustum[ci.wrIdx]) { + ci.isFrustumCheckPending = true; + } else { + WorldRenderer wr = Minecraft.getMinecraft().renderGlobal.worldRenderers[ci.wrIdx]; + wr.updateInFrustum(frustum); + isWRInFrustum[ci.wrIdx] = wr.isInFrustum; + } + return isWRInFrustum[ci.wrIdx]; + } + + public enum StepDirection { + // EnumFacing.EAST and EnumFacing.WEST is flipped in MCP + DOWN(EnumFacing.DOWN, 0, -1, 0), + UP(EnumFacing.UP, 0, 16, 0), + WEST(EnumFacing.EAST /* WEST */, -1, 0, 0), + EAST(EnumFacing.WEST /* EAST */, 16, 0, 0), + NORTH(EnumFacing.NORTH, 0, 0, -1), + SOUTH(EnumFacing.SOUTH, 0, 0, 16), + NONE(null, 0, 0, 0), + NONE_opp(null, 0, 0, 0); + + public static final StepDirection[] DIRECTIONS = values(); + public static final StepDirection[][] DIRECTIONS_BIAS = new StepDirection[6][6]; + public static final StepDirection[] FROM_FACING = new StepDirection[6]; + public static final List SIDES = Arrays.asList(DIRECTIONS).subList(1, 6); + static { + for (int i = 0; i < 6; ++i) { + StepDirection pos = DIRECTIONS[i]; + FROM_FACING[pos.facing.ordinal()] = pos; + StepDirection[] bias = DIRECTIONS_BIAS[i]; + int j = 0, xor = pos.ordinal() & 1; + switch (pos) { + case DOWN: + case UP: + bias[j++] = pos; + bias[j++] = DIRECTIONS[NORTH.ordinal() ^ xor]; + bias[j++] = DIRECTIONS[SOUTH.ordinal() ^ xor]; + bias[j++] = DIRECTIONS[EAST.ordinal() ^ xor]; + bias[j++] = DIRECTIONS[WEST.ordinal() ^ xor]; + bias[j++] = pos.getOpposite(); + break; + case WEST: + case EAST: + bias[j++] = pos; + bias[j++] = DIRECTIONS[NORTH.ordinal() ^ xor]; + bias[j++] = DIRECTIONS[SOUTH.ordinal() ^ xor]; + bias[j++] = DIRECTIONS[UP.ordinal() ^ xor]; + bias[j++] = DIRECTIONS[DOWN.ordinal() ^ xor]; + bias[j++] = pos.getOpposite(); + break; + case NORTH: + case SOUTH: + bias[j++] = pos; + bias[j++] = DIRECTIONS[EAST.ordinal() ^ xor]; + bias[j++] = DIRECTIONS[WEST.ordinal() ^ xor]; + bias[j++] = DIRECTIONS[UP.ordinal() ^ xor]; + bias[j++] = DIRECTIONS[DOWN.ordinal() ^ xor]; + bias[j++] = pos.getOpposite(); + break; + case NONE: + case NONE_opp: + break; + } + } + } + + public final int x, y, z; + public final EnumFacing facing; + + StepDirection(EnumFacing face, int x, int y, int z) { + + this.facing = face; + this.x = x; + this.y = y; + this.z = z; + _x = x > 0 ? 1 : x; + _y = y > 0 ? 1 : y; + _z = z > 0 ? 1 : z; + } + + public StepDirection getOpposite() { + + return DIRECTIONS[ordinal() ^ 1]; + } + + private final int _x, _y, _z; + } + + public static class CullInfo { + + public static final StepDirection[][] ALLOWED_STEPS; + + static { + ALLOWED_STEPS = generateAllowedSteps(); + } + + private static StepDirection[][] generateAllowedSteps() { + StepDirection[][] allowedSteps = new StepDirection[(int) Math.pow(2, 6) + 1][]; + + for (int xStep = -1; xStep <= 1; xStep++) { + for (int yStep = -1; yStep <= 1; yStep++) { + for (int zStep = -1; zStep <= 1; zStep++) { + byte mask = 0; + + // SNEWUD + mask |= new byte[]{0b000100, + 0b000000, + 0b001000 + }[xStep + 1]; + + // SNEWUD + mask |= new byte[]{0b000001, + 0b000000, + 0b000010 + }[yStep + 1]; + + // SNEWUD + mask |= new byte[]{0b010000, + 0b000000, + 0b100000 + }[zStep + 1]; + + byte finalMask = mask; + allowedSteps[mask] = + Stream.of(StepDirection.DOWN, StepDirection.UP, StepDirection.NORTH, StepDirection.SOUTH, StepDirection.WEST, StepDirection.EAST) + .filter(p -> (1 << (p.getOpposite().ordinal()) & finalMask) == 0) + .toArray(StepDirection[]::new); + } + } + } + return allowedSteps; + } + + /** + * The index of the world renderer in RenderGlobal#worldRenderers. Not stored as a reference because I + * found that having it slows things down significantly. + */ + public int wrIdx; + public CullInfo[] neighbors; + /** + * A direct reference to the visibility graph's visibility mask, used to avoid the significant overhead of + * accessing VisGraph's fields. + */ + public long[] vis; + public VisGraph visGraph; + /** + * The direction we stepped in to reach this subchunk. + */ + public StepDirection dir; + /** + * All the directions we have stepped in to reach this subchunk. + */ + public byte facings; + public int lastCullUpdateFrame; + public boolean isFrustumCheckPending; + + public CullInfo() { + this.neighbors = new CullInfo[EnumFacing.values().length]; + this.visGraph = DUMMY; + this.vis = visGraph.getVisibilityArray(); + } + + public CullInfo init(StepDirection dir, byte facings) { + this.dir = dir; + + this.facings = facings; + this.facings |= (1 << dir.ordinal()); + + return this; + } + + public CullInfo getNeighbor(EnumFacing dir) { + return neighbors[dir.ordinal()]; + } + + public void setNeighbor(EnumFacing dir, CullInfo neighbor) { + neighbors[dir.ordinal()] = neighbor; + } + + /** + * Sets the number of the last frame when this renderer was visited by the occlusion culling algorithm. + * Returns true if the value was changed as a result. + */ + public boolean setLastCullUpdateFrame(int lastCullUpdateFrame) { + if (this.lastCullUpdateFrame == lastCullUpdateFrame) return false; + this.lastCullUpdateFrame = lastCullUpdateFrame; + return true; + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/PreviousActiveRenderInfo.java b/src/main/java/org/embeddedt/archaicfix/occlusion/PreviousActiveRenderInfo.java new file mode 100644 index 000000000..ac28d2b39 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/PreviousActiveRenderInfo.java @@ -0,0 +1,26 @@ +package org.embeddedt.archaicfix.occlusion; + +import net.minecraft.client.renderer.ActiveRenderInfo; + +public class PreviousActiveRenderInfo { + public static float objectX = Float.NaN, objectY, objectZ; + public static float rotationX, rotationZ, rotationYZ; + + public static boolean changed() { + return PreviousActiveRenderInfo.objectX != ActiveRenderInfo.objectX || + PreviousActiveRenderInfo.objectY != ActiveRenderInfo.objectY || + PreviousActiveRenderInfo.objectZ != ActiveRenderInfo.objectZ || + PreviousActiveRenderInfo.rotationX != ActiveRenderInfo.rotationX || + PreviousActiveRenderInfo.rotationYZ != ActiveRenderInfo.rotationYZ || + PreviousActiveRenderInfo.rotationZ != ActiveRenderInfo.rotationZ; + } + + public static void update() { + PreviousActiveRenderInfo.objectX = ActiveRenderInfo.objectX; + PreviousActiveRenderInfo.objectY = ActiveRenderInfo.objectY; + PreviousActiveRenderInfo.objectZ = ActiveRenderInfo.objectZ; + PreviousActiveRenderInfo.rotationX = ActiveRenderInfo.rotationX; + PreviousActiveRenderInfo.rotationYZ = ActiveRenderInfo.rotationYZ; + PreviousActiveRenderInfo.rotationZ = ActiveRenderInfo.rotationZ; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java b/src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java new file mode 100644 index 000000000..359d85f5b --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java @@ -0,0 +1,93 @@ +package org.embeddedt.archaicfix.occlusion; + +import java.util.Iterator; +import java.util.Set; + +import net.minecraft.util.EnumFacing; + +public class SetVisibility { + + private static final int COUNT_FACES = EnumFacing.values().length; + + public static long setManyVisible(long bitSet, Set faces) { + Iterator iterator = faces.iterator(); + + while (iterator.hasNext()) { + EnumFacing enumfacing = iterator.next(); + Iterator iterator1 = faces.iterator(); + + while (iterator1.hasNext()) { + EnumFacing enumfacing1 = iterator1.next(); + bitSet = setVisible(bitSet, enumfacing, enumfacing1, true); + } + } + return bitSet; + } + + public static long setVisible(long bitSet, EnumFacing from, EnumFacing to, boolean visible) { + bitSet = setBit(bitSet, from.ordinal() + to.ordinal() * COUNT_FACES, visible); + bitSet = setBit(bitSet, to.ordinal() + from.ordinal() * COUNT_FACES, visible); + + return bitSet; + } + + private static long setBit(long bitSet, int index, boolean value) { + if(value) { + bitSet |= (1L << index); + } else { + bitSet &= ~(1L << index); + } + return bitSet; + } + + public static boolean isVisible(long bitSet, EnumFacing from, EnumFacing to) { + return from == null || to == null ? true : (bitSet & (1L << (from.ordinal() + to.ordinal() * COUNT_FACES))) != 0; + } + + public static String toString(long bitSet) { + + StringBuilder stringbuilder = new StringBuilder(); + stringbuilder.append(' '); + EnumFacing[] aenumfacing = EnumFacing.values(); + int i = aenumfacing.length; + int j; + EnumFacing enumfacing; + + for (j = 0; j < i; ++j) { + enumfacing = aenumfacing[j]; + stringbuilder.append(' ').append(enumFacingToStringFixed(enumfacing).toUpperCase().charAt(0)); + } + + stringbuilder.append('\n'); + aenumfacing = EnumFacing.values(); + i = aenumfacing.length; + + for (j = 0; j < i; ++j) { + enumfacing = aenumfacing[j]; + stringbuilder.append(enumFacingToStringFixed(enumfacing).toUpperCase().charAt(0)); + EnumFacing[] aenumfacing1 = EnumFacing.values(); + int k = aenumfacing1.length; + + for (int l = 0; l < k; ++l) { + EnumFacing enumfacing1 = aenumfacing1[l]; + + if (enumfacing == enumfacing1) { + stringbuilder.append(" "); + } else { + boolean flag = isVisible(bitSet, enumfacing, enumfacing1); + stringbuilder.append(' ').append(flag ? 'Y' : 'n'); + } + } + + stringbuilder.append('\n'); + } + + return stringbuilder.toString(); + } + + // Do not trust MCP. + private static String enumFacingToStringFixed(EnumFacing f) { + return new String[]{"DOWN", "UP", "NORTH", "SOUTH", "WEST", "EAST"}[f.ordinal()]; + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java b/src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java new file mode 100644 index 000000000..23dd219d8 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java @@ -0,0 +1,222 @@ +package org.embeddedt.archaicfix.occlusion; + +import java.util.BitSet; +import java.util.EnumSet; +import java.util.Set; + +import net.minecraft.util.EnumFacing; +import org.embeddedt.archaicfix.occlusion.util.IntStack; + +public class VisGraph { + + private static final int X_OFFSET = (int) Math.pow(16.0D, 0.0D); + private static final int Z_OFFSET = (int) Math.pow(16.0D, 1.0D); + private static final int Y_OFFSET = (int) Math.pow(16.0D, 2.0D); + private static final int[] EDGES = new int[1352]; + public static final long ALL_VIS = 0xFFFFFFFFFFFFFFFFL; + + static { + int var2 = 0; + + for (int var3 = 0; var3 < 16; ++var3) { + for (int var4 = 0; var4 < 16; ++var4) { + for (int var5 = 0; var5 < 16; ++var5) { + if (var3 == 0 || var3 == 15 || var4 == 0 || var4 == 15 || var5 == 0 || var5 == 15) { + EDGES[var2++] = getIndex(var3, var4, var5); + } + } + } + } + } + + /* + * This is a pretty hefty structure: 1340 bytes per 16^3 (40+bytes per object, and the array of long[] in BitSet) + * weighing in around 190 bytes for BitSets, 40 bytes for SetVisibility, and 50 bytes for this. + * ~4,824,000 bytes at view distance 7; This could be halved if it were not reusable, but reusability is part + * of what makes it speedy when recalculating the viewable area. + */ + private final BitSet opaqueBlocks = new BitSet(4096); + private final BitSet visibleBlocks = new BitSet(4096); + private short transparentBlocks = 4096; + private boolean dirty = true, computedVis = true; + + /** Accessing this class's fields is slow, so we let the visibility value be referenced directly. */ + private long[] visibility = new long[]{ALL_VIS}; + + private static int getIndex(int x, int y, int z) { + + return x << 0 | y << 8 | z << 4; + } + + public boolean isDirty() { + + return dirty; + } + + public boolean isRenderDirty() { + + if (isDirty()) { + return true; + } + boolean r = computedVis; + computedVis = false; + return r; + } + + public void setOpaque(int x, int y, int z, boolean opaque) { + + boolean prev = opaqueBlocks.get(getIndex(x, y, z)); + if (prev != opaque) { + opaqueBlocks.set(getIndex(x, y, z), opaque); + transparentBlocks += opaque ? -1 : 1; + dirty = true; + } + } + + public long getVisibility() { + return visibility[0]; + } + + public long[] getVisibilityArray() { + return visibility; + } + + @SuppressWarnings("unchecked") + public void computeVisibility() { + + dirty = false; + long setvisibility = 0; + + if (4096 - transparentBlocks < 256) { + setvisibility = ALL_VIS; + } else if (transparentBlocks == 0) { + setvisibility = 0; + } else { + int[] edges = EDGES; + int i = edges.length; + + visibleBlocks.andNot(visibleBlocks); + visibleBlocks.or(opaqueBlocks); + IntStack linkedlist = new IntStack(1024, 512); + for (int j = 0; j < i; ++j) { + int k = edges[j]; + + if (!opaqueBlocks.get(k)) { + setvisibility = SetVisibility.setManyVisible(setvisibility, computeVisibleFacingsFrom(k, linkedlist)); + } + linkedlist.setSize(0); + } + } + + visibility[0] = setvisibility; + computedVis = true; + } + + @SuppressWarnings("unchecked") + public Set getVisibleFacingsFrom(int x, int y, int z) { + + visibleBlocks.andNot(visibleBlocks); + visibleBlocks.or(opaqueBlocks); + return computeVisibleFacingsFrom(getIndex(x & 15, y & 15, z & 15), new IntStack(256, 512)); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private EnumSet computeVisibleFacingsFrom(int index, IntStack linkedlist) { + + EnumSet enumset = EnumSet.noneOf((Class)EnumFacing.class); + linkedlist.add(index); + BitSet blocks = this.visibleBlocks; + blocks.set(index, true); + + EnumFacing[] facings = EnumFacing.values(); + int k = facings.length; + while (!linkedlist.isEmpty()) { + int j = linkedlist.poll(); + addSides(j, enumset); + + for (int l = 0; l < k; ++l) { + EnumFacing face = facings[l]; + int i1 = stepTo(j, face); + + if (i1 >= 0 && !blocks.get(i1)) { + blocks.set(i1, true); + linkedlist.add(i1); + } + } + } + + return enumset; + } + + private void addSides(int index, Set set) { + + int j = index >> 0 & 15; + + if (j == 0) { + set.add(EnumFacing.EAST /* WEST */); + } else if (j == 15) { + set.add(EnumFacing.WEST /* EAST */); + } + + int k = index >> 8 & 15; + + if (k == 0) { + set.add(EnumFacing.DOWN); + } else if (k == 15) { + set.add(EnumFacing.UP); + } + + int l = index >> 4 & 15; + + if (l == 0) { + set.add(EnumFacing.NORTH); + } else if (l == 15) { + set.add(EnumFacing.SOUTH); + } + } + + private int stepTo(int index, EnumFacing side) { + + switch (side) { + case DOWN: + if ((index >> 8 & 15) == 0) { + return -1; + } + + return index - Y_OFFSET; + case UP: + if ((index >> 8 & 15) == 15) { + return -1; + } + + return index + Y_OFFSET; + case NORTH: + if ((index >> 4 & 15) == 0) { + return -1; + } + + return index - Z_OFFSET; + case SOUTH: + if ((index >> 4 & 15) == 15) { + return -1; + } + + return index + Z_OFFSET; + case EAST: /* WEST */ + if ((index >> 0 & 15) == 0) { + return -1; + } + + return index - X_OFFSET; + case WEST: /* EAST */ + if ((index >> 0 & 15) == 15) { + return -1; + } + + return index + X_OFFSET; + default: + return -1; + } + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/ArrayHashList.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/ArrayHashList.java new file mode 100644 index 000000000..30efcfcec --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/util/ArrayHashList.java @@ -0,0 +1,626 @@ +package org.embeddedt.archaicfix.occlusion.util; + +import com.google.common.base.Objects; +import com.google.common.primitives.Ints; + +import java.util.AbstractCollection; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +@SuppressWarnings("unchecked") +public class ArrayHashList extends AbstractCollection implements List, Cloneable, java.io.Serializable { + + private static final long serialVersionUID = 3230581060536180693L; + + protected static final class Entry { + + public final Object key; + public final int hash; + public Entry nextInBucket; + + protected Entry(Object key, int keyHash) { + + this.key = key; + this.hash = keyHash; + } + } + + protected static int hash(Object n) { + + int h = n == null ? 0 : n.hashCode(); + h ^= (h >>> 20) ^ (h >>> 12); + return h ^ (h >>> 7) ^ (h >>> 4); + } + + private static int roundUpToPowerOf2(int number) { + + return number >= Ints.MAX_POWER_OF_TWO ? Ints.MAX_POWER_OF_TWO : (number > 2) ? Integer.highestOneBit((number - 1) << 1) : 2; + } + + private transient Object[] elementData; + protected transient int size; + protected transient int mask; + protected transient Entry[] hashTable; + protected transient int modCount; + + public ArrayHashList() { + + elementData = new Object[10]; + hashTable = new Entry[8]; + mask = 7; + } + + public ArrayHashList(int size) { + + elementData = new Object[size]; + size = roundUpToPowerOf2(size) >> 1; + hashTable = new Entry[size]; + mask = size - 1; + } + + public ArrayHashList(Collection col) { + + int size = col.size(); + elementData = new Object[size]; + size = roundUpToPowerOf2(size) >> 1; + hashTable = new Entry[size]; + mask = size - 1; + addAll(col); + } + + @Override + public int size() { + + return size; + } + + protected void add(E obj, int hash) { + + ensureCapacityInternal(size + 1); + elementData[size++] = obj; + insert(new Entry(obj, hash)); + rehashIfNecessary(); + } + + @Override + public boolean add(E obj) { + + int hash = hash(obj); + if (seek(obj, hash) != null) { + return false; + } + + add(obj, hash); + + return true; + } + + @Override + public E set(int index, E obj) { + + checkElementIndex(index); + + int hash = hash(obj); + if (seek(obj, hash) != null) { + // return null; + throw new IllegalArgumentException("Duplicate entries not allowed"); + } + + ++modCount; + Entry e = seek(elementData[index], hash(elementData[index])); + delete(e); + elementData[index] = obj; + insert(new Entry(obj, hash)); + + return (E) e.key; + } + + @Override + public void add(int index, E obj) { + + checkPositionIndex(index); + + int hash = hash(obj); + if (seek(obj, hash) != null) { + throw new IllegalArgumentException("Duplicate entries not allowed"); + } + + if (index == size) { + add(obj, hash); + return; + } + + ensureCapacityInternal(++size); + System.arraycopy(elementData, index, elementData, index + 1, size - index - 1); + elementData[index] = obj; + insert(new Entry(obj, hash)); + rehashIfNecessary(); + } + + @Override + public boolean addAll(int index, Collection c) { + + if (c.size() == 0) { + return false; + } + + for (E e : c) { + add(index++, e); + } + + return true; + } + + @Override + public E get(int index) { + + checkElementIndex(index); + return index(index); + } + + @Override + public int indexOf(Object obj) { + + Entry e = seek(obj, hash(obj)); + if (e == null) { + return -1; + } + + Object o = e.key; + Object[] data = elementData; + int i = size; + while (i-- > 0) { + if (data[i] == o) { + break; + } + } + return i; + } + + @Override + public int lastIndexOf(Object o) { + + return indexOf(o); + } + + @Override + public boolean contains(Object obj) { + + return seek(obj, hash(obj)) != null; + } + + @Override + public E remove(int index) { + + checkElementIndex(index); + + E oldValue = index(index); + delete(seek(oldValue, hash(oldValue))); + fastRemove(index); + + return oldValue; + } + + @Override + public boolean remove(Object obj) { + + Entry e = seek(obj, hash(obj)); + if (e == null) { + return false; + } + + Object o = e.key; + Object[] data = elementData; + for (int i = size; i-- > 0;) { + if (data[i] == o) { + fastRemove(i); + break; + } + } + delete(e); + return true; + } + + private void fastRemove(int index) { + + modCount++; + int numMoved = size - index - 1; + if (numMoved > 0) { + System.arraycopy(elementData, index + 1, elementData, index, numMoved); + } + elementData[--size] = null; // clear to let GC do its work + } + + // { following methods (until the next }) copied mostly verbatim from ArrayList + @Override + public void clear() { + + modCount++; + + // clear to let GC do its work + for (int i = 0; i < size; i++) { + elementData[i] = null; + } + + for (int i = hashTable.length; i-- > 0;) { + hashTable[i] = null; + } + + size = 0; + } + + /** + * Trims the capacity of this ArrayHashList instance to be the list's current size. An application can use this operation to minimize the storage + * of an ArrayHashList instance. + */ + public void trimToSize() { + + ++modCount; + if (size < elementData.length) { + elementData = Arrays.copyOf(elementData, size); + } + } + + /** + * Increases the capacity of this ArrayHashList instance, if necessary, to ensure that it can hold at least the number of elements specified by the + * minimum capacity argument. + * + * @param minCapacity + * the desired minimum capacity + */ + public void ensureCapacity(int minCapacity) { + + if (minCapacity > 0) { + ensureCapacityInternal(minCapacity); + } + } + + private void ensureCapacityInternal(int minCapacity) { + + ++modCount; + // overflow-conscious code + if (minCapacity - elementData.length > 0) { + grow(minCapacity); + } + } + + /** + * The maximum size of array to allocate. Some VMs reserve some header words in an array. Attempts to allocate larger arrays may result in OutOfMemoryError: + * Requested array size exceeds VM limit + */ + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** + * Increases the capacity to ensure that it can hold at least the number of elements specified by the minimum capacity argument. + * + * @param minCapacity + * the desired minimum capacity + */ + private void grow(int minCapacity) { + + // overflow-conscious code + int oldCapacity = elementData.length; + int newCapacity = oldCapacity + (oldCapacity >> 1); + if (newCapacity - minCapacity < 0) { + newCapacity = minCapacity; + } + if (newCapacity - MAX_ARRAY_SIZE > 0) { + newCapacity = hugeCapacity(minCapacity); + } + // minCapacity is usually close to size, so this is a win: + elementData = Arrays.copyOf(elementData, newCapacity); + } + + private static int hugeCapacity(int minCapacity) { + + if (minCapacity < 0) { + throw new OutOfMemoryError(); + } + return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; + } + + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + + // Write out element count, and any hidden stuff + int expectedModCount = modCount; + s.defaultWriteObject(); + + // Write out size as capacity for behavioural compatibility with clone() + s.writeInt(size); + + // Write out all elements in the proper order. + for (int i = 0; i < size; i++) { + s.writeObject(elementData[i]); + } + + if (modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + } + + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + + elementData = new Object[10]; + hashTable = new Entry[8]; + mask = 7; + + // Read in size, and any hidden stuff + s.defaultReadObject(); + + // Read in capacity + int size = s.readInt(); + + if (size > 0) { + // be like clone(), allocate array based upon size not capacity + ensureCapacityInternal(size); + + // Read in all elements in the proper order. + for (int i = 0; i < size; i++) { + add((E) s.readObject()); + } + } + } + + // } + + E index(int index) { + + return (E) elementData[index]; + } + + protected Entry seek(Object obj, int hash) { + + for (Entry entry = hashTable[hash & mask]; entry != null; entry = entry.nextInBucket) { + if (hash == entry.hash && Objects.equal(obj, entry.key)) { + return entry; + } + } + + return null; + } + + protected void insert(Entry entry) { + + int bucket = entry.hash & mask; + entry.nextInBucket = hashTable[bucket]; + hashTable[bucket] = entry; + } + + protected void delete(Entry entry) { + + l: synchronized (hashTable) { + int bucket = entry.hash & mask; + Entry prev = null, cur = hashTable[bucket]; + if (cur == entry) { + hashTable[bucket] = cur.nextInBucket; + break l; + } + for (; true; cur = cur.nextInBucket) { + if (cur == entry) { + prev.nextInBucket = entry.nextInBucket; + break l; + } + prev = cur; + } + } + } + + protected void rehashIfNecessary() { + + Entry[] old = hashTable, newTable; + if (size > old.length * 2 && old.length < Ints.MAX_POWER_OF_TWO) { + synchronized (hashTable) { + int newTableSize = old.length * 2, newMask = newTableSize - 1; + newTable = new Entry[newTableSize]; + + for (int bucket = old.length; bucket-- > 0;) { + Entry entry = old[bucket]; + while (entry != null) { + Entry nextEntry = entry.nextInBucket; + int keyBucket = entry.hash & newMask; + entry.nextInBucket = newTable[keyBucket]; + newTable[keyBucket] = entry; + entry = nextEntry; + } + } + hashTable = newTable; + mask = newMask; + } + } + } + + @Override + public ArrayHashList clone() { + + return new ArrayHashList(this); + } + + @Override + public List subList(int fromIndex, int toIndex) { + + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } + + @Override + public Iterator iterator() { + + return new Itr(); + } + + @Override + public ListIterator listIterator() { + + return listIterator(0); + } + + @Override + public ListIterator listIterator(int index) { + + return new ListItr(index); + } + + protected boolean isElementIndex(int index) { + + return index >= 0 && index < size; + } + + protected boolean isPositionIndex(int index) { + + return index >= 0 && index <= size; + } + + protected String outOfBoundsMsg(int index) { + + return "Index: " + index + ", Size: " + size; + } + + protected void checkElementIndex(int index) { + + if (!isElementIndex(index)) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + } + + protected void checkPositionIndex(int index) { + + if (!isPositionIndex(index)) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + } + + private class Itr implements Iterator { + + int cursor; // index of next element to return + int lastRet = -1; // index of last element returned; -1 if no such + int expectedModCount = modCount; + + @Override + public boolean hasNext() { + + return cursor != size; + } + + @Override + public E next() { + + checkForComodification(); + int i = cursor; + if (i >= size) { + throw new NoSuchElementException(); + } + Object[] elementData = ArrayHashList.this.elementData; + if (i >= elementData.length) { + throw new ConcurrentModificationException(); + } + cursor = i + 1; + return (E) elementData[lastRet = i]; + } + + @Override + public void remove() { + + if (lastRet < 0) { + throw new IllegalStateException(); + } + checkForComodification(); + + try { + ArrayHashList.this.remove(lastRet); + cursor = lastRet; + lastRet = -1; + expectedModCount = modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + final void checkForComodification() { + + if (modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + } + } + + private class ListItr extends Itr implements ListIterator { + + ListItr(int index) { + + super(); + cursor = index; + } + + @Override + public boolean hasPrevious() { + + return cursor != 0; + } + + @Override + public int nextIndex() { + + return cursor; + } + + @Override + public int previousIndex() { + + return cursor - 1; + } + + @Override + @SuppressWarnings("unchecked") + public E previous() { + + checkForComodification(); + int i = cursor - 1; + if (i < 0) { + throw new NoSuchElementException(); + } + Object[] elementData = ArrayHashList.this.elementData; + if (i >= elementData.length) { + throw new ConcurrentModificationException(); + } + cursor = i; + return (E) elementData[lastRet = i]; + } + + @Override + public void set(E e) { + + if (lastRet < 0) { + throw new IllegalStateException(); + } + checkForComodification(); + + try { + ArrayHashList.this.set(lastRet, e); + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + @Override + public void add(E e) { + + checkForComodification(); + + try { + int i = cursor; + ArrayHashList.this.add(i, e); + cursor = i + 1; + lastRet = -1; + expectedModCount = modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/IdentityLinkedHashList.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/IdentityLinkedHashList.java new file mode 100644 index 000000000..f37bd7995 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/util/IdentityLinkedHashList.java @@ -0,0 +1,48 @@ +package org.embeddedt.archaicfix.occlusion.util; + +import java.util.Collection; + +@SuppressWarnings("unchecked") +public class IdentityLinkedHashList extends LinkedHashList { + + private static final long serialVersionUID = 4893829808146776641L; + + public IdentityLinkedHashList() { + + super(); + } + + public IdentityLinkedHashList(int size) { + + super(size); + } + + public IdentityLinkedHashList(Collection col) { + + super(col); + } + + @Override + protected int hash(Object o) { + + return System.identityHashCode(o); + } + + @Override + protected Entry seek(Object obj, int hash) { + + for (Entry entry = hashTable[hash & mask]; entry != null; entry = entry.nextInBucket) { + if (obj == entry.key) { + return entry; + } + } + + return null; + } + + @Override + public IdentityLinkedHashList clone() { + + return new IdentityLinkedHashList(this); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntStack.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntStack.java new file mode 100644 index 000000000..f1da2f639 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntStack.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * $Id: IntStack.java,v 1.2.4.1 2005/09/15 08:15:45 suresh_emailid Exp $ + */ +package org.embeddedt.archaicfix.occlusion.util; + +import java.util.EmptyStackException; + +/** + * Implement a stack of simple integers. + * + * %OPT% + * This is currently based on IntVector, which permits fast acess but pays a + * heavy recopying penalty if/when its size is increased. If we expect deep + * stacks, we should consider a version based on ChunkedIntVector. + * + * @xsl.usage internal + */ +public class IntStack extends IntVector { + + /** + * Default constructor. Note that the default + * block size is very small, for small lists. + */ + public IntStack() { + + super(); + } + + /** + * Construct a IntVector, using the given block size. + * + * @param blocksize + * Size of block to allocate + */ + public IntStack(int blocksize) { + + super(blocksize); + } + + /** + * Construct a IntVector, using the given block size. + * + * @param blocksize + * Size of block to allocate + */ + public IntStack(int blocksize, int increaseSize) { + + super(blocksize, increaseSize); + } + + /** + * Copy constructor for IntStack + * + * @param v + * IntStack to copy + */ + public IntStack(IntStack v) { + + super(v); + } + + /** + * Pushes an item onto the top of this stack. + * + * @param i + * the int to be pushed onto this stack. + * @return the item argument. + */ + public int push(int i) { + + if ((m_firstFree + 1) >= m_mapSize) { + m_mapSize += m_blocksize; + + int newMap[] = new int[m_mapSize]; + + System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1); + + m_map = newMap; + } + + m_map[m_firstFree] = i; + + m_firstFree++; + + return i; + } + + /** + * Removes the object at the top of this stack and returns that + * object as the value of this function. + * + * @return The object at the top of this stack. + */ + public final int pop() { + + return m_map[--m_firstFree]; + } + + /** + * Quickly pops a number of items from the stack. + */ + + public final void quickPop(int n) { + + m_firstFree -= n; + } + + /** + * Looks at the object at the top of this stack without removing it + * from the stack. + * + * @return the object at the top of this stack. + * @throws EmptyStackException + * if this stack is empty. + */ + public final int peek() { + + try { + return m_map[m_firstFree - 1]; + } catch (ArrayIndexOutOfBoundsException e) { + throw new EmptyStackException(); + } + } + + /** + * Looks at the object at the position the stack counting down n items. + * + * @param n + * The number of items down, indexed from zero. + * @return the object at n items down. + * @throws EmptyStackException + * if this stack is empty. + */ + public int peek(int n) { + + try { + return m_map[m_firstFree - (1 + n)]; + } catch (ArrayIndexOutOfBoundsException e) { + throw new EmptyStackException(); + } + } + + /** + * Sets an object at a the top of the statck + * + * + * @param val + * object to set at the top + * @throws EmptyStackException + * if this stack is empty. + */ + public void setTop(int val) { + + try { + m_map[m_firstFree - 1] = val; + } catch (ArrayIndexOutOfBoundsException e) { + throw new EmptyStackException(); + } + } + + /** + * Tests if this stack is empty. + * + * @return true if this stack is empty; false + * otherwise. + * @since JDK1.0 + */ + public boolean empty() { + + return m_firstFree == 0; + } + + /** + * Returns where an object is on this stack. + * + * @param o + * the desired object. + * @return the distance from the top of the stack where the object is] + * located; the return value -1 indicates that the + * object is not on the stack. + * @since JDK1.0 + */ + public int search(int o) { + + int i = lastIndexOf(o); + + if (i >= 0) { + return size() - i; + } + + return -1; + } + + /** + * Returns clone of current IntStack + * + * @return clone of current IntStack + */ + @Override + public Object clone() { + + return new IntStack(this); + } + + public boolean isEmpty() { + + return size() == 0; + } + + /* + @Override + public boolean contains(Object o) { + + return false; + } + + @Override + public Iterator iterator() { + + return null; + } + + @Override + public Object[] toArray() { + + return null; + } + + @Override + public Object[] toArray(Object[] a) { + + return null; + }//*/ + + public void clear() { + + setSize(0); + } + + public boolean add(int e) { + + push(e); + return true; + } + + public boolean offer(int e) { + + push(e); + return true; + } + + public int remove() { + + return pop(); + } + + public int poll() { + + return pop(); + } + + public int element() { + + return peek(0); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntVector.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntVector.java new file mode 100644 index 000000000..9ff505e3d --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntVector.java @@ -0,0 +1,403 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * $Id: IntVector.java,v 1.2.4.1 2005/09/15 08:15:45 suresh_emailid Exp $ + */ +package org.embeddedt.archaicfix.occlusion.util; + +/** + * A very simple table that stores a list of int. + * + * This version is based on a "realloc" strategy -- a simle array is + * used, and when more storage is needed, a larger array is obtained + * and all existing data is recopied into it. As a result, read/write + * access to existing nodes is O(1) fast but appending may be O(N**2) + * slow. See also SuballocatedIntVector. + * + * @xsl.usage internal + */ +public class IntVector implements Cloneable { + + /** Size of blocks to allocate */ + protected int m_blocksize; + + /** Array of ints */ + protected int m_map[]; // IntStack is trying to see this directly + + /** Number of ints in array */ + protected int m_firstFree = 0; + + /** Size of array */ + protected int m_mapSize; + + /** + * Default constructor. Note that the default + * block size is very small, for small lists. + */ + public IntVector() { + + m_blocksize = 32; + m_mapSize = m_blocksize; + m_map = new int[m_blocksize]; + } + + /** + * Construct a IntVector, using the given block size. + * + * @param blocksize + * Size of block to allocate + */ + public IntVector(int blocksize) { + + m_blocksize = blocksize; + m_mapSize = blocksize; + m_map = new int[blocksize]; + } + + /** + * Construct a IntVector, using the given block size. + * + * @param blocksize + * Size of block to allocate + */ + public IntVector(int blocksize, int increaseSize) { + + m_blocksize = increaseSize; + m_mapSize = blocksize; + m_map = new int[blocksize]; + } + + /** + * Copy constructor for IntVector + * + * @param v + * Existing IntVector to copy + */ + public IntVector(IntVector v) { + + m_map = new int[v.m_mapSize]; + m_mapSize = v.m_mapSize; + m_firstFree = v.m_firstFree; + m_blocksize = v.m_blocksize; + System.arraycopy(v.m_map, 0, m_map, 0, m_firstFree); + } + + /** + * Get the length of the list. + * + * @return length of the list + */ + public final int size() { + + return m_firstFree; + } + + /** + * Get the length of the list. + * + * @return length of the list + */ + public final void setSize(int sz) { + + m_firstFree = sz; + } + + /** + * Append a int onto the vector. + * + * @param value + * Int to add to the list + */ + public final void addElement(int value) { + + if ((m_firstFree + 1) >= m_mapSize) { + m_mapSize += m_blocksize; + + int newMap[] = new int[m_mapSize]; + + System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1); + + m_map = newMap; + } + + m_map[m_firstFree] = value; + + m_firstFree++; + } + + /** + * Append several int values onto the vector. + * + * @param value + * Int to add to the list + */ + public final void addElements(int value, int numberOfElements) { + + if ((m_firstFree + numberOfElements) >= m_mapSize) { + m_mapSize += (m_blocksize + numberOfElements); + + int newMap[] = new int[m_mapSize]; + + System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1); + + m_map = newMap; + } + + for (int i = 0; i < numberOfElements; i++) { + m_map[m_firstFree] = value; + m_firstFree++; + } + } + + /** + * Append several slots onto the vector, but do not set the values. + * + * @param numberOfElements + * Int to add to the list + */ + public final void addElements(int numberOfElements) { + + if ((m_firstFree + numberOfElements) >= m_mapSize) { + m_mapSize += (m_blocksize + numberOfElements); + + int newMap[] = new int[m_mapSize]; + + System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1); + + m_map = newMap; + } + + m_firstFree += numberOfElements; + } + + /** + * Inserts the specified node in this vector at the specified index. + * Each component in this vector with an index greater or equal to + * the specified index is shifted upward to have an index one greater + * than the value it had previously. + * + * @param value + * Int to insert + * @param at + * Index of where to insert + */ + public final void insertElementAt(int value, int at) { + + if ((m_firstFree + 1) >= m_mapSize) { + m_mapSize += m_blocksize; + + int newMap[] = new int[m_mapSize]; + + System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1); + + m_map = newMap; + } + + if (at <= (m_firstFree - 1)) { + System.arraycopy(m_map, at, m_map, at + 1, m_firstFree - at); + } + + m_map[at] = value; + + m_firstFree++; + } + + /** + * Inserts the specified node in this vector at the specified index. + * Each component in this vector with an index greater or equal to + * the specified index is shifted upward to have an index one greater + * than the value it had previously. + */ + public final void removeAllElements() { + + for (int i = 0; i < m_firstFree; i++) { + m_map[i] = Integer.MIN_VALUE; + } + + m_firstFree = 0; + } + + /** + * Removes the first occurrence of the argument from this vector. + * If the object is found in this vector, each component in the vector + * with an index greater or equal to the object's index is shifted + * downward to have an index one smaller than the value it had + * previously. + * + * @param s + * Int to remove from array + * + * @return True if the int was removed, false if it was not found + */ + public final boolean removeElement(int s) { + + for (int i = 0; i < m_firstFree; i++) { + if (m_map[i] == s) { + if ((i + 1) < m_firstFree) + System.arraycopy(m_map, i + 1, m_map, i - 1, m_firstFree - i); + else + m_map[i] = Integer.MIN_VALUE; + + m_firstFree--; + + return true; + } + } + + return false; + } + + /** + * Deletes the component at the specified index. Each component in + * this vector with an index greater or equal to the specified + * index is shifted downward to have an index one smaller than + * the value it had previously. + * + * @param i + * index of where to remove and int + */ + public final void removeElementAt(int i) { + + if (i > m_firstFree) + System.arraycopy(m_map, i + 1, m_map, i, m_firstFree); + else + m_map[i] = Integer.MIN_VALUE; + + m_firstFree--; + } + + /** + * Sets the component at the specified index of this vector to be the + * specified object. The previous component at that position is discarded. + * + * The index must be a value greater than or equal to 0 and less + * than the current size of the vector. + * + * @param value + * object to set + * @param index + * Index of where to set the object + */ + public final void setElementAt(int value, int index) { + + m_map[index] = value; + } + + /** + * Get the nth element. + * + * @param i + * index of object to get + * + * @return object at given index + */ + public final int elementAt(int i) { + + return m_map[i]; + } + + /** + * Tell if the table contains the given node. + * + * @param s + * object to look for + * + * @return true if the object is in the list + */ + public final boolean contains(int s) { + + for (int i = 0; i < m_firstFree; i++) { + if (m_map[i] == s) + return true; + } + + return false; + } + + /** + * Searches for the first occurence of the given argument, + * beginning the search at index, and testing for equality + * using the equals method. + * + * @param elem + * object to look for + * @param index + * Index of where to begin search + * @return the index of the first occurrence of the object + * argument in this vector at position index or later in the + * vector; returns -1 if the object is not found. + */ + public final int indexOf(int elem, int index) { + + for (int i = index; i < m_firstFree; i++) { + if (m_map[i] == elem) + return i; + } + + return Integer.MIN_VALUE; + } + + /** + * Searches for the first occurence of the given argument, + * beginning the search at index, and testing for equality + * using the equals method. + * + * @param elem + * object to look for + * @return the index of the first occurrence of the object + * argument in this vector at position index or later in the + * vector; returns -1 if the object is not found. + */ + public final int indexOf(int elem) { + + for (int i = 0; i < m_firstFree; i++) { + if (m_map[i] == elem) + return i; + } + + return Integer.MIN_VALUE; + } + + /** + * Searches for the first occurence of the given argument, + * beginning the search at index, and testing for equality + * using the equals method. + * + * @param elem + * Object to look for + * @return the index of the first occurrence of the object + * argument in this vector at position index or later in the + * vector; returns -1 if the object is not found. + */ + public final int lastIndexOf(int elem) { + + for (int i = (m_firstFree - 1); i >= 0; i--) { + if (m_map[i] == elem) + return i; + } + + return Integer.MIN_VALUE; + } + + /** + * Returns clone of current IntVector + * + * @return clone of current IntVector + */ + @Override + public Object clone() { + + return new IntVector(this); + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java new file mode 100644 index 000000000..e2385d4e0 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java @@ -0,0 +1,667 @@ +package org.embeddedt.archaicfix.occlusion.util; + +import com.google.common.base.Objects; +import com.google.common.primitives.Ints; + +import java.util.*; + +@SuppressWarnings("unchecked") +public class LinkedHashList extends AbstractCollection implements List, Cloneable, java.io.Serializable { + + private static final long serialVersionUID = -642033533165934945L; + + protected static final class Entry { + + protected Entry next; + protected Entry prev; + protected final Object key; + protected final int hash; + protected Entry nextInBucket; + + protected Entry(Object key, int keyHash) { + + this.key = key; + this.hash = keyHash; + } + } + + protected static int roundUpToPowerOf2(int number) { + + return number >= Ints.MAX_POWER_OF_TWO ? Ints.MAX_POWER_OF_TWO : (number > 2) ? Integer.highestOneBit((number - 1) << 1) : 2; + } + + protected transient Entry head; + protected transient Entry tail; + protected transient int size; + protected transient int mask; + protected transient Entry[] hashTable; + protected transient int modCount; + + public LinkedHashList() { + + hashTable = new Entry[8]; + mask = 7; + } + + public LinkedHashList(int size) { + + size = roundUpToPowerOf2(size); + hashTable = new Entry[size]; + mask = size - 1; + } + + public LinkedHashList(Collection col) { + + int size = roundUpToPowerOf2(col.size()); + hashTable = new Entry[size]; + mask = size - 1; + addAll(col); + } + + protected int hash(Object n) { + + int h = n == null ? 0 : n.hashCode(); + h ^= (h >>> 20) ^ (h >>> 12); + return h ^ (h >>> 7) ^ (h >>> 4); + } + + @Override + public int size() { + + return size; + } + + protected boolean add(E obj, int hash) { + + if (seek(obj, hash) != null) { + return false; + } + + Entry e; + ++modCount; + insert(e = new Entry(obj, hash)); + rehashIfNecessary(); + e.prev = tail; + e.next = null; + if (tail != null) { + tail.next = e; + } else { + head = e; + } + tail = e; + return true; + } + + @Override + public boolean add(E obj) { + + int hash = hash(obj); + return add(obj, hash); + } + + @Override + public E set(int index, E obj) { + + checkElementIndex(index); + + int hash = hash(obj); + if (seek(obj, hash) != null) { + // return null; + throw new IllegalArgumentException("Duplicate entries not allowed"); + } + + ++modCount; + Entry e = index(index); + delete(e); + insert(new Entry(obj, hash)); + + return (E) e.key; + } + + @Override + public void add(int index, E obj) { + + checkPositionIndex(index); + + int hash = hash(obj); + if (seek(obj, hash) != null) { + throw new IllegalArgumentException("Duplicate entries not allowed"); + } + + if (index == size) { + add(obj, hash); + return; + } + + ++modCount; + Entry e = index(index); + Entry n = new Entry(obj, hash); + n.next = e.next; + n.prev = e; + e.next = n; + if (n.next != null) { + n.next.prev = n; + } + insert(n); + rehashIfNecessary(); + } + + @Override + public boolean addAll(int index, Collection c) { + + if (c.size() == 0) { + return false; + } + + for (E e : c) { + add(index++, e); + } + + return true; + } + + @Override + public E get(int index) { + + checkElementIndex(index); + return (E) index(index).key; + } + + @Override + public int indexOf(Object o) { + + Entry v = seek(o, hash(o)); + if (v == null) { + return -1; + } + Entry n = head; + for (int i = 0; n != tail; ++i) { + if (v == n) { + return i; + } + n = n.next; + } + return size; + } + + @Override + public int lastIndexOf(Object o) { + + return indexOf(o); + } + + public boolean push(E obj) { + + int hash = hash(obj); + return add(obj, hash); + } + + public E pop() { + + Entry e = tail; + if (e != null) { + unlink(e); + return (E) e.key; + } + return null; + } + + public E peek() { + + return tail != null ? (E) tail.key : null; + } + + public E poke() { + + return head != null ? (E) head.key : null; + } + + public boolean unshift(E obj) { + + int hash = hash(obj); + if (seek(obj, hash) != null) { + return false; + } + + Entry e; + ++modCount; + insert(e = new Entry(obj, hash)); + rehashIfNecessary(); + e.next = head; + e.prev = null; + if (head != null) { + head.prev = e; + } else { + tail = e; + } + head = e; + return true; + } + + public E shift() { + + Entry e = head; + if (e != null) { + unlink(e); + return (E) e.key; + } + return null; + } + + @Override + public boolean contains(Object obj) { + + return seek(obj, hash(obj)) != null; + } + + @Override + public boolean remove(Object obj) { + + Entry e = seek(obj, hash(obj)); + if (e == null) { + return false; + } + + unlink(e); + return true; + } + + @Override + public E remove(int index) { + + checkElementIndex(index); + + Entry oldValue = index(index); + unlink(oldValue); + + return (E) oldValue.key; + } + + protected Entry index(int index) { + + Entry x; + if (index < (size >> 1)) { + x = head; + for (int i = index; i-- > 0;) { + x = x.next; + } + } else { + x = tail; + for (int i = size - 1; i-- > index;) { + x = x.prev; + } + } + return x; + } + + protected Entry seek(Object obj, int hash) { + + for (Entry entry = hashTable[hash & mask]; entry != null; entry = entry.nextInBucket) { + if (hash == entry.hash && Objects.equal(obj, entry.key)) { + return entry; + } + } + + return null; + } + + protected void insert(Entry entry) { + + int bucket = entry.hash & mask; + entry.nextInBucket = hashTable[bucket]; + hashTable[bucket] = entry; + ++size; + } + + protected boolean linkBefore(E obj, Entry succ) { + + int hash = hash(obj); + if (seek(obj, hash) != null) { + return false; + } + + final Entry pred = succ.prev; + final Entry newNode = new Entry(obj, hash); + modCount++; + insert(newNode); + rehashIfNecessary(); + newNode.next = succ; + newNode.prev = pred; + succ.prev = newNode; + if (pred == null) { + head = newNode; + } else { + pred.next = newNode; + } + return true; + } + + protected void delete(Entry entry) { + + l: { + int bucket = entry.hash & mask; + Entry prev = null, cur = hashTable[bucket]; + if (cur == entry) { + hashTable[bucket] = cur.nextInBucket; + break l; + } + for (; true; cur = cur.nextInBucket) { + if (cur == entry) { + prev.nextInBucket = entry.nextInBucket; + break l; + } + prev = cur; + } + } + --size; + } + + protected E unlink(Entry x) { + + final E element = (E) x.key; + final Entry next = x.next; + final Entry prev = x.prev; + + if (prev == null) { + head = next; + } else { + prev.next = next; + x.prev = null; + } + + if (next == null) { + tail = prev; + } else { + next.prev = prev; + x.next = null; + } + + delete(x); + modCount++; + return element; + } + + protected void rehashIfNecessary() { + + Entry[] old = hashTable, newTable; + if (size > old.length * 2 && old.length < Ints.MAX_POWER_OF_TWO) { + int newTableSize = old.length * 2, newMask = newTableSize - 1; + newTable = new Entry[newTableSize]; + + for (int bucket = old.length; bucket-- > 0;) { + Entry entry = old[bucket]; + while (entry != null) { + Entry nextEntry = entry.nextInBucket; + int keyBucket = entry.hash & newMask; + entry.nextInBucket = newTable[keyBucket]; + newTable[keyBucket] = entry; + entry = nextEntry; + } + } + hashTable = newTable; + mask = newMask; + } + } + + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + + // Write out element count, and any hidden stuff + int expectedModCount = modCount; + s.defaultWriteObject(); + + // Write out size as capacity for behavioural compatibility with clone() + s.writeInt(size); + + // Write out all elements in the proper order. + Entry n = head; + for (int i = 0; i < size; i++) { + s.writeObject(n.key); + n = n.next; + } + + if (modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + } + + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + + head = tail = null; + hashTable = new Entry[8]; + mask = 7; + size = 0; + + // Read in size, and any hidden stuff + s.defaultReadObject(); + + // Read in capacity + int size = s.readInt(); + + if (size > 0) { + + // Read in all elements in the proper order. + for (int i = 0; i < size; i++) { + add((E) s.readObject()); + } + } + } + + @Override + public LinkedHashList clone() { + + return new LinkedHashList(this); + } + + @Override + public List subList(int fromIndex, int toIndex) { + + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } + + @Override + public Iterator iterator() { + + return listIterator(); + } + + @Override + public ListIterator listIterator() { + + return listIterator(0); + } + + @Override + public ListIterator listIterator(int index) { + + checkPositionIndex(index); + return new ListItr(index); + } + + public Iterator descendingIterator() { + + return new DescendingIterator(); + } + + protected boolean isElementIndex(int index) { + + return index >= 0 && index < size; + } + + protected boolean isPositionIndex(int index) { + + return index >= 0 && index <= size; + } + + protected String outOfBoundsMsg(int index) { + + return "Index: " + index + ", Size: " + size; + } + + protected void checkElementIndex(int index) { + + if (!isElementIndex(index)) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + } + + protected void checkPositionIndex(int index) { + + if (!isPositionIndex(index)) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + } + + @Override + public void sort(Comparator comparator) { + ArrayList sorter = new ArrayList<>(this); + sorter.sort(comparator); + this.clear(); + this.addAll(sorter); + } + + protected class ListItr implements ListIterator { + + protected Entry lastReturned = null; + protected Entry next; + protected int nextIndex; + protected int expectedModCount = modCount; + + protected ListItr(int index) { + + next = (index == size) ? null : index(index); + nextIndex = index; + } + + @Override + public boolean hasNext() { + + return nextIndex < size; + } + + @Override + public E next() { + + checkForComodification(); + if (!hasNext()) { + throw new NoSuchElementException(); + } + + lastReturned = next; + next = next.next; + nextIndex++; + return (E) lastReturned.key; + } + + @Override + public boolean hasPrevious() { + + return nextIndex > 0; + } + + @Override + public E previous() { + + checkForComodification(); + if (!hasPrevious()) { + throw new NoSuchElementException(); + } + + lastReturned = next = (next == null) ? tail : next.prev; + nextIndex--; + return (E) lastReturned.key; + } + + @Override + public int nextIndex() { + + return nextIndex; + } + + @Override + public int previousIndex() { + + return nextIndex - 1; + } + + @Override + public void remove() { + + checkForComodification(); + if (lastReturned == null) { + throw new IllegalStateException(); + } + + Entry lastNext = lastReturned.next; + unlink(lastReturned); + if (next == lastReturned) { + next = lastNext; + } else { + nextIndex--; + } + lastReturned = null; + expectedModCount++; + } + + @Override + public void set(E e) { + + checkForComodification(); + if (lastReturned == null) { + throw new IllegalStateException(); + } + + linkBefore(e, lastReturned); + unlink(lastReturned); + lastReturned = (next == null) ? tail : next.prev; + expectedModCount += 2; + } + + @Override + public void add(E e) { + + checkForComodification(); + lastReturned = null; + if (next == null) { + push(e); + } else { + linkBefore(e, next); + } + nextIndex++; + expectedModCount++; + } + + protected final void checkForComodification() { + + if (modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + } + + } + + protected class DescendingIterator implements Iterator { + + protected final ListItr itr = new ListItr(size()); + + @Override + public boolean hasNext() { + + return itr.hasPrevious(); + } + + @Override + public E next() { + + return itr.previous(); + } + + @Override + public void remove() { + + itr.remove(); + } + + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/SynchronizedIdentityLinkedHashList.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/SynchronizedIdentityLinkedHashList.java new file mode 100644 index 000000000..3a125b0db --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/util/SynchronizedIdentityLinkedHashList.java @@ -0,0 +1,137 @@ +package org.embeddedt.archaicfix.occlusion.util; + +public class SynchronizedIdentityLinkedHashList extends IdentityLinkedHashList { + + private static final long serialVersionUID = -4821513020637725603L; + + public SynchronizedIdentityLinkedHashList() { + + } + + @Override + protected synchronized boolean add(E obj, int hash) { + + return super.add(obj, hash); + } + + @Override + public synchronized E set(int index, E obj) { + + return super.set(index, obj); + } + + @Override + public synchronized void add(int index, E obj) { + + super.add(index, obj); + } + + @Override + public synchronized E get(int index) { + + return super.get(index); + } + + @Override + public synchronized int indexOf(Object o) { + + return super.indexOf(o); + } + + @Override + public synchronized boolean push(E obj) { + + return super.add(obj); + } + + @Override + public synchronized E pop() { + + return super.pop(); + } + + @Override + public synchronized E peek() { + + return super.peek(); + } + + @Override + public synchronized E poke() { + + return super.poke(); + } + + @Override + public synchronized boolean unshift(E obj) { + + return super.unshift(obj); + } + + @Override + public synchronized E shift() { + + return super.shift(); + } + + @Override + public synchronized boolean contains(Object obj) { + + return super.contains(obj); + } + + @Override + public synchronized boolean remove(Object obj) { + + return super.remove(obj); + } + + @Override + public synchronized E remove(int index) { + + return super.remove(index); + } + + @Override + protected synchronized Entry index(int index) { + + return super.index(index); + } + + @Override + protected synchronized Entry seek(Object obj, int hash) { + + return super.seek(obj, hash); + } + + @Override + protected synchronized void insert(Entry entry) { + + super.insert(entry); + } + + @Override + protected synchronized boolean linkBefore(E obj, Entry succ) { + + return super.linkBefore(obj, succ); + } + + @Override + protected synchronized void delete(Entry entry) { + + super.delete(entry); + } + + @Override + protected synchronized E unlink(Entry x) { + + return super.unlink(x); + } + + @Override + protected synchronized void rehashIfNecessary() { + + super.rehashIfNecessary(); + } + +} diff --git a/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java b/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java new file mode 100644 index 000000000..a078367cf --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java @@ -0,0 +1,180 @@ +package org.embeddedt.archaicfix.proxy; + +import com.google.common.base.Objects; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.EventPriority; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiMainMenu; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.server.integrated.IntegratedServer; +import net.minecraft.util.Direction; +import net.minecraft.util.MathHelper; +import net.minecraft.util.MovingObjectPosition; +import net.minecraftforge.client.event.EntityViewRenderEvent; +import net.minecraftforge.client.event.GuiOpenEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.client.event.sound.SoundLoadEvent; +import net.minecraftforge.common.MinecraftForge; +import org.embeddedt.archaicfix.ArchaicLogger; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.embeddedt.archaicfix.helpers.BuiltInResourcePack; +import org.embeddedt.archaicfix.helpers.SoundDeviceThread; +import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; +import zone.rong.rongasm.api.LoliStringPool; + +import java.lang.management.ManagementFactory; +import java.util.Locale; + +public class ClientProxy extends CommonProxy { + SoundDeviceThread soundThread = null; + public static volatile boolean soundSystemReloadLock = false; + @Override + public void preinit() { + super.preinit(); + Minecraft.memoryReserve = new byte[0]; + if(ArchaicConfig.enableOcclusionTweaks) + OcclusionHelpers.init(); + MinecraftForge.EVENT_BUS.register(new LoliStringPool.EventHandler()); + MinecraftForge.EVENT_BUS.register(this); + FMLCommonHandler.instance().bus().register(this); + if(ArchaicConfig.modernizeTextures) { + BuiltInResourcePack.register("vanilla_overrides"); + } + } + + float lastIntegratedTickTime; + @SubscribeEvent + public void onTick(TickEvent.ServerTickEvent event) { + if(FMLCommonHandler.instance().getSide().isClient() && event.phase == TickEvent.Phase.END) { + IntegratedServer srv = Minecraft.getMinecraft().getIntegratedServer(); + if(srv != null) { + long currentTickTime = srv.tickTimeArray[srv.getTickCounter() % 100]; + lastIntegratedTickTime = lastIntegratedTickTime * 0.8F + (float)currentTickTime / 1000000.0F * 0.2F; + } else + lastIntegratedTickTime = 0; + } + } + + private float gameStartTime = -1; + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onGuiOpen(GuiOpenEvent event) { + if(!event.isCanceled() && event.gui instanceof GuiMainMenu && gameStartTime == -1) { + gameStartTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f; + ArchaicLogger.LOGGER.info("The game loaded in " + gameStartTime + " seconds."); + } + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onRenderOverlay(RenderGameOverlayEvent.Text event) { + Minecraft mc = Minecraft.getMinecraft(); + if(event.isCanceled() || !mc.gameSettings.showDebugInfo || event.left.size() < 1) + return; + NetHandlerPlayClient cl = mc.getNetHandler(); + if(cl != null) { + IntegratedServer srv = mc.getIntegratedServer(); + + if (srv != null) { + String s = String.format("Integrated server @ %.0f ms ticks", lastIntegratedTickTime); + event.left.add(1, s); + } + } + if(ArchaicConfig.showBlockDebugInfo && mc.objectMouseOver != null && mc.objectMouseOver.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) { + if(!event.right.isEmpty() && Objects.firstNonNull(event.right.get(event.right.size() - 1), "").length() > 0) + event.right.add(""); + Block block = mc.theWorld.getBlock(mc.objectMouseOver.blockX, mc.objectMouseOver.blockY, mc.objectMouseOver.blockZ); + int meta = mc.theWorld.getBlockMetadata(mc.objectMouseOver.blockX, mc.objectMouseOver.blockY, mc.objectMouseOver.blockZ); + event.right.add(Block.blockRegistry.getNameForObject(block)); + event.right.add("meta: " + meta); + } + if(ArchaicConfig.modernizeF3Screen) { + boolean hasReplacedXYZ = false; + for(int i = 0; i < event.left.size() - 3; i++) { + /* These checks should not be inefficient as most of the time the first one will already fail */ + if(!hasReplacedXYZ && Objects.firstNonNull(event.left.get(i), "").startsWith("x:") + && Objects.firstNonNull(event.left.get(i + 1), "").startsWith("y:") + && Objects.firstNonNull(event.left.get(i + 2), "").startsWith("z:") + && Objects.firstNonNull(event.left.get(i + 3), "").startsWith("f:")) { + hasReplacedXYZ = true; + int heading = MathHelper.floor_double((double)(mc.thePlayer.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3; + String heading_str; + switch(heading) { + case 0: + heading_str = "Towards positive Z"; + break; + case 1: + heading_str = "Towards negative X"; + break; + case 2: + heading_str = "Towards negative Z"; + break; + case 3: + heading_str = "Towards positive X"; + break; + default: + throw new RuntimeException(); + } + event.left.set(i, String.format("XYZ: %.3f / %.5f / %.3f", mc.thePlayer.posX, mc.thePlayer.boundingBox.minY, mc.thePlayer.posZ)); + int blockX = MathHelper.floor_double(mc.thePlayer.posX); + int blockY = MathHelper.floor_double(mc.thePlayer.boundingBox.minY); + int blockZ = MathHelper.floor_double(mc.thePlayer.posZ); + event.left.set(i + 1, String.format("Block: %d %d %d [%d %d %d]", blockX, blockY, blockZ, blockX & 15, blockY & 15, blockZ & 15)); + event.left.set(i + 2, String.format("Chunk: %d %d %d", blockX >> 4, blockY >> 4, blockZ >> 4)); + event.left.set(i + 3, String.format("Facing: %s (%s) (%.1f / %.1f)", Direction.directions[heading].toLowerCase(Locale.ROOT), heading_str, MathHelper.wrapAngleTo180_float(mc.thePlayer.rotationYaw), MathHelper.wrapAngleTo180_float(mc.thePlayer.rotationPitch))); + } + } + event.setCanceled(true); + /* render ourselves */ + FontRenderer fontrenderer = mc.fontRenderer; + int fontColor = 0xe0e0e0; + int rectColor = 0x90505050; + for (int x = 0; x < event.left.size(); x++) + { + String msg = event.left.get(x); + if (msg == null) continue; + int strX = 2; + int strY = 2 + x * fontrenderer.FONT_HEIGHT; + Gui.drawRect(1, strY - 1, strX + fontrenderer.getStringWidth(msg) + 1, strY + fontrenderer.FONT_HEIGHT - 1, rectColor); + fontrenderer.drawString(msg, strX, strY, fontColor); + } + int width = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight).getScaledWidth(); + for (int x = 0; x < event.right.size(); x++) + { + String msg = event.right.get(x); + if (msg == null) continue; + int w = fontrenderer.getStringWidth(msg); + int strX = width - w - 2; + int strY = 2 + x * fontrenderer.FONT_HEIGHT; + Gui.drawRect(strX - 1, strY - 1, strX + w + 1, strY + fontrenderer.FONT_HEIGHT - 1, rectColor); + fontrenderer.drawString(msg, strX, strY, fontColor); + } + } + } + + @SubscribeEvent + public void onSoundSetup(SoundLoadEvent event) { + soundSystemReloadLock = false; + if(soundThread == null) { + ArchaicLogger.LOGGER.info("Starting sound device thread"); + soundThread = new SoundDeviceThread(); + soundThread.start(); + } + } + + /* coerce NaN fog values back to 0 (https://bugs.mojang.com/browse/MC-10480) */ + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onFogColor(EntityViewRenderEvent.FogColors event) { + if(Float.isNaN(event.red)) + event.red = 0f; + if(Float.isNaN(event.green)) + event.green = 0f; + if(Float.isNaN(event.blue)) + event.blue = 0f; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java b/src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java new file mode 100644 index 000000000..fd65160e2 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java @@ -0,0 +1,18 @@ +package org.embeddedt.archaicfix.proxy; + +import ca.fxco.memoryleakfix.MemoryLeakFix; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import zone.rong.rongasm.api.LoliHelpers; + +public class CommonProxy { + public void preinit() { + + } + + public void loadcomplete() { + if(ArchaicConfig.clearMixinCache) + MemoryLeakFix.forceLoadAllMixinsAndClearSpongePoweredCache(); + if(ArchaicConfig.clearLaunchLoaderCache) + LoliHelpers.cleanupLaunchClassLoader(); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/recipe/LastMatchedInfo.java b/src/main/java/org/embeddedt/archaicfix/recipe/LastMatchedInfo.java new file mode 100644 index 000000000..d52295747 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/recipe/LastMatchedInfo.java @@ -0,0 +1,70 @@ +package org.embeddedt.archaicfix.recipe; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; + +public class LastMatchedInfo { + public final IRecipe recipe; + int hash; + ItemStack[] invItems; + + public LastMatchedInfo(IRecipe recipe, InventoryCrafting inventory) { + invItems = new ItemStack[inventory.getSizeInventory()]; + for(int i = 0; i < invItems.length; i++) { + ItemStack stack = inventory.getStackInSlot(i); + invItems[i] = stack != null ? stack.copy() : null; + } + this.recipe = recipe; + hash = getHash(inventory); + } + + private boolean matchesSavedInventory(InventoryCrafting inventory) { + if(invItems == null) + return false; + if(invItems.length != inventory.getSizeInventory()) + return false; + for(int i = 0; i < invItems.length; i++) { + ItemStack newStack = inventory.getStackInSlot(i); + /* they definitely match */ + if(invItems[i] == null && newStack == null) + continue; + /* they don't match */ + if(invItems[i] == null || newStack == null) + return false; + /* now we know they are both non-null */ + if(!invItems[i].isItemEqual(newStack) || !ItemStack.areItemStackTagsEqual(invItems[i], newStack)) + return false; + } + return true; + } + + public boolean matches(InventoryCrafting crafting) { + if(getHash(crafting) != hash) + return false; + return matchesSavedInventory(crafting); + } + + public ItemStack getCraftingResult(InventoryCrafting inventory) { + if(recipe != null) + return recipe.getCraftingResult(inventory); + return null; + } + + private int getHash(InventoryCrafting inventory) { + int result = 1; + for(int i = 0; i < inventory.getSizeInventory(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + int hashCode = 1; + if(stack != null) { + //hashCode = 31 * hashCode + stack.stackSize; + hashCode = 31 * hashCode + Item.getIdFromItem(stack.getItem()); + hashCode = 31 * hashCode + stack.getItemDamage(); + hashCode = 31 * hashCode + (!stack.hasTagCompound() ? 0 : stack.getTagCompound().hashCode()); + } + result = 17 * result + hashCode; + } + return result; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java b/src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java new file mode 100644 index 000000000..cf78615e0 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java @@ -0,0 +1,41 @@ +package org.embeddedt.archaicfix.recipe; + +import com.google.common.cache.CacheLoader; +import net.minecraft.item.Item; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; + +import java.util.List; +import java.util.Set; + +/** + * Helper class that determines the set of all crafting recipes that utilize a given set of items. + */ +public class RecipeCacheLoader extends CacheLoader, IRecipe[]> { + private static final IRecipe[] NO_RECIPES = new IRecipe[0]; + @Override + public IRecipe[] load(Set key) throws Exception { + List recipes = CraftingManager.getInstance().getRecipeList(); + if (key.size() == 0) { + return NO_RECIPES; /* no recipes that utilize no items */ + } + return recipes.parallelStream() + .filter(recipe -> { + if (!(recipe instanceof IAcceleratedRecipe)) + return true; + Set potentialItems = ((IAcceleratedRecipe) recipe).getPotentialItems(); + if (potentialItems == null) { + /* The recipe can accept an unbounded set of items */ + return true; + } + for (Item item : key) { + /* If the recipe would never make use of an item we have, don't include it in the final list */ + if (!potentialItems.contains(item)) + return false; + } + return true; + }) + .toArray(IRecipe[]::new); + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/recipe/RecipeWeigher.java b/src/main/java/org/embeddedt/archaicfix/recipe/RecipeWeigher.java new file mode 100644 index 000000000..a57304f1a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/recipe/RecipeWeigher.java @@ -0,0 +1,14 @@ +package org.embeddedt.archaicfix.recipe; + +import com.google.common.cache.Weigher; +import net.minecraft.item.Item; +import net.minecraft.item.crafting.IRecipe; + +import java.util.Set; + +public class RecipeWeigher implements Weigher, IRecipe[]> { + @Override + public int weigh(Set key, IRecipe[] value) { + return value.length; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/threadedupdates/ICapturableTessellator.java b/src/main/java/org/embeddedt/archaicfix/threadedupdates/ICapturableTessellator.java new file mode 100644 index 000000000..e0c71f153 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/threadedupdates/ICapturableTessellator.java @@ -0,0 +1,16 @@ +package org.embeddedt.archaicfix.threadedupdates; + +import net.minecraft.client.shader.TesselatorVertexState; + +public interface ICapturableTessellator { + + /** Like getVertexState, but doesn't sort the quads. */ + TesselatorVertexState arch$getUnsortedVertexState(); + + /** Adds the quads inside a TessellatorVertexState to this tessellator. */ + void arch$addTessellatorVertexState(TesselatorVertexState state); + + /** Flushes the tessellator's state similarly to draw(), but without drawing anything. */ + void discard(); + +} diff --git a/src/main/java/org/embeddedt/archaicfix/threadedupdates/IRendererUpdateResultHolder.java b/src/main/java/org/embeddedt/archaicfix/threadedupdates/IRendererUpdateResultHolder.java new file mode 100644 index 000000000..ffd10a80c --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/threadedupdates/IRendererUpdateResultHolder.java @@ -0,0 +1,7 @@ +package org.embeddedt.archaicfix.threadedupdates; + +public interface IRendererUpdateResultHolder { + + ThreadedChunkUpdateHelper.UpdateTask arch$getRendererUpdateTask(); + +} diff --git a/src/main/java/org/embeddedt/archaicfix/threadedupdates/RenderBlocksStack.java b/src/main/java/org/embeddedt/archaicfix/threadedupdates/RenderBlocksStack.java new file mode 100644 index 000000000..1a277d51a --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/threadedupdates/RenderBlocksStack.java @@ -0,0 +1,34 @@ +package org.embeddedt.archaicfix.threadedupdates; + +/** A helper class to detect re-entrance of renderBlockByRenderType. */ +public class RenderBlocksStack { + + private int level; + + /** Re-entrance should be impossible on the render threads, since only vanilla blocks are rendered there. So let's + * just assume this is the case. + */ + private boolean isMainThread() { + return Thread.currentThread() == ThreadedChunkUpdateHelper.MAIN_THREAD; + } + + public void push() { + if(!isMainThread()) return; + level++; + } + + public void pop() { + if(!isMainThread()) return; + level--; + } + + public void reset() { + if(!isMainThread()) return; + level = 0; + } + + public int getLevel() { + if(!isMainThread()) return 0; + return level; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java b/src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java new file mode 100644 index 000000000..7dc5e55f6 --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java @@ -0,0 +1,323 @@ +package org.embeddedt.archaicfix.threadedupdates; + +import static org.embeddedt.archaicfix.ArchaicLogger.LOGGER; + +import com.google.common.base.Preconditions; +import lombok.SneakyThrows; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.shader.TesselatorVertexState; +import net.minecraft.world.ChunkCache; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.embeddedt.archaicfix.occlusion.IRenderGlobalListener; +import org.embeddedt.archaicfix.occlusion.IRendererUpdateOrderProvider; +import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; + +import java.util.*; +import java.util.concurrent.*; + +public class ThreadedChunkUpdateHelper implements IRenderGlobalListener { + + public static ThreadedChunkUpdateHelper instance; + + public static Thread MAIN_THREAD; + + private static final boolean DEBUG_THREADED_UPDATE_FINE_LOG = Boolean.parseBoolean(System.getProperty("archaicfix.debug.enableThreadedUpdateFineLog")); + + /** Used within the scope of WorldRenderer#updateRenderer (on the main thread). */ + public static WorldRenderer lastWorldRenderer; + + public static final RenderBlocksStack renderBlocksStack = new RenderBlocksStack(); + + /** Tasks not yet started */ + public BlockingQueue taskQueue = new LinkedBlockingDeque<>(); + /** Finished tasks ready for consumption */ + public BlockingDeque finishedTasks = new LinkedBlockingDeque<>(); + + /** Tasks that should be completed immediately on the main thread */ + public Queue urgentTaskQueue = new ArrayDeque<>(); + + public ThreadLocal threadTessellator = ThreadLocal.withInitial(Tessellator::new); + + IRendererUpdateOrderProvider rendererUpdateOrderProvider = new IRendererUpdateOrderProvider() { + /** The renderers updated during the batch */ + private List updatedRenderers = new ArrayList<>(); + + private WorldRenderer nextRenderer; + + @Override + public void prepare(List worldRenderersToUpdateList) { + preRendererUpdates(worldRenderersToUpdateList); + } + + @Override + public boolean hasNext(List worldRenderersToUpdateList) { + WorldRenderer wr; + + if(!urgentTaskQueue.isEmpty()) { + nextRenderer = urgentTaskQueue.poll(); + UpdateTask task = ((IRendererUpdateResultHolder)nextRenderer).arch$getRendererUpdateTask(); + task.cancelled = true; + return true; + } + + while((wr = finishedTasks.poll()) != null) { + UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); + if(task.cancelled || !wr.needsUpdate) { + task.clear(); + } else { + nextRenderer = wr; + return true; + } + } + return false; + } + + @Override + public WorldRenderer next(List worldRenderersToUpdateList) { + Preconditions.checkNotNull(nextRenderer); + WorldRenderer wr = nextRenderer; + nextRenderer = null; + updatedRenderers.add(wr); + + debugLog("Consuming renderer " + worldRendererToString(wr) + " " + worldRendererUpdateTaskToString(wr)); + + return wr; + } + + @Override + public void cleanup(List worldRenderersToUpdateList) { + for(WorldRenderer wr : updatedRenderers) { + worldRenderersToUpdateList.remove(wr); + ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask().clear(); + } + updatedRenderers.clear(); + urgentTaskQueue.clear(); + nextRenderer = null; + } + }; + + public void init() { + OcclusionHelpers.renderer.arch$setRendererUpdateOrderProvider(rendererUpdateOrderProvider); + OcclusionHelpers.renderer.arch$addRenderGlobalListener(this); + MAIN_THREAD = Thread.currentThread(); + + LOGGER.info("Creating " + ArchaicConfig.numChunkUpdateThreads + " chunk builder" + (ArchaicConfig.numChunkUpdateThreads > 1 ? "s" : "")); + for(int i = 0; i < ArchaicConfig.numChunkUpdateThreads; i++) { + new Thread(this::runThread, "Chunk Update Worker Thread #" + i).start(); + } + } + + private void preRendererUpdates(List toUpdateList) { + updateWorkQueue(toUpdateList); + removeCancelledResults(); + } + + private void updateWorkQueue(List toUpdateList) { + final int updateQueueSize = 64; // TODO decide this dynamically + taskQueue.clear(); + for(int i = 0; i < updateQueueSize && i < toUpdateList.size(); i++) { + WorldRenderer wr = toUpdateList.get(i); + UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); + + if(wr.distanceToEntitySquared(Minecraft.getMinecraft().renderViewEntity) < 16 * 16) { + if(!ArchaicConfig.disableBlockingChunkUpdates){ + urgentTaskQueue.add(wr); + } else { + task.important = true; + } + } + + if(task.isEmpty()) { + // No update in progress; add to task queue + debugLog("Adding " + worldRendererToString(wr) + " to task queue"); + task.chunkCache = getChunkCacheSnapshot(wr); + taskQueue.add(wr); + } + } + } + + private void removeCancelledResults() { + for(Iterator it = finishedTasks.iterator(); it.hasNext(); ) { + WorldRenderer wr = it.next(); + UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); + if(task.cancelled) { + // Discard results and allow re-schedule on worker thread. + task.clear(); + it.remove(); + } + } + } + + @Override + public void onDirtyRendererChanged(WorldRenderer wr) { + onWorldRendererDirty(wr); + } + + public void onWorldRendererDirty(WorldRenderer wr) { + UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); + if(!task.isEmpty()) { + debugLog("Renderer " + worldRendererToString(wr) + " is dirty, cancelling task"); + task.cancelled = true; + } + } + + @SneakyThrows + private void runThread() { + while(true) { + WorldRenderer wr = taskQueue.take(); + UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); + task.started = true; + try { + doChunkUpdate(wr); + } catch(Exception e) { + LOGGER.error("Failed to update chunk " + worldRendererToString(wr)); + e.printStackTrace(); + for(UpdateTask.Result r : task.result) { + r.clear(); + } + ((ICapturableTessellator)threadTessellator.get()).discard(); + } + if(!task.important) { + finishedTasks.add(wr); + } else { + finishedTasks.addFirst(wr); + } + + } + } + + /** Renders certain blocks (as defined in canBlockBeRenderedOffThread) on the worker thread, and saves the + * tessellation result. WorldRenderer#updateRenderer will skip over these blocks, and use the result that was + * produced by the worker thread to fill them in. + */ + public void doChunkUpdate(WorldRenderer wr) { + debugLog("Starting update of renderer " + worldRendererToString(wr)); + + UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); + + ChunkCache chunkcache = task.chunkCache; + + Tessellator tess = threadTessellator.get(); + + if(chunkcache != null && !chunkcache.extendedLevelsInChunkCache()) { + RenderBlocks renderblocks = new RenderBlocks(chunkcache); + + for(int pass = 0; pass < 2; pass++) { + boolean renderedSomething = false; + boolean startedTessellator = false; + + BlockLoop: + for (int y = wr.posY; y < wr.posY + 16; ++y) { + for (int z = wr.posZ; z < wr.posZ + 16; ++z) { + for (int x = wr.posX; x < wr.posX + 16; ++x) { + if(task.cancelled) { + debugLog("Realized renderer " + worldRendererToString(wr) + " is dirty, aborting update"); + break BlockLoop; + } + + Block block = chunkcache.getBlock(x, y, z); + + if (block.getMaterial() != Material.air) { + if (!startedTessellator) { + startedTessellator = true; + tess.startDrawingQuads(); + tess.setTranslation(-wr.posX, -wr.posY, -wr.posZ); + } + + int k3 = block.getRenderBlockPass(); + + if (!block.canRenderInPass(pass)) continue; + + renderedSomething |= renderblocks.renderBlockByRenderType(block, x, y, z); + } + } + } + } + + if (startedTessellator) { + task.result[pass].renderedQuads = ((ICapturableTessellator) tess).arch$getUnsortedVertexState(); + ((ICapturableTessellator) tess).discard(); + } + task.result[pass].renderedSomething = renderedSomething; + } + } + debugLog("Result of updating " + worldRendererToString(wr) + ": " + worldRendererUpdateTaskToString(wr)); + } + + public static boolean canBlockBeRenderedOffThread(Block block, int pass, int renderType) { + return renderType < 42 && renderType != 22; // vanilla block + } + + private ChunkCache getChunkCacheSnapshot(WorldRenderer wr) { + // TODO This is not thread-safe! Actually make a snapshot here. + byte pad = 1; + ChunkCache chunkcache = new ChunkCache(wr.worldObj, wr.posX - pad, wr.posY - pad, wr.posZ - pad, + wr.posX + 16 + pad, wr.posY + 16 + pad, wr.posZ + 16 + pad, pad); + return chunkcache; + } + + public void clear() { + // TODO: destroy state when chunks are reloaded or server is stopped + } + + public Tessellator getThreadTessellator() { + if(Thread.currentThread() == MAIN_THREAD) { + return Tessellator.instance; + } else { + return threadTessellator.get(); + } + } + + private static String worldRendererToString(WorldRenderer wr) { + return wr + "(" + wr.posX + ", " + wr.posY + ", " + wr.posZ + ")"; + } + + private static String worldRendererUpdateTaskToString(WorldRenderer wr) { + UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); + return task.result[0].renderedSomething + " (" + (task.result[0].renderedQuads == null ? "null" : task.result[0].renderedQuads.getVertexCount()) + ")/" + task.result[1].renderedSomething + " (" + (task.result[1].renderedQuads == null ? "null" : task.result[1].renderedQuads.getVertexCount()) + ")"; + } + + private static void debugLog(String msg) { + if(DEBUG_THREADED_UPDATE_FINE_LOG) { + LOGGER.trace(msg); + } + } + + public static class UpdateTask { + public boolean started; + public boolean cancelled; + public boolean important; + public Result[] result = new Result[]{new Result(), new Result()}; + + public ChunkCache chunkCache; + + public boolean isEmpty() { + return !started; + } + + public void clear() { + started = false; + chunkCache = null; + for(Result r : result) { + r.clear(); + } + cancelled = false; + important = false; + } + + public static class Result { + public boolean renderedSomething; + public TesselatorVertexState renderedQuads; + + public void clear() { + renderedSomething = false; + renderedQuads = null; + } + } + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/threadedupdates/api/ThreadedChunkUpdates.java b/src/main/java/org/embeddedt/archaicfix/threadedupdates/api/ThreadedChunkUpdates.java new file mode 100644 index 000000000..e0ee7379e --- /dev/null +++ b/src/main/java/org/embeddedt/archaicfix/threadedupdates/api/ThreadedChunkUpdates.java @@ -0,0 +1,17 @@ +package org.embeddedt.archaicfix.threadedupdates.api; + +import net.minecraft.client.renderer.Tessellator; +import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; + +public class ThreadedChunkUpdates { + + public static boolean isEnabled() { + return ThreadedChunkUpdateHelper.instance != null; + } + + /** Returns the thread-local tessellator instance. Can only be called after init phase. */ + public static Tessellator getThreadTessellator() { + return ThreadedChunkUpdateHelper.instance.getThreadTessellator(); + } + +} diff --git a/src/main/java/speiger/src/collections/booleans/functions/BooleanComparator.java b/src/main/java/speiger/src/collections/booleans/functions/BooleanComparator.java new file mode 100644 index 000000000..7c33854a8 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/BooleanComparator.java @@ -0,0 +1,70 @@ +package speiger.src.collections.booleans.functions; + +import java.util.Comparator; +import java.util.Objects; + +/** + * Type-Specific Class for Comparator to reduce (un)boxing + */ +public interface BooleanComparator extends Comparator +{ + /** + * Type-Specific compare function to reduce (un)boxing + * @param o1 the first object to be compared. + * @param o2 the second object to be compared. + * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. + * @see Comparator#compare(Object, Object) + */ + int compare(boolean o1, boolean o2); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default int compare(Boolean o1, Boolean o2) { + return compare(o1.booleanValue(), o2.booleanValue()); + } + + /** + * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator + * @param c comparator to convert + * @return the wrapper of the comparator + * @throws NullPointerException if the comparator is null + */ + public static BooleanComparator of(Comparator c) { + Objects.requireNonNull(c); + return (K, V) -> c.compare(Boolean.valueOf(K), Boolean.valueOf(V)); + } + + @Override + public default BooleanComparator reversed() { + return new Reversed(this); + } + + /** + * A Type Specific Reversed Comparator to reduce boxing/unboxing + */ + static class Reversed implements BooleanComparator + { + BooleanComparator original; + + /** + * default constructor + * @param original that is going to be reversed + */ + public Reversed(BooleanComparator original) { + this.original = original; + } + + public int compare(boolean o1, boolean o2) { + return original.compare(o2, o1); + } + + @Override + public BooleanComparator reversed() { + return original; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/BooleanConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/BooleanConsumer.java new file mode 100644 index 000000000..c1bae90d4 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/BooleanConsumer.java @@ -0,0 +1,48 @@ +package speiger.src.collections.booleans.functions; + +import java.util.Objects; +import java.util.function.Consumer; +/** + * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +@FunctionalInterface +public interface BooleanConsumer extends Consumer +{ + /** + * Type-Specific function to reduce (un)boxing. + * Performs this operation on the given argument. + * + * @param t the input argument + */ + void accept(boolean t); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced consumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default BooleanConsumer andThen(BooleanConsumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(T);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Boolean t) { accept(t.booleanValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default BooleanConsumer andThen(Consumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(Boolean.valueOf(T));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/BooleanSupplier.java b/src/main/java/speiger/src/collections/booleans/functions/BooleanSupplier.java new file mode 100644 index 000000000..ea1f2dcc5 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/BooleanSupplier.java @@ -0,0 +1,12 @@ +package speiger.src.collections.booleans.functions; + +/** + * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +public interface BooleanSupplier +{ + /** + * @return the supplied value + */ + public boolean getAsBoolean(); +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanBooleanConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanBooleanConsumer.java new file mode 100644 index 000000000..edc30210f --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanBooleanConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.booleans.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface BooleanBooleanConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(boolean k, boolean v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default BooleanBooleanConsumer andThen(BooleanBooleanConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Boolean k, Boolean v) { accept(k.booleanValue(), v.booleanValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default BooleanBooleanConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Boolean.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanByteConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanByteConsumer.java new file mode 100644 index 000000000..5304d1866 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanByteConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.booleans.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface BooleanByteConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(boolean k, byte v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default BooleanByteConsumer andThen(BooleanByteConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Boolean k, Byte v) { accept(k.booleanValue(), v.byteValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default BooleanByteConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Byte.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanCharConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanCharConsumer.java new file mode 100644 index 000000000..46bfe23a5 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanCharConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.booleans.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface BooleanCharConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(boolean k, char v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default BooleanCharConsumer andThen(BooleanCharConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Boolean k, Character v) { accept(k.booleanValue(), v.charValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default BooleanCharConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Character.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanDoubleConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanDoubleConsumer.java new file mode 100644 index 000000000..2b03c5b36 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanDoubleConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.booleans.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface BooleanDoubleConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(boolean k, double v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default BooleanDoubleConsumer andThen(BooleanDoubleConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Boolean k, Double v) { accept(k.booleanValue(), v.doubleValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default BooleanDoubleConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Double.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanFloatConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanFloatConsumer.java new file mode 100644 index 000000000..26d150783 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanFloatConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.booleans.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface BooleanFloatConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(boolean k, float v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default BooleanFloatConsumer andThen(BooleanFloatConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Boolean k, Float v) { accept(k.booleanValue(), v.floatValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default BooleanFloatConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Float.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanIntConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanIntConsumer.java new file mode 100644 index 000000000..1268cc6c1 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanIntConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.booleans.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface BooleanIntConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(boolean k, int v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default BooleanIntConsumer andThen(BooleanIntConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Boolean k, Integer v) { accept(k.booleanValue(), v.intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default BooleanIntConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Integer.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanLongConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanLongConsumer.java new file mode 100644 index 000000000..bd7c17fb2 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanLongConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.booleans.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface BooleanLongConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(boolean k, long v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default BooleanLongConsumer andThen(BooleanLongConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Boolean k, Long v) { accept(k.booleanValue(), v.longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default BooleanLongConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Long.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanObjectConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanObjectConsumer.java new file mode 100644 index 000000000..8cda2d073 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanObjectConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.booleans.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface BooleanObjectConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(boolean k, V v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default BooleanObjectConsumer andThen(BooleanObjectConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Boolean k, V v) { accept(k.booleanValue(), v); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default BooleanObjectConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), V);}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanShortConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanShortConsumer.java new file mode 100644 index 000000000..9169b38c3 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanShortConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.booleans.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface BooleanShortConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(boolean k, short v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default BooleanShortConsumer andThen(BooleanShortConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Boolean k, Short v) { accept(k.booleanValue(), v.shortValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default BooleanShortConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Short.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ByteFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ByteFunction.java new file mode 100644 index 000000000..e54db5048 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ByteFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.booleans.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Boolean2ByteFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public byte applyAsByte(boolean k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2CharFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2CharFunction.java new file mode 100644 index 000000000..3b17a61f4 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2CharFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.booleans.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Boolean2CharFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public char applyAsChar(boolean k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2DoubleFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2DoubleFunction.java new file mode 100644 index 000000000..312b9bc7c --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2DoubleFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.booleans.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Boolean2DoubleFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public double applyAsDouble(boolean k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2FloatFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2FloatFunction.java new file mode 100644 index 000000000..1be0cdff6 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2FloatFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.booleans.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Boolean2FloatFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public float applyAsFloat(boolean k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2IntFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2IntFunction.java new file mode 100644 index 000000000..145f4fa7d --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2IntFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.booleans.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Boolean2IntFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public int applyAsInt(boolean k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2LongFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2LongFunction.java new file mode 100644 index 000000000..dc27b5080 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2LongFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.booleans.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Boolean2LongFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public long applyAsLong(boolean k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ShortFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ShortFunction.java new file mode 100644 index 000000000..0061ac27c --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ShortFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.booleans.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Boolean2ShortFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public short applyAsShort(boolean k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanBooleanUnaryOperator.java new file mode 100644 index 000000000..921b6718d --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanBooleanUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.booleans.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface BooleanBooleanUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public boolean applyAsBoolean(boolean k, boolean v); + + @Override + public default Boolean apply(Boolean k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.booleanValue(), v.booleanValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanByteUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanByteUnaryOperator.java new file mode 100644 index 000000000..967a61f3f --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanByteUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.booleans.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface BooleanByteUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public byte applyAsByte(boolean k, byte v); + + @Override + public default Byte apply(Boolean k, Byte v) { return Byte.valueOf(applyAsByte(k.booleanValue(), v.byteValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanCharUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanCharUnaryOperator.java new file mode 100644 index 000000000..1af5f651f --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanCharUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.booleans.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface BooleanCharUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public char applyAsChar(boolean k, char v); + + @Override + public default Character apply(Boolean k, Character v) { return Character.valueOf(applyAsChar(k.booleanValue(), v.charValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanDoubleUnaryOperator.java new file mode 100644 index 000000000..b63f208dc --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanDoubleUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.booleans.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface BooleanDoubleUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public double applyAsDouble(boolean k, double v); + + @Override + public default Double apply(Boolean k, Double v) { return Double.valueOf(applyAsDouble(k.booleanValue(), v.doubleValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFloatUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFloatUnaryOperator.java new file mode 100644 index 000000000..9c6e05102 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFloatUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.booleans.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface BooleanFloatUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public float applyAsFloat(boolean k, float v); + + @Override + public default Float apply(Boolean k, Float v) { return Float.valueOf(applyAsFloat(k.booleanValue(), v.floatValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFunction.java new file mode 100644 index 000000000..ba141ca6b --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.booleans.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface BooleanFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public V apply(boolean k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanIntUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanIntUnaryOperator.java new file mode 100644 index 000000000..d75ace711 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanIntUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.booleans.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface BooleanIntUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public int applyAsInt(boolean k, int v); + + @Override + public default Integer apply(Boolean k, Integer v) { return Integer.valueOf(applyAsInt(k.booleanValue(), v.intValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanLongUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanLongUnaryOperator.java new file mode 100644 index 000000000..43fdeda94 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanLongUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.booleans.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface BooleanLongUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public long applyAsLong(boolean k, long v); + + @Override + public default Long apply(Boolean k, Long v) { return Long.valueOf(applyAsLong(k.booleanValue(), v.longValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanObjectUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanObjectUnaryOperator.java new file mode 100644 index 000000000..6f6cdc12a --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanObjectUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.booleans.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface BooleanObjectUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public V apply(boolean k, V v); + + @Override + public default V apply(Boolean k, V v) { return apply(k.booleanValue(), v); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanPredicate.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanPredicate.java new file mode 100644 index 000000000..b8e690fe8 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanPredicate.java @@ -0,0 +1,98 @@ +package speiger.src.collections.booleans.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface BooleanPredicate +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public boolean test(boolean k); + + /** + * Creates a Default function that returns the input provided. + * @return a input returning function + */ + public static BooleanPredicate identity() { + return T -> T; + } + + /** + * Returns a composed function that first applies the {@code before} + * function to its input, and then applies this function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param before the function that should be used first + * @return a composed function with a different starting function. + */ + public default BooleanPredicate compose(BooleanPredicate before) { + Objects.requireNonNull(before); + return T -> test(before.test(T)); + } + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param after the function that should be used last + * @return a composed function with a different starting function. + */ + public default BooleanPredicate andThen(BooleanPredicate after) { + Objects.requireNonNull(after); + return T -> after.test(test(T)); + } + + /** + * Creates a Always true function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static BooleanPredicate alwaysTrue() { + return T -> true; + } + + /** + * Creates a Always false function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static BooleanPredicate alwaysFalse() { + return T -> false; + } + + /** + * A Type specific and-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a and comparason + */ + public default BooleanPredicate andType(BooleanPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + /** + * A type specific inverter function + * @return the same function but inverts the result + */ + public default BooleanPredicate negate() { + return T -> !test(T); + } + + /** + * A Type specific or-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a or comparason + */ + public default BooleanPredicate orType(BooleanPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanShortUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanShortUnaryOperator.java new file mode 100644 index 000000000..5ebb8b2a6 --- /dev/null +++ b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanShortUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.booleans.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface BooleanShortUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public short applyAsShort(boolean k, short v); + + @Override + public default Short apply(Boolean k, Short v) { return Short.valueOf(applyAsShort(k.booleanValue(), v.shortValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/ByteComparator.java b/src/main/java/speiger/src/collections/bytes/functions/ByteComparator.java new file mode 100644 index 000000000..bd37bb208 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/ByteComparator.java @@ -0,0 +1,70 @@ +package speiger.src.collections.bytes.functions; + +import java.util.Comparator; +import java.util.Objects; + +/** + * Type-Specific Class for Comparator to reduce (un)boxing + */ +public interface ByteComparator extends Comparator +{ + /** + * Type-Specific compare function to reduce (un)boxing + * @param o1 the first object to be compared. + * @param o2 the second object to be compared. + * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. + * @see Comparator#compare(Object, Object) + */ + int compare(byte o1, byte o2); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default int compare(Byte o1, Byte o2) { + return compare(o1.byteValue(), o2.byteValue()); + } + + /** + * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator + * @param c comparator to convert + * @return the wrapper of the comparator + * @throws NullPointerException if the comparator is null + */ + public static ByteComparator of(Comparator c) { + Objects.requireNonNull(c); + return (K, V) -> c.compare(Byte.valueOf(K), Byte.valueOf(V)); + } + + @Override + public default ByteComparator reversed() { + return new Reversed(this); + } + + /** + * A Type Specific Reversed Comparator to reduce boxing/unboxing + */ + static class Reversed implements ByteComparator + { + ByteComparator original; + + /** + * default constructor + * @param original that is going to be reversed + */ + public Reversed(ByteComparator original) { + this.original = original; + } + + public int compare(byte o1, byte o2) { + return original.compare(o2, o1); + } + + @Override + public ByteComparator reversed() { + return original; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/ByteConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/ByteConsumer.java new file mode 100644 index 000000000..9b4007dd3 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/ByteConsumer.java @@ -0,0 +1,48 @@ +package speiger.src.collections.bytes.functions; + +import java.util.Objects; +import java.util.function.Consumer; +/** + * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +@FunctionalInterface +public interface ByteConsumer extends Consumer +{ + /** + * Type-Specific function to reduce (un)boxing. + * Performs this operation on the given argument. + * + * @param t the input argument + */ + void accept(byte t); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced consumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ByteConsumer andThen(ByteConsumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(T);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Byte t) { accept(t.byteValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ByteConsumer andThen(Consumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(Byte.valueOf(T));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/ByteSupplier.java b/src/main/java/speiger/src/collections/bytes/functions/ByteSupplier.java new file mode 100644 index 000000000..de0e3f6c6 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/ByteSupplier.java @@ -0,0 +1,12 @@ +package speiger.src.collections.bytes.functions; + +/** + * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +public interface ByteSupplier +{ + /** + * @return the supplied value + */ + public byte getAsInt(); +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteBooleanConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteBooleanConsumer.java new file mode 100644 index 000000000..8022f911d --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteBooleanConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.bytes.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ByteBooleanConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(byte k, boolean v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ByteBooleanConsumer andThen(ByteBooleanConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Byte k, Boolean v) { accept(k.byteValue(), v.booleanValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ByteBooleanConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Boolean.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteByteConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteByteConsumer.java new file mode 100644 index 000000000..85ff921a3 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteByteConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.bytes.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ByteByteConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(byte k, byte v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ByteByteConsumer andThen(ByteByteConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Byte k, Byte v) { accept(k.byteValue(), v.byteValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ByteByteConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Byte.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteCharConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteCharConsumer.java new file mode 100644 index 000000000..f1a52044f --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteCharConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.bytes.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ByteCharConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(byte k, char v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ByteCharConsumer andThen(ByteCharConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Byte k, Character v) { accept(k.byteValue(), v.charValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ByteCharConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Character.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteDoubleConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteDoubleConsumer.java new file mode 100644 index 000000000..6acbf3323 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteDoubleConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.bytes.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ByteDoubleConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(byte k, double v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ByteDoubleConsumer andThen(ByteDoubleConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Byte k, Double v) { accept(k.byteValue(), v.doubleValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ByteDoubleConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Double.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteFloatConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteFloatConsumer.java new file mode 100644 index 000000000..77b934d31 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteFloatConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.bytes.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ByteFloatConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(byte k, float v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ByteFloatConsumer andThen(ByteFloatConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Byte k, Float v) { accept(k.byteValue(), v.floatValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ByteFloatConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Float.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteIntConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteIntConsumer.java new file mode 100644 index 000000000..c13ef686c --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteIntConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.bytes.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ByteIntConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(byte k, int v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ByteIntConsumer andThen(ByteIntConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Byte k, Integer v) { accept(k.byteValue(), v.intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ByteIntConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Integer.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteLongConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteLongConsumer.java new file mode 100644 index 000000000..36ea5472e --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteLongConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.bytes.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ByteLongConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(byte k, long v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ByteLongConsumer andThen(ByteLongConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Byte k, Long v) { accept(k.byteValue(), v.longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ByteLongConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Long.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteObjectConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteObjectConsumer.java new file mode 100644 index 000000000..dfb70283f --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteObjectConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.bytes.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface ByteObjectConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(byte k, V v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ByteObjectConsumer andThen(ByteObjectConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Byte k, V v) { accept(k.byteValue(), v); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ByteObjectConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), V);}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteShortConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteShortConsumer.java new file mode 100644 index 000000000..c486aff63 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteShortConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.bytes.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ByteShortConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(byte k, short v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ByteShortConsumer andThen(ByteShortConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Byte k, Short v) { accept(k.byteValue(), v.shortValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ByteShortConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Short.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2CharFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2CharFunction.java new file mode 100644 index 000000000..b543f1b7f --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2CharFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.bytes.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Byte2CharFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public char applyAsChar(byte k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2DoubleFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2DoubleFunction.java new file mode 100644 index 000000000..6f5a16064 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2DoubleFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.bytes.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Byte2DoubleFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public double applyAsDouble(byte k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2FloatFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2FloatFunction.java new file mode 100644 index 000000000..3e3776fdd --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2FloatFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.bytes.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Byte2FloatFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public float applyAsFloat(byte k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2IntFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2IntFunction.java new file mode 100644 index 000000000..1672969e9 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2IntFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.bytes.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Byte2IntFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public int applyAsInt(byte k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2LongFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2LongFunction.java new file mode 100644 index 000000000..8673498a8 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2LongFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.bytes.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Byte2LongFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public long applyAsLong(byte k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2ShortFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2ShortFunction.java new file mode 100644 index 000000000..198bdf043 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2ShortFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.bytes.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Byte2ShortFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public short applyAsShort(byte k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteBooleanUnaryOperator.java new file mode 100644 index 000000000..742120fd5 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/ByteBooleanUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.bytes.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ByteBooleanUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public boolean applyAsBoolean(byte k, boolean v); + + @Override + public default Boolean apply(Byte k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.byteValue(), v.booleanValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteByteUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteByteUnaryOperator.java new file mode 100644 index 000000000..0fb74d9c1 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/ByteByteUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.bytes.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ByteByteUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public byte applyAsByte(byte k, byte v); + + @Override + public default Byte apply(Byte k, Byte v) { return Byte.valueOf(applyAsByte(k.byteValue(), v.byteValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteCharUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteCharUnaryOperator.java new file mode 100644 index 000000000..89ff943fe --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/ByteCharUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.bytes.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ByteCharUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public char applyAsChar(byte k, char v); + + @Override + public default Character apply(Byte k, Character v) { return Character.valueOf(applyAsChar(k.byteValue(), v.charValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteDoubleUnaryOperator.java new file mode 100644 index 000000000..f9e86aafe --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/ByteDoubleUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.bytes.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ByteDoubleUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public double applyAsDouble(byte k, double v); + + @Override + public default Double apply(Byte k, Double v) { return Double.valueOf(applyAsDouble(k.byteValue(), v.doubleValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteFloatUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteFloatUnaryOperator.java new file mode 100644 index 000000000..8e583645b --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/ByteFloatUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.bytes.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ByteFloatUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public float applyAsFloat(byte k, float v); + + @Override + public default Float apply(Byte k, Float v) { return Float.valueOf(applyAsFloat(k.byteValue(), v.floatValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteFunction.java new file mode 100644 index 000000000..8296b7ea1 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/ByteFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.bytes.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface ByteFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public V apply(byte k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteIntUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteIntUnaryOperator.java new file mode 100644 index 000000000..d7f51b603 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/ByteIntUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.bytes.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ByteIntUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public int applyAsInt(byte k, int v); + + @Override + public default Integer apply(Byte k, Integer v) { return Integer.valueOf(applyAsInt(k.byteValue(), v.intValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteLongUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteLongUnaryOperator.java new file mode 100644 index 000000000..75e451569 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/ByteLongUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.bytes.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ByteLongUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public long applyAsLong(byte k, long v); + + @Override + public default Long apply(Byte k, Long v) { return Long.valueOf(applyAsLong(k.byteValue(), v.longValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteObjectUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteObjectUnaryOperator.java new file mode 100644 index 000000000..943b70045 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/ByteObjectUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.bytes.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface ByteObjectUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public V apply(byte k, V v); + + @Override + public default V apply(Byte k, V v) { return apply(k.byteValue(), v); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/BytePredicate.java b/src/main/java/speiger/src/collections/bytes/functions/function/BytePredicate.java new file mode 100644 index 000000000..7629e541f --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/BytePredicate.java @@ -0,0 +1,62 @@ +package speiger.src.collections.bytes.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface BytePredicate +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public boolean test(byte k); + + /** + * Creates a Always true function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static BytePredicate alwaysTrue() { + return T -> true; + } + + /** + * Creates a Always false function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static BytePredicate alwaysFalse() { + return T -> false; + } + + /** + * A Type specific and-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a and comparason + */ + public default BytePredicate andType(BytePredicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + /** + * A type specific inverter function + * @return the same function but inverts the result + */ + public default BytePredicate negate() { + return T -> !test(T); + } + + /** + * A Type specific or-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a or comparason + */ + public default BytePredicate orType(BytePredicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteShortUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteShortUnaryOperator.java new file mode 100644 index 000000000..11e207e41 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/ByteShortUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.bytes.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ByteShortUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public short applyAsShort(byte k, short v); + + @Override + public default Short apply(Byte k, Short v) { return Short.valueOf(applyAsShort(k.byteValue(), v.shortValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteUnaryOperator.java new file mode 100644 index 000000000..a49b4e5d7 --- /dev/null +++ b/src/main/java/speiger/src/collections/bytes/functions/function/ByteUnaryOperator.java @@ -0,0 +1,54 @@ +package speiger.src.collections.bytes.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface ByteUnaryOperator +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public byte applyAsByte(byte k); + + /** + * Creates a Default function that returns the input provided. + * @return a input returning function + */ + public static ByteUnaryOperator identity() { + return T -> T; + } + + /** + * Returns a composed function that first applies the {@code before} + * function to its input, and then applies this function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param before the function that should be used first + * @return a composed function with a different starting function. + */ + public default ByteUnaryOperator compose(ByteUnaryOperator before) { + Objects.requireNonNull(before); + return T -> applyAsByte(before.applyAsByte(T)); + } + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param after the function that should be used last + * @return a composed function with a different starting function. + */ + public default ByteUnaryOperator andThen(ByteUnaryOperator after) { + Objects.requireNonNull(after); + return T -> after.applyAsByte(applyAsByte(T)); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/CharComparator.java b/src/main/java/speiger/src/collections/chars/functions/CharComparator.java new file mode 100644 index 000000000..cd22da54f --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/CharComparator.java @@ -0,0 +1,70 @@ +package speiger.src.collections.chars.functions; + +import java.util.Comparator; +import java.util.Objects; + +/** + * Type-Specific Class for Comparator to reduce (un)boxing + */ +public interface CharComparator extends Comparator +{ + /** + * Type-Specific compare function to reduce (un)boxing + * @param o1 the first object to be compared. + * @param o2 the second object to be compared. + * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. + * @see Comparator#compare(Object, Object) + */ + int compare(char o1, char o2); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default int compare(Character o1, Character o2) { + return compare(o1.charValue(), o2.charValue()); + } + + /** + * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator + * @param c comparator to convert + * @return the wrapper of the comparator + * @throws NullPointerException if the comparator is null + */ + public static CharComparator of(Comparator c) { + Objects.requireNonNull(c); + return (K, V) -> c.compare(Character.valueOf(K), Character.valueOf(V)); + } + + @Override + public default CharComparator reversed() { + return new Reversed(this); + } + + /** + * A Type Specific Reversed Comparator to reduce boxing/unboxing + */ + static class Reversed implements CharComparator + { + CharComparator original; + + /** + * default constructor + * @param original that is going to be reversed + */ + public Reversed(CharComparator original) { + this.original = original; + } + + public int compare(char o1, char o2) { + return original.compare(o2, o1); + } + + @Override + public CharComparator reversed() { + return original; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/CharConsumer.java b/src/main/java/speiger/src/collections/chars/functions/CharConsumer.java new file mode 100644 index 000000000..3e657c4b0 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/CharConsumer.java @@ -0,0 +1,48 @@ +package speiger.src.collections.chars.functions; + +import java.util.Objects; +import java.util.function.Consumer; +/** + * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +@FunctionalInterface +public interface CharConsumer extends Consumer +{ + /** + * Type-Specific function to reduce (un)boxing. + * Performs this operation on the given argument. + * + * @param t the input argument + */ + void accept(char t); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced consumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default CharConsumer andThen(CharConsumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(T);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Character t) { accept(t.charValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default CharConsumer andThen(Consumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(Character.valueOf(T));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/CharSupplier.java b/src/main/java/speiger/src/collections/chars/functions/CharSupplier.java new file mode 100644 index 000000000..8d675dce8 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/CharSupplier.java @@ -0,0 +1,12 @@ +package speiger.src.collections.chars.functions; + +/** + * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +public interface CharSupplier +{ + /** + * @return the supplied value + */ + public char getAsInt(); +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharBooleanConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharBooleanConsumer.java new file mode 100644 index 000000000..db31509a0 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/consumer/CharBooleanConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.chars.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface CharBooleanConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(char k, boolean v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default CharBooleanConsumer andThen(CharBooleanConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Character k, Boolean v) { accept(k.charValue(), v.booleanValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default CharBooleanConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Boolean.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharByteConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharByteConsumer.java new file mode 100644 index 000000000..ea86de532 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/consumer/CharByteConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.chars.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface CharByteConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(char k, byte v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default CharByteConsumer andThen(CharByteConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Character k, Byte v) { accept(k.charValue(), v.byteValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default CharByteConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Byte.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharCharConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharCharConsumer.java new file mode 100644 index 000000000..c4e922661 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/consumer/CharCharConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.chars.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface CharCharConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(char k, char v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default CharCharConsumer andThen(CharCharConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Character k, Character v) { accept(k.charValue(), v.charValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default CharCharConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Character.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharDoubleConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharDoubleConsumer.java new file mode 100644 index 000000000..4d27c0f36 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/consumer/CharDoubleConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.chars.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface CharDoubleConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(char k, double v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default CharDoubleConsumer andThen(CharDoubleConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Character k, Double v) { accept(k.charValue(), v.doubleValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default CharDoubleConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Double.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharFloatConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharFloatConsumer.java new file mode 100644 index 000000000..9e993edf5 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/consumer/CharFloatConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.chars.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface CharFloatConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(char k, float v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default CharFloatConsumer andThen(CharFloatConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Character k, Float v) { accept(k.charValue(), v.floatValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default CharFloatConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Float.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharIntConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharIntConsumer.java new file mode 100644 index 000000000..1668caeda --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/consumer/CharIntConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.chars.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface CharIntConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(char k, int v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default CharIntConsumer andThen(CharIntConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Character k, Integer v) { accept(k.charValue(), v.intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default CharIntConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Integer.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharLongConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharLongConsumer.java new file mode 100644 index 000000000..3048c08f3 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/consumer/CharLongConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.chars.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface CharLongConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(char k, long v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default CharLongConsumer andThen(CharLongConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Character k, Long v) { accept(k.charValue(), v.longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default CharLongConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Long.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharObjectConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharObjectConsumer.java new file mode 100644 index 000000000..b03888e8c --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/consumer/CharObjectConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.chars.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface CharObjectConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(char k, V v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default CharObjectConsumer andThen(CharObjectConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Character k, V v) { accept(k.charValue(), v); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default CharObjectConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), V);}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharShortConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharShortConsumer.java new file mode 100644 index 000000000..ffa3baf78 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/consumer/CharShortConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.chars.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface CharShortConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(char k, short v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default CharShortConsumer andThen(CharShortConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Character k, Short v) { accept(k.charValue(), v.shortValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default CharShortConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Short.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2ByteFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2ByteFunction.java new file mode 100644 index 000000000..16c70dd0f --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/Char2ByteFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.chars.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Char2ByteFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public byte applyAsByte(char k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2DoubleFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2DoubleFunction.java new file mode 100644 index 000000000..a425c7559 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/Char2DoubleFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.chars.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Char2DoubleFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public double applyAsDouble(char k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2FloatFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2FloatFunction.java new file mode 100644 index 000000000..ed1c488e5 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/Char2FloatFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.chars.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Char2FloatFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public float applyAsFloat(char k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2IntFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2IntFunction.java new file mode 100644 index 000000000..2e17ab27f --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/Char2IntFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.chars.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Char2IntFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public int applyAsInt(char k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2LongFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2LongFunction.java new file mode 100644 index 000000000..809d3e440 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/Char2LongFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.chars.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Char2LongFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public long applyAsLong(char k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2ShortFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2ShortFunction.java new file mode 100644 index 000000000..435518d5f --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/Char2ShortFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.chars.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Char2ShortFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public short applyAsShort(char k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharBooleanUnaryOperator.java new file mode 100644 index 000000000..c5870677a --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharBooleanUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.chars.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface CharBooleanUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public boolean applyAsBoolean(char k, boolean v); + + @Override + public default Boolean apply(Character k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.charValue(), v.booleanValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharByteUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharByteUnaryOperator.java new file mode 100644 index 000000000..9688c32c7 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharByteUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.chars.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface CharByteUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public byte applyAsByte(char k, byte v); + + @Override + public default Byte apply(Character k, Byte v) { return Byte.valueOf(applyAsByte(k.charValue(), v.byteValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharCharUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharCharUnaryOperator.java new file mode 100644 index 000000000..440df1e8d --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharCharUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.chars.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface CharCharUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public char applyAsChar(char k, char v); + + @Override + public default Character apply(Character k, Character v) { return Character.valueOf(applyAsChar(k.charValue(), v.charValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharDoubleUnaryOperator.java new file mode 100644 index 000000000..bc961f87c --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharDoubleUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.chars.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface CharDoubleUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public double applyAsDouble(char k, double v); + + @Override + public default Double apply(Character k, Double v) { return Double.valueOf(applyAsDouble(k.charValue(), v.doubleValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharFloatUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharFloatUnaryOperator.java new file mode 100644 index 000000000..a541e9bcf --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharFloatUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.chars.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface CharFloatUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public float applyAsFloat(char k, float v); + + @Override + public default Float apply(Character k, Float v) { return Float.valueOf(applyAsFloat(k.charValue(), v.floatValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/CharFunction.java new file mode 100644 index 000000000..fc0d0180f --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.chars.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface CharFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public V apply(char k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharIntUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharIntUnaryOperator.java new file mode 100644 index 000000000..a9b5f6729 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharIntUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.chars.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface CharIntUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public int applyAsInt(char k, int v); + + @Override + public default Integer apply(Character k, Integer v) { return Integer.valueOf(applyAsInt(k.charValue(), v.intValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharLongUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharLongUnaryOperator.java new file mode 100644 index 000000000..d5ed6c5c0 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharLongUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.chars.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface CharLongUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public long applyAsLong(char k, long v); + + @Override + public default Long apply(Character k, Long v) { return Long.valueOf(applyAsLong(k.charValue(), v.longValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharObjectUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharObjectUnaryOperator.java new file mode 100644 index 000000000..8c5c1b20e --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharObjectUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.chars.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface CharObjectUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public V apply(char k, V v); + + @Override + public default V apply(Character k, V v) { return apply(k.charValue(), v); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharPredicate.java b/src/main/java/speiger/src/collections/chars/functions/function/CharPredicate.java new file mode 100644 index 000000000..095deb2cf --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharPredicate.java @@ -0,0 +1,62 @@ +package speiger.src.collections.chars.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface CharPredicate +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public boolean test(char k); + + /** + * Creates a Always true function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static CharPredicate alwaysTrue() { + return T -> true; + } + + /** + * Creates a Always false function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static CharPredicate alwaysFalse() { + return T -> false; + } + + /** + * A Type specific and-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a and comparason + */ + public default CharPredicate andType(CharPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + /** + * A type specific inverter function + * @return the same function but inverts the result + */ + public default CharPredicate negate() { + return T -> !test(T); + } + + /** + * A Type specific or-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a or comparason + */ + public default CharPredicate orType(CharPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharShortUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharShortUnaryOperator.java new file mode 100644 index 000000000..e407d7f90 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharShortUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.chars.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface CharShortUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public short applyAsShort(char k, short v); + + @Override + public default Short apply(Character k, Short v) { return Short.valueOf(applyAsShort(k.charValue(), v.shortValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharUnaryOperator.java new file mode 100644 index 000000000..1cb396e59 --- /dev/null +++ b/src/main/java/speiger/src/collections/chars/functions/function/CharUnaryOperator.java @@ -0,0 +1,54 @@ +package speiger.src.collections.chars.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface CharUnaryOperator +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public char applyAsChar(char k); + + /** + * Creates a Default function that returns the input provided. + * @return a input returning function + */ + public static CharUnaryOperator identity() { + return T -> T; + } + + /** + * Returns a composed function that first applies the {@code before} + * function to its input, and then applies this function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param before the function that should be used first + * @return a composed function with a different starting function. + */ + public default CharUnaryOperator compose(CharUnaryOperator before) { + Objects.requireNonNull(before); + return T -> applyAsChar(before.applyAsChar(T)); + } + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param after the function that should be used last + * @return a composed function with a different starting function. + */ + public default CharUnaryOperator andThen(CharUnaryOperator after) { + Objects.requireNonNull(after); + return T -> after.applyAsChar(applyAsChar(T)); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/DoubleComparator.java b/src/main/java/speiger/src/collections/doubles/functions/DoubleComparator.java new file mode 100644 index 000000000..73d815452 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/DoubleComparator.java @@ -0,0 +1,70 @@ +package speiger.src.collections.doubles.functions; + +import java.util.Comparator; +import java.util.Objects; + +/** + * Type-Specific Class for Comparator to reduce (un)boxing + */ +public interface DoubleComparator extends Comparator +{ + /** + * Type-Specific compare function to reduce (un)boxing + * @param o1 the first object to be compared. + * @param o2 the second object to be compared. + * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. + * @see Comparator#compare(Object, Object) + */ + int compare(double o1, double o2); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default int compare(Double o1, Double o2) { + return compare(o1.doubleValue(), o2.doubleValue()); + } + + /** + * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator + * @param c comparator to convert + * @return the wrapper of the comparator + * @throws NullPointerException if the comparator is null + */ + public static DoubleComparator of(Comparator c) { + Objects.requireNonNull(c); + return (K, V) -> c.compare(Double.valueOf(K), Double.valueOf(V)); + } + + @Override + public default DoubleComparator reversed() { + return new Reversed(this); + } + + /** + * A Type Specific Reversed Comparator to reduce boxing/unboxing + */ + static class Reversed implements DoubleComparator + { + DoubleComparator original; + + /** + * default constructor + * @param original that is going to be reversed + */ + public Reversed(DoubleComparator original) { + this.original = original; + } + + public int compare(double o1, double o2) { + return original.compare(o2, o1); + } + + @Override + public DoubleComparator reversed() { + return original; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/DoubleConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/DoubleConsumer.java new file mode 100644 index 000000000..d0053a087 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/DoubleConsumer.java @@ -0,0 +1,59 @@ +package speiger.src.collections.doubles.functions; + +import java.util.Objects; +import java.util.function.Consumer; +/** + * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +@FunctionalInterface +public interface DoubleConsumer extends Consumer, java.util.function.DoubleConsumer +{ + /** + * Type-Specific function to reduce (un)boxing. + * Performs this operation on the given argument. + * + * @param t the input argument + */ + void accept(double t); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced consumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default DoubleConsumer andThen(DoubleConsumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(T);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Double t) { accept(t.doubleValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default DoubleConsumer andThen(Consumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(Double.valueOf(T));}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default DoubleConsumer andThen(java.util.function.DoubleConsumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(T);}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/DoubleSupplier.java b/src/main/java/speiger/src/collections/doubles/functions/DoubleSupplier.java new file mode 100644 index 000000000..a6cd25199 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/DoubleSupplier.java @@ -0,0 +1,12 @@ +package speiger.src.collections.doubles.functions; + +/** + * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +public interface DoubleSupplier extends java.util.function.DoubleSupplier +{ + /** + * @return the supplied value + */ + public double getAsDouble(); +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleBooleanConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleBooleanConsumer.java new file mode 100644 index 000000000..8acbc28be --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleBooleanConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.doubles.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface DoubleBooleanConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(double k, boolean v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default DoubleBooleanConsumer andThen(DoubleBooleanConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Double k, Boolean v) { accept(k.doubleValue(), v.booleanValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default DoubleBooleanConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Boolean.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleByteConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleByteConsumer.java new file mode 100644 index 000000000..05f3706cf --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleByteConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.doubles.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface DoubleByteConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(double k, byte v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default DoubleByteConsumer andThen(DoubleByteConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Double k, Byte v) { accept(k.doubleValue(), v.byteValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default DoubleByteConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Byte.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleCharConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleCharConsumer.java new file mode 100644 index 000000000..6c6400330 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleCharConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.doubles.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface DoubleCharConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(double k, char v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default DoubleCharConsumer andThen(DoubleCharConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Double k, Character v) { accept(k.doubleValue(), v.charValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default DoubleCharConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Character.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleDoubleConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleDoubleConsumer.java new file mode 100644 index 000000000..f54938468 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleDoubleConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.doubles.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface DoubleDoubleConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(double k, double v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default DoubleDoubleConsumer andThen(DoubleDoubleConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Double k, Double v) { accept(k.doubleValue(), v.doubleValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default DoubleDoubleConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Double.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleFloatConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleFloatConsumer.java new file mode 100644 index 000000000..42cb0b24b --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleFloatConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.doubles.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface DoubleFloatConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(double k, float v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default DoubleFloatConsumer andThen(DoubleFloatConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Double k, Float v) { accept(k.doubleValue(), v.floatValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default DoubleFloatConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Float.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleIntConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleIntConsumer.java new file mode 100644 index 000000000..aed40a7a4 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleIntConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.doubles.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface DoubleIntConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(double k, int v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default DoubleIntConsumer andThen(DoubleIntConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Double k, Integer v) { accept(k.doubleValue(), v.intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default DoubleIntConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Integer.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleLongConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleLongConsumer.java new file mode 100644 index 000000000..5d234c71b --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleLongConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.doubles.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface DoubleLongConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(double k, long v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default DoubleLongConsumer andThen(DoubleLongConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Double k, Long v) { accept(k.doubleValue(), v.longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default DoubleLongConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Long.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleObjectConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleObjectConsumer.java new file mode 100644 index 000000000..75eb69663 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleObjectConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.doubles.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface DoubleObjectConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(double k, V v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default DoubleObjectConsumer andThen(DoubleObjectConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Double k, V v) { accept(k.doubleValue(), v); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default DoubleObjectConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), V);}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleShortConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleShortConsumer.java new file mode 100644 index 000000000..c3285d7c6 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleShortConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.doubles.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface DoubleShortConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(double k, short v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default DoubleShortConsumer andThen(DoubleShortConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Double k, Short v) { accept(k.doubleValue(), v.shortValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default DoubleShortConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Short.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2ByteFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2ByteFunction.java new file mode 100644 index 000000000..a82a984bb --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/Double2ByteFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.doubles.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Double2ByteFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public byte applyAsByte(double k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2CharFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2CharFunction.java new file mode 100644 index 000000000..fbf78e66a --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/Double2CharFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.doubles.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Double2CharFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public char applyAsChar(double k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2FloatFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2FloatFunction.java new file mode 100644 index 000000000..55a0b494a --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/Double2FloatFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.doubles.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Double2FloatFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public float applyAsFloat(double k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2IntFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2IntFunction.java new file mode 100644 index 000000000..67953bfe4 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/Double2IntFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.doubles.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Double2IntFunction extends java.util.function.DoubleToIntFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public int applyAsInt(double k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2LongFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2LongFunction.java new file mode 100644 index 000000000..1a9b1a6cd --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/Double2LongFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.doubles.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Double2LongFunction extends java.util.function.DoubleToLongFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public long applyAsLong(double k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2ShortFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2ShortFunction.java new file mode 100644 index 000000000..53a07d9fc --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/Double2ShortFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.doubles.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Double2ShortFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public short applyAsShort(double k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleBooleanUnaryOperator.java new file mode 100644 index 000000000..0d49a925c --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleBooleanUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.doubles.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface DoubleBooleanUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public boolean applyAsBoolean(double k, boolean v); + + @Override + public default Boolean apply(Double k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.doubleValue(), v.booleanValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleByteUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleByteUnaryOperator.java new file mode 100644 index 000000000..756058fdd --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleByteUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.doubles.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface DoubleByteUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public byte applyAsByte(double k, byte v); + + @Override + public default Byte apply(Double k, Byte v) { return Byte.valueOf(applyAsByte(k.doubleValue(), v.byteValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleCharUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleCharUnaryOperator.java new file mode 100644 index 000000000..7510e3bca --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleCharUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.doubles.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface DoubleCharUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public char applyAsChar(double k, char v); + + @Override + public default Character apply(Double k, Character v) { return Character.valueOf(applyAsChar(k.doubleValue(), v.charValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleDoubleUnaryOperator.java new file mode 100644 index 000000000..c223a05fe --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleDoubleUnaryOperator.java @@ -0,0 +1,13 @@ +package speiger.src.collections.doubles.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ + +public interface DoubleDoubleUnaryOperator extends BiFunction, java.util.function.DoubleBinaryOperator +{ + @Override + public default Double apply(Double k, Double v) { return Double.valueOf(applyAsDouble(k.doubleValue(), v.doubleValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFloatUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFloatUnaryOperator.java new file mode 100644 index 000000000..9d3054cce --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFloatUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.doubles.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface DoubleFloatUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public float applyAsFloat(double k, float v); + + @Override + public default Float apply(Double k, Float v) { return Float.valueOf(applyAsFloat(k.doubleValue(), v.floatValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFunction.java new file mode 100644 index 000000000..6c0cdbd7d --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.doubles.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface DoubleFunction extends java.util.function.DoubleFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public V apply(double k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleIntUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleIntUnaryOperator.java new file mode 100644 index 000000000..8ae3091cd --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleIntUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.doubles.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface DoubleIntUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public int applyAsInt(double k, int v); + + @Override + public default Integer apply(Double k, Integer v) { return Integer.valueOf(applyAsInt(k.doubleValue(), v.intValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleLongUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleLongUnaryOperator.java new file mode 100644 index 000000000..ad41c8b72 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleLongUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.doubles.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface DoubleLongUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public long applyAsLong(double k, long v); + + @Override + public default Long apply(Double k, Long v) { return Long.valueOf(applyAsLong(k.doubleValue(), v.longValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleObjectUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleObjectUnaryOperator.java new file mode 100644 index 000000000..f7e9c5af0 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleObjectUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.doubles.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface DoubleObjectUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public V apply(double k, V v); + + @Override + public default V apply(Double k, V v) { return apply(k.doubleValue(), v); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoublePredicate.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoublePredicate.java new file mode 100644 index 000000000..0a256c7f4 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoublePredicate.java @@ -0,0 +1,72 @@ +package speiger.src.collections.doubles.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface DoublePredicate extends java.util.function.DoublePredicate +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public boolean test(double k); + + /** + * Creates a Always true function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static DoublePredicate alwaysTrue() { + return T -> true; + } + + /** + * Creates a Always false function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static DoublePredicate alwaysFalse() { + return T -> false; + } + + /** + * A Type specific and-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a and comparason + */ + public default DoublePredicate andType(DoublePredicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + @Override + @Deprecated + public default DoublePredicate and(java.util.function.DoublePredicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + @Override + public default DoublePredicate negate() { + return T -> !test(T); + } + + /** + * A Type specific or-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a or comparason + */ + public default DoublePredicate orType(DoublePredicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } + + @Override + @Deprecated + public default DoublePredicate or(java.util.function.DoublePredicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleShortUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleShortUnaryOperator.java new file mode 100644 index 000000000..280ed1dcc --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleShortUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.doubles.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface DoubleShortUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public short applyAsShort(double k, short v); + + @Override + public default Short apply(Double k, Short v) { return Short.valueOf(applyAsShort(k.doubleValue(), v.shortValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleUnaryOperator.java new file mode 100644 index 000000000..c3156b404 --- /dev/null +++ b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleUnaryOperator.java @@ -0,0 +1,54 @@ +package speiger.src.collections.doubles.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface DoubleUnaryOperator extends java.util.function.DoubleUnaryOperator +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public double applyAsDouble(double k); + + /** + * Creates a Default function that returns the input provided. + * @return a input returning function + */ + public static DoubleUnaryOperator identity() { + return T -> T; + } + + /** + * Returns a composed function that first applies the {@code before} + * function to its input, and then applies this function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param before the function that should be used first + * @return a composed function with a different starting function. + */ + public default DoubleUnaryOperator compose(DoubleUnaryOperator before) { + Objects.requireNonNull(before); + return T -> applyAsDouble(before.applyAsDouble(T)); + } + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param after the function that should be used last + * @return a composed function with a different starting function. + */ + public default DoubleUnaryOperator andThen(DoubleUnaryOperator after) { + Objects.requireNonNull(after); + return T -> after.applyAsDouble(applyAsDouble(T)); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/FloatComparator.java b/src/main/java/speiger/src/collections/floats/functions/FloatComparator.java new file mode 100644 index 000000000..5fd257c47 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/FloatComparator.java @@ -0,0 +1,70 @@ +package speiger.src.collections.floats.functions; + +import java.util.Comparator; +import java.util.Objects; + +/** + * Type-Specific Class for Comparator to reduce (un)boxing + */ +public interface FloatComparator extends Comparator +{ + /** + * Type-Specific compare function to reduce (un)boxing + * @param o1 the first object to be compared. + * @param o2 the second object to be compared. + * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. + * @see Comparator#compare(Object, Object) + */ + int compare(float o1, float o2); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default int compare(Float o1, Float o2) { + return compare(o1.floatValue(), o2.floatValue()); + } + + /** + * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator + * @param c comparator to convert + * @return the wrapper of the comparator + * @throws NullPointerException if the comparator is null + */ + public static FloatComparator of(Comparator c) { + Objects.requireNonNull(c); + return (K, V) -> c.compare(Float.valueOf(K), Float.valueOf(V)); + } + + @Override + public default FloatComparator reversed() { + return new Reversed(this); + } + + /** + * A Type Specific Reversed Comparator to reduce boxing/unboxing + */ + static class Reversed implements FloatComparator + { + FloatComparator original; + + /** + * default constructor + * @param original that is going to be reversed + */ + public Reversed(FloatComparator original) { + this.original = original; + } + + public int compare(float o1, float o2) { + return original.compare(o2, o1); + } + + @Override + public FloatComparator reversed() { + return original; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/FloatConsumer.java b/src/main/java/speiger/src/collections/floats/functions/FloatConsumer.java new file mode 100644 index 000000000..5e8724377 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/FloatConsumer.java @@ -0,0 +1,48 @@ +package speiger.src.collections.floats.functions; + +import java.util.Objects; +import java.util.function.Consumer; +/** + * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +@FunctionalInterface +public interface FloatConsumer extends Consumer +{ + /** + * Type-Specific function to reduce (un)boxing. + * Performs this operation on the given argument. + * + * @param t the input argument + */ + void accept(float t); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced consumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default FloatConsumer andThen(FloatConsumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(T);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Float t) { accept(t.floatValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default FloatConsumer andThen(Consumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(Float.valueOf(T));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/FloatSupplier.java b/src/main/java/speiger/src/collections/floats/functions/FloatSupplier.java new file mode 100644 index 000000000..f0009ae9c --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/FloatSupplier.java @@ -0,0 +1,12 @@ +package speiger.src.collections.floats.functions; + +/** + * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +public interface FloatSupplier +{ + /** + * @return the supplied value + */ + public float getAsDouble(); +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatBooleanConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatBooleanConsumer.java new file mode 100644 index 000000000..3033a6838 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatBooleanConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.floats.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface FloatBooleanConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(float k, boolean v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default FloatBooleanConsumer andThen(FloatBooleanConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Float k, Boolean v) { accept(k.floatValue(), v.booleanValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default FloatBooleanConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Boolean.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatByteConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatByteConsumer.java new file mode 100644 index 000000000..6e3c3f1c4 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatByteConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.floats.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface FloatByteConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(float k, byte v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default FloatByteConsumer andThen(FloatByteConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Float k, Byte v) { accept(k.floatValue(), v.byteValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default FloatByteConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Byte.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatCharConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatCharConsumer.java new file mode 100644 index 000000000..c6af3eab1 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatCharConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.floats.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface FloatCharConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(float k, char v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default FloatCharConsumer andThen(FloatCharConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Float k, Character v) { accept(k.floatValue(), v.charValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default FloatCharConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Character.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatDoubleConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatDoubleConsumer.java new file mode 100644 index 000000000..46d992a0d --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatDoubleConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.floats.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface FloatDoubleConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(float k, double v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default FloatDoubleConsumer andThen(FloatDoubleConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Float k, Double v) { accept(k.floatValue(), v.doubleValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default FloatDoubleConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Double.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatFloatConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatFloatConsumer.java new file mode 100644 index 000000000..d13211938 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatFloatConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.floats.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface FloatFloatConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(float k, float v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default FloatFloatConsumer andThen(FloatFloatConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Float k, Float v) { accept(k.floatValue(), v.floatValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default FloatFloatConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Float.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatIntConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatIntConsumer.java new file mode 100644 index 000000000..6e9aef642 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatIntConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.floats.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface FloatIntConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(float k, int v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default FloatIntConsumer andThen(FloatIntConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Float k, Integer v) { accept(k.floatValue(), v.intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default FloatIntConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Integer.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatLongConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatLongConsumer.java new file mode 100644 index 000000000..237dc338c --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatLongConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.floats.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface FloatLongConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(float k, long v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default FloatLongConsumer andThen(FloatLongConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Float k, Long v) { accept(k.floatValue(), v.longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default FloatLongConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Long.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatObjectConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatObjectConsumer.java new file mode 100644 index 000000000..5d6bd04e1 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatObjectConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.floats.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface FloatObjectConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(float k, V v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default FloatObjectConsumer andThen(FloatObjectConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Float k, V v) { accept(k.floatValue(), v); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default FloatObjectConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), V);}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatShortConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatShortConsumer.java new file mode 100644 index 000000000..a62ea9be8 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatShortConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.floats.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface FloatShortConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(float k, short v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default FloatShortConsumer andThen(FloatShortConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Float k, Short v) { accept(k.floatValue(), v.shortValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default FloatShortConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Short.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2ByteFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2ByteFunction.java new file mode 100644 index 000000000..cef35f7bd --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/Float2ByteFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.floats.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Float2ByteFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public byte applyAsByte(float k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2CharFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2CharFunction.java new file mode 100644 index 000000000..0e29cb921 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/Float2CharFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.floats.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Float2CharFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public char applyAsChar(float k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2DoubleFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2DoubleFunction.java new file mode 100644 index 000000000..465bd779e --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/Float2DoubleFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.floats.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Float2DoubleFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public double applyAsDouble(float k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2IntFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2IntFunction.java new file mode 100644 index 000000000..76d49cee8 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/Float2IntFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.floats.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Float2IntFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public int applyAsInt(float k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2LongFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2LongFunction.java new file mode 100644 index 000000000..8101424f4 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/Float2LongFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.floats.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Float2LongFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public long applyAsLong(float k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2ShortFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2ShortFunction.java new file mode 100644 index 000000000..048862454 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/Float2ShortFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.floats.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Float2ShortFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public short applyAsShort(float k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatBooleanUnaryOperator.java new file mode 100644 index 000000000..894733145 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatBooleanUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.floats.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface FloatBooleanUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public boolean applyAsBoolean(float k, boolean v); + + @Override + public default Boolean apply(Float k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.floatValue(), v.booleanValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatByteUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatByteUnaryOperator.java new file mode 100644 index 000000000..e0549ac62 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatByteUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.floats.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface FloatByteUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public byte applyAsByte(float k, byte v); + + @Override + public default Byte apply(Float k, Byte v) { return Byte.valueOf(applyAsByte(k.floatValue(), v.byteValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatCharUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatCharUnaryOperator.java new file mode 100644 index 000000000..4acb9ba38 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatCharUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.floats.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface FloatCharUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public char applyAsChar(float k, char v); + + @Override + public default Character apply(Float k, Character v) { return Character.valueOf(applyAsChar(k.floatValue(), v.charValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatDoubleUnaryOperator.java new file mode 100644 index 000000000..0e5c33743 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatDoubleUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.floats.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface FloatDoubleUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public double applyAsDouble(float k, double v); + + @Override + public default Double apply(Float k, Double v) { return Double.valueOf(applyAsDouble(k.floatValue(), v.doubleValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatFloatUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatFloatUnaryOperator.java new file mode 100644 index 000000000..9cc4df923 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatFloatUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.floats.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface FloatFloatUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public float applyAsFloat(float k, float v); + + @Override + public default Float apply(Float k, Float v) { return Float.valueOf(applyAsFloat(k.floatValue(), v.floatValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatFunction.java new file mode 100644 index 000000000..36fea4f7f --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.floats.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface FloatFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public V apply(float k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatIntUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatIntUnaryOperator.java new file mode 100644 index 000000000..099238999 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatIntUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.floats.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface FloatIntUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public int applyAsInt(float k, int v); + + @Override + public default Integer apply(Float k, Integer v) { return Integer.valueOf(applyAsInt(k.floatValue(), v.intValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatLongUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatLongUnaryOperator.java new file mode 100644 index 000000000..140169b41 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatLongUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.floats.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface FloatLongUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public long applyAsLong(float k, long v); + + @Override + public default Long apply(Float k, Long v) { return Long.valueOf(applyAsLong(k.floatValue(), v.longValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatObjectUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatObjectUnaryOperator.java new file mode 100644 index 000000000..b44e40367 --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatObjectUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.floats.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface FloatObjectUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public V apply(float k, V v); + + @Override + public default V apply(Float k, V v) { return apply(k.floatValue(), v); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatPredicate.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatPredicate.java new file mode 100644 index 000000000..08a95d62c --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatPredicate.java @@ -0,0 +1,62 @@ +package speiger.src.collections.floats.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface FloatPredicate +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public boolean test(float k); + + /** + * Creates a Always true function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static FloatPredicate alwaysTrue() { + return T -> true; + } + + /** + * Creates a Always false function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static FloatPredicate alwaysFalse() { + return T -> false; + } + + /** + * A Type specific and-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a and comparason + */ + public default FloatPredicate andType(FloatPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + /** + * A type specific inverter function + * @return the same function but inverts the result + */ + public default FloatPredicate negate() { + return T -> !test(T); + } + + /** + * A Type specific or-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a or comparason + */ + public default FloatPredicate orType(FloatPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatShortUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatShortUnaryOperator.java new file mode 100644 index 000000000..915982b5b --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatShortUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.floats.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface FloatShortUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public short applyAsShort(float k, short v); + + @Override + public default Short apply(Float k, Short v) { return Short.valueOf(applyAsShort(k.floatValue(), v.shortValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatUnaryOperator.java new file mode 100644 index 000000000..59c3063db --- /dev/null +++ b/src/main/java/speiger/src/collections/floats/functions/function/FloatUnaryOperator.java @@ -0,0 +1,54 @@ +package speiger.src.collections.floats.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface FloatUnaryOperator +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public float applyAsFloat(float k); + + /** + * Creates a Default function that returns the input provided. + * @return a input returning function + */ + public static FloatUnaryOperator identity() { + return T -> T; + } + + /** + * Returns a composed function that first applies the {@code before} + * function to its input, and then applies this function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param before the function that should be used first + * @return a composed function with a different starting function. + */ + public default FloatUnaryOperator compose(FloatUnaryOperator before) { + Objects.requireNonNull(before); + return T -> applyAsFloat(before.applyAsFloat(T)); + } + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param after the function that should be used last + * @return a composed function with a different starting function. + */ + public default FloatUnaryOperator andThen(FloatUnaryOperator after) { + Objects.requireNonNull(after); + return T -> after.applyAsFloat(applyAsFloat(T)); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/collections/AbstractIntCollection.java b/src/main/java/speiger/src/collections/ints/collections/AbstractIntCollection.java new file mode 100644 index 000000000..9223fa81c --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/collections/AbstractIntCollection.java @@ -0,0 +1,252 @@ +package speiger.src.collections.ints.collections; + +import java.util.Collection; +import java.util.Objects; +import java.util.AbstractCollection; + +import speiger.src.collections.ints.functions.IntConsumer; +import speiger.src.collections.ints.utils.IntIterators; +import speiger.src.collections.ints.utils.IntArrays; + +/** + * Abstract Type Specific Collection that reduces boxing/unboxing + */ +public abstract class AbstractIntCollection extends AbstractCollection implements IntCollection +{ + @Override + public abstract IntIterator iterator(); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public boolean add(Integer e) { return IntCollection.super.add(e); } + + @Override + public boolean addAll(IntCollection c) { + boolean modified = false; + for(IntIterator iter = c.iterator();iter.hasNext();modified |= add(iter.nextInt())); + return modified; + } + + @Override + public IntCollection copy() { throw new UnsupportedOperationException(); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public boolean contains(Object e) { return IntCollection.super.contains(e); } + + /** + * A Type-Specific implementation of contains. This implementation iterates over the elements and returns true if the value match. + * @param e the element that should be searched for. + * @return true if the value was found. + */ + @Override + public boolean contains(int e) { + for(IntIterator iter = iterator();iter.hasNext();) { if(iter.nextInt() == e) return true; } + return false; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public boolean addAll(Collection c) + { + return c instanceof IntCollection ? addAll((IntCollection)c) : super.addAll(c); + } + + /** + * A Type-Specific implementation of containsAll. This implementation iterates over all elements and checks all elements are present in the other collection. + * @param c the collection that should be checked if it contains all elements. + * @return true if all elements were found in the collection + * @throws NullPointerException if the collection is null + */ + @Override + public boolean containsAll(IntCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return true; + for(IntIterator iter = c.iterator();iter.hasNext();) + if(!contains(iter.nextInt())) + return false; + return true; + } + + @Override + public boolean containsAll(Collection c) { + Objects.requireNonNull(c); + return c instanceof IntCollection ? containsAll((IntCollection)c) : super.containsAll(c); + } + + /** + * This implementation iterates over the elements of the collection and checks if they are stored in this collection + * @param c the elements that should be checked for + * @return true if any element is in this collection + * @throws NullPointerException if the collection is null + */ + @Override + @Deprecated + public boolean containsAny(Collection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + for(Object e : c) + if(contains(e)) + return true; + return false; + } + + /** + * This implementation iterates over the elements of the collection and checks if they are stored in this collection. + * @param c the elements that should be checked for + * @return true if any element is in this collection + * @throws NullPointerException if the collection is null + */ + @Override + public boolean containsAny(IntCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + for(IntIterator iter = c.iterator();iter.hasNext();) + if(contains(iter.nextInt())) + return true; + return false; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public boolean remove(Object e) { return IntCollection.super.remove(e); } + + /** + * A Type-Specific implementation of remove. This implementation iterates over the elements until it finds the element that is searched for or it runs out of elements. + * It stops after finding the first element + * @param e the element that is searched for + * @return true if the element was found and removed. + */ + @Override + public boolean remInt(int e) { + for(IntIterator iter = iterator();iter.hasNext();) { + if(iter.nextInt() == e) { + iter.remove(); + return true; + } + } + return false; + } + + /** + * A Type-Specific implementation of removeAll. This Implementation iterates over all elements and removes them as they were found in the other collection. + * @param c the elements that should be deleted + * @return true if the collection was modified. + * @throws NullPointerException if the collection is null + */ + @Override + public boolean removeAll(IntCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + boolean modified = false; + for(IntIterator iter = iterator();iter.hasNext();) { + if(c.contains(iter.nextInt())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + @Override + public boolean removeAll(IntCollection c, IntConsumer r) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + Objects.requireNonNull(r); + boolean modified = false; + for(IntIterator iter = iterator();iter.hasNext();) { + int e = iter.nextInt(); + if(c.contains(e)) { + r.accept(e); + iter.remove(); + modified = true; + } + } + return modified; + } + + /** + * A Type-Specific implementation of retainAll. This Implementation iterates over all elements and removes them as they were not found in the other collection. + * @param c the elements that should be kept + * @return true if the collection was modified. + * @throws NullPointerException if the collection is null + */ + @Override + public boolean retainAll(IntCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) { + boolean modified = !isEmpty(); + clear(); + return modified; + } + boolean modified = false; + for(IntIterator iter = iterator();iter.hasNext();) { + if(!c.contains(iter.nextInt())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + @Override + public boolean retainAll(IntCollection c, IntConsumer r) { + Objects.requireNonNull(c); + Objects.requireNonNull(r); + if(c.isEmpty()) { + boolean modified = !isEmpty(); + forEach(r); + clear(); + return modified; + } + boolean modified = false; + for(IntIterator iter = iterator();iter.hasNext();) { + int e = iter.nextInt(); + if(!c.contains(e)) { + r.accept(e); + iter.remove(); + modified = true; + } + } + return modified; + } + + /** + * A Type-Specific implementation of toArray that links to {@link #toIntArray(int[])} with a newly created array. + * @return an array containing all of the elements in this collection + */ + @Override + public int[] toIntArray() { + if(isEmpty()) return IntArrays.EMPTY_ARRAY; + return toIntArray(new int[size()]); + } + + /** + * A Type-Specific implementation of toArray. This implementation iterates over all elements and unwraps them into primitive type. + * @param a array that the elements should be injected to. If null or to small a new array with the right size is created + * @return an array containing all of the elements in this collection + */ + @Override + public int[] toIntArray(int[] a) { + if(a == null || a.length < size()) a = new int[size()]; + IntIterators.unwrap(a, iterator()); + if (a.length > size()) a[size()] = 0; + return a; + } +} diff --git a/src/main/java/speiger/src/collections/ints/collections/IntBidirectionalIterator.java b/src/main/java/speiger/src/collections/ints/collections/IntBidirectionalIterator.java new file mode 100644 index 000000000..c422b0e08 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/collections/IntBidirectionalIterator.java @@ -0,0 +1,52 @@ +package speiger.src.collections.ints.collections; + +import speiger.src.collections.objects.collections.ObjectBidirectionalIterator; +/** + * A Type-Specific {@link ObjectBidirectionalIterator} to reduce (un)boxing + */ +public interface IntBidirectionalIterator extends IntIterator, ObjectBidirectionalIterator +{ + /** + * Returns true if the Iterator has a Previous element + * @return true if the Iterator has a Previous element + */ + public boolean hasPrevious(); + + /** + * Returns the Previous element of the iterator. + * @return the Previous element of the iterator. + * @throws java.util.NoSuchElementException if the iteration has no more elements + */ + public int previousInt(); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default Integer previous() { + return Integer.valueOf(previousInt()); + } + + /** + * {@inheritDoc} + */ + @Override + default int skip(int amount) + { + return IntIterator.super.skip(amount); + } + + /** + * Reverses the Given amount of elements if possible. A Optimization function to reverse elements faster if the implementation allows it. + * @param amount the amount of elements that should be reversed + * @return the amount of elements that were reversed + */ + public default int back(int amount) { + if(amount < 0) throw new IllegalStateException("Can't go forward"); + int i = 0; + for(;i, IntIterable, ISizeProvider +{ + /** + * A Type-Specific add function to reduce (un)boxing + * @param o the element that should be added + * @return true if the element was added to the collection + */ + public boolean add(int o); + + /** + * A Type-Specific addAll function to reduce (un)boxing + * @param c the collection of elements that should be added + * @return true if elements were added into the collection + */ + public boolean addAll(IntCollection c); + + /** + * A Type-Specific Array based addAll method to reduce the amount of Wrapping + * @param e the elements that should be added + * @return if the collection was modified + */ + public default boolean addAll(int... e) { return addAll(e, 0, e.length); } + + /** + * A Type-Specific Array based addAll method to reduce the amount of Wrapping + * @param e the elements that should be added + * @param length how many elements of the array should be added + * @return if the collection was modified + */ + public default boolean addAll(int[] e, int length) { return addAll(e, 0, length); } + + /** + * A Type-Specific Array based addAll method to reduce the amount of Wrapping + * @param e the elements that should be added + * @param offset where to start within the array + * @param length how many elements of the array should be added + * @return if the collection was modified + */ + public default boolean addAll(int[] e, int offset, int length) { + if(length <= 0) return false; + SanityChecks.checkArrayCapacity(e.length, offset, length); + boolean added = false; + for(int i = 0;i c); + + /** + * A Type-Specific remove function that reduces (un)boxing. + * @param o the element that should be removed + * @return true if the element was removed + * @see Collection#remove(Object) + */ + public boolean remInt(int o); + + /** + * A Type-Specific removeAll function that reduces (un)boxing. + * @param c the collection of elements that should be removed + * @return true if any element was removed + * @see Collection#removeAll(Collection) + */ + public boolean removeAll(IntCollection c); + + /** + * A Type-Specific removeAll function that reduces (un)boxing. + * It also notifies the remover of which exact element is going to be removed. + * @param c the collection of elements that should be removed + * @param r elements that got removed + * @return true if any element was removed + * @see Collection#removeAll(Collection) + */ + public boolean removeAll(IntCollection c, IntConsumer r); + + /** + * A Type-Specific retainAll function that reduces (un)boxing. + * @param c the collection of elements that should be kept + * @return true if any element was removed + * @see Collection#retainAll(Collection) + */ + public boolean retainAll(IntCollection c); + + /** + * A Type-Specific retainAll function that reduces (un)boxing. + * It also notifies the remover of which exact element is going to be removed. + * @param c the collection of elements that should be kept + * @param r elements that got removed + * @return true if any element was removed + * @see Collection#retainAll(Collection) + */ + public boolean retainAll(IntCollection c, IntConsumer r); + + /** + * A Helper function to reduce the usage of Streams and allows to collect all elements + * @param collection that the elements should be inserted to + * @param the collection type + * @return the input with the desired elements + */ + default E pour(E collection) { + collection.addAll(this); + return collection; + } + + /** + * A Function that does a shallow clone of the Collection itself. + * This function is more optimized then a copy constructor since the Collection does not have to be unsorted/resorted. + * It can be compared to Cloneable but with less exception risk + * @return a Shallow Copy of the collection + * @note Wrappers and view collections will not support this feature + */ + public IntCollection copy(); + + /** + * A Type-Specific toArray function that delegates to {@link #toIntArray(int[])} with a newly created array. + * @return an array containing all of the elements in this collection + * @see Collection#toArray() + */ + public int[] toIntArray(); + + /** + * A Type-Specific toArray function that reduces (un)boxing. + * @param a array that the elements should be injected to. If null or to small a new array with the right size is created + * @return an array containing all of the elements in this collection + * @see Collection#toArray(Object[]) + */ + public int[] toIntArray(int[] a); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default boolean removeIf(Predicate filter) { + Objects.requireNonNull(filter); + return remIf(v -> filter.test(Integer.valueOf(v))); + } + + /** + * A Type-Specific removeIf function to reduce (un)boxing. + *

Removes elements that were selected by the filter + * @see Collection#removeIf(Predicate) + * @param filter Filters the elements that should be removed + * @return true if the collection was modified + * @throws NullPointerException if filter is null + */ + public default boolean remIf(IntPredicate filter) { + Objects.requireNonNull(filter); + boolean removed = false; + final IntIterator each = iterator(); + while (each.hasNext()) { + if (filter.test(each.nextInt())) { + each.remove(); + removed = true; + } + } + return removed; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default boolean add(Integer o) { return add(o.intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default boolean contains(Object o) { return o != null && contains(((Integer)o).intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default boolean remove(Object o) { return o != null && remInt(((Integer)o).intValue()); } + + /** + * Returns a Type-Specific Iterator to reduce (un)boxing + * @return a iterator of the collection + * @see Collection#iterator() + */ + @Override + public IntIterator iterator(); + + /** + * Creates a Wrapped Collection that is Synchronized + * @return a new Collection that is synchronized + * @see IntCollections#synchronize + */ + public default IntCollection synchronize() { return IntCollections.synchronize(this); } + + /** + * Creates a Wrapped Collection that is Synchronized + * @param mutex is the controller of the synchronization block + * @return a new Collection Wrapper that is synchronized + * @see IntCollections#synchronize + */ + public default IntCollection synchronize(Object mutex) { return IntCollections.synchronize(this, mutex); } + + /** + * Creates a Wrapped Collection that is unmodifiable + * @return a new Collection Wrapper that is unmodifiable + * @see IntCollections#unmodifiable + */ + public default IntCollection unmodifiable() { return IntCollections.unmodifiable(this); } + + /** + * Returns a Java-Type-Specific Stream to reduce boxing/unboxing. + * @return a Stream of the closest java type + */ + default IntStream primitiveStream() { return StreamSupport.intStream(IntSplititerators.createJavaSplititerator(this, 0), false); } + + /** + * Returns a Java-Type-Specific Parallel Stream to reduce boxing/unboxing. + * @return a Stream of the closest java type + */ + default IntStream parallelPrimitiveStream() { return StreamSupport.intStream(IntSplititerators.createJavaSplititerator(this, 0), true); } + + /** + * A Type Specific Type Splititerator to reduce boxing/unboxing + * @return type specific splititerator + */ + @Override + default IntSplititerator spliterator() { return IntSplititerators.createSplititerator(this, 0); } +} diff --git a/src/main/java/speiger/src/collections/ints/collections/IntIterable.java b/src/main/java/speiger/src/collections/ints/collections/IntIterable.java new file mode 100644 index 000000000..6cdae2d4a --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/collections/IntIterable.java @@ -0,0 +1,314 @@ +package speiger.src.collections.ints.collections; + +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.IntPredicate; + + +import speiger.src.collections.ints.functions.IntConsumer; +import speiger.src.collections.ints.functions.IntComparator; +import speiger.src.collections.objects.collections.ObjectIterable; +import speiger.src.collections.ints.functions.function.IntFunction; +import speiger.src.collections.ints.functions.consumer.IntIntConsumer; +import speiger.src.collections.objects.functions.consumer.ObjectIntConsumer; +import speiger.src.collections.ints.functions.function.IntIntUnaryOperator; + +import speiger.src.collections.ints.utils.IntArrays; +import speiger.src.collections.ints.utils.IntSplititerators; +import speiger.src.collections.ints.utils.IntIterables; +import speiger.src.collections.ints.utils.IntIterators; +import speiger.src.collections.utils.ISizeProvider; + +/** + * A Type-Specific {@link Iterable} that reduces (un)boxing + */ +public interface IntIterable extends Iterable +{ + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + IntIterator iterator(); + + /** + * A Type Specific foreach function that reduces (un)boxing + * + * @implSpec + *

The default implementation behaves as if: + *

{@code
+	 *	iterator().forEachRemaining(action);
+	 * }
+ * + * @param action The action to be performed for each element + * @throws NullPointerException if the specified action is null + * @see Iterable#forEach(Consumer) + */ + default void forEach(IntConsumer action) { + Objects.requireNonNull(action); + iterator().forEachRemaining(action); + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Deprecated + @Override + default void forEach(Consumer action) { + Objects.requireNonNull(action); + iterator().forEachRemaining(action); + } + + /** + * A Indexed forEach implementation that allows you to keep track of how many elements were already iterated over. + * @param action The action to be performed for each element + * @throws NullPointerException if the specified action is null + */ + public default void forEachIndexed(IntIntConsumer action) { + Objects.requireNonNull(action); + int index = 0; + for(IntIterator iter = iterator();iter.hasNext();action.accept(index++, iter.nextInt())); + } + + /** + * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. + * @param input the object that should be included + * @param action The action to be performed for each element + * @param the generic type of the Object + * @throws NullPointerException if the specified action is null + */ + default void forEach(E input, ObjectIntConsumer action) { + Objects.requireNonNull(action); + iterator().forEachRemaining(input, action); + } + + /** + * A Type Specific Type Splititerator to reduce boxing/unboxing + * @return type specific splititerator + */ + @Override + default IntSplititerator spliterator() { return IntSplititerators.createUnknownSplititerator(iterator(), 0); } + + /** + * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. + * @param mapper the mapping function + * @param The return type. + * @return a new Iterable that returns the desired result + */ + default ObjectIterable map(IntFunction mapper) { + return IntIterables.map(this, mapper); + } + + /** + * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. + * @param mapper the flatMapping function + * @param The return type supplier. + * @param The return type. + * @return a new Iterable that returns the desired result + * @note does not support toIntArray optimizations. + */ + default > ObjectIterable flatMap(IntFunction mapper) { + return IntIterables.flatMap(this, mapper); + } + + /** + * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. + * @param mapper the flatMapping function + * @param The return type. + * @return a new Iterable that returns the desired result + * @note does not support toIntArray optimizations. + */ + default ObjectIterable arrayflatMap(IntFunction mapper) { + return IntIterables.arrayFlatMap(this, mapper); + } + + /** + * A Helper function to reduce the usage of Streams and allows to filter out unwanted elements + * @param filter the elements that should be kept. + * @return a Iterable that filtered out all unwanted elements + * @note does not support toIntArray optimizations. + */ + default IntIterable filter(IntPredicate filter) { + return IntIterables.filter(this, filter); + } + + /** + * A Helper function to reduce the usage of Streams and allows to filter out duplicated elements + * @return a Iterable that filtered out all duplicated elements + * @note does not support toIntArray optimizations. + */ + default IntIterable distinct() { + return IntIterables.distinct(this); + } + + /** + * A Helper function to reduce the usage of Streams and allows to repeat elements a desired amount of times + * @param repeats how many times the elements should be repeated + * @return a Iterable that is repeating multiple times + */ + default IntIterable repeat(int repeats) { + return IntIterables.repeat(this, repeats); + } + + /** + * A Helper function to reduce the usage of Streams and allows to limit the amount of elements + * @param limit the amount of elements it should be limited to + * @return a Iterable that is limited in length + */ + default IntIterable limit(long limit) { + return IntIterables.limit(this, limit); + } + + /** + * A Helper function to reduce the usage of Streams and allows to sort the elements + * @param sorter that sorts the elements. + * @return a Iterable that is sorted + */ + default IntIterable sorted(IntComparator sorter) { + return IntIterables.sorted(this, sorter); + } + + /** + * A Helper function to reduce the usage of Streams and allows to preview elements before they are iterated through + * @param action the action that should be applied + * @return a Peeked Iterable + */ + default IntIterable peek(IntConsumer action) { + return IntIterables.peek(this, action); + } + + /** + * A Helper function to reduce the usage of Streams and allows to collect all elements + * @param collection that the elements should be inserted to + * @param the collection type + * @return the input with the desired elements + */ + default E pour(E collection) { + IntIterators.pour(iterator(), collection); + return collection; + } + + + /** + * A Helper function that reduces the usage of streams and allows to collect all elements as a Array + * @return a new Array of all elements + */ + default int[] toIntArray() { + ISizeProvider prov = ISizeProvider.of(this); + if(prov != null) { + int size = prov.size(); + if(size >= 0) { + int[] array = new int[size]; + IntIterators.unwrap(array, iterator()); + return array; + } + } + return IntArrays.pour(iterator()); + } + + /** + * Helper function to reduce stream usage that allows to filter for any matches. + * @param filter that should be applied + * @return true if any matches were found + */ + default boolean matchesAny(IntPredicate filter) { + Objects.requireNonNull(filter); + for(IntIterator iter = iterator();iter.hasNext();) { + if(filter.test(iter.nextInt())) return true; + } + return false; + } + + /** + * Helper function to reduce stream usage that allows to filter for no matches. + * @param filter that should be applied + * @return true if no matches were found + */ + default boolean matchesNone(IntPredicate filter) { + Objects.requireNonNull(filter); + for(IntIterator iter = iterator();iter.hasNext();) { + if(filter.test(iter.nextInt())) return false; + } + return true; + } + + /** + * Helper function to reduce stream usage that allows to filter for all matches. + * @param filter that should be applied + * @return true if all matches. + */ + default boolean matchesAll(IntPredicate filter) { + Objects.requireNonNull(filter); + for(IntIterator iter = iterator();iter.hasNext();) { + if(!filter.test(iter.nextInt())) return false; + } + return true; + } + + /** + * Helper function to reduce stream usage that allows to filter for the first match. + * @param filter that should be applied + * @return the found value or the null equivalent variant. + */ + default int findFirst(IntPredicate filter) { + Objects.requireNonNull(filter); + for(IntIterator iter = iterator();iter.hasNext();) { + int entry = iter.nextInt(); + if(filter.test(entry)) return entry; + } + return 0; + } + + /** + * Performs a reduction on the + * elements of this Iterable + * @param operator the operation that should be applied + * @param identity the start value + * @return the reduction result, returns identity if nothing was found + */ + default int reduce(int identity, IntIntUnaryOperator operator) { + Objects.requireNonNull(operator); + int state = identity; + for(IntIterator iter = iterator();iter.hasNext();) { + state = operator.applyAsInt(state, iter.nextInt()); + } + return state; + } + + /** + * Performs a reduction on the + * elements of this Iterable + * @param operator the operation that should be applied + * @return the reduction result, returns null value if nothing was found + */ + default int reduce(IntIntUnaryOperator operator) { + Objects.requireNonNull(operator); + int state = 0; + boolean empty = true; + for(IntIterator iter = iterator();iter.hasNext();) { + if(empty) { + empty = false; + state = iter.nextInt(); + continue; + } + state = operator.applyAsInt(state, iter.nextInt()); + } + return state; + } + + /** + * Helper function to reduce stream usage that allows to count the valid elements. + * @param filter that should be applied + * @return the amount of Valid Elements + */ + default int count(IntPredicate filter) { + Objects.requireNonNull(filter); + int result = 0; + for(IntIterator iter = iterator();iter.hasNext();) { + if(filter.test(iter.nextInt())) result++; + } + return result; + } +} diff --git a/src/main/java/speiger/src/collections/ints/collections/IntIterator.java b/src/main/java/speiger/src/collections/ints/collections/IntIterator.java new file mode 100644 index 000000000..626ff1c82 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/collections/IntIterator.java @@ -0,0 +1,88 @@ +package speiger.src.collections.ints.collections; + +import java.util.Iterator; +import java.util.Objects; +import java.util.function.Consumer; + +import speiger.src.collections.ints.functions.IntConsumer; + +import speiger.src.collections.objects.functions.consumer.ObjectIntConsumer; + +/** + * A Type-Specific {@link Iterator} that reduces (un)boxing + */ +public interface IntIterator extends Iterator +{ + /** + * Returns the next element in the iteration. + * + * @return the next element in the iteration + * @throws java.util.NoSuchElementException if the iteration has no more elements + * @see Iterator#next() + */ + public int nextInt(); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default Integer next() { return Integer.valueOf(nextInt()); } + + /** + * Performs the given action for each remaining element until all elements + * have been processed or the action throws an exception. Actions are + * performed in the order of iteration, if that order is specified. + * Exceptions thrown by the action are relayed to the caller. + * + * @implSpec + *

The default implementation behaves as if: + *

{@code
+	 *	while (hasNext()) action.accept(nextInt());
+	 * }
+ * + * @param action The action to be performed for each element + * @throws NullPointerException if the specified action is null + * @see Iterator#forEachRemaining(Consumer) + */ + public default void forEachRemaining(IntConsumer action) { + Objects.requireNonNull(action); + while(hasNext()) { action.accept(nextInt()); } + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Deprecated + @Override + default void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + forEachRemaining(action::accept); + } + + /** + * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. + * @param input the object that should be included + * @param action The action to be performed for each element + * @param the generic type of the Object + * @throws NullPointerException if the specified action is null + */ + default void forEachRemaining(E input, ObjectIntConsumer action) { + Objects.requireNonNull(action); + while(hasNext()) { action.accept(input, nextInt()); } + } + + /** + * Skips the Given amount of elements if possible. A Optimization function to skip elements faster if the implementation allows it. + * @param amount the amount of elements that should be skipped + * @return the amount of elements that were skipped + */ + default int skip(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int i = 0; + for(;i, IntIterator +{ + @Override + default void forEachRemaining(IntConsumer action) { IntIterator.super.forEachRemaining(action); } + @Override + @Deprecated + default void forEachRemaining(Consumer action) { IntIterator.super.forEachRemaining(action); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/collections/IntStack.java b/src/main/java/speiger/src/collections/ints/collections/IntStack.java new file mode 100644 index 000000000..57731e4c5 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/collections/IntStack.java @@ -0,0 +1,62 @@ +package speiger.src.collections.ints.collections; + +import speiger.src.collections.utils.Stack; + +/** + * A Type-Specific {@link Stack} that reduces (un)boxing + */ +public interface IntStack +{ + /** + * Inserts a given Object on top of the stack + * @param e the Object to insert + * @see Stack#push(Object) + */ + public void push(int e); + + /** + * Removes the Object on top of the stack. + * @return the element that is on top of the stack + * @throws ArrayIndexOutOfBoundsException if the stack is empty + * @see Stack#pop() + */ + public int pop(); + + /** + * Provides the Object on top of the stack + * @return the element that is on top of the stack + * @throws ArrayIndexOutOfBoundsException if the stack is empty + * @see Stack#top() + */ + public default int top() { + return peek(0); + } + + /** + * Provides the Selected Object from the stack. + * Top to bottom + * @param index of the element that should be provided + * @return the element that was requested + * @throws ArrayIndexOutOfBoundsException if the index is out of bounds + * @see Stack#peek(int) + */ + public int peek(int index); + + /** + * Clears the stack + */ + public void clear(); + + /** + * Provides the amount of elements currently in the stack + * @return amount of elements in the list + */ + public int size(); + + /** + * @return if the stack is empty + */ + public default boolean isEmpty() { + return size() == 0; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/IntComparator.java b/src/main/java/speiger/src/collections/ints/functions/IntComparator.java new file mode 100644 index 000000000..81a78895b --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/IntComparator.java @@ -0,0 +1,70 @@ +package speiger.src.collections.ints.functions; + +import java.util.Comparator; +import java.util.Objects; + +/** + * Type-Specific Class for Comparator to reduce (un)boxing + */ +public interface IntComparator extends Comparator +{ + /** + * Type-Specific compare function to reduce (un)boxing + * @param o1 the first object to be compared. + * @param o2 the second object to be compared. + * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. + * @see Comparator#compare(Object, Object) + */ + int compare(int o1, int o2); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default int compare(Integer o1, Integer o2) { + return compare(o1.intValue(), o2.intValue()); + } + + /** + * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator + * @param c comparator to convert + * @return the wrapper of the comparator + * @throws NullPointerException if the comparator is null + */ + public static IntComparator of(Comparator c) { + Objects.requireNonNull(c); + return (K, V) -> c.compare(Integer.valueOf(K), Integer.valueOf(V)); + } + + @Override + public default IntComparator reversed() { + return new Reversed(this); + } + + /** + * A Type Specific Reversed Comparator to reduce boxing/unboxing + */ + static class Reversed implements IntComparator + { + IntComparator original; + + /** + * default constructor + * @param original that is going to be reversed + */ + public Reversed(IntComparator original) { + this.original = original; + } + + public int compare(int o1, int o2) { + return original.compare(o2, o1); + } + + @Override + public IntComparator reversed() { + return original; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/IntConsumer.java b/src/main/java/speiger/src/collections/ints/functions/IntConsumer.java new file mode 100644 index 000000000..0bd0e65fb --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/IntConsumer.java @@ -0,0 +1,59 @@ +package speiger.src.collections.ints.functions; + +import java.util.Objects; +import java.util.function.Consumer; +/** + * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +@FunctionalInterface +public interface IntConsumer extends Consumer, java.util.function.IntConsumer +{ + /** + * Type-Specific function to reduce (un)boxing. + * Performs this operation on the given argument. + * + * @param t the input argument + */ + void accept(int t); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced consumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default IntConsumer andThen(IntConsumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(T);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Integer t) { accept(t.intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default IntConsumer andThen(Consumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(Integer.valueOf(T));}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default IntConsumer andThen(java.util.function.IntConsumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(T);}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/IntSupplier.java b/src/main/java/speiger/src/collections/ints/functions/IntSupplier.java new file mode 100644 index 000000000..10d7293c8 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/IntSupplier.java @@ -0,0 +1,12 @@ +package speiger.src.collections.ints.functions; + +/** + * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +public interface IntSupplier extends java.util.function.IntSupplier +{ + /** + * @return the supplied value + */ + public int getAsInt(); +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntBooleanConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntBooleanConsumer.java new file mode 100644 index 000000000..deb8915ca --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/consumer/IntBooleanConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.ints.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface IntBooleanConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(int k, boolean v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default IntBooleanConsumer andThen(IntBooleanConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Integer k, Boolean v) { accept(k.intValue(), v.booleanValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default IntBooleanConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Boolean.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntByteConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntByteConsumer.java new file mode 100644 index 000000000..c5774680d --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/consumer/IntByteConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.ints.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface IntByteConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(int k, byte v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default IntByteConsumer andThen(IntByteConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Integer k, Byte v) { accept(k.intValue(), v.byteValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default IntByteConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Byte.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntCharConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntCharConsumer.java new file mode 100644 index 000000000..74a0ff391 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/consumer/IntCharConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.ints.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface IntCharConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(int k, char v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default IntCharConsumer andThen(IntCharConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Integer k, Character v) { accept(k.intValue(), v.charValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default IntCharConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Character.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntDoubleConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntDoubleConsumer.java new file mode 100644 index 000000000..fb44f3df3 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/consumer/IntDoubleConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.ints.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface IntDoubleConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(int k, double v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default IntDoubleConsumer andThen(IntDoubleConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Integer k, Double v) { accept(k.intValue(), v.doubleValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default IntDoubleConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Double.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntFloatConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntFloatConsumer.java new file mode 100644 index 000000000..766d64158 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/consumer/IntFloatConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.ints.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface IntFloatConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(int k, float v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default IntFloatConsumer andThen(IntFloatConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Integer k, Float v) { accept(k.intValue(), v.floatValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default IntFloatConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Float.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntIntConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntIntConsumer.java new file mode 100644 index 000000000..f8a000a33 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/consumer/IntIntConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.ints.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface IntIntConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(int k, int v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default IntIntConsumer andThen(IntIntConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Integer k, Integer v) { accept(k.intValue(), v.intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default IntIntConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Integer.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntLongConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntLongConsumer.java new file mode 100644 index 000000000..401e5b4f7 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/consumer/IntLongConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.ints.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface IntLongConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(int k, long v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default IntLongConsumer andThen(IntLongConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Integer k, Long v) { accept(k.intValue(), v.longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default IntLongConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Long.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntObjectConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntObjectConsumer.java new file mode 100644 index 000000000..cfa621bcb --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/consumer/IntObjectConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.ints.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface IntObjectConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(int k, V v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default IntObjectConsumer andThen(IntObjectConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Integer k, V v) { accept(k.intValue(), v); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default IntObjectConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), V);}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntShortConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntShortConsumer.java new file mode 100644 index 000000000..254d7f669 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/consumer/IntShortConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.ints.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface IntShortConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(int k, short v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default IntShortConsumer andThen(IntShortConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Integer k, Short v) { accept(k.intValue(), v.shortValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default IntShortConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Short.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2ByteFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2ByteFunction.java new file mode 100644 index 000000000..21c2e245b --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/Int2ByteFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.ints.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Int2ByteFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public byte applyAsByte(int k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2CharFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2CharFunction.java new file mode 100644 index 000000000..51a398bbe --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/Int2CharFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.ints.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Int2CharFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public char applyAsChar(int k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2DoubleFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2DoubleFunction.java new file mode 100644 index 000000000..2de20d298 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/Int2DoubleFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.ints.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Int2DoubleFunction extends java.util.function.IntToDoubleFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public double applyAsDouble(int k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2FloatFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2FloatFunction.java new file mode 100644 index 000000000..ea5f500c7 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/Int2FloatFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.ints.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Int2FloatFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public float applyAsFloat(int k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2LongFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2LongFunction.java new file mode 100644 index 000000000..01311f37d --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/Int2LongFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.ints.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Int2LongFunction extends java.util.function.IntToLongFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public long applyAsLong(int k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2ShortFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2ShortFunction.java new file mode 100644 index 000000000..0364640e5 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/Int2ShortFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.ints.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Int2ShortFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public short applyAsShort(int k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntBooleanUnaryOperator.java new file mode 100644 index 000000000..c733dc345 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntBooleanUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.ints.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface IntBooleanUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public boolean applyAsBoolean(int k, boolean v); + + @Override + public default Boolean apply(Integer k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.intValue(), v.booleanValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntByteUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntByteUnaryOperator.java new file mode 100644 index 000000000..13131d4f9 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntByteUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.ints.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface IntByteUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public byte applyAsByte(int k, byte v); + + @Override + public default Byte apply(Integer k, Byte v) { return Byte.valueOf(applyAsByte(k.intValue(), v.byteValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntCharUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntCharUnaryOperator.java new file mode 100644 index 000000000..d77f63888 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntCharUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.ints.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface IntCharUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public char applyAsChar(int k, char v); + + @Override + public default Character apply(Integer k, Character v) { return Character.valueOf(applyAsChar(k.intValue(), v.charValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntDoubleUnaryOperator.java new file mode 100644 index 000000000..d6abe599d --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntDoubleUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.ints.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface IntDoubleUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public double applyAsDouble(int k, double v); + + @Override + public default Double apply(Integer k, Double v) { return Double.valueOf(applyAsDouble(k.intValue(), v.doubleValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntFloatUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntFloatUnaryOperator.java new file mode 100644 index 000000000..5b306c323 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntFloatUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.ints.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface IntFloatUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public float applyAsFloat(int k, float v); + + @Override + public default Float apply(Integer k, Float v) { return Float.valueOf(applyAsFloat(k.intValue(), v.floatValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/IntFunction.java new file mode 100644 index 000000000..4660c7194 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.ints.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface IntFunction extends java.util.function.IntFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public V apply(int k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntIntUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntIntUnaryOperator.java new file mode 100644 index 000000000..6b92a8a51 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntIntUnaryOperator.java @@ -0,0 +1,13 @@ +package speiger.src.collections.ints.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ + +public interface IntIntUnaryOperator extends BiFunction, java.util.function.IntBinaryOperator +{ + @Override + public default Integer apply(Integer k, Integer v) { return Integer.valueOf(applyAsInt(k.intValue(), v.intValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntLongUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntLongUnaryOperator.java new file mode 100644 index 000000000..008526f80 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntLongUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.ints.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface IntLongUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public long applyAsLong(int k, long v); + + @Override + public default Long apply(Integer k, Long v) { return Long.valueOf(applyAsLong(k.intValue(), v.longValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntObjectUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntObjectUnaryOperator.java new file mode 100644 index 000000000..338e398b5 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntObjectUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.ints.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface IntObjectUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public V apply(int k, V v); + + @Override + public default V apply(Integer k, V v) { return apply(k.intValue(), v); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntPredicate.java b/src/main/java/speiger/src/collections/ints/functions/function/IntPredicate.java new file mode 100644 index 000000000..7f7c138f6 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntPredicate.java @@ -0,0 +1,72 @@ +package speiger.src.collections.ints.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface IntPredicate extends java.util.function.IntPredicate +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public boolean test(int k); + + /** + * Creates a Always true function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static IntPredicate alwaysTrue() { + return T -> true; + } + + /** + * Creates a Always false function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static IntPredicate alwaysFalse() { + return T -> false; + } + + /** + * A Type specific and-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a and comparason + */ + public default IntPredicate andType(IntPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + @Override + @Deprecated + public default IntPredicate and(java.util.function.IntPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + @Override + public default IntPredicate negate() { + return T -> !test(T); + } + + /** + * A Type specific or-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a or comparason + */ + public default IntPredicate orType(IntPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } + + @Override + @Deprecated + public default IntPredicate or(java.util.function.IntPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntShortUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntShortUnaryOperator.java new file mode 100644 index 000000000..2f4648aaf --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntShortUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.ints.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface IntShortUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public short applyAsShort(int k, short v); + + @Override + public default Short apply(Integer k, Short v) { return Short.valueOf(applyAsShort(k.intValue(), v.shortValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntUnaryOperator.java new file mode 100644 index 000000000..0693d8085 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/functions/function/IntUnaryOperator.java @@ -0,0 +1,54 @@ +package speiger.src.collections.ints.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface IntUnaryOperator extends java.util.function.IntUnaryOperator +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public int applyAsInt(int k); + + /** + * Creates a Default function that returns the input provided. + * @return a input returning function + */ + public static IntUnaryOperator identity() { + return T -> T; + } + + /** + * Returns a composed function that first applies the {@code before} + * function to its input, and then applies this function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param before the function that should be used first + * @return a composed function with a different starting function. + */ + public default IntUnaryOperator compose(IntUnaryOperator before) { + Objects.requireNonNull(before); + return T -> applyAsInt(before.applyAsInt(T)); + } + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param after the function that should be used last + * @return a composed function with a different starting function. + */ + public default IntUnaryOperator andThen(IntUnaryOperator after) { + Objects.requireNonNull(after); + return T -> after.applyAsInt(applyAsInt(T)); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/lists/IntListIterator.java b/src/main/java/speiger/src/collections/ints/lists/IntListIterator.java new file mode 100644 index 000000000..425aa06df --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/lists/IntListIterator.java @@ -0,0 +1,65 @@ +package speiger.src.collections.ints.lists; + +import java.util.ListIterator; + +import speiger.src.collections.ints.collections.IntBidirectionalIterator; + +/** + * A Type Specific ListIterator that reduces boxing/unboxing + */ +public interface IntListIterator extends ListIterator, IntBidirectionalIterator +{ + /** + * A Primitive set function to reduce (un)boxing + * @param e the element that should replace the last returned value + * @see ListIterator#set(Object) + */ + public void set(int e); + + /** + * A Primitive set function to reduce (un)boxing + * @param e the element that should be inserted before the last returned value + * @see ListIterator#set(Object) + */ + public void add(int e); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default Integer previous() { + return IntBidirectionalIterator.super.previous(); + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default Integer next() { + return IntBidirectionalIterator.super.next(); + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default void set(Integer e) { + set(e.intValue()); + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default void add(Integer e) { + add(e.intValue()); + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/maps/abstracts/AbstractInt2ObjectMap.java b/src/main/java/speiger/src/collections/ints/maps/abstracts/AbstractInt2ObjectMap.java new file mode 100644 index 000000000..855d3d2b9 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/maps/abstracts/AbstractInt2ObjectMap.java @@ -0,0 +1,451 @@ +package speiger.src.collections.ints.maps.abstracts; + +import java.util.AbstractMap; +import java.util.Map; +import java.util.Objects; + +import speiger.src.collections.ints.collections.IntIterator; +import speiger.src.collections.ints.functions.consumer.IntObjectConsumer; +import speiger.src.collections.ints.functions.function.IntFunction; +import speiger.src.collections.ints.functions.function.IntObjectUnaryOperator; +import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap; +import speiger.src.collections.ints.sets.AbstractIntSet; +import speiger.src.collections.ints.sets.IntSet; +import speiger.src.collections.objects.collections.AbstractObjectCollection; +import speiger.src.collections.objects.collections.ObjectCollection; +import speiger.src.collections.objects.collections.ObjectIterator; +import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator; +import speiger.src.collections.objects.functions.ObjectSupplier; +import speiger.src.collections.objects.collections.ObjectIterable; +import speiger.src.collections.objects.sets.ObjectSet; +import speiger.src.collections.utils.SanityChecks; + +/** + * A Base Implementation of a Type Specific Map to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public abstract class AbstractInt2ObjectMap extends AbstractMap implements Int2ObjectMap +{ + protected V defaultReturnValue = null; + + @Override + public V getDefaultReturnValue() { + return defaultReturnValue; + } + + @Override + public AbstractInt2ObjectMap setDefaultReturnValue(V v) { + defaultReturnValue = v; + return this; + } + + protected ObjectIterable> getFastIterable(Int2ObjectMap map) { + return map.int2ObjectEntrySet(); + } + + protected ObjectIterator> getFastIterator(Int2ObjectMap map) { + return map.int2ObjectEntrySet().iterator(); + } + + @Override + public Int2ObjectMap copy() { + throw new UnsupportedOperationException(); + } + + @Override + @Deprecated + public V put(Integer key, V value) { + return put(key.intValue(), value); + } + + @Override + public void putAll(Int2ObjectMap m) { + for(ObjectIterator> iter = getFastIterator(m);iter.hasNext();) { + Int2ObjectMap.Entry entry = iter.next(); + put(entry.getIntKey(), entry.getValue()); + } + } + + @Override + public void putAll(Map m) + { + if(m instanceof Int2ObjectMap) putAll((Int2ObjectMap)m); + else super.putAll(m); + } + + @Override + public void putAll(int[] keys, V[] values, int offset, int size) { + SanityChecks.checkArrayCapacity(keys.length, offset, size); + SanityChecks.checkArrayCapacity(values.length, offset, size); + for(int i = 0;i m) { + for(Int2ObjectMap.Entry entry : getFastIterable(m)) + putIfAbsent(entry.getIntKey(), entry.getValue()); + } + + + @Override + public boolean containsKey(int key) { + for(IntIterator iter = keySet().iterator();iter.hasNext();) + if(iter.nextInt() == key) return true; + return false; + } + + @Override + public boolean containsValue(Object value) { + for(ObjectIterator iter = values().iterator();iter.hasNext();) + if(Objects.equals(value, iter.next())) return true; + return false; + } + + @Override + public boolean replace(int key, V oldValue, V newValue) { + V curValue = get(key); + if (!Objects.equals(curValue, oldValue) || (Objects.equals(curValue, getDefaultReturnValue()) && !containsKey(key))) { + return false; + } + put(key, newValue); + return true; + } + + @Override + public V replace(int key, V value) { + V curValue; + if (!Objects.equals((curValue = get(key)), getDefaultReturnValue()) || containsKey(key)) { + curValue = put(key, value); + } + return curValue; + } + + @Override + public void replaceObjects(Int2ObjectMap m) { + for(Int2ObjectMap.Entry entry : getFastIterable(m)) + replace(entry.getIntKey(), entry.getValue()); + } + + @Override + public void replaceObjects(IntObjectUnaryOperator mappingFunction) { + Objects.requireNonNull(mappingFunction); + for(ObjectIterator> iter = getFastIterator(this);iter.hasNext();) { + Int2ObjectMap.Entry entry = iter.next(); + entry.setValue(mappingFunction.apply(entry.getIntKey(), entry.getValue())); + } + } + + @Override + public V compute(int key, IntObjectUnaryOperator mappingFunction) { + Objects.requireNonNull(mappingFunction); + V value = get(key); + V newValue = mappingFunction.apply(key, value); + if(Objects.equals(newValue, getDefaultReturnValue())) { + if(!Objects.equals(value, getDefaultReturnValue()) || containsKey(key)) { + remove(key); + return getDefaultReturnValue(); + } + return getDefaultReturnValue(); + } + put(key, newValue); + return newValue; + } + + @Override + public V computeIfAbsent(int key, IntFunction mappingFunction) { + Objects.requireNonNull(mappingFunction); + V value; + if((value = get(key)) == getDefaultReturnValue() || !containsKey(key)) { + V newValue = mappingFunction.apply(key); + if(!Objects.equals(newValue, getDefaultReturnValue())) { + put(key, newValue); + return newValue; + } + } + return value; + } + + @Override + public V supplyIfAbsent(int key, ObjectSupplier valueProvider) { + Objects.requireNonNull(valueProvider); + V value; + if((value = get(key)) == getDefaultReturnValue() || !containsKey(key)) { + V newValue = valueProvider.get(); + if(!Objects.equals(newValue, getDefaultReturnValue())) { + put(key, newValue); + return newValue; + } + } + return value; + } + + @Override + public V computeIfPresent(int key, IntObjectUnaryOperator mappingFunction) { + Objects.requireNonNull(mappingFunction); + V value; + if(!Objects.equals((value = get(key)), getDefaultReturnValue()) || containsKey(key)) { + V newValue = mappingFunction.apply(key, value); + if(!Objects.equals(newValue, getDefaultReturnValue())) { + put(key, newValue); + return newValue; + } + remove(key); + } + return getDefaultReturnValue(); + } + + @Override + public V merge(int key, V value, ObjectObjectUnaryOperator mappingFunction) { + Objects.requireNonNull(mappingFunction); + V oldValue = get(key); + V newValue = Objects.equals(oldValue, getDefaultReturnValue()) ? value : mappingFunction.apply(oldValue, value); + if(Objects.equals(newValue, getDefaultReturnValue())) remove(key); + else put(key, newValue); + return newValue; + } + + @Override + public void mergeAll(Int2ObjectMap m, ObjectObjectUnaryOperator mappingFunction) { + Objects.requireNonNull(mappingFunction); + for(Int2ObjectMap.Entry entry : getFastIterable(m)) { + int key = entry.getIntKey(); + V oldValue = get(key); + V newValue = Objects.equals(oldValue, getDefaultReturnValue()) ? entry.getValue() : mappingFunction.apply(oldValue, entry.getValue()); + if(Objects.equals(newValue, getDefaultReturnValue())) remove(key); + else put(key, newValue); + } + } + + @Override + public V get(Object key) { + return key instanceof Integer ? get(((Integer)key).intValue()) : getDefaultReturnValue(); + } + + @Override + public V getOrDefault(Object key, V defaultValue) { + return key instanceof Integer ? getOrDefault(((Integer)key).intValue(), defaultValue) : getDefaultReturnValue(); + } + + @Override + public V getOrDefault(int key, V defaultValue) { + V value = get(key); + return !Objects.equals(value, getDefaultReturnValue()) || containsKey(key) ? value : defaultValue; + } + + + @Override + public V remove(Object key) { + return key instanceof Integer ? remove(((Integer)key).intValue()) : getDefaultReturnValue(); + } + + @Override + public void forEach(IntObjectConsumer action) { + Objects.requireNonNull(action); + for(ObjectIterator> iter = getFastIterator(this);iter.hasNext();) { + Int2ObjectMap.Entry entry = iter.next(); + action.accept(entry.getIntKey(), entry.getValue()); + } + } + + @Override + public IntSet keySet() { + return new AbstractIntSet() { + @Override + public boolean remove(int o) { + return !Objects.equals(AbstractInt2ObjectMap.this.remove(o), getDefaultReturnValue()); + } + + @Override + public boolean add(int o) { + throw new UnsupportedOperationException(); + } + + @Override + public IntIterator iterator() { + return new IntIterator() { + ObjectIterator> iter = getFastIterator(AbstractInt2ObjectMap.this); + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public int nextInt() { + return iter.next().getIntKey(); + } + + @Override + public void remove() { + iter.remove(); + } + }; + } + + @Override + public int size() { + return AbstractInt2ObjectMap.this.size(); + } + + @Override + public void clear() { + AbstractInt2ObjectMap.this.clear(); + } + }; + } + + @Override + public ObjectCollection values() { + return new AbstractObjectCollection() { + @Override + public boolean add(V o) { + throw new UnsupportedOperationException(); + } + + @Override + public int size() { + return AbstractInt2ObjectMap.this.size(); + } + + @Override + public void clear() { + AbstractInt2ObjectMap.this.clear(); + } + + @Override + public ObjectIterator iterator() { + return new ObjectIterator() { + ObjectIterator> iter = getFastIterator(AbstractInt2ObjectMap.this); + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public V next() { + return iter.next().getValue(); + } + + @Override + public void remove() { + iter.remove(); + } + }; + } + }; + } + + @Override + @SuppressWarnings("rawtypes") + public ObjectSet> entrySet() { + return (ObjectSet)int2ObjectEntrySet(); + } + + @Override + public boolean equals(Object o) { + if(o == this) return true; + if(o instanceof Map) { + if(size() != ((Map)o).size()) return false; + if(o instanceof Int2ObjectMap) return int2ObjectEntrySet().containsAll(((Int2ObjectMap)o).int2ObjectEntrySet()); + return int2ObjectEntrySet().containsAll(((Map)o).entrySet()); + } + return false; + } + + @Override + public int hashCode() { + int hash = 0; + ObjectIterator> iter = getFastIterator(this); + while(iter.hasNext()) hash += iter.next().hashCode(); + return hash; + } + + /** + * A Simple Type Specific Entry class to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ + public static class BasicEntry implements Int2ObjectMap.Entry { + protected int key; + protected V value; + + /** + * A basic Empty constructor + */ + public BasicEntry() {} + /** + * A Boxed Constructor for supporting java variants + * @param key the key of a entry + * @param value the value of a entry + */ + public BasicEntry(Integer key, V value) { + this.key = key.intValue(); + this.value = value; + } + + /** + * A Type Specific Constructor + * @param key the key of a entry + * @param value the value of a entry + */ + public BasicEntry(int key, V value) { + this.key = key; + this.value = value; + } + + /** + * A Helper method for fast replacing values + * @param key the key that should be replaced + * @param value the value that should be replaced + */ + public void set(int key, V value) { + this.key = key; + this.value = value; + } + + @Override + public int getIntKey() { + return key; + } + + @Override + public V getValue() { + return value; + } + + @Override + public V setValue(V value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object obj) { + if(obj instanceof Map.Entry) { + if(obj instanceof Int2ObjectMap.Entry) { + Int2ObjectMap.Entry entry = (Int2ObjectMap.Entry)obj; + return key == entry.getIntKey() && Objects.equals(value, entry.getValue()); + } + Map.Entry entry = (Map.Entry)obj; + Object key = entry.getKey(); + Object value = entry.getValue(); + return key instanceof Integer && this.key == ((Integer)key).intValue() && Objects.equals(this.value, value); + } + return false; + } + + @Override + public int hashCode() { + return Integer.hashCode(key) ^ Objects.hashCode(value); + } + + @Override + public String toString() { + return Integer.toString(key) + "=" + Objects.toString(value); + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/maps/impl/misc/Int2ObjectArrayMap.java b/src/main/java/speiger/src/collections/ints/maps/impl/misc/Int2ObjectArrayMap.java new file mode 100644 index 000000000..2e6f09621 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/maps/impl/misc/Int2ObjectArrayMap.java @@ -0,0 +1,1296 @@ +package speiger.src.collections.ints.maps.impl.misc; + +import java.util.Arrays; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.BiFunction; +import java.util.function.Predicate; +import java.util.function.IntPredicate; + +import speiger.src.collections.ints.collections.IntBidirectionalIterator; +import speiger.src.collections.ints.functions.IntConsumer; +import speiger.src.collections.objects.functions.consumer.ObjectIntConsumer; +import speiger.src.collections.ints.functions.consumer.IntIntConsumer; +import speiger.src.collections.ints.functions.consumer.IntObjectConsumer; +import speiger.src.collections.ints.functions.consumer.IntObjectConsumer; +import speiger.src.collections.ints.functions.function.IntFunction; +import speiger.src.collections.ints.functions.function.IntObjectUnaryOperator; +import speiger.src.collections.ints.functions.function.IntIntUnaryOperator; +import speiger.src.collections.ints.lists.IntListIterator; +import speiger.src.collections.ints.maps.abstracts.AbstractInt2ObjectMap; +import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap; +import speiger.src.collections.ints.maps.interfaces.Int2ObjectOrderedMap; +import speiger.src.collections.ints.sets.AbstractIntSet; +import speiger.src.collections.ints.sets.IntOrderedSet; +import speiger.src.collections.objects.collections.AbstractObjectCollection; +import speiger.src.collections.objects.collections.ObjectCollection; +import speiger.src.collections.objects.collections.ObjectIterator; +import speiger.src.collections.objects.functions.ObjectSupplier; +import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator; +import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer; + +import speiger.src.collections.objects.collections.ObjectBidirectionalIterator; +import speiger.src.collections.objects.lists.ObjectListIterator; +import speiger.src.collections.objects.sets.AbstractObjectSet; +import speiger.src.collections.objects.sets.ObjectOrderedSet; +import speiger.src.collections.utils.HashUtil; + +/** + * A Very Specific Type Specific implementation of a ArrayMap. + * This type of map is for very specific use cases that usaully would have lead to Tupled Lists otherwise. + * It also does not allow duplication (except for array constructors) and checks from last to first. + * It is not designed to be used as a HashMap replacement due to the poor performance it would cause. + * @note in this implementation SubMaps do NOT keep track of parent changes fully. For performance reasons it will just have a start/end index and not values + * Anything within that range will be updated appropiatly a shrink/growth of elements will break SubMaps in some ways. This can be useful but be careful + * @note this implementation does not shrink and only grows. + * @param the keyType of elements maintained by this Collection + */ +public class Int2ObjectArrayMap extends AbstractInt2ObjectMap implements Int2ObjectOrderedMap +{ + /** The Backing keys array */ + protected transient int[] keys; + /** The Backing values array */ + protected transient V[] values; + /** Amount of Elements stored in the ArrayMap */ + protected int size = 0; + /** KeySet cache */ + protected IntOrderedSet keySet; + /** Values cache */ + protected ObjectCollection valuesC; + /** EntrySet cache */ + protected FastOrderedSet entrySet; + + /** + * Default Constructor + */ + public Int2ObjectArrayMap() { + this(HashUtil.DEFAULT_MIN_CAPACITY); + } + + /** + * Constructor that defines the minimum capacity + * @param minCapacity the minimum capacity the HashMap is allowed to be. + * @throws IllegalStateException if the minimum capacity is negative + */ + public Int2ObjectArrayMap(int minCapacity) { + if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); + keys = new int[minCapacity]; + values = (V[])new Object[minCapacity]; + } + + /** + * Helper constructor that allow to create a map from boxed values (it will unbox them) + * @param keys the keys that should be put into the map + * @param values the values that should be put into the map. + * @throws IllegalStateException if the keys and values do not match in length + */ + public Int2ObjectArrayMap(Integer[] keys, V[] values) { + this(keys, values, keys.length); + } + + /** + * Helper constructor that allow to create a map from boxed values (it will unbox them) with a custom length + * @param keys the keys that should be put into the map + * @param values the values that should be put into the map. + * @param length the amount of values that should be pulled from the array + * @throws IllegalStateException if the keys and values do not match in length + */ + public Int2ObjectArrayMap(Integer[] keys, V[] values, int length) { + this(length); + if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size"); + putAll(keys, values, 0, length); + } + + /** + * Helper constructor that allow to create a map from unboxed values + * @param keys the keys that should be put into the map + * @param values the values that should be put into the map. + * @throws IllegalStateException if the keys and values do not match in lenght + */ + public Int2ObjectArrayMap(int[] keys, V[] values) { + this(keys, values, keys.length); + } + + /** + * Helper constructor that allow to create a map from unboxed values + * @param keys the keys that should be put into the map + * @param values the values that should be put into the map. + * @param length the amount of values that should be pulled from the array + * @throws IllegalStateException if the keys and values do not match in lenght + */ + public Int2ObjectArrayMap(int[] keys, V[] values, int length) { + this(length); + if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size"); + putAll(keys, values, 0, length); + } + + /** + * A Helper constructor that allows to create a Map with exactly the same values as the provided map. + * @param map the values that should be present in the map + */ + public Int2ObjectArrayMap(Map map) { + this(map.size()); + putAll(map); + } + + /** + * A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map. + * @param map the values that should be present in the map + */ + public Int2ObjectArrayMap(Int2ObjectMap map) { + this(map.size()); + for(ObjectIterator> iter = getFastIterator(map);iter.hasNext();size++) { + Int2ObjectMap.Entry entry = iter.next(); + keys[size] = entry.getIntKey(); + values[size] = entry.getValue(); + } + } + + @Override + public V put(int key, V value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(size++, key, value); + return getDefaultReturnValue(); + } + V oldValue = values[index]; + values[index] = value; + return oldValue; + } + + @Override + public V putIfAbsent(int key, V value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(size++, key, value); + return getDefaultReturnValue(); + } + else if(Objects.equals(values[index], getDefaultReturnValue())) { + V oldValue = values[index]; + values[index] = value; + return oldValue; + } + return values[index]; + } + + @Override + public V putAndMoveToFirst(int key, V value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(0, key, value); + size++; + return getDefaultReturnValue(); + } + V lastValue = values[index]; + values[index] = value; + moveIndexToFirst(index); + return lastValue; + } + + @Override + public V putAndMoveToLast(int key, V value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(size++, key, value); + return getDefaultReturnValue(); + } + V lastValue = values[index]; + values[index] = value; + moveIndexToLast(index); + return lastValue; + } + + @Override + public boolean moveToFirst(int key) { + int index = findIndex(key); + if(index > 0) { + moveIndexToFirst(index); + return true; + } + return false; + } + + @Override + public boolean moveToLast(int key) { + int index = findIndex(key); + if(index >= 0 && index < size-1) { + moveIndexToLast(index); + return true; + } + return false; + } + + @Override + public boolean containsKey(int key) { + return findIndex(key) >= 0; + } + + @Override + public boolean containsKey(Object key) { + return findIndex(key) >= 0; + } + + @Override + public boolean containsValue(Object value) { + return findValue(value) >= 0; + } + + @Override + public V get(int key) { + int index = findIndex(key); + return index < 0 ? getDefaultReturnValue() : values[index]; + } + + @Override + public V getOrDefault(int key, V defaultValue) { + int index = findIndex(key); + return index < 0 ? defaultValue : values[index]; + } + + @Override + public V getAndMoveToFirst(int key) { + int index = findIndex(key); + if(index >= 0) { + V value = values[index]; + moveIndexToFirst(index); + return value; + } + return getDefaultReturnValue(); + } + + @Override + public V getAndMoveToLast(int key) { + int index = findIndex(key); + if(index >= 0) { + V value = values[index]; + moveIndexToLast(index); + return value; + } + return getDefaultReturnValue(); + } + + @Override + public int firstIntKey() { + if(size <= 0) throw new NoSuchElementException(); + return keys[0]; + } + + @Override + public int lastIntKey() { + if(size <= 0) throw new NoSuchElementException(); + return keys[size-1]; + } + + @Override + public V firstValue() { + if(size <= 0) throw new NoSuchElementException(); + return values[0]; + } + + @Override + public V lastValue() { + if(size <= 0) throw new NoSuchElementException(); + return values[size-1]; + } + + @Override + public int pollFirstIntKey() { + if(size == 0) throw new NoSuchElementException(); + int result = keys[0]; + removeIndex(0); + return result; + } + + @Override + public int pollLastIntKey() { + if(size == 0) throw new NoSuchElementException(); + int result = keys[size-1]; + removeIndex(size-1); + return result; + } + + @Override + public V remove(int key) { + int index = findIndex(key); + if(index < 0) return getDefaultReturnValue(); + V value = values[index]; + removeIndex(index); + return value; + } + + @Override + public V removeOrDefault(int key, V defaultValue) { + int index = findIndex(key); + if(index < 0) return defaultValue; + V value = values[index]; + removeIndex(index); + return value; + } + + @Override + public boolean remove(int key, V value) { + int index = findIndex(key, value); + if(index < 0) return false; + removeIndex(index); + return true; + } + + @Override + public V remove(Object key) { + int index = findIndex(key); + if(index < 0) return getDefaultReturnValue(); + V value = values[index]; + removeIndex(index); + return value; + } + + @Override + public boolean remove(Object key, Object value) { + int index = findIndex(key, value); + if(index < 0) return false; + removeIndex(index); + return true; + } + + @Override + public void forEach(IntObjectConsumer action) { + if(size() <= 0) return; + for(int i = 0;i values() { + if(valuesC == null) valuesC = new Values(); + return valuesC; + } + + @Override + public ObjectOrderedSet> int2ObjectEntrySet() { + if(entrySet == null) entrySet = new MapEntrySet(); + return entrySet; + } + + @Override + public boolean replace(int key, V oldValue, V newValue) { + int index = findIndex(key); + if(index < 0 || values[index] != oldValue) return false; + values[index] = newValue; + return true; + } + + @Override + public V replace(int key, V value) { + int index = findIndex(key); + if(index < 0) return getDefaultReturnValue(); + V oldValue = values[index]; + values[index] = value; + return oldValue; + } + + @Override + public V compute(int key, IntObjectUnaryOperator mappingFunction) { + Objects.requireNonNull(mappingFunction); + int index = findIndex(key); + if(index == -1) { + V newValue = mappingFunction.apply(key, getDefaultReturnValue()); + if(Objects.equals(newValue, getDefaultReturnValue())) return newValue; + insertIndex(size++, key, newValue); + return newValue; + } + V newValue = mappingFunction.apply(key, values[index]); + if(Objects.equals(newValue, getDefaultReturnValue())) { + removeIndex(index); + return newValue; + } + values[index] = newValue; + return newValue; + } + + @Override + public V computeIfAbsent(int key, IntFunction mappingFunction) { + Objects.requireNonNull(mappingFunction); + int index = findIndex(key); + if(index == -1) { + V newValue = mappingFunction.apply(key); + if(Objects.equals(newValue, getDefaultReturnValue())) return newValue; + insertIndex(size++, key, newValue); + return newValue; + } + V newValue = values[index]; + if(Objects.equals(newValue, getDefaultReturnValue())) { + newValue = mappingFunction.apply(key); + if(Objects.equals(newValue, getDefaultReturnValue())) return newValue; + values[index] = newValue; + } + return newValue; + } + + @Override + public V supplyIfAbsent(int key, ObjectSupplier valueProvider) { + Objects.requireNonNull(valueProvider); + int index = findIndex(key); + if(index == -1) { + V newValue = valueProvider.get(); + if(Objects.equals(newValue, getDefaultReturnValue())) return newValue; + insertIndex(size++, key, newValue); + return newValue; + } + V newValue = values[index]; + if(Objects.equals(newValue, getDefaultReturnValue())) { + newValue = valueProvider.get(); + if(Objects.equals(newValue, getDefaultReturnValue())) return newValue; + values[index] = newValue; + } + return newValue; + } + + @Override + public V computeIfPresent(int key, IntObjectUnaryOperator mappingFunction) { + Objects.requireNonNull(mappingFunction); + int index = findIndex(key); + if(index == -1 || Objects.equals(values[index], getDefaultReturnValue())) return getDefaultReturnValue(); + V newValue = mappingFunction.apply(key, values[index]); + if(Objects.equals(newValue, getDefaultReturnValue())) { + removeIndex(index); + return newValue; + } + values[index] = newValue; + return newValue; + } + + @Override + public V merge(int key, V value, ObjectObjectUnaryOperator mappingFunction) { + Objects.requireNonNull(mappingFunction); + Objects.requireNonNull(value); + int index = findIndex(key); + V newValue = index == -1 || Objects.equals(values[index], getDefaultReturnValue()) ? value : mappingFunction.apply(values[index], value); + if(Objects.equals(newValue, getDefaultReturnValue())) { + if(index >= 0) + removeIndex(index); + } + else if(index == -1) insertIndex(size++, key, newValue); + else values[index] = newValue; + return newValue; + } + + @Override + public void mergeAll(Int2ObjectMap m, ObjectObjectUnaryOperator mappingFunction) { + Objects.requireNonNull(mappingFunction); + for(Int2ObjectMap.Entry entry : getFastIterable(m)) { + int key = entry.getIntKey(); + int index = findIndex(key); + V newValue = index == -1 || Objects.equals(values[index], getDefaultReturnValue()) ? entry.getValue() : mappingFunction.apply(values[index], entry.getValue()); + if(Objects.equals(newValue, getDefaultReturnValue())) { + if(index >= 0) + removeIndex(index); + } + else if(index == -1) insertIndex(size++, key, newValue); + else values[index] = newValue; + } + } + + @Override + public int size() { + return size; + } + + @Override + public void clear() { + Arrays.fill(keys, 0, size, 0); + Arrays.fill(values, 0, size, null); + size = 0; + } + + public Int2ObjectArrayMap copy() { + Int2ObjectArrayMap map = new Int2ObjectArrayMap<>(); + map.size = size; + map.keys = Arrays.copyOf(keys, keys.length); + map.values = Arrays.copyOf(values, keys.length); + return map; + } + + protected void moveIndexToFirst(int index) { + if(index == 0) return; + int key = keys[index]; + V value = values[index]; + System.arraycopy(keys, 0, keys, 1, index); + System.arraycopy(values, 0, values, 1, index); + keys[0] = key; + values[0] = value; + } + + protected void moveIndexToLast(int index) { + if(index == size-1) return; + int key = keys[index]; + V value = values[index]; + System.arraycopy(keys, index+1, keys, index, size-index-1); + System.arraycopy(values, index+1, values, index, size-index-1); + keys[size-1] = key; + values[size-1] = value; + } + + protected void grow(int newSize) { + if(newSize < keys.length) return; + newSize = Math.max(newSize, keys.length == 0 ? 2 : keys.length * 2); + keys = Arrays.copyOf(keys, newSize); + values = Arrays.copyOf(values, newSize); + } + + protected void insertIndex(int index, int key, V value) { + grow(size+1); + if(index != size) { + System.arraycopy(keys, index, keys, index+1, size-index); + System.arraycopy(values, index, values, index+1, size-index); + } + keys[index] = key; + values[index] = value; + } + + protected void removeRange(int from, int to) { + if(from < 0 || from >= size) throw new IllegalStateException("From Element "); + int length = to - from; + if(length <= 0) return; + if(to != size) { + System.arraycopy(keys, to, keys, from, size - to); + System.arraycopy(values, to, values, from, size - to); + } + for(int i = 0;i=0;i--) + if(keys[i] == key && Objects.equals(values[i], value)) return i; + return -1; + } + + protected int findIndex(int key) { + for(int i = size-1;i>=0;i--) + if(keys[i] == key) return i; + return -1; + } + + protected int findIndex(Object key, Object value) { + for(int i = size-1;i>=0;i--) + if(Objects.equals(key, Integer.valueOf(keys[i])) && Objects.equals(value, values[i])) return i; + return -1; + } + + protected int findIndex(Object key) { + for(int i = size-1;i>=0;i--) + if(Objects.equals(key, Integer.valueOf(keys[i]))) return i; + return -1; + } + + protected int findValue(Object value) { + for(int i = size-1;i>=0;i--) + if(Objects.equals(value, values[i])) return i; + return -1; + } + + private class MapEntrySet extends AbstractObjectSet> implements FastOrderedSet { + @Override + public boolean addAndMoveToFirst(Int2ObjectMap.Entry o) { throw new UnsupportedOperationException(); } + @Override + public boolean addAndMoveToLast(Int2ObjectMap.Entry o) { throw new UnsupportedOperationException(); } + + @Override + public boolean moveToFirst(Int2ObjectMap.Entry o) { + return Int2ObjectArrayMap.this.moveToFirst(o.getIntKey()); + } + + @Override + public boolean moveToLast(Int2ObjectMap.Entry o) { + return Int2ObjectArrayMap.this.moveToLast(o.getIntKey()); + } + + @Override + public Int2ObjectMap.Entry first() { + return new BasicEntry<>(firstIntKey(), firstValue()); + } + + @Override + public Int2ObjectMap.Entry last() { + return new BasicEntry<>(lastIntKey(), lastValue()); + } + + @Override + public Int2ObjectMap.Entry pollFirst() { + BasicEntry entry = new BasicEntry<>(firstIntKey(), firstValue()); + pollFirstIntKey(); + return entry; + } + + @Override + public Int2ObjectMap.Entry pollLast() { + BasicEntry entry = new BasicEntry<>(lastIntKey(), lastValue()); + pollLastIntKey(); + return entry; + } + + @Override + public ObjectBidirectionalIterator> iterator() { + return new EntryIterator(); + } + + @Override + public ObjectBidirectionalIterator> iterator(Int2ObjectMap.Entry fromElement) { + return new EntryIterator(fromElement.getIntKey()); + } + + @Override + public ObjectBidirectionalIterator> fastIterator() { + return new FastEntryIterator(); + } + + @Override + public ObjectBidirectionalIterator> fastIterator(int fromElement) { + return new FastEntryIterator(fromElement); + } + + @Override + public MapEntrySet copy() { throw new UnsupportedOperationException(); } + + @Override + public void forEach(Consumer> action) { + Objects.requireNonNull(action); + for(int i = 0;i(keys[i], values[i])); + } + + @Override + public void fastForEach(Consumer> action) { + Objects.requireNonNull(action); + if(size() <= 0) return; + BasicEntry entry = new BasicEntry<>(); + for(int i = 0;i> action) { + Objects.requireNonNull(action); + for(int i = 0;i(keys[i], values[i])); + } + } + + @Override + public void forEach(E input, ObjectObjectConsumer> action) { + Objects.requireNonNull(action); + for(int i = 0;i(keys[i], values[i])); + } + } + + @Override + public boolean matchesAny(Predicate> filter) { + Objects.requireNonNull(filter); + if(size() <= 0) return false; + BasicEntry entry = new BasicEntry<>(); + for(int i = 0;i> filter) { + Objects.requireNonNull(filter); + if(size() <= 0) return true; + BasicEntry entry = new BasicEntry<>(); + for(int i = 0;i> filter) { + Objects.requireNonNull(filter); + if(size() <= 0) return true; + BasicEntry entry = new BasicEntry<>(); + for(int i = 0;i E reduce(E identity, BiFunction, E> operator) { + Objects.requireNonNull(operator); + E state = identity; + for(int i = 0;i(keys[i], values[i])); + } + return state; + } + + @Override + public Int2ObjectMap.Entry reduce(ObjectObjectUnaryOperator, Int2ObjectMap.Entry> operator) { + Objects.requireNonNull(operator); + Int2ObjectMap.Entry state = null; + boolean empty = true; + for(int i = 0;i(keys[i], values[i]); + continue; + } + state = operator.apply(state, new BasicEntry<>(keys[i], values[i])); + } + return state; + } + + @Override + public Int2ObjectMap.Entry findFirst(Predicate> filter) { + Objects.requireNonNull(filter); + if(size() <= 0) return null; + BasicEntry entry = new BasicEntry<>(); + for(int i = 0;i> filter) { + Objects.requireNonNull(filter); + if(size() <= 0) return 0; + int result = 0; + BasicEntry entry = new BasicEntry<>(); + for(int i = 0;i entry = (Int2ObjectMap.Entry)o; + int index = Int2ObjectArrayMap.this.findIndex(entry.getIntKey()); + if(index >= 0) return Objects.equals(entry.getValue(), Int2ObjectArrayMap.this.values[index]); + } + else { + Map.Entry entry = (Map.Entry)o; + int index = Int2ObjectArrayMap.this.findIndex(entry.getKey()); + if(index >= 0) return Objects.equals(entry.getValue(), Int2ObjectArrayMap.this.values[index]); + } + } + return false; + } + + @Override + @Deprecated + public boolean remove(Object o) { + if(o instanceof Map.Entry) { + if(o instanceof Int2ObjectMap.Entry) { + Int2ObjectMap.Entry entry = (Int2ObjectMap.Entry)o; + return Int2ObjectArrayMap.this.remove(entry.getIntKey(), entry.getValue()); + } + Map.Entry entry = (Map.Entry)o; + return Int2ObjectArrayMap.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + + @Override + public int size() { + return Int2ObjectArrayMap.this.size(); + } + + @Override + public void clear() { + Int2ObjectArrayMap.this.clear(); + } + } + + private class KeySet extends AbstractIntSet implements IntOrderedSet { + @Override + public boolean contains(int e) { return containsKey(e); } + + @Override + public boolean remove(int o) { + int oldSize = size; + Int2ObjectArrayMap.this.remove(o); + return size != oldSize; + } + + @Override + public boolean add(int o) { throw new UnsupportedOperationException(); } + @Override + public boolean addAndMoveToFirst(int o) { throw new UnsupportedOperationException(); } + @Override + public boolean addAndMoveToLast(int o) { throw new UnsupportedOperationException(); } + @Override + public boolean moveToFirst(int o) { return Int2ObjectArrayMap.this.moveToFirst(o); } + @Override + public boolean moveToLast(int o) { return Int2ObjectArrayMap.this.moveToLast(o); } + @Override + public IntListIterator iterator() { return new KeyIterator(); } + @Override + public IntBidirectionalIterator iterator(int fromElement) { return new KeyIterator(fromElement); } + @Override + public int size() { return Int2ObjectArrayMap.this.size(); } + @Override + public void clear() { Int2ObjectArrayMap.this.clear(); } + @Override + public int firstInt() { return firstIntKey(); } + @Override + public int pollFirstInt() { return pollFirstIntKey(); } + @Override + public int lastInt() { return lastIntKey(); } + @Override + public int pollLastInt() { return pollLastIntKey(); } + + @Override + public KeySet copy() { throw new UnsupportedOperationException(); } + + @Override + public void forEach(IntConsumer action) { + Objects.requireNonNull(action); + for(int i = 0;i void forEach(E input, ObjectIntConsumer action) { + Objects.requireNonNull(action); + for(int i = 0;i { + @Override + public boolean contains(Object e) { + return containsValue(e); + } + + @Override + public boolean add(V o) { + throw new UnsupportedOperationException(); + } + + @Override + public ObjectIterator iterator() { + return new ValueIterator(); + } + + @Override + public int size() { + return Int2ObjectArrayMap.this.size(); + } + + @Override + public void clear() { + Int2ObjectArrayMap.this.clear(); + } + + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + for(int i = 0;i action) { + Objects.requireNonNull(action); + for(int i = 0;i filter) { + Objects.requireNonNull(filter); + for(int i = 0;i filter) { + Objects.requireNonNull(filter); + for(int i = 0;i filter) { + Objects.requireNonNull(filter); + for(int i = 0;i E reduce(E identity, BiFunction operator) { + Objects.requireNonNull(operator); + E state = identity; + for(int i = 0;i operator) { + Objects.requireNonNull(operator); + V state = null; + boolean empty = true; + for(int i = 0;i filter) { + Objects.requireNonNull(filter); + for(int i = 0;i filter) { + Objects.requireNonNull(filter); + int result = 0; + for(int i = 0;i> { + MapEntry entry = new MapEntry(); + + public FastEntryIterator() {} + public FastEntryIterator(int from) { + index = findIndex(from); + } + + @Override + public Int2ObjectMap.Entry next() { + entry.index = nextEntry(); + return entry; + } + + @Override + public Int2ObjectMap.Entry previous() { + entry.index = previousEntry(); + return entry; + } + + @Override + public void set(Int2ObjectMap.Entry e) { throw new UnsupportedOperationException(); } + @Override + public void add(Int2ObjectMap.Entry e) { throw new UnsupportedOperationException(); } + } + + private class EntryIterator extends MapIterator implements ObjectListIterator> { + MapEntry entry = null; + + public EntryIterator() {} + public EntryIterator(int from) { + index = findIndex(from); + if(index == -1) throw new NoSuchElementException(); + } + + @Override + public Int2ObjectMap.Entry next() { + return entry = new MapEntry(nextEntry()); + } + + @Override + public Int2ObjectMap.Entry previous() { + return entry = new MapEntry(previousEntry()); + } + + @Override + public void remove() { + super.remove(); + if(entry != null && entry.index != -1) { + entry.index = -1; + } + } + + @Override + public void set(Int2ObjectMap.Entry e) { throw new UnsupportedOperationException(); } + @Override + public void add(Int2ObjectMap.Entry e) { throw new UnsupportedOperationException(); } + } + + private class KeyIterator extends MapIterator implements IntListIterator { + public KeyIterator() {} + public KeyIterator(int element) { + index = findIndex(element); + if(index == -1) throw new NoSuchElementException(); + } + + @Override + public int previousInt() { + return keys[previousEntry()]; + } + + @Override + public int nextInt() { + return keys[nextEntry()]; + } + + @Override + public void set(int e) { throw new UnsupportedOperationException(); } + + @Override + public void add(int e) { throw new UnsupportedOperationException(); } + } + + private class ValueIterator extends MapIterator implements ObjectListIterator { + @Override + public V previous() { + return values[previousEntry()]; + } + + @Override + public V next() { + return values[nextEntry()]; + } + + @Override + public void set(V e) { throw new UnsupportedOperationException(); } + + @Override + public void add(V e) { throw new UnsupportedOperationException(); } + } + + private class MapIterator { + int index; + int lastReturned = -1; + + public boolean hasNext() { + return index < size; + } + + public boolean hasPrevious() { + return index > 0; + } + + public int nextIndex() { + return index; + } + + public int previousIndex() { + return index-1; + } + + public void remove() { + if(lastReturned == -1) throw new IllegalStateException(); + removeIndex(lastReturned); + if(lastReturned < index) + index--; + lastReturned = -1; + } + + public int previousEntry() { + if(!hasPrevious()) throw new NoSuchElementException(); + index--; + return (lastReturned = index); + } + + public int nextEntry() { + if(!hasNext()) throw new NoSuchElementException(); + lastReturned = index; + return index++; + } + + public int skip(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int steps = Math.min(amount, size() - index); + index += steps; + if(steps > 0) lastReturned = Math.min(index-1, size()-1); + return steps; + } + + public int back(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int steps = Math.min(amount, index); + index -= steps; + if(steps > 0) lastReturned = Math.min(index, size()-1); + return steps; + } + } + + private class MapEntry implements Int2ObjectMap.Entry, Map.Entry { + int index = -1; + + public MapEntry() {} + public MapEntry(int index) { + this.index = index; + } + + @Override + public int getIntKey() { + return keys[index]; + } + + @Override + public V getValue() { + return values[index]; + } + + @Override + public V setValue(V value) { + V oldValue = values[index]; + values[index] = value; + return oldValue; + } + + @Override + public boolean equals(Object obj) { + if(obj instanceof Map.Entry) { + if(obj instanceof Int2ObjectMap.Entry) { + Int2ObjectMap.Entry entry = (Int2ObjectMap.Entry)obj; + return keys[index] == entry.getIntKey() && Objects.equals(values[index], entry.getValue()); + } + Map.Entry entry = (Map.Entry)obj; + Object key = entry.getKey(); + Object value = entry.getValue(); + return key instanceof Integer && keys[index] == ((Integer)key).intValue() && Objects.equals(values[index], value); + } + return false; + } + + @Override + public int hashCode() { + return Integer.hashCode(keys[index]) ^ Objects.hashCode(values[index]); + } + + @Override + public String toString() { + return Integer.toString(keys[index]) + "=" + Objects.toString(values[index]); + } + } +} diff --git a/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectMap.java b/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectMap.java new file mode 100644 index 000000000..be6d23167 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectMap.java @@ -0,0 +1,679 @@ +package speiger.src.collections.ints.maps.interfaces; + +import java.util.Map; +import java.util.Objects; +import java.util.Collection; +import java.util.Arrays; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; + + +import speiger.src.collections.objects.collections.ObjectCollection; +import speiger.src.collections.ints.functions.consumer.IntObjectConsumer; +import speiger.src.collections.ints.functions.function.IntFunction; +import speiger.src.collections.ints.functions.function.IntObjectUnaryOperator; + +import speiger.src.collections.ints.maps.impl.misc.Int2ObjectArrayMap; +import speiger.src.collections.objects.collections.ObjectIterable; +import speiger.src.collections.ints.sets.IntSet; +import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator; +import speiger.src.collections.objects.functions.ObjectSupplier; +import speiger.src.collections.objects.collections.ObjectIterator; +import speiger.src.collections.objects.sets.ObjectSet; +import speiger.src.collections.utils.HashUtil; +import speiger.src.collections.utils.SanityChecks; + +/** + * A Type Specific Map that reduces memory overhead due to boxing/unboxing of Primitives + * and some extra helper functions. + * @param the keyType of elements maintained by this Collection + */ +public interface Int2ObjectMap extends Map, IntFunction +{ + /** + * Helper Class that allows to create Maps without requiring a to type out the entire implementation or know it. + * @return a MapBuilder + */ + public static MapBuilder builder() { + return MapBuilder.INSTANCE; + } + + /** + * Method to see what the default return value is. + * @return default return value + */ + public V getDefaultReturnValue(); + /** + * Method to define the default return value if a requested key isn't present + * @param v value that should be the default return value + * @return itself + */ + public Int2ObjectMap setDefaultReturnValue(V v); + + /** + * A Function that does a shallow clone of the Map itself. + * This function is more optimized then a copy constructor since the Map does not have to be unsorted/resorted. + * It can be compared to Cloneable but with less exception risk + * @return a Shallow Copy of the Map + * @note Wrappers and view Maps will not support this feature + */ + public Int2ObjectMap copy(); + + /** + * Type Specific method to reduce boxing/unboxing of values + * @param key the key that should be inserted, + * @param value the value that should be inserted + * @return the last present value or default return value. + * @see Map#put(Object, Object) + */ + public V put(int key, V value); + + /** + * A Helper method that allows to put int a Int2ObjectMap.Entry into a map. + * @param entry then Entry that should be inserted. + * @return the last present value or default return value. + */ + public default V put(Entry entry) { + return put(entry.getIntKey(), entry.getValue()); + } + + /** + * A Helper method that allows to put int a Map.Entry into a map. + * @param entry then Entry that should be inserted. + * @return the last present value or default return value. + */ + public default V put(Map.Entry entry) { + return put(entry.getKey(), entry.getValue()); + } + + /** + * Type Specific array method to bulk add elements into a map without creating a wrapper and increasing performances + * @param keys the keys that should be added + * @param values the values that should be added + * @see Map#putAll(Map) + * @throws IllegalStateException if the arrays are not the same size + */ + public default void putAll(int[] keys, V[] values) { + if(keys.length != values.length) throw new IllegalStateException("Array sizes do not match"); + putAll(keys, values, 0, keys.length); + } + + /** + * Type Specific array method to bulk add elements into a map without creating a wrapper and increasing performances + * @param keys the keys that should be added + * @param values the values that should be added + * @param offset where the to start in the array + * @param size how many elements should be added + * @see Map#putAll(Map) + * @throws IllegalStateException if the arrays are not within the range + */ + public void putAll(int[] keys, V[] values, int offset, int size); + + /** + * Type Specific Object array method to bulk add elements into a map without creating a wrapper and increasing performances + * @param keys the keys that should be added + * @param values the values that should be added + * @see Map#putAll(Map) + * @throws IllegalStateException if the arrays are not the same size + */ + public default void putAll(Integer[] keys, V[] values) { + if(keys.length != values.length) throw new IllegalStateException("Array sizes do not match"); + putAll(keys, values, 0, keys.length); + } + + /** + * Type Specific Object array method to bulk add elements into a map without creating a wrapper and increasing performances + * @param keys the keys that should be added + * @param values the values that should be added + * @param offset where the to start in the array + * @param size how many elements should be added + * @see Map#putAll(Map) + * @throws IllegalStateException if the arrays are not within the range + */ + public void putAll(Integer[] keys, V[] values, int offset, int size); + + /** + * Type Specific method to reduce boxing/unboxing of values + * @param key the key that should be inserted, + * @param value the value that should be inserted + * @return the last present value or default return value. + * @see Map#putIfAbsent(Object, Object) + */ + public V putIfAbsent(int key, V value); + + /** + * Type-Specific bulk put method put elements into the map if not present. + * @param m elements that should be added if not present. + */ + public void putAllIfAbsent(Int2ObjectMap m); + + /** + * Type Specific function for the bull putting of values + * @param m the elements that should be inserted + */ + public void putAll(Int2ObjectMap m); + + /** + * Type Specific method to reduce boxing/unboxing of values + * @param key element that is searched for + * @return if the key is present + */ + public boolean containsKey(int key); + + /** + * @see Map#containsKey(Object) + * @param key that is searched for. + * @return true if found + * @note in some implementations key does not have to be Integer but just have to support equals with Integer. + */ + @Override + public default boolean containsKey(Object key) { + return key instanceof Integer && containsKey(((Integer)key).intValue()); + } + + /** + * Type Specific remove function to reduce boxing/unboxing + * @param key the element that should be removed + * @return the value that was removed or default return value + */ + public V remove(int key); + + /** + * @see Map#remove(Object) + * @param key the element that should be removed + * @return the value that was removed or default return value + * @note in some implementations key does not have to be Integer but just have to support equals with Integer. + */ + @Override + public default V remove(Object key) { + return key instanceof Integer ? remove(((Integer)key).intValue()) : getDefaultReturnValue(); + } + + /** + * Type Specific remove function to reduce boxing/unboxing + * @param key the element that should be removed + * @param value the expected value that should be found + * @return true if the key and value was found and removed + * @see Map#remove(Object, Object) + */ + public boolean remove(int key, V value); + + /** + * @see Map#remove(Object, Object) + * @param key the element that should be removed + * @param value the expected value that should be found + * @return true if the key and value was found and removed + */ + @Override + public default boolean remove(Object key, Object value) { + return key instanceof Integer && remove(((Integer)key).intValue(), (V)value); + } + + /** + * Type-Specific Remove function with a default return value if wanted. + * @see Map#remove(Object, Object) + * @param key the element that should be removed + * @param defaultValue the value that should be returned if the entry doesn't exist + * @return the value that was removed or default value + */ + public V removeOrDefault(int key, V defaultValue); + /** + * A Type Specific replace method to replace an existing value + * @param key the element that should be searched for + * @param oldValue the expected value to be replaced + * @param newValue the value to replace the oldValue with. + * @return true if the value got replaced + * @note this fails if the value is not present even if it matches the oldValue + */ + public boolean replace(int key, V oldValue, V newValue); + /** + * A Type Specific replace method to reduce boxing/unboxing replace an existing value + * @param key the element that should be searched for + * @param value the value to replace with. + * @return the present value or default return value + * @note this fails if the value is not present + */ + public V replace(int key, V value); + + /** + * Type-Specific bulk replace method. Could be seen as putAllIfPresent + * @param m elements that should be replaced. + */ + public void replaceObjects(Int2ObjectMap m); + /** + * A Type Specific mass replace method to reduce boxing/unboxing + * @param mappingFunction operation to replace all values + */ + public void replaceObjects(IntObjectUnaryOperator mappingFunction); + /** + * A Type Specific compute method to reduce boxing/unboxing + * @param key the key that should be computed + * @param mappingFunction the operator that should generate the value + * @return the result of the computation + */ + public V compute(int key, IntObjectUnaryOperator mappingFunction); + /** + * A Type Specific compute method to reduce boxing/unboxing + * @param key the key that should be computed + * @param mappingFunction the operator that should generate the value if not present + * @return the result of the computed value or present value + */ + public V computeIfAbsent(int key, IntFunction mappingFunction); + + /** + * A Supplier based computeIfAbsent function to fill the most used usecase of this function + * @param key the key that should be computed + * @param valueProvider the value if not present + * @return the result of the computed value or present value + */ + public V supplyIfAbsent(int key, ObjectSupplier valueProvider); + /** + * A Type Specific compute method to reduce boxing/unboxing + * @param key the key that should be computed + * @param mappingFunction the operator that should generate the value if present + * @return the result of the default return value or present value + * @note if not present then compute is not executed + */ + public V computeIfPresent(int key, IntObjectUnaryOperator mappingFunction); + /** + * A Type Specific merge method to reduce boxing/unboxing + * @param key the key that should be be searched for + * @param value the value that should be merged with + * @param mappingFunction the operator that should generate the new Value + * @return the result of the merge + * @note if the result matches the default return value then the key is removed from the map + */ + public V merge(int key, V value, ObjectObjectUnaryOperator mappingFunction); + /** + * A Bulk method for merging Maps. + * @param m the entries that should be bulk added + * @param mappingFunction the operator that should generate the new Value + * @note if the result matches the default return value then the key is removed from the map + */ + public void mergeAll(Int2ObjectMap m, ObjectObjectUnaryOperator mappingFunction); + + @Override + @Deprecated + public default boolean replace(Integer key, V oldValue, V newValue) { + return replace(key.intValue(), oldValue, newValue); + } + + @Override + @Deprecated + public default V replace(Integer key, V value) { + return replace(key.intValue(), value); + } + + @Override + public default V apply(int key) { + return get(key); + } + /** + * A Type Specific get method to reduce boxing/unboxing + * @param key the key that is searched for + * @return the searched value or default return value + */ + public V get(int key); + + /** + * A Type Specific getOrDefault method to reduce boxing/unboxing + * @param key the key that is searched for + * @param defaultValue the value that should be returned if the key is not present + * @return the searched value or defaultValue value + */ + public V getOrDefault(int key, V defaultValue); + + @Override + @Deprecated + public default V get(Object key) { + return key instanceof Integer ? get(((Integer)key).intValue()) : getDefaultReturnValue(); + } + + @Override + @Deprecated + public default V getOrDefault(Object key, V defaultValue) { + V value = key instanceof Integer ? get(((Integer)key).intValue()) : getDefaultReturnValue(); + return !Objects.equals(value, getDefaultReturnValue()) || containsKey(key) ? value : defaultValue; + } + + @Override + @Deprecated + public default void replaceAll(BiFunction mappingFunction) { + Objects.requireNonNull(mappingFunction); + replaceObjects(mappingFunction instanceof IntObjectUnaryOperator ? (IntObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(Integer.valueOf(K), V)); + } + + @Override + @Deprecated + public default V compute(Integer key, BiFunction mappingFunction) { + Objects.requireNonNull(mappingFunction); + return compute(key.intValue(), mappingFunction instanceof IntObjectUnaryOperator ? (IntObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(Integer.valueOf(K), V)); + } + + @Override + @Deprecated + public default V computeIfAbsent(Integer key, Function mappingFunction) { + Objects.requireNonNull(mappingFunction); + return computeIfAbsent(key.intValue(), mappingFunction instanceof IntFunction ? (IntFunction)mappingFunction : K -> mappingFunction.apply(Integer.valueOf(K))); + } + + @Override + @Deprecated + public default V computeIfPresent(Integer key, BiFunction mappingFunction) { + Objects.requireNonNull(mappingFunction); + return computeIfPresent(key.intValue(), mappingFunction instanceof IntObjectUnaryOperator ? (IntObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(Integer.valueOf(K), V)); + } + + @Override + @Deprecated + public default V merge(Integer key, V value, BiFunction mappingFunction) { + Objects.requireNonNull(mappingFunction); + Objects.requireNonNull(value); + return merge(key.intValue(), value, mappingFunction instanceof ObjectObjectUnaryOperator ? (ObjectObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(K, V)); + } + + /** + * Type Specific forEach method to reduce boxing/unboxing + * @param action processor of the values that are iterator over + */ + public void forEach(IntObjectConsumer action); + + @Override + @Deprecated + public default void forEach(BiConsumer action) { + Objects.requireNonNull(action); + forEach(action instanceof IntObjectConsumer ? (IntObjectConsumer)action : (K, V) -> action.accept(Integer.valueOf(K), V)); + } + + @Override + public IntSet keySet(); + @Override + public ObjectCollection values(); + @Override + @Deprecated + public ObjectSet> entrySet(); + /** + * Type Sensitive EntrySet to reduce boxing/unboxing and optionally Temp Object Allocation. + * @return a EntrySet of the collection + */ + public ObjectSet> int2ObjectEntrySet(); + + @Override + @Deprecated + public default V put(Integer key, V value) { + return put(key.intValue(), value); + } + + @Override + @Deprecated + public default V putIfAbsent(Integer key, V value) { + return put(key.intValue(), value); + } + /** + * Fast Entry set that allows for a faster Entry Iterator by recycling the Entry Object and just exchanging 1 internal value + * @param the keyType of elements maintained by this Collection + */ + public interface FastEntrySet extends ObjectSet> + { + /** + * Fast iterator that recycles the given Entry object to improve speed and reduce object allocation + * @return a Recycling ObjectIterator of the given set + */ + public ObjectIterator> fastIterator(); + /** + * Fast for each that recycles the given Entry object to improve speed and reduce object allocation + * @param action the action that should be applied to each given entry + */ + public default void fastForEach(Consumer> action) { + forEach(action); + } + } + + /** + * Type Specific Map Entry that reduces boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ + public interface Entry extends Map.Entry + { + /** + * Type Specific getKey method that reduces boxing/unboxing + * @return the key of a given Entry + */ + public int getIntKey(); + public default Integer getKey() { return Integer.valueOf(getIntKey()); } + + } + + /** + * Helper class that reduces the method spam of the Map Class. + */ + public static final class MapBuilder + { + static final MapBuilder INSTANCE = new MapBuilder(); + + /** + * Starts a Map Builder that allows you to create maps as Constants a lot easier + * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen + * @param the keyType of elements maintained by this Collection + * @return a MapBuilder + */ + public BuilderCache start() { + return new BuilderCache(); + } + + /** + * Starts a Map Builder that allows you to create maps as Constants a lot easier + * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen + * @param size the expected minimum size of Elements in the Map, default is 16 + * @param the keyType of elements maintained by this Collection + * @return a MapBuilder + */ + public BuilderCache start(int size) { + return new BuilderCache(size); + } + + /** + * Starts a Map builder and puts in the Key and Value into it + * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen + * @param key the key that should be added + * @param value the value that should be added + * @param the keyType of elements maintained by this Collection + * @return a MapBuilder with the key and value stored in it. + */ + public BuilderCache put(int key, V value) { + return new BuilderCache().put(key, value); + } + + /** + * Starts a Map builder and puts in the Key and Value into it + * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen + * @param key the key that should be added + * @param value the value that should be added + * @param the keyType of elements maintained by this Collection + * @return a MapBuilder with the key and value stored in it. + */ + public BuilderCache put(Integer key, V value) { + return new BuilderCache().put(key, value); + } + + /** + * Helper function to unify code + * @param the keyType of elements maintained by this Collection + * @return a OpenHashMap + */ + public Int2ObjectArrayMap arrayMap() { + return new Int2ObjectArrayMap<>(); + } + + /** + * Helper function to unify code + * @param size the minimum capacity of the Map + * @param the keyType of elements maintained by this Collection + * @return a OpenHashMap with a mimimum capacity + */ + public Int2ObjectArrayMap arrayMap(int size) { + return new Int2ObjectArrayMap<>(size); + } + + /** + * Helper function to unify code + * @param keys the keys that should be inserted + * @param values the values that should be inserted + * @param the keyType of elements maintained by this Collection + * @throws IllegalStateException if the keys and values do not match in length + * @return a OpenHashMap thats contains the injected values + */ + public Int2ObjectArrayMap arrayMap(int[] keys, V[] values) { + return new Int2ObjectArrayMap<>(keys, values); + } + + /** + * Helper function to unify code + * @param keys the keys that should be inserted + * @param values the values that should be inserted + * @param the keyType of elements maintained by this Collection + * @throws IllegalStateException if the keys and values do not match in length + * @return a OpenHashMap thats contains the injected values + * @note the keys and values will be unboxed + */ + public Int2ObjectArrayMap arrayMap(Integer[] keys, V[] values) { + return new Int2ObjectArrayMap<>(keys, values); + } + + /** + * Helper function to unify code + * @param map that should be cloned + * @param the keyType of elements maintained by this Collection + * @return a OpenHashMap thats copies the contents of the provided map + */ + public Int2ObjectArrayMap arrayMap(Int2ObjectMap map) { + return new Int2ObjectArrayMap<>(map); + } + + /** + * Helper function to unify code + * @param map that should be cloned + * @param the keyType of elements maintained by this Collection + * @return a OpenHashMap thats copies the contents of the provided map + * @note the map will be unboxed + */ + public Int2ObjectArrayMap arrayMap(Map map) { + return new Int2ObjectArrayMap<>(map); + } + + } + + /** + * Builder Cache for allowing to buildMaps + * @param the keyType of elements maintained by this Collection + */ + public static class BuilderCache + { + int[] keys; + V[] values; + int size; + + /** + * Default Constructor + */ + public BuilderCache() { + this(HashUtil.DEFAULT_MIN_CAPACITY); + } + + /** + * Constructor providing a Minimum Capcity + * @param initialSize the requested start capacity + */ + public BuilderCache(int initialSize) { + if(initialSize < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); + keys = new int[initialSize]; + values = (V[])new Object[initialSize]; + } + + private void ensureSize(int newSize) { + if(keys.length >= newSize) return; + newSize = (int)Math.max(Math.min((long)keys.length + (keys.length >> 1), SanityChecks.MAX_ARRAY_SIZE), newSize); + keys = Arrays.copyOf(keys, newSize); + values = Arrays.copyOf(values, newSize); + } + + /** + * Helper function to add a Entry into the Map + * @param key the key that should be added + * @param value the value that should be added + * @return self + */ + public BuilderCache put(int key, V value) { + ensureSize(size+1); + keys[size] = key; + values[size] = value; + size++; + return this; + } + + /** + * Helper function to add a Entry into the Map + * @param key the key that should be added + * @param value the value that should be added + * @return self + */ + public BuilderCache put(Integer key, V value) { + return put(key.intValue(), value); + } + + /** + * Helper function to add a Entry into the Map + * @param entry the Entry that should be added + * @return self + */ + public BuilderCache put(Entry entry) { + return put(entry.getIntKey(), entry.getValue()); + } + + /** + * Helper function to add a Map to the Map + * @param map that should be added + * @return self + */ + public BuilderCache putAll(Int2ObjectMap map) { + return putAll(map.int2ObjectEntrySet()); + } + + /** + * Helper function to add a Map to the Map + * @param map that should be added + * @return self + */ + public BuilderCache putAll(Map map) { + for(Map.Entry entry : map.entrySet()) + put(entry.getKey(), entry.getValue()); + return this; + } + + /** + * Helper function to add a Collection of Entries to the Map + * @param c that should be added + * @return self + */ + public BuilderCache putAll(ObjectIterable> c) { + if(c instanceof Collection) + ensureSize(size+((Collection>)c).size()); + + for(Entry entry : c) + put(entry); + + return this; + } + + /** + * Builds the Keys and Values into a Array Map + * @return a Int2ObjectArrayMap + */ + public Int2ObjectArrayMap arrayMap() { + return new Int2ObjectArrayMap<>(keys, values, size); + } + + } +} diff --git a/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectOrderedMap.java b/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectOrderedMap.java new file mode 100644 index 000000000..58fcd9ca8 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectOrderedMap.java @@ -0,0 +1,115 @@ +package speiger.src.collections.ints.maps.interfaces; + +import speiger.src.collections.ints.sets.IntOrderedSet; +import speiger.src.collections.objects.collections.ObjectBidirectionalIterator; +import speiger.src.collections.objects.sets.ObjectOrderedSet; +/** + * A Special Map Interface giving Access to some really usefull functions + * The Idea behind this interface is to allow access to functions that give control to the Order of elements. + * Since Linked implementations as examples can be reordered outside of the Insertion Order. + * This interface provides basic access to such functions while also providing some Sorted/NaivgableMap implementations that still fit into here. + * + * @param the keyType of elements maintained by this Collection + */ +public interface Int2ObjectOrderedMap extends Int2ObjectMap +{ + /** + * A customized put method that allows you to insert into the first index. + * @param key the key that should be inserted + * @param value the value that should be inserted + * @return the previous present or default return value + * @see java.util.Map#put(Object, Object) + */ + public V putAndMoveToFirst(int key, V value); + + /** + * A customized put method that allows you to insert into the last index. (This may be nessesary depending on the implementation) + * @param key the key that should be inserted + * @param value the value that should be inserted + * @return the previous present or default return value + * @see java.util.Map#put(Object, Object) + */ + public V putAndMoveToLast(int key, V value); + + /** + * A specific move method to move a given key/value to the first index. + * @param key that should be moved to the first index + * @return true if the value was moved. + * @note returns false if the value was not present in the first place + */ + public boolean moveToFirst(int key); + /** + * A specific move method to move a given key/value to the last index. + * @param key that should be moved to the first last + * @return true if the value was moved. + * @note returns false if the value was not present in the first place + */ + public boolean moveToLast(int key); + + /** + * A Specific get method that allows to move teh given key/value int the first index. + * @param key that is searched for + * @return the given value for the requested key or default return value + */ + public V getAndMoveToFirst(int key); + /** + * A Specific get method that allows to move teh given key/value int the last index. + * @param key that is searched for + * @return the given value for the requested key or default return value + */ + public V getAndMoveToLast(int key); + + /** + * A method to get the first Key of a Map. + * @return the first key in the map + */ + public int firstIntKey(); + /** + * A method to get and remove the first Key of a Map. + * @return the first key in the map + */ + public int pollFirstIntKey(); + /** + * A method to get the last Key of a Map. + * @return the last key in the map + */ + public int lastIntKey(); + /** + * A method to get and remove the last Key of a Map. + * @return the last key in the map + */ + public int pollLastIntKey(); + + /** + * A method to get the first Value of a Map. + * @return the first key in the map + */ + public V firstValue(); + /** + * A method to get the last Value of a Map. + * @return the last key in the map + */ + public V lastValue(); + + @Override + public Int2ObjectOrderedMap copy(); + @Override + public IntOrderedSet keySet(); + @Override + public ObjectOrderedSet> int2ObjectEntrySet(); + + /** + * Fast Ordered Entry Set that allows for a faster Entry Iterator by recycling the Entry Object and just exchanging 1 internal value + * @param the keyType of elements maintained by this Collection + */ + interface FastOrderedSet extends FastEntrySet, ObjectOrderedSet> { + @Override + public ObjectBidirectionalIterator> fastIterator(); + /** + * Fast iterator that recycles the given Entry object to improve speed and reduce object allocation + * @param fromElement that is going to be started from. + * @return a improved iterator that starts from the desired element + */ + public ObjectBidirectionalIterator> fastIterator(int fromElement); + } +} diff --git a/src/main/java/speiger/src/collections/ints/sets/AbstractIntSet.java b/src/main/java/speiger/src/collections/ints/sets/AbstractIntSet.java new file mode 100644 index 000000000..5f0433a54 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/sets/AbstractIntSet.java @@ -0,0 +1,41 @@ +package speiger.src.collections.ints.sets; + +import java.util.Set; + +import speiger.src.collections.ints.collections.AbstractIntCollection; +import speiger.src.collections.ints.collections.IntIterator; + +/** + * Abstract Type Specific Set that reduces boxing/unboxing + */ +public abstract class AbstractIntSet extends AbstractIntCollection implements IntSet +{ + @Override + public abstract IntIterator iterator(); + @Override + public AbstractIntSet copy() { throw new UnsupportedOperationException(); } + + @Override + public int hashCode() { + int hashCode = 0; + IntIterator i = iterator(); + while(i.hasNext()) + hashCode += Integer.hashCode(i.nextInt()); + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Set l = (Set)o; + if(l.size() != size()) return false; + try { + return containsAll(l); + } catch (ClassCastException | NullPointerException unused) { + return false; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/sets/IntOrderedSet.java b/src/main/java/speiger/src/collections/ints/sets/IntOrderedSet.java new file mode 100644 index 000000000..2a11d0e96 --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/sets/IntOrderedSet.java @@ -0,0 +1,88 @@ +package speiger.src.collections.ints.sets; + +import speiger.src.collections.ints.collections.IntBidirectionalIterator; +import speiger.src.collections.ints.collections.IntSplititerator; +import speiger.src.collections.ints.utils.IntSplititerators; + +/** + * A Special Set Interface giving Access to some really usefull functions + * The Idea behind this interface is to allow access to functions that give control to the Order of elements. + * Since Linked implementations as examples can be reordered outside of the Insertion Order. + * This interface provides basic access to such functions while also providing some Sorted/NaivgableSet implementations that still fit into here. + * + */ +public interface IntOrderedSet extends IntSet +{ + /** + * A customized add method that allows you to insert into the first index. + * @param o the element that should be inserted + * @return true if it was added + * @see java.util.Set#add(Object) + */ + public boolean addAndMoveToFirst(int o); + /** + * A customized add method that allows you to insert into the last index. + * @param o the element that should be inserted + * @return true if it was added + * @see java.util.Set#add(Object) + */ + public boolean addAndMoveToLast(int o); + + /** + * A specific move method to move a given key to the first index. + * @param o that should be moved to the first index + * @return true if the value was moved. + * @note returns false if the value was not present in the first place + */ + public boolean moveToFirst(int o); + /** + * A specific move method to move a given key to the last index. + * @param o that should be moved to the first last + * @return true if the value was moved. + * @note returns false if the value was not present in the first place + */ + public boolean moveToLast(int o); + + @Override + public IntOrderedSet copy(); + + @Override + public IntBidirectionalIterator iterator(); + + /** + * A type Specific Iterator starting from a given key + * @param fromElement the element the iterator should start from + * @return a iterator starting from the given element + * @throws java.util.NoSuchElementException if fromElement isn't found + */ + public IntBidirectionalIterator iterator(int fromElement); + + /** + * A Type Specific Type Splititerator to reduce boxing/unboxing + * @return type specific splititerator + */ + @Override + default IntSplititerator spliterator() { return IntSplititerators.createSplititerator(this, 0); } + + /** + * A method to get the first element in the set + * @return first element in the set + */ + public int firstInt(); + /** + * A method to get and remove the first element in the set + * @return first element in the set + */ + public int pollFirstInt(); + /** + * A method to get the last element in the set + * @return last element in the set + */ + public int lastInt(); + /** + * A method to get and remove the last element in the set + * @return last element in the set + */ + public int pollLastInt(); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/sets/IntSet.java b/src/main/java/speiger/src/collections/ints/sets/IntSet.java new file mode 100644 index 000000000..721ae0e4b --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/sets/IntSet.java @@ -0,0 +1,58 @@ +package speiger.src.collections.ints.sets; + +import java.util.Set; + +import speiger.src.collections.ints.collections.IntCollection; +import speiger.src.collections.ints.collections.IntIterator; +import speiger.src.collections.ints.collections.IntSplititerator; +import speiger.src.collections.ints.utils.IntSplititerators; + + +/** + * A Type Specific Set class to reduce boxing/unboxing + */ +public interface IntSet extends Set, IntCollection +{ + @Override + public IntIterator iterator(); + + @Override + public IntSet copy(); + + /** + * A Type Specific remove function to reduce boxing/unboxing + * @param o the element that should be removed + * @return true if the element was removed + */ + public boolean remove(int o); + + @Override + public default boolean remInt(int o) { + return remove(o); + } + + @Override + @Deprecated + public default boolean add(Integer e) { + return IntCollection.super.add(e); + } + + @Override + @Deprecated + public default boolean contains(Object o) { + return IntCollection.super.contains(o); + } + + @Override + @Deprecated + public default boolean remove(Object o) { + return IntCollection.super.remove(o); + } + + /** + * A Type Specific Type Splititerator to reduce boxing/unboxing + * @return type specific splititerator + */ + @Override + default IntSplititerator spliterator() { return IntSplititerators.createSplititerator(this, 0); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IIntArray.java b/src/main/java/speiger/src/collections/ints/utils/IIntArray.java new file mode 100644 index 000000000..ab6a3793f --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/utils/IIntArray.java @@ -0,0 +1,29 @@ +package speiger.src.collections.ints.utils; + +import java.util.Objects; +import java.util.function.Consumer; + +import speiger.src.collections.utils.IArray; + +/** + * Type-Specific Helper class to get the underlying array of array implementations. + */ +public interface IIntArray extends IArray +{ + /** + * Provides the Underlying Array in the Implementation + * @return underlying Array + * @throws ClassCastException if the return type does not match the underlying array. (Only for Object Implementations) + */ + public int[] elements(); + + /** + * Provides the Underlying Array in the Implementation. This function exists purely because of Synchronization wrappers to help run Synchronized Code + * @param action the action that handles the array + * @throws NullPointerException if action is null + */ + public default void elements(Consumer action) { + Objects.requireNonNull(action); + action.accept(elements()); + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IntArrays.java b/src/main/java/speiger/src/collections/ints/utils/IntArrays.java new file mode 100644 index 000000000..5b331bfcb --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/utils/IntArrays.java @@ -0,0 +1,1527 @@ +package speiger.src.collections.ints.utils; + +import java.util.Arrays; +import java.util.Random; +import java.util.concurrent.RecursiveAction; + +import speiger.src.collections.ints.functions.IntComparator; +import speiger.src.collections.ints.collections.IntIterator; +import speiger.src.collections.ints.utils.IntIterators; +import speiger.src.collections.ints.utils.IntCollections; +import speiger.src.collections.utils.SanityChecks; + +/** + * A Helper class for Arrays + */ +public class IntArrays +{ + /** Default Limit for Insertion/Selection Sort */ + public static final int BASE_THRESHOLD = 16; + /** Default Threshold for Multithreaded Sorting Algorythm options*/ + public static final int PARALLEL_THRESHOLD = 8192; + + /** Empty Array Reference used for Uninitialized Collections */ + public static final int[] EMPTY_ARRAY = new int[0]; + + /** + * A Helper function to convert a Primitive Array to a Integer Array. + * @param a the array that should be converted + * @return a Integer Array of the input array. + */ + public static Integer[] wrap(int[] a) { + return wrap(a, 0, a.length); + } + + /** + * A Helper function to convert a Primitive Array to a Integer Array. + * @param a the array that should be converted + * @param length the maximum length that should be coverted + * @return a Integer Array of the input array. + */ + public static Integer[] wrap(int[] a, int length) { + return wrap(a, 0, length); + } + + /** + * A Helper function to convert a Primitive Array to a Integer Array. + * @param a the array that should be converted + * @param offset the starting offset of the inputarray + * @param length the maximum length that should be coverted + * @return a Integer Array of the input array. + */ + public static Integer[] wrap(int[] a, int offset, int length) { + SanityChecks.checkArrayCapacity(a.length, offset, length); + Integer[] result = new Integer[length]; + for(int i = offset;i>> 1; + int value = data[index]; + if(comp != null) { + while(index < half) { + int child = (index << 1) + 1; + int childValue = data[child]; + int right = child+1; + if(right < size && comp.compare(data[right], childValue) < 0) childValue = data[child = right]; + if(comp.compare(value, childValue) <= 0) break; + data[index] = childValue; + index = child; + } + } + else { + while(index < half) { + int child = (index << 1) + 1; + int childValue = data[child]; + int right = child+1; + if(right < size && Integer.compare(data[right], childValue) < 0) childValue = data[child = right]; + if(Integer.compare(value, childValue) <= 0) break; + data[index] = childValue; + index = child; + } + } + data[index] = value; + return index; + } + + /** + * Method to sort a specific value into the heap. + * @param data the heap itself. + * @param index that should be heapified. + * @param comp the comparator to sort the heap. Can be null + * @return the index the element was shifted to + */ + public static int shiftUp(int[] data, int index, IntComparator comp) { + int value = data[index]; + if(comp != null) { + while(index > 0) { + int parent = (index - 1) >>> 1; + int parentValue = data[parent]; + if(comp.compare(value, parentValue) >= 0) break; + data[index] = parentValue; + index = parent; + } + } + else { + while(index > 0) { + int parent = (index - 1) >>> 1; + int parentValue = data[parent]; + if(Integer.compare(value, parentValue) >= 0) break; + data[index] = parentValue; + index = parent; + } + } + data[index] = value; + return index; + } + + /** + * Helper function to create a Heap out of an array. + * @param data the array to heapify + * @param size the current size of elements within the array. + * @param comp the Comparator to sort the array. Can be null + * @return the input array + */ + public static int[] heapify(int[] data, int size, IntComparator comp) { + for(int i = (size >>> 1) - 1;i>=0;shiftDown(data, size, i--, comp)); + return data; + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @note This uses the SanityChecks#getRandom + * @return the provided sorted array + */ + public static int[] shuffle(int[] array) { + return shuffle(array, SanityChecks.getRandom()); + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @param length the length of the array + * @note This uses the SanityChecks#getRandom + * @return the provided sorted array + */ + public static int[] shuffle(int[] array, int length) { + return shuffle(array, 0, length, SanityChecks.getRandom()); + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @param offset the start array + * @param length the length of the array + * @note This uses the SanityChecks#getRandom + * @return the provided sorted array + */ + public static int[] shuffle(int[] array, int offset, int length) { + return shuffle(array, offset, length, SanityChecks.getRandom()); + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @param random the Random Number Generator that should be used for the shuffling + * @return the provided sorted array + */ + public static int[] shuffle(int[] array, Random random) { + for(int i = array.length-1; i>=0;i--) { + int p = random.nextInt(i + 1); + int t = array[i]; + array[i] = array[p]; + array[p] = t; + } + return array; + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @param length the length of the array + * @param random the Random Number Generator that should be used for the shuffling + * @return the provided sorted array + */ + public static int[] shuffle(int[] array, int length, Random random) { + return shuffle(array, 0, length, random); + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @param offset the start array + * @param length the length of the array + * @param random the Random Number Generator that should be used for the shuffling + * @return the provided sorted array + */ + public static int[] shuffle(int[] array, int offset, int length, Random random) { + for(int i = length-1; i>=0;i--) { + int p = offset + random.nextInt(i + 1); + int t = array[offset+i]; + array[offset+i] = array[p]; + array[p] = t; + } + return array; + } + + /** + * Simple Array Reversal method + * @param array the Array that should flip + * @return the provided array + */ + public static int[] reverse(int[] array) { + return reverse(array, 0, array.length); + } + + /** + * Simple Array Reversal method + * @param array the Array that should flip + * @param length the length of the array + * @return the provided array + */ + public static int[] reverse(int[] array, int length) { + return reverse(array, 0, length); + } + + /** + * Simple Array Reversal method + * @param array the Array that should flip + * @param length the length of the array + * @param offset the start of the array + * @return the provided array + */ + public static int[] reverse(int[] array, int offset, int length) { + for (int i = offset, mid = offset + length >> 1, j = offset + length - 1; i < mid; i++, j--) { + int temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array. + */ + public static int[] stableSort(int[] array, IntComparator comp) { + stableSort(array, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void stableSort(int[] array, int length, IntComparator comp) { + stableSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void stableSort(int[] array, int from, int to, IntComparator comp) { + mergeSort(array, null, from, to, comp); + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @return input array + */ + public static int[] stableSort(int[] array) { + stableSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void stableSort(int[] array, int length) { + stableSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void stableSort(int[] array, int from, int to) { + mergeSort(array, null, from, to); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array + */ + public static int[] unstableSort(int[] array, IntComparator comp) { + unstableSort(array, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void unstableSort(int[] array, int length, IntComparator comp) { + unstableSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void unstableSort(int[] array, int from, int to, IntComparator comp) { + quickSort(array, from, to, comp); + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @return input array + */ + public static int[] unstableSort(int[] array) { + unstableSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void unstableSort(int[] array, int length) { + unstableSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void unstableSort(int[] array, int from, int to) { + quickSort(array, from, to); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array + */ + public static int[] insertionSort(int[] array, IntComparator comp) { + insertionSort(array, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void insertionSort(int[] array, int length, IntComparator comp) { + insertionSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void insertionSort(int[] array, int from, int to, IntComparator comp) { + for (int i = from+1;i= from && comp.compare(current, array[j]) < 0) { + array[j+1] = array[j--]; + } + array[j+1] = current; + } + } + + /** + * Sorts an array according to the natural ascending order using InsertionSort, + * @param array the array that needs to be sorted + * @return input array + */ + public static int[] insertionSort(int[] array) { + insertionSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order using InsertionSort, + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void insertionSort(int[] array, int length) { + insertionSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using InsertionSort, + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void insertionSort(int[] array, int from, int to) { + for (int i = from+1;i= from && Integer.compare(current, array[j]) < 0) { + array[j+1] = array[j--]; + } + array[j+1] = current; + } + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array + */ + public static int[] selectionSort(int[] array, IntComparator comp) { + selectionSort(array, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void selectionSort(int[] array, int length, IntComparator comp) { + selectionSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void selectionSort(int[] array, int from, int to, IntComparator comp) { + for (int i = from; i < to; i++) { + int min = array[i]; + int minId = i; + for(int j = i+1; j < to; j++) { + if(comp.compare(array[j], min) < 0) { + min = array[j]; + minId = j; + } + } + int temp = array[i]; + array[i] = min; + array[minId] = temp; + } + } + + /** + * Sorts an array according to the natural ascending order using Selection Sort, + * @param array the array that needs to be sorted + * @return input array + */ + public static int[] selectionSort(int[] array) { + selectionSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order using Selection Sort, + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void selectionSort(int[] array, int length) { + selectionSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Selection Sort, + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void selectionSort(int[] array, int from, int to) { + for (int i = from; i < to; i++) { + int min = array[i]; + int minId = i; + for(int j = i+1; j < to; j++) { + if(Integer.compare(array[j], min) < 0) { + min = array[j]; + minId = j; + } + } + int temp = array[i]; + array[i] = min; + array[minId] = temp; + } + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array + */ + public static int[] mergeSort(int[] array, IntComparator comp) { + mergeSort(array, null, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void mergeSort(int[] array, int length, IntComparator comp) { + mergeSort(array, null, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param supp the auxillary array that is used to simplify the sorting + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void mergeSort(int[] array, int[] supp, int from, int to, IntComparator comp) { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to, comp); + return; + } + if(supp == null) supp = Arrays.copyOf(array, to); + int mid = (from + to) >>> 1; + mergeSort(supp, array, from, mid, comp); + mergeSort(supp, array, mid, to, comp); + if(comp.compare(supp[mid - 1], supp[mid]) <= 0) + { + System.arraycopy(supp, from, array, from, to - from); + return; + } + for(int p = from, q = mid;from < to;from++) { + if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; + else array[from] = supp[q++]; + } + } + + /** + * Sorts an array according to the natural ascending order using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @return input array + */ + public static int[] mergeSort(int[] array) { + mergeSort(array, null, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void mergeSort(int[] array, int length) { + mergeSort(array, null, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param supp the auxillary array that is used to simplify the sorting + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void mergeSort(int[] array, int[] supp, int from, int to) { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to); + return; + } + if(supp == null) supp = Arrays.copyOf(array, to); + int mid = (from + to) >>> 1; + mergeSort(supp, array, from, mid); + mergeSort(supp, array, mid, to); + if(Integer.compare(supp[mid - 1], supp[mid]) <= 0) + { + System.arraycopy(supp, from, array, from, to - from); + return; + } + for(int p = from, q = mid;from < to;from++) { + if(q >= to || p < mid && Integer.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; + else array[from] = supp[q++]; + } + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using a Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(int[] array, IntComparator comp) { + parallelMergeSort(array, null, 0, array.length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(int[] array, int length, IntComparator comp) { + parallelMergeSort(array, null, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param supp the auxillary array that is used to simplify the sorting + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(int[] array, int[] supp, int from, int to, IntComparator comp) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new MergeSortActionComp(array, supp, from, to, comp)); + return; + } + mergeSort(array, supp, from, to, comp); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(int[] array) { + parallelMergeSort(array, null, 0, array.length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(int[] array, int length) { + parallelMergeSort(array, null, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param supp the auxillary array that is used to simplify the sorting + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(int[] array, int[] supp, int from, int to) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new MergeSortAction(array, supp, from, to)); + return; + } + mergeSort(array, supp, from, to); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void memFreeMergeSort(int[] array, IntComparator comp) { + memFreeMergeSort(array, 0, array.length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void memFreeMergeSort(int[] array, int length, IntComparator comp) { + memFreeMergeSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void memFreeMergeSort(int[] array, int from, int to, IntComparator comp) { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to, comp); + return; + } + int mid = (from + to) >>> 1; + memFreeMergeSort(array, from, mid, comp); + memFreeMergeSort(array, mid, to, comp); + if(comp.compare(array[mid - 1], array[mid]) <= 0) + return; + for(int i = from, j = mid, compare;i < j && j < to;) { + if((compare = comp.compare(array[i], array[j])) < 0) + i++; + else if(compare == 0) swap(array, ++i, j); + else { + int k = j; + for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); + continue; + } + else if(j + 1 == k) { + int value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + int[] data = new int[k - j]; + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; + } + } + } + + /** + * Sorts an array according to the natural ascending order using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @return input array + */ + public static int[] memFreeMergeSort(int[] array) { + memFreeMergeSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void memFreeMergeSort(int[] array, int length) { + memFreeMergeSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void memFreeMergeSort(int[] array, int from, int to) { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to); + return; + } + int mid = (from + to) >>> 1; + memFreeMergeSort(array, from, mid); + memFreeMergeSort(array, mid, to); + if(Integer.compare(array[mid - 1], array[mid]) <= 0) + return; + for(int i = from, j = mid, comp;i < j && j < to;) { + if((comp = Integer.compare(array[i], array[j])) < 0) + i++; + else if(comp == 0) swap(array, ++i, j); + else { + int k = j; + for(;k < to - 1 && Integer.compare(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); + continue; + } + else if(j + 1 == k) { + int value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + int[] data = new int[k - j]; + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; + } + } + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(int[] array, IntComparator comp) { + parallelMemFreeMergeSort(array, 0, array.length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(int[] array, int length, IntComparator comp) { + parallelMemFreeMergeSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(int[] array, int from, int to, IntComparator comp) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new MemFreeMergeSortActionComp(array, from, to, comp)); + return; + } + memFreeMergeSort(array, from, to, comp); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(int[] array) { + parallelMemFreeMergeSort(array, 0, array.length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(int[] array, int length) { + parallelMemFreeMergeSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(int[] array, int from, int to) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new MemFreeMergeSortAction(array, from, to)); + return; + } + memFreeMergeSort(array, from, to); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array + */ + public static int[] quickSort(int[] array, IntComparator comp) { + quickSort(array, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void quickSort(int[] array, int length, IntComparator comp) { + quickSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void quickSort(int[] array, int from, int to, IntComparator comp) { + int length = to - from; + if(length <= 0) return; + if(length < BASE_THRESHOLD) { + selectionSort(array, from, to, comp); + return; + } + int pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)]; + int a = from, b = a, c = to - 1, d = c; + for(int compare;;swap(array, b++, c--)) { + for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) { + if(compare == 0) swap(array, a++, b); + } + for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) { + if(compare == 0) swap(array, c, d--); + } + if(b>c) break; + } + swap(array, from, b, Math.min(a - from, b - a)); + swap(array, b, to, Math.min(d - c, to - d - 1)); + if((length = b - a) > 1) quickSort(array, from, from + length, comp); + if((length = d - c) > 1) quickSort(array, to - length, to, comp); + } + + /** + * Sorts an array according to the natural ascending order using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @return input array + */ + public static int[] quickSort(int[] array) { + quickSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void quickSort(int[] array, int length) { + quickSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void quickSort(int[] array, int from, int to) { + int length = to - from; + if(length <= 0) return; + if(length < BASE_THRESHOLD) { + selectionSort(array, from, to); + return; + } + int pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)]; + int a = from, b = a, c = to - 1, d = c; + for(int comp = 0;;swap(array, b++, c--)) { + for(;b<=c && (comp = Integer.compare(array[b], pivot)) <= 0;b++) { + if(comp == 0) swap(array, a++, b); + } + for(;c>=b && (comp = Integer.compare(array[c], pivot)) >= 0;c--) { + if(comp == 0) swap(array, c, d--); + } + if(b>c) break; + } + swap(array, from, b, Math.min(a - from, b - a)); + swap(array, b, to, Math.min(d - c, to - d - 1)); + if((length = b - a) > 1) quickSort(array, from, from + length); + if((length = d - c) > 1) quickSort(array, to - length, to); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(int[] array, IntComparator comp) { + parallelQuickSort(array, 0, array.length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(int[] array, int length, IntComparator comp) { + parallelQuickSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(int[] array, int from, int to, IntComparator comp) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new QuickSortActionComp(array, from, to, comp)); + return; + } + quickSort(array, from, to, comp); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(int[] array) { + parallelQuickSort(array, 0, array.length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(int[] array, int length) { + parallelQuickSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(int[] array, int from, int to) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new QuickSortAction(array, from, to)); + return; + } + quickSort(array, from, to); + } + + static void swap(int[] a, int from, int to) { + int t = a[from]; + a[from] = a[to]; + a[to] = t; + } + + static void swap(int[] a, int from, int to, int length) { + to -= length; + for(int i = 0;i 0 ? b : comp.compare(data[a], data[c]) > 0 ? c : a); + } + + static int subMedium(int[] data, int a, int b, int c, int length) { + return medium(data, medium(data, a, a + length, a + (length * 2)), medium(data, b - length, b, b + length), medium(data, c - (length * 2), c - length, c)); + } + + static int medium(int[] data, int a, int b, int c) { + return Integer.compare(data[a], data[b]) < 0 ? (Integer.compare(data[b], data[c]) < 0 ? b : Integer.compare(data[a], data[c]) < 0 ? c : a) : (Integer.compare(data[b], data[c]) > 0 ? b : Integer.compare(data[a], data[c]) > 0 ? c : a); + } + + static class QuickSortAction extends RecursiveAction { + private static final long serialVersionUID = 0L; + int[] array; + int from; + int to; + + QuickSortAction(int[] array, int from, int to) + { + this.array = array; + this.from = from; + this.to = to; + } + + @Override + protected void compute() + { + int length = to - from; + if(length <= 0) return; + if(length < BASE_THRESHOLD) { + selectionSort(array, from, to); + return; + } + int pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)]; + int a = from, b = a, c = to - 1, d = c; + for(int comp = 0;;swap(array, b++, c--)) { + for(;b<=c && (comp = Integer.compare(array[b], pivot)) <= 0;b++) { + if(comp == 0) swap(array, a++, b); + } + for(;c>=b && (comp = Integer.compare(array[c], pivot)) >= 0;c--) { + if(comp == 0) swap(array, c, d--); + } + if(b>c) break; + } + swap(array, from, b, Math.min(a - from, b - a)); + swap(array, b, to, Math.min(d - c, to - d - 1)); + if(b - a > 1 && d - c > 1) invokeAll(new QuickSortAction(array, from, from + (b - a)), new QuickSortAction(array, to - (d - c), to)); + else if(b - a > 1) new QuickSortAction(array, from, from + (b - a)).invoke(); + else if(d - c > 1) new QuickSortAction(array, to - (d - c), to).invoke(); + } + } + + static class QuickSortActionComp extends RecursiveAction { + private static final long serialVersionUID = 0L; + int[] array; + int from; + int to; + IntComparator comp; + + QuickSortActionComp(int[] array, int from, int to, IntComparator comp) + { + this.array = array; + this.from = from; + this.to = to; + this.comp = comp; + } + + @Override + protected void compute() + { + int length = to - from; + if(length <= 0) return; + if(length < BASE_THRESHOLD) { + selectionSort(array, from, to, comp); + return; + } + int pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)]; + int a = from, b = a, c = to - 1, d = c; + for(int compare;;swap(array, b++, c--)) { + for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) { + if(compare == 0) swap(array, a++, b); + } + for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) { + if(compare == 0) swap(array, c, d--); + } + if(b>c) break; + } + swap(array, from, b, Math.min(a - from, b - a)); + swap(array, b, to, Math.min(d - c, to - d - 1)); + if(b - a > 1 && d - c > 1) invokeAll(new QuickSortActionComp(array, from, from + (b - a), comp), new QuickSortActionComp(array, to - (d - c), to, comp)); + else if(b - a > 1) new QuickSortActionComp(array, from, from + (b - a), comp).invoke(); + else if(d - c > 1) new QuickSortActionComp(array, to - (d - c), to, comp).invoke(); + } + } + + static class MergeSortAction extends RecursiveAction { + private static final long serialVersionUID = 0L; + int[] array; + int[] supp; + int from; + int to; + + MergeSortAction(int[] array, int[] supp, int from, int to) + { + this.array = array; + this.supp = supp; + this.from = from; + this.to = to; + } + + @Override + protected void compute() + { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to); + return; + } + if(supp == null) supp = Arrays.copyOf(array, to); + int mid = (from + to) >>> 1; + invokeAll(new MergeSortAction(supp, array, from, mid), new MergeSortAction(supp, array, mid, to)); + if(Integer.compare(supp[mid - 1], supp[mid]) <= 0) + { + System.arraycopy(supp, from, array, from, to - from); + return; + } + for(int p = from, q = mid;from < to;from++) { + if(q >= to || p < mid && Integer.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; + else array[from] = supp[q++]; + } + } + } + + static class MergeSortActionComp extends RecursiveAction { + private static final long serialVersionUID = 0L; + int[] array; + int[] supp; + int from; + int to; + IntComparator comp; + + MergeSortActionComp(int[] array, int[] supp, int from, int to, IntComparator comp) + { + this.array = array; + this.supp = supp; + this.from = from; + this.to = to; + this.comp = comp; + } + + @Override + protected void compute() + { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to, comp); + return; + } + if(supp == null) supp = Arrays.copyOf(array, to); + int mid = (from + to) >>> 1; + invokeAll(new MergeSortActionComp(supp, array, from, mid, comp), new MergeSortActionComp(supp, array, mid, to, comp)); + if(comp.compare(supp[mid - 1], supp[mid]) <= 0) + { + System.arraycopy(supp, from, array, from, to - from); + return; + } + for(int p = from, q = mid;from < to;from++) { + if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; + else array[from] = supp[q++]; + } + } + } + + static class MemFreeMergeSortAction extends RecursiveAction { + private static final long serialVersionUID = 0L; + int[] array; + int from; + int to; + + MemFreeMergeSortAction(int[] array, int from, int to) + { + this.array = array; + this.from = from; + this.to = to; + } + + @Override + protected void compute() + { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to); + return; + } + int mid = (from + to) >>> 1; + invokeAll(new MemFreeMergeSortAction(array, from, mid), new MemFreeMergeSortAction(array, mid, to)); + if(Integer.compare(array[mid - 1], array[mid]) <= 0) + return; + for(int i = from, j = mid, comp;i < j && j < to;) { + if((comp = Integer.compare(array[i], array[j])) < 0) + i++; + else if(comp == 0) swap(array, ++i, j); + else { + int k = j; + for(;k < to - 1 && Integer.compare(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); + continue; + } + else if(j + 1 == k) { + int value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + int[] data = new int[k - j]; + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; + } + } + } + } + + static class MemFreeMergeSortActionComp extends RecursiveAction { + private static final long serialVersionUID = 0L; + int[] array; + int from; + int to; + IntComparator comp; + + MemFreeMergeSortActionComp(int[] array, int from, int to, IntComparator comp) + { + this.array = array; + this.from = from; + this.to = to; + this.comp = comp; + } + + @Override + protected void compute() + { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to, comp); + return; + } + int mid = (from + to) >>> 1; + invokeAll(new MemFreeMergeSortActionComp(array, from, mid, comp), new MemFreeMergeSortActionComp(array, mid, to, comp)); + + if(comp.compare(array[mid - 1], array[mid]) <= 0) + return; + for(int i = from, j = mid, compare;i < j && j < to;) { + if((compare = comp.compare(array[i], array[j])) < 0) + i++; + else if(compare == 0) swap(array, ++i, j); + else { + int k = j; + for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); + continue; + } + else if(j + 1 == k) { + int value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + int[] data = new int[k - j]; + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IntCollections.java b/src/main/java/speiger/src/collections/ints/utils/IntCollections.java new file mode 100644 index 000000000..91aeb66af --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/utils/IntCollections.java @@ -0,0 +1,892 @@ +package speiger.src.collections.ints.utils; + +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.function.IntPredicate; +import java.util.function.Consumer; + +import speiger.src.collections.ints.collections.AbstractIntCollection; +import speiger.src.collections.ints.collections.IntCollection; +import speiger.src.collections.ints.collections.IntIterator; +import speiger.src.collections.ints.functions.IntComparator; +import speiger.src.collections.objects.utils.ObjectArrays; +import speiger.src.collections.ints.functions.IntConsumer; +import speiger.src.collections.ints.utils.IntArrays; +import speiger.src.collections.ints.functions.function.IntIntUnaryOperator; +import speiger.src.collections.ints.functions.consumer.IntIntConsumer; +import speiger.src.collections.objects.functions.consumer.ObjectIntConsumer; +import speiger.src.collections.utils.HashUtil; +import speiger.src.collections.utils.ITrimmable; +import speiger.src.collections.utils.SanityChecks; + +/** + * A Helper class for Collections + */ +public class IntCollections +{ + /** + * Empty Collection Reference + */ + public static final IntCollection EMPTY = new EmptyCollection(); + + /** + * Returns a Immutable EmptyCollection instance that is automatically casted. + * @return an empty collection + */ + public static IntCollection empty() { + return EMPTY; + } + + /** + * Returns a Immutable Collection instance based on the instance given. + * @param c that should be made immutable/unmodifiable + * @return a unmodifiable collection wrapper. If the Collection already a unmodifiable wrapper then it just returns itself. + */ + public static IntCollection unmodifiable(IntCollection c) { + return c instanceof UnmodifiableCollection ? c : new UnmodifiableCollection(c); + } + + /** + * Returns a synchronized Collection instance based on the instance given. + * @param c that should be synchronized + * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself. + */ + public static IntCollection synchronize(IntCollection c) { + return c instanceof SynchronizedCollection ? c : new SynchronizedCollection(c); + } + + /** + * Returns a synchronized Collection instance based on the instance given. + * @param c that should be synchronized + * @param mutex is the controller of the synchronization block. + * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself. + */ + public static IntCollection synchronize(IntCollection c, Object mutex) { + return c instanceof SynchronizedCollection ? c : new SynchronizedCollection(c, mutex); + } + + /** + * Creates a Singleton Collection of a given element + * @param element the element that should be converted into a singleton collection + * @return a singletoncollection of the given element + */ + public static IntCollection singleton(int element) { + return new SingletonCollection(element); + } + + protected static CollectionWrapper wrapper() { + return new CollectionWrapper(); + } + + protected static CollectionWrapper wrapper(int size) { + return new CollectionWrapper(size); + } + + protected static DistinctCollectionWrapper distinctWrapper() { + return new DistinctCollectionWrapper(); + } + + protected static DistinctCollectionWrapper distinctWrapper(int size) { + return new DistinctCollectionWrapper(size); + } + + protected static class CollectionWrapper extends AbstractIntCollection implements ITrimmable { + int[] elements; + int size = 0; + + public CollectionWrapper() { + this(10); + } + + public CollectionWrapper(int size) { + if(size < 0) throw new IllegalStateException("Size has to be 0 or greater"); + elements = new int[size]; + } + + @Override + public boolean add(int o) { + if(size >= elements.length) elements = Arrays.copyOf(elements, (int)Math.min((long)elements.length + (elements.length >> 1), SanityChecks.MAX_ARRAY_SIZE)); + elements[size++] = o; + return true; + } + + public int getInt(int index) { + if(index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + return elements[index]; + } + + @Override + public boolean remInt(int e) { + for(int i = 0;i= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + size--; + if(index != size) System.arraycopy(elements, index+1, elements, index, size - index); + } + + @Override + public IntIterator iterator() { + return new IntIterator() { + int index = 0; + int lastReturned = -1; + + @Override + public boolean hasNext() { + return index < size; + } + + @Override + public int nextInt() { + int i = index++; + return elements[(lastReturned = i)]; + } + + @Override + public void remove() { + if(lastReturned == -1) throw new IllegalStateException(); + removeIndex(lastReturned); + index = lastReturned; + lastReturned = -1; + } + }; + } + + @Override + public int size() { + return size; + } + + @Override + public void clear() { + size = 0; + } + + public void sort(IntComparator c) { + if(c != null) IntArrays.stableSort(elements, size, c); + else IntArrays.stableSort(elements, size); + } + + public void unstableSort(IntComparator c) { + if(c != null) IntArrays.unstableSort(elements, size, c); + else IntArrays.unstableSort(elements, size); + } + + @Override + public void forEach(IntConsumer action) { + Objects.requireNonNull(action); + for(int i = 0;i void forEach(E input, ObjectIntConsumer action) { + Objects.requireNonNull(action); + for(int i = 0;i size() || size() == elements.length) return false; + int value = Math.max(size, size()); + elements = value == 0 ? IntArrays.EMPTY_ARRAY : Arrays.copyOf(elements, value); + return true; + } + + @Override + public void clearAndTrim(int size) { + if(elements.length <= size) { + clear(); + return; + } + elements = size == 0 ? IntArrays.EMPTY_ARRAY : new int[size]; + this.size = size; + } + + @Override + @Deprecated + public Object[] toArray() { + Object[] obj = new Object[size]; + for(int i = 0;i E[] toArray(E[] a) { + if(a == null) a = (E[])new Object[size]; + else if(a.length < size) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), size); + for(int i = 0;i size) a[size] = null; + return a; + } + + @Override + public int[] toIntArray(int[] a) { + if(a.length < size) a = new int[size]; + System.arraycopy(elements, 0, a, 0, size); + if (a.length > size) a[size] = 0; + return a; + } + } + + protected static class DistinctCollectionWrapper extends AbstractIntCollection { + int[] keys; + boolean containsNull; + int minCapacity; + int nullIndex; + int maxFill; + int mask; + int size; + + public DistinctCollectionWrapper() { + this(HashUtil.DEFAULT_MIN_CAPACITY); + } + + public DistinctCollectionWrapper(int size) { + if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); + minCapacity = nullIndex = HashUtil.arraySize(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR); + mask = nullIndex - 1; + maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1); + keys = new int[nullIndex + 1]; + } + + @Override + public boolean add(int o) { + if(o == 0) { + if(containsNull) return false; + containsNull = true; + } + else { + int pos = HashUtil.mix(Integer.hashCode(o)) & mask; + int current = keys[pos]; + if(current != 0) { + if(current == o) return false; + while((current = keys[pos = (++pos & mask)]) != 0) + if(current == o) return false; + } + keys[pos] = o; + } + if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, HashUtil.DEFAULT_LOAD_FACTOR)); + return true; + } + + @Override + public boolean contains(Object o) { + if(o == null) return false; + if(o instanceof Integer && ((Integer)o).intValue() == 0) return containsNull; + int pos = HashUtil.mix(o.hashCode()) & mask; + int current = keys[pos]; + if(current == 0) return false; + if(Objects.equals(o, Integer.valueOf(current))) return true; + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(Objects.equals(o, Integer.valueOf(current))) return true; + } + } + + @Override + public boolean remove(Object o) { + if(o == null) return false; + if(o instanceof Integer && ((Integer)o).intValue() == 0) return (containsNull ? removeNullIndex() : false); + int pos = HashUtil.mix(o.hashCode()) & mask; + int current = keys[pos]; + if(current == 0) return false; + if(Objects.equals(o, Integer.valueOf(current))) return removeIndex(pos); + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(Objects.equals(o, Integer.valueOf(current))) return removeIndex(pos); + } + } + + @Override + public boolean contains(int o) { + if(o == 0) return containsNull; + int pos = HashUtil.mix(Integer.hashCode(o)) & mask; + int current = keys[pos]; + if(current == 0) return false; + if(current == o) return true; + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(current == o) return true; + } + } + + @Override + public boolean remInt(int o) { + if(o == 0) return containsNull ? removeNullIndex() : false; + int pos = HashUtil.mix(Integer.hashCode(o)) & mask; + int current = keys[pos]; + if(current == 0) return false; + if(current == o) return removeIndex(pos); + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(current == o) return removeIndex(pos); + } + } + + protected boolean removeIndex(int pos) { + if(pos == nullIndex) return containsNull ? removeNullIndex() : false; + keys[pos] = 0; + size--; + shiftKeys(pos); + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return true; + } + + protected boolean removeNullIndex() { + containsNull = false; + keys[nullIndex] = 0; + size--; + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return true; + } + + @Override + public IntIterator iterator() { + return new SetIterator(); + } + + @Override + public void forEach(IntConsumer action) { + if(size() <= 0) return; + if(containsNull) action.accept(keys[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) { + if(keys[i] != 0) action.accept(keys[i]); + } + } + + @Override + public DistinctCollectionWrapper copy() { + DistinctCollectionWrapper set = new DistinctCollectionWrapper(0); + set.minCapacity = minCapacity; + set.mask = mask; + set.maxFill = maxFill; + set.nullIndex = nullIndex; + set.containsNull = containsNull; + set.size = size; + set.keys = Arrays.copyOf(keys, keys.length); + return set; + } + + protected void shiftKeys(int startPos) { + int slot, last; + int current; + while(true) { + startPos = ((last = startPos) + 1) & mask; + while(true){ + if((current = keys[startPos]) == 0) { + keys[last] = 0; + return; + } + slot = HashUtil.mix(Integer.hashCode(current)) & mask; + if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; + startPos = ++startPos & mask; + } + keys[last] = current; + } + } + + protected void rehash(int newSize) { + int newMask = newSize - 1; + int[] newKeys = new int[newSize + 1]; + for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) { + while(true) { + if(--i < 0) throw new ConcurrentModificationException("Set was modified during rehash"); + if(keys[i] != 0) break; + } + if(newKeys[pos = HashUtil.mix(Integer.hashCode(keys[i])) & newMask] != 0) + while(newKeys[pos = (++pos & newMask)] != 0); + newKeys[pos] = keys[i]; + } + nullIndex = newSize; + mask = newMask; + maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1); + keys = newKeys; + } + + @Override + public void clear() { + if(size == 0) return; + size = 0; + containsNull = false; + Arrays.fill(keys, 0); + } + + @Override + public int size() { + return size; + } + + private class SetIterator implements IntIterator { + int pos = nullIndex; + int returnedPos = -1; + int lastReturned = -1; + int nextIndex = Integer.MIN_VALUE; + boolean returnNull = containsNull; + int[] wrapped = null; + int wrappedIndex = 0; + + @Override + public boolean hasNext() { + if(nextIndex == Integer.MIN_VALUE) { + if(returnNull) { + returnNull = false; + nextIndex = nullIndex; + } + else + { + while(true) { + if(--pos < 0) { + if(wrapped == null || wrappedIndex <= -pos - 1) break; + nextIndex = -pos - 1; + break; + } + if(keys[pos] != 0){ + nextIndex = pos; + break; + } + } + } + } + return nextIndex != Integer.MIN_VALUE; + } + + @Override + public int nextInt() { + if(!hasNext()) throw new NoSuchElementException(); + returnedPos = pos; + if(nextIndex < 0){ + lastReturned = Integer.MAX_VALUE; + int value = wrapped[nextIndex]; + nextIndex = Integer.MIN_VALUE; + return value; + } + int value = keys[(lastReturned = nextIndex)]; + nextIndex = Integer.MIN_VALUE; + return value; + } + + @Override + public void remove() { + if(lastReturned == -1) throw new IllegalStateException(); + if(lastReturned == nullIndex) { + containsNull = false; + keys[nullIndex] = 0; + } + else if(returnedPos >= 0) shiftKeys(returnedPos); + else { + DistinctCollectionWrapper.this.remInt(wrapped[-returnedPos - 1]); + lastReturned = -1; + return; + } + size--; + lastReturned = -1; + } + + private void shiftKeys(int startPos) { + int slot, last; + int current; + while(true) { + startPos = ((last = startPos) + 1) & mask; + while(true){ + if((current = keys[startPos]) == 0) { + keys[last] = 0; + return; + } + slot = HashUtil.mix(Integer.hashCode(current)) & mask; + if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; + startPos = ++startPos & mask; + } + if(startPos < last) addWrapper(keys[startPos]); + keys[last] = current; + } + } + + private void addWrapper(int value) { + if(wrapped == null) wrapped = new int[2]; + else if(wrappedIndex >= wrapped.length) { + int[] newArray = new int[wrapped.length * 2]; + System.arraycopy(wrapped, 0, newArray, 0, wrapped.length); + wrapped = newArray; + } + wrapped[wrappedIndex++] = value; + } + } + } + + private static class SingletonCollection extends AbstractIntCollection + { + int element; + + SingletonCollection(int element) { + this.element = element; + } + + @Override + public boolean remInt(int o) { throw new UnsupportedOperationException(); } + @Override + public boolean add(int o) { throw new UnsupportedOperationException(); } + @Override + public IntIterator iterator() + { + return new IntIterator() { + boolean next = true; + @Override + public boolean hasNext() { return next; } + @Override + public int nextInt() { + if(!hasNext()) throw new NoSuchElementException(); + next = false; + return element; + } + }; + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Collection)) + return false; + Collection l = (Collection)o; + if(l.size() != size()) return false; + Iterator iter = l.iterator(); + if (iter.hasNext() && !Objects.equals(element, iter.next())) { + return false; + } + return !iter.hasNext(); + } + + @Override + public int hashCode() { + return Integer.hashCode(element); + } + + @Override + public int size() { return 1; } + + @Override + public SingletonCollection copy() { return new SingletonCollection(element); } + } + + /** + * Synchronized Collection Wrapper for the synchronizedCollection function + */ + public static class SynchronizedCollection implements IntCollection { + IntCollection c; + protected Object mutex; + + SynchronizedCollection(IntCollection c) { + this.c = c; + mutex = this; + } + + SynchronizedCollection(IntCollection c, Object mutex) { + this.c = c; + this.mutex = mutex; + } + + @Override + public boolean add(int o) { synchronized(mutex) { return c.add(o); } } + @Override + public boolean addAll(Collection c) { synchronized(mutex) { return this.c.addAll(c); } } + @Override + public boolean addAll(IntCollection c) { synchronized(mutex) { return this.c.addAll(c); } } + @Override + public boolean addAll(int[] e, int offset, int length) { synchronized(mutex) { return c.addAll(e, offset, length); } } + @Override + public boolean contains(int o) { synchronized(mutex) { return c.contains(o); } } + @Override + @Deprecated + public boolean containsAll(Collection c) { synchronized(mutex) { return this.c.containsAll(c); } } + + @Override + @Deprecated + public boolean containsAny(Collection c) { synchronized(mutex) { return this.c.containsAny(c); } } + + @Override + public boolean containsAll(IntCollection c) { synchronized(mutex) { return this.c.containsAll(c); } } + + @Override + public boolean containsAny(IntCollection c) { synchronized(mutex) { return this.c.containsAny(c); } } + + @Override + public int size() { synchronized(mutex) { return c.size(); } } + + @Override + public boolean isEmpty() { synchronized(mutex) { return c.isEmpty(); } } + + @Override + public IntIterator iterator() { + return c.iterator(); + } + + @Override + public IntCollection copy() { synchronized(mutex) { return c.copy(); } } + + @Override + @Deprecated + public boolean remove(Object o) { synchronized(mutex) { return c.remove(o); } } + @Override + @Deprecated + public boolean removeAll(Collection c) { synchronized(mutex) { return this.c.removeAll(c); } } + @Override + @Deprecated + public boolean retainAll(Collection c) { synchronized(mutex) { return this.c.retainAll(c); } } + @Override + public boolean remInt(int o) { synchronized(mutex) { return c.remInt(o); } } + @Override + public boolean removeAll(IntCollection c) { synchronized(mutex) { return this.c.removeAll(c); } } + @Override + public boolean removeAll(IntCollection c, IntConsumer r) { synchronized(mutex) { return this.c.removeAll(c, r); } } + @Override + public boolean retainAll(IntCollection c) { synchronized(mutex) { return this.c.retainAll(c); } } + @Override + public boolean retainAll(IntCollection c, IntConsumer r) { synchronized(mutex) { return this.c.retainAll(c, r); } } + @Override + public boolean remIf(IntPredicate filter){ synchronized(mutex) { return c.remIf(filter); } } + @Override + public void clear() { synchronized(mutex) { c.clear(); } } + @Override + public Object[] toArray() { synchronized(mutex) { return c.toArray(); } } + @Override + public T[] toArray(T[] a) { synchronized(mutex) { return c.toArray(a); } } + @Override + public int[] toIntArray() { synchronized(mutex) { return c.toIntArray(); } } + @Override + public int[] toIntArray(int[] a) { synchronized(mutex) { return c.toIntArray(a); } } + @Override + public void forEach(IntConsumer action) { synchronized(mutex) { c.forEach(action); } } + @Override + @Deprecated + public void forEach(Consumer action) { synchronized(mutex) { c.forEach(action); } } + @Override + public void forEachIndexed(IntIntConsumer action) { synchronized(mutex) { c.forEachIndexed(action); } } + @Override + public int hashCode() { synchronized(mutex) { return c.hashCode(); } } + @Override + public boolean equals(Object obj) { + if(obj == this) return true; + synchronized(mutex) { return c.equals(obj); } + } + @Override + public String toString() { synchronized(mutex) { return c.toString(); } } + @Override + public void forEach(E input, ObjectIntConsumer action) { synchronized(mutex) { c.forEach(input, action); } } + @Override + public boolean matchesAny(IntPredicate filter) { synchronized(mutex) { return c.matchesAny(filter); } } + @Override + public boolean matchesNone(IntPredicate filter) { synchronized(mutex) { return c.matchesNone(filter); } } + @Override + public boolean matchesAll(IntPredicate filter) { synchronized(mutex) { return c.matchesAll(filter); } } + @Override + public int reduce(int identity, IntIntUnaryOperator operator) { synchronized(mutex) { return c.reduce(identity, operator); } } + @Override + public int reduce(IntIntUnaryOperator operator) { synchronized(mutex) { return c.reduce(operator); } } + @Override + public int findFirst(IntPredicate filter) { synchronized(mutex) { return c.findFirst(filter); } } + @Override + public int count(IntPredicate filter) { synchronized(mutex) { return c.count(filter); } } + } + + /** + * Unmodifyable Collection Wrapper for the unmodifyableCollection method + */ + public static class UnmodifiableCollection implements IntCollection { + IntCollection c; + + UnmodifiableCollection(IntCollection c) { + this.c = c; + } + + @Override + public boolean add(int o) { throw new UnsupportedOperationException(); } + @Override + public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } + @Override + public boolean addAll(IntCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean addAll(int[] e, int offset, int length) { throw new UnsupportedOperationException(); } + @Override + public boolean contains(int o) { return c.contains(o); } + @Override + public boolean containsAll(IntCollection c) { return this.c.containsAll(c); } + @Override + public boolean containsAny(IntCollection c) { return this.c.containsAny(c); } + @Override + @Deprecated + public boolean containsAny(Collection c) { return this.c.containsAny(c); } + @Override + @Deprecated + public boolean containsAll(Collection c) { return this.c.containsAll(c); } + @Override + public int size() { return c.size(); } + @Override + public boolean isEmpty() { return c.isEmpty(); } + @Override + public IntIterator iterator() { return IntIterators.unmodifiable(c.iterator()); } + @Override + public IntCollection copy() { return c.copy(); } + @Override + @Deprecated + public boolean remove(Object o) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); } + @Override + public boolean remInt(int o) { throw new UnsupportedOperationException(); } + @Override + public boolean removeAll(IntCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean removeAll(IntCollection c, IntConsumer r) { throw new UnsupportedOperationException(); } + @Override + public boolean retainAll(IntCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean retainAll(IntCollection c, IntConsumer r) { throw new UnsupportedOperationException(); } + @Override + public boolean remIf(IntPredicate filter){ throw new UnsupportedOperationException(); } + @Override + public void clear() { throw new UnsupportedOperationException(); } + @Override + public Object[] toArray() { return c.toArray(); } + @Override + public T[] toArray(T[] a) { return c.toArray(a); } + @Override + public int[] toIntArray() { return c.toIntArray(); } + @Override + public int[] toIntArray(int[] a) { return c.toIntArray(a); } + @Override + public void forEach(IntConsumer action) { c.forEach(action); } + @Override + @Deprecated + public void forEach(Consumer action) { c.forEach(action); } + @Override + public void forEachIndexed(IntIntConsumer action) { c.forEachIndexed(action); } + @Override + public int hashCode() { return c.hashCode(); } + @Override + public boolean equals(Object obj) { return obj == this || c.equals(obj); } + @Override + public String toString() { return c.toString(); } + @Override + public void forEach(E input, ObjectIntConsumer action) { c.forEach(input, action); } + @Override + public boolean matchesAny(IntPredicate filter) { return c.matchesAny(filter); } + @Override + public boolean matchesNone(IntPredicate filter) { return c.matchesNone(filter); } + @Override + public boolean matchesAll(IntPredicate filter) { return c.matchesAll(filter); } + @Override + public int reduce(int identity, IntIntUnaryOperator operator) { return c.reduce(identity, operator); } + @Override + public int reduce(IntIntUnaryOperator operator) { return c.reduce(operator); } + @Override + public int findFirst(IntPredicate filter) { return c.findFirst(filter); } + @Override + public int count(IntPredicate filter) { return c.count(filter); } + } + + /** + * Empty Collection implementation for the empty collection function + */ + public static class EmptyCollection extends AbstractIntCollection { + @Override + public boolean add(int o) { throw new UnsupportedOperationException(); } + + @Override + public boolean addAll(IntCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean addAll(int[] e, int offset, int length) { throw new UnsupportedOperationException(); } + + @Override + public boolean contains(int o) { return false; } + @Override + public boolean containsAll(IntCollection c) { return c.isEmpty(); } + @Override + public boolean containsAny(IntCollection c) { return false; } + @Override + @Deprecated + public boolean containsAny(Collection c) { return false; } + @Override + @Deprecated + public boolean containsAll(Collection c) { return c.isEmpty(); } + @Override + public int hashCode() { return 0; } + + @Override + public boolean equals(Object o) { + if(o == this) return true; + if(!(o instanceof Collection)) return false; + return ((Collection)o).isEmpty(); + } + + @Override + @Deprecated + public boolean remove(Object o) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); } + @Override + public boolean remInt(int o) { throw new UnsupportedOperationException(); } + @Override + public boolean removeAll(IntCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean retainAll(IntCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean remIf(IntPredicate filter){ throw new UnsupportedOperationException(); } + @Override + public Object[] toArray() { return ObjectArrays.EMPTY_ARRAY; } + @Override + public T[] toArray(T[] a) { + if(a != null && a.length > 0) + a[0] = null; + return a; + } + + @Override + public int[] toIntArray() { return IntArrays.EMPTY_ARRAY; } + @Override + public int[] toIntArray(int[] a) { + if(a != null && a.length > 0) + a[0] = 0; + return a; + } + + @Override + public IntIterator iterator() { return IntIterators.empty(); } + @Override + public void clear() {} + @Override + public int size() { return 0; } + @Override + public EmptyCollection copy() { return this; } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IntIterables.java b/src/main/java/speiger/src/collections/ints/utils/IntIterables.java new file mode 100644 index 000000000..46cd7b21f --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/utils/IntIterables.java @@ -0,0 +1,485 @@ +package speiger.src.collections.ints.utils; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; +import java.util.function.IntPredicate; + +import speiger.src.collections.ints.collections.IntIterable; +import speiger.src.collections.ints.collections.IntCollection; +import speiger.src.collections.objects.collections.ObjectIterable; +import speiger.src.collections.objects.collections.ObjectIterator; +import speiger.src.collections.ints.functions.IntConsumer; +import speiger.src.collections.ints.functions.IntComparator; +import speiger.src.collections.ints.collections.IntIterator; +import speiger.src.collections.ints.functions.function.IntFunction; +import speiger.src.collections.utils.ISizeProvider; + +/** + * A Helper class for Iterables + */ +public class IntIterables +{ + /** + * A Helper function that maps a Java-Iterable into a new Type. + * @param iterable the iterable that should be mapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterable that is mapped to a new result + */ + public static ObjectIterable map(Iterable iterable, IntFunction mapper) { + return new MappedIterable<>(wrap(iterable), mapper); + } + + /** + * A Helper function that maps a Iterable into a new Type. + * @param iterable the iterable that should be mapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterable that is mapped to a new result + */ + public static ObjectIterable map(IntIterable iterable, IntFunction mapper) { + return new MappedIterable<>(iterable, mapper); + } + + /** + * A Helper function that flatMaps a Java-Iterable into a new Type. + * @param iterable the iterable that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type supplier. + * @param The return type. + * @return a iterable that is flatMapped to a new result + */ + public static > ObjectIterable flatMap(Iterable iterable, IntFunction mapper) { + return new FlatMappedIterable<>(wrap(iterable), mapper); + } + + /** + * A Helper function that flatMaps a Iterable into a new Type. + * @param iterable the iterable that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type supplier. + * @param The return type. + * @return a iterable that is flatMapped to a new result + */ + public static > ObjectIterable flatMap(IntIterable iterable, IntFunction mapper) { + return new FlatMappedIterable<>(iterable, mapper); + } + + /** + * A Helper function that flatMaps a Java-Iterable into a new Type. + * @param iterable the iterable that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterable that is flatMapped to a new result + */ + public static ObjectIterable arrayFlatMap(Iterable iterable, IntFunction mapper) { + return new FlatMappedArrayIterable<>(wrap(iterable), mapper); + } + + /** + * A Helper function that flatMaps a Iterable into a new Type. + * @param iterable the iterable that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterable that is flatMapped to a new result + */ + public static ObjectIterable arrayFlatMap(IntIterable iterable, IntFunction mapper) { + return new FlatMappedArrayIterable<>(iterable, mapper); + } + + /** + * A Helper function that filters out all desired elements from a Java-Iterable + * @param iterable that should be filtered. + * @param filter the filter that decides that should be let through + * @return a filtered iterable + */ + public static IntIterable filter(Iterable iterable, IntPredicate filter) { + return new FilteredIterable(wrap(iterable), filter); + } + + /** + * A Helper function that filters out all desired elements + * @param iterable that should be filtered. + * @param filter the filter that decides that should be let through + * @return a filtered iterable + */ + public static IntIterable filter(IntIterable iterable, IntPredicate filter) { + return new FilteredIterable(iterable, filter); + } + + /** + * A Helper function that filters out all duplicated elements. + * @param iterable that should be distinct + * @return a distinct iterable + */ + public static IntIterable distinct(IntIterable iterable) { + return new DistinctIterable(iterable); + } + + /** + * A Helper function that filters out all duplicated elements from a Java Iterable. + * @param iterable that should be distinct + * @return a distinct iterable + */ + public static IntIterable distinct(Iterable iterable) { + return new DistinctIterable(wrap(iterable)); + } + + /** + * A Helper function that repeats the Iterable a specific amount of times + * @param iterable that should be repeated + * @param repeats the amount of times the iterable should be repeated + * @return a repeating iterable + */ + public static IntIterable repeat(IntIterable iterable, int repeats) { + return new RepeatingIterable(iterable, repeats); + } + + /** + * A Helper function that repeats the Iterable a specific amount of times from a Java Iterable + * @param iterable that should be repeated + * @param repeats the amount of times the iterable should be repeated + * @return a repeating iterable + */ + public static IntIterable repeat(Iterable iterable, int repeats) { + return new RepeatingIterable(wrap(iterable), repeats); + } + + /** + * A Helper function that hard limits the Iterable to a specific size + * @param iterable that should be limited + * @param limit the amount of elements it should be limited to + * @return a limited iterable + */ + public static IntIterable limit(IntIterable iterable, long limit) { + return new LimitedIterable(iterable, limit); + } + + /** + * A Helper function that hard limits the Iterable to a specific size from a Java Iterable + * @param iterable that should be limited + * @param limit the amount of elements it should be limited to + * @return a limited iterable + */ + public static IntIterable limit(Iterable iterable, long limit) { + return new LimitedIterable(wrap(iterable), limit); + } + + /** + * A Helper function that sorts the Iterable. + * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. + * @param iterable that should be sorted + * @param sorter that sorts the iterable. Can be null. + * @return a sorted iterable. + */ + public static IntIterable sorted(IntIterable iterable, IntComparator sorter) { + return new SortedIterable(iterable, sorter); + } + + /** + * A Helper function that sorts the Iterable from a Java Iterable + * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. + * @param iterable that should be sorted + * @param sorter that sorts the iterable. Can be null. + * @return a sorted iterable. + */ + public static IntIterable sorted(Iterable iterable, IntComparator sorter) { + return new SortedIterable(wrap(iterable), sorter); + } + + /** + * A Helper function that allows to preview the result of a Iterable. + * @param iterable that should be peeked at + * @param action callback that receives the value before the iterable returns it + * @return a peeked iterable + */ + public static IntIterable peek(IntIterable iterable, IntConsumer action) { + return new PeekIterable(iterable, action); + } + + /** + * A Helper function that allows to preview the result of a Iterable from a Java Iterable + * @param iterable that should be peeked at + * @param action callback that receives the value before the iterable returns it + * @return a peeked iterable + */ + public static IntIterable peek(Iterable iterable, IntConsumer action) { + return new PeekIterable(wrap(iterable), action); + } + + /** + * A Wrapper function that wraps a Java-Iterable into a Type Specific Iterable + * @param iterable that should be wrapped + * @return a type specific iterable + */ + public static IntIterable wrap(Iterable iterable) { + return new WrappedIterable(iterable); + } + + private static class WrappedIterable implements IntIterable, ISizeProvider + { + Iterable iterable; + + public WrappedIterable(Iterable iterable) { + this.iterable = iterable; + } + + public IntIterator iterator() { + return IntIterators.wrap(iterable.iterator()); + } + + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : prov.size(); + } + + @Override + public void forEach(IntConsumer action) { + Objects.requireNonNull(action); + iterable.forEach(action); + } + } + + private static class MappedIterable implements ObjectIterable, ISizeProvider + { + IntIterable iterable; + IntFunction mapper; + + MappedIterable(IntIterable iterable, IntFunction mapper) { + this.iterable = iterable; + this.mapper = mapper; + } + + public ObjectIterator iterator() { + return IntIterators.map(iterable.iterator(), mapper); + } + + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(this); + return prov == null ? -1 : prov.size(); + } + + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + iterable.forEach(E -> action.accept(mapper.apply(E))); + } + } + + private static class FlatMappedIterable> implements ObjectIterable + { + IntIterable iterable; + IntFunction mapper; + + FlatMappedIterable(IntIterable iterable, IntFunction mapper) { + this.iterable = iterable; + this.mapper = mapper; + } + + @Override + public ObjectIterator iterator() { + return IntIterators.flatMap(iterable.iterator(), mapper); + } + + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + iterable.forEach(E -> mapper.apply(E).forEach(action)); + } + + } + + private static class FlatMappedArrayIterable implements ObjectIterable + { + IntIterable iterable; + IntFunction mapper; + + FlatMappedArrayIterable(IntIterable iterable, IntFunction mapper) { + this.iterable = iterable; + this.mapper = mapper; + } + + @Override + public ObjectIterator iterator() { + return IntIterators.arrayFlatMap(iterable.iterator(), mapper); + } + + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + iterable.forEach(E -> { + T[] array = mapper.apply(E); + for(int i = 0,m=array.length;i { if(!filter.test(T)) action.accept(T); } ); + } + } + + private static class LimitedIterable implements IntIterable, ISizeProvider + { + IntIterable iterable; + long limit; + + public LimitedIterable(IntIterable iterable, long limit) { + this.iterable = iterable; + this.limit = limit; + } + + @Override + public IntIterator iterator() { + return IntIterators.limit(iterable.iterator(), limit); + } + + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : (int)Math.min(prov.size(), limit); + } + + @Override + public void forEach(IntConsumer action) { + Objects.requireNonNull(action); + AtomicLong counter = new AtomicLong(); + iterable.forEach(T -> { + if(counter.get() >= limit) return; + counter.incrementAndGet(); + action.accept(T); + }); + } + } + + private static class SortedIterable implements IntIterable, ISizeProvider + { + IntIterable iterable; + IntComparator sorter; + + public SortedIterable(IntIterable iterable, IntComparator sorter) { + this.iterable = iterable; + this.sorter = sorter; + } + + @Override + public IntIterator iterator() { + return IntIterators.sorted(iterable.iterator(), sorter); + } + + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : prov.size(); + } + + @Override + public void forEach(IntConsumer action) { + Objects.requireNonNull(action); + IntCollections.CollectionWrapper wrapper = IntCollections.wrapper(); + iterable.forEach(wrapper::add); + wrapper.unstableSort(sorter); + wrapper.forEach(action); + } + } + + private static class DistinctIterable implements IntIterable + { + IntIterable iterable; + + public DistinctIterable(IntIterable iterable) { + this.iterable = iterable; + } + + @Override + public IntIterator iterator() { + return IntIterators.distinct(iterable.iterator()); + } + + @Override + public void forEach(IntConsumer action) { + Objects.requireNonNull(action); + IntCollection filtered = IntCollections.distinctWrapper(); + iterable.forEach(T -> { if(filtered.add(T)) action.accept(T); }); + } + } + + private static class PeekIterable implements IntIterable, ISizeProvider + { + IntIterable iterable; + IntConsumer action; + + public PeekIterable(IntIterable iterable, IntConsumer action) { + this.iterable = iterable; + this.action = action; + } + + @Override + public IntIterator iterator() { + return IntIterators.peek(iterable.iterator(), action); + } + + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : prov.size(); + } + + @Override + public void forEach(IntConsumer action) { + Objects.requireNonNull(action); + iterable.forEach(this.action.andThen(action)); + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IntIterators.java b/src/main/java/speiger/src/collections/ints/utils/IntIterators.java new file mode 100644 index 000000000..e0068176c --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/utils/IntIterators.java @@ -0,0 +1,1003 @@ +package speiger.src.collections.ints.utils; + +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.function.IntPredicate; + +import speiger.src.collections.ints.collections.IntIterator; +import speiger.src.collections.objects.collections.ObjectIterator; +import speiger.src.collections.objects.utils.ObjectIterators; +import speiger.src.collections.ints.functions.IntConsumer; +import speiger.src.collections.ints.functions.IntComparator; +import speiger.src.collections.ints.functions.function.IntFunction; +import speiger.src.collections.ints.lists.IntListIterator; +import speiger.src.collections.ints.collections.IntBidirectionalIterator; +import speiger.src.collections.ints.collections.IntCollection; + +/** + * A Helper class for Iterators + */ +public class IntIterators +{ + /** + * Empty Iterator Reference + */ + private static final EmptyIterator EMPTY = new EmptyIterator(); + + /** + * Returns a Immutable EmptyIterator instance that is automatically casted. + * @return an empty iterator + */ + public static EmptyIterator empty() { + return EMPTY; + } + + /** + * Inverter function for Bidirectional Iterators + * @param it the iterator that should be inverted + * @return a Inverted Bidirectional Iterator. If it was inverted then it just gives back the original reference + */ + public static IntBidirectionalIterator invert(IntBidirectionalIterator it) { + return it instanceof ReverseBiIterator ? ((ReverseBiIterator)it).it : new ReverseBiIterator(it); + } + + /** + * Inverter function for List Iterators + * @param it the iterator that should be inverted + * @return a Inverted List Iterator. If it was inverted then it just gives back the original reference + */ + public static IntListIterator invert(IntListIterator it) { + return it instanceof ReverseListIterator ? ((ReverseListIterator)it).it : new ReverseListIterator(it); + } + + /** + * Returns a Immutable Iterator instance based on the instance given. + * @param iterator that should be made immutable/unmodifiable + * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself. + */ + public static IntIterator unmodifiable(IntIterator iterator) { + return iterator instanceof UnmodifiableIterator ? iterator : new UnmodifiableIterator(iterator); + } + + /** + * Returns a Immutable Iterator instance based on the instance given. + * @param iterator that should be made immutable/unmodifiable + * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself. + */ + public static IntBidirectionalIterator unmodifiable(IntBidirectionalIterator iterator) { + return iterator instanceof UnmodifiableBiIterator ? iterator : new UnmodifiableBiIterator(iterator); + } + + /** + * Returns a Immutable ListIterator instance based on the instance given. + * @param iterator that should be made immutable/unmodifiable + * @return a unmodifiable listiterator wrapper. If the ListIterator already a unmodifiable wrapper then it just returns itself. + */ + public static IntListIterator unmodifiable(IntListIterator iterator) { + return iterator instanceof UnmodifiableListIterator ? iterator : new UnmodifiableListIterator(iterator); + } + + /** + * A Helper function that maps a Java-Iterator into a new Type. + * @param iterator that should be mapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterator that is mapped to a new result + */ + public static ObjectIterator map(Iterator iterator, IntFunction mapper) { + return new MappedIterator<>(wrap(iterator), mapper); + } + + /** + * A Helper function that maps a Iterator into a new Type. + * @param iterator that should be mapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterator that is mapped to a new result + */ + public static ObjectIterator map(IntIterator iterator, IntFunction mapper) { + return new MappedIterator<>(iterator, mapper); + } + + /** + * A Helper function that flatMaps a Java-Iterator into a new Type. + * @param iterator that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type supplier. + * @param The return type. + * @return a iterator that is flatMapped to a new result + */ + public static > ObjectIterator flatMap(Iterator iterator, IntFunction mapper) { + return new FlatMappedIterator<>(wrap(iterator), mapper); + } + + /** + * A Helper function that flatMaps a Iterator into a new Type. + * @param iterator that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type supplier. + * @param The return type. + * @return a iterator that is flatMapped to a new result + */ + public static > ObjectIterator flatMap(IntIterator iterator, IntFunction mapper) { + return new FlatMappedIterator<>(iterator, mapper); + } + + /** + * A Helper function that flatMaps a Java-Iterator into a new Type. + * @param iterator that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterator that is flatMapped to a new result + */ + public static ObjectIterator arrayFlatMap(Iterator iterator, IntFunction mapper) { + return new FlatMappedArrayIterator<>(wrap(iterator), mapper); + } + + /** + * A Helper function that flatMaps a Iterator into a new Type. + * @param iterator that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterator that is flatMapped to a new result + */ + public static ObjectIterator arrayFlatMap(IntIterator iterator, IntFunction mapper) { + return new FlatMappedArrayIterator<>(iterator, mapper); + } + + /** + * A Helper function that filters out all desired elements from a Java-Iterator + * @param iterator that should be filtered. + * @param filter the filter that decides that should be let through + * @return a filtered iterator + */ + public static IntIterator filter(Iterator iterator, IntPredicate filter) { + return new FilteredIterator(wrap(iterator), filter); + } + + /** + * A Helper function that filters out all desired elements + * @param iterator that should be filtered. + * @param filter the filter that decides that should be let through + * @return a filtered iterator + */ + public static IntIterator filter(IntIterator iterator, IntPredicate filter) { + return new FilteredIterator(iterator, filter); + } + + /** + * A Helper function that filters out all duplicated elements. + * @param iterator that should be distinct + * @return a distinct iterator + */ + public static IntIterator distinct(IntIterator iterator) { + return new DistinctIterator(iterator); + } + + /** + * A Helper function that filters out all duplicated elements from a Java Iterator. + * @param iterator that should be distinct + * @return a distinct iterator + */ + public static IntIterator distinct(Iterator iterator) { + return new DistinctIterator(wrap(iterator)); + } + + /** + * A Helper function that repeats the Iterator a specific amount of times + * @param iterator that should be repeated + * @param repeats the amount of times the iterator should be repeated + * @return a repeating iterator + */ + public static IntIterator repeat(IntIterator iterator, int repeats) { + return new RepeatingIterator(iterator, repeats); + } + + /** + * A Helper function that repeats the Iterator a specific amount of times from a Java Iterator + * @param iterator that should be repeated + * @param repeats the amount of times the iterator should be repeated + * @return a repeating iterator + */ + public static IntIterator repeat(Iterator iterator, int repeats) { + return new RepeatingIterator(wrap(iterator), repeats); + } + + /** + * A Helper function that hard limits the Iterator to a specific size + * @param iterator that should be limited + * @param limit the amount of elements it should be limited to + * @return a limited iterator + */ + public static IntIterator limit(IntIterator iterator, long limit) { + return new LimitedIterator(iterator, limit); + } + + /** + * A Helper function that hard limits the Iterator to a specific size from a Java Iterator + * @param iterator that should be limited + * @param limit the amount of elements it should be limited to + * @return a limited iterator + */ + public static IntIterator limit(Iterator iterator, long limit) { + return new LimitedIterator(wrap(iterator), limit); + } + + /** + * A Helper function that sorts the Iterator beforehand. + * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. + * @param iterator that should be sorted. + * @param sorter the sorter of the iterator. Can be null. + * @return a new sorted iterator + */ + public static IntIterator sorted(IntIterator iterator, IntComparator sorter) { + return new SortedIterator(iterator, sorter); + } + + /** + * A Helper function that sorts the Iterator beforehand from a Java Iterator. + * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. + * @param iterator that should be sorted. + * @param sorter the sorter of the iterator. Can be null. + * @return a new sorted iterator + */ + public static IntIterator sorted(Iterator iterator, IntComparator sorter) { + return new SortedIterator(wrap(iterator), sorter); + } + + /** + * A Helper function that allows to preview the result of a Iterator. + * @param iterator that should be peeked at + * @param action callback that receives the value before the iterator returns it + * @return a peeked iterator + */ + public static IntIterator peek(IntIterator iterator, IntConsumer action) { + return new PeekIterator(iterator, action); + } + + /** + * A Helper function that allows to preview the result of a Iterator from a Java Iterator + * @param iterator that should be peeked at + * @param action callback that receives the value before the iterator returns it + * @return a peeked iterator + */ + public static IntIterator peek(Iterator iterator, IntConsumer action) { + return new PeekIterator(wrap(iterator), action); + } + + /** + * Helper function to convert a Object Iterator into a Primitive Iterator + * @param iterator that should be converted to a unboxing iterator + * @return a primitive iterator + */ + public static IntIterator wrap(Iterator iterator) { + return iterator instanceof IntIterator ? (IntIterator)iterator : new IteratorWrapper(iterator); + } + + /** + * Returns a Array Wrapping iterator + * @param a the array that should be wrapped + * @return a Iterator that is wrapping a array. + */ + public static ArrayIterator wrap(int... a) { + return wrap(a, 0, a.length); + } + + /** + * Returns a Array Wrapping iterator + * @param a the array that should be wrapped. + * @param start the index to be started from. + * @param end the index that should be ended. + * @return a Iterator that is wrapping a array. + */ + public static ArrayIterator wrap(int[] a, int start, int end) { + return new ArrayIterator(a, start, end); + } + + /** + * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted + * @param a where the elements should be inserted + * @param i the source iterator + * @return the amount of elements that were inserted into the array. + */ + public static int unwrap(int[] a, Iterator i) { + return unwrap(a, i, 0, a.length); + } + + /** + * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted + * @param a where the elements should be inserted + * @param i the source iterator + * @param offset the array offset where the start should be + * @return the amount of elements that were inserted into the array. + */ + public static int unwrap(int[] a, Iterator i, int offset) { + return unwrap(a, i, offset, a.length - offset); + } + + /** + * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted + * @param a where the elements should be inserted + * @param i the source iterator + * @param offset the array offset where the start should be + * @param max the maximum values that should be extracted from the source + * @return the amount of elements that were inserted into the array. + * @throws IllegalStateException if max is smaller the 0 or if the maximum index is larger then the array + */ + public static int unwrap(int[] a, Iterator i, int offset, int max) { + if(max < 0) throw new IllegalStateException("The max size is smaller then 0"); + if(offset + max > a.length) throw new IllegalStateException("largest array index exceeds array size"); + int index = 0; + for(;index a.length) throw new IllegalStateException("largest array index exceeds array size"); + int index = 0; + for(;index a.length) throw new IllegalStateException("largest array index exceeds array size"); + int index = 0; + for(;index iter; + + public IteratorWrapper(Iterator iter) { + this.iter = iter; + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public int nextInt() { + return iter.next().intValue(); + } + + @Override + @Deprecated + public Integer next() { + return iter.next(); + } + } + + private static class ConcatIterator implements IntIterator + { + IntIterator[] iters; + int offset; + int lastOffset = -1; + int length; + + public ConcatIterator(IntIterator[] iters, int offset, int length) { + this.iters = iters; + this.offset = offset; + this.length = length; + find(); + } + + private void find() { + for(;length != 0 && !iters[offset].hasNext();length--, offset++); + } + + @Override + public boolean hasNext() { + return length > 0; + } + + @Override + public int nextInt() { + if(!hasNext()) throw new NoSuchElementException(); + int result = iters[lastOffset = offset].nextInt(); + find(); + return result; + } + + @Override + public void remove() { + if(lastOffset == -1) throw new IllegalStateException(); + iters[lastOffset].remove(); + lastOffset = -1; + } + } + + private static class ReverseBiIterator implements IntBidirectionalIterator { + IntBidirectionalIterator it; + + ReverseBiIterator(IntBidirectionalIterator it) { + this.it = it; + } + + @Override + public int nextInt() { return it.previousInt(); } + @Override + public boolean hasNext() { return it.hasPrevious(); } + @Override + public boolean hasPrevious() { return it.hasNext(); } + @Override + public int previousInt() { return it.nextInt(); } + @Override + public void remove() { it.remove(); } + } + + private static class ReverseListIterator implements IntListIterator { + IntListIterator it; + + ReverseListIterator(IntListIterator it) { + this.it = it; + } + + @Override + public int nextInt() { return it.previousInt(); } + @Override + public boolean hasNext() { return it.hasPrevious(); } + @Override + public boolean hasPrevious() { return it.hasNext(); } + @Override + public int previousInt() { return it.nextInt(); } + @Override + public void remove() { it.remove(); } + @Override + public int nextIndex() { return it.previousIndex(); } + @Override + public int previousIndex() { return it.nextIndex(); } + @Override + public void set(int e) { it.set(e); } + @Override + public void add(int e) { it.add(e); } + } + + private static class UnmodifiableListIterator implements IntListIterator + { + IntListIterator iter; + + UnmodifiableListIterator(IntListIterator iter) { + this.iter = iter; + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public boolean hasPrevious() { + return iter.hasPrevious(); + } + + @Override + public int nextIndex() { + return iter.nextIndex(); + } + + @Override + public int previousIndex() { + return iter.previousIndex(); + } + + @Override + public void remove() { throw new UnsupportedOperationException(); } + + @Override + public int previousInt() { + return iter.previousInt(); + } + + @Override + public int nextInt() { + return iter.nextInt(); + } + + @Override + public void set(int e) { throw new UnsupportedOperationException(); } + + @Override + public void add(int e) { throw new UnsupportedOperationException(); } + } + + private static class UnmodifiableBiIterator implements IntBidirectionalIterator + { + IntBidirectionalIterator iter; + + UnmodifiableBiIterator(IntBidirectionalIterator iter) { + this.iter = iter; + } + + @Override + public int nextInt() { + return iter.nextInt(); + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public boolean hasPrevious() { + return iter.hasPrevious(); + } + + @Override + public int previousInt() { + return iter.previousInt(); + } + } + + private static class UnmodifiableIterator implements IntIterator + { + IntIterator iterator; + + UnmodifiableIterator(IntIterator iterator) { + this.iterator = iterator; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public int nextInt() { + return iterator.nextInt(); + } + } + + private static class EmptyIterator implements IntListIterator + { + @Override + public boolean hasNext() { return false; } + @Override + public int nextInt() { throw new NoSuchElementException(); } + @Override + public boolean hasPrevious() { return false; } + @Override + public int previousInt() { throw new NoSuchElementException(); } + @Override + public int nextIndex() { return 0; } + @Override + public int previousIndex() { return -1; } + @Override + public void remove() { throw new UnsupportedOperationException(); } + @Override + public void set(int e) { throw new UnsupportedOperationException(); } + @Override + public void add(int e) { throw new UnsupportedOperationException(); } + } + + private static class ArrayIterator implements IntIterator + { + int[] a; + int from; + int to; + + ArrayIterator(int[] a, int from, int to) { + this.a = a; + this.from = from; + this.to = to; + } + + @Override + public boolean hasNext() { + return from < to; + } + + @Override + public int nextInt() { + if(!hasNext()) throw new NoSuchElementException(); + return a[from++]; + } + + @Override + public int skip(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int left = Math.min(amount, to - from); + from += left; + return amount - left; + } + } + + private static class MappedIterator implements ObjectIterator + { + IntIterator iterator; + IntFunction mapper; + + MappedIterator(IntIterator iterator, IntFunction mapper) { + this.iterator = iterator; + this.mapper = mapper; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public T next() { + return mapper.apply(iterator.nextInt()); + } + + @Override + public int skip(int amount) { + return iterator.skip(amount); + } + } + + private static class FlatMappedIterator> implements ObjectIterator + { + IntIterator iterator; + Iterator last = null; + IntFunction mapper; + boolean foundNext = false; + + FlatMappedIterator(IntIterator iterator, IntFunction mapper) { + this.iterator = iterator; + this.mapper = mapper; + } + + void compute() { + if(foundNext) return; + foundNext = true; + while(iterator.hasNext()) { + if(last != null && last.hasNext()) return; + last = mapper.apply(iterator.nextInt()).iterator(); + } + } + + @Override + public boolean hasNext() { + compute(); + return last != null && last.hasNext(); + } + + @Override + public T next() { + if(!hasNext()) throw new NoSuchElementException(); + T result = last.next(); + foundNext = false; + return result; + } + } + + private static class FlatMappedArrayIterator implements ObjectIterator + { + IntIterator iterator; + Iterator last = null; + IntFunction mapper; + boolean foundNext = false; + + FlatMappedArrayIterator(IntIterator iterator, IntFunction mapper) { + this.iterator = iterator; + this.mapper = mapper; + } + + void compute() { + if(foundNext) return; + foundNext = true; + while(iterator.hasNext()) { + if(last != null && last.hasNext()) return; + last = ObjectIterators.wrap(mapper.apply(iterator.nextInt())); + } + } + + @Override + public boolean hasNext() { + compute(); + return last != null && last.hasNext(); + } + + @Override + public T next() { + if(!hasNext()) throw new NoSuchElementException(); + T result = last.next(); + foundNext = false; + return result; + } + } + + private static class RepeatingIterator implements IntIterator + { + final int repeats; + int index = 0; + IntIterator iter; + IntCollection repeater = IntCollections.wrapper(); + + public RepeatingIterator(IntIterator iter, int repeat) { + this.iter = iter; + this.repeats = repeat; + } + + @Override + public boolean hasNext() { + if(iter.hasNext()) return true; + if(index < repeats) { + index++; + iter = repeater.iterator(); + return iter.hasNext(); + } + return false; + } + + @Override + public int nextInt() { + if(!hasNext()) throw new NoSuchElementException(); + int value = iter.nextInt(); + if(index == 0) repeater.add(value); + return value; + } + } + + private static class SortedIterator implements IntIterator + { + IntIterator iterator; + IntComparator sorter; + IntCollections.CollectionWrapper sortedElements = null; + int index = 0; + + public SortedIterator(IntIterator iterator, IntComparator sorter) { + this.iterator = iterator; + this.sorter = sorter; + } + + @Override + public boolean hasNext() { + if(sortedElements == null) { + boolean hasNext = iterator.hasNext(); + if(hasNext) { + sortedElements = IntCollections.wrapper(); + pour(iterator, sortedElements); + } + else sortedElements = IntCollections.wrapper(); + if(hasNext) sortedElements.unstableSort(sorter); + } + return index < sortedElements.size(); + } + + @Override + public int nextInt() { + if(!hasNext()) throw new NoSuchElementException(); + return sortedElements.getInt(index++); + } + } + + private static class DistinctIterator implements IntIterator + { + IntIterator iterator; + IntCollection filtered = IntCollections.distinctWrapper(); + int lastFound; + boolean foundNext = false; + + public DistinctIterator(IntIterator iterator) { + this.iterator = iterator; + } + + void compute() { + if(foundNext) return; + while(iterator.hasNext()) { + lastFound = iterator.nextInt(); + if(filtered.add(lastFound)) { + foundNext = true; + break; + } + } + } + + @Override + public boolean hasNext() { + compute(); + return foundNext; + } + + @Override + public int nextInt() { + if(!hasNext()) throw new NoSuchElementException(); + foundNext = false; + return lastFound; + } + } + + private static class FilteredIterator implements IntIterator + { + IntIterator iterator; + IntPredicate filter; + int lastFound; + boolean foundNext = false; + + public FilteredIterator(IntIterator iterator, IntPredicate filter) { + this.iterator = iterator; + this.filter = filter; + } + + void compute() { + if(foundNext) return; + while(iterator.hasNext()) { + lastFound = iterator.nextInt(); + if(filter.test(lastFound)) { + foundNext = true; + break; + } + } + } + + @Override + public boolean hasNext() { + compute(); + return foundNext; + } + + @Override + public int nextInt() { + if(!hasNext()) throw new NoSuchElementException(); + foundNext = false; + return lastFound; + } + } + + private static class LimitedIterator implements IntIterator + { + IntIterator iterator; + long limit; + + public LimitedIterator(IntIterator iterator, long limit) { + this.iterator = iterator; + this.limit = limit; + } + + @Override + public boolean hasNext() { + return limit > 0 && iterator.hasNext(); + } + + @Override + public int nextInt() { + if(!hasNext()) throw new NoSuchElementException(); + limit--; + return iterator.nextInt(); + } + } + + private static class PeekIterator implements IntIterator + { + IntIterator iterator; + IntConsumer action; + + public PeekIterator(IntIterator iterator, IntConsumer action) { + this.iterator = iterator; + this.action = action; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public int nextInt() { + if(!hasNext()) throw new NoSuchElementException(); + int result = iterator.nextInt(); + action.accept(result); + return result; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IntSplititerators.java b/src/main/java/speiger/src/collections/ints/utils/IntSplititerators.java new file mode 100644 index 000000000..a1571f64f --- /dev/null +++ b/src/main/java/speiger/src/collections/ints/utils/IntSplititerators.java @@ -0,0 +1,461 @@ +package speiger.src.collections.ints.utils; + +import java.util.Comparator; +import java.util.NoSuchElementException; +import java.util.Spliterator; +import java.util.Spliterator.OfInt; +import java.util.function.Consumer; + +import speiger.src.collections.ints.collections.IntCollection; +import speiger.src.collections.ints.collections.IntIterator; +import speiger.src.collections.ints.collections.IntSplititerator; +import speiger.src.collections.ints.functions.IntConsumer; +import speiger.src.collections.utils.SanityChecks; + +/** + * Helper class that provides SplitIterators for normal and stream usage + */ +public class IntSplititerators +{ + /** + * Creates A stream compatible split iterator without copying the original array or boxing + * @param array that should be wrapped into a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + */ + public static OfInt createArrayJavaSplititerator(int[] array, int characteristics) { return createArrayJavaSplititerator(array, 0, array.length, characteristics);} + /** + * Creates A stream compatible split iterator without copying the original array or boxing + * @param array that should be wrapped into a split iterator + * @param size the maximum index within the array + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + * @throws IllegalStateException if the size is outside of the array size + */ + public static OfInt createArrayJavaSplititerator(int[] array, int size, int characteristics) { return createArrayJavaSplititerator(array, 0, size, characteristics);} + /** + * Creates A stream compatible split iterator without copying the original array or boxing + * @param array that should be wrapped into a split iterator + * @param offset the starting index of the array + * @param size the maximum index within the array + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + * @throws IllegalStateException the offset and size are outside of the arrays range + */ + public static OfInt createArrayJavaSplititerator(int[] array, int offset, int size, int characteristics) { + SanityChecks.checkArrayCapacity(array.length, offset, size); + return new ArraySplitIterator(array, offset, size, characteristics); + } + + /** + * Creates a stream compatible split iterator without copying it or boxing it + * @param collection the collection that should be wrapped in a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + */ + public static OfInt createJavaSplititerator(IntCollection collection, int characteristics) { + return new IteratorSpliterator(collection, characteristics); + } + + /** + * Creates a stream compatible split iterator without copying it or boxing it + * @param iterator the Iterator that should be wrapped in a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + */ + public static OfInt createUnknownJavaSplititerator(IntIterator iterator, int characteristics) { + return new IteratorSpliterator(iterator, characteristics); + } + + /** + * Creates a stream compatible split iterator without copying it or boxing it + * @param iterator the collection that should be wrapped in a split iterator + * @param size the amount of elements in the iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + */ + public static OfInt createSizedJavaSplititerator(IntIterator iterator, long size, int characteristics) { + return new IteratorSpliterator(iterator, size, characteristics); + } + + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param array that should be wrapped into a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + */ + public static IntSplititerator createArraySplititerator(int[] array, int characteristics) { return createArraySplititerator(array, 0, array.length, characteristics);} + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param array that should be wrapped into a split iterator + * @param size the maximum index within the array + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + * @throws IllegalStateException if the size is outside of the array size + */ + public static IntSplititerator createArraySplititerator(int[] array, int size, int characteristics) { return createArraySplititerator(array, 0, size, characteristics);} + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param array that should be wrapped into a split iterator + * @param offset the starting index of the array + * @param size the maximum index within the array + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + * @throws IllegalStateException the offset and size are outside of the arrays range + */ + public static IntSplititerator createArraySplititerator(int[] array, int offset, int size, int characteristics) { + SanityChecks.checkArrayCapacity(array.length, offset, size); + return new TypeArraySplitIterator(array, offset, size, characteristics); + } + + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param collection the collection that should be wrapped in a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + */ + public static IntSplititerator createSplititerator(IntCollection collection, int characteristics) { + return new TypeIteratorSpliterator(collection, characteristics); + } + + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param iterator the Iterator that should be wrapped in a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + */ + public static IntSplititerator createUnknownSplititerator(IntIterator iterator, int characteristics) { + return new TypeIteratorSpliterator(iterator, characteristics); + } + + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param iterator the collection that should be wrapped in a split iterator + * @param size the amount of elements in the iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + */ + public static IntSplititerator createSizedSplititerator(IntIterator iterator, long size, int characteristics) { + return new TypeIteratorSpliterator(iterator, size, characteristics); + } + + static class TypeIteratorSpliterator implements IntSplititerator { + static final int BATCH_UNIT = 1 << 10; + static final int MAX_BATCH = 1 << 25; + private final IntCollection collection; + private IntIterator it; + private final int characteristics; + private long est; + private int batch; + + TypeIteratorSpliterator(IntCollection collection, int characteristics) { + this.collection = collection; + it = null; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; + } + + TypeIteratorSpliterator(IntIterator iterator, long size, int characteristics) { + collection = null; + it = iterator; + est = size; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; + } + + TypeIteratorSpliterator(IntIterator iterator, int characteristics) { + collection = null; + it = iterator; + est = Long.MAX_VALUE; + this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); + } + + private IntIterator iterator() + { + if (it == null) { + it = collection.iterator(); + est = collection.size(); + } + return it; + } + + @Override + public IntSplititerator trySplit() { + IntIterator i = iterator(); + if (est > 1 && i.hasNext()) { + int n = Math.min(batch + BATCH_UNIT, Math.min((int)est, MAX_BATCH)); + int[] a = new int[n]; + int j = 0; + do { a[j] = i.nextInt(); } while (++j < n && i.hasNext()); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new TypeArraySplitIterator(a, 0, j, characteristics); + } + return null; + } + + @Override + public void forEachRemaining(IntConsumer action) { + if (action == null) throw new NullPointerException(); + iterator().forEachRemaining(action); + } + + @Override + public boolean tryAdvance(IntConsumer action) { + if (action == null) throw new NullPointerException(); + IntIterator iter = iterator(); + if (iter.hasNext()) { + action.accept(iter.nextInt()); + return true; + } + return false; + } + + @Override + public boolean tryAdvance(Consumer action) { + if (action == null) throw new NullPointerException(); + IntIterator iter = iterator(); + if (iter.hasNext()) { + action.accept(Integer.valueOf(iter.nextInt())); + return true; + } + return false; + } + + @Override + public long estimateSize() { + iterator(); + return est; + } + + @Override + public int characteristics() { return characteristics; } + + @Override + public Comparator getComparator() { + if (hasCharacteristics(4)) //Sorted + return null; + throw new IllegalStateException(); + } + + @Override + public int nextInt() { return iterator().nextInt(); } + + @Override + public boolean hasNext() { return iterator().hasNext(); } + } + + static final class TypeArraySplitIterator implements IntSplititerator { + private final int[] array; + private int index; + private final int fence; + private final int characteristics; + + public TypeArraySplitIterator(int[] array, int origin, int fence, int additionalCharacteristics) { + this.array = array; + index = origin; + this.fence = fence; + characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + @Override + public IntSplititerator trySplit() { + int lo = index, mid = (lo + fence) >>> 1; + return (lo >= mid) ? null : new TypeArraySplitIterator(array, lo, index = mid, characteristics); + } + + @Override + public void forEachRemaining(IntConsumer action) { + if (action == null) throw new NullPointerException(); + int[] a; int i, hi; + if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) { + do { action.accept(a[i]); } while (++i < hi); + } + } + + @Override + public boolean tryAdvance(IntConsumer action) { + if (action == null) throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(array[index++]); + return true; + } + return false; + } + + @Override + public boolean tryAdvance(Consumer action) { + if (action == null) throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(Integer.valueOf(array[index++])); + return true; + } + return false; + } + + @Override + public long estimateSize() { return fence - index; } + @Override + public int characteristics() { return characteristics; } + @Override + public Comparator getComparator() { + if (hasCharacteristics(4)) //Sorted + return null; + throw new IllegalStateException(); + } + + @Override + public int nextInt() { + if(!hasNext()) throw new NoSuchElementException(); + return array[index++]; + } + + @Override + public boolean hasNext() { return index < fence; } + } + + static class IteratorSpliterator implements OfInt { + static final int BATCH_UNIT = 1 << 10; + static final int MAX_BATCH = 1 << 25; + private final IntCollection collection; + private IntIterator it; + private final int characteristics; + private long est; + private int batch; + + IteratorSpliterator(IntCollection collection, int characteristics) { + this.collection = collection; + it = null; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; + } + + IteratorSpliterator(IntIterator iterator, long size, int characteristics) { + collection = null; + it = iterator; + est = size; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; + } + + IteratorSpliterator(IntIterator iterator, int characteristics) { + collection = null; + it = iterator; + est = Long.MAX_VALUE; + this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); + } + + private IntIterator iterator() + { + if (it == null) { + it = collection.iterator(); + est = collection.size(); + } + return it; + } + + @Override + public OfInt trySplit() { + IntIterator i = iterator(); + if (est > 1 && i.hasNext()) { + int n = Math.min(batch + BATCH_UNIT, Math.min((int)est, MAX_BATCH)); + int[] a = new int[n]; + int j = 0; + do { a[j] = i.nextInt(); } while (++j < n && i.hasNext()); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new ArraySplitIterator(a, 0, j, characteristics); + } + return null; + } + + @Override + public void forEachRemaining(java.util.function.IntConsumer action) { + if (action == null) throw new NullPointerException(); + iterator().forEachRemaining(T -> action.accept(T)); + } + + @Override + public boolean tryAdvance(java.util.function.IntConsumer action) { + if (action == null) throw new NullPointerException(); + IntIterator iter = iterator(); + if (iter.hasNext()) { + action.accept(iter.nextInt()); + return true; + } + return false; + } + + @Override + public long estimateSize() { + iterator(); + return est; + } + + @Override + public int characteristics() { return characteristics; } + + @Override + public Comparator getComparator() { + if (hasCharacteristics(4)) //Sorted + return null; + throw new IllegalStateException(); + } + } + + static final class ArraySplitIterator implements OfInt { + private final int[] array; + private int index; + private final int fence; + private final int characteristics; + + public ArraySplitIterator(int[] array, int origin, int fence, int additionalCharacteristics) { + this.array = array; + index = origin; + this.fence = fence; + characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + @Override + public OfInt trySplit() { + int lo = index, mid = (lo + fence) >>> 1; + return (lo >= mid) ? null : new ArraySplitIterator(array, lo, index = mid, characteristics); + } + + @Override + public void forEachRemaining(java.util.function.IntConsumer action) { + if (action == null) throw new NullPointerException(); + int[] a; int i, hi; + if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) { + do { action.accept(a[i]); } while (++i < hi); + } + } + + @Override + public boolean tryAdvance(java.util.function.IntConsumer action) { + if (action == null) throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(array[index++]); + return true; + } + return false; + } + + @Override + public long estimateSize() { return fence - index; } + @Override + public int characteristics() { return characteristics; } + @Override + public Comparator getComparator() { + if (hasCharacteristics(4)) //Sorted + return null; + throw new IllegalStateException(); + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/collections/AbstractLongCollection.java b/src/main/java/speiger/src/collections/longs/collections/AbstractLongCollection.java new file mode 100644 index 000000000..88abe106a --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/collections/AbstractLongCollection.java @@ -0,0 +1,252 @@ +package speiger.src.collections.longs.collections; + +import java.util.Collection; +import java.util.Objects; +import java.util.AbstractCollection; + +import speiger.src.collections.longs.functions.LongConsumer; +import speiger.src.collections.longs.utils.LongIterators; +import speiger.src.collections.longs.utils.LongArrays; + +/** + * Abstract Type Specific Collection that reduces boxing/unboxing + */ +public abstract class AbstractLongCollection extends AbstractCollection implements LongCollection +{ + @Override + public abstract LongIterator iterator(); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public boolean add(Long e) { return LongCollection.super.add(e); } + + @Override + public boolean addAll(LongCollection c) { + boolean modified = false; + for(LongIterator iter = c.iterator();iter.hasNext();modified |= add(iter.nextLong())); + return modified; + } + + @Override + public LongCollection copy() { throw new UnsupportedOperationException(); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public boolean contains(Object e) { return LongCollection.super.contains(e); } + + /** + * A Type-Specific implementation of contains. This implementation iterates over the elements and returns true if the value match. + * @param e the element that should be searched for. + * @return true if the value was found. + */ + @Override + public boolean contains(long e) { + for(LongIterator iter = iterator();iter.hasNext();) { if(iter.nextLong() == e) return true; } + return false; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public boolean addAll(Collection c) + { + return c instanceof LongCollection ? addAll((LongCollection)c) : super.addAll(c); + } + + /** + * A Type-Specific implementation of containsAll. This implementation iterates over all elements and checks all elements are present in the other collection. + * @param c the collection that should be checked if it contains all elements. + * @return true if all elements were found in the collection + * @throws NullPointerException if the collection is null + */ + @Override + public boolean containsAll(LongCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return true; + for(LongIterator iter = c.iterator();iter.hasNext();) + if(!contains(iter.nextLong())) + return false; + return true; + } + + @Override + public boolean containsAll(Collection c) { + Objects.requireNonNull(c); + return c instanceof LongCollection ? containsAll((LongCollection)c) : super.containsAll(c); + } + + /** + * This implementation iterates over the elements of the collection and checks if they are stored in this collection + * @param c the elements that should be checked for + * @return true if any element is in this collection + * @throws NullPointerException if the collection is null + */ + @Override + @Deprecated + public boolean containsAny(Collection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + for(Object e : c) + if(contains(e)) + return true; + return false; + } + + /** + * This implementation iterates over the elements of the collection and checks if they are stored in this collection. + * @param c the elements that should be checked for + * @return true if any element is in this collection + * @throws NullPointerException if the collection is null + */ + @Override + public boolean containsAny(LongCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + for(LongIterator iter = c.iterator();iter.hasNext();) + if(contains(iter.nextLong())) + return true; + return false; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public boolean remove(Object e) { return LongCollection.super.remove(e); } + + /** + * A Type-Specific implementation of remove. This implementation iterates over the elements until it finds the element that is searched for or it runs out of elements. + * It stops after finding the first element + * @param e the element that is searched for + * @return true if the element was found and removed. + */ + @Override + public boolean remLong(long e) { + for(LongIterator iter = iterator();iter.hasNext();) { + if(iter.nextLong() == e) { + iter.remove(); + return true; + } + } + return false; + } + + /** + * A Type-Specific implementation of removeAll. This Implementation iterates over all elements and removes them as they were found in the other collection. + * @param c the elements that should be deleted + * @return true if the collection was modified. + * @throws NullPointerException if the collection is null + */ + @Override + public boolean removeAll(LongCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + boolean modified = false; + for(LongIterator iter = iterator();iter.hasNext();) { + if(c.contains(iter.nextLong())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + @Override + public boolean removeAll(LongCollection c, LongConsumer r) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + Objects.requireNonNull(r); + boolean modified = false; + for(LongIterator iter = iterator();iter.hasNext();) { + long e = iter.nextLong(); + if(c.contains(e)) { + r.accept(e); + iter.remove(); + modified = true; + } + } + return modified; + } + + /** + * A Type-Specific implementation of retainAll. This Implementation iterates over all elements and removes them as they were not found in the other collection. + * @param c the elements that should be kept + * @return true if the collection was modified. + * @throws NullPointerException if the collection is null + */ + @Override + public boolean retainAll(LongCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) { + boolean modified = !isEmpty(); + clear(); + return modified; + } + boolean modified = false; + for(LongIterator iter = iterator();iter.hasNext();) { + if(!c.contains(iter.nextLong())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + @Override + public boolean retainAll(LongCollection c, LongConsumer r) { + Objects.requireNonNull(c); + Objects.requireNonNull(r); + if(c.isEmpty()) { + boolean modified = !isEmpty(); + forEach(r); + clear(); + return modified; + } + boolean modified = false; + for(LongIterator iter = iterator();iter.hasNext();) { + long e = iter.nextLong(); + if(!c.contains(e)) { + r.accept(e); + iter.remove(); + modified = true; + } + } + return modified; + } + + /** + * A Type-Specific implementation of toArray that links to {@link #toLongArray(long[])} with a newly created array. + * @return an array containing all of the elements in this collection + */ + @Override + public long[] toLongArray() { + if(isEmpty()) return LongArrays.EMPTY_ARRAY; + return toLongArray(new long[size()]); + } + + /** + * A Type-Specific implementation of toArray. This implementation iterates over all elements and unwraps them into primitive type. + * @param a array that the elements should be injected to. If null or to small a new array with the right size is created + * @return an array containing all of the elements in this collection + */ + @Override + public long[] toLongArray(long[] a) { + if(a == null || a.length < size()) a = new long[size()]; + LongIterators.unwrap(a, iterator()); + if (a.length > size()) a[size()] = 0L; + return a; + } +} diff --git a/src/main/java/speiger/src/collections/longs/collections/LongBidirectionalIterator.java b/src/main/java/speiger/src/collections/longs/collections/LongBidirectionalIterator.java new file mode 100644 index 000000000..e9d759f2c --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/collections/LongBidirectionalIterator.java @@ -0,0 +1,52 @@ +package speiger.src.collections.longs.collections; + +import speiger.src.collections.objects.collections.ObjectBidirectionalIterator; +/** + * A Type-Specific {@link ObjectBidirectionalIterator} to reduce (un)boxing + */ +public interface LongBidirectionalIterator extends LongIterator, ObjectBidirectionalIterator +{ + /** + * Returns true if the Iterator has a Previous element + * @return true if the Iterator has a Previous element + */ + public boolean hasPrevious(); + + /** + * Returns the Previous element of the iterator. + * @return the Previous element of the iterator. + * @throws java.util.NoSuchElementException if the iteration has no more elements + */ + public long previousLong(); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default Long previous() { + return Long.valueOf(previousLong()); + } + + /** + * {@inheritDoc} + */ + @Override + default int skip(int amount) + { + return LongIterator.super.skip(amount); + } + + /** + * Reverses the Given amount of elements if possible. A Optimization function to reverse elements faster if the implementation allows it. + * @param amount the amount of elements that should be reversed + * @return the amount of elements that were reversed + */ + public default int back(int amount) { + if(amount < 0) throw new IllegalStateException("Can't go forward"); + int i = 0; + for(;i, LongIterable, ISizeProvider +{ + /** + * A Type-Specific add function to reduce (un)boxing + * @param o the element that should be added + * @return true if the element was added to the collection + */ + public boolean add(long o); + + /** + * A Type-Specific addAll function to reduce (un)boxing + * @param c the collection of elements that should be added + * @return true if elements were added into the collection + */ + public boolean addAll(LongCollection c); + + /** + * A Type-Specific Array based addAll method to reduce the amount of Wrapping + * @param e the elements that should be added + * @return if the collection was modified + */ + public default boolean addAll(long... e) { return addAll(e, 0, e.length); } + + /** + * A Type-Specific Array based addAll method to reduce the amount of Wrapping + * @param e the elements that should be added + * @param length how many elements of the array should be added + * @return if the collection was modified + */ + public default boolean addAll(long[] e, int length) { return addAll(e, 0, length); } + + /** + * A Type-Specific Array based addAll method to reduce the amount of Wrapping + * @param e the elements that should be added + * @param offset where to start within the array + * @param length how many elements of the array should be added + * @return if the collection was modified + */ + public default boolean addAll(long[] e, int offset, int length) { + if(length <= 0) return false; + SanityChecks.checkArrayCapacity(e.length, offset, length); + boolean added = false; + for(int i = 0;i c); + + /** + * A Type-Specific remove function that reduces (un)boxing. + * @param o the element that should be removed + * @return true if the element was removed + * @see Collection#remove(Object) + */ + public boolean remLong(long o); + + /** + * A Type-Specific removeAll function that reduces (un)boxing. + * @param c the collection of elements that should be removed + * @return true if any element was removed + * @see Collection#removeAll(Collection) + */ + public boolean removeAll(LongCollection c); + + /** + * A Type-Specific removeAll function that reduces (un)boxing. + * It also notifies the remover of which exact element is going to be removed. + * @param c the collection of elements that should be removed + * @param r elements that got removed + * @return true if any element was removed + * @see Collection#removeAll(Collection) + */ + public boolean removeAll(LongCollection c, LongConsumer r); + + /** + * A Type-Specific retainAll function that reduces (un)boxing. + * @param c the collection of elements that should be kept + * @return true if any element was removed + * @see Collection#retainAll(Collection) + */ + public boolean retainAll(LongCollection c); + + /** + * A Type-Specific retainAll function that reduces (un)boxing. + * It also notifies the remover of which exact element is going to be removed. + * @param c the collection of elements that should be kept + * @param r elements that got removed + * @return true if any element was removed + * @see Collection#retainAll(Collection) + */ + public boolean retainAll(LongCollection c, LongConsumer r); + + /** + * A Helper function to reduce the usage of Streams and allows to collect all elements + * @param collection that the elements should be inserted to + * @param the collection type + * @return the input with the desired elements + */ + default E pour(E collection) { + collection.addAll(this); + return collection; + } + + /** + * A Function that does a shallow clone of the Collection itself. + * This function is more optimized then a copy constructor since the Collection does not have to be unsorted/resorted. + * It can be compared to Cloneable but with less exception risk + * @return a Shallow Copy of the collection + * @note Wrappers and view collections will not support this feature + */ + public LongCollection copy(); + + /** + * A Type-Specific toArray function that delegates to {@link #toLongArray(long[])} with a newly created array. + * @return an array containing all of the elements in this collection + * @see Collection#toArray() + */ + public long[] toLongArray(); + + /** + * A Type-Specific toArray function that reduces (un)boxing. + * @param a array that the elements should be injected to. If null or to small a new array with the right size is created + * @return an array containing all of the elements in this collection + * @see Collection#toArray(Object[]) + */ + public long[] toLongArray(long[] a); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default boolean removeIf(Predicate filter) { + Objects.requireNonNull(filter); + return remIf(v -> filter.test(Long.valueOf(v))); + } + + /** + * A Type-Specific removeIf function to reduce (un)boxing. + *

Removes elements that were selected by the filter + * @see Collection#removeIf(Predicate) + * @param filter Filters the elements that should be removed + * @return true if the collection was modified + * @throws NullPointerException if filter is null + */ + public default boolean remIf(LongPredicate filter) { + Objects.requireNonNull(filter); + boolean removed = false; + final LongIterator each = iterator(); + while (each.hasNext()) { + if (filter.test(each.nextLong())) { + each.remove(); + removed = true; + } + } + return removed; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default boolean add(Long o) { return add(o.longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default boolean contains(Object o) { return o != null && contains(((Long)o).longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default boolean remove(Object o) { return o != null && remLong(((Long)o).longValue()); } + + /** + * Returns a Type-Specific Iterator to reduce (un)boxing + * @return a iterator of the collection + * @see Collection#iterator() + */ + @Override + public LongIterator iterator(); + + /** + * Creates a Wrapped Collection that is Synchronized + * @return a new Collection that is synchronized + * @see LongCollections#synchronize + */ + public default LongCollection synchronize() { return LongCollections.synchronize(this); } + + /** + * Creates a Wrapped Collection that is Synchronized + * @param mutex is the controller of the synchronization block + * @return a new Collection Wrapper that is synchronized + * @see LongCollections#synchronize + */ + public default LongCollection synchronize(Object mutex) { return LongCollections.synchronize(this, mutex); } + + /** + * Creates a Wrapped Collection that is unmodifiable + * @return a new Collection Wrapper that is unmodifiable + * @see LongCollections#unmodifiable + */ + public default LongCollection unmodifiable() { return LongCollections.unmodifiable(this); } + + /** + * Returns a Java-Type-Specific Stream to reduce boxing/unboxing. + * @return a Stream of the closest java type + */ + default LongStream primitiveStream() { return StreamSupport.longStream(LongSplititerators.createJavaSplititerator(this, 0), false); } + + /** + * Returns a Java-Type-Specific Parallel Stream to reduce boxing/unboxing. + * @return a Stream of the closest java type + */ + default LongStream parallelPrimitiveStream() { return StreamSupport.longStream(LongSplititerators.createJavaSplititerator(this, 0), true); } + + /** + * A Type Specific Type Splititerator to reduce boxing/unboxing + * @return type specific splititerator + */ + @Override + default LongSplititerator spliterator() { return LongSplititerators.createSplititerator(this, 0); } +} diff --git a/src/main/java/speiger/src/collections/longs/collections/LongIterable.java b/src/main/java/speiger/src/collections/longs/collections/LongIterable.java new file mode 100644 index 000000000..ad3b382fe --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/collections/LongIterable.java @@ -0,0 +1,314 @@ +package speiger.src.collections.longs.collections; + +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.LongPredicate; + + +import speiger.src.collections.longs.functions.LongConsumer; +import speiger.src.collections.longs.functions.LongComparator; +import speiger.src.collections.objects.collections.ObjectIterable; +import speiger.src.collections.longs.functions.function.LongFunction; +import speiger.src.collections.ints.functions.consumer.IntLongConsumer; +import speiger.src.collections.objects.functions.consumer.ObjectLongConsumer; +import speiger.src.collections.longs.functions.function.LongLongUnaryOperator; + +import speiger.src.collections.longs.utils.LongArrays; +import speiger.src.collections.longs.utils.LongSplititerators; +import speiger.src.collections.longs.utils.LongIterables; +import speiger.src.collections.longs.utils.LongIterators; +import speiger.src.collections.utils.ISizeProvider; + +/** + * A Type-Specific {@link Iterable} that reduces (un)boxing + */ +public interface LongIterable extends Iterable +{ + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + LongIterator iterator(); + + /** + * A Type Specific foreach function that reduces (un)boxing + * + * @implSpec + *

The default implementation behaves as if: + *

{@code
+	 *	iterator().forEachRemaining(action);
+	 * }
+ * + * @param action The action to be performed for each element + * @throws NullPointerException if the specified action is null + * @see Iterable#forEach(Consumer) + */ + default void forEach(LongConsumer action) { + Objects.requireNonNull(action); + iterator().forEachRemaining(action); + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Deprecated + @Override + default void forEach(Consumer action) { + Objects.requireNonNull(action); + iterator().forEachRemaining(action); + } + + /** + * A Indexed forEach implementation that allows you to keep track of how many elements were already iterated over. + * @param action The action to be performed for each element + * @throws NullPointerException if the specified action is null + */ + public default void forEachIndexed(IntLongConsumer action) { + Objects.requireNonNull(action); + int index = 0; + for(LongIterator iter = iterator();iter.hasNext();action.accept(index++, iter.nextLong())); + } + + /** + * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. + * @param input the object that should be included + * @param action The action to be performed for each element + * @param the generic type of the Object + * @throws NullPointerException if the specified action is null + */ + default void forEach(E input, ObjectLongConsumer action) { + Objects.requireNonNull(action); + iterator().forEachRemaining(input, action); + } + + /** + * A Type Specific Type Splititerator to reduce boxing/unboxing + * @return type specific splititerator + */ + @Override + default LongSplititerator spliterator() { return LongSplititerators.createUnknownSplititerator(iterator(), 0); } + + /** + * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. + * @param mapper the mapping function + * @param The return type. + * @return a new Iterable that returns the desired result + */ + default ObjectIterable map(LongFunction mapper) { + return LongIterables.map(this, mapper); + } + + /** + * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. + * @param mapper the flatMapping function + * @param The return type supplier. + * @param The return type. + * @return a new Iterable that returns the desired result + * @note does not support toLongArray optimizations. + */ + default > ObjectIterable flatMap(LongFunction mapper) { + return LongIterables.flatMap(this, mapper); + } + + /** + * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. + * @param mapper the flatMapping function + * @param The return type. + * @return a new Iterable that returns the desired result + * @note does not support toLongArray optimizations. + */ + default ObjectIterable arrayflatMap(LongFunction mapper) { + return LongIterables.arrayFlatMap(this, mapper); + } + + /** + * A Helper function to reduce the usage of Streams and allows to filter out unwanted elements + * @param filter the elements that should be kept. + * @return a Iterable that filtered out all unwanted elements + * @note does not support toLongArray optimizations. + */ + default LongIterable filter(LongPredicate filter) { + return LongIterables.filter(this, filter); + } + + /** + * A Helper function to reduce the usage of Streams and allows to filter out duplicated elements + * @return a Iterable that filtered out all duplicated elements + * @note does not support toLongArray optimizations. + */ + default LongIterable distinct() { + return LongIterables.distinct(this); + } + + /** + * A Helper function to reduce the usage of Streams and allows to repeat elements a desired amount of times + * @param repeats how many times the elements should be repeated + * @return a Iterable that is repeating multiple times + */ + default LongIterable repeat(int repeats) { + return LongIterables.repeat(this, repeats); + } + + /** + * A Helper function to reduce the usage of Streams and allows to limit the amount of elements + * @param limit the amount of elements it should be limited to + * @return a Iterable that is limited in length + */ + default LongIterable limit(long limit) { + return LongIterables.limit(this, limit); + } + + /** + * A Helper function to reduce the usage of Streams and allows to sort the elements + * @param sorter that sorts the elements. + * @return a Iterable that is sorted + */ + default LongIterable sorted(LongComparator sorter) { + return LongIterables.sorted(this, sorter); + } + + /** + * A Helper function to reduce the usage of Streams and allows to preview elements before they are iterated through + * @param action the action that should be applied + * @return a Peeked Iterable + */ + default LongIterable peek(LongConsumer action) { + return LongIterables.peek(this, action); + } + + /** + * A Helper function to reduce the usage of Streams and allows to collect all elements + * @param collection that the elements should be inserted to + * @param the collection type + * @return the input with the desired elements + */ + default E pour(E collection) { + LongIterators.pour(iterator(), collection); + return collection; + } + + + /** + * A Helper function that reduces the usage of streams and allows to collect all elements as a Array + * @return a new Array of all elements + */ + default long[] toLongArray() { + ISizeProvider prov = ISizeProvider.of(this); + if(prov != null) { + int size = prov.size(); + if(size >= 0) { + long[] array = new long[size]; + LongIterators.unwrap(array, iterator()); + return array; + } + } + return LongArrays.pour(iterator()); + } + + /** + * Helper function to reduce stream usage that allows to filter for any matches. + * @param filter that should be applied + * @return true if any matches were found + */ + default boolean matchesAny(LongPredicate filter) { + Objects.requireNonNull(filter); + for(LongIterator iter = iterator();iter.hasNext();) { + if(filter.test(iter.nextLong())) return true; + } + return false; + } + + /** + * Helper function to reduce stream usage that allows to filter for no matches. + * @param filter that should be applied + * @return true if no matches were found + */ + default boolean matchesNone(LongPredicate filter) { + Objects.requireNonNull(filter); + for(LongIterator iter = iterator();iter.hasNext();) { + if(filter.test(iter.nextLong())) return false; + } + return true; + } + + /** + * Helper function to reduce stream usage that allows to filter for all matches. + * @param filter that should be applied + * @return true if all matches. + */ + default boolean matchesAll(LongPredicate filter) { + Objects.requireNonNull(filter); + for(LongIterator iter = iterator();iter.hasNext();) { + if(!filter.test(iter.nextLong())) return false; + } + return true; + } + + /** + * Helper function to reduce stream usage that allows to filter for the first match. + * @param filter that should be applied + * @return the found value or the null equivalent variant. + */ + default long findFirst(LongPredicate filter) { + Objects.requireNonNull(filter); + for(LongIterator iter = iterator();iter.hasNext();) { + long entry = iter.nextLong(); + if(filter.test(entry)) return entry; + } + return 0L; + } + + /** + * Performs a reduction on the + * elements of this Iterable + * @param operator the operation that should be applied + * @param identity the start value + * @return the reduction result, returns identity if nothing was found + */ + default long reduce(long identity, LongLongUnaryOperator operator) { + Objects.requireNonNull(operator); + long state = identity; + for(LongIterator iter = iterator();iter.hasNext();) { + state = operator.applyAsLong(state, iter.nextLong()); + } + return state; + } + + /** + * Performs a reduction on the + * elements of this Iterable + * @param operator the operation that should be applied + * @return the reduction result, returns null value if nothing was found + */ + default long reduce(LongLongUnaryOperator operator) { + Objects.requireNonNull(operator); + long state = 0L; + boolean empty = true; + for(LongIterator iter = iterator();iter.hasNext();) { + if(empty) { + empty = false; + state = iter.nextLong(); + continue; + } + state = operator.applyAsLong(state, iter.nextLong()); + } + return state; + } + + /** + * Helper function to reduce stream usage that allows to count the valid elements. + * @param filter that should be applied + * @return the amount of Valid Elements + */ + default int count(LongPredicate filter) { + Objects.requireNonNull(filter); + int result = 0; + for(LongIterator iter = iterator();iter.hasNext();) { + if(filter.test(iter.nextLong())) result++; + } + return result; + } +} diff --git a/src/main/java/speiger/src/collections/longs/collections/LongIterator.java b/src/main/java/speiger/src/collections/longs/collections/LongIterator.java new file mode 100644 index 000000000..1f19934b2 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/collections/LongIterator.java @@ -0,0 +1,88 @@ +package speiger.src.collections.longs.collections; + +import java.util.Iterator; +import java.util.Objects; +import java.util.function.Consumer; + +import speiger.src.collections.longs.functions.LongConsumer; + +import speiger.src.collections.objects.functions.consumer.ObjectLongConsumer; + +/** + * A Type-Specific {@link Iterator} that reduces (un)boxing + */ +public interface LongIterator extends Iterator +{ + /** + * Returns the next element in the iteration. + * + * @return the next element in the iteration + * @throws java.util.NoSuchElementException if the iteration has no more elements + * @see Iterator#next() + */ + public long nextLong(); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default Long next() { return Long.valueOf(nextLong()); } + + /** + * Performs the given action for each remaining element until all elements + * have been processed or the action throws an exception. Actions are + * performed in the order of iteration, if that order is specified. + * Exceptions thrown by the action are relayed to the caller. + * + * @implSpec + *

The default implementation behaves as if: + *

{@code
+	 *	while (hasNext()) action.accept(nextLong());
+	 * }
+ * + * @param action The action to be performed for each element + * @throws NullPointerException if the specified action is null + * @see Iterator#forEachRemaining(Consumer) + */ + public default void forEachRemaining(LongConsumer action) { + Objects.requireNonNull(action); + while(hasNext()) { action.accept(nextLong()); } + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Deprecated + @Override + default void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + forEachRemaining(action::accept); + } + + /** + * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. + * @param input the object that should be included + * @param action The action to be performed for each element + * @param the generic type of the Object + * @throws NullPointerException if the specified action is null + */ + default void forEachRemaining(E input, ObjectLongConsumer action) { + Objects.requireNonNull(action); + while(hasNext()) { action.accept(input, nextLong()); } + } + + /** + * Skips the Given amount of elements if possible. A Optimization function to skip elements faster if the implementation allows it. + * @param amount the amount of elements that should be skipped + * @return the amount of elements that were skipped + */ + default int skip(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int i = 0; + for(;i, LongIterator +{ + @Override + default void forEachRemaining(LongConsumer action) { LongIterator.super.forEachRemaining(action); } + @Override + @Deprecated + default void forEachRemaining(Consumer action) { LongIterator.super.forEachRemaining(action); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/collections/LongStack.java b/src/main/java/speiger/src/collections/longs/collections/LongStack.java new file mode 100644 index 000000000..47feba4cc --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/collections/LongStack.java @@ -0,0 +1,62 @@ +package speiger.src.collections.longs.collections; + +import speiger.src.collections.utils.Stack; + +/** + * A Type-Specific {@link Stack} that reduces (un)boxing + */ +public interface LongStack +{ + /** + * Inserts a given Object on top of the stack + * @param e the Object to insert + * @see Stack#push(Object) + */ + public void push(long e); + + /** + * Removes the Object on top of the stack. + * @return the element that is on top of the stack + * @throws ArrayIndexOutOfBoundsException if the stack is empty + * @see Stack#pop() + */ + public long pop(); + + /** + * Provides the Object on top of the stack + * @return the element that is on top of the stack + * @throws ArrayIndexOutOfBoundsException if the stack is empty + * @see Stack#top() + */ + public default long top() { + return peek(0); + } + + /** + * Provides the Selected Object from the stack. + * Top to bottom + * @param index of the element that should be provided + * @return the element that was requested + * @throws ArrayIndexOutOfBoundsException if the index is out of bounds + * @see Stack#peek(int) + */ + public long peek(int index); + + /** + * Clears the stack + */ + public void clear(); + + /** + * Provides the amount of elements currently in the stack + * @return amount of elements in the list + */ + public int size(); + + /** + * @return if the stack is empty + */ + public default boolean isEmpty() { + return size() == 0; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/LongComparator.java b/src/main/java/speiger/src/collections/longs/functions/LongComparator.java new file mode 100644 index 000000000..5d41f4d8b --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/LongComparator.java @@ -0,0 +1,70 @@ +package speiger.src.collections.longs.functions; + +import java.util.Comparator; +import java.util.Objects; + +/** + * Type-Specific Class for Comparator to reduce (un)boxing + */ +public interface LongComparator extends Comparator +{ + /** + * Type-Specific compare function to reduce (un)boxing + * @param o1 the first object to be compared. + * @param o2 the second object to be compared. + * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. + * @see Comparator#compare(Object, Object) + */ + int compare(long o1, long o2); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default int compare(Long o1, Long o2) { + return compare(o1.longValue(), o2.longValue()); + } + + /** + * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator + * @param c comparator to convert + * @return the wrapper of the comparator + * @throws NullPointerException if the comparator is null + */ + public static LongComparator of(Comparator c) { + Objects.requireNonNull(c); + return (K, V) -> c.compare(Long.valueOf(K), Long.valueOf(V)); + } + + @Override + public default LongComparator reversed() { + return new Reversed(this); + } + + /** + * A Type Specific Reversed Comparator to reduce boxing/unboxing + */ + static class Reversed implements LongComparator + { + LongComparator original; + + /** + * default constructor + * @param original that is going to be reversed + */ + public Reversed(LongComparator original) { + this.original = original; + } + + public int compare(long o1, long o2) { + return original.compare(o2, o1); + } + + @Override + public LongComparator reversed() { + return original; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/LongConsumer.java b/src/main/java/speiger/src/collections/longs/functions/LongConsumer.java new file mode 100644 index 000000000..f4772ad26 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/LongConsumer.java @@ -0,0 +1,59 @@ +package speiger.src.collections.longs.functions; + +import java.util.Objects; +import java.util.function.Consumer; +/** + * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +@FunctionalInterface +public interface LongConsumer extends Consumer, java.util.function.LongConsumer +{ + /** + * Type-Specific function to reduce (un)boxing. + * Performs this operation on the given argument. + * + * @param t the input argument + */ + void accept(long t); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced consumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default LongConsumer andThen(LongConsumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(T);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Long t) { accept(t.longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default LongConsumer andThen(Consumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(Long.valueOf(T));}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default LongConsumer andThen(java.util.function.LongConsumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(T);}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/LongSupplier.java b/src/main/java/speiger/src/collections/longs/functions/LongSupplier.java new file mode 100644 index 000000000..224b391e2 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/LongSupplier.java @@ -0,0 +1,12 @@ +package speiger.src.collections.longs.functions; + +/** + * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +public interface LongSupplier extends java.util.function.LongSupplier +{ + /** + * @return the supplied value + */ + public long getAsLong(); +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongBooleanConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongBooleanConsumer.java new file mode 100644 index 000000000..1bca0ed2c --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/consumer/LongBooleanConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.longs.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface LongBooleanConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(long k, boolean v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default LongBooleanConsumer andThen(LongBooleanConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Long k, Boolean v) { accept(k.longValue(), v.booleanValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default LongBooleanConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Boolean.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongByteConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongByteConsumer.java new file mode 100644 index 000000000..01ae96c13 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/consumer/LongByteConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.longs.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface LongByteConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(long k, byte v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default LongByteConsumer andThen(LongByteConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Long k, Byte v) { accept(k.longValue(), v.byteValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default LongByteConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Byte.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongCharConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongCharConsumer.java new file mode 100644 index 000000000..b312c0451 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/consumer/LongCharConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.longs.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface LongCharConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(long k, char v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default LongCharConsumer andThen(LongCharConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Long k, Character v) { accept(k.longValue(), v.charValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default LongCharConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Character.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongDoubleConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongDoubleConsumer.java new file mode 100644 index 000000000..c00a09d39 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/consumer/LongDoubleConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.longs.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface LongDoubleConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(long k, double v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default LongDoubleConsumer andThen(LongDoubleConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Long k, Double v) { accept(k.longValue(), v.doubleValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default LongDoubleConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Double.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongFloatConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongFloatConsumer.java new file mode 100644 index 000000000..fc6d1f454 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/consumer/LongFloatConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.longs.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface LongFloatConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(long k, float v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default LongFloatConsumer andThen(LongFloatConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Long k, Float v) { accept(k.longValue(), v.floatValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default LongFloatConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Float.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongIntConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongIntConsumer.java new file mode 100644 index 000000000..f3a72ef27 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/consumer/LongIntConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.longs.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface LongIntConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(long k, int v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default LongIntConsumer andThen(LongIntConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Long k, Integer v) { accept(k.longValue(), v.intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default LongIntConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Integer.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongLongConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongLongConsumer.java new file mode 100644 index 000000000..efd2d5808 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/consumer/LongLongConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.longs.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface LongLongConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(long k, long v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default LongLongConsumer andThen(LongLongConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Long k, Long v) { accept(k.longValue(), v.longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default LongLongConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Long.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongObjectConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongObjectConsumer.java new file mode 100644 index 000000000..756a34d76 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/consumer/LongObjectConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.longs.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface LongObjectConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(long k, V v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default LongObjectConsumer andThen(LongObjectConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Long k, V v) { accept(k.longValue(), v); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default LongObjectConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), V);}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongShortConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongShortConsumer.java new file mode 100644 index 000000000..2ed74ccb9 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/consumer/LongShortConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.longs.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface LongShortConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(long k, short v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default LongShortConsumer andThen(LongShortConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Long k, Short v) { accept(k.longValue(), v.shortValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default LongShortConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Short.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2ByteFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2ByteFunction.java new file mode 100644 index 000000000..c4ea52d4d --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/Long2ByteFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.longs.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Long2ByteFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public byte applyAsByte(long k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2CharFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2CharFunction.java new file mode 100644 index 000000000..43ecd9821 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/Long2CharFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.longs.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Long2CharFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public char applyAsChar(long k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2DoubleFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2DoubleFunction.java new file mode 100644 index 000000000..c860ab5cb --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/Long2DoubleFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.longs.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Long2DoubleFunction extends java.util.function.LongToDoubleFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public double applyAsDouble(long k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2FloatFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2FloatFunction.java new file mode 100644 index 000000000..15e07cefa --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/Long2FloatFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.longs.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Long2FloatFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public float applyAsFloat(long k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2IntFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2IntFunction.java new file mode 100644 index 000000000..c1b2bdddd --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/Long2IntFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.longs.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Long2IntFunction extends java.util.function.LongToIntFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public int applyAsInt(long k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2ShortFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2ShortFunction.java new file mode 100644 index 000000000..deb4e53cb --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/Long2ShortFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.longs.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Long2ShortFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public short applyAsShort(long k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongBooleanUnaryOperator.java new file mode 100644 index 000000000..f5a30815a --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongBooleanUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.longs.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface LongBooleanUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public boolean applyAsBoolean(long k, boolean v); + + @Override + public default Boolean apply(Long k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.longValue(), v.booleanValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongByteUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongByteUnaryOperator.java new file mode 100644 index 000000000..dd49dda5d --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongByteUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.longs.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface LongByteUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public byte applyAsByte(long k, byte v); + + @Override + public default Byte apply(Long k, Byte v) { return Byte.valueOf(applyAsByte(k.longValue(), v.byteValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongCharUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongCharUnaryOperator.java new file mode 100644 index 000000000..b55597ae8 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongCharUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.longs.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface LongCharUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public char applyAsChar(long k, char v); + + @Override + public default Character apply(Long k, Character v) { return Character.valueOf(applyAsChar(k.longValue(), v.charValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongDoubleUnaryOperator.java new file mode 100644 index 000000000..e558e3533 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongDoubleUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.longs.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface LongDoubleUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public double applyAsDouble(long k, double v); + + @Override + public default Double apply(Long k, Double v) { return Double.valueOf(applyAsDouble(k.longValue(), v.doubleValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongFloatUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongFloatUnaryOperator.java new file mode 100644 index 000000000..49c1edd88 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongFloatUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.longs.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface LongFloatUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public float applyAsFloat(long k, float v); + + @Override + public default Float apply(Long k, Float v) { return Float.valueOf(applyAsFloat(k.longValue(), v.floatValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/LongFunction.java new file mode 100644 index 000000000..959749882 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.longs.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface LongFunction extends java.util.function.LongFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public V apply(long k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongIntUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongIntUnaryOperator.java new file mode 100644 index 000000000..986b7037b --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongIntUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.longs.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface LongIntUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public int applyAsInt(long k, int v); + + @Override + public default Integer apply(Long k, Integer v) { return Integer.valueOf(applyAsInt(k.longValue(), v.intValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongLongUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongLongUnaryOperator.java new file mode 100644 index 000000000..f0a35c2b9 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongLongUnaryOperator.java @@ -0,0 +1,13 @@ +package speiger.src.collections.longs.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ + +public interface LongLongUnaryOperator extends BiFunction, java.util.function.LongBinaryOperator +{ + @Override + public default Long apply(Long k, Long v) { return Long.valueOf(applyAsLong(k.longValue(), v.longValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongObjectUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongObjectUnaryOperator.java new file mode 100644 index 000000000..16d522964 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongObjectUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.longs.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface LongObjectUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public V apply(long k, V v); + + @Override + public default V apply(Long k, V v) { return apply(k.longValue(), v); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongPredicate.java b/src/main/java/speiger/src/collections/longs/functions/function/LongPredicate.java new file mode 100644 index 000000000..2fd7fcbde --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongPredicate.java @@ -0,0 +1,72 @@ +package speiger.src.collections.longs.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface LongPredicate extends java.util.function.LongPredicate +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public boolean test(long k); + + /** + * Creates a Always true function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static LongPredicate alwaysTrue() { + return T -> true; + } + + /** + * Creates a Always false function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static LongPredicate alwaysFalse() { + return T -> false; + } + + /** + * A Type specific and-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a and comparason + */ + public default LongPredicate andType(LongPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + @Override + @Deprecated + public default LongPredicate and(java.util.function.LongPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + @Override + public default LongPredicate negate() { + return T -> !test(T); + } + + /** + * A Type specific or-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a or comparason + */ + public default LongPredicate orType(LongPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } + + @Override + @Deprecated + public default LongPredicate or(java.util.function.LongPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongShortUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongShortUnaryOperator.java new file mode 100644 index 000000000..d1d81cf8d --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongShortUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.longs.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface LongShortUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public short applyAsShort(long k, short v); + + @Override + public default Short apply(Long k, Short v) { return Short.valueOf(applyAsShort(k.longValue(), v.shortValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongUnaryOperator.java new file mode 100644 index 000000000..5e74927a2 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/functions/function/LongUnaryOperator.java @@ -0,0 +1,54 @@ +package speiger.src.collections.longs.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface LongUnaryOperator extends java.util.function.LongUnaryOperator +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public long applyAsLong(long k); + + /** + * Creates a Default function that returns the input provided. + * @return a input returning function + */ + public static LongUnaryOperator identity() { + return T -> T; + } + + /** + * Returns a composed function that first applies the {@code before} + * function to its input, and then applies this function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param before the function that should be used first + * @return a composed function with a different starting function. + */ + public default LongUnaryOperator compose(LongUnaryOperator before) { + Objects.requireNonNull(before); + return T -> applyAsLong(before.applyAsLong(T)); + } + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param after the function that should be used last + * @return a composed function with a different starting function. + */ + public default LongUnaryOperator andThen(LongUnaryOperator after) { + Objects.requireNonNull(after); + return T -> after.applyAsLong(applyAsLong(T)); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/lists/LongListIterator.java b/src/main/java/speiger/src/collections/longs/lists/LongListIterator.java new file mode 100644 index 000000000..7076dc998 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/lists/LongListIterator.java @@ -0,0 +1,65 @@ +package speiger.src.collections.longs.lists; + +import java.util.ListIterator; + +import speiger.src.collections.longs.collections.LongBidirectionalIterator; + +/** + * A Type Specific ListIterator that reduces boxing/unboxing + */ +public interface LongListIterator extends ListIterator, LongBidirectionalIterator +{ + /** + * A Primitive set function to reduce (un)boxing + * @param e the element that should replace the last returned value + * @see ListIterator#set(Object) + */ + public void set(long e); + + /** + * A Primitive set function to reduce (un)boxing + * @param e the element that should be inserted before the last returned value + * @see ListIterator#set(Object) + */ + public void add(long e); + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default Long previous() { + return LongBidirectionalIterator.super.previous(); + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default Long next() { + return LongBidirectionalIterator.super.next(); + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default void set(Long e) { + set(e.longValue()); + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public default void add(Long e) { + add(e.longValue()); + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/sets/AbstractLongSet.java b/src/main/java/speiger/src/collections/longs/sets/AbstractLongSet.java new file mode 100644 index 000000000..22c4ff1ae --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/sets/AbstractLongSet.java @@ -0,0 +1,41 @@ +package speiger.src.collections.longs.sets; + +import java.util.Set; + +import speiger.src.collections.longs.collections.AbstractLongCollection; +import speiger.src.collections.longs.collections.LongIterator; + +/** + * Abstract Type Specific Set that reduces boxing/unboxing + */ +public abstract class AbstractLongSet extends AbstractLongCollection implements LongSet +{ + @Override + public abstract LongIterator iterator(); + @Override + public AbstractLongSet copy() { throw new UnsupportedOperationException(); } + + @Override + public int hashCode() { + int hashCode = 0; + LongIterator i = iterator(); + while(i.hasNext()) + hashCode += Long.hashCode(i.nextLong()); + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Set l = (Set)o; + if(l.size() != size()) return false; + try { + return containsAll(l); + } catch (ClassCastException | NullPointerException unused) { + return false; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/sets/LongOpenHashSet.java b/src/main/java/speiger/src/collections/longs/sets/LongOpenHashSet.java new file mode 100644 index 000000000..12f0307cf --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/sets/LongOpenHashSet.java @@ -0,0 +1,635 @@ +package speiger.src.collections.longs.sets; + +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.LongPredicate; + +import speiger.src.collections.longs.collections.LongCollection; +import speiger.src.collections.longs.collections.LongIterator; +import speiger.src.collections.longs.utils.LongIterators; +import speiger.src.collections.longs.functions.LongConsumer; +import speiger.src.collections.ints.functions.consumer.IntLongConsumer; +import speiger.src.collections.objects.functions.consumer.ObjectLongConsumer; +import speiger.src.collections.longs.functions.function.LongLongUnaryOperator; +import speiger.src.collections.utils.HashUtil; +import speiger.src.collections.utils.ITrimmable; +import speiger.src.collections.utils.SanityChecks; + +/** + * A Type Specific Custom implementation of the HashSet + * Instead of using Wrapper Object Arrays for storing keys and values there is dedicated arrays for storing keys. + * Extra to that there is a couple quality of life functions provided + */ +public class LongOpenHashSet extends AbstractLongSet implements ITrimmable +{ + /** The Backing keys array */ + protected transient long[] keys; + /** If a null value is present */ + protected transient boolean containsNull; + /** Minimum array size the HashSet will be */ + protected transient int minCapacity; + /** Index of the Null Value */ + protected transient int nullIndex; + /** Maximum amount of Values that can be stored before the array gets expanded usually 75% */ + protected transient int maxFill; + /** Max Index that is allowed to be searched through nullIndex - 1 */ + protected transient int mask; + + /** Amount of Elements stored in the HashSet */ + protected int size; + /** How full the Array is allowed to get before resize */ + protected final float loadFactor; + + /** + * Default Constructor + */ + public LongOpenHashSet() { + this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR); + } + + /** + * Constructor that defines the minimum capacity + * @param minCapacity the minimum capacity the HashSet is allowed to be. + * @throws IllegalStateException if the minimum capacity is negative + */ + public LongOpenHashSet(int minCapacity) { + this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR); + } + + /** + * Constructor that defines the minimum capacity and load factor + * @param minCapacity the minimum capacity the HashSet is allowed to be. + * @param loadFactor the percentage of how full the backing array can be before they resize + * @throws IllegalStateException if the minimum capacity is negative + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + */ + public LongOpenHashSet(int minCapacity, float loadFactor) { + if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); + if(loadFactor <= 0 || loadFactor >= 1F) throw new IllegalStateException("Load Factor is not between 0 and 1"); + this.loadFactor = loadFactor; + this.minCapacity = nullIndex = HashUtil.arraySize(minCapacity, loadFactor); + mask = nullIndex - 1; + maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); + keys = new long[nullIndex + 1]; + } + + /** + * Helper constructor that allow to create a set from unboxed values + * @param array the elements that should be put into the set + */ + public LongOpenHashSet(long[] array) { + this(array, 0, array.length, HashUtil.DEFAULT_LOAD_FACTOR); + } + + /** + * Helper constructor that allow to create a set from unboxed values + * @param array the elements that should be put into the set + * @param loadFactor the percentage of how full the backing array can be before they resize + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + */ + public LongOpenHashSet(long[] array, float loadFactor) { + this(array, 0, array.length, loadFactor); + } + + /** + * Helper constructor that allow to create a set from unboxed values + * @param array the elements that should be put into the set + * @param offset the starting index within the array that should be used + * @param length the amount of elements used from the array + * @throws IllegalStateException if offset and length causes to step outside of the arrays range + */ + public LongOpenHashSet(long[] array, int offset, int length) { + this(array, offset, length, HashUtil.DEFAULT_LOAD_FACTOR); + } + + /** + * Helper constructor that allow to create a set from unboxed values + * @param array the elements that should be put into the set + * @param offset the starting index within the array that should be used + * @param length the amount of elements used from the array + * @param loadFactor the percentage of how full the backing array can be before they resize + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + * @throws IllegalStateException if offset and length causes to step outside of the arrays range + */ + public LongOpenHashSet(long[] array, int offset, int length, float loadFactor) { + this(length < 0 ? 0 : length); + SanityChecks.checkArrayCapacity(array.length, offset, length); + for(int i = 0;i collection) { + this(collection, HashUtil.DEFAULT_LOAD_FACTOR); + } + + /** + * A Helper constructor that allows to create a Set with exactly the same values as the provided collection. + * @param collection the set the elements should be added to the Set + * @param loadFactor the percentage of how full the backing array can be before they resize + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + */ + @Deprecated + public LongOpenHashSet(Collection collection, float loadFactor) { + this(collection.size(), loadFactor); + addAll(collection); + } + + /** + * A Helper constructor that allows to create a Set with exactly the same values as the provided collection. + * @param collection the set the elements should be added to the Set + */ + public LongOpenHashSet(LongCollection collection) { + this(collection, HashUtil.DEFAULT_LOAD_FACTOR); + } + + /** + * A Helper constructor that allows to create a Set with exactly the same values as the provided collection. + * @param collection the set the elements should be added to the Set + * @param loadFactor the percentage of how full the backing array can be before they resize + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + */ + public LongOpenHashSet(LongCollection collection, float loadFactor) { + this(collection.size()); + addAll(collection); + } + + /** + * A Helper constructor that allows to create a set from a iterator of an unknown size + * @param iterator the elements that should be added to the set + */ + public LongOpenHashSet(Iterator iterator) { + this(iterator, HashUtil.DEFAULT_LOAD_FACTOR); + } + + /** + * A Helper constructor that allows to create a set from a iterator of an unknown size + * @param iterator the elements that should be added to the set + * @param loadFactor the percentage of how full the backing array can be before they resize + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + */ + public LongOpenHashSet(Iterator iterator, float loadFactor) { + this(LongIterators.wrap(iterator), loadFactor); + } + + /** + * A Helper constructor that allows to create a set from a iterator of an unknown size + * @param iterator the elements that should be added to the set + */ + public LongOpenHashSet(LongIterator iterator) { + this(iterator, HashUtil.DEFAULT_LOAD_FACTOR); + } + + /** + * A Helper constructor that allows to create a set from a iterator of an unknown size + * @param iterator the elements that should be added to the set + * @param loadFactor the percentage of how full the backing array can be before they resize + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + */ + public LongOpenHashSet(LongIterator iterator, float loadFactor) { + this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor); + while(iterator.hasNext()) add(iterator.nextLong()); + } + + @Override + public boolean add(long o) { + if(o == 0) { + if(containsNull) return false; + containsNull = true; + onNodeAdded(nullIndex); + } + else { + int pos = HashUtil.mix(Long.hashCode(o)) & mask; + long current = keys[pos]; + if(current != 0) { + if(current == o) return false; + while((current = keys[pos = (++pos & mask)]) != 0) + if(current == o) return false; + } + keys[pos] = o; + onNodeAdded(pos); + } + if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor)); + return true; + } + + @Override + @Deprecated + public boolean addAll(Collection c) { + if(loadFactor <= 0.5F) ensureCapacity(c.size()); + else ensureCapacity(c.size() + size()); + return super.addAll(c); + } + + @Override + public boolean addAll(LongCollection c) { + if(loadFactor <= 0.5F) ensureCapacity(c.size()); + else ensureCapacity(c.size() + size()); + return super.addAll(c); + } + + @Override + public boolean contains(Object o) { + if(o == null) return false; + if(o instanceof Long && ((Long)o).longValue() == 0L) return containsNull; + int pos = HashUtil.mix(o.hashCode()) & mask; + long current = keys[pos]; + if(current == 0) return false; + if(Objects.equals(o, Long.valueOf(current))) return true; + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(Objects.equals(o, Long.valueOf(current))) return true; + } + } + + @Override + public boolean remove(Object o) { + if(o == null) return false; + if(o instanceof Long && ((Long)o).longValue() == 0L) return (containsNull ? removeNullIndex() : false); + int pos = HashUtil.mix(o.hashCode()) & mask; + long current = keys[pos]; + if(current == 0) return false; + if(Objects.equals(o, Long.valueOf(current))) return removeIndex(pos); + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(Objects.equals(o, Long.valueOf(current))) return removeIndex(pos); + } + } + + @Override + public boolean contains(long o) { + if(o == 0) return containsNull; + int pos = HashUtil.mix(Long.hashCode(o)) & mask; + long current = keys[pos]; + if(current == 0) return false; + if(current == o) return true; + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(current == o) return true; + } + } + + @Override + public boolean remove(long o) { + if(o == 0) return containsNull ? removeNullIndex() : false; + int pos = HashUtil.mix(Long.hashCode(o)) & mask; + long current = keys[pos]; + if(current == 0) return false; + if(current == o) return removeIndex(pos); + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(current == o) return removeIndex(pos); + } + } + + @Override + public boolean trim(int size) { + int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor))); + if(request >= nullIndex || this.size >= Math.min((int)Math.ceil(request * loadFactor), request - 1)) return false; + try { + rehash(request); + } + catch(OutOfMemoryError e) { return false; } + return true; + } + + @Override + public void clearAndTrim(int size) { + int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor))); + if(request >= nullIndex) { + clear(); + return; + } + nullIndex = request; + mask = request-1; + maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); + keys = new long[request + 1]; + this.size = 0; + containsNull = false; + } + + @Override + public void forEach(LongConsumer action) { + if(size() <= 0) return; + if(containsNull) action.accept(keys[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) { + if(keys[i] != 0) action.accept(keys[i]); + } + } + + @Override + public void forEachIndexed(IntLongConsumer action) { + Objects.requireNonNull(action); + if(size() <= 0) return; + if(containsNull) action.accept(0, keys[nullIndex]); + for(int i = nullIndex-1, index = containsNull ? 1 : 0;i>=0;i--) { + if(keys[i] != 0) action.accept(index++, keys[i]); + } + } + + @Override + public void forEach(E input, ObjectLongConsumer action) { + Objects.requireNonNull(action); + if(size() <= 0) return; + if(containsNull) action.accept(input, keys[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) { + if(keys[i] != 0) action.accept(input, keys[i]); + } + } + + @Override + public boolean matchesAny(LongPredicate filter) { + Objects.requireNonNull(filter); + if(size() <= 0) return false; + if(containsNull && filter.test(keys[nullIndex])) return true; + for(int i = nullIndex-1;i>=0;i--) { + if(keys[i] != 0 && filter.test(keys[i])) return true; + } + return false; + } + + @Override + public boolean matchesNone(LongPredicate filter) { + Objects.requireNonNull(filter); + if(size() <= 0) return true; + if(containsNull && filter.test(keys[nullIndex])) return false; + for(int i = nullIndex-1;i>=0;i--) { + if(keys[i] != 0 && filter.test(keys[i])) return false; + } + return true; + } + + @Override + public boolean matchesAll(LongPredicate filter) { + Objects.requireNonNull(filter); + if(size() <= 0) return true; + if(containsNull && !filter.test(keys[nullIndex])) return false; + for(int i = nullIndex-1;i>=0;i--) { + if(keys[i] != 0 && !filter.test(keys[i])) return false; + } + return true; + } + + @Override + public long reduce(long identity, LongLongUnaryOperator operator) { + Objects.requireNonNull(operator); + long state = identity; + if(containsNull) state = operator.applyAsLong(state, keys[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) { + if(keys[i] == 0) continue; + state = operator.applyAsLong(state, keys[i]); + } + return state; + } + + @Override + public long reduce(LongLongUnaryOperator operator) { + Objects.requireNonNull(operator); + long state = 0L; + boolean empty = true; + if(containsNull) { + state = keys[nullIndex]; + empty = false; + } + for(int i = nullIndex-1;i>=0;i--) { + if(keys[i] == 0) continue; + if(empty) { + empty = false; + state = keys[i]; + continue; + } + state = operator.applyAsLong(state, keys[i]); + } + return state; + } + + @Override + public long findFirst(LongPredicate filter) { + Objects.requireNonNull(filter); + if(size() <= 0) return 0L; + if(containsNull && filter.test(keys[nullIndex])) return keys[nullIndex]; + for(int i = nullIndex-1;i>=0;i--) { + if(keys[i] != 0 && filter.test(keys[i])) return keys[i]; + } + return 0L; + } + + @Override + public int count(LongPredicate filter) { + Objects.requireNonNull(filter); + if(size() <= 0) return 0; + int result = 0; + if(containsNull && filter.test(keys[nullIndex])) result++; + for(int i = nullIndex-1;i>=0;i--) { + if(keys[i] != 0 && filter.test(keys[i])) result++; + } + return result; + } + + private void ensureCapacity(int newCapacity) { + int size = HashUtil.arraySize(newCapacity, loadFactor); + if(size > nullIndex) rehash(size); + } + + protected boolean removeIndex(int pos) { + if(pos == nullIndex) return containsNull ? removeNullIndex() : false; + keys[pos] = 0L; + size--; + onNodeRemoved(pos); + shiftKeys(pos); + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return true; + } + + protected boolean removeNullIndex() { + containsNull = false; + keys[nullIndex] = 0L; + size--; + onNodeRemoved(nullIndex); + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return true; + } + + protected void onNodeAdded(int pos) { + + } + + protected void onNodeRemoved(int pos) { + + } + + protected void onNodeMoved(int from, int to) { + + } + + protected void shiftKeys(int startPos) { + int slot, last; + long current; + while(true) { + startPos = ((last = startPos) + 1) & mask; + while(true){ + if((current = keys[startPos]) == 0) { + keys[last] = 0L; + return; + } + slot = HashUtil.mix(Long.hashCode(current)) & mask; + if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; + startPos = ++startPos & mask; + } + keys[last] = current; + onNodeMoved(startPos, last); + } + } + + protected void rehash(int newSize) { + int newMask = newSize - 1; + long[] newKeys = new long[newSize + 1]; + for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) { + while(true) { + if(--i < 0) throw new ConcurrentModificationException("Set was modified during rehash"); + if(keys[i] != 0) break; + } + if(newKeys[pos = HashUtil.mix(Long.hashCode(keys[i])) & newMask] != 0) + while(newKeys[pos = (++pos & newMask)] != 0); + newKeys[pos] = keys[i]; + } + nullIndex = newSize; + mask = newMask; + maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); + keys = newKeys; + } + + @Override + public LongIterator iterator() { + return new SetIterator(); + } + + @Override + public LongOpenHashSet copy() { + LongOpenHashSet set = new LongOpenHashSet(0, loadFactor); + set.minCapacity = minCapacity; + set.mask = mask; + set.maxFill = maxFill; + set.nullIndex = nullIndex; + set.containsNull = containsNull; + set.size = size; + set.keys = Arrays.copyOf(keys, keys.length); + return set; + } + + @Override + public void clear() { + if(size == 0) return; + size = 0; + containsNull = false; + Arrays.fill(keys, 0L); + } + + @Override + public int size() { + return size; + } + + private class SetIterator implements LongIterator { + int pos = nullIndex; + int returnedPos = -1; + int lastReturned = -1; + int nextIndex = Integer.MIN_VALUE; + boolean returnNull = containsNull; + long[] wrapped = null; + int wrappedIndex = 0; + + @Override + public boolean hasNext() { + if(nextIndex == Integer.MIN_VALUE) { + if(returnNull) { + returnNull = false; + nextIndex = nullIndex; + } + else + { + while(true) { + if(--pos < 0) { + if(wrapped == null || wrappedIndex <= -pos - 1) break; + nextIndex = -pos - 1; + break; + } + if(keys[pos] != 0){ + nextIndex = pos; + break; + } + } + } + } + return nextIndex != Integer.MIN_VALUE; + } + + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + returnedPos = pos; + if(nextIndex < 0){ + lastReturned = Integer.MAX_VALUE; + long value = wrapped[nextIndex]; + nextIndex = Integer.MIN_VALUE; + return value; + } + long value = keys[(lastReturned = nextIndex)]; + nextIndex = Integer.MIN_VALUE; + return value; + } + + @Override + public void remove() { + if(lastReturned == -1) throw new IllegalStateException(); + if(lastReturned == nullIndex) { + containsNull = false; + keys[nullIndex] = 0L; + } + else if(returnedPos >= 0) shiftKeys(returnedPos); + else { + LongOpenHashSet.this.remove(wrapped[-returnedPos - 1]); + lastReturned = -1; + return; + } + size--; + lastReturned = -1; + } + + private void shiftKeys(int startPos) { + int slot, last; + long current; + while(true) { + startPos = ((last = startPos) + 1) & mask; + while(true){ + if((current = keys[startPos]) == 0) { + keys[last] = 0L; + return; + } + slot = HashUtil.mix(Long.hashCode(current)) & mask; + if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; + startPos = ++startPos & mask; + } + if(startPos < last) addWrapper(keys[startPos]); + keys[last] = current; + } + } + + private void addWrapper(long value) { + if(wrapped == null) wrapped = new long[2]; + else if(wrappedIndex >= wrapped.length) { + long[] newArray = new long[wrapped.length * 2]; + System.arraycopy(wrapped, 0, newArray, 0, wrapped.length); + wrapped = newArray; + } + wrapped[wrappedIndex++] = value; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/sets/LongSet.java b/src/main/java/speiger/src/collections/longs/sets/LongSet.java new file mode 100644 index 000000000..aa17eb396 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/sets/LongSet.java @@ -0,0 +1,58 @@ +package speiger.src.collections.longs.sets; + +import java.util.Set; + +import speiger.src.collections.longs.collections.LongCollection; +import speiger.src.collections.longs.collections.LongIterator; +import speiger.src.collections.longs.collections.LongSplititerator; +import speiger.src.collections.longs.utils.LongSplititerators; + + +/** + * A Type Specific Set class to reduce boxing/unboxing + */ +public interface LongSet extends Set, LongCollection +{ + @Override + public LongIterator iterator(); + + @Override + public LongSet copy(); + + /** + * A Type Specific remove function to reduce boxing/unboxing + * @param o the element that should be removed + * @return true if the element was removed + */ + public boolean remove(long o); + + @Override + public default boolean remLong(long o) { + return remove(o); + } + + @Override + @Deprecated + public default boolean add(Long e) { + return LongCollection.super.add(e); + } + + @Override + @Deprecated + public default boolean contains(Object o) { + return LongCollection.super.contains(o); + } + + @Override + @Deprecated + public default boolean remove(Object o) { + return LongCollection.super.remove(o); + } + + /** + * A Type Specific Type Splititerator to reduce boxing/unboxing + * @return type specific splititerator + */ + @Override + default LongSplititerator spliterator() { return LongSplititerators.createSplititerator(this, 0); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/utils/LongArrays.java b/src/main/java/speiger/src/collections/longs/utils/LongArrays.java new file mode 100644 index 000000000..76432313f --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/utils/LongArrays.java @@ -0,0 +1,1527 @@ +package speiger.src.collections.longs.utils; + +import java.util.Arrays; +import java.util.Random; +import java.util.concurrent.RecursiveAction; + +import speiger.src.collections.longs.functions.LongComparator; +import speiger.src.collections.longs.collections.LongIterator; +import speiger.src.collections.longs.utils.LongIterators; +import speiger.src.collections.longs.utils.LongCollections; +import speiger.src.collections.utils.SanityChecks; + +/** + * A Helper class for Arrays + */ +public class LongArrays +{ + /** Default Limit for Insertion/Selection Sort */ + public static final int BASE_THRESHOLD = 16; + /** Default Threshold for Multithreaded Sorting Algorythm options*/ + public static final int PARALLEL_THRESHOLD = 8192; + + /** Empty Array Reference used for Uninitialized Collections */ + public static final long[] EMPTY_ARRAY = new long[0]; + + /** + * A Helper function to convert a Primitive Array to a Long Array. + * @param a the array that should be converted + * @return a Long Array of the input array. + */ + public static Long[] wrap(long[] a) { + return wrap(a, 0, a.length); + } + + /** + * A Helper function to convert a Primitive Array to a Long Array. + * @param a the array that should be converted + * @param length the maximum length that should be coverted + * @return a Long Array of the input array. + */ + public static Long[] wrap(long[] a, int length) { + return wrap(a, 0, length); + } + + /** + * A Helper function to convert a Primitive Array to a Long Array. + * @param a the array that should be converted + * @param offset the starting offset of the inputarray + * @param length the maximum length that should be coverted + * @return a Long Array of the input array. + */ + public static Long[] wrap(long[] a, int offset, int length) { + SanityChecks.checkArrayCapacity(a.length, offset, length); + Long[] result = new Long[length]; + for(int i = offset;i>> 1; + long value = data[index]; + if(comp != null) { + while(index < half) { + int child = (index << 1) + 1; + long childValue = data[child]; + int right = child+1; + if(right < size && comp.compare(data[right], childValue) < 0) childValue = data[child = right]; + if(comp.compare(value, childValue) <= 0) break; + data[index] = childValue; + index = child; + } + } + else { + while(index < half) { + int child = (index << 1) + 1; + long childValue = data[child]; + int right = child+1; + if(right < size && Long.compare(data[right], childValue) < 0) childValue = data[child = right]; + if(Long.compare(value, childValue) <= 0) break; + data[index] = childValue; + index = child; + } + } + data[index] = value; + return index; + } + + /** + * Method to sort a specific value into the heap. + * @param data the heap itself. + * @param index that should be heapified. + * @param comp the comparator to sort the heap. Can be null + * @return the index the element was shifted to + */ + public static int shiftUp(long[] data, int index, LongComparator comp) { + long value = data[index]; + if(comp != null) { + while(index > 0) { + int parent = (index - 1) >>> 1; + long parentValue = data[parent]; + if(comp.compare(value, parentValue) >= 0) break; + data[index] = parentValue; + index = parent; + } + } + else { + while(index > 0) { + int parent = (index - 1) >>> 1; + long parentValue = data[parent]; + if(Long.compare(value, parentValue) >= 0) break; + data[index] = parentValue; + index = parent; + } + } + data[index] = value; + return index; + } + + /** + * Helper function to create a Heap out of an array. + * @param data the array to heapify + * @param size the current size of elements within the array. + * @param comp the Comparator to sort the array. Can be null + * @return the input array + */ + public static long[] heapify(long[] data, int size, LongComparator comp) { + for(int i = (size >>> 1) - 1;i>=0;shiftDown(data, size, i--, comp)); + return data; + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @note This uses the SanityChecks#getRandom + * @return the provided sorted array + */ + public static long[] shuffle(long[] array) { + return shuffle(array, SanityChecks.getRandom()); + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @param length the length of the array + * @note This uses the SanityChecks#getRandom + * @return the provided sorted array + */ + public static long[] shuffle(long[] array, int length) { + return shuffle(array, 0, length, SanityChecks.getRandom()); + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @param offset the start array + * @param length the length of the array + * @note This uses the SanityChecks#getRandom + * @return the provided sorted array + */ + public static long[] shuffle(long[] array, int offset, int length) { + return shuffle(array, offset, length, SanityChecks.getRandom()); + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @param random the Random Number Generator that should be used for the shuffling + * @return the provided sorted array + */ + public static long[] shuffle(long[] array, Random random) { + for(int i = array.length-1; i>=0;i--) { + int p = random.nextInt(i + 1); + long t = array[i]; + array[i] = array[p]; + array[p] = t; + } + return array; + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @param length the length of the array + * @param random the Random Number Generator that should be used for the shuffling + * @return the provided sorted array + */ + public static long[] shuffle(long[] array, int length, Random random) { + return shuffle(array, 0, length, random); + } + + /** + * Simple Shuffle method for Arrays. + * @param array the elements that should be shuffled + * @param offset the start array + * @param length the length of the array + * @param random the Random Number Generator that should be used for the shuffling + * @return the provided sorted array + */ + public static long[] shuffle(long[] array, int offset, int length, Random random) { + for(int i = length-1; i>=0;i--) { + int p = offset + random.nextInt(i + 1); + long t = array[offset+i]; + array[offset+i] = array[p]; + array[p] = t; + } + return array; + } + + /** + * Simple Array Reversal method + * @param array the Array that should flip + * @return the provided array + */ + public static long[] reverse(long[] array) { + return reverse(array, 0, array.length); + } + + /** + * Simple Array Reversal method + * @param array the Array that should flip + * @param length the length of the array + * @return the provided array + */ + public static long[] reverse(long[] array, int length) { + return reverse(array, 0, length); + } + + /** + * Simple Array Reversal method + * @param array the Array that should flip + * @param length the length of the array + * @param offset the start of the array + * @return the provided array + */ + public static long[] reverse(long[] array, int offset, int length) { + for (int i = offset, mid = offset + length >> 1, j = offset + length - 1; i < mid; i++, j--) { + long temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array. + */ + public static long[] stableSort(long[] array, LongComparator comp) { + stableSort(array, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void stableSort(long[] array, int length, LongComparator comp) { + stableSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void stableSort(long[] array, int from, int to, LongComparator comp) { + mergeSort(array, null, from, to, comp); + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @return input array + */ + public static long[] stableSort(long[] array) { + stableSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void stableSort(long[] array, int length) { + stableSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Stable sort referres to Mergesort or Insertionsort + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void stableSort(long[] array, int from, int to) { + mergeSort(array, null, from, to); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array + */ + public static long[] unstableSort(long[] array, LongComparator comp) { + unstableSort(array, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void unstableSort(long[] array, int length, LongComparator comp) { + unstableSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void unstableSort(long[] array, int from, int to, LongComparator comp) { + quickSort(array, from, to, comp); + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @return input array + */ + public static long[] unstableSort(long[] array) { + unstableSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void unstableSort(long[] array, int length) { + unstableSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order, + * potentially dynamically choosing an appropriate algorithm given the type and size of the array. + * Unstable sort referres to QuickSort or SelectionSort + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void unstableSort(long[] array, int from, int to) { + quickSort(array, from, to); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array + */ + public static long[] insertionSort(long[] array, LongComparator comp) { + insertionSort(array, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void insertionSort(long[] array, int length, LongComparator comp) { + insertionSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void insertionSort(long[] array, int from, int to, LongComparator comp) { + for (int i = from+1;i= from && comp.compare(current, array[j]) < 0) { + array[j+1] = array[j--]; + } + array[j+1] = current; + } + } + + /** + * Sorts an array according to the natural ascending order using InsertionSort, + * @param array the array that needs to be sorted + * @return input array + */ + public static long[] insertionSort(long[] array) { + insertionSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order using InsertionSort, + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void insertionSort(long[] array, int length) { + insertionSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using InsertionSort, + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void insertionSort(long[] array, int from, int to) { + for (int i = from+1;i= from && Long.compare(current, array[j]) < 0) { + array[j+1] = array[j--]; + } + array[j+1] = current; + } + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array + */ + public static long[] selectionSort(long[] array, LongComparator comp) { + selectionSort(array, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void selectionSort(long[] array, int length, LongComparator comp) { + selectionSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void selectionSort(long[] array, int from, int to, LongComparator comp) { + for (int i = from; i < to; i++) { + long min = array[i]; + int minId = i; + for(int j = i+1; j < to; j++) { + if(comp.compare(array[j], min) < 0) { + min = array[j]; + minId = j; + } + } + long temp = array[i]; + array[i] = min; + array[minId] = temp; + } + } + + /** + * Sorts an array according to the natural ascending order using Selection Sort, + * @param array the array that needs to be sorted + * @return input array + */ + public static long[] selectionSort(long[] array) { + selectionSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order using Selection Sort, + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void selectionSort(long[] array, int length) { + selectionSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Selection Sort, + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void selectionSort(long[] array, int from, int to) { + for (int i = from; i < to; i++) { + long min = array[i]; + int minId = i; + for(int j = i+1; j < to; j++) { + if(Long.compare(array[j], min) < 0) { + min = array[j]; + minId = j; + } + } + long temp = array[i]; + array[i] = min; + array[minId] = temp; + } + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array + */ + public static long[] mergeSort(long[] array, LongComparator comp) { + mergeSort(array, null, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void mergeSort(long[] array, int length, LongComparator comp) { + mergeSort(array, null, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param supp the auxillary array that is used to simplify the sorting + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void mergeSort(long[] array, long[] supp, int from, int to, LongComparator comp) { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to, comp); + return; + } + if(supp == null) supp = Arrays.copyOf(array, to); + int mid = (from + to) >>> 1; + mergeSort(supp, array, from, mid, comp); + mergeSort(supp, array, mid, to, comp); + if(comp.compare(supp[mid - 1], supp[mid]) <= 0) + { + System.arraycopy(supp, from, array, from, to - from); + return; + } + for(int p = from, q = mid;from < to;from++) { + if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; + else array[from] = supp[q++]; + } + } + + /** + * Sorts an array according to the natural ascending order using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @return input array + */ + public static long[] mergeSort(long[] array) { + mergeSort(array, null, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void mergeSort(long[] array, int length) { + mergeSort(array, null, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param supp the auxillary array that is used to simplify the sorting + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void mergeSort(long[] array, long[] supp, int from, int to) { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to); + return; + } + if(supp == null) supp = Arrays.copyOf(array, to); + int mid = (from + to) >>> 1; + mergeSort(supp, array, from, mid); + mergeSort(supp, array, mid, to); + if(Long.compare(supp[mid - 1], supp[mid]) <= 0) + { + System.arraycopy(supp, from, array, from, to - from); + return; + } + for(int p = from, q = mid;from < to;from++) { + if(q >= to || p < mid && Long.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; + else array[from] = supp[q++]; + } + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using a Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(long[] array, LongComparator comp) { + parallelMergeSort(array, null, 0, array.length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(long[] array, int length, LongComparator comp) { + parallelMergeSort(array, null, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param supp the auxillary array that is used to simplify the sorting + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(long[] array, long[] supp, int from, int to, LongComparator comp) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new MergeSortActionComp(array, supp, from, to, comp)); + return; + } + mergeSort(array, supp, from, to, comp); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(long[] array) { + parallelMergeSort(array, null, 0, array.length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(long[] array, int length) { + parallelMergeSort(array, null, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Merge Sort, + * This implementation was copied from FastUtil with a couple custom optimizations + * @param array the array that needs to be sorted + * @param supp the auxillary array that is used to simplify the sorting + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMergeSort(long[] array, long[] supp, int from, int to) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new MergeSortAction(array, supp, from, to)); + return; + } + mergeSort(array, supp, from, to); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void memFreeMergeSort(long[] array, LongComparator comp) { + memFreeMergeSort(array, 0, array.length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void memFreeMergeSort(long[] array, int length, LongComparator comp) { + memFreeMergeSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void memFreeMergeSort(long[] array, int from, int to, LongComparator comp) { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to, comp); + return; + } + int mid = (from + to) >>> 1; + memFreeMergeSort(array, from, mid, comp); + memFreeMergeSort(array, mid, to, comp); + if(comp.compare(array[mid - 1], array[mid]) <= 0) + return; + for(int i = from, j = mid, compare;i < j && j < to;) { + if((compare = comp.compare(array[i], array[j])) < 0) + i++; + else if(compare == 0) swap(array, ++i, j); + else { + int k = j; + for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); + continue; + } + else if(j + 1 == k) { + long value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + long[] data = new long[k - j]; + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; + } + } + } + + /** + * Sorts an array according to the natural ascending order using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @return input array + */ + public static long[] memFreeMergeSort(long[] array) { + memFreeMergeSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void memFreeMergeSort(long[] array, int length) { + memFreeMergeSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void memFreeMergeSort(long[] array, int from, int to) { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to); + return; + } + int mid = (from + to) >>> 1; + memFreeMergeSort(array, from, mid); + memFreeMergeSort(array, mid, to); + if(Long.compare(array[mid - 1], array[mid]) <= 0) + return; + for(int i = from, j = mid, comp;i < j && j < to;) { + if((comp = Long.compare(array[i], array[j])) < 0) + i++; + else if(comp == 0) swap(array, ++i, j); + else { + int k = j; + for(;k < to - 1 && Long.compare(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); + continue; + } + else if(j + 1 == k) { + long value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + long[] data = new long[k - j]; + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; + } + } + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(long[] array, LongComparator comp) { + parallelMemFreeMergeSort(array, 0, array.length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(long[] array, int length, LongComparator comp) { + parallelMemFreeMergeSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(long[] array, int from, int to, LongComparator comp) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new MemFreeMergeSortActionComp(array, from, to, comp)); + return; + } + memFreeMergeSort(array, from, to, comp); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(long[] array) { + parallelMemFreeMergeSort(array, 0, array.length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(long[] array, int length) { + parallelMemFreeMergeSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelMemFreeMergeSort(long[] array, int from, int to) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new MemFreeMergeSortAction(array, from, to)); + return; + } + memFreeMergeSort(array, from, to); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @return input array + */ + public static long[] quickSort(long[] array, LongComparator comp) { + quickSort(array, 0, array.length, comp); + return array; + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + */ + public static void quickSort(long[] array, int length, LongComparator comp) { + quickSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + */ + public static void quickSort(long[] array, int from, int to, LongComparator comp) { + int length = to - from; + if(length <= 0) return; + if(length < BASE_THRESHOLD) { + selectionSort(array, from, to, comp); + return; + } + long pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)]; + int a = from, b = a, c = to - 1, d = c; + for(int compare;;swap(array, b++, c--)) { + for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) { + if(compare == 0) swap(array, a++, b); + } + for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) { + if(compare == 0) swap(array, c, d--); + } + if(b>c) break; + } + swap(array, from, b, Math.min(a - from, b - a)); + swap(array, b, to, Math.min(d - c, to - d - 1)); + if((length = b - a) > 1) quickSort(array, from, from + length, comp); + if((length = d - c) > 1) quickSort(array, to - length, to, comp); + } + + /** + * Sorts an array according to the natural ascending order using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @return input array + */ + public static long[] quickSort(long[] array) { + quickSort(array, 0, array.length); + return array; + } + + /** + * Sorts an array according to the natural ascending order using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + */ + public static void quickSort(long[] array, int length) { + quickSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + */ + public static void quickSort(long[] array, int from, int to) { + int length = to - from; + if(length <= 0) return; + if(length < BASE_THRESHOLD) { + selectionSort(array, from, to); + return; + } + long pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)]; + int a = from, b = a, c = to - 1, d = c; + for(int comp = 0;;swap(array, b++, c--)) { + for(;b<=c && (comp = Long.compare(array[b], pivot)) <= 0;b++) { + if(comp == 0) swap(array, a++, b); + } + for(;c>=b && (comp = Long.compare(array[c], pivot)) >= 0;c--) { + if(comp == 0) swap(array, c, d--); + } + if(b>c) break; + } + swap(array, from, b, Math.min(a - from, b - a)); + swap(array, b, to, Math.min(d - c, to - d - 1)); + if((length = b - a) > 1) quickSort(array, from, from + length); + if((length = d - c) > 1) quickSort(array, to - length, to); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(long[] array, LongComparator comp) { + parallelQuickSort(array, 0, array.length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(long[] array, int length, LongComparator comp) { + parallelQuickSort(array, 0, length, comp); + } + + /** + * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @param comp the Comparator that decides the sorting order + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(long[] array, int from, int to, LongComparator comp) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new QuickSortActionComp(array, from, to, comp)); + return; + } + quickSort(array, from, to, comp); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(long[] array) { + parallelQuickSort(array, 0, array.length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param length the maxmium size of the array to be sorted + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(long[] array, int length) { + parallelQuickSort(array, 0, length); + } + + /** + * Sorts an array according to the natural ascending order using Parallel Quick Sort, + * This implementation is a custom of FastUtil quicksort but with a different code structure, + * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. + * @param array the array that needs to be sorted + * @param from where the array should be sorted from + * @param to where the array should be sorted to + * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed + */ + public static void parallelQuickSort(long[] array, int from, int to) { + if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { + SanityChecks.invokeTask(new QuickSortAction(array, from, to)); + return; + } + quickSort(array, from, to); + } + + static void swap(long[] a, int from, int to) { + long t = a[from]; + a[from] = a[to]; + a[to] = t; + } + + static void swap(long[] a, int from, int to, int length) { + to -= length; + for(int i = 0;i 0 ? b : comp.compare(data[a], data[c]) > 0 ? c : a); + } + + static int subMedium(long[] data, int a, int b, int c, int length) { + return medium(data, medium(data, a, a + length, a + (length * 2)), medium(data, b - length, b, b + length), medium(data, c - (length * 2), c - length, c)); + } + + static int medium(long[] data, int a, int b, int c) { + return Long.compare(data[a], data[b]) < 0 ? (Long.compare(data[b], data[c]) < 0 ? b : Long.compare(data[a], data[c]) < 0 ? c : a) : (Long.compare(data[b], data[c]) > 0 ? b : Long.compare(data[a], data[c]) > 0 ? c : a); + } + + static class QuickSortAction extends RecursiveAction { + private static final long serialVersionUID = 0L; + long[] array; + int from; + int to; + + QuickSortAction(long[] array, int from, int to) + { + this.array = array; + this.from = from; + this.to = to; + } + + @Override + protected void compute() + { + int length = to - from; + if(length <= 0) return; + if(length < BASE_THRESHOLD) { + selectionSort(array, from, to); + return; + } + long pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)]; + int a = from, b = a, c = to - 1, d = c; + for(int comp = 0;;swap(array, b++, c--)) { + for(;b<=c && (comp = Long.compare(array[b], pivot)) <= 0;b++) { + if(comp == 0) swap(array, a++, b); + } + for(;c>=b && (comp = Long.compare(array[c], pivot)) >= 0;c--) { + if(comp == 0) swap(array, c, d--); + } + if(b>c) break; + } + swap(array, from, b, Math.min(a - from, b - a)); + swap(array, b, to, Math.min(d - c, to - d - 1)); + if(b - a > 1 && d - c > 1) invokeAll(new QuickSortAction(array, from, from + (b - a)), new QuickSortAction(array, to - (d - c), to)); + else if(b - a > 1) new QuickSortAction(array, from, from + (b - a)).invoke(); + else if(d - c > 1) new QuickSortAction(array, to - (d - c), to).invoke(); + } + } + + static class QuickSortActionComp extends RecursiveAction { + private static final long serialVersionUID = 0L; + long[] array; + int from; + int to; + LongComparator comp; + + QuickSortActionComp(long[] array, int from, int to, LongComparator comp) + { + this.array = array; + this.from = from; + this.to = to; + this.comp = comp; + } + + @Override + protected void compute() + { + int length = to - from; + if(length <= 0) return; + if(length < BASE_THRESHOLD) { + selectionSort(array, from, to, comp); + return; + } + long pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)]; + int a = from, b = a, c = to - 1, d = c; + for(int compare;;swap(array, b++, c--)) { + for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) { + if(compare == 0) swap(array, a++, b); + } + for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) { + if(compare == 0) swap(array, c, d--); + } + if(b>c) break; + } + swap(array, from, b, Math.min(a - from, b - a)); + swap(array, b, to, Math.min(d - c, to - d - 1)); + if(b - a > 1 && d - c > 1) invokeAll(new QuickSortActionComp(array, from, from + (b - a), comp), new QuickSortActionComp(array, to - (d - c), to, comp)); + else if(b - a > 1) new QuickSortActionComp(array, from, from + (b - a), comp).invoke(); + else if(d - c > 1) new QuickSortActionComp(array, to - (d - c), to, comp).invoke(); + } + } + + static class MergeSortAction extends RecursiveAction { + private static final long serialVersionUID = 0L; + long[] array; + long[] supp; + int from; + int to; + + MergeSortAction(long[] array, long[] supp, int from, int to) + { + this.array = array; + this.supp = supp; + this.from = from; + this.to = to; + } + + @Override + protected void compute() + { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to); + return; + } + if(supp == null) supp = Arrays.copyOf(array, to); + int mid = (from + to) >>> 1; + invokeAll(new MergeSortAction(supp, array, from, mid), new MergeSortAction(supp, array, mid, to)); + if(Long.compare(supp[mid - 1], supp[mid]) <= 0) + { + System.arraycopy(supp, from, array, from, to - from); + return; + } + for(int p = from, q = mid;from < to;from++) { + if(q >= to || p < mid && Long.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; + else array[from] = supp[q++]; + } + } + } + + static class MergeSortActionComp extends RecursiveAction { + private static final long serialVersionUID = 0L; + long[] array; + long[] supp; + int from; + int to; + LongComparator comp; + + MergeSortActionComp(long[] array, long[] supp, int from, int to, LongComparator comp) + { + this.array = array; + this.supp = supp; + this.from = from; + this.to = to; + this.comp = comp; + } + + @Override + protected void compute() + { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to, comp); + return; + } + if(supp == null) supp = Arrays.copyOf(array, to); + int mid = (from + to) >>> 1; + invokeAll(new MergeSortActionComp(supp, array, from, mid, comp), new MergeSortActionComp(supp, array, mid, to, comp)); + if(comp.compare(supp[mid - 1], supp[mid]) <= 0) + { + System.arraycopy(supp, from, array, from, to - from); + return; + } + for(int p = from, q = mid;from < to;from++) { + if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; + else array[from] = supp[q++]; + } + } + } + + static class MemFreeMergeSortAction extends RecursiveAction { + private static final long serialVersionUID = 0L; + long[] array; + int from; + int to; + + MemFreeMergeSortAction(long[] array, int from, int to) + { + this.array = array; + this.from = from; + this.to = to; + } + + @Override + protected void compute() + { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to); + return; + } + int mid = (from + to) >>> 1; + invokeAll(new MemFreeMergeSortAction(array, from, mid), new MemFreeMergeSortAction(array, mid, to)); + if(Long.compare(array[mid - 1], array[mid]) <= 0) + return; + for(int i = from, j = mid, comp;i < j && j < to;) { + if((comp = Long.compare(array[i], array[j])) < 0) + i++; + else if(comp == 0) swap(array, ++i, j); + else { + int k = j; + for(;k < to - 1 && Long.compare(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); + continue; + } + else if(j + 1 == k) { + long value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + long[] data = new long[k - j]; + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; + } + } + } + } + + static class MemFreeMergeSortActionComp extends RecursiveAction { + private static final long serialVersionUID = 0L; + long[] array; + int from; + int to; + LongComparator comp; + + MemFreeMergeSortActionComp(long[] array, int from, int to, LongComparator comp) + { + this.array = array; + this.from = from; + this.to = to; + this.comp = comp; + } + + @Override + protected void compute() + { + if(to - from < BASE_THRESHOLD) { + insertionSort(array, from, to, comp); + return; + } + int mid = (from + to) >>> 1; + invokeAll(new MemFreeMergeSortActionComp(array, from, mid, comp), new MemFreeMergeSortActionComp(array, mid, to, comp)); + + if(comp.compare(array[mid - 1], array[mid]) <= 0) + return; + for(int i = from, j = mid, compare;i < j && j < to;) { + if((compare = comp.compare(array[i], array[j])) < 0) + i++; + else if(compare == 0) swap(array, ++i, j); + else { + int k = j; + for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); + continue; + } + else if(j + 1 == k) { + long value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + long[] data = new long[k - j]; + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/utils/LongCollections.java b/src/main/java/speiger/src/collections/longs/utils/LongCollections.java new file mode 100644 index 000000000..18ed50122 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/utils/LongCollections.java @@ -0,0 +1,892 @@ +package speiger.src.collections.longs.utils; + +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.function.LongPredicate; +import java.util.function.Consumer; + +import speiger.src.collections.longs.collections.AbstractLongCollection; +import speiger.src.collections.longs.collections.LongCollection; +import speiger.src.collections.longs.collections.LongIterator; +import speiger.src.collections.longs.functions.LongComparator; +import speiger.src.collections.objects.utils.ObjectArrays; +import speiger.src.collections.longs.functions.LongConsumer; +import speiger.src.collections.longs.utils.LongArrays; +import speiger.src.collections.longs.functions.function.LongLongUnaryOperator; +import speiger.src.collections.ints.functions.consumer.IntLongConsumer; +import speiger.src.collections.objects.functions.consumer.ObjectLongConsumer; +import speiger.src.collections.utils.HashUtil; +import speiger.src.collections.utils.ITrimmable; +import speiger.src.collections.utils.SanityChecks; + +/** + * A Helper class for Collections + */ +public class LongCollections +{ + /** + * Empty Collection Reference + */ + public static final LongCollection EMPTY = new EmptyCollection(); + + /** + * Returns a Immutable EmptyCollection instance that is automatically casted. + * @return an empty collection + */ + public static LongCollection empty() { + return EMPTY; + } + + /** + * Returns a Immutable Collection instance based on the instance given. + * @param c that should be made immutable/unmodifiable + * @return a unmodifiable collection wrapper. If the Collection already a unmodifiable wrapper then it just returns itself. + */ + public static LongCollection unmodifiable(LongCollection c) { + return c instanceof UnmodifiableCollection ? c : new UnmodifiableCollection(c); + } + + /** + * Returns a synchronized Collection instance based on the instance given. + * @param c that should be synchronized + * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself. + */ + public static LongCollection synchronize(LongCollection c) { + return c instanceof SynchronizedCollection ? c : new SynchronizedCollection(c); + } + + /** + * Returns a synchronized Collection instance based on the instance given. + * @param c that should be synchronized + * @param mutex is the controller of the synchronization block. + * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself. + */ + public static LongCollection synchronize(LongCollection c, Object mutex) { + return c instanceof SynchronizedCollection ? c : new SynchronizedCollection(c, mutex); + } + + /** + * Creates a Singleton Collection of a given element + * @param element the element that should be converted into a singleton collection + * @return a singletoncollection of the given element + */ + public static LongCollection singleton(long element) { + return new SingletonCollection(element); + } + + protected static CollectionWrapper wrapper() { + return new CollectionWrapper(); + } + + protected static CollectionWrapper wrapper(int size) { + return new CollectionWrapper(size); + } + + protected static DistinctCollectionWrapper distinctWrapper() { + return new DistinctCollectionWrapper(); + } + + protected static DistinctCollectionWrapper distinctWrapper(int size) { + return new DistinctCollectionWrapper(size); + } + + protected static class CollectionWrapper extends AbstractLongCollection implements ITrimmable { + long[] elements; + int size = 0; + + public CollectionWrapper() { + this(10); + } + + public CollectionWrapper(int size) { + if(size < 0) throw new IllegalStateException("Size has to be 0 or greater"); + elements = new long[size]; + } + + @Override + public boolean add(long o) { + if(size >= elements.length) elements = Arrays.copyOf(elements, (int)Math.min((long)elements.length + (elements.length >> 1), SanityChecks.MAX_ARRAY_SIZE)); + elements[size++] = o; + return true; + } + + public long getLong(int index) { + if(index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + return elements[index]; + } + + @Override + public boolean remLong(long e) { + for(int i = 0;i= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + size--; + if(index != size) System.arraycopy(elements, index+1, elements, index, size - index); + } + + @Override + public LongIterator iterator() { + return new LongIterator() { + int index = 0; + int lastReturned = -1; + + @Override + public boolean hasNext() { + return index < size; + } + + @Override + public long nextLong() { + int i = index++; + return elements[(lastReturned = i)]; + } + + @Override + public void remove() { + if(lastReturned == -1) throw new IllegalStateException(); + removeIndex(lastReturned); + index = lastReturned; + lastReturned = -1; + } + }; + } + + @Override + public int size() { + return size; + } + + @Override + public void clear() { + size = 0; + } + + public void sort(LongComparator c) { + if(c != null) LongArrays.stableSort(elements, size, c); + else LongArrays.stableSort(elements, size); + } + + public void unstableSort(LongComparator c) { + if(c != null) LongArrays.unstableSort(elements, size, c); + else LongArrays.unstableSort(elements, size); + } + + @Override + public void forEach(LongConsumer action) { + Objects.requireNonNull(action); + for(int i = 0;i void forEach(E input, ObjectLongConsumer action) { + Objects.requireNonNull(action); + for(int i = 0;i size() || size() == elements.length) return false; + int value = Math.max(size, size()); + elements = value == 0 ? LongArrays.EMPTY_ARRAY : Arrays.copyOf(elements, value); + return true; + } + + @Override + public void clearAndTrim(int size) { + if(elements.length <= size) { + clear(); + return; + } + elements = size == 0 ? LongArrays.EMPTY_ARRAY : new long[size]; + this.size = size; + } + + @Override + @Deprecated + public Object[] toArray() { + Object[] obj = new Object[size]; + for(int i = 0;i E[] toArray(E[] a) { + if(a == null) a = (E[])new Object[size]; + else if(a.length < size) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), size); + for(int i = 0;i size) a[size] = null; + return a; + } + + @Override + public long[] toLongArray(long[] a) { + if(a.length < size) a = new long[size]; + System.arraycopy(elements, 0, a, 0, size); + if (a.length > size) a[size] = 0L; + return a; + } + } + + protected static class DistinctCollectionWrapper extends AbstractLongCollection { + long[] keys; + boolean containsNull; + int minCapacity; + int nullIndex; + int maxFill; + int mask; + int size; + + public DistinctCollectionWrapper() { + this(HashUtil.DEFAULT_MIN_CAPACITY); + } + + public DistinctCollectionWrapper(int size) { + if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); + minCapacity = nullIndex = HashUtil.arraySize(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR); + mask = nullIndex - 1; + maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1); + keys = new long[nullIndex + 1]; + } + + @Override + public boolean add(long o) { + if(o == 0) { + if(containsNull) return false; + containsNull = true; + } + else { + int pos = HashUtil.mix(Long.hashCode(o)) & mask; + long current = keys[pos]; + if(current != 0) { + if(current == o) return false; + while((current = keys[pos = (++pos & mask)]) != 0) + if(current == o) return false; + } + keys[pos] = o; + } + if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, HashUtil.DEFAULT_LOAD_FACTOR)); + return true; + } + + @Override + public boolean contains(Object o) { + if(o == null) return false; + if(o instanceof Long && ((Long)o).longValue() == 0L) return containsNull; + int pos = HashUtil.mix(o.hashCode()) & mask; + long current = keys[pos]; + if(current == 0) return false; + if(Objects.equals(o, Long.valueOf(current))) return true; + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(Objects.equals(o, Long.valueOf(current))) return true; + } + } + + @Override + public boolean remove(Object o) { + if(o == null) return false; + if(o instanceof Long && ((Long)o).longValue() == 0L) return (containsNull ? removeNullIndex() : false); + int pos = HashUtil.mix(o.hashCode()) & mask; + long current = keys[pos]; + if(current == 0) return false; + if(Objects.equals(o, Long.valueOf(current))) return removeIndex(pos); + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(Objects.equals(o, Long.valueOf(current))) return removeIndex(pos); + } + } + + @Override + public boolean contains(long o) { + if(o == 0) return containsNull; + int pos = HashUtil.mix(Long.hashCode(o)) & mask; + long current = keys[pos]; + if(current == 0) return false; + if(current == o) return true; + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(current == o) return true; + } + } + + @Override + public boolean remLong(long o) { + if(o == 0) return containsNull ? removeNullIndex() : false; + int pos = HashUtil.mix(Long.hashCode(o)) & mask; + long current = keys[pos]; + if(current == 0) return false; + if(current == o) return removeIndex(pos); + while(true) { + if((current = keys[pos = (++pos & mask)]) == 0) return false; + else if(current == o) return removeIndex(pos); + } + } + + protected boolean removeIndex(int pos) { + if(pos == nullIndex) return containsNull ? removeNullIndex() : false; + keys[pos] = 0L; + size--; + shiftKeys(pos); + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return true; + } + + protected boolean removeNullIndex() { + containsNull = false; + keys[nullIndex] = 0L; + size--; + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return true; + } + + @Override + public LongIterator iterator() { + return new SetIterator(); + } + + @Override + public void forEach(LongConsumer action) { + if(size() <= 0) return; + if(containsNull) action.accept(keys[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) { + if(keys[i] != 0) action.accept(keys[i]); + } + } + + @Override + public DistinctCollectionWrapper copy() { + DistinctCollectionWrapper set = new DistinctCollectionWrapper(0); + set.minCapacity = minCapacity; + set.mask = mask; + set.maxFill = maxFill; + set.nullIndex = nullIndex; + set.containsNull = containsNull; + set.size = size; + set.keys = Arrays.copyOf(keys, keys.length); + return set; + } + + protected void shiftKeys(int startPos) { + int slot, last; + long current; + while(true) { + startPos = ((last = startPos) + 1) & mask; + while(true){ + if((current = keys[startPos]) == 0) { + keys[last] = 0L; + return; + } + slot = HashUtil.mix(Long.hashCode(current)) & mask; + if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; + startPos = ++startPos & mask; + } + keys[last] = current; + } + } + + protected void rehash(int newSize) { + int newMask = newSize - 1; + long[] newKeys = new long[newSize + 1]; + for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) { + while(true) { + if(--i < 0) throw new ConcurrentModificationException("Set was modified during rehash"); + if(keys[i] != 0) break; + } + if(newKeys[pos = HashUtil.mix(Long.hashCode(keys[i])) & newMask] != 0) + while(newKeys[pos = (++pos & newMask)] != 0); + newKeys[pos] = keys[i]; + } + nullIndex = newSize; + mask = newMask; + maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1); + keys = newKeys; + } + + @Override + public void clear() { + if(size == 0) return; + size = 0; + containsNull = false; + Arrays.fill(keys, 0L); + } + + @Override + public int size() { + return size; + } + + private class SetIterator implements LongIterator { + int pos = nullIndex; + int returnedPos = -1; + int lastReturned = -1; + int nextIndex = Integer.MIN_VALUE; + boolean returnNull = containsNull; + long[] wrapped = null; + int wrappedIndex = 0; + + @Override + public boolean hasNext() { + if(nextIndex == Integer.MIN_VALUE) { + if(returnNull) { + returnNull = false; + nextIndex = nullIndex; + } + else + { + while(true) { + if(--pos < 0) { + if(wrapped == null || wrappedIndex <= -pos - 1) break; + nextIndex = -pos - 1; + break; + } + if(keys[pos] != 0){ + nextIndex = pos; + break; + } + } + } + } + return nextIndex != Integer.MIN_VALUE; + } + + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + returnedPos = pos; + if(nextIndex < 0){ + lastReturned = Integer.MAX_VALUE; + long value = wrapped[nextIndex]; + nextIndex = Integer.MIN_VALUE; + return value; + } + long value = keys[(lastReturned = nextIndex)]; + nextIndex = Integer.MIN_VALUE; + return value; + } + + @Override + public void remove() { + if(lastReturned == -1) throw new IllegalStateException(); + if(lastReturned == nullIndex) { + containsNull = false; + keys[nullIndex] = 0L; + } + else if(returnedPos >= 0) shiftKeys(returnedPos); + else { + DistinctCollectionWrapper.this.remLong(wrapped[-returnedPos - 1]); + lastReturned = -1; + return; + } + size--; + lastReturned = -1; + } + + private void shiftKeys(int startPos) { + int slot, last; + long current; + while(true) { + startPos = ((last = startPos) + 1) & mask; + while(true){ + if((current = keys[startPos]) == 0) { + keys[last] = 0L; + return; + } + slot = HashUtil.mix(Long.hashCode(current)) & mask; + if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; + startPos = ++startPos & mask; + } + if(startPos < last) addWrapper(keys[startPos]); + keys[last] = current; + } + } + + private void addWrapper(long value) { + if(wrapped == null) wrapped = new long[2]; + else if(wrappedIndex >= wrapped.length) { + long[] newArray = new long[wrapped.length * 2]; + System.arraycopy(wrapped, 0, newArray, 0, wrapped.length); + wrapped = newArray; + } + wrapped[wrappedIndex++] = value; + } + } + } + + private static class SingletonCollection extends AbstractLongCollection + { + long element; + + SingletonCollection(long element) { + this.element = element; + } + + @Override + public boolean remLong(long o) { throw new UnsupportedOperationException(); } + @Override + public boolean add(long o) { throw new UnsupportedOperationException(); } + @Override + public LongIterator iterator() + { + return new LongIterator() { + boolean next = true; + @Override + public boolean hasNext() { return next; } + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + next = false; + return element; + } + }; + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Collection)) + return false; + Collection l = (Collection)o; + if(l.size() != size()) return false; + Iterator iter = l.iterator(); + if (iter.hasNext() && !Objects.equals(element, iter.next())) { + return false; + } + return !iter.hasNext(); + } + + @Override + public int hashCode() { + return Long.hashCode(element); + } + + @Override + public int size() { return 1; } + + @Override + public SingletonCollection copy() { return new SingletonCollection(element); } + } + + /** + * Synchronized Collection Wrapper for the synchronizedCollection function + */ + public static class SynchronizedCollection implements LongCollection { + LongCollection c; + protected Object mutex; + + SynchronizedCollection(LongCollection c) { + this.c = c; + mutex = this; + } + + SynchronizedCollection(LongCollection c, Object mutex) { + this.c = c; + this.mutex = mutex; + } + + @Override + public boolean add(long o) { synchronized(mutex) { return c.add(o); } } + @Override + public boolean addAll(Collection c) { synchronized(mutex) { return this.c.addAll(c); } } + @Override + public boolean addAll(LongCollection c) { synchronized(mutex) { return this.c.addAll(c); } } + @Override + public boolean addAll(long[] e, int offset, int length) { synchronized(mutex) { return c.addAll(e, offset, length); } } + @Override + public boolean contains(long o) { synchronized(mutex) { return c.contains(o); } } + @Override + @Deprecated + public boolean containsAll(Collection c) { synchronized(mutex) { return this.c.containsAll(c); } } + + @Override + @Deprecated + public boolean containsAny(Collection c) { synchronized(mutex) { return this.c.containsAny(c); } } + + @Override + public boolean containsAll(LongCollection c) { synchronized(mutex) { return this.c.containsAll(c); } } + + @Override + public boolean containsAny(LongCollection c) { synchronized(mutex) { return this.c.containsAny(c); } } + + @Override + public int size() { synchronized(mutex) { return c.size(); } } + + @Override + public boolean isEmpty() { synchronized(mutex) { return c.isEmpty(); } } + + @Override + public LongIterator iterator() { + return c.iterator(); + } + + @Override + public LongCollection copy() { synchronized(mutex) { return c.copy(); } } + + @Override + @Deprecated + public boolean remove(Object o) { synchronized(mutex) { return c.remove(o); } } + @Override + @Deprecated + public boolean removeAll(Collection c) { synchronized(mutex) { return this.c.removeAll(c); } } + @Override + @Deprecated + public boolean retainAll(Collection c) { synchronized(mutex) { return this.c.retainAll(c); } } + @Override + public boolean remLong(long o) { synchronized(mutex) { return c.remLong(o); } } + @Override + public boolean removeAll(LongCollection c) { synchronized(mutex) { return this.c.removeAll(c); } } + @Override + public boolean removeAll(LongCollection c, LongConsumer r) { synchronized(mutex) { return this.c.removeAll(c, r); } } + @Override + public boolean retainAll(LongCollection c) { synchronized(mutex) { return this.c.retainAll(c); } } + @Override + public boolean retainAll(LongCollection c, LongConsumer r) { synchronized(mutex) { return this.c.retainAll(c, r); } } + @Override + public boolean remIf(LongPredicate filter){ synchronized(mutex) { return c.remIf(filter); } } + @Override + public void clear() { synchronized(mutex) { c.clear(); } } + @Override + public Object[] toArray() { synchronized(mutex) { return c.toArray(); } } + @Override + public T[] toArray(T[] a) { synchronized(mutex) { return c.toArray(a); } } + @Override + public long[] toLongArray() { synchronized(mutex) { return c.toLongArray(); } } + @Override + public long[] toLongArray(long[] a) { synchronized(mutex) { return c.toLongArray(a); } } + @Override + public void forEach(LongConsumer action) { synchronized(mutex) { c.forEach(action); } } + @Override + @Deprecated + public void forEach(Consumer action) { synchronized(mutex) { c.forEach(action); } } + @Override + public void forEachIndexed(IntLongConsumer action) { synchronized(mutex) { c.forEachIndexed(action); } } + @Override + public int hashCode() { synchronized(mutex) { return c.hashCode(); } } + @Override + public boolean equals(Object obj) { + if(obj == this) return true; + synchronized(mutex) { return c.equals(obj); } + } + @Override + public String toString() { synchronized(mutex) { return c.toString(); } } + @Override + public void forEach(E input, ObjectLongConsumer action) { synchronized(mutex) { c.forEach(input, action); } } + @Override + public boolean matchesAny(LongPredicate filter) { synchronized(mutex) { return c.matchesAny(filter); } } + @Override + public boolean matchesNone(LongPredicate filter) { synchronized(mutex) { return c.matchesNone(filter); } } + @Override + public boolean matchesAll(LongPredicate filter) { synchronized(mutex) { return c.matchesAll(filter); } } + @Override + public long reduce(long identity, LongLongUnaryOperator operator) { synchronized(mutex) { return c.reduce(identity, operator); } } + @Override + public long reduce(LongLongUnaryOperator operator) { synchronized(mutex) { return c.reduce(operator); } } + @Override + public long findFirst(LongPredicate filter) { synchronized(mutex) { return c.findFirst(filter); } } + @Override + public int count(LongPredicate filter) { synchronized(mutex) { return c.count(filter); } } + } + + /** + * Unmodifyable Collection Wrapper for the unmodifyableCollection method + */ + public static class UnmodifiableCollection implements LongCollection { + LongCollection c; + + UnmodifiableCollection(LongCollection c) { + this.c = c; + } + + @Override + public boolean add(long o) { throw new UnsupportedOperationException(); } + @Override + public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } + @Override + public boolean addAll(LongCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean addAll(long[] e, int offset, int length) { throw new UnsupportedOperationException(); } + @Override + public boolean contains(long o) { return c.contains(o); } + @Override + public boolean containsAll(LongCollection c) { return this.c.containsAll(c); } + @Override + public boolean containsAny(LongCollection c) { return this.c.containsAny(c); } + @Override + @Deprecated + public boolean containsAny(Collection c) { return this.c.containsAny(c); } + @Override + @Deprecated + public boolean containsAll(Collection c) { return this.c.containsAll(c); } + @Override + public int size() { return c.size(); } + @Override + public boolean isEmpty() { return c.isEmpty(); } + @Override + public LongIterator iterator() { return LongIterators.unmodifiable(c.iterator()); } + @Override + public LongCollection copy() { return c.copy(); } + @Override + @Deprecated + public boolean remove(Object o) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); } + @Override + public boolean remLong(long o) { throw new UnsupportedOperationException(); } + @Override + public boolean removeAll(LongCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean removeAll(LongCollection c, LongConsumer r) { throw new UnsupportedOperationException(); } + @Override + public boolean retainAll(LongCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean retainAll(LongCollection c, LongConsumer r) { throw new UnsupportedOperationException(); } + @Override + public boolean remIf(LongPredicate filter){ throw new UnsupportedOperationException(); } + @Override + public void clear() { throw new UnsupportedOperationException(); } + @Override + public Object[] toArray() { return c.toArray(); } + @Override + public T[] toArray(T[] a) { return c.toArray(a); } + @Override + public long[] toLongArray() { return c.toLongArray(); } + @Override + public long[] toLongArray(long[] a) { return c.toLongArray(a); } + @Override + public void forEach(LongConsumer action) { c.forEach(action); } + @Override + @Deprecated + public void forEach(Consumer action) { c.forEach(action); } + @Override + public void forEachIndexed(IntLongConsumer action) { c.forEachIndexed(action); } + @Override + public int hashCode() { return c.hashCode(); } + @Override + public boolean equals(Object obj) { return obj == this || c.equals(obj); } + @Override + public String toString() { return c.toString(); } + @Override + public void forEach(E input, ObjectLongConsumer action) { c.forEach(input, action); } + @Override + public boolean matchesAny(LongPredicate filter) { return c.matchesAny(filter); } + @Override + public boolean matchesNone(LongPredicate filter) { return c.matchesNone(filter); } + @Override + public boolean matchesAll(LongPredicate filter) { return c.matchesAll(filter); } + @Override + public long reduce(long identity, LongLongUnaryOperator operator) { return c.reduce(identity, operator); } + @Override + public long reduce(LongLongUnaryOperator operator) { return c.reduce(operator); } + @Override + public long findFirst(LongPredicate filter) { return c.findFirst(filter); } + @Override + public int count(LongPredicate filter) { return c.count(filter); } + } + + /** + * Empty Collection implementation for the empty collection function + */ + public static class EmptyCollection extends AbstractLongCollection { + @Override + public boolean add(long o) { throw new UnsupportedOperationException(); } + + @Override + public boolean addAll(LongCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean addAll(long[] e, int offset, int length) { throw new UnsupportedOperationException(); } + + @Override + public boolean contains(long o) { return false; } + @Override + public boolean containsAll(LongCollection c) { return c.isEmpty(); } + @Override + public boolean containsAny(LongCollection c) { return false; } + @Override + @Deprecated + public boolean containsAny(Collection c) { return false; } + @Override + @Deprecated + public boolean containsAll(Collection c) { return c.isEmpty(); } + @Override + public int hashCode() { return 0; } + + @Override + public boolean equals(Object o) { + if(o == this) return true; + if(!(o instanceof Collection)) return false; + return ((Collection)o).isEmpty(); + } + + @Override + @Deprecated + public boolean remove(Object o) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } + @Override + @Deprecated + public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); } + @Override + public boolean remLong(long o) { throw new UnsupportedOperationException(); } + @Override + public boolean removeAll(LongCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean retainAll(LongCollection c) { throw new UnsupportedOperationException(); } + @Override + public boolean remIf(LongPredicate filter){ throw new UnsupportedOperationException(); } + @Override + public Object[] toArray() { return ObjectArrays.EMPTY_ARRAY; } + @Override + public T[] toArray(T[] a) { + if(a != null && a.length > 0) + a[0] = null; + return a; + } + + @Override + public long[] toLongArray() { return LongArrays.EMPTY_ARRAY; } + @Override + public long[] toLongArray(long[] a) { + if(a != null && a.length > 0) + a[0] = 0L; + return a; + } + + @Override + public LongIterator iterator() { return LongIterators.empty(); } + @Override + public void clear() {} + @Override + public int size() { return 0; } + @Override + public EmptyCollection copy() { return this; } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/utils/LongIterables.java b/src/main/java/speiger/src/collections/longs/utils/LongIterables.java new file mode 100644 index 000000000..651724660 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/utils/LongIterables.java @@ -0,0 +1,485 @@ +package speiger.src.collections.longs.utils; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; +import java.util.function.LongPredicate; + +import speiger.src.collections.longs.collections.LongIterable; +import speiger.src.collections.longs.collections.LongCollection; +import speiger.src.collections.objects.collections.ObjectIterable; +import speiger.src.collections.objects.collections.ObjectIterator; +import speiger.src.collections.longs.functions.LongConsumer; +import speiger.src.collections.longs.functions.LongComparator; +import speiger.src.collections.longs.collections.LongIterator; +import speiger.src.collections.longs.functions.function.LongFunction; +import speiger.src.collections.utils.ISizeProvider; + +/** + * A Helper class for Iterables + */ +public class LongIterables +{ + /** + * A Helper function that maps a Java-Iterable into a new Type. + * @param iterable the iterable that should be mapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterable that is mapped to a new result + */ + public static ObjectIterable map(Iterable iterable, LongFunction mapper) { + return new MappedIterable<>(wrap(iterable), mapper); + } + + /** + * A Helper function that maps a Iterable into a new Type. + * @param iterable the iterable that should be mapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterable that is mapped to a new result + */ + public static ObjectIterable map(LongIterable iterable, LongFunction mapper) { + return new MappedIterable<>(iterable, mapper); + } + + /** + * A Helper function that flatMaps a Java-Iterable into a new Type. + * @param iterable the iterable that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type supplier. + * @param The return type. + * @return a iterable that is flatMapped to a new result + */ + public static > ObjectIterable flatMap(Iterable iterable, LongFunction mapper) { + return new FlatMappedIterable<>(wrap(iterable), mapper); + } + + /** + * A Helper function that flatMaps a Iterable into a new Type. + * @param iterable the iterable that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type supplier. + * @param The return type. + * @return a iterable that is flatMapped to a new result + */ + public static > ObjectIterable flatMap(LongIterable iterable, LongFunction mapper) { + return new FlatMappedIterable<>(iterable, mapper); + } + + /** + * A Helper function that flatMaps a Java-Iterable into a new Type. + * @param iterable the iterable that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterable that is flatMapped to a new result + */ + public static ObjectIterable arrayFlatMap(Iterable iterable, LongFunction mapper) { + return new FlatMappedArrayIterable<>(wrap(iterable), mapper); + } + + /** + * A Helper function that flatMaps a Iterable into a new Type. + * @param iterable the iterable that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterable that is flatMapped to a new result + */ + public static ObjectIterable arrayFlatMap(LongIterable iterable, LongFunction mapper) { + return new FlatMappedArrayIterable<>(iterable, mapper); + } + + /** + * A Helper function that filters out all desired elements from a Java-Iterable + * @param iterable that should be filtered. + * @param filter the filter that decides that should be let through + * @return a filtered iterable + */ + public static LongIterable filter(Iterable iterable, LongPredicate filter) { + return new FilteredIterable(wrap(iterable), filter); + } + + /** + * A Helper function that filters out all desired elements + * @param iterable that should be filtered. + * @param filter the filter that decides that should be let through + * @return a filtered iterable + */ + public static LongIterable filter(LongIterable iterable, LongPredicate filter) { + return new FilteredIterable(iterable, filter); + } + + /** + * A Helper function that filters out all duplicated elements. + * @param iterable that should be distinct + * @return a distinct iterable + */ + public static LongIterable distinct(LongIterable iterable) { + return new DistinctIterable(iterable); + } + + /** + * A Helper function that filters out all duplicated elements from a Java Iterable. + * @param iterable that should be distinct + * @return a distinct iterable + */ + public static LongIterable distinct(Iterable iterable) { + return new DistinctIterable(wrap(iterable)); + } + + /** + * A Helper function that repeats the Iterable a specific amount of times + * @param iterable that should be repeated + * @param repeats the amount of times the iterable should be repeated + * @return a repeating iterable + */ + public static LongIterable repeat(LongIterable iterable, int repeats) { + return new RepeatingIterable(iterable, repeats); + } + + /** + * A Helper function that repeats the Iterable a specific amount of times from a Java Iterable + * @param iterable that should be repeated + * @param repeats the amount of times the iterable should be repeated + * @return a repeating iterable + */ + public static LongIterable repeat(Iterable iterable, int repeats) { + return new RepeatingIterable(wrap(iterable), repeats); + } + + /** + * A Helper function that hard limits the Iterable to a specific size + * @param iterable that should be limited + * @param limit the amount of elements it should be limited to + * @return a limited iterable + */ + public static LongIterable limit(LongIterable iterable, long limit) { + return new LimitedIterable(iterable, limit); + } + + /** + * A Helper function that hard limits the Iterable to a specific size from a Java Iterable + * @param iterable that should be limited + * @param limit the amount of elements it should be limited to + * @return a limited iterable + */ + public static LongIterable limit(Iterable iterable, long limit) { + return new LimitedIterable(wrap(iterable), limit); + } + + /** + * A Helper function that sorts the Iterable. + * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. + * @param iterable that should be sorted + * @param sorter that sorts the iterable. Can be null. + * @return a sorted iterable. + */ + public static LongIterable sorted(LongIterable iterable, LongComparator sorter) { + return new SortedIterable(iterable, sorter); + } + + /** + * A Helper function that sorts the Iterable from a Java Iterable + * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. + * @param iterable that should be sorted + * @param sorter that sorts the iterable. Can be null. + * @return a sorted iterable. + */ + public static LongIterable sorted(Iterable iterable, LongComparator sorter) { + return new SortedIterable(wrap(iterable), sorter); + } + + /** + * A Helper function that allows to preview the result of a Iterable. + * @param iterable that should be peeked at + * @param action callback that receives the value before the iterable returns it + * @return a peeked iterable + */ + public static LongIterable peek(LongIterable iterable, LongConsumer action) { + return new PeekIterable(iterable, action); + } + + /** + * A Helper function that allows to preview the result of a Iterable from a Java Iterable + * @param iterable that should be peeked at + * @param action callback that receives the value before the iterable returns it + * @return a peeked iterable + */ + public static LongIterable peek(Iterable iterable, LongConsumer action) { + return new PeekIterable(wrap(iterable), action); + } + + /** + * A Wrapper function that wraps a Java-Iterable into a Type Specific Iterable + * @param iterable that should be wrapped + * @return a type specific iterable + */ + public static LongIterable wrap(Iterable iterable) { + return new WrappedIterable(iterable); + } + + private static class WrappedIterable implements LongIterable, ISizeProvider + { + Iterable iterable; + + public WrappedIterable(Iterable iterable) { + this.iterable = iterable; + } + + public LongIterator iterator() { + return LongIterators.wrap(iterable.iterator()); + } + + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : prov.size(); + } + + @Override + public void forEach(LongConsumer action) { + Objects.requireNonNull(action); + iterable.forEach(action); + } + } + + private static class MappedIterable implements ObjectIterable, ISizeProvider + { + LongIterable iterable; + LongFunction mapper; + + MappedIterable(LongIterable iterable, LongFunction mapper) { + this.iterable = iterable; + this.mapper = mapper; + } + + public ObjectIterator iterator() { + return LongIterators.map(iterable.iterator(), mapper); + } + + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(this); + return prov == null ? -1 : prov.size(); + } + + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + iterable.forEach(E -> action.accept(mapper.apply(E))); + } + } + + private static class FlatMappedIterable> implements ObjectIterable + { + LongIterable iterable; + LongFunction mapper; + + FlatMappedIterable(LongIterable iterable, LongFunction mapper) { + this.iterable = iterable; + this.mapper = mapper; + } + + @Override + public ObjectIterator iterator() { + return LongIterators.flatMap(iterable.iterator(), mapper); + } + + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + iterable.forEach(E -> mapper.apply(E).forEach(action)); + } + + } + + private static class FlatMappedArrayIterable implements ObjectIterable + { + LongIterable iterable; + LongFunction mapper; + + FlatMappedArrayIterable(LongIterable iterable, LongFunction mapper) { + this.iterable = iterable; + this.mapper = mapper; + } + + @Override + public ObjectIterator iterator() { + return LongIterators.arrayFlatMap(iterable.iterator(), mapper); + } + + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + iterable.forEach(E -> { + T[] array = mapper.apply(E); + for(int i = 0,m=array.length;i { if(!filter.test(T)) action.accept(T); } ); + } + } + + private static class LimitedIterable implements LongIterable, ISizeProvider + { + LongIterable iterable; + long limit; + + public LimitedIterable(LongIterable iterable, long limit) { + this.iterable = iterable; + this.limit = limit; + } + + @Override + public LongIterator iterator() { + return LongIterators.limit(iterable.iterator(), limit); + } + + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : (int)Math.min(prov.size(), limit); + } + + @Override + public void forEach(LongConsumer action) { + Objects.requireNonNull(action); + AtomicLong counter = new AtomicLong(); + iterable.forEach(T -> { + if(counter.get() >= limit) return; + counter.incrementAndGet(); + action.accept(T); + }); + } + } + + private static class SortedIterable implements LongIterable, ISizeProvider + { + LongIterable iterable; + LongComparator sorter; + + public SortedIterable(LongIterable iterable, LongComparator sorter) { + this.iterable = iterable; + this.sorter = sorter; + } + + @Override + public LongIterator iterator() { + return LongIterators.sorted(iterable.iterator(), sorter); + } + + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : prov.size(); + } + + @Override + public void forEach(LongConsumer action) { + Objects.requireNonNull(action); + LongCollections.CollectionWrapper wrapper = LongCollections.wrapper(); + iterable.forEach(wrapper::add); + wrapper.unstableSort(sorter); + wrapper.forEach(action); + } + } + + private static class DistinctIterable implements LongIterable + { + LongIterable iterable; + + public DistinctIterable(LongIterable iterable) { + this.iterable = iterable; + } + + @Override + public LongIterator iterator() { + return LongIterators.distinct(iterable.iterator()); + } + + @Override + public void forEach(LongConsumer action) { + Objects.requireNonNull(action); + LongCollection filtered = LongCollections.distinctWrapper(); + iterable.forEach(T -> { if(filtered.add(T)) action.accept(T); }); + } + } + + private static class PeekIterable implements LongIterable, ISizeProvider + { + LongIterable iterable; + LongConsumer action; + + public PeekIterable(LongIterable iterable, LongConsumer action) { + this.iterable = iterable; + this.action = action; + } + + @Override + public LongIterator iterator() { + return LongIterators.peek(iterable.iterator(), action); + } + + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : prov.size(); + } + + @Override + public void forEach(LongConsumer action) { + Objects.requireNonNull(action); + iterable.forEach(this.action.andThen(action)); + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/utils/LongIterators.java b/src/main/java/speiger/src/collections/longs/utils/LongIterators.java new file mode 100644 index 000000000..2355d7ae8 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/utils/LongIterators.java @@ -0,0 +1,1003 @@ +package speiger.src.collections.longs.utils; + +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.function.LongPredicate; + +import speiger.src.collections.longs.collections.LongIterator; +import speiger.src.collections.objects.collections.ObjectIterator; +import speiger.src.collections.objects.utils.ObjectIterators; +import speiger.src.collections.longs.functions.LongConsumer; +import speiger.src.collections.longs.functions.LongComparator; +import speiger.src.collections.longs.functions.function.LongFunction; +import speiger.src.collections.longs.lists.LongListIterator; +import speiger.src.collections.longs.collections.LongBidirectionalIterator; +import speiger.src.collections.longs.collections.LongCollection; + +/** + * A Helper class for Iterators + */ +public class LongIterators +{ + /** + * Empty Iterator Reference + */ + private static final EmptyIterator EMPTY = new EmptyIterator(); + + /** + * Returns a Immutable EmptyIterator instance that is automatically casted. + * @return an empty iterator + */ + public static EmptyIterator empty() { + return EMPTY; + } + + /** + * Inverter function for Bidirectional Iterators + * @param it the iterator that should be inverted + * @return a Inverted Bidirectional Iterator. If it was inverted then it just gives back the original reference + */ + public static LongBidirectionalIterator invert(LongBidirectionalIterator it) { + return it instanceof ReverseBiIterator ? ((ReverseBiIterator)it).it : new ReverseBiIterator(it); + } + + /** + * Inverter function for List Iterators + * @param it the iterator that should be inverted + * @return a Inverted List Iterator. If it was inverted then it just gives back the original reference + */ + public static LongListIterator invert(LongListIterator it) { + return it instanceof ReverseListIterator ? ((ReverseListIterator)it).it : new ReverseListIterator(it); + } + + /** + * Returns a Immutable Iterator instance based on the instance given. + * @param iterator that should be made immutable/unmodifiable + * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself. + */ + public static LongIterator unmodifiable(LongIterator iterator) { + return iterator instanceof UnmodifiableIterator ? iterator : new UnmodifiableIterator(iterator); + } + + /** + * Returns a Immutable Iterator instance based on the instance given. + * @param iterator that should be made immutable/unmodifiable + * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself. + */ + public static LongBidirectionalIterator unmodifiable(LongBidirectionalIterator iterator) { + return iterator instanceof UnmodifiableBiIterator ? iterator : new UnmodifiableBiIterator(iterator); + } + + /** + * Returns a Immutable ListIterator instance based on the instance given. + * @param iterator that should be made immutable/unmodifiable + * @return a unmodifiable listiterator wrapper. If the ListIterator already a unmodifiable wrapper then it just returns itself. + */ + public static LongListIterator unmodifiable(LongListIterator iterator) { + return iterator instanceof UnmodifiableListIterator ? iterator : new UnmodifiableListIterator(iterator); + } + + /** + * A Helper function that maps a Java-Iterator into a new Type. + * @param iterator that should be mapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterator that is mapped to a new result + */ + public static ObjectIterator map(Iterator iterator, LongFunction mapper) { + return new MappedIterator<>(wrap(iterator), mapper); + } + + /** + * A Helper function that maps a Iterator into a new Type. + * @param iterator that should be mapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterator that is mapped to a new result + */ + public static ObjectIterator map(LongIterator iterator, LongFunction mapper) { + return new MappedIterator<>(iterator, mapper); + } + + /** + * A Helper function that flatMaps a Java-Iterator into a new Type. + * @param iterator that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type supplier. + * @param The return type. + * @return a iterator that is flatMapped to a new result + */ + public static > ObjectIterator flatMap(Iterator iterator, LongFunction mapper) { + return new FlatMappedIterator<>(wrap(iterator), mapper); + } + + /** + * A Helper function that flatMaps a Iterator into a new Type. + * @param iterator that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type supplier. + * @param The return type. + * @return a iterator that is flatMapped to a new result + */ + public static > ObjectIterator flatMap(LongIterator iterator, LongFunction mapper) { + return new FlatMappedIterator<>(iterator, mapper); + } + + /** + * A Helper function that flatMaps a Java-Iterator into a new Type. + * @param iterator that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterator that is flatMapped to a new result + */ + public static ObjectIterator arrayFlatMap(Iterator iterator, LongFunction mapper) { + return new FlatMappedArrayIterator<>(wrap(iterator), mapper); + } + + /** + * A Helper function that flatMaps a Iterator into a new Type. + * @param iterator that should be flatMapped + * @param mapper the function that decides what the result turns into. + * @param The return type. + * @return a iterator that is flatMapped to a new result + */ + public static ObjectIterator arrayFlatMap(LongIterator iterator, LongFunction mapper) { + return new FlatMappedArrayIterator<>(iterator, mapper); + } + + /** + * A Helper function that filters out all desired elements from a Java-Iterator + * @param iterator that should be filtered. + * @param filter the filter that decides that should be let through + * @return a filtered iterator + */ + public static LongIterator filter(Iterator iterator, LongPredicate filter) { + return new FilteredIterator(wrap(iterator), filter); + } + + /** + * A Helper function that filters out all desired elements + * @param iterator that should be filtered. + * @param filter the filter that decides that should be let through + * @return a filtered iterator + */ + public static LongIterator filter(LongIterator iterator, LongPredicate filter) { + return new FilteredIterator(iterator, filter); + } + + /** + * A Helper function that filters out all duplicated elements. + * @param iterator that should be distinct + * @return a distinct iterator + */ + public static LongIterator distinct(LongIterator iterator) { + return new DistinctIterator(iterator); + } + + /** + * A Helper function that filters out all duplicated elements from a Java Iterator. + * @param iterator that should be distinct + * @return a distinct iterator + */ + public static LongIterator distinct(Iterator iterator) { + return new DistinctIterator(wrap(iterator)); + } + + /** + * A Helper function that repeats the Iterator a specific amount of times + * @param iterator that should be repeated + * @param repeats the amount of times the iterator should be repeated + * @return a repeating iterator + */ + public static LongIterator repeat(LongIterator iterator, int repeats) { + return new RepeatingIterator(iterator, repeats); + } + + /** + * A Helper function that repeats the Iterator a specific amount of times from a Java Iterator + * @param iterator that should be repeated + * @param repeats the amount of times the iterator should be repeated + * @return a repeating iterator + */ + public static LongIterator repeat(Iterator iterator, int repeats) { + return new RepeatingIterator(wrap(iterator), repeats); + } + + /** + * A Helper function that hard limits the Iterator to a specific size + * @param iterator that should be limited + * @param limit the amount of elements it should be limited to + * @return a limited iterator + */ + public static LongIterator limit(LongIterator iterator, long limit) { + return new LimitedIterator(iterator, limit); + } + + /** + * A Helper function that hard limits the Iterator to a specific size from a Java Iterator + * @param iterator that should be limited + * @param limit the amount of elements it should be limited to + * @return a limited iterator + */ + public static LongIterator limit(Iterator iterator, long limit) { + return new LimitedIterator(wrap(iterator), limit); + } + + /** + * A Helper function that sorts the Iterator beforehand. + * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. + * @param iterator that should be sorted. + * @param sorter the sorter of the iterator. Can be null. + * @return a new sorted iterator + */ + public static LongIterator sorted(LongIterator iterator, LongComparator sorter) { + return new SortedIterator(iterator, sorter); + } + + /** + * A Helper function that sorts the Iterator beforehand from a Java Iterator. + * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. + * @param iterator that should be sorted. + * @param sorter the sorter of the iterator. Can be null. + * @return a new sorted iterator + */ + public static LongIterator sorted(Iterator iterator, LongComparator sorter) { + return new SortedIterator(wrap(iterator), sorter); + } + + /** + * A Helper function that allows to preview the result of a Iterator. + * @param iterator that should be peeked at + * @param action callback that receives the value before the iterator returns it + * @return a peeked iterator + */ + public static LongIterator peek(LongIterator iterator, LongConsumer action) { + return new PeekIterator(iterator, action); + } + + /** + * A Helper function that allows to preview the result of a Iterator from a Java Iterator + * @param iterator that should be peeked at + * @param action callback that receives the value before the iterator returns it + * @return a peeked iterator + */ + public static LongIterator peek(Iterator iterator, LongConsumer action) { + return new PeekIterator(wrap(iterator), action); + } + + /** + * Helper function to convert a Object Iterator into a Primitive Iterator + * @param iterator that should be converted to a unboxing iterator + * @return a primitive iterator + */ + public static LongIterator wrap(Iterator iterator) { + return iterator instanceof LongIterator ? (LongIterator)iterator : new IteratorWrapper(iterator); + } + + /** + * Returns a Array Wrapping iterator + * @param a the array that should be wrapped + * @return a Iterator that is wrapping a array. + */ + public static ArrayIterator wrap(long... a) { + return wrap(a, 0, a.length); + } + + /** + * Returns a Array Wrapping iterator + * @param a the array that should be wrapped. + * @param start the index to be started from. + * @param end the index that should be ended. + * @return a Iterator that is wrapping a array. + */ + public static ArrayIterator wrap(long[] a, int start, int end) { + return new ArrayIterator(a, start, end); + } + + /** + * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted + * @param a where the elements should be inserted + * @param i the source iterator + * @return the amount of elements that were inserted into the array. + */ + public static int unwrap(long[] a, Iterator i) { + return unwrap(a, i, 0, a.length); + } + + /** + * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted + * @param a where the elements should be inserted + * @param i the source iterator + * @param offset the array offset where the start should be + * @return the amount of elements that were inserted into the array. + */ + public static int unwrap(long[] a, Iterator i, int offset) { + return unwrap(a, i, offset, a.length - offset); + } + + /** + * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted + * @param a where the elements should be inserted + * @param i the source iterator + * @param offset the array offset where the start should be + * @param max the maximum values that should be extracted from the source + * @return the amount of elements that were inserted into the array. + * @throws IllegalStateException if max is smaller the 0 or if the maximum index is larger then the array + */ + public static int unwrap(long[] a, Iterator i, int offset, int max) { + if(max < 0) throw new IllegalStateException("The max size is smaller then 0"); + if(offset + max > a.length) throw new IllegalStateException("largest array index exceeds array size"); + int index = 0; + for(;index a.length) throw new IllegalStateException("largest array index exceeds array size"); + int index = 0; + for(;index a.length) throw new IllegalStateException("largest array index exceeds array size"); + int index = 0; + for(;index iter; + + public IteratorWrapper(Iterator iter) { + this.iter = iter; + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public long nextLong() { + return iter.next().longValue(); + } + + @Override + @Deprecated + public Long next() { + return iter.next(); + } + } + + private static class ConcatIterator implements LongIterator + { + LongIterator[] iters; + int offset; + int lastOffset = -1; + int length; + + public ConcatIterator(LongIterator[] iters, int offset, int length) { + this.iters = iters; + this.offset = offset; + this.length = length; + find(); + } + + private void find() { + for(;length != 0 && !iters[offset].hasNext();length--, offset++); + } + + @Override + public boolean hasNext() { + return length > 0; + } + + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + long result = iters[lastOffset = offset].nextLong(); + find(); + return result; + } + + @Override + public void remove() { + if(lastOffset == -1) throw new IllegalStateException(); + iters[lastOffset].remove(); + lastOffset = -1; + } + } + + private static class ReverseBiIterator implements LongBidirectionalIterator { + LongBidirectionalIterator it; + + ReverseBiIterator(LongBidirectionalIterator it) { + this.it = it; + } + + @Override + public long nextLong() { return it.previousLong(); } + @Override + public boolean hasNext() { return it.hasPrevious(); } + @Override + public boolean hasPrevious() { return it.hasNext(); } + @Override + public long previousLong() { return it.nextLong(); } + @Override + public void remove() { it.remove(); } + } + + private static class ReverseListIterator implements LongListIterator { + LongListIterator it; + + ReverseListIterator(LongListIterator it) { + this.it = it; + } + + @Override + public long nextLong() { return it.previousLong(); } + @Override + public boolean hasNext() { return it.hasPrevious(); } + @Override + public boolean hasPrevious() { return it.hasNext(); } + @Override + public long previousLong() { return it.nextLong(); } + @Override + public void remove() { it.remove(); } + @Override + public int nextIndex() { return it.previousIndex(); } + @Override + public int previousIndex() { return it.nextIndex(); } + @Override + public void set(long e) { it.set(e); } + @Override + public void add(long e) { it.add(e); } + } + + private static class UnmodifiableListIterator implements LongListIterator + { + LongListIterator iter; + + UnmodifiableListIterator(LongListIterator iter) { + this.iter = iter; + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public boolean hasPrevious() { + return iter.hasPrevious(); + } + + @Override + public int nextIndex() { + return iter.nextIndex(); + } + + @Override + public int previousIndex() { + return iter.previousIndex(); + } + + @Override + public void remove() { throw new UnsupportedOperationException(); } + + @Override + public long previousLong() { + return iter.previousLong(); + } + + @Override + public long nextLong() { + return iter.nextLong(); + } + + @Override + public void set(long e) { throw new UnsupportedOperationException(); } + + @Override + public void add(long e) { throw new UnsupportedOperationException(); } + } + + private static class UnmodifiableBiIterator implements LongBidirectionalIterator + { + LongBidirectionalIterator iter; + + UnmodifiableBiIterator(LongBidirectionalIterator iter) { + this.iter = iter; + } + + @Override + public long nextLong() { + return iter.nextLong(); + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public boolean hasPrevious() { + return iter.hasPrevious(); + } + + @Override + public long previousLong() { + return iter.previousLong(); + } + } + + private static class UnmodifiableIterator implements LongIterator + { + LongIterator iterator; + + UnmodifiableIterator(LongIterator iterator) { + this.iterator = iterator; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public long nextLong() { + return iterator.nextLong(); + } + } + + private static class EmptyIterator implements LongListIterator + { + @Override + public boolean hasNext() { return false; } + @Override + public long nextLong() { throw new NoSuchElementException(); } + @Override + public boolean hasPrevious() { return false; } + @Override + public long previousLong() { throw new NoSuchElementException(); } + @Override + public int nextIndex() { return 0; } + @Override + public int previousIndex() { return -1; } + @Override + public void remove() { throw new UnsupportedOperationException(); } + @Override + public void set(long e) { throw new UnsupportedOperationException(); } + @Override + public void add(long e) { throw new UnsupportedOperationException(); } + } + + private static class ArrayIterator implements LongIterator + { + long[] a; + int from; + int to; + + ArrayIterator(long[] a, int from, int to) { + this.a = a; + this.from = from; + this.to = to; + } + + @Override + public boolean hasNext() { + return from < to; + } + + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + return a[from++]; + } + + @Override + public int skip(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int left = Math.min(amount, to - from); + from += left; + return amount - left; + } + } + + private static class MappedIterator implements ObjectIterator + { + LongIterator iterator; + LongFunction mapper; + + MappedIterator(LongIterator iterator, LongFunction mapper) { + this.iterator = iterator; + this.mapper = mapper; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public T next() { + return mapper.apply(iterator.nextLong()); + } + + @Override + public int skip(int amount) { + return iterator.skip(amount); + } + } + + private static class FlatMappedIterator> implements ObjectIterator + { + LongIterator iterator; + Iterator last = null; + LongFunction mapper; + boolean foundNext = false; + + FlatMappedIterator(LongIterator iterator, LongFunction mapper) { + this.iterator = iterator; + this.mapper = mapper; + } + + void compute() { + if(foundNext) return; + foundNext = true; + while(iterator.hasNext()) { + if(last != null && last.hasNext()) return; + last = mapper.apply(iterator.nextLong()).iterator(); + } + } + + @Override + public boolean hasNext() { + compute(); + return last != null && last.hasNext(); + } + + @Override + public T next() { + if(!hasNext()) throw new NoSuchElementException(); + T result = last.next(); + foundNext = false; + return result; + } + } + + private static class FlatMappedArrayIterator implements ObjectIterator + { + LongIterator iterator; + Iterator last = null; + LongFunction mapper; + boolean foundNext = false; + + FlatMappedArrayIterator(LongIterator iterator, LongFunction mapper) { + this.iterator = iterator; + this.mapper = mapper; + } + + void compute() { + if(foundNext) return; + foundNext = true; + while(iterator.hasNext()) { + if(last != null && last.hasNext()) return; + last = ObjectIterators.wrap(mapper.apply(iterator.nextLong())); + } + } + + @Override + public boolean hasNext() { + compute(); + return last != null && last.hasNext(); + } + + @Override + public T next() { + if(!hasNext()) throw new NoSuchElementException(); + T result = last.next(); + foundNext = false; + return result; + } + } + + private static class RepeatingIterator implements LongIterator + { + final int repeats; + int index = 0; + LongIterator iter; + LongCollection repeater = LongCollections.wrapper(); + + public RepeatingIterator(LongIterator iter, int repeat) { + this.iter = iter; + this.repeats = repeat; + } + + @Override + public boolean hasNext() { + if(iter.hasNext()) return true; + if(index < repeats) { + index++; + iter = repeater.iterator(); + return iter.hasNext(); + } + return false; + } + + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + long value = iter.nextLong(); + if(index == 0) repeater.add(value); + return value; + } + } + + private static class SortedIterator implements LongIterator + { + LongIterator iterator; + LongComparator sorter; + LongCollections.CollectionWrapper sortedElements = null; + int index = 0; + + public SortedIterator(LongIterator iterator, LongComparator sorter) { + this.iterator = iterator; + this.sorter = sorter; + } + + @Override + public boolean hasNext() { + if(sortedElements == null) { + boolean hasNext = iterator.hasNext(); + if(hasNext) { + sortedElements = LongCollections.wrapper(); + pour(iterator, sortedElements); + } + else sortedElements = LongCollections.wrapper(); + if(hasNext) sortedElements.unstableSort(sorter); + } + return index < sortedElements.size(); + } + + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + return sortedElements.getLong(index++); + } + } + + private static class DistinctIterator implements LongIterator + { + LongIterator iterator; + LongCollection filtered = LongCollections.distinctWrapper(); + long lastFound; + boolean foundNext = false; + + public DistinctIterator(LongIterator iterator) { + this.iterator = iterator; + } + + void compute() { + if(foundNext) return; + while(iterator.hasNext()) { + lastFound = iterator.nextLong(); + if(filtered.add(lastFound)) { + foundNext = true; + break; + } + } + } + + @Override + public boolean hasNext() { + compute(); + return foundNext; + } + + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + foundNext = false; + return lastFound; + } + } + + private static class FilteredIterator implements LongIterator + { + LongIterator iterator; + LongPredicate filter; + long lastFound; + boolean foundNext = false; + + public FilteredIterator(LongIterator iterator, LongPredicate filter) { + this.iterator = iterator; + this.filter = filter; + } + + void compute() { + if(foundNext) return; + while(iterator.hasNext()) { + lastFound = iterator.nextLong(); + if(filter.test(lastFound)) { + foundNext = true; + break; + } + } + } + + @Override + public boolean hasNext() { + compute(); + return foundNext; + } + + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + foundNext = false; + return lastFound; + } + } + + private static class LimitedIterator implements LongIterator + { + LongIterator iterator; + long limit; + + public LimitedIterator(LongIterator iterator, long limit) { + this.iterator = iterator; + this.limit = limit; + } + + @Override + public boolean hasNext() { + return limit > 0 && iterator.hasNext(); + } + + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + limit--; + return iterator.nextLong(); + } + } + + private static class PeekIterator implements LongIterator + { + LongIterator iterator; + LongConsumer action; + + public PeekIterator(LongIterator iterator, LongConsumer action) { + this.iterator = iterator; + this.action = action; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + long result = iterator.nextLong(); + action.accept(result); + return result; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/utils/LongSplititerators.java b/src/main/java/speiger/src/collections/longs/utils/LongSplititerators.java new file mode 100644 index 000000000..1456acbc0 --- /dev/null +++ b/src/main/java/speiger/src/collections/longs/utils/LongSplititerators.java @@ -0,0 +1,461 @@ +package speiger.src.collections.longs.utils; + +import java.util.Comparator; +import java.util.NoSuchElementException; +import java.util.Spliterator; +import java.util.Spliterator.OfLong; +import java.util.function.Consumer; + +import speiger.src.collections.longs.collections.LongCollection; +import speiger.src.collections.longs.collections.LongIterator; +import speiger.src.collections.longs.collections.LongSplititerator; +import speiger.src.collections.longs.functions.LongConsumer; +import speiger.src.collections.utils.SanityChecks; + +/** + * Helper class that provides SplitIterators for normal and stream usage + */ +public class LongSplititerators +{ + /** + * Creates A stream compatible split iterator without copying the original array or boxing + * @param array that should be wrapped into a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + */ + public static OfLong createArrayJavaSplititerator(long[] array, int characteristics) { return createArrayJavaSplititerator(array, 0, array.length, characteristics);} + /** + * Creates A stream compatible split iterator without copying the original array or boxing + * @param array that should be wrapped into a split iterator + * @param size the maximum index within the array + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + * @throws IllegalStateException if the size is outside of the array size + */ + public static OfLong createArrayJavaSplititerator(long[] array, int size, int characteristics) { return createArrayJavaSplititerator(array, 0, size, characteristics);} + /** + * Creates A stream compatible split iterator without copying the original array or boxing + * @param array that should be wrapped into a split iterator + * @param offset the starting index of the array + * @param size the maximum index within the array + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + * @throws IllegalStateException the offset and size are outside of the arrays range + */ + public static OfLong createArrayJavaSplititerator(long[] array, int offset, int size, int characteristics) { + SanityChecks.checkArrayCapacity(array.length, offset, size); + return new ArraySplitIterator(array, offset, size, characteristics); + } + + /** + * Creates a stream compatible split iterator without copying it or boxing it + * @param collection the collection that should be wrapped in a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + */ + public static OfLong createJavaSplititerator(LongCollection collection, int characteristics) { + return new IteratorSpliterator(collection, characteristics); + } + + /** + * Creates a stream compatible split iterator without copying it or boxing it + * @param iterator the Iterator that should be wrapped in a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + */ + public static OfLong createUnknownJavaSplititerator(LongIterator iterator, int characteristics) { + return new IteratorSpliterator(iterator, characteristics); + } + + /** + * Creates a stream compatible split iterator without copying it or boxing it + * @param iterator the collection that should be wrapped in a split iterator + * @param size the amount of elements in the iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a split iterator of a Stream compatible type + */ + public static OfLong createSizedJavaSplititerator(LongIterator iterator, long size, int characteristics) { + return new IteratorSpliterator(iterator, size, characteristics); + } + + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param array that should be wrapped into a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + */ + public static LongSplititerator createArraySplititerator(long[] array, int characteristics) { return createArraySplititerator(array, 0, array.length, characteristics);} + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param array that should be wrapped into a split iterator + * @param size the maximum index within the array + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + * @throws IllegalStateException if the size is outside of the array size + */ + public static LongSplititerator createArraySplititerator(long[] array, int size, int characteristics) { return createArraySplititerator(array, 0, size, characteristics);} + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param array that should be wrapped into a split iterator + * @param offset the starting index of the array + * @param size the maximum index within the array + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + * @throws IllegalStateException the offset and size are outside of the arrays range + */ + public static LongSplititerator createArraySplititerator(long[] array, int offset, int size, int characteristics) { + SanityChecks.checkArrayCapacity(array.length, offset, size); + return new TypeArraySplitIterator(array, offset, size, characteristics); + } + + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param collection the collection that should be wrapped in a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + */ + public static LongSplititerator createSplititerator(LongCollection collection, int characteristics) { + return new TypeIteratorSpliterator(collection, characteristics); + } + + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param iterator the Iterator that should be wrapped in a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + */ + public static LongSplititerator createUnknownSplititerator(LongIterator iterator, int characteristics) { + return new TypeIteratorSpliterator(iterator, characteristics); + } + + /** + * Creates a Type Specific SplitIterator to reduce boxing/unboxing + * @param iterator the collection that should be wrapped in a split iterator + * @param size the amount of elements in the iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @return a Type Specific SplitIterator + */ + public static LongSplititerator createSizedSplititerator(LongIterator iterator, long size, int characteristics) { + return new TypeIteratorSpliterator(iterator, size, characteristics); + } + + static class TypeIteratorSpliterator implements LongSplititerator { + static final int BATCH_UNIT = 1 << 10; + static final int MAX_BATCH = 1 << 25; + private final LongCollection collection; + private LongIterator it; + private final int characteristics; + private long est; + private int batch; + + TypeIteratorSpliterator(LongCollection collection, int characteristics) { + this.collection = collection; + it = null; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; + } + + TypeIteratorSpliterator(LongIterator iterator, long size, int characteristics) { + collection = null; + it = iterator; + est = size; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; + } + + TypeIteratorSpliterator(LongIterator iterator, int characteristics) { + collection = null; + it = iterator; + est = Long.MAX_VALUE; + this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); + } + + private LongIterator iterator() + { + if (it == null) { + it = collection.iterator(); + est = collection.size(); + } + return it; + } + + @Override + public LongSplititerator trySplit() { + LongIterator i = iterator(); + if (est > 1 && i.hasNext()) { + int n = Math.min(batch + BATCH_UNIT, Math.min((int)est, MAX_BATCH)); + long[] a = new long[n]; + int j = 0; + do { a[j] = i.nextLong(); } while (++j < n && i.hasNext()); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new TypeArraySplitIterator(a, 0, j, characteristics); + } + return null; + } + + @Override + public void forEachRemaining(LongConsumer action) { + if (action == null) throw new NullPointerException(); + iterator().forEachRemaining(action); + } + + @Override + public boolean tryAdvance(LongConsumer action) { + if (action == null) throw new NullPointerException(); + LongIterator iter = iterator(); + if (iter.hasNext()) { + action.accept(iter.nextLong()); + return true; + } + return false; + } + + @Override + public boolean tryAdvance(Consumer action) { + if (action == null) throw new NullPointerException(); + LongIterator iter = iterator(); + if (iter.hasNext()) { + action.accept(Long.valueOf(iter.nextLong())); + return true; + } + return false; + } + + @Override + public long estimateSize() { + iterator(); + return est; + } + + @Override + public int characteristics() { return characteristics; } + + @Override + public Comparator getComparator() { + if (hasCharacteristics(4)) //Sorted + return null; + throw new IllegalStateException(); + } + + @Override + public long nextLong() { return iterator().nextLong(); } + + @Override + public boolean hasNext() { return iterator().hasNext(); } + } + + static final class TypeArraySplitIterator implements LongSplititerator { + private final long[] array; + private int index; + private final int fence; + private final int characteristics; + + public TypeArraySplitIterator(long[] array, int origin, int fence, int additionalCharacteristics) { + this.array = array; + index = origin; + this.fence = fence; + characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + @Override + public LongSplititerator trySplit() { + int lo = index, mid = (lo + fence) >>> 1; + return (lo >= mid) ? null : new TypeArraySplitIterator(array, lo, index = mid, characteristics); + } + + @Override + public void forEachRemaining(LongConsumer action) { + if (action == null) throw new NullPointerException(); + long[] a; int i, hi; + if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) { + do { action.accept(a[i]); } while (++i < hi); + } + } + + @Override + public boolean tryAdvance(LongConsumer action) { + if (action == null) throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(array[index++]); + return true; + } + return false; + } + + @Override + public boolean tryAdvance(Consumer action) { + if (action == null) throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(Long.valueOf(array[index++])); + return true; + } + return false; + } + + @Override + public long estimateSize() { return fence - index; } + @Override + public int characteristics() { return characteristics; } + @Override + public Comparator getComparator() { + if (hasCharacteristics(4)) //Sorted + return null; + throw new IllegalStateException(); + } + + @Override + public long nextLong() { + if(!hasNext()) throw new NoSuchElementException(); + return array[index++]; + } + + @Override + public boolean hasNext() { return index < fence; } + } + + static class IteratorSpliterator implements OfLong { + static final int BATCH_UNIT = 1 << 10; + static final int MAX_BATCH = 1 << 25; + private final LongCollection collection; + private LongIterator it; + private final int characteristics; + private long est; + private int batch; + + IteratorSpliterator(LongCollection collection, int characteristics) { + this.collection = collection; + it = null; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; + } + + IteratorSpliterator(LongIterator iterator, long size, int characteristics) { + collection = null; + it = iterator; + est = size; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; + } + + IteratorSpliterator(LongIterator iterator, int characteristics) { + collection = null; + it = iterator; + est = Long.MAX_VALUE; + this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); + } + + private LongIterator iterator() + { + if (it == null) { + it = collection.iterator(); + est = collection.size(); + } + return it; + } + + @Override + public OfLong trySplit() { + LongIterator i = iterator(); + if (est > 1 && i.hasNext()) { + int n = Math.min(batch + BATCH_UNIT, Math.min((int)est, MAX_BATCH)); + long[] a = new long[n]; + int j = 0; + do { a[j] = i.nextLong(); } while (++j < n && i.hasNext()); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new ArraySplitIterator(a, 0, j, characteristics); + } + return null; + } + + @Override + public void forEachRemaining(java.util.function.LongConsumer action) { + if (action == null) throw new NullPointerException(); + iterator().forEachRemaining(T -> action.accept(T)); + } + + @Override + public boolean tryAdvance(java.util.function.LongConsumer action) { + if (action == null) throw new NullPointerException(); + LongIterator iter = iterator(); + if (iter.hasNext()) { + action.accept(iter.nextLong()); + return true; + } + return false; + } + + @Override + public long estimateSize() { + iterator(); + return est; + } + + @Override + public int characteristics() { return characteristics; } + + @Override + public Comparator getComparator() { + if (hasCharacteristics(4)) //Sorted + return null; + throw new IllegalStateException(); + } + } + + static final class ArraySplitIterator implements OfLong { + private final long[] array; + private int index; + private final int fence; + private final int characteristics; + + public ArraySplitIterator(long[] array, int origin, int fence, int additionalCharacteristics) { + this.array = array; + index = origin; + this.fence = fence; + characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + @Override + public OfLong trySplit() { + int lo = index, mid = (lo + fence) >>> 1; + return (lo >= mid) ? null : new ArraySplitIterator(array, lo, index = mid, characteristics); + } + + @Override + public void forEachRemaining(java.util.function.LongConsumer action) { + if (action == null) throw new NullPointerException(); + long[] a; int i, hi; + if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) { + do { action.accept(a[i]); } while (++i < hi); + } + } + + @Override + public boolean tryAdvance(java.util.function.LongConsumer action) { + if (action == null) throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(array[index++]); + return true; + } + return false; + } + + @Override + public long estimateSize() { return fence - index; } + @Override + public int characteristics() { return characteristics; } + @Override + public Comparator getComparator() { + if (hasCharacteristics(4)) //Sorted + return null; + throw new IllegalStateException(); + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/collections/AbstractObjectCollection.java b/src/main/java/speiger/src/collections/objects/collections/AbstractObjectCollection.java new file mode 100644 index 000000000..13080cf5c --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/collections/AbstractObjectCollection.java @@ -0,0 +1,167 @@ +package speiger.src.collections.objects.collections; + +import java.util.Collection; +import java.util.Objects; +import java.util.AbstractCollection; +import java.util.function.Consumer; + +import speiger.src.collections.objects.utils.ObjectArrays; + +/** + * Abstract Type Specific Collection that reduces boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public abstract class AbstractObjectCollection extends AbstractCollection implements ObjectCollection +{ + @Override + public abstract ObjectIterator iterator(); + + @Override + public boolean addAll(ObjectCollection c) { + boolean modified = false; + for(ObjectIterator iter = c.iterator();iter.hasNext();modified |= add(iter.next())); + return modified; + } + + @Override + public ObjectCollection copy() { throw new UnsupportedOperationException(); } + + + /** + * A Type-Specific implementation of containsAll. This implementation iterates over all elements and checks all elements are present in the other collection. + * @param c the collection that should be checked if it contains all elements. + * @return true if all elements were found in the collection + * @throws NullPointerException if the collection is null + */ + @Override + public boolean containsAll(ObjectCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return true; + for(ObjectIterator iter = c.iterator();iter.hasNext();) + if(!contains(iter.next())) + return false; + return true; + } + + @Override + public boolean containsAll(Collection c) { + Objects.requireNonNull(c); + return c instanceof ObjectCollection ? containsAll((ObjectCollection)c) : super.containsAll(c); + } + + /** + * This implementation iterates over the elements of the collection and checks if they are stored in this collection + * @param c the elements that should be checked for + * @return true if any element is in this collection + * @throws NullPointerException if the collection is null + */ + @Override + public boolean containsAny(Collection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + for(Object e : c) + if(contains(e)) + return true; + return false; + } + + /** + * This implementation iterates over the elements of the collection and checks if they are stored in this collection. + * @param c the elements that should be checked for + * @return true if any element is in this collection + * @throws NullPointerException if the collection is null + */ + @Override + public boolean containsAny(ObjectCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + for(ObjectIterator iter = c.iterator();iter.hasNext();) + if(contains(iter.next())) + return true; + return false; + } + + /** + * A Type-Specific implementation of removeAll. This Implementation iterates over all elements and removes them as they were found in the other collection. + * @param c the elements that should be deleted + * @return true if the collection was modified. + * @throws NullPointerException if the collection is null + */ + @Override + public boolean removeAll(ObjectCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + boolean modified = false; + for(ObjectIterator iter = iterator();iter.hasNext();) { + if(c.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + @Override + public boolean removeAll(ObjectCollection c, Consumer r) { + Objects.requireNonNull(c); + if(c.isEmpty()) return false; + Objects.requireNonNull(r); + boolean modified = false; + for(ObjectIterator iter = iterator();iter.hasNext();) { + T e = iter.next(); + if(c.contains(e)) { + r.accept(e); + iter.remove(); + modified = true; + } + } + return modified; + } + + /** + * A Type-Specific implementation of retainAll. This Implementation iterates over all elements and removes them as they were not found in the other collection. + * @param c the elements that should be kept + * @return true if the collection was modified. + * @throws NullPointerException if the collection is null + */ + @Override + public boolean retainAll(ObjectCollection c) { + Objects.requireNonNull(c); + if(c.isEmpty()) { + boolean modified = !isEmpty(); + clear(); + return modified; + } + boolean modified = false; + for(ObjectIterator iter = iterator();iter.hasNext();) { + if(!c.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + @Override + public boolean retainAll(ObjectCollection c, Consumer r) { + Objects.requireNonNull(c); + Objects.requireNonNull(r); + if(c.isEmpty()) { + boolean modified = !isEmpty(); + forEach(r); + clear(); + return modified; + } + boolean modified = false; + for(ObjectIterator iter = iterator();iter.hasNext();) { + T e = iter.next(); + if(!c.contains(e)) { + r.accept(e); + iter.remove(); + modified = true; + } + } + return modified; + } + +} diff --git a/src/main/java/speiger/src/collections/objects/collections/ObjectBidirectionalIterator.java b/src/main/java/speiger/src/collections/objects/collections/ObjectBidirectionalIterator.java new file mode 100644 index 000000000..1d1d77cdc --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/collections/ObjectBidirectionalIterator.java @@ -0,0 +1,34 @@ +package speiger.src.collections.objects.collections; + +/** + * This is a basically a {@link java.util.ListIterator} without the index functions. + * Allowing to have a simple Bidirectional Iterator without having to keep track of the Iteration index. + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectBidirectionalIterator extends ObjectIterator +{ + /** + * Returns true if the Iterator has a Previous element + * @return true if the Iterator has a Previous element + */ + public boolean hasPrevious(); + + /** + * Returns the Previous element of the iterator. + * @return the Previous element of the iterator. + * @throws java.util.NoSuchElementException if the iteration has no more elements + */ + public T previous(); + + /** + * Reverses the Given amount of elements if possible. A Optimization function to reverse elements faster if the implementation allows it. + * @param amount the amount of elements that should be reversed + * @return the amount of elements that were reversed + */ + public default int back(int amount) { + if(amount < 0) throw new IllegalStateException("Can't go forward"); + int i = 0; + for(;i the keyType of elements maintained by this Collection + */ +public interface ObjectCollection extends Collection, ObjectIterable, ISizeProvider +{ + /** + * A Type-Specific addAll function to reduce (un)boxing + * @param c the collection of elements that should be added + * @return true if elements were added into the collection + */ + public boolean addAll(ObjectCollection c); + + /** + * A Type-Specific Array based addAll method to reduce the amount of Wrapping + * @param e the elements that should be added + * @return if the collection was modified + */ + public default boolean addAll(T... e) { return addAll(e, 0, e.length); } + + /** + * A Type-Specific Array based addAll method to reduce the amount of Wrapping + * @param e the elements that should be added + * @param length how many elements of the array should be added + * @return if the collection was modified + */ + public default boolean addAll(T[] e, int length) { return addAll(e, 0, length); } + + /** + * A Type-Specific Array based addAll method to reduce the amount of Wrapping + * @param e the elements that should be added + * @param offset where to start within the array + * @param length how many elements of the array should be added + * @return if the collection was modified + */ + public default boolean addAll(T[] e, int offset, int length) { + if(length <= 0) return false; + SanityChecks.checkArrayCapacity(e.length, offset, length); + boolean added = false; + for(int i = 0;i c); + + /** + * A Type-Specific containsAny function to reduce (un)boxing + * @param c the collection of elements that should be tested for + * @return true if any element was found + */ + public boolean containsAny(ObjectCollection c); + + /** + * Returns true if any element of the Collection is found in the provided collection. + * A Small Optimization function to find out of any element is present when comparing collections and not all of them. + * @param c the collection of elements that should be tested for + * @return true if any element was found. + */ + public boolean containsAny(Collection c); + + /** + * A Type-Specific removeAll function that reduces (un)boxing. + * @param c the collection of elements that should be removed + * @return true if any element was removed + * @see Collection#removeAll(Collection) + */ + public boolean removeAll(ObjectCollection c); + + /** + * A Type-Specific removeAll function that reduces (un)boxing. + * It also notifies the remover of which exact element is going to be removed. + * @param c the collection of elements that should be removed + * @param r elements that got removed + * @return true if any element was removed + * @see Collection#removeAll(Collection) + */ + public boolean removeAll(ObjectCollection c, Consumer r); + + /** + * A Type-Specific retainAll function that reduces (un)boxing. + * @param c the collection of elements that should be kept + * @return true if any element was removed + * @see Collection#retainAll(Collection) + */ + public boolean retainAll(ObjectCollection c); + + /** + * A Type-Specific retainAll function that reduces (un)boxing. + * It also notifies the remover of which exact element is going to be removed. + * @param c the collection of elements that should be kept + * @param r elements that got removed + * @return true if any element was removed + * @see Collection#retainAll(Collection) + */ + public boolean retainAll(ObjectCollection c, Consumer r); + + /** + * A Helper function to reduce the usage of Streams and allows to collect all elements + * @param collection that the elements should be inserted to + * @param the collection type + * @return the input with the desired elements + */ + default > E pour(E collection) { + collection.addAll(this); + return collection; + } + + /** + * A Function that does a shallow clone of the Collection itself. + * This function is more optimized then a copy constructor since the Collection does not have to be unsorted/resorted. + * It can be compared to Cloneable but with less exception risk + * @return a Shallow Copy of the collection + * @note Wrappers and view collections will not support this feature + */ + public ObjectCollection copy(); + + /** + * A Helper function that simplifies the process of creating a new Array. + * @param action the array creation function + * @return an array containing all of the elements in this collection + * @see Collection#toArray(Object[]) + */ + default E[] toArray(IntFunction action) { + return toArray(action.apply(size())); + } + + /** + * Returns a Type-Specific Iterator to reduce (un)boxing + * @return a iterator of the collection + * @see Collection#iterator() + */ + @Override + public ObjectIterator iterator(); + + /** + * Creates a Wrapped Collection that is Synchronized + * @return a new Collection that is synchronized + * @see ObjectCollections#synchronize + */ + public default ObjectCollection synchronize() { return ObjectCollections.synchronize(this); } + + /** + * Creates a Wrapped Collection that is Synchronized + * @param mutex is the controller of the synchronization block + * @return a new Collection Wrapper that is synchronized + * @see ObjectCollections#synchronize + */ + public default ObjectCollection synchronize(Object mutex) { return ObjectCollections.synchronize(this, mutex); } + + /** + * Creates a Wrapped Collection that is unmodifiable + * @return a new Collection Wrapper that is unmodifiable + * @see ObjectCollections#unmodifiable + */ + public default ObjectCollection unmodifiable() { return ObjectCollections.unmodifiable(this); } + + + /** + * A Type Specific Type Splititerator to reduce boxing/unboxing + * @return type specific splititerator + */ + @Override + default ObjectSplititerator spliterator() { return ObjectSplititerators.createSplititerator(this, 0); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/collections/ObjectIterable.java b/src/main/java/speiger/src/collections/objects/collections/ObjectIterable.java new file mode 100644 index 000000000..792ba6ab0 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/collections/ObjectIterable.java @@ -0,0 +1,297 @@ +package speiger.src.collections.objects.collections; + +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Predicate; + +import java.util.function.BiFunction; +import java.util.function.IntFunction; +import java.util.Comparator; + +import speiger.src.collections.objects.functions.function.UnaryOperator; +import speiger.src.collections.ints.functions.consumer.IntObjectConsumer; +import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer; +import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator; +import speiger.src.collections.objects.lists.ObjectList; +import speiger.src.collections.objects.lists.ObjectArrayList; + +import speiger.src.collections.objects.utils.ObjectArrays; +import speiger.src.collections.objects.utils.ObjectSplititerators; +import speiger.src.collections.objects.utils.ObjectIterables; +import speiger.src.collections.objects.utils.ObjectIterators; +import speiger.src.collections.utils.ISizeProvider; + +/** + * A Type-Specific {@link Iterable} that reduces (un)boxing + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectIterable extends Iterable +{ + /** + * Returns an iterator over elements of type {@code T}. + * + * @return an Iterator. + */ + @Override + ObjectIterator iterator(); + + /** + * A Indexed forEach implementation that allows you to keep track of how many elements were already iterated over. + * @param action The action to be performed for each element + * @throws NullPointerException if the specified action is null + */ + public default void forEachIndexed(IntObjectConsumer action) { + Objects.requireNonNull(action); + int index = 0; + for(ObjectIterator iter = iterator();iter.hasNext();action.accept(index++, iter.next())); + } + + /** + * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. + * @param input the object that should be included + * @param action The action to be performed for each element + * @param the generic type of the Object + * @throws NullPointerException if the specified action is null + */ + default void forEach(E input, ObjectObjectConsumer action) { + Objects.requireNonNull(action); + iterator().forEachRemaining(input, action); + } + + /** + * A Type Specific Type Splititerator to reduce boxing/unboxing + * @return type specific splititerator + */ + @Override + default ObjectSplititerator spliterator() { return ObjectSplititerators.createUnknownSplititerator(iterator(), 0); } + + /** + * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. + * @param mapper the mapping function + * @param The return type. + * @return a new Iterable that returns the desired result + */ + default ObjectIterable map(UnaryOperator mapper) { + return ObjectIterables.map(this, mapper); + } + + /** + * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. + * @param mapper the flatMapping function + * @param The return type supplier. + * @param The return type. + * @return a new Iterable that returns the desired result + * @note does not support toArray optimizations. + */ + default > ObjectIterable flatMap(UnaryOperator mapper) { + return ObjectIterables.flatMap(this, mapper); + } + + /** + * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. + * @param mapper the flatMapping function + * @param The return type. + * @return a new Iterable that returns the desired result + * @note does not support toArray optimizations. + */ + default ObjectIterable arrayflatMap(UnaryOperator mapper) { + return ObjectIterables.arrayFlatMap(this, mapper); + } + + /** + * A Helper function to reduce the usage of Streams and allows to filter out unwanted elements + * @param filter the elements that should be kept. + * @return a Iterable that filtered out all unwanted elements + * @note does not support toArray optimizations. + */ + default ObjectIterable filter(Predicate filter) { + return ObjectIterables.filter(this, filter); + } + + /** + * A Helper function to reduce the usage of Streams and allows to filter out duplicated elements + * @return a Iterable that filtered out all duplicated elements + * @note does not support toArray optimizations. + */ + default ObjectIterable distinct() { + return ObjectIterables.distinct(this); + } + + /** + * A Helper function to reduce the usage of Streams and allows to repeat elements a desired amount of times + * @param repeats how many times the elements should be repeated + * @return a Iterable that is repeating multiple times + */ + default ObjectIterable repeat(int repeats) { + return ObjectIterables.repeat(this, repeats); + } + + /** + * A Helper function to reduce the usage of Streams and allows to limit the amount of elements + * @param limit the amount of elements it should be limited to + * @return a Iterable that is limited in length + */ + default ObjectIterable limit(long limit) { + return ObjectIterables.limit(this, limit); + } + + /** + * A Helper function to reduce the usage of Streams and allows to sort the elements + * @param sorter that sorts the elements. + * @return a Iterable that is sorted + */ + default ObjectIterable sorted(Comparator sorter) { + return ObjectIterables.sorted(this, sorter); + } + + /** + * A Helper function to reduce the usage of Streams and allows to preview elements before they are iterated through + * @param action the action that should be applied + * @return a Peeked Iterable + */ + default ObjectIterable peek(Consumer action) { + return ObjectIterables.peek(this, action); + } + + /** + * A Helper function to reduce the usage of Streams and allows to collect all elements + * @param collection that the elements should be inserted to + * @param the collection type + * @return the input with the desired elements + */ + default > E pour(E collection) { + ObjectIterators.pour(iterator(), collection); + return collection; + } + + /** + * A Helper function that reduces the usage of streams and allows to collect all elements as a ArrayList + * @return a new ArrayList of all elements + */ + default ObjectList pourAsList() { + return pour(new ObjectArrayList<>()); + } + + + /** + * A Helper function that reduces the usage of streams and allows to collect all elements as a Array + * @param action is the creator function of said Array to ensure type is kept. + * @return a new Array of all elements + */ + default E[] toArray(IntFunction action) { + ISizeProvider prov = ISizeProvider.of(this); + if(prov != null) { + int size = prov.size(); + if(size >= 0) { + E[] array = action.apply(size); + ObjectIterators.unwrap(array, iterator()); + return array; + } + } + return ObjectArrays.pour(iterator(), action); + } + /** + * Helper function to reduce stream usage that allows to filter for any matches. + * @param filter that should be applied + * @return true if any matches were found + */ + default boolean matchesAny(Predicate filter) { + Objects.requireNonNull(filter); + for(ObjectIterator iter = iterator();iter.hasNext();) { + if(filter.test(iter.next())) return true; + } + return false; + } + + /** + * Helper function to reduce stream usage that allows to filter for no matches. + * @param filter that should be applied + * @return true if no matches were found + */ + default boolean matchesNone(Predicate filter) { + Objects.requireNonNull(filter); + for(ObjectIterator iter = iterator();iter.hasNext();) { + if(filter.test(iter.next())) return false; + } + return true; + } + + /** + * Helper function to reduce stream usage that allows to filter for all matches. + * @param filter that should be applied + * @return true if all matches. + */ + default boolean matchesAll(Predicate filter) { + Objects.requireNonNull(filter); + for(ObjectIterator iter = iterator();iter.hasNext();) { + if(!filter.test(iter.next())) return false; + } + return true; + } + + /** + * Helper function to reduce stream usage that allows to filter for the first match. + * @param filter that should be applied + * @return the found value or the null equivalent variant. + */ + default T findFirst(Predicate filter) { + Objects.requireNonNull(filter); + for(ObjectIterator iter = iterator();iter.hasNext();) { + T entry = iter.next(); + if(filter.test(entry)) return entry; + } + return null; + } + + /** + * Performs a reduction on the + * elements of this Iterable + * @param operator the operation that should be applied + * @param identity the start value + * @param the keyType of elements maintained by this Collection + * @return the reduction result, returns identity if nothing was found + */ + default E reduce(E identity, BiFunction operator) { + Objects.requireNonNull(operator); + E state = identity; + for(ObjectIterator iter = iterator();iter.hasNext();) { + state = operator.apply(state, iter.next()); + } + return state; + } + + /** + * Performs a reduction on the + * elements of this Iterable + * @param operator the operation that should be applied + * @return the reduction result, returns null value if nothing was found + */ + default T reduce(ObjectObjectUnaryOperator operator) { + Objects.requireNonNull(operator); + T state = null; + boolean empty = true; + for(ObjectIterator iter = iterator();iter.hasNext();) { + if(empty) { + empty = false; + state = iter.next(); + continue; + } + state = operator.apply(state, iter.next()); + } + return state; + } + + /** + * Helper function to reduce stream usage that allows to count the valid elements. + * @param filter that should be applied + * @return the amount of Valid Elements + */ + default int count(Predicate filter) { + Objects.requireNonNull(filter); + int result = 0; + for(ObjectIterator iter = iterator();iter.hasNext();) { + if(filter.test(iter.next())) result++; + } + return result; + } +} diff --git a/src/main/java/speiger/src/collections/objects/collections/ObjectIterator.java b/src/main/java/speiger/src/collections/objects/collections/ObjectIterator.java new file mode 100644 index 000000000..288121002 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/collections/ObjectIterator.java @@ -0,0 +1,36 @@ +package speiger.src.collections.objects.collections; + +import java.util.Iterator; +import java.util.Objects; +import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer; + +/** + * A Type-Specific {@link Iterator} that reduces (un)boxing + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectIterator extends Iterator +{ + /** + * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. + * @param input the object that should be included + * @param action The action to be performed for each element + * @param the generic type of the Object + * @throws NullPointerException if the specified action is null + */ + default void forEachRemaining(E input, ObjectObjectConsumer action) { + Objects.requireNonNull(action); + while(hasNext()) { action.accept(input, next()); } + } + + /** + * Skips the Given amount of elements if possible. A Optimization function to skip elements faster if the implementation allows it. + * @param amount the amount of elements that should be skipped + * @return the amount of elements that were skipped + */ + default int skip(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int i = 0; + for(;i the keyType of elements maintained by this Collection + */ +public interface ObjectSplititerator extends Spliterator, ObjectIterator +{ + @Override + default void forEachRemaining(Consumer action) { ObjectIterator.super.forEachRemaining(action); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/ObjectSupplier.java b/src/main/java/speiger/src/collections/objects/functions/ObjectSupplier.java new file mode 100644 index 000000000..879c06448 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/ObjectSupplier.java @@ -0,0 +1,13 @@ +package speiger.src.collections.objects.functions; + +/** + * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectSupplier extends java.util.function.Supplier +{ + /** + * @return the supplied value + */ + public T get(); +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectBooleanConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectBooleanConsumer.java new file mode 100644 index 000000000..2a5494190 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectBooleanConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.objects.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectBooleanConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(T k, boolean v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ObjectBooleanConsumer andThen(ObjectBooleanConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(T k, Boolean v) { accept(k, v.booleanValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ObjectBooleanConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, Boolean.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectByteConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectByteConsumer.java new file mode 100644 index 000000000..0893b1e86 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectByteConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.objects.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectByteConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(T k, byte v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ObjectByteConsumer andThen(ObjectByteConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(T k, Byte v) { accept(k, v.byteValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ObjectByteConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, Byte.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectCharConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectCharConsumer.java new file mode 100644 index 000000000..e45bf7e7f --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectCharConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.objects.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectCharConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(T k, char v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ObjectCharConsumer andThen(ObjectCharConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(T k, Character v) { accept(k, v.charValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ObjectCharConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, Character.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectDoubleConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectDoubleConsumer.java new file mode 100644 index 000000000..6581a6fbe --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectDoubleConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.objects.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectDoubleConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(T k, double v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ObjectDoubleConsumer andThen(ObjectDoubleConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(T k, Double v) { accept(k, v.doubleValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ObjectDoubleConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, Double.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectFloatConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectFloatConsumer.java new file mode 100644 index 000000000..79e3bf128 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectFloatConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.objects.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectFloatConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(T k, float v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ObjectFloatConsumer andThen(ObjectFloatConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(T k, Float v) { accept(k, v.floatValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ObjectFloatConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, Float.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectIntConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectIntConsumer.java new file mode 100644 index 000000000..7522cc984 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectIntConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.objects.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectIntConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(T k, int v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ObjectIntConsumer andThen(ObjectIntConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(T k, Integer v) { accept(k, v.intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ObjectIntConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, Integer.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectLongConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectLongConsumer.java new file mode 100644 index 000000000..59317a6ac --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectLongConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.objects.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectLongConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(T k, long v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ObjectLongConsumer andThen(ObjectLongConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(T k, Long v) { accept(k, v.longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ObjectLongConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, Long.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectObjectConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectObjectConsumer.java new file mode 100644 index 000000000..6b17b99f6 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectObjectConsumer.java @@ -0,0 +1,33 @@ +package speiger.src.collections.objects.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectObjectConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(T k, V v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ObjectObjectConsumer andThen(ObjectObjectConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectShortConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectShortConsumer.java new file mode 100644 index 000000000..63ea95440 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectShortConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.objects.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectShortConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(T k, short v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ObjectShortConsumer andThen(ObjectShortConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(T k, Short v) { accept(k, v.shortValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ObjectShortConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, Short.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectBooleanUnaryOperator.java new file mode 100644 index 000000000..e8b5658c9 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ObjectBooleanUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.objects.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectBooleanUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public boolean applyAsBoolean(T k, boolean v); + + @Override + public default Boolean apply(T k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k, v.booleanValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectByteUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectByteUnaryOperator.java new file mode 100644 index 000000000..ceddb19f4 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ObjectByteUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.objects.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectByteUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public byte applyAsByte(T k, byte v); + + @Override + public default Byte apply(T k, Byte v) { return Byte.valueOf(applyAsByte(k, v.byteValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectCharUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectCharUnaryOperator.java new file mode 100644 index 000000000..834d99440 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ObjectCharUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.objects.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectCharUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public char applyAsChar(T k, char v); + + @Override + public default Character apply(T k, Character v) { return Character.valueOf(applyAsChar(k, v.charValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectDoubleUnaryOperator.java new file mode 100644 index 000000000..c13963ef7 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ObjectDoubleUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.objects.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectDoubleUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public double applyAsDouble(T k, double v); + + @Override + public default Double apply(T k, Double v) { return Double.valueOf(applyAsDouble(k, v.doubleValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectFloatUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectFloatUnaryOperator.java new file mode 100644 index 000000000..df6d4359e --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ObjectFloatUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.objects.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectFloatUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public float applyAsFloat(T k, float v); + + @Override + public default Float apply(T k, Float v) { return Float.valueOf(applyAsFloat(k, v.floatValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectIntUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectIntUnaryOperator.java new file mode 100644 index 000000000..b68141a2c --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ObjectIntUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.objects.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectIntUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public int applyAsInt(T k, int v); + + @Override + public default Integer apply(T k, Integer v) { return Integer.valueOf(applyAsInt(k, v.intValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectLongUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectLongUnaryOperator.java new file mode 100644 index 000000000..0ec8b1018 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ObjectLongUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.objects.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectLongUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public long applyAsLong(T k, long v); + + @Override + public default Long apply(T k, Long v) { return Long.valueOf(applyAsLong(k, v.longValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectObjectUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectObjectUnaryOperator.java new file mode 100644 index 000000000..e4d6de7d7 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ObjectObjectUnaryOperator.java @@ -0,0 +1,13 @@ +package speiger.src.collections.objects.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectObjectUnaryOperator extends BiFunction +{ + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectShortUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectShortUnaryOperator.java new file mode 100644 index 000000000..1ec7c91c3 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ObjectShortUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.objects.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface ObjectShortUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public short applyAsShort(T k, short v); + + @Override + public default Short apply(T k, Short v) { return Short.valueOf(applyAsShort(k, v.shortValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/Predicate.java b/src/main/java/speiger/src/collections/objects/functions/function/Predicate.java new file mode 100644 index 000000000..988fd6967 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/Predicate.java @@ -0,0 +1,75 @@ +package speiger.src.collections.objects.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface Predicate extends java.util.function.Predicate +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public boolean test(T k); + + /** + * Creates a Always true function that may be useful if you don't need to process information or just want a default. + * @param the keyType of elements maintained by this Collection + * @return a default returning function + */ + public static Predicate alwaysTrue() { + return T -> true; + } + + /** + * Creates a Always false function that may be useful if you don't need to process information or just want a default. + * @param the keyType of elements maintained by this Collection + * @return a default returning function + */ + public static Predicate alwaysFalse() { + return T -> false; + } + + /** + * A Type specific and-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a and comparason + */ + public default Predicate andType(Predicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + @Override + @Deprecated + public default Predicate and(java.util.function.Predicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + @Override + public default Predicate negate() { + return T -> !test(T); + } + + /** + * A Type specific or-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a or comparason + */ + public default Predicate orType(Predicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } + + @Override + @Deprecated + public default Predicate or(java.util.function.Predicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToByteFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToByteFunction.java new file mode 100644 index 000000000..5af08681d --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ToByteFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.objects.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface ToByteFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public byte applyAsByte(T k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToCharFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToCharFunction.java new file mode 100644 index 000000000..5b5ccac38 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ToCharFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.objects.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface ToCharFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public char applyAsChar(T k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToDoubleFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToDoubleFunction.java new file mode 100644 index 000000000..27b567e09 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ToDoubleFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.objects.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface ToDoubleFunction extends java.util.function.ToDoubleFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public double applyAsDouble(T k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToFloatFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToFloatFunction.java new file mode 100644 index 000000000..ca72c0160 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ToFloatFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.objects.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface ToFloatFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public float applyAsFloat(T k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToIntFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToIntFunction.java new file mode 100644 index 000000000..f8c7f007e --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ToIntFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.objects.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface ToIntFunction extends java.util.function.ToIntFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public int applyAsInt(T k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToLongFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToLongFunction.java new file mode 100644 index 000000000..3e04c28f1 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ToLongFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.objects.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface ToLongFunction extends java.util.function.ToLongFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public long applyAsLong(T k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToShortFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToShortFunction.java new file mode 100644 index 000000000..6e6789654 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/ToShortFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.objects.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface ToShortFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public short applyAsShort(T k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/UnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/UnaryOperator.java new file mode 100644 index 000000000..69b19ecde --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/functions/function/UnaryOperator.java @@ -0,0 +1,59 @@ +package speiger.src.collections.objects.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface UnaryOperator extends java.util.function.Function +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public V apply(T k); + + /** + * Creates a Default function that returns the input provided. + * @param the keyType of elements maintained by this Collection + * @return a input returning function + */ + public static UnaryOperator identity() { + return T -> T; + } + + /** + * Returns a composed function that first applies the {@code before} + * function to its input, and then applies this function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param the keyType of elements maintained by this Collection + * @param before the function that should be used first + * @return a composed function with a different starting function. + */ + public default UnaryOperator compose(UnaryOperator before) { + Objects.requireNonNull(before); + return T -> apply(before.apply(T)); + } + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param the keyType of elements maintained by this Collection + * @param after the function that should be used last + * @return a composed function with a different starting function. + */ + public default UnaryOperator andThen(UnaryOperator after) { + Objects.requireNonNull(after); + return T -> after.apply(apply(T)); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/lists/AbstractObjectList.java b/src/main/java/speiger/src/collections/objects/lists/AbstractObjectList.java new file mode 100644 index 000000000..b6533836c --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/lists/AbstractObjectList.java @@ -0,0 +1,493 @@ +package speiger.src.collections.objects.lists; + +import java.util.Collection; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; +import java.util.Objects; + +import speiger.src.collections.objects.collections.AbstractObjectCollection; +import speiger.src.collections.objects.collections.ObjectCollection; +import speiger.src.collections.objects.collections.ObjectIterator; +import speiger.src.collections.objects.collections.ObjectSplititerator; +import speiger.src.collections.objects.utils.ObjectSplititerators; +import speiger.src.collections.utils.SanityChecks; + +/** + * Abstract implementation of the {@link ObjectList} interface. + * @param the keyType of elements maintained by this Collection + */ +public abstract class AbstractObjectList extends AbstractObjectCollection implements ObjectList +{ + /** + * A Type-Specific implementation of add function that delegates to {@link List#add(int, Object)} + */ + @Override + public boolean add(T e) { + add(size(), e); + return true; + } + + /** + * A Type-Specific implementation that iterates over the elements and adds them. + * @param c the elements that wants to be added + * @return true if the list was modified + */ + @Override + public boolean addAll(ObjectCollection c) { + return addAll(size(), c); + } + + /** + * A Type-Specific implementation that iterates over the elements and adds them. + * @param c the elements that wants to be added + * @return true if the list was modified + */ + @Override + public boolean addAll(ObjectList c) { + return addAll(size(), c); + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + public boolean addAll(Collection c) + { + return c instanceof ObjectCollection ? addAll((ObjectCollection)c) : addAll(size(), c); + } + + /** + * The IndexOf implementation iterates over all elements and compares them to the search value. + * @param o the value that the index is searched for. + * @return index of the value that was searched for. -1 if not found + * @note it is highly suggested not to use this with Primitives because of boxing. But it is still supported because of ObjectComparason that are custom objects and allow to find the contents. + */ + @Override + public int indexOf(Object o) { + ObjectListIterator iter = listIterator(); + if(o == null) { + while(iter.hasNext()) { + if(iter.next() == null) + return iter.previousIndex(); + } + return -1; + } + while(iter.hasNext()) { + if(Objects.equals(o, iter.next())) + return iter.previousIndex(); + } + return -1; + } + + /** + * The lastIndexOf implementation iterates over all elements and compares them to the search value. + * @param o the value that the index is searched for. + * @return the last index of the value that was searched for. -1 if not found + * @note it is highly suggested not to use this with Primitives because of boxing. But it is still supported because of ObjectComparason that are custom objects and allow to find the contents. + */ + @Override + public int lastIndexOf(Object o) { + ObjectListIterator iter = listIterator(size()); + if(o == null) { + while(iter.hasPrevious()) { + if(iter.previous() == null) + return iter.nextIndex(); + } + return -1; + } + while(iter.hasPrevious()) { + if(Objects.equals(o, iter.previous())) + return iter.nextIndex(); + } + return -1; + } + + @Override + public boolean swapRemove(T e) { + int index = indexOf(e); + if(index == -1) return false; + swapRemove(index); + return true; + } + + /** + * Compares if the list are the same. + */ + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof List)) + return false; + List l = (List)o; + if(l.size() != size()) return false; + ListIterator e1 = listIterator(); + ListIterator e2 = l.listIterator(); + while (e1.hasNext() && e2.hasNext()) { + if(!Objects.equals(e1.next(), e2.next())) + return false; + } + return !(e1.hasNext() || e2.hasNext()); + } + + /** + * Generates the hashcode based on the values stored in the list. + */ + @Override + public int hashCode() { + int hashCode = 1; + ObjectListIterator i = listIterator(); + while(i.hasNext()) + hashCode = 31 * hashCode + i.next().hashCode(); + return hashCode; + } + + @Override + public ObjectList subList(int fromIndex, int toIndex) { + SanityChecks.checkArrayCapacity(size(), fromIndex, toIndex-fromIndex); + return new SubList(this, 0, fromIndex, toIndex); + } + + @Override + public ObjectIterator iterator() { + return listIterator(0); + } + + @Override + public ObjectListIterator listIterator() { + return listIterator(0); + } + + @Override + public ObjectListIterator listIterator(int index) { + if(index < 0 || index > size()) throw new IndexOutOfBoundsException(); + return new ObjectListIter(index); + } + + @Override + public void size(int size) { + while(size > size()) add(null); + while(size < size()) remove(size() - 1); + } + + public AbstractObjectList copy() { throw new UnsupportedOperationException(); } + + private class SubList extends AbstractObjectList + { + final AbstractObjectList list; + final int parentOffset; + final int offset; + int size; + + public SubList(AbstractObjectList list, int offset, int from, int to) { + this.list = list; + this.parentOffset = from; + this.offset = offset + from; + this.size = to - from; + } + + @Override + public void add(int index, T element) { + checkAddSubRange(index); + list.add(parentOffset+index, element); + size++; + } + + @Override + public boolean addAll(int index, Collection c) { + checkAddSubRange(index); + int add = c.size(); + if(add <= 0) return false; + list.addAll(parentOffset+index, c); + this.size += add; + return true; + } + + @Override + public boolean addAll(int index, ObjectCollection c) { + checkAddSubRange(index); + int add = c.size(); + if(add <= 0) return false; + list.addAll(parentOffset+index, c); + this.size += add; + return true; + } + + @Override + public boolean addAll(int index, ObjectList c) { + checkAddSubRange(index); + int add = c.size(); + if(add <= 0) return false; + list.addAll(parentOffset+index, c); + this.size += add; + return true; + } + + @Override + public void addElements(int from, T[] a, int offset, int length) { + checkAddSubRange(from); + if(length <= 0) return; + list.addElements(parentOffset+from, a, offset, length); + this.size += length; + } + + @Override + public T[] getElements(int from, T[] a, int offset, int length) { + SanityChecks.checkArrayCapacity(size, from, length); + SanityChecks.checkArrayCapacity(a.length, offset, length); + return list.getElements(from+parentOffset, a, offset, length); + } + + @Override + public void removeElements(int from, int to) { + if(to-from <= 0) return; + checkSubRange(from); + checkAddSubRange(to); + list.removeElements(from+parentOffset, to+parentOffset); + size -= to - from; + } + + @Override + public K[] extractElements(int from, int to, Class type) { + checkSubRange(from); + checkAddSubRange(to); + K[] result = list.extractElements(from+parentOffset, to+parentOffset, type); + size -= result.length; + return result; + } + + @Override + public T get(int index) { + checkSubRange(index); + return list.get(parentOffset+index); + } + + @Override + public T set(int index, T element) { + checkSubRange(index); + return list.set(parentOffset+index, element); + } + + @Override + public T swapRemove(int index) { + checkSubRange(index); + if(index == size-1) { + T result = list.remove(parentOffset+size-1); + size--; + return result; + } + T result = list.set(index+parentOffset, list.get(parentOffset+size-1)); + list.remove(parentOffset+size-1); + size--; + return result; + } + + @Override + public T remove(int index) { + checkSubRange(index); + T result = list.remove(index+parentOffset); + size--; + return result; + } + + @Override + public int size() { + return size; + } + + @Override + public ObjectSplititerator spliterator() { return ObjectSplititerators.createSplititerator(this, 16464); } + + @Override + public ObjectListIterator listIterator(int index) { + if(index < 0 || index > size()) throw new IndexOutOfBoundsException(); + return new SubListIterator(this, index); + } + + @Override + public ObjectList subList(int fromIndex, int toIndex) { + SanityChecks.checkArrayCapacity(size, fromIndex, toIndex-fromIndex); + return new SubList(this, offset, fromIndex, toIndex); + } + + protected void checkSubRange(int index) { + if (index < 0 || index >= size) + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + + protected void checkAddSubRange(int index) { + if (index < 0 || index > size) + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + + private class SubListIterator implements ObjectListIterator + { + AbstractObjectList list; + int index; + int lastReturned = -1; + + SubListIterator(AbstractObjectList list, int index) { + this.list = list; + this.index = index; + } + + @Override + public boolean hasNext() { + return index < list.size(); + } + + @Override + public T next() { + if(!hasNext()) throw new NoSuchElementException(); + int i = index++; + return list.get((lastReturned = i)); + } + + @Override + public boolean hasPrevious() { + return index > 0; + } + + @Override + public T previous() { + if(!hasPrevious()) throw new NoSuchElementException(); + index--; + return list.get((lastReturned = index)); + } + + @Override + public int nextIndex() { + return index; + } + + @Override + public int previousIndex() { + return index-1; + } + + @Override + public void remove() { + if(lastReturned == -1) throw new IllegalStateException(); + list.remove(lastReturned); + index = lastReturned; + lastReturned = -1; + } + + @Override + public void set(T e) { + if(lastReturned == -1) throw new IllegalStateException(); + list.set(lastReturned, e); + } + + @Override + public void add(T e) { + list.add(index, e); + index++; + lastReturned = -1; + } + + @Override + public int skip(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int steps = Math.min(amount, size() - index); + index += steps; + if(steps > 0) lastReturned = Math.min(index-1, size()-1); + return steps; + } + + @Override + public int back(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int steps = Math.min(amount, index); + index -= steps; + if(steps > 0) lastReturned = Math.min(index, size()-1); + return steps; + } + } + } + + private class ObjectListIter implements ObjectListIterator { + int index; + int lastReturned = -1; + + ObjectListIter(int index) { + this.index = index; + } + + @Override + public boolean hasNext() { + return index < size(); + } + + @Override + public T next() { + if(!hasNext()) throw new NoSuchElementException(); + int i = index++; + return get((lastReturned = i)); + } + + @Override + public boolean hasPrevious() { + return index > 0; + } + + @Override + public T previous() { + if(!hasPrevious()) throw new NoSuchElementException(); + index--; + return get((lastReturned = index)); + } + + @Override + public int nextIndex() { + return index; + } + + @Override + public int previousIndex() { + return index-1; + } + + @Override + public void remove() { + if(lastReturned == -1) throw new IllegalStateException(); + AbstractObjectList.this.remove(lastReturned); + index = lastReturned; + lastReturned = -1; + } + + @Override + public void set(T e) { + if(lastReturned == -1) throw new IllegalStateException(); + AbstractObjectList.this.set(lastReturned, e); + } + + @Override + public void add(T e) { + AbstractObjectList.this.add(index, e); + index++; + lastReturned = -1; + } + + @Override + public int skip(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int steps = Math.min(amount, size() - index); + index += steps; + if(steps > 0) lastReturned = Math.min(index-1, size()-1); + return steps; + } + + @Override + public int back(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int steps = Math.min(amount, index); + index -= steps; + if(steps > 0) lastReturned = Math.min(index, size()-1); + return steps; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/lists/ObjectArrayList.java b/src/main/java/speiger/src/collections/objects/lists/ObjectArrayList.java new file mode 100644 index 000000000..a666fb1b3 --- /dev/null +++ b/src/main/java/speiger/src/collections/objects/lists/ObjectArrayList.java @@ -0,0 +1,888 @@ +package speiger.src.collections.objects.lists; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.Collection; +import java.util.Iterator; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.BiFunction; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + +import speiger.src.collections.objects.collections.ObjectCollection; +import speiger.src.collections.objects.collections.ObjectIterator; +import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer; +import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator; +import speiger.src.collections.objects.utils.ObjectArrays; +import speiger.src.collections.objects.utils.ObjectArrays; +import speiger.src.collections.objects.utils.ObjectIterators; +import speiger.src.collections.utils.Stack; +import speiger.src.collections.objects.collections.ObjectSplititerator; +import speiger.src.collections.objects.utils.ObjectSplititerators; +import speiger.src.collections.utils.IArray; +import speiger.src.collections.utils.SanityChecks; + +/** + * A Type-Specific Array-based implementation of list that is written to reduce (un)boxing + * + *

This implementation is optimized to improve how data is processed with interfaces like {@link IArray}, {@link Stack} + * and with optimized functions that use type-specific implementations for primitives and optimized logic for bulkactions. + * + * @param the keyType of elements maintained by this Collection + */ +public class ObjectArrayList extends AbstractObjectList implements IArray, Stack +{ + static final int DEFAULT_ARRAY_SIZE = 10; + + /** The backing array */ + protected transient T[] data; + /** The current size of the elements stored in the backing array */ + protected int size = 0; + + /** + * Creates a new ArrayList with a Empty array. + */ + public ObjectArrayList() { + data = (T[])ObjectArrays.EMPTY_ARRAY; + } + + /** + * Creates a new ArrayList with the specific requested size + * @param size the minimum initial size of the Backing array + */ + public ObjectArrayList(int size) { + if(size < 0) throw new IllegalStateException("Size has to be 0 or greater"); + data = (T[])new Object[size]; + } + + /** + * Creates a new ArrayList a copy with the contents of the Collection. + * @param c the elements that should be added into the list + */ + public ObjectArrayList(Collection c) { + this(c.size()); + size = ObjectIterators.unwrap(data, c.iterator()); + } + + /** + * Creates a new ArrayList a copy with the contents of the Collection. + * @param c the elements that should be added into the list + */ + public ObjectArrayList(ObjectCollection c) { + this(c.size()); + size = ObjectIterators.unwrap(data, c.iterator()); + } + + /** + * Creates a new ArrayList a copy with the contents of the List. + * @param l the elements that should be added into the list + */ + public ObjectArrayList(ObjectList l) { + this(l.size()); + size = l.size(); + l.getElements(0, data, 0, size); + } + + /** + * Creates a new ArrayList with a Copy of the array + * @param a the array that should be copied + */ + public ObjectArrayList(T... a) { + this(a, 0, a.length); + } + + /** + * Creates a new ArrayList with a Copy of the array with a custom length + * @param a the array that should be copied + * @param length the desired length that should be copied + */ + public ObjectArrayList(T[] a, int length) { + this(a, 0, length); + } + + /** + * Creates a new ArrayList with a Copy of the array with in the custom range. + * @param a the array that should be copied + * @param offset the starting offset of where the array should be copied from + * @param length the desired length that should be copied + * @throws IllegalStateException if offset is smaller then 0 + * @throws IllegalStateException if the offset + length exceeds the array length + */ + public ObjectArrayList(T[] a, int offset, int length) { + this(length); + SanityChecks.checkArrayCapacity(a.length, offset, length); + System.arraycopy(a, offset, data, 0, length); + size = length; + } + + /** + * Creates a wrapped arraylist that uses the array as backing array + * @param a elements that should be wrapped + * @param the keyType of elements maintained by this Collection + * @return a Wrapped list using the input array + */ + public static ObjectArrayList wrap(T... a) { + return wrap(a, a.length); + } + + /** + * Creates a wrapped arraylist that uses the array as backing array and a custom fill size + * @param a elements that should be wrapped + * @param length the size of the elements within the array + * @param the keyType of elements maintained by this Collection + * @return a Wrapped list using the input array + */ + public static ObjectArrayList wrap(T[] a, int length) { + SanityChecks.checkArrayCapacity(a.length, 0, length); + ObjectArrayList list = new ObjectArrayList<>(); + list.data = a; + list.size = length; + return list; + } + + /** + * Creates a new ArrayList with a EmptyObject array of the Type requested + * @param c the type of the array + * @param the keyType of elements maintained by this Collection + * @return a typed List + */ + public static ObjectArrayList of(Class c) { + ObjectArrayList list = new ObjectArrayList<>(); + list.data = (T[])ObjectArrays.newArray(c, 0); + return list; + } + + /** + * Creates a new ArrayList with a EmptyObject array of the Type requested + * @param c the type of the array + * @param size the initial size of the backing array + * @param the keyType of elements maintained by this Collection + * @return a typed List + */ + public static ObjectArrayList of(Class c, int size) { + ObjectArrayList list = new ObjectArrayList<>(); + list.data = (T[])ObjectArrays.newArray(c, size); + return list; + } + + /** + * Appends the specified element to the end of this list. + * + * @param e element to be appended to this list + * @return true (as specified by {@link Collection#add}) + */ + @Override + public boolean add(T e) { + grow(size + 1); + data[size++] = e; + return true; + } + + /** + * Appends the specified element to the end of this Stack. + * @param e element to be appended to this Stack + */ + @Override + public void push(T e) { + add(e); + } + + /** + * Appends the specified element to the index of the list + * @param index the index where to append the element to + * @param e the element to append to the list + * @throws IndexOutOfBoundsException if index is outside of the lists range + */ + @Override + public void add(int index, T e) { + checkAddRange(index); + grow(size + 1); + if(index != size) System.arraycopy(data, index, data, index+1, size - index); + data[index] = e; + size++; + } + + /** + * Appends the specified elements to the index of the list. + * This function may delegate to more appropriate function if necessary + * @param index the index where to append the elements to + * @param c the elements to append to the list + * @throws IndexOutOfBoundsException if index is outside of the lists range + * @throws NullPointerException if collection contains a null element + */ + @Override + public boolean addAll(int index, Collection c) { + if(c instanceof ObjectCollection) return addAll(index, (ObjectCollection)c); + int add = c.size(); + if(add <= 0) return false; + grow(size + add); + if(index != size) System.arraycopy(data, index, data, index+add, size - index); + size+=add; + Iterator iter = c.iterator(); + while(add-- != 0) data[index++] = iter.next(); + return true; + } + + /** + * Appends the specified elements to the index of the list. + * This function may delegate to more appropriate function if necessary + * @param index the index where to append the elements to + * @param c the elements to append to the list + * @throws IndexOutOfBoundsException if index is outside of the lists range + */ + @Override + public boolean addAll(int index, ObjectCollection c) { + if(c instanceof ObjectList) return addAll(index, (ObjectList)c); + int add = c.size(); + if(add <= 0) return false; + grow(size + add); + if(index != size) System.arraycopy(data, index, data, index+add, size - index); + size+=add; + ObjectIterator iter = c.iterator(); + while(add-- != 0) data[index++] = iter.next(); + return true; + } + + /** + * Appends the specified elements to the index of the list. + * @param index the index where to append the elements to + * @param c the elements to append to the list + * @throws IndexOutOfBoundsException if index is outside of the lists range + */ + @Override + public boolean addAll(int index, ObjectList c) { + int add = c.size(); + if(add <= 0) return false; + checkAddRange(index); + grow(size + add); + if(index != size) System.arraycopy(data, index, data, index+add, size - index); + size+=add; + c.getElements(0, data, index, c.size()); + return true; + } + + @Override + public boolean addAll(T[] e, int offset, int length) { + if(length <= 0) return false; + SanityChecks.checkArrayCapacity(e.length, offset, length); + grow(size + length); + System.arraycopy(e, offset, data, size, length); + size+=length; + return true; + } + + /** + * Appends the specified array elements to the index of the list. + * @param from the index where to append the elements to + * @param a the elements to append to the list + * @param offset where to start ino the array + * @param length the amount of elements to insert + * @throws IndexOutOfBoundsException if index is outside of the lists range + */ + @Override + public void addElements(int from, T[] a, int offset, int length) { + if(length <= 0) return; + checkAddRange(from); + SanityChecks.checkArrayCapacity(a.length, offset, length); + grow(size + length); + if(from != size) System.arraycopy(data, from, data, from+length, size - from); + size+=length; + System.arraycopy(a, offset, data, from, length); + } + + /** + * A function to fast fetch elements from the list + * @param from index where the list should be fetching elements from + * @param a the array where the values should be inserted to + * @param offset the startIndex of where the array should be written to + * @param length the number of elements the values should be fetched from + * @return the inputArray + * @throws NullPointerException if the array is null + * @throws IndexOutOfBoundsException if from is outside of the lists range + * @throws IllegalStateException if offset or length are smaller then 0 or exceed the array length + */ + @Override + public T[] getElements(int from, T[] a, int offset, int length) { + SanityChecks.checkArrayCapacity(size, from, length); + SanityChecks.checkArrayCapacity(a.length, offset, length); + System.arraycopy(data, from, a, offset, length); + return a; + } + + /** + * a function to fast remove elements from the list. + * @param from the start index of where the elements should be removed from (inclusive) + * @param to the end index of where the elements should be removed to (exclusive) + */ + @Override + public void removeElements(int from, int to) { + checkRange(from); + checkAddRange(to); + int length = to - from; + if(length <= 0) return; + if(to != size) System.arraycopy(data, to, data, from, size - to); + size -= length; + for(int i = 0;i K[] extractElements(int from, int to, Class type) { + checkRange(from); + checkAddRange(to); + int length = to - from; + if(length <= 0) return ObjectArrays.newArray(type, 0); + K[] a = ObjectArrays.newArray(type, length); + System.arraycopy(data, from, a, 0, length); + if(to != size) System.arraycopy(data, to, data, from, size - to); + size -= length; + for(int i = 0;i=0;i--) + if(data[i] == null) return i; + return -1; + } + for(int i = size - 1;i>=0;i--) { + if(Objects.equals(o, data[i])) return i; + } + return -1; + } + + /** + * Sorts the elements specified by the Natural order either by using the Comparator or the elements + * @param c the sorter of the elements, can be null + * @see java.util.List#sort(Comparator) + */ + @Override + public void sort(Comparator c) { + if(c != null) ObjectArrays.stableSort(data, size, c); + else ObjectArrays.stableSort(data, size); + } + + /** + * Sorts the elements specified by the Natural order either by using the Comparator or the elements using a unstable sort + * @param c the sorter of the elements, can be null + * @see java.util.List#sort(Comparator) + */ + @Override + public void unstableSort(Comparator c) { + if(c != null) ObjectArrays.unstableSort(data, size, c); + else ObjectArrays.unstableSort(data, size); + } + + /** + * A Type-Specific get function to reduce (un)boxing + * @param index the index of the element to fetch + * @return the value of the requested index + * @throws IndexOutOfBoundsException if the index is out of range + */ + @Override + public T get(int index) { + checkRange(index); + return data[index]; + } + + /** + * Provides the Selected Object from the stack. + * Top to bottom + * @param index of the element that should be provided + * @return the element that was requested + * @throws ArrayIndexOutOfBoundsException if the index is out of bounds + * @see Stack#peek(int) + */ + @Override + public T peek(int index) { + checkRange((size() - 1) - index); + return data[(size() - 1) - index]; + } + + /** + * A Type Specific foreach function that reduces (un)boxing + * + * @implSpec + *

The default implementation behaves as if: + *

{@code
+	 * 	for(int i = 0;i
+	 *
+	 * @param action The action to be performed for each element
+	 * @throws NullPointerException if the specified action is null
+	 * @see Iterable#forEach(Consumer)
+	 */
+	@Override
+	public void forEach(Consumer action) {
+		Objects.requireNonNull(action);
+		for(int i = 0;i void forEach(E input, ObjectObjectConsumer action) {
+		Objects.requireNonNull(action);
+		for(int i = 0;i filter) {
+		Objects.requireNonNull(filter);
+		for(int i = 0;i filter) {
+		Objects.requireNonNull(filter);
+		for(int i = 0;i filter) {
+		Objects.requireNonNull(filter);
+		for(int i = 0;i filter) {
+		Objects.requireNonNull(filter);
+		for(int i = 0;i E reduce(E identity, BiFunction operator) {
+		Objects.requireNonNull(operator);
+		E state = identity;
+		for(int i = 0;i operator) {
+		Objects.requireNonNull(operator);
+		T state = null;
+		boolean empty = true;
+		for(int i = 0;i filter) {
+		Objects.requireNonNull(filter);
+		int result = 0;
+		for(int i = 0;i o) {
+		Objects.requireNonNull(o);
+		for(int i = 0;i c) {
+		if(c.isEmpty()) return false;
+		boolean modified = false;
+		int j = 0;
+		for(int i = 0;i c) {
+		if(c.isEmpty()) {
+			boolean modifed = size > 0;
+			clear();
+			return modifed;
+		}
+		boolean modified = false;
+		int j = 0;
+		for(int i = 0;i filter) {
+		Objects.requireNonNull(filter);
+		boolean modified = false;
+		int j = 0;
+		for(int i = 0;i c) {
+		if(c.isEmpty()) return false;
+		boolean modified = false;
+		int j = 0;
+		for(int i = 0;i c, Consumer r) {
+		if(c.isEmpty()) return false;
+		int j = 0;
+		for(int i = 0;i c) {
+		if(c.isEmpty()) {
+			boolean modifed = size > 0;
+			clear();
+			return modifed;
+		}
+		boolean modified = false;
+		int j = 0;
+		for(int i = 0;i c, Consumer r) {
+		if(c.isEmpty()) {
+			boolean modifed = size > 0;
+			forEach(r);
+			clear();
+			return modifed;
+		}
+		int j = 0;
+		for(int i = 0;i E[] toArray(E[] a) {
+		if(a == null) a = (E[])new Object[size];
+		else if(a.length < size) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), size);
+        System.arraycopy(data, 0, a, 0, size);
+		if (a.length > size) a[size] = null;
+		return a;
+	}
+
+	/**
+	 * A function to return the size of the list
+	 * @return the size of elements in the list
+	 */
+	@Override
+	public int size() {
+		return size;
+	}
+
+	/**
+	 * A function to ensure the elements are within the requested size.
+	 * If smaller then the stored elements they get removed as needed.
+	 * If bigger it is ensured that enough room is provided depending on the implementation
+	 * @param size the requested amount of elements/room for elements
+	 */
+	@Override
+	public void size(int size) {
+		if(size > data.length)
+			data = Arrays.copyOf(data, size);
+		else if(size < size() && size >= 0)
+			Arrays.fill(data, size, size(), null);
+		this.size = size;
+	}
+
+	/**
+	 * A function to clear all elements in the list.
+	 */
+	@Override
+	public void clear() {
+		for(int i = 0;i size() || size() == data.length) return false;
+		int value = Math.max(size, size());
+		data = value == 0 ? (T[])ObjectArrays.EMPTY_ARRAY : Arrays.copyOf(data, value);
+		return true;
+	}
+
+	/**
+	 * Trims the collection down to the requested size and clears all elements while doing so
+	 * @param size the amount of elements that should be allowed
+	 * @note this will enforce minimum size of the collection itself
+	 */
+	@Override
+	public void clearAndTrim(int size) {
+		if(data.length <= size) {
+			clear();
+			return;
+		}
+		data = size == 0 ? (T[])ObjectArrays.EMPTY_ARRAY : (T[])new Object[size];
+		this.size = size;
+	}
+
+	/**
+	 * Increases the capacity of this implementation instance, if necessary,
+	 * to ensure that it can hold at least the number of elements specified by
+	 * the minimum capacity argument.
+	 *
+	 * @param size the desired minimum capacity
+	 */
+	@Override
+	public void ensureCapacity(int size) {
+		grow(size);
+	}
+
+	@Override
+	public ObjectArrayList copy() {
+		ObjectArrayList list = new ObjectArrayList<>();
+		list.data = Arrays.copyOf(data, data.length);
+		list.size = size;
+		return list;
+	}
+
+	protected void grow(int capacity) {
+		if(capacity <= data.length) return;
+		data = Arrays.copyOf(data, data == ObjectArrays.EMPTY_ARRAY ? Math.max(DEFAULT_ARRAY_SIZE, capacity) : (int)Math.max(Math.min((long)data.length + (data.length >> 1), SanityChecks.MAX_ARRAY_SIZE), capacity));
+	}
+
+	protected void checkRange(int index) {
+		if (index < 0 || index >= size)
+			throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+	}
+
+	protected void checkAddRange(int index) {
+		if (index < 0 || index > size)
+			throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+	}
+
+	/**
+	 * A Type Specific Type Splititerator to reduce boxing/unboxing
+	 * @return type specific splititerator
+	 * @note characteristics are ordered, sized, subsized
+	 */
+	@Override
+	public ObjectSplititerator spliterator() { return ObjectSplititerators.createArraySplititerator(data, size, 16464); }
+}
diff --git a/src/main/java/speiger/src/collections/objects/lists/ObjectList.java b/src/main/java/speiger/src/collections/objects/lists/ObjectList.java
new file mode 100644
index 000000000..dcfe8cd9f
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/lists/ObjectList.java
@@ -0,0 +1,238 @@
+package speiger.src.collections.objects.lists;
+
+import java.util.List;
+
+import java.util.Objects;
+import java.util.Comparator;
+import java.util.function.UnaryOperator;
+
+import speiger.src.collections.objects.collections.ObjectCollection;
+import speiger.src.collections.objects.collections.ObjectSplititerator;
+import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
+import speiger.src.collections.objects.utils.ObjectArrays;
+import speiger.src.collections.objects.utils.ObjectSplititerators;
+
+/**
+ * A Type Specific List interface that reduces boxing/unboxing and adds a couple extra quality of life features
+ * @param  the keyType of elements maintained by this Collection
+ */
+public interface ObjectList extends ObjectCollection, List
+{
+	/**
+	 * A Helper function that will only add elements if it is not present.
+	 * @param e the element to add
+	 * @return true if the list was modified
+	 */
+	public default boolean addIfAbsent(T e) {
+		if(indexOf(e) == -1) return add(e);
+		return false;
+	}
+
+	/**
+	 * A Helper function that will only add elements if it is present.
+	 * @param e the element to add
+	 * @return true if the list was modified
+	 */
+	public default boolean addIfPresent(T e) {
+		if(indexOf(e) != -1) return add(e);
+		return false;
+	}
+
+	/**
+	 * A Type-Specific addAll Function to reduce (un)boxing
+	 * @param c the elements that need to be added
+	 * @param index index at which the specified elements is to be inserted
+	 * @return true if the list was modified
+	 * @see List#addAll(int, java.util.Collection)
+	 */
+	public boolean addAll(int index, ObjectCollection c);
+
+	/**
+	 * A Type-Specific and optimized addAll function that allows a faster transfer of elements
+	 * @param c the elements that need to be added
+	 * @return true if the list was modified
+	 */
+	public boolean addAll(ObjectList c);
+
+	/**
+	 * A Type-Specific and optimized addAll function that allows a faster transfer of elements
+	 * @param c the elements that need to be added
+	 * @param index index at which the specified elements is to be inserted
+	 * @return true if the list was modified
+	 */
+	public boolean addAll(int index, ObjectList c);
+
+	/**
+	 * A function to replace all values in the list
+	 * @param o the action to replace the values
+	 * @throws NullPointerException if o is null
+	 */
+	@Override
+	public default void replaceAll(UnaryOperator o) {
+		Objects.requireNonNull(o);
+		ObjectListIterator iter = listIterator();
+		while (iter.hasNext()) iter.set(o.apply(iter.next()));
+	}
+
+	/**
+	 * A function to fast add elements to the list
+	 * @param a the elements that should be added
+	 * @throws IndexOutOfBoundsException if from is outside of the lists range
+	 */
+	public default void addElements(T... a) { addElements(size(), a, 0, a.length); }
+
+	/**
+	 * A function to fast add elements to the list
+	 * @param from the index where the elements should be added into the list
+	 * @param a the elements that should be added
+	 * @throws IndexOutOfBoundsException if from is outside of the lists range
+	 */
+	public default void addElements(int from, T... a) { addElements(from, a, 0, a.length); }
+
+	/**
+	 * A function to fast add elements to the list
+	 * @param from the index where the elements should be added into the list
+	 * @param a the elements that should be added
+	 * @param offset the start index of the array should be read from
+	 * @param length how many elements should be read from
+	 * @throws IndexOutOfBoundsException if from is outside of the lists range
+	 */
+	public void addElements(int from, T[] a, int offset, int length);
+
+	/**
+	 * A function to fast fetch elements from the list
+	 * @param from index where the list should be fetching elements from
+	 * @param a the array where the values should be inserted to
+	 * @return the inputArray
+	 * @throws NullPointerException if the array is null
+	 * @throws IndexOutOfBoundsException if from is outside of the lists range
+	 * @throws IllegalStateException if offset or length are smaller then 0 or exceed the array length
+	 */
+	public default T[] getElements(int from, T[] a) { return getElements(from, a, 0, a.length); }
+
+	/**
+	 * A function to fast fetch elements from the list
+	 * @param from index where the list should be fetching elements from
+	 * @param a the array where the values should be inserted to
+	 * @param offset the startIndex of where the array should be written to
+	 * @param length the number of elements the values should be fetched from
+	 * @return the inputArray
+	 * @throws NullPointerException if the array is null
+	 * @throws IndexOutOfBoundsException if from is outside of the lists range
+	 * @throws IllegalStateException if offset or length are smaller then 0 or exceed the array length
+	 */
+	public T[] getElements(int from, T[] a, int offset, int length);
+
+	/**
+	 * a function to fast remove elements from the list.
+	 * @param from the start index of where the elements should be removed from (inclusive)
+	 * @param to the end index of where the elements should be removed to (exclusive)
+	 */
+	public void removeElements(int from, int to);
+
+	/**
+	 * A Highly Optimized remove function that removes the desired element.
+	 * But instead of shifting the elements to the left it moves the last element to the removed space.
+	 * @param index the index of the element to be removed
+	 * @return the element previously at the specified position
+	 */
+	public T swapRemove(int index);
+
+	/**
+	 * A Highly Optimized remove function that removes the desired element.
+	 * But instead of shifting the elements to the left it moves the last element to the removed space.
+	 * @param e the element that should be removed
+	 * @return true if the element was removed
+	 */
+	public boolean swapRemove(T e);
+
+	/**
+	 * A function to fast extract elements out of the list, this removes the elements that were fetched.
+	 * @param from the start index of where the elements should be fetched from (inclusive)
+	 * @param to the end index of where the elements should be fetched to (exclusive)
+	 * @param type the type of the OutputArray
+	 * @return a array of the elements that were fetched
+	 * @param  the keyType of elements maintained by this Collection
+ 	 */
+	public  K[] extractElements(int from, int to, Class type);
+
+	/**
+	 * Sorts the elements specified by the Natural order either by using the Comparator or the elements
+	 * @see List#sort(Comparator)
+	 */
+	@Override
+	public default void sort(Comparator c) {
+		T[] array = (T[])toArray();
+		if(c != null) ObjectArrays.stableSort(array, c);
+		else ObjectArrays.stableSort(array);
+		ObjectListIterator iter = listIterator();
+		for (int i = 0,m=size();i c) {
+		T[] array = (T[])toArray();
+		if(c != null) ObjectArrays.unstableSort(array, c);
+		else ObjectArrays.unstableSort(array);
+		ObjectListIterator iter = listIterator();
+		for (int i = 0,m=size();i action) {
+		Objects.requireNonNull(action);
+		for(int i = 0,m=size();i listIterator();
+
+	/**
+	 * A Type-Specific Iterator of listIterator
+	 * @see List#listIterator(int)
+	 */
+	@Override
+	public ObjectListIterator listIterator(int index);
+
+	/**
+	 * A Type-Specific List of subList
+	 * @see List#subList(int, int)
+	 */
+	@Override
+	public ObjectList subList(int from, int to);
+
+	/**
+	 * A function to ensure the elements are within the requested size.
+	 * If smaller then the stored elements they get removed as needed.
+	 * If bigger it is ensured that enough room is provided depending on the implementation
+	 * @param size the requested amount of elements/room for elements
+	 */
+	public void size(int size);
+
+	@Override
+	public ObjectList copy();
+	/**
+	 * A Type Specific Type Splititerator to reduce boxing/unboxing
+	 * @return type specific splititerator
+	 */
+	@Override
+	default ObjectSplititerator spliterator() { return ObjectSplititerators.createSplititerator(this, 0); }
+}
diff --git a/src/main/java/speiger/src/collections/objects/lists/ObjectListIterator.java b/src/main/java/speiger/src/collections/objects/lists/ObjectListIterator.java
new file mode 100644
index 000000000..87e6d421f
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/lists/ObjectListIterator.java
@@ -0,0 +1,13 @@
+package speiger.src.collections.objects.lists;
+
+import java.util.ListIterator;
+
+import speiger.src.collections.objects.collections.ObjectBidirectionalIterator;
+
+/**
+ * A Type Specific ListIterator that reduces boxing/unboxing
+ * @param  the keyType of elements maintained by this Collection
+ */
+public interface ObjectListIterator extends ListIterator, ObjectBidirectionalIterator
+{
+}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/maps/abstracts/AbstractObject2ObjectMap.java b/src/main/java/speiger/src/collections/objects/maps/abstracts/AbstractObject2ObjectMap.java
new file mode 100644
index 000000000..8f6964218
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/maps/abstracts/AbstractObject2ObjectMap.java
@@ -0,0 +1,426 @@
+package speiger.src.collections.objects.maps.abstracts;
+
+import java.util.AbstractMap;
+import java.util.Map;
+import java.util.Objects;
+
+import speiger.src.collections.objects.collections.ObjectIterator;
+import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
+import speiger.src.collections.objects.functions.function.UnaryOperator;
+import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator;
+import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
+import speiger.src.collections.objects.sets.AbstractObjectSet;
+import speiger.src.collections.objects.sets.ObjectSet;
+import speiger.src.collections.objects.collections.AbstractObjectCollection;
+import speiger.src.collections.objects.collections.ObjectCollection;
+import speiger.src.collections.objects.functions.ObjectSupplier;
+import speiger.src.collections.objects.collections.ObjectIterable;
+import speiger.src.collections.utils.SanityChecks;
+
+/**
+ * A Base Implementation of a Type Specific Map to reduce boxing/unboxing
+ * @param  the keyType of elements maintained by this Collection
+ * @param  the keyType of elements maintained by this Collection
+ */
+public abstract class AbstractObject2ObjectMap extends AbstractMap implements Object2ObjectMap
+{
+	protected V defaultReturnValue = null;
+	
+	@Override
+	public V getDefaultReturnValue() {
+		return defaultReturnValue;
+	}
+	
+	@Override
+	public AbstractObject2ObjectMap setDefaultReturnValue(V v) {
+		defaultReturnValue = v;
+		return this;
+	}
+	
+	protected ObjectIterable> getFastIterable(Object2ObjectMap map) {
+		return map.object2ObjectEntrySet();
+	}
+	
+	protected ObjectIterator> getFastIterator(Object2ObjectMap map) {
+		return map.object2ObjectEntrySet().iterator();
+	}
+	
+	@Override
+	public Object2ObjectMap copy() { 
+		throw new UnsupportedOperationException();
+	}
+	
+	@Override
+	public void putAll(Object2ObjectMap m) {
+		for(ObjectIterator> iter = getFastIterator(m);iter.hasNext();) {
+			Object2ObjectMap.Entry entry = iter.next();
+			put(entry.getKey(), entry.getValue());
+		}
+	}
+	
+	@Override
+	public void putAll(Map m)
+	{
+		if(m instanceof Object2ObjectMap) putAll((Object2ObjectMap)m);
+		else super.putAll(m);
+	}
+	
+	@Override
+	public void putAll(T[] keys, V[] values, int offset, int size) {
+		SanityChecks.checkArrayCapacity(keys.length, offset, size);
+		SanityChecks.checkArrayCapacity(values.length, offset, size);
+		for(int i = 0;i m) {
+		for(Object2ObjectMap.Entry entry : getFastIterable(m))
+			putIfAbsent(entry.getKey(), entry.getValue());
+	}
+	
+	
+	@Override
+	public boolean containsKey(Object key) {
+		for(ObjectIterator iter = keySet().iterator();iter.hasNext();)
+			if(Objects.equals(key, iter.next())) return true;
+		return false;
+	}
+	
+	@Override
+	public boolean containsValue(Object value) {
+		for(ObjectIterator iter = values().iterator();iter.hasNext();)
+			if(Objects.equals(value, iter.next())) return true;
+		return false;
+	}
+	
+	@Override
+	public boolean replace(T key, V oldValue, V newValue) {
+		V curValue = getObject(key);
+		if (!Objects.equals(curValue, oldValue) || (Objects.equals(curValue, getDefaultReturnValue()) && !containsKey(key))) {
+			return false;
+		}
+		put(key, newValue);
+		return true;
+	}
+
+	@Override
+	public V replace(T key, V value) {
+		V curValue;
+		if (!Objects.equals((curValue = getObject(key)), getDefaultReturnValue()) || containsKey(key)) {
+			curValue = put(key, value);
+		}
+		return curValue;
+	}
+	
+	@Override
+	public void replaceObjects(Object2ObjectMap m) {
+		for(Object2ObjectMap.Entry entry : getFastIterable(m))
+			replace(entry.getKey(), entry.getValue());
+	}
+	
+	@Override
+	public void replaceObjects(ObjectObjectUnaryOperator mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		for(ObjectIterator> iter = getFastIterator(this);iter.hasNext();) {
+			Object2ObjectMap.Entry entry = iter.next();
+			entry.setValue(mappingFunction.apply(entry.getKey(), entry.getValue()));
+		}
+	}
+
+	@Override
+	public V compute(T key, ObjectObjectUnaryOperator mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		V value = getObject(key);
+		V newValue = mappingFunction.apply(key, value);
+		if(Objects.equals(newValue, getDefaultReturnValue())) {
+			if(!Objects.equals(value, getDefaultReturnValue()) || containsKey(key)) {
+				remove(key);
+				return getDefaultReturnValue();
+			}
+			return getDefaultReturnValue();
+		}
+		put(key, newValue);
+		return newValue;
+	}
+	
+	@Override
+	public V computeIfAbsent(T key, UnaryOperator mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		V value;
+		if((value = getObject(key)) == getDefaultReturnValue() || !containsKey(key)) {
+			V newValue = mappingFunction.apply(key);
+			if(!Objects.equals(newValue, getDefaultReturnValue())) {
+				put(key, newValue);
+				return newValue;
+			}
+		}
+		return value;
+	}
+	
+	@Override
+	public V supplyIfAbsent(T key, ObjectSupplier valueProvider) {
+		Objects.requireNonNull(valueProvider);
+		V value;
+		if((value = getObject(key)) == getDefaultReturnValue() || !containsKey(key)) {
+			V newValue = valueProvider.get();
+			if(!Objects.equals(newValue, getDefaultReturnValue())) {
+				put(key, newValue);
+				return newValue;
+			}
+		}
+		return value;
+	}
+	
+	@Override
+	public V computeIfPresent(T key, ObjectObjectUnaryOperator mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		V value;
+		if(!Objects.equals((value = getObject(key)), getDefaultReturnValue()) || containsKey(key)) {
+			V newValue = mappingFunction.apply(key, value);
+			if(!Objects.equals(newValue, getDefaultReturnValue())) {
+				put(key, newValue);
+				return newValue;
+			}
+			remove(key);
+		}
+		return getDefaultReturnValue();
+	}
+
+	@Override
+	public V merge(T key, V value, ObjectObjectUnaryOperator mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		V oldValue = getObject(key);
+		V newValue = Objects.equals(oldValue, getDefaultReturnValue()) ? value : mappingFunction.apply(oldValue, value);
+		if(Objects.equals(newValue, getDefaultReturnValue())) remove(key);
+		else put(key, newValue);
+		return newValue;
+	}
+	
+	@Override
+	public void mergeAll(Object2ObjectMap m, ObjectObjectUnaryOperator mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		for(Object2ObjectMap.Entry entry : getFastIterable(m)) {
+			T key = entry.getKey();
+			V oldValue = getObject(key);
+			V newValue = Objects.equals(oldValue, getDefaultReturnValue()) ? entry.getValue() : mappingFunction.apply(oldValue, entry.getValue());
+			if(Objects.equals(newValue, getDefaultReturnValue())) remove(key);
+			else put(key, newValue);
+		}
+	}
+	
+	@Override
+	public V get(Object key) {
+		return getObject((T)key);
+	}
+	
+	@Override
+	public V getOrDefault(Object key, V defaultValue) {
+		V value = get(key);
+		return !Objects.equals(value, getDefaultReturnValue()) || containsKey(key) ? value : defaultValue;
+	}
+	
+	
+	@Override
+	public V remove(Object key) {
+		return rem((T)key);
+	}
+	
+	@Override
+	public void forEach(ObjectObjectConsumer action) {
+		Objects.requireNonNull(action);
+		for(ObjectIterator> iter = getFastIterator(this);iter.hasNext();) {
+			Object2ObjectMap.Entry entry = iter.next();
+			action.accept(entry.getKey(), entry.getValue());
+		}
+	}
+
+	@Override
+	public ObjectSet keySet() {
+		return new AbstractObjectSet() {
+			@Override
+			public boolean remove(Object o) {
+				if(AbstractObject2ObjectMap.this.containsKey(o)) {
+					AbstractObject2ObjectMap.this.remove(o);
+					return true;
+				}
+				return false;
+			}
+			
+			@Override
+			public boolean add(T o) {
+				throw new UnsupportedOperationException();
+			}
+			
+			@Override
+			public ObjectIterator iterator() {
+				return new ObjectIterator() {
+					ObjectIterator> iter = getFastIterator(AbstractObject2ObjectMap.this);
+					@Override
+					public boolean hasNext() {
+						return iter.hasNext();
+					}
+
+					@Override
+					public T next() {
+						return iter.next().getKey();
+					}
+					
+					@Override
+					public void remove() {
+						iter.remove();
+					}
+				};
+			}
+			
+			@Override
+			public int size() {
+				return AbstractObject2ObjectMap.this.size();
+			}
+			
+			@Override
+			public void clear() {
+				AbstractObject2ObjectMap.this.clear();
+			}
+		};
+	}
+
+	@Override
+	public ObjectCollection values() {
+		return new AbstractObjectCollection() {
+			@Override
+			public boolean add(V o) {
+				throw new UnsupportedOperationException();
+			}
+			
+			@Override
+			public int size() {
+				return AbstractObject2ObjectMap.this.size();
+			}
+			
+			@Override
+			public void clear() {
+				AbstractObject2ObjectMap.this.clear();
+			}
+			
+			@Override
+			public ObjectIterator iterator() {
+				return new ObjectIterator() {
+					ObjectIterator> iter = getFastIterator(AbstractObject2ObjectMap.this);
+					@Override
+					public boolean hasNext() {
+						return iter.hasNext();
+					}
+					
+					@Override
+					public V next() {
+						return iter.next().getValue();
+					}
+					
+					@Override
+					public void remove() {
+						iter.remove();
+					}
+				};
+			}
+		};
+	}
+	
+	@Override
+	@SuppressWarnings("rawtypes")
+	public ObjectSet> entrySet() {
+		return (ObjectSet)object2ObjectEntrySet();
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if(o == this) return true;
+		if(o instanceof Map) {
+			if(size() != ((Map)o).size()) return false;
+			if(o instanceof Object2ObjectMap) return object2ObjectEntrySet().containsAll(((Object2ObjectMap)o).object2ObjectEntrySet());
+			return object2ObjectEntrySet().containsAll(((Map)o).entrySet());
+		}
+		return false;
+	}
+	
+	@Override
+	public int hashCode() {
+		int hash = 0;
+		ObjectIterator> iter = getFastIterator(this);
+		while(iter.hasNext()) hash += iter.next().hashCode();
+		return hash;
+	}
+	
+	/**
+	 * A Simple Type Specific Entry class to reduce boxing/unboxing
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  the keyType of elements maintained by this Collection
+	 */
+	public static class BasicEntry implements Object2ObjectMap.Entry {
+		protected T key;
+		protected V value;
+		
+		/**
+		 * A basic Empty constructor
+		 */
+		public BasicEntry() {}
+		/**
+		 * A Type Specific Constructor
+		 * @param key the key of a entry
+		 * @param value the value of a entry 
+		 */
+		public BasicEntry(T key, V value) {
+			this.key = key;
+			this.value = value;
+		}
+		
+		/**
+		 * A Helper method for fast replacing values
+		 * @param key the key that should be replaced
+		 * @param value the value that should be replaced
+		 */
+		public void set(T key, V value) {
+			this.key = key;
+			this.value = value;
+		}
+		
+		@Override
+		public T getKey() {
+			return key;
+		}
+
+		@Override
+		public V getValue() {
+			return value;
+		}
+
+		@Override
+		public V setValue(V value) {
+			throw new UnsupportedOperationException();
+		}
+		
+		@Override
+		public boolean equals(Object obj) {
+			if(obj instanceof Map.Entry) {
+				if(obj instanceof Object2ObjectMap.Entry) {
+					Object2ObjectMap.Entry entry = (Object2ObjectMap.Entry)obj;
+					return Objects.equals(key, entry.getKey()) && Objects.equals(value, entry.getValue());
+				}
+				Map.Entry entry = (Map.Entry)obj;
+				Object key = entry.getKey();
+				Object value = entry.getValue();
+				return Objects.equals(this.key, key) && Objects.equals(this.value, value);
+			}
+			return false;
+		}
+		
+		@Override
+		public int hashCode() {
+			return Objects.hashCode(key) ^ Objects.hashCode(value);
+		}
+		
+		@Override
+		public String toString() {
+			return Objects.toString(key) + "=" + Objects.toString(value);
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/maps/impl/hash/Object2ObjectOpenHashMap.java b/src/main/java/speiger/src/collections/objects/maps/impl/hash/Object2ObjectOpenHashMap.java
new file mode 100644
index 000000000..721708384
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/maps/impl/hash/Object2ObjectOpenHashMap.java
@@ -0,0 +1,1258 @@
+package speiger.src.collections.objects.maps.impl.hash;
+
+import java.util.Arrays;
+import java.util.ConcurrentModificationException;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.BiFunction;
+import java.util.function.Predicate;
+
+import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
+import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
+import speiger.src.collections.objects.functions.function.UnaryOperator;
+import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator;
+import speiger.src.collections.objects.maps.abstracts.AbstractObject2ObjectMap;
+import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
+import speiger.src.collections.objects.collections.AbstractObjectCollection;
+import speiger.src.collections.objects.collections.ObjectCollection;
+import speiger.src.collections.objects.functions.ObjectSupplier;
+import speiger.src.collections.objects.collections.ObjectIterator;
+import speiger.src.collections.objects.sets.AbstractObjectSet;
+import speiger.src.collections.objects.sets.ObjectSet;
+import speiger.src.collections.utils.HashUtil;
+import speiger.src.collections.utils.ITrimmable;
+
+/**
+ * A Type Specific Custom implementation of the HashMap
+ * Instead of using Wrapper Object Arrays for storing keys and values there is dedicated arrays for storing keys and values.
+ * Extra to that there is a couple quality of life functions provided
+ * @param  the keyType of elements maintained by this Collection
+ * @param  the keyType of elements maintained by this Collection
+ */
+public class Object2ObjectOpenHashMap extends AbstractObject2ObjectMap implements ITrimmable
+{
+	/** The Backing keys array */
+	protected transient T[] keys;
+	/** The Backing values array */
+	protected transient V[] values;
+	/** If a null value is present */
+	protected transient boolean containsNull;
+	/** Minimum array size the HashMap will be */
+	protected transient int minCapacity;
+	/** Index of the Null Value */
+	protected transient int nullIndex;
+	/** Maximum amount of Values that can be stored before the array gets expanded usually 75% */
+	protected transient int maxFill;
+	/** Max Index that is allowed to be searched through nullIndex - 1 */
+	protected transient int mask;
+	/** EntrySet cache */
+	protected transient FastEntrySet entrySet;
+	/** KeySet cache */
+	protected transient ObjectSet keySet;
+	/** Values cache */
+	protected transient ObjectCollection valuesC;
+
+	/** Amount of Elements stored in the HashMap */
+	protected int size;
+	/** How full the Arrays are allowed to get before resize */
+	protected final float loadFactor;
+
+	/**
+	 * Default Constructor
+	 */
+	public Object2ObjectOpenHashMap() {
+		this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+
+	/**
+	 * Constructor that defines the minimum capacity
+	 * @param minCapacity the minimum capacity the HashMap is allowed to be.
+	 * @throws IllegalStateException if the minimum capacity is negative
+	 */
+	public Object2ObjectOpenHashMap(int minCapacity) {
+		this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+
+	/**
+	 * Constructor that defines the minimum capacity and load factor
+	 * @param minCapacity the minimum capacity the HashMap is allowed to be.
+	 * @param loadFactor the percentage of how full the backing array can be before they resize
+	 * @throws IllegalStateException if the minimum capacity is negative
+	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
+	 */
+	public Object2ObjectOpenHashMap(int minCapacity, float loadFactor) {
+		if(minCapacity < 0)	throw new IllegalStateException("Minimum Capacity is negative. This is not allowed");
+		if(loadFactor <= 0 || loadFactor >= 1F) throw new IllegalStateException("Load Factor is not between 0 and 1");
+		this.loadFactor = loadFactor;
+		this.minCapacity = nullIndex = HashUtil.arraySize(minCapacity, loadFactor);
+		mask = nullIndex - 1;
+		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
+		keys = (T[])new Object[nullIndex + 1];
+		values = (V[])new Object[nullIndex + 1];
+	}
+
+	/**
+	 * Helper constructor that allow to create a map from unboxed values
+	 * @param keys the keys that should be put into the map
+	 * @param values the values that should be put into the map.
+	 * @throws IllegalStateException if the keys and values do not match in lenght
+	 */
+	public Object2ObjectOpenHashMap(T[] keys, V[] values) {
+		this(keys, values, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+
+	/**
+	 * Helper constructor that allow to create a map from unboxed values
+	 * @param keys the keys that should be put into the map
+	 * @param values the values that should be put into the map.
+	 * @param loadFactor the percentage of how full the backing array can be before they resize
+	 * @throws IllegalStateException if the keys and values do not match in lenght
+	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
+	 */
+	public Object2ObjectOpenHashMap(T[] keys, V[] values, float loadFactor) {
+		this(keys.length, loadFactor);
+		if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size");
+		for(int i = 0,m=keys.length;i map) {
+		this(map, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+
+	/**
+	 * A Helper constructor that allows to create a Map with exactly the same values as the provided map.
+	 * @param map the values that should be present in the map
+	 * @param loadFactor the percentage of how full the backing array can be before they resize
+	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
+	 */
+	public Object2ObjectOpenHashMap(Map map, float loadFactor) {
+		this(map.size(), loadFactor);
+		putAll(map);
+	}
+
+	/**
+	 * A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map.
+	 * @param map the values that should be present in the map
+ 	 */
+	public Object2ObjectOpenHashMap(Object2ObjectMap map) {
+		this(map, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+
+	/**
+	 * A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map.
+	 * @param map the values that should be present in the map
+	 * @param loadFactor the percentage of how full the backing array can be before they resize
+	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
+ 	 */
+	public Object2ObjectOpenHashMap(Object2ObjectMap map, float loadFactor) {
+		this(map.size(), loadFactor);
+		putAll(map);
+	}
+
+	@Override
+	public V put(T key, V value) {
+		int slot = findIndex(key);
+		if(slot < 0) {
+			insert(-slot-1, key, value);
+			return getDefaultReturnValue();
+		}
+		V oldValue = values[slot];
+		values[slot] = value;
+		return oldValue;
+	}
+
+	@Override
+	public V putIfAbsent(T key, V value) {
+		int slot = findIndex(key);
+		if(slot < 0) {
+			insert(-slot-1, key, value);
+			return getDefaultReturnValue();
+		}
+		else if(Objects.equals(values[slot], getDefaultReturnValue())) {
+			V oldValue = values[slot];
+			values[slot] = value;
+			return oldValue;
+		}
+		return values[slot];
+	}
+
+	@Override
+	public boolean containsKey(Object key) {
+		return findIndex(key) >= 0;
+	}
+
+	@Override
+	public boolean containsValue(Object value) {
+		if(containsNull && Objects.equals(values[nullIndex], value)) return true;
+		for(int i = nullIndex-1;i >= 0;i--)
+			if(keys[i] != null && Objects.equals(value, values[i])) return true;
+		return false;
+	}
+
+	@Override
+	public V rem(T key) {
+		int slot = findIndex(key);
+		if(slot < 0) return getDefaultReturnValue();
+		return removeIndex(slot);
+	}
+
+	@Override
+	public V remOrDefault(T key, V defaultValue) {
+		int slot = findIndex(key);
+		if(slot < 0) return defaultValue;
+		return removeIndex(slot);
+	}
+
+	@Override
+	public V remove(Object key) {
+		int slot = findIndex(key);
+		if(slot < 0) return getDefaultReturnValue();
+		return removeIndex(slot);
+	}
+
+	@Override
+	public boolean remove(Object key, Object value) {
+		Objects.requireNonNull(value);
+		if(key == null) {
+			if(containsNull && Objects.equals(value, values[nullIndex])) {
+				removeNullIndex();
+				return true;
+			}
+			return false;
+		}
+		int pos = HashUtil.mix(key.hashCode()) & mask;
+		T current = keys[pos];
+		if(current == null) return false;
+		if(Objects.equals(key, current) && Objects.equals(value, values[pos])) {
+			removeIndex(pos);
+			return true;
+		}
+		while(true) {
+			if((current = keys[pos = (++pos & mask)]) == null) return false;
+			else if(Objects.equals(key, current) && Objects.equals(value, values[pos])){
+				removeIndex(pos);
+				return true;
+			}
+		}
+	}
+
+	@Override
+	public V getObject(T key) {
+		int slot = findIndex(key);
+		return slot < 0 ? getDefaultReturnValue() : values[slot];
+	}
+
+	@Override
+	public V get(Object key) {
+		int slot = findIndex(key);
+		return slot < 0 ? getDefaultReturnValue() : values[slot];
+	}
+
+	@Override
+	public V getOrDefault(Object key, V defaultValue) {
+		int slot = findIndex(key);
+		return slot < 0 ? defaultValue : values[slot];
+	}
+
+	@Override
+	public Object2ObjectOpenHashMap copy() {
+		Object2ObjectOpenHashMap map = new Object2ObjectOpenHashMap<>(0, loadFactor);
+		map.minCapacity = minCapacity;
+		map.mask = mask;
+		map.maxFill = maxFill;
+		map.nullIndex = nullIndex;
+		map.containsNull = containsNull;
+		map.size = size;
+		map.keys = Arrays.copyOf(keys, keys.length);
+		map.values = Arrays.copyOf(values, values.length);
+		return map;
+	}
+
+	@Override
+	public ObjectSet> object2ObjectEntrySet() {
+		if(entrySet == null) entrySet = new MapEntrySet();
+		return entrySet;
+	}
+
+	@Override
+	public ObjectSet keySet() {
+		if(keySet == null) keySet = new KeySet();
+		return keySet;
+	}
+
+	@Override
+	public ObjectCollection values() {
+		if(valuesC == null) valuesC = new Values();
+		return valuesC;
+	}
+
+	@Override
+	public void forEach(ObjectObjectConsumer action) {
+		if(size() <= 0) return;
+		if(containsNull) action.accept(keys[nullIndex], values[nullIndex]);
+		for(int i = nullIndex-1;i>=0;i--) {
+			if(keys[i] != null) action.accept(keys[i], values[i]);
+		}
+	}
+
+	@Override
+	public boolean replace(T key, V oldValue, V newValue) {
+		int index = findIndex(key);
+		if(index < 0 || values[index] != oldValue) return false;
+		values[index] = newValue;
+		return true;
+	}
+
+	@Override
+	public V replace(T key, V value) {
+		int index = findIndex(key);
+		if(index < 0) return getDefaultReturnValue();
+		V oldValue = values[index];
+		values[index] = value;
+		return oldValue;
+	}
+
+	@Override
+	public V compute(T key, ObjectObjectUnaryOperator mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		int index = findIndex(key);
+		if(index < 0) {
+			V newValue = mappingFunction.apply(key, getDefaultReturnValue());
+			if(Objects.equals(newValue, getDefaultReturnValue())) return newValue;
+			insert(-index-1, key, newValue);
+			return newValue;
+		}
+		V newValue = mappingFunction.apply(key, values[index]);
+		if(Objects.equals(newValue, getDefaultReturnValue())) {
+			removeIndex(index);
+			return newValue;
+		}
+		values[index] = newValue;
+		return newValue;
+	}
+
+	@Override
+	public V computeIfAbsent(T key, UnaryOperator mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		int index = findIndex(key);
+		if(index < 0) {
+			V newValue = mappingFunction.apply(key);
+			if(Objects.equals(newValue, getDefaultReturnValue())) return newValue;
+			insert(-index-1, key, newValue);
+			return newValue;
+		}
+		V newValue = values[index];
+		if(Objects.equals(newValue, getDefaultReturnValue())) {
+			newValue = mappingFunction.apply(key);
+			if(Objects.equals(newValue, getDefaultReturnValue())) return newValue;
+			values[index] = newValue;
+		}
+		return newValue;
+	}
+
+	@Override
+	public V supplyIfAbsent(T key, ObjectSupplier valueProvider) {
+		Objects.requireNonNull(valueProvider);
+		int index = findIndex(key);
+		if(index < 0) {
+			V newValue = valueProvider.get();
+			if(Objects.equals(newValue, getDefaultReturnValue())) return newValue;
+			insert(-index-1, key, newValue);
+			return newValue;
+		}
+		V newValue = values[index];
+		if(Objects.equals(newValue, getDefaultReturnValue())) {
+			newValue = valueProvider.get();
+			if(Objects.equals(newValue, getDefaultReturnValue())) return newValue;
+			values[index] = newValue;
+		}
+		return newValue;
+	}
+
+	@Override
+	public V computeIfPresent(T key, ObjectObjectUnaryOperator mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		int index = findIndex(key);
+		if(index < 0 || Objects.equals(values[index], getDefaultReturnValue())) return getDefaultReturnValue();
+		V newValue = mappingFunction.apply(key, values[index]);
+		if(Objects.equals(newValue, getDefaultReturnValue())) {
+			removeIndex(index);
+			return newValue;
+		}
+		values[index] = newValue;
+		return newValue;
+	}
+
+	@Override
+	public V merge(T key, V value, ObjectObjectUnaryOperator mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		Objects.requireNonNull(value);
+		int index = findIndex(key);
+		V newValue = index < 0 || Objects.equals(values[index], getDefaultReturnValue()) ? value : mappingFunction.apply(values[index], value);
+		if(Objects.equals(newValue, getDefaultReturnValue())) {
+			if(index >= 0)
+				removeIndex(index);
+		}
+		else if(index < 0) insert(-index-1, key, newValue);
+		else values[index] = newValue;
+		return newValue;
+	}
+
+	@Override
+	public void mergeAll(Object2ObjectMap m, ObjectObjectUnaryOperator mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		for(Object2ObjectMap.Entry entry : getFastIterable(m)) {
+			T key = entry.getKey();
+			int index = findIndex(key);
+			V newValue = index < 0 || Objects.equals(values[index], getDefaultReturnValue()) ? entry.getValue() : mappingFunction.apply(values[index], entry.getValue());
+			if(Objects.equals(newValue, getDefaultReturnValue())) {
+				if(index >= 0)
+					removeIndex(index);
+			}
+			else if(index < 0) insert(-index-1, key, newValue);
+			else values[index] = newValue;
+		}
+	}
+
+	@Override
+	public int size() { return size; }
+
+	@Override
+	public void clear() {
+		if(size == 0) return;
+		size = 0;
+		containsNull = false;
+		Arrays.fill(keys, null);
+		Arrays.fill(values, null);
+	}
+
+	@Override
+	public boolean trim(int size) {
+		int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor)));
+		if(request >= nullIndex || this.size >= Math.min((int)Math.ceil(request * loadFactor), request - 1)) return false;
+		try {
+			rehash(request);
+		}
+		catch(OutOfMemoryError noMemory) { return false; }
+		return true;
+	}
+
+	@Override
+	public void clearAndTrim(int size) {
+		int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor)));
+		if(request >= nullIndex) {
+			clear();
+			return;
+		}
+		nullIndex = request;
+		mask = request-1;
+		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
+		keys = (T[])new Object[request + 1];
+		values = (V[])new Object[request + 1];
+		this.size = 0;
+		containsNull = false;
+	}
+
+	protected int findIndex(Object key) {
+		if(key == null) return containsNull ? nullIndex : -(nullIndex + 1);
+		int pos = HashUtil.mix(key.hashCode()) & mask;
+		T current = keys[pos];
+		if(current != null) {
+			if(Objects.equals(key, current)) return pos;
+			while((current = keys[pos = (++pos & mask)]) != null)
+				if(Objects.equals(key, current)) return pos;
+		}
+		return -(pos + 1);
+	}
+
+	protected V removeIndex(int pos) {
+		if(pos == nullIndex) return containsNull ? removeNullIndex() : getDefaultReturnValue();
+		V value = values[pos];
+		keys[pos] = null;
+		values[pos] = null;
+		size--;
+		onNodeRemoved(pos);
+		shiftKeys(pos);
+		if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
+		return value;
+	}
+
+	protected V removeNullIndex() {
+		V value = values[nullIndex];
+		containsNull = false;
+		keys[nullIndex] = null;
+		values[nullIndex] = null;
+		size--;
+		onNodeRemoved(nullIndex);
+		if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
+		return value;
+	}
+
+	protected void insert(int slot, T key, V value) {
+		if(slot == nullIndex) containsNull = true;
+		keys[slot] = key;
+		values[slot] = value;
+		onNodeAdded(slot);
+		if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor));
+	}
+
+	protected void rehash(int newSize) {
+		int newMask = newSize - 1;
+		T[] newKeys = (T[])new Object[newSize + 1];
+		V[] newValues = (V[])new Object[newSize + 1];
+		for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) {
+			while(true) {
+				if(--i < 0) throw new ConcurrentModificationException("Map was modified during rehash");
+				if(keys[i] != null) break;
+			}
+			if(newKeys[pos = HashUtil.mix(Objects.hashCode(keys[i])) & newMask] != null)
+				while(newKeys[pos = (++pos & newMask)] != null);
+			newKeys[pos] = keys[i];
+			newValues[pos] = values[i];
+		}
+		newValues[newSize] = values[nullIndex];
+		nullIndex = newSize;
+		mask = newMask;
+		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
+		keys = newKeys;
+		values = newValues;
+	}
+
+	protected void onNodeAdded(int pos) {
+
+	}
+
+	protected void onNodeRemoved(int pos) {
+
+	}
+
+	protected void onNodeMoved(int from, int to) {
+
+	}
+
+	protected void shiftKeys(int startPos) {
+		int slot, last;
+		T current;
+		while(true) {
+			startPos = ((last = startPos) + 1) & mask;
+			while(true){
+				if((current = keys[startPos]) == null) {
+					keys[last] = null;
+					values[last] = null;
+					return;
+				}
+				slot = HashUtil.mix(Objects.hashCode(current)) & mask;
+				if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
+				startPos = ++startPos & mask;
+			}
+			keys[last] = current;
+			values[last] = values[startPos];
+			onNodeMoved(startPos, last);
+		}
+	}
+
+	protected class MapEntry implements Object2ObjectMap.Entry, Map.Entry {
+		public int index = -1;
+
+		public MapEntry() {}
+		public MapEntry(int index) {
+			this.index = index;
+		}
+
+		@Override
+		public T getKey() {
+			return keys[index];
+		}
+
+		@Override
+		public V getValue() {
+			return values[index];
+		}
+
+		@Override
+		public V setValue(V value) {
+			V oldValue = values[index];
+			values[index] = value;
+			return oldValue;
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if(obj instanceof Map.Entry) {
+				if(obj instanceof Object2ObjectMap.Entry) {
+					Object2ObjectMap.Entry entry = (Object2ObjectMap.Entry)obj;
+					return Objects.equals(keys[index], entry.getKey()) && Objects.equals(values[index], entry.getValue());
+				}
+				Map.Entry entry = (Map.Entry)obj;
+				Object key = entry.getKey();
+				Object value = entry.getValue();
+				return Objects.equals(keys[index], key) && Objects.equals(values[index], value);
+			}
+			return false;
+		}
+
+		@Override
+		public int hashCode() {
+			return Objects.hashCode(keys[index]) ^ Objects.hashCode(values[index]);
+		}
+
+		@Override
+		public String toString() {
+			return Objects.toString(keys[index]) + "=" + Objects.toString(values[index]);
+		}
+	}
+
+	private final class MapEntrySet extends AbstractObjectSet> implements FastEntrySet {
+		@Override
+		public ObjectIterator> fastIterator() {
+			return new FastEntryIterator();
+		}
+
+		@Override
+		public ObjectIterator> iterator() {
+			return new EntryIterator();
+		}
+
+		@Override
+		public void forEach(Consumer> action) {
+			if(containsNull) action.accept(new BasicEntry<>(keys[nullIndex], values[nullIndex]));
+			for(int i = nullIndex-1;i>=0;i--)
+				if(keys[i] != null) action.accept(new BasicEntry<>(keys[i], values[i]));
+		}
+
+		@Override
+		public void fastForEach(Consumer> action) {
+			BasicEntry entry = new BasicEntry<>();
+			if(containsNull) {
+				entry.set(keys[nullIndex], values[nullIndex]);
+				action.accept(entry);
+			}
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null) {
+					entry.set(keys[i], values[i]);
+					action.accept(entry);
+				}
+			}
+		}
+
+		@Override
+		public void forEachIndexed(IntObjectConsumer> action) {
+			Objects.requireNonNull(action);
+			if(size() <= 0) return;
+			if(containsNull) action.accept(0, new BasicEntry<>(keys[nullIndex], values[nullIndex]));
+			for(int i = nullIndex-1, index = containsNull ? 1 : 0;i>=0;i--) {
+				if(keys[i] != null) action.accept(index++, new BasicEntry<>(keys[i], values[i]));
+			}
+		}
+
+		@Override
+		public  void forEach(E input, ObjectObjectConsumer> action) {
+			Objects.requireNonNull(action);
+			if(size() <= 0) return;
+			if(containsNull) action.accept(input, new BasicEntry<>(keys[nullIndex], values[nullIndex]));
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null) action.accept(input, new BasicEntry<>(keys[i], values[i]));
+			}
+		}
+
+		@Override
+		public boolean matchesAny(Predicate> filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return false;
+			BasicEntry entry = new BasicEntry<>();
+			if(containsNull) {
+				entry.set(keys[nullIndex], values[nullIndex]);
+				if(filter.test(entry)) return true;
+			}
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null) {
+					entry.set(keys[i], values[i]);
+					if(filter.test(entry)) return true;
+				}
+			}
+			return false;
+		}
+
+		@Override
+		public boolean matchesNone(Predicate> filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return true;
+			BasicEntry entry = new BasicEntry<>();
+			if(containsNull) {
+				entry.set(keys[nullIndex], values[nullIndex]);
+				if(filter.test(entry)) return false;
+			}
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null) {
+					entry.set(keys[i], values[i]);
+					if(filter.test(entry)) return false;
+				}
+			}
+			return true;
+		}
+
+		@Override
+		public boolean matchesAll(Predicate> filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return true;
+			BasicEntry entry = new BasicEntry<>();
+			if(containsNull) {
+				entry.set(keys[nullIndex], values[nullIndex]);
+				if(!filter.test(entry)) return false;
+			}
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null) {
+					entry.set(keys[i], values[i]);
+					if(!filter.test(entry)) return false;
+				}
+			}
+			return true;
+		}
+
+		@Override
+		public  E reduce(E identity, BiFunction, E> operator) {
+			Objects.requireNonNull(operator);
+			E state = identity;
+			if(containsNull) state = operator.apply(state, new BasicEntry<>(keys[nullIndex], values[nullIndex]));
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] == null) continue;
+				state = operator.apply(state, new BasicEntry<>(keys[i], values[i]));
+			}
+			return state;
+		}
+
+		@Override
+		public Object2ObjectMap.Entry reduce(ObjectObjectUnaryOperator, Object2ObjectMap.Entry> operator) {
+			Objects.requireNonNull(operator);
+			Object2ObjectMap.Entry state = null;
+			boolean empty = true;
+			if(containsNull) {
+				state = new BasicEntry<>(keys[nullIndex], values[nullIndex]);
+				empty = false;
+			}
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] == null) continue;
+				if(empty) {
+					empty = false;
+					state = new BasicEntry<>(keys[i], values[i]);
+					continue;
+				}
+				state = operator.apply(state, new BasicEntry<>(keys[i], values[i]));
+			}
+			return state;
+		}
+
+		@Override
+		public Object2ObjectMap.Entry findFirst(Predicate> filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return null;
+			BasicEntry entry = new BasicEntry<>();
+			if(containsNull) {
+				entry.set(keys[nullIndex], values[nullIndex]);
+				if(filter.test(entry)) return entry;
+			}
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null) {
+					entry.set(keys[i], values[i]);
+					if(filter.test(entry)) return entry;
+				}
+			}
+			return null;
+		}
+
+		@Override
+		public int count(Predicate> filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return 0;
+			BasicEntry entry = new BasicEntry<>();
+			int result = 0;
+			if(containsNull) {
+				entry.set(keys[nullIndex], values[nullIndex]);
+				if(filter.test(entry)) result++;
+			}
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null) {
+					entry.set(keys[i], values[i]);
+					if(filter.test(entry)) result++;
+				}
+			}
+			return result;
+		}
+
+		@Override
+		public int size() {
+			return Object2ObjectOpenHashMap.this.size();
+		}
+
+		@Override
+		public void clear() {
+			Object2ObjectOpenHashMap.this.clear();
+		}
+
+		@Override
+		public boolean contains(Object o) {
+			if(o instanceof Map.Entry) {
+				if(o instanceof Object2ObjectMap.Entry) {
+					Object2ObjectMap.Entry entry = (Object2ObjectMap.Entry)o;
+					int index = Object2ObjectOpenHashMap.this.findIndex(entry.getKey());
+					if(index >= 0) return Objects.equals(entry.getValue(), Object2ObjectOpenHashMap.this.values[index]);
+				}
+				else {
+					Map.Entry entry = (Map.Entry)o;
+					int index = Object2ObjectOpenHashMap.this.findIndex(entry.getKey());
+					if(index >= 0) return Objects.equals(entry.getValue(), Object2ObjectOpenHashMap.this.values[index]);
+				}
+			}
+			return false;
+		}
+
+		@Override
+		public boolean remove(Object o) {
+			if(o instanceof Map.Entry) {
+				if(o instanceof Object2ObjectMap.Entry) {
+					Object2ObjectMap.Entry entry = (Object2ObjectMap.Entry)o;
+					return Object2ObjectOpenHashMap.this.remove(entry.getKey(), entry.getValue());
+				}
+				Map.Entry entry = (Map.Entry)o;
+				return Object2ObjectOpenHashMap.this.remove(entry.getKey(), entry.getValue());
+			}
+			return false;
+		}
+	}
+
+	private final class KeySet extends AbstractObjectSet {
+		@Override
+		public boolean contains(Object e) {
+			return containsKey(e);
+		}
+
+		@Override
+		public boolean remove(Object o) {
+			int oldSize = size;
+			Object2ObjectOpenHashMap.this.remove(o);
+			return size != oldSize;
+		}
+
+		@Override
+		public boolean add(T o) {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public ObjectIterator iterator() {
+			return new KeyIterator();
+		}
+
+		@Override
+		public int size() {
+			return Object2ObjectOpenHashMap.this.size();
+		}
+
+		@Override
+		public void clear() {
+			Object2ObjectOpenHashMap.this.clear();
+		}
+
+		@Override
+		public KeySet copy() { throw new UnsupportedOperationException(); }
+
+		@Override
+		public void forEach(Consumer action) {
+			if(containsNull) action.accept(keys[nullIndex]);
+			for(int i = nullIndex-1;i>=0;i--)
+				if(keys[i] != null) action.accept(keys[i]);
+		}
+
+		@Override
+		public void forEachIndexed(IntObjectConsumer action) {
+			Objects.requireNonNull(action);
+			if(size() <= 0) return;
+			if(containsNull) action.accept(0, keys[nullIndex]);
+			for(int i = nullIndex-1, index = containsNull ? 1 : 0;i>=0;i--) {
+				if(keys[i] != null) action.accept(index++, keys[i]);
+			}
+		}
+
+		@Override
+		public  void forEach(E input, ObjectObjectConsumer action) {
+			Objects.requireNonNull(action);
+			if(size() <= 0) return;
+			if(containsNull) action.accept(input, keys[nullIndex]);
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null) action.accept(input, keys[i]);
+			}
+		}
+
+		@Override
+		public boolean matchesAny(Predicate filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return false;
+			if(containsNull && filter.test(keys[nullIndex])) return true;
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null && filter.test(keys[i])) return true;
+			}
+			return false;
+		}
+
+		@Override
+		public boolean matchesNone(Predicate filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return true;
+			if(containsNull && filter.test(keys[nullIndex])) return false;
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null && filter.test(keys[i])) return false;
+			}
+			return true;
+		}
+
+		@Override
+		public boolean matchesAll(Predicate filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return true;
+			if(containsNull && !filter.test(keys[nullIndex])) return false;
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null && !filter.test(keys[i])) return false;
+			}
+			return true;
+		}
+
+		@Override
+		public  E reduce(E identity, BiFunction operator) {
+			Objects.requireNonNull(operator);
+			E state = identity;
+			if(containsNull) state = operator.apply(state, keys[nullIndex]);
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] == null) continue;
+				state = operator.apply(state, keys[i]);
+			}
+			return state;
+		}
+
+		@Override
+		public T reduce(ObjectObjectUnaryOperator operator) {
+			Objects.requireNonNull(operator);
+			T state = null;
+			boolean empty = true;
+			if(containsNull) {
+				state = keys[nullIndex];
+				empty = false;
+			}
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] == null) continue;
+				if(empty) {
+					empty = false;
+					state = keys[i];
+					continue;
+				}
+				state = operator.apply(state, keys[i]);
+			}
+			return state;
+		}
+
+		@Override
+		public T findFirst(Predicate filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return null;
+			if(containsNull && filter.test(keys[nullIndex])) return keys[nullIndex];
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null && filter.test(keys[i])) return keys[i];
+			}
+			return null;
+		}
+
+		@Override
+		public int count(Predicate filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return 0;
+			int result = 0;
+			if(containsNull && filter.test(keys[nullIndex])) result++;
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null && filter.test(keys[i])) result++;
+			}
+			return result;
+		}
+	}
+
+	private class Values extends AbstractObjectCollection {
+		@Override
+		public boolean contains(Object e) {
+			return containsValue(e);
+		}
+
+		@Override
+		public boolean add(V o) {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public ObjectIterator iterator() {
+			return new ValueIterator();
+		}
+
+		@Override
+		public int size() {
+			return Object2ObjectOpenHashMap.this.size();
+		}
+
+		@Override
+		public void clear() {
+			Object2ObjectOpenHashMap.this.clear();
+		}
+
+		@Override
+		public void forEach(Consumer action) {
+			if(containsNull) action.accept(values[nullIndex]);
+			for(int i = nullIndex-1;i>=0;i--)
+				if(keys[i] != null) action.accept(values[i]);
+		}
+
+		@Override
+		public void forEachIndexed(IntObjectConsumer action) {
+			Objects.requireNonNull(action);
+			if(size() <= 0) return;
+			if(containsNull) action.accept(0, values[nullIndex]);
+			for(int i = nullIndex-1, index = containsNull ? 1 : 0;i>=0;i--) {
+				if(keys[i] != null) action.accept(index++, values[i]);
+			}
+		}
+
+		@Override
+		public  void forEach(E input, ObjectObjectConsumer action) {
+			Objects.requireNonNull(action);
+			if(size() <= 0) return;
+			if(containsNull) action.accept(input, values[nullIndex]);
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null) action.accept(input, values[i]);
+			}
+		}
+
+		@Override
+		public boolean matchesAny(Predicate filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return false;
+			if(containsNull && filter.test(values[nullIndex])) return true;
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null && filter.test(values[i])) return true;
+			}
+			return false;
+		}
+
+		@Override
+		public boolean matchesNone(Predicate filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return true;
+			if(containsNull && filter.test(values[nullIndex])) return false;
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null && filter.test(values[i])) return false;
+			}
+			return true;
+		}
+
+		@Override
+		public boolean matchesAll(Predicate filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return true;
+			if(containsNull && !filter.test(values[nullIndex])) return false;
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null && !filter.test(values[i])) return false;
+			}
+			return true;
+		}
+
+		@Override
+		public  E reduce(E identity, BiFunction operator) {
+			Objects.requireNonNull(operator);
+			E state = identity;
+			if(containsNull) state = operator.apply(state, values[nullIndex]);
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] == null) continue;
+				state = operator.apply(state, values[i]);
+			}
+			return state;
+		}
+
+		@Override
+		public V reduce(ObjectObjectUnaryOperator operator) {
+			Objects.requireNonNull(operator);
+			V state = null;
+			boolean empty = true;
+			if(containsNull) {
+				state = values[nullIndex];
+				empty = false;
+			}
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] == null) continue;
+				if(empty) {
+					empty = false;
+					state = values[i];
+					continue;
+				}
+				state = operator.apply(state, values[i]);
+			}
+			return state;
+		}
+
+		@Override
+		public V findFirst(Predicate filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return null;
+			if(containsNull && filter.test(values[nullIndex])) return values[nullIndex];
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null && filter.test(values[i])) return values[i];
+			}
+			return null;
+		}
+
+		@Override
+		public int count(Predicate filter) {
+			Objects.requireNonNull(filter);
+			if(size() <= 0) return 0;
+			int result = 0;
+			if(containsNull && filter.test(values[nullIndex])) result++;
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null && filter.test(values[i])) result++;
+			}
+			return result;
+		}
+	}
+
+	private class FastEntryIterator extends MapIterator implements ObjectIterator> {
+		MapEntry entry = new MapEntry();
+		@Override
+		public Object2ObjectMap.Entry next() {
+			entry.index = nextEntry();
+			return entry;
+		}
+	}
+
+	private class EntryIterator extends MapIterator implements ObjectIterator> {
+		MapEntry entry;
+		@Override
+		public Object2ObjectMap.Entry next() {
+			return entry = new MapEntry(nextEntry());
+		}
+
+		@Override
+		public void remove() {
+			super.remove();
+			entry.index = -1;
+		}
+	}
+
+	private class KeyIterator extends MapIterator implements ObjectIterator {
+		@Override
+		public T next() {
+			return keys[nextEntry()];
+		}
+	}
+
+	private class ValueIterator extends MapIterator implements ObjectIterator {
+		@Override
+		public V next() {
+			return values[nextEntry()];
+		}
+	}
+
+	private class MapIterator {
+		int pos = nullIndex;
+		int returnedPos = -1;
+		int lastReturned = -1;
+		int nextIndex = Integer.MIN_VALUE;
+		boolean returnNull = containsNull;
+		T[] wrapped = null;
+		int wrappedIndex = 0;
+
+		public boolean hasNext() {
+			if(nextIndex == Integer.MIN_VALUE) {
+				if(returnNull) {
+					returnNull = false;
+					nextIndex = nullIndex;
+				}
+				else
+				{
+					while(true) {
+						if(--pos < 0) {
+							if(wrapped == null || wrappedIndex <= -pos - 1) break;
+							nextIndex = -pos - 1;
+							break;
+						}
+						if(keys[pos] != null){
+							nextIndex = pos;
+							break;
+						}
+					}
+				}
+			}
+			return nextIndex != Integer.MIN_VALUE;
+		}
+
+		public int nextEntry() {
+			if(!hasNext()) throw new NoSuchElementException();
+			returnedPos = pos;
+			if(nextIndex < 0){
+				lastReturned = Integer.MAX_VALUE;
+				int value = findIndex(wrapped[nextIndex]);
+				if(value < 0) throw new IllegalStateException("Entry ["+nextIndex+"] was removed during Iteration");
+				nextIndex = Integer.MIN_VALUE;
+				return value;
+			}
+			int value = (lastReturned = nextIndex);
+			nextIndex = Integer.MIN_VALUE;
+			return value;
+		}
+
+		public void remove() {
+			if(lastReturned == -1) throw new IllegalStateException();
+			if(lastReturned == nullIndex) {
+				containsNull = false;
+				keys[nullIndex] = null;
+				values[nullIndex] = null;
+			}
+			else if(returnedPos >= 0) shiftKeys(returnedPos);
+			else {
+				Object2ObjectOpenHashMap.this.remove(wrapped[-returnedPos - 1]);
+				lastReturned = -1;
+				return;
+			}
+			size--;
+			lastReturned = -1;
+		}
+
+		private void shiftKeys(int startPos) {
+			int slot, last;
+			T current;
+			while(true) {
+				startPos = ((last = startPos) + 1) & mask;
+				while(true){
+					if((current = keys[startPos]) == null) {
+						keys[last] = null;
+						values[last] = null;
+						return;
+					}
+					slot = HashUtil.mix(Objects.hashCode(current)) & mask;
+					if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
+					startPos = ++startPos & mask;
+				}
+				if(startPos < last) addWrapper(keys[startPos]);
+				keys[last] = current;
+				values[last] = values[startPos];
+			}
+		}
+
+		private void addWrapper(T value) {
+			if(wrapped == null) wrapped = (T[])new Object[2];
+			else if(wrappedIndex >= wrapped.length) {
+				T[] newArray = (T[])new Object[wrapped.length * 2];
+				System.arraycopy(wrapped, 0, newArray, 0, wrapped.length);
+				wrapped = newArray;
+			}
+			wrapped[wrappedIndex++] = value;
+		}
+	}
+}
diff --git a/src/main/java/speiger/src/collections/objects/maps/interfaces/Object2ObjectMap.java b/src/main/java/speiger/src/collections/objects/maps/interfaces/Object2ObjectMap.java
new file mode 100644
index 000000000..e904c6ac0
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/maps/interfaces/Object2ObjectMap.java
@@ -0,0 +1,534 @@
+package speiger.src.collections.objects.maps.interfaces;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Collection;
+import java.util.Arrays;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+
+
+import speiger.src.collections.objects.collections.ObjectCollection;
+import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
+import speiger.src.collections.objects.functions.function.UnaryOperator;
+import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator;
+
+import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
+
+import speiger.src.collections.objects.collections.ObjectIterable;
+import speiger.src.collections.objects.sets.ObjectSet;
+import speiger.src.collections.objects.functions.ObjectSupplier;
+import speiger.src.collections.objects.collections.ObjectIterator;
+import speiger.src.collections.utils.HashUtil;
+import speiger.src.collections.utils.SanityChecks;
+
+/**
+ * A Type Specific Map that reduces memory overhead due to boxing/unboxing of Primitives
+ * and some extra helper functions.
+ * @param  the keyType of elements maintained by this Collection
+ * @param  the keyType of elements maintained by this Collection
+ */
+public interface Object2ObjectMap extends Map, UnaryOperator
+{
+	/**
+	 * Helper Class that allows to create Maps without requiring a to type out the entire implementation or know it.
+	 * @return a MapBuilder
+	 */
+	public static MapBuilder builder() {
+		return MapBuilder.INSTANCE;
+	}
+
+	/**
+	 * Method to see what the default return value is.
+	 * @return default return value
+	 */
+	public V getDefaultReturnValue();
+	/**
+	 * Method to define the default return value if a requested key isn't present
+	 * @param v value that should be the default return value
+	 * @return itself
+	 */
+	public Object2ObjectMap setDefaultReturnValue(V v);
+
+	/**
+	 * A Function that does a shallow clone of the Map itself.
+	 * This function is more optimized then a copy constructor since the Map does not have to be unsorted/resorted.
+	 * It can be compared to Cloneable but with less exception risk
+	 * @return a Shallow Copy of the Map
+	 * @note Wrappers and view Maps will not support this feature
+	 */
+	public Object2ObjectMap copy();
+
+	/**
+	 * Type Specific method to reduce boxing/unboxing of values
+	 * @param key the key that should be inserted,
+	 * @param value the value that should be inserted
+	 * @return the last present value or default return value.
+	 * @see Map#put(Object, Object)
+	 */
+	public V put(T key, V value);
+
+	/**
+	 * A Helper method that allows to put int a Object2ObjectMap.Entry into a map.
+	 * @param entry then Entry that should be inserted.
+	 * @return the last present value or default return value.
+	 */
+	public default V put(Entry entry) {
+		return put(entry.getKey(), entry.getValue());
+	}
+
+	/**
+	 * Type Specific array method to bulk add elements into a map without creating a wrapper and increasing performances
+	 * @param keys the keys that should be added
+	 * @param values the values that should be added
+	 * @see Map#putAll(Map)
+	 * @throws IllegalStateException if the arrays are not the same size
+	 */
+	public default void putAll(T[] keys, V[] values) {
+		if(keys.length != values.length) throw new IllegalStateException("Array sizes do not match");
+		putAll(keys, values, 0, keys.length);
+	}
+
+	/**
+	 * Type Specific array method to bulk add elements into a map without creating a wrapper and increasing performances
+	 * @param keys the keys that should be added
+	 * @param values the values that should be added
+	 * @param offset where the to start in the array
+	 * @param size how many elements should be added
+	 * @see Map#putAll(Map)
+	 * @throws IllegalStateException if the arrays are not within the range
+	 */
+	public void putAll(T[] keys, V[] values, int offset, int size);
+
+	/**
+	 * Type Specific method to reduce boxing/unboxing of values
+	 * @param key the key that should be inserted,
+	 * @param value the value that should be inserted
+	 * @return the last present value or default return value.
+	 * @see Map#putIfAbsent(Object, Object)
+	 */
+	public V putIfAbsent(T key, V value);
+
+	/**
+	 * Type-Specific bulk put method put elements into the map if not present.
+	 * @param m elements that should be added if not present.
+	 */
+	public void putAllIfAbsent(Object2ObjectMap m);
+
+	/**
+	 * Type Specific function for the bull putting of values
+	 * @param m the elements that should be inserted
+	 */
+	public void putAll(Object2ObjectMap m);
+
+	/**
+	 * Type Specific remove function to reduce boxing/unboxing
+	 * @param key the element that should be removed
+	 * @return the value that was removed or default return value
+	 */
+	public V rem(T key);
+
+	/**
+	 * @see Map#remove(Object)
+	 * @param key the element that should be removed
+	 * @return the value that was removed or default return value
+	 * @note in some implementations key does not have to be T but just have to support equals with T.
+	 */
+	@Override
+	public default V remove(Object key) {
+		return rem((T)key);
+	}
+
+	/**
+	 * Type-Specific Remove function with a default return value if wanted.
+	 * @see Map#remove(Object, Object)
+ 	 * @param key the element that should be removed
+ 	 * @param defaultValue the value that should be returned if the entry doesn't exist
+	 * @return the value that was removed or default value
+	 */
+	public V remOrDefault(T key, V defaultValue);
+	/**
+	 * A Type Specific replace method to replace an existing value
+	 * @param key the element that should be searched for
+	 * @param oldValue the expected value to be replaced
+	 * @param newValue the value to replace the oldValue with.
+	 * @return true if the value got replaced
+	 * @note this fails if the value is not present even if it matches the oldValue
+	 */
+	public boolean replace(T key, V oldValue, V newValue);
+	/**
+	 * A Type Specific replace method to reduce boxing/unboxing replace an existing value
+	 * @param key the element that should be searched for
+	 * @param value the value to replace with.
+	 * @return the present value or default return value
+	 * @note this fails if the value is not present
+	 */
+	public V replace(T key, V value);
+
+	/**
+	 * Type-Specific bulk replace method. Could be seen as putAllIfPresent
+	 * @param m elements that should be replaced.
+	 */
+	public void replaceObjects(Object2ObjectMap m);
+	/**
+	 * A Type Specific mass replace method to reduce boxing/unboxing
+	 * @param mappingFunction operation to replace all values
+	 */
+	public void replaceObjects(ObjectObjectUnaryOperator mappingFunction);
+	/**
+	 * A Type Specific compute method to reduce boxing/unboxing
+	 * @param key the key that should be computed
+	 * @param mappingFunction the operator that should generate the value
+	 * @return the result of the computation
+	 */
+	public V compute(T key, ObjectObjectUnaryOperator mappingFunction);
+	/**
+	 * A Type Specific compute method to reduce boxing/unboxing
+	 * @param key the key that should be computed
+	 * @param mappingFunction the operator that should generate the value if not present
+	 * @return the result of the computed value or present value
+	 */
+	public V computeIfAbsent(T key, UnaryOperator mappingFunction);
+
+	/**
+	 * A Supplier based computeIfAbsent function to fill the most used usecase of this function
+	 * @param key the key that should be computed
+	 * @param valueProvider the value if not present
+	 * @return the result of the computed value or present value
+	 */
+	public V supplyIfAbsent(T key, ObjectSupplier valueProvider);
+	/**
+	 * A Type Specific compute method to reduce boxing/unboxing
+	 * @param key the key that should be computed
+	 * @param mappingFunction the operator that should generate the value if present
+	 * @return the result of the default return value or present value
+	 * @note if not present then compute is not executed
+	 */
+	public V computeIfPresent(T key, ObjectObjectUnaryOperator mappingFunction);
+	/**
+	 * A Type Specific merge method to reduce boxing/unboxing
+	 * @param key the key that should be be searched for
+	 * @param value the value that should be merged with
+	 * @param mappingFunction the operator that should generate the new Value
+	 * @return the result of the merge
+	 * @note if the result matches the default return value then the key is removed from the map
+	 */
+	public V merge(T key, V value, ObjectObjectUnaryOperator mappingFunction);
+	/**
+	 * A Bulk method for merging Maps.
+	 * @param m the entries that should be bulk added
+	 * @param mappingFunction the operator that should generate the new Value
+	 * @note if the result matches the default return value then the key is removed from the map
+	 */
+	public void mergeAll(Object2ObjectMap m, ObjectObjectUnaryOperator mappingFunction);
+
+	@Override
+	public default V apply(T key) {
+		return getObject(key);
+	}
+	/**
+	 * A Type Specific get method to reduce boxing/unboxing
+	 * @param key the key that is searched for
+	 * @return the searched value or default return value
+	 */
+	public V getObject(T key);
+
+	@Override
+	public default void replaceAll(BiFunction mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		replaceObjects(mappingFunction instanceof ObjectObjectUnaryOperator ? (ObjectObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(K, V));
+	}
+
+	@Override
+	public default V compute(T key, BiFunction mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		return compute(key, mappingFunction instanceof ObjectObjectUnaryOperator ? (ObjectObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(K, V));
+	}
+
+	@Override
+	public default V computeIfAbsent(T key, Function mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		return computeIfAbsent(key, mappingFunction instanceof UnaryOperator ? (UnaryOperator)mappingFunction : K -> mappingFunction.apply(K));
+	}
+
+	@Override
+	public default V computeIfPresent(T key, BiFunction mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		return computeIfPresent(key, mappingFunction instanceof ObjectObjectUnaryOperator ? (ObjectObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(K, V));
+	}
+
+	@Override
+	public default V merge(T key, V value, BiFunction mappingFunction) {
+		Objects.requireNonNull(mappingFunction);
+		Objects.requireNonNull(value);
+		return merge(key, value, mappingFunction instanceof ObjectObjectUnaryOperator ? (ObjectObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(K, V));
+	}
+
+	/**
+	 * Type Specific forEach method to reduce boxing/unboxing
+	 * @param action processor of the values that are iterator over
+	 */
+	public void forEach(ObjectObjectConsumer action);
+
+	@Override
+	public default void forEach(BiConsumer action) {
+		Objects.requireNonNull(action);
+		forEach(action instanceof ObjectObjectConsumer ? (ObjectObjectConsumer)action : (K, V) -> action.accept(K, V));
+	}
+
+	@Override
+	public ObjectSet keySet();
+	@Override
+	public ObjectCollection values();
+	@Override
+	public ObjectSet> entrySet();
+	/**
+	 * Type Sensitive EntrySet to reduce boxing/unboxing and optionally Temp Object Allocation.
+	 * @return a EntrySet of the collection
+	 */
+	public ObjectSet> object2ObjectEntrySet();
+
+	/**
+	 * Fast Entry set that allows for a faster Entry Iterator by recycling the Entry Object and just exchanging 1 internal value
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  the keyType of elements maintained by this Collection
+	 */
+	public interface FastEntrySet extends ObjectSet>
+	{
+		/**
+		 * Fast iterator that recycles the given Entry object to improve speed and reduce object allocation
+		 * @return a Recycling ObjectIterator of the given set
+		 */
+		public ObjectIterator> fastIterator();
+		/**
+		 * Fast for each that recycles the given Entry object to improve speed and reduce object allocation
+		 * @param action the action that should be applied to each given entry
+		 */
+		public default void fastForEach(Consumer> action) {
+			forEach(action);
+		}
+	}
+
+	/**
+	 * Type Specific Map Entry that reduces boxing/unboxing
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  the keyType of elements maintained by this Collection
+	 */
+	public interface Entry extends Map.Entry
+	{
+	}
+
+	/**
+	 * Helper class that reduces the method spam of the Map Class.
+	 */
+	public static final class MapBuilder
+	{
+		static final MapBuilder INSTANCE = new MapBuilder();
+
+		/**
+		 * Starts a Map Builder that allows you to create maps as Constants a lot easier
+		 * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen
+		 * @param  the keyType of elements maintained by this Collection
+		 * @param  the keyType of elements maintained by this Collection
+		 * @return a MapBuilder
+		 */
+		public  BuilderCache start() {
+			return new BuilderCache();
+		}
+
+		/**
+		 * Starts a Map Builder that allows you to create maps as Constants a lot easier
+		 * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen
+		 * @param size the expected minimum size of Elements in the Map, default is 16
+		 * @param  the keyType of elements maintained by this Collection
+		 * @param  the keyType of elements maintained by this Collection
+		 * @return a MapBuilder
+		 */
+		public  BuilderCache start(int size) {
+			return new BuilderCache(size);
+		}
+
+		/**
+		 * Starts a Map builder and puts in the Key and Value into it
+		 * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen
+		 * @param key the key that should be added
+		 * @param value the value that should be added
+		 * @param  the keyType of elements maintained by this Collection
+		 * @param  the keyType of elements maintained by this Collection
+		 * @return a MapBuilder with the key and value stored in it.
+		 */
+		public  BuilderCache put(T key, V value) {
+			return new BuilderCache().put(key, value);
+		}
+
+		/**
+		* Helper function to unify code
+		* @param  the keyType of elements maintained by this Collection
+		* @param  the keyType of elements maintained by this Collection
+		* @return a OpenHashMap
+		*/
+		public  Object2ObjectOpenHashMap map() {
+			return new Object2ObjectOpenHashMap<>();
+		}
+
+		/**
+		* Helper function to unify code
+		* @param size the minimum capacity of the Map
+		* @param  the keyType of elements maintained by this Collection
+		* @param  the keyType of elements maintained by this Collection
+		* @return a OpenHashMap with a mimimum capacity
+		*/
+		public  Object2ObjectOpenHashMap map(int size) {
+			return new Object2ObjectOpenHashMap<>(size);
+		}
+
+		/**
+		* Helper function to unify code
+		* @param keys the keys that should be inserted
+		* @param values the values that should be inserted
+		* @param  the keyType of elements maintained by this Collection
+		* @param  the keyType of elements maintained by this Collection
+		* @throws IllegalStateException if the keys and values do not match in length
+		* @return a OpenHashMap thats contains the injected values
+		*/
+		public  Object2ObjectOpenHashMap map(T[] keys, V[] values) {
+			return new Object2ObjectOpenHashMap<>(keys, values);
+		}
+
+		/**
+		* Helper function to unify code
+		* @param map that should be cloned
+		* @param  the keyType of elements maintained by this Collection
+		* @param  the keyType of elements maintained by this Collection
+		* @return a OpenHashMap thats copies the contents of the provided map
+		*/
+		public  Object2ObjectOpenHashMap map(Object2ObjectMap map) {
+			return new Object2ObjectOpenHashMap<>(map);
+		}
+
+		/**
+		* Helper function to unify code
+		* @param map that should be cloned
+		* @param  the keyType of elements maintained by this Collection
+		* @param  the keyType of elements maintained by this Collection
+		* @return a OpenHashMap thats copies the contents of the provided map
+		* @note the map will be unboxed
+		*/
+		public  Object2ObjectOpenHashMap map(Map map) {
+			return new Object2ObjectOpenHashMap<>(map);
+		}
+
+
+	}
+
+	/**
+	 * Builder Cache for allowing to buildMaps
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  the keyType of elements maintained by this Collection
+	 */
+	public static class BuilderCache
+	{
+		T[] keys;
+		V[] values;
+		int size;
+
+		/**
+		 * Default Constructor
+		 */
+		public BuilderCache() {
+			this(HashUtil.DEFAULT_MIN_CAPACITY);
+		}
+
+		/**
+		 * Constructor providing a Minimum Capcity
+		 * @param initialSize the requested start capacity
+		 */
+		public BuilderCache(int initialSize) {
+			if(initialSize < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed");
+			keys = (T[])new Object[initialSize];
+			values = (V[])new Object[initialSize];
+		}
+
+		private void ensureSize(int newSize) {
+			if(keys.length >= newSize) return;
+			newSize = (int)Math.max(Math.min((long)keys.length + (keys.length >> 1), SanityChecks.MAX_ARRAY_SIZE), newSize);
+			keys = Arrays.copyOf(keys, newSize);
+			values = Arrays.copyOf(values, newSize);
+		}
+
+		/**
+		 * Helper function to add a Entry into the Map
+		 * @param key the key that should be added
+		 * @param value the value that should be added
+		 * @return self
+		 */
+		public BuilderCache put(T key, V value) {
+			ensureSize(size+1);
+			keys[size] = key;
+			values[size] = value;
+			size++;
+			return this;
+		}
+
+		/**
+		 * Helper function to add a Entry into the Map
+		 * @param entry the Entry that should be added
+		 * @return self
+		 */
+		public BuilderCache put(Entry entry) {
+			return put(entry.getKey(), entry.getValue());
+		}
+
+		/**
+		 * Helper function to add a Map to the Map
+		 * @param map that should be added
+		 * @return self
+		 */
+		public BuilderCache putAll(Object2ObjectMap map) {
+			return putAll(map.object2ObjectEntrySet());
+		}
+
+		/**
+		 * Helper function to add a Map to the Map
+		 * @param map that should be added
+		 * @return self
+		 */
+		public BuilderCache putAll(Map map) {
+			for(Map.Entry entry : map.entrySet())
+				put(entry.getKey(), entry.getValue());
+			return this;
+		}
+
+		/**
+		 * Helper function to add a Collection of Entries to the Map
+		 * @param c that should be added
+		 * @return self
+		 */
+		public BuilderCache putAll(ObjectIterable> c) {
+			if(c instanceof Collection)
+				ensureSize(size+((Collection>)c).size());
+
+			for(Entry entry : c)
+				put(entry);
+
+			return this;
+		}
+
+		private > E putElements(E e){
+			e.putAll(keys, values, 0, size);
+			return e;
+		}
+
+		/**
+		 * Builds the Keys and Values into a Hash Map
+		 * @return a Object2ObjectOpenHashMap
+		 */
+		public Object2ObjectOpenHashMap map() {
+			return putElements(new Object2ObjectOpenHashMap<>(size));
+		}
+
+	}
+}
diff --git a/src/main/java/speiger/src/collections/objects/sets/AbstractObjectSet.java b/src/main/java/speiger/src/collections/objects/sets/AbstractObjectSet.java
new file mode 100644
index 000000000..e9b6f4e6c
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/sets/AbstractObjectSet.java
@@ -0,0 +1,46 @@
+package speiger.src.collections.objects.sets;
+
+import java.util.Objects;
+import java.util.Set;
+
+import speiger.src.collections.objects.collections.AbstractObjectCollection;
+import speiger.src.collections.objects.collections.ObjectIterator;
+
+/**
+ * Abstract Type Specific Set that reduces boxing/unboxing
+ * @param  the keyType of elements maintained by this Collection
+ */
+public abstract class AbstractObjectSet extends AbstractObjectCollection implements ObjectSet
+{
+	@Override
+	public T addOrGet(T o) { throw new UnsupportedOperationException(); }
+	
+	@Override
+	public abstract ObjectIterator iterator();
+	@Override
+	public AbstractObjectSet copy() { throw new UnsupportedOperationException(); }
+	
+	@Override
+	public int hashCode() {
+		int hashCode = 0;
+		ObjectIterator i = iterator();
+		while(i.hasNext())
+			hashCode += Objects.hashCode(i.next());
+		return hashCode;
+	}
+	
+	@Override
+	public boolean equals(Object o) {
+		if (o == this)
+			return true;
+		if (!(o instanceof Set))
+			return false;
+		Set l = (Set)o;
+		if(l.size() != size()) return false;
+		try {
+			return containsAll(l);
+		} catch (ClassCastException | NullPointerException unused) {
+			return false;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/sets/ObjectOpenHashSet.java b/src/main/java/speiger/src/collections/objects/sets/ObjectOpenHashSet.java
new file mode 100644
index 000000000..a2b443ab3
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/sets/ObjectOpenHashSet.java
@@ -0,0 +1,609 @@
+package speiger.src.collections.objects.sets;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.BiFunction;
+import java.util.function.Predicate;
+
+import speiger.src.collections.objects.collections.ObjectCollection;
+import speiger.src.collections.objects.collections.ObjectIterator;
+import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
+import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
+import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator;
+import speiger.src.collections.utils.HashUtil;
+import speiger.src.collections.utils.ITrimmable;
+import speiger.src.collections.utils.SanityChecks;
+
+/**
+ * A Type Specific Custom implementation of the HashSet
+ * Instead of using Wrapper Object Arrays for storing keys and values there is dedicated arrays for storing keys.
+ * Extra to that there is a couple quality of life functions provided
+ * @param  the keyType of elements maintained by this Collection
+ */
+public class ObjectOpenHashSet extends AbstractObjectSet implements ITrimmable
+{
+	/** The Backing keys array */
+	protected transient T[] keys;
+	/** If a null value is present */
+	protected transient boolean containsNull;
+	/** Minimum array size the HashSet will be */
+	protected transient int minCapacity;
+	/** Index of the Null Value */
+	protected transient int nullIndex;
+	/** Maximum amount of Values that can be stored before the array gets expanded usually 75% */
+	protected transient int maxFill;
+	/** Max Index that is allowed to be searched through nullIndex - 1 */
+	protected transient int mask;
+	
+	/** Amount of Elements stored in the HashSet */
+	protected int size;
+	/** How full the Array is allowed to get before resize */
+	protected final float loadFactor;
+	
+	/**
+	 * Default Constructor
+	 */
+	public ObjectOpenHashSet() {
+		this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+	
+	/**
+	 * Constructor that defines the minimum capacity
+	 * @param minCapacity the minimum capacity the HashSet is allowed to be.
+	 * @throws IllegalStateException if the minimum capacity is negative
+	 */
+	public ObjectOpenHashSet(int minCapacity) {
+		this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+	
+	/**
+	 * Constructor that defines the minimum capacity and load factor
+	 * @param minCapacity the minimum capacity the HashSet is allowed to be.
+	 * @param loadFactor the percentage of how full the backing array can be before they resize
+	 * @throws IllegalStateException if the minimum capacity is negative
+	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
+	 */
+	public ObjectOpenHashSet(int minCapacity, float loadFactor) {
+		if(minCapacity < 0)	throw new IllegalStateException("Minimum Capacity is negative. This is not allowed");
+		if(loadFactor <= 0 || loadFactor >= 1F) throw new IllegalStateException("Load Factor is not between 0 and 1");
+		this.loadFactor = loadFactor;
+		this.minCapacity = nullIndex = HashUtil.arraySize(minCapacity, loadFactor);
+		mask = nullIndex - 1;
+		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
+		keys = (T[])new Object[nullIndex + 1];
+	}
+	
+	/**
+	 * Helper constructor that allow to create a set from unboxed values
+	 * @param array the elements that should be put into the set
+	 */
+	public ObjectOpenHashSet(T[] array) {
+		this(array, 0, array.length, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+	
+	/**
+	 * Helper constructor that allow to create a set from unboxed values
+	 * @param array the elements that should be put into the set
+	 * @param loadFactor the percentage of how full the backing array can be before they resize
+	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
+	 */
+	public ObjectOpenHashSet(T[] array, float loadFactor) {
+		this(array, 0, array.length, loadFactor);
+	}
+	
+	/**
+	 * Helper constructor that allow to create a set from unboxed values
+	 * @param array the elements that should be put into the set
+	 * @param offset the starting index within the array that should be used
+	 * @param length the amount of elements used from the array
+	 * @throws IllegalStateException if offset and length causes to step outside of the arrays range
+	 */
+	public ObjectOpenHashSet(T[] array, int offset, int length) {
+		this(array, offset, length, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+	
+	/**
+	 * Helper constructor that allow to create a set from unboxed values
+	 * @param array the elements that should be put into the set
+	 * @param offset the starting index within the array that should be used
+	 * @param length the amount of elements used from the array
+	 * @param loadFactor the percentage of how full the backing array can be before they resize
+	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
+	 * @throws IllegalStateException if offset and length causes to step outside of the arrays range
+	 */
+	public ObjectOpenHashSet(T[] array, int offset, int length, float loadFactor) {
+		this(length < 0 ? 0 : length);
+		SanityChecks.checkArrayCapacity(array.length, offset, length);
+		for(int i = 0;i collection) {
+		this(collection, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+	
+	/**
+	 * A Helper constructor that allows to create a Set with exactly the same values as the provided collection.
+	 * @param collection the set the elements should be added to the Set
+	 * @param loadFactor the percentage of how full the backing array can be before they resize
+	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
+	 */
+	public ObjectOpenHashSet(Collection collection, float loadFactor) {
+		this(collection.size(), loadFactor);
+		addAll(collection);
+	}
+	
+	/**
+	 * A Helper constructor that allows to create a Set with exactly the same values as the provided collection.
+	 * @param collection the set the elements should be added to the Set
+	 */
+	public ObjectOpenHashSet(ObjectCollection collection) {
+		this(collection, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+	
+	/**
+	 * A Helper constructor that allows to create a Set with exactly the same values as the provided collection.
+	 * @param collection the set the elements should be added to the Set
+	 * @param loadFactor the percentage of how full the backing array can be before they resize
+	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
+	 */
+	public ObjectOpenHashSet(ObjectCollection collection, float loadFactor) {
+		this(collection.size());
+		addAll(collection);
+	}
+	
+	/**
+	 * A Helper constructor that allows to create a set from a iterator of an unknown size
+	 * @param iterator the elements that should be added to the set
+	 */
+	public ObjectOpenHashSet(Iterator iterator) {
+		this(iterator, HashUtil.DEFAULT_LOAD_FACTOR);
+	}
+	
+	/**
+	 * A Helper constructor that allows to create a set from a iterator of an unknown size
+	 * @param iterator the elements that should be added to the set
+	 * @param loadFactor the percentage of how full the backing array can be before they resize
+	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
+	 */
+	public ObjectOpenHashSet(Iterator iterator, float loadFactor) {
+		this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor);
+		while(iterator.hasNext()) add(iterator.next());
+	}
+	
+	@Override
+	public boolean add(T o) {
+		if(o == null) {
+			if(containsNull) return false;
+			containsNull = true;
+			onNodeAdded(nullIndex);
+		}
+		else {
+			int pos = HashUtil.mix(Objects.hashCode(o)) & mask;
+			T current = keys[pos];
+			if(current != null) {
+				if(Objects.equals(current, o)) return false;
+				while((current = keys[pos = (++pos & mask)]) != null)
+					if(Objects.equals(current, o)) return false;
+			}
+			keys[pos] = o;
+			onNodeAdded(pos);
+		}
+		if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor));
+		return true;
+	}
+	
+	@Override
+	public T addOrGet(T o) {
+		if(o == null) {
+			if(containsNull) return null;
+			containsNull = true;
+			onNodeAdded(nullIndex);
+		}
+		else {
+			int pos = HashUtil.mix(Objects.hashCode(o)) & mask;
+			T current = keys[pos];
+			if(current != null) {
+				if(Objects.equals(current, o)) return current;
+				while((current = keys[pos = (++pos & mask)]) != null)
+					if(Objects.equals(current, o)) return current;
+			}
+			keys[pos] = o;
+			onNodeAdded(pos);
+		}
+		if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor));
+		return o;
+	}
+	
+	@Override
+	public boolean addAll(Collection c) {
+		if(loadFactor <= 0.5F) ensureCapacity(c.size());
+		else ensureCapacity(c.size() + size());
+		return super.addAll(c);
+	}
+	
+	@Override
+	public boolean addAll(ObjectCollection c) {
+		if(loadFactor <= 0.5F) ensureCapacity(c.size());
+		else ensureCapacity(c.size() + size());		
+		return super.addAll(c);
+	}
+	
+	@Override
+	public boolean contains(Object o) {
+		if(o == null) return containsNull;
+		int pos = HashUtil.mix(o.hashCode()) & mask;
+		T current = keys[pos];
+		if(current == null) return false;
+		if(Objects.equals(o, current)) return true;
+		while(true) {
+			if((current = keys[pos = (++pos & mask)]) == null) return false;
+			else if(Objects.equals(o, current)) return true;
+		}
+	}
+
+	@Override
+	public boolean remove(Object o) {
+		if(o == null) return (containsNull ? removeNullIndex() : false);
+		int pos = HashUtil.mix(o.hashCode()) & mask;
+		T current = keys[pos];
+		if(current == null) return false;
+		if(Objects.equals(o, current)) return removeIndex(pos);
+		while(true) {
+			if((current = keys[pos = (++pos & mask)]) == null) return false;
+			else if(Objects.equals(o, current)) return removeIndex(pos);
+		}
+	}
+
+	@Override
+	public boolean trim(int size) {
+		int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor)));
+		if(request >= nullIndex || this.size >= Math.min((int)Math.ceil(request * loadFactor), request - 1)) return false;
+		try {
+			rehash(request);
+		}
+		catch(OutOfMemoryError e) { return false; }
+		return true;
+	}
+	
+	@Override
+	public void clearAndTrim(int size) {
+		int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor)));
+		if(request >= nullIndex) {
+			clear();
+			return;
+		}
+		nullIndex = request;
+		mask = request-1;
+		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
+		keys = (T[])new Object[request + 1];
+		this.size = 0;
+		containsNull = false;
+	}
+	
+	@Override
+	public void forEach(Consumer action) {
+		if(size() <= 0) return;
+		if(containsNull) action.accept(keys[nullIndex]);
+		for(int i = nullIndex-1;i>=0;i--) {
+			if(keys[i] != null) action.accept(keys[i]);
+		}
+	}
+	
+	@Override
+	public void forEachIndexed(IntObjectConsumer action) {
+		Objects.requireNonNull(action);
+		if(size() <= 0) return;
+		if(containsNull) action.accept(0, keys[nullIndex]);
+		for(int i = nullIndex-1, index = containsNull ? 1 : 0;i>=0;i--) {
+			if(keys[i] != null) action.accept(index++, keys[i]);
+		}
+	}
+	
+	@Override
+	public  void forEach(E input, ObjectObjectConsumer action) {
+		Objects.requireNonNull(action);
+		if(size() <= 0) return;
+		if(containsNull) action.accept(input, keys[nullIndex]);
+		for(int i = nullIndex-1;i>=0;i--) {
+			if(keys[i] != null) action.accept(input, keys[i]);
+		}
+	}
+	
+	@Override
+	public boolean matchesAny(Predicate filter) {
+		Objects.requireNonNull(filter);
+		if(size() <= 0) return false;
+		if(containsNull && filter.test(keys[nullIndex])) return true;
+		for(int i = nullIndex-1;i>=0;i--) {
+			if(keys[i] != null && filter.test(keys[i])) return true;
+		}
+		return false;
+	}
+	
+	@Override
+	public boolean matchesNone(Predicate filter) {
+		Objects.requireNonNull(filter);
+		if(size() <= 0) return true;
+		if(containsNull && filter.test(keys[nullIndex])) return false;
+		for(int i = nullIndex-1;i>=0;i--) {
+			if(keys[i] != null && filter.test(keys[i])) return false;
+		}
+		return true;
+	}
+	
+	@Override
+	public boolean matchesAll(Predicate filter) {
+		Objects.requireNonNull(filter);
+		if(size() <= 0) return true;
+		if(containsNull && !filter.test(keys[nullIndex])) return false;
+		for(int i = nullIndex-1;i>=0;i--) {
+			if(keys[i] != null && !filter.test(keys[i])) return false;
+		}
+		return true;
+	}
+	
+	@Override
+	public  E reduce(E identity, BiFunction operator) {
+		Objects.requireNonNull(operator);
+		E state = identity;
+		if(containsNull) state = operator.apply(state, keys[nullIndex]);
+		for(int i = nullIndex-1;i>=0;i--) {
+			if(keys[i] == null) continue;
+			state = operator.apply(state, keys[i]);
+		}
+		return state;
+	}
+	
+	@Override
+	public T reduce(ObjectObjectUnaryOperator operator) {
+		Objects.requireNonNull(operator);
+		T state = null;
+		boolean empty = true;
+		if(containsNull) {
+			state = keys[nullIndex];
+			empty = false;
+		}
+		for(int i = nullIndex-1;i>=0;i--) {
+			if(keys[i] == null) continue;
+			if(empty) {
+				empty = false;
+				state = keys[i];
+				continue;
+			}
+			state = operator.apply(state, keys[i]);
+		}
+		return state;
+	}
+	
+	@Override
+	public T findFirst(Predicate filter) {
+		Objects.requireNonNull(filter);
+		if(size() <= 0) return null;
+		if(containsNull && filter.test(keys[nullIndex])) return keys[nullIndex];
+		for(int i = nullIndex-1;i>=0;i--) {
+			if(keys[i] != null && filter.test(keys[i])) return keys[i];
+		}
+		return null;
+	}
+	
+	@Override
+	public int count(Predicate filter) {
+		Objects.requireNonNull(filter);
+		if(size() <= 0) return 0;
+		int result = 0;
+		if(containsNull && filter.test(keys[nullIndex])) result++;
+		for(int i = nullIndex-1;i>=0;i--) {
+			if(keys[i] != null && filter.test(keys[i])) result++;
+		}
+		return result;
+	}
+	
+	private void ensureCapacity(int newCapacity) {
+		int size = HashUtil.arraySize(newCapacity, loadFactor);
+		if(size > nullIndex) rehash(size);
+	}
+	
+	protected boolean removeIndex(int pos) {
+		if(pos == nullIndex) return containsNull ? removeNullIndex() : false;
+		keys[pos] = null;
+		size--;
+		onNodeRemoved(pos);
+		shiftKeys(pos);
+		if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
+		return true;
+	}
+	
+	protected boolean removeNullIndex() {
+		containsNull = false;
+		keys[nullIndex] = null;
+		size--;
+		onNodeRemoved(nullIndex);
+		if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
+		return true;
+	}
+	
+	protected void onNodeAdded(int pos) {
+		
+	}
+	
+	protected void onNodeRemoved(int pos) {
+		
+	}
+	
+	protected void onNodeMoved(int from, int to) {
+		
+	}
+	
+	protected void shiftKeys(int startPos) {
+		int slot, last;
+		T current;
+		while(true) {
+			startPos = ((last = startPos) + 1) & mask;
+			while(true){
+				if((current = keys[startPos]) == null) {
+					keys[last] = null;
+					return;
+				}
+				slot = HashUtil.mix(Objects.hashCode(current)) & mask;
+				if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
+				startPos = ++startPos & mask;
+			}
+			keys[last] = current;
+			onNodeMoved(startPos, last);
+		}
+	}
+	
+	protected void rehash(int newSize) {
+		int newMask = newSize - 1;
+		T[] newKeys = (T[])new Object[newSize + 1];
+		for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) {
+			while(true) {
+				if(--i < 0) throw new ConcurrentModificationException("Set was modified during rehash");
+				if(keys[i] != null) break;
+			}
+			if(newKeys[pos = HashUtil.mix(Objects.hashCode(keys[i])) & newMask] != null)
+				while(newKeys[pos = (++pos & newMask)] != null);
+			newKeys[pos] = keys[i];
+		}
+		nullIndex = newSize;
+		mask = newMask;
+		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
+		keys = newKeys;
+	}
+	
+	@Override
+	public ObjectIterator iterator() {
+		return new SetIterator();
+	}
+	
+	@Override
+	public ObjectOpenHashSet copy() {
+		ObjectOpenHashSet set = new ObjectOpenHashSet<>(0, loadFactor);
+		set.minCapacity = minCapacity;
+		set.mask = mask;
+		set.maxFill = maxFill;
+		set.nullIndex = nullIndex;
+		set.containsNull = containsNull;
+		set.size = size;
+		set.keys = Arrays.copyOf(keys, keys.length);
+		return set;
+	}
+	
+	@Override
+	public void clear() {
+		if(size == 0) return;
+		size = 0;
+		containsNull = false;
+		Arrays.fill(keys, null);
+	}
+	
+	@Override
+	public int size() {
+		return size;
+	}
+	
+	private class SetIterator implements ObjectIterator {
+		int pos = nullIndex;
+		int returnedPos = -1;
+		int lastReturned = -1;
+		int nextIndex = Integer.MIN_VALUE;
+		boolean returnNull = containsNull;
+		T[] wrapped = null;
+		int wrappedIndex = 0;
+		
+		@Override
+		public boolean hasNext() {
+			if(nextIndex == Integer.MIN_VALUE) {
+				if(returnNull) {
+					returnNull = false;
+					nextIndex = nullIndex;
+				}
+				else
+				{
+					while(true) {
+						if(--pos < 0) {
+							if(wrapped == null || wrappedIndex <= -pos - 1) break;
+							nextIndex = -pos - 1;
+							break;
+						}
+						if(keys[pos] != null){
+							nextIndex = pos;
+							break;
+						}
+					}
+				}
+			}
+			return nextIndex != Integer.MIN_VALUE;
+		}
+		
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			returnedPos = pos;
+			if(nextIndex < 0){
+				lastReturned = Integer.MAX_VALUE;
+				T value = wrapped[nextIndex];
+				nextIndex = Integer.MIN_VALUE;
+				return value;
+			}
+			T value = keys[(lastReturned = nextIndex)];
+			nextIndex = Integer.MIN_VALUE;
+			return value;
+		}
+		
+		@Override
+		public void remove() {
+			if(lastReturned == -1) throw new IllegalStateException();
+			if(lastReturned == nullIndex) {
+				containsNull = false;
+				keys[nullIndex] = null;
+			}
+			else if(returnedPos >= 0) shiftKeys(returnedPos);
+			else {
+				ObjectOpenHashSet.this.remove(wrapped[-returnedPos - 1]);
+				lastReturned = -1;
+				return;
+			}
+			size--;
+			lastReturned = -1;
+		}
+		
+		private void shiftKeys(int startPos) {
+			int slot, last;
+			T current;
+			while(true) {
+				startPos = ((last = startPos) + 1) & mask;
+				while(true){
+					if((current = keys[startPos]) == null) {
+						keys[last] = null;
+						return;
+					}
+					slot = HashUtil.mix(Objects.hashCode(current)) & mask;
+					if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
+					startPos = ++startPos & mask;
+				}
+				if(startPos < last) addWrapper(keys[startPos]);
+				keys[last] = current;
+			}
+		}
+		
+		private void addWrapper(T value) {
+			if(wrapped == null) wrapped = (T[])new Object[2];
+			else if(wrappedIndex >= wrapped.length) {
+				T[] newArray = (T[])new Object[wrapped.length * 2];
+				System.arraycopy(wrapped, 0, newArray, 0, wrapped.length);
+				wrapped = newArray;
+			}
+			wrapped[wrappedIndex++] = value;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/sets/ObjectOrderedSet.java b/src/main/java/speiger/src/collections/objects/sets/ObjectOrderedSet.java
new file mode 100644
index 000000000..428f9538c
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/sets/ObjectOrderedSet.java
@@ -0,0 +1,89 @@
+package speiger.src.collections.objects.sets;
+
+import speiger.src.collections.objects.collections.ObjectBidirectionalIterator;
+import speiger.src.collections.objects.collections.ObjectSplititerator;
+import speiger.src.collections.objects.utils.ObjectSplititerators;
+
+/**
+ * A Special Set Interface giving Access to some really usefull functions
+ * The Idea behind this interface is to allow access to functions that give control to the Order of elements.
+ * Since Linked implementations as examples can be reordered outside of the Insertion Order.
+ * This interface provides basic access to such functions while also providing some Sorted/NaivgableSet implementations that still fit into here.
+ * 
+ * @param  the keyType of elements maintained by this Collection
+ */
+public interface ObjectOrderedSet extends ObjectSet
+{
+	/**
+	 * A customized add method that allows you to insert into the first index.
+	 * @param o the element that should be inserted
+	 * @return true if it was added
+	 * @see java.util.Set#add(Object)
+	 */
+	public boolean addAndMoveToFirst(T o);
+	/**
+	 * A customized add method that allows you to insert into the last index.
+	 * @param o the element that should be inserted
+	 * @return true if it was added
+	 * @see java.util.Set#add(Object)
+	 */
+	public boolean addAndMoveToLast(T o);
+	
+	/**
+	 * A specific move method to move a given key to the first index.
+	 * @param o that should be moved to the first index
+	 * @return true if the value was moved.
+	 * @note returns false if the value was not present in the first place
+	 */
+	public boolean moveToFirst(T o);
+	/**
+	 * A specific move method to move a given key to the last index.
+	 * @param o that should be moved to the first last
+	 * @return true if the value was moved.
+	 * @note returns false if the value was not present in the first place
+	 */
+	public boolean moveToLast(T o);
+	
+	@Override
+	public ObjectOrderedSet copy();
+	
+	@Override
+	public ObjectBidirectionalIterator iterator();
+	
+	/**
+	 * A type Specific Iterator starting from a given key
+	 * @param fromElement the element the iterator should start from
+	 * @return a iterator starting from the given element
+	 * @throws java.util.NoSuchElementException if fromElement isn't found
+	 */
+	public ObjectBidirectionalIterator iterator(T fromElement);
+	
+	/**
+	 * A Type Specific Type Splititerator to reduce boxing/unboxing
+	 * @return type specific splititerator
+	 */
+	@Override
+	default ObjectSplititerator spliterator() { return ObjectSplititerators.createSplititerator(this, 0); }
+	
+	/**
+	 * A method to get the first element in the set
+	 * @return first element in the set
+	 */
+	public T first();
+	/**
+	 * A method to get and remove the first element in the set
+	 * @return first element in the set
+	 */
+	public T pollFirst();
+	/**
+	 * A method to get the last element in the set
+	 * @return last element in the set
+	 */
+	public T last();
+	/**
+	 * A method to get and remove the last element in the set
+	 * @return last element in the set
+	 */
+	public T pollLast();
+	
+}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/sets/ObjectSet.java b/src/main/java/speiger/src/collections/objects/sets/ObjectSet.java
new file mode 100644
index 000000000..31d393d5b
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/sets/ObjectSet.java
@@ -0,0 +1,37 @@
+package speiger.src.collections.objects.sets;
+
+import java.util.Set;
+
+import speiger.src.collections.objects.collections.ObjectCollection;
+import speiger.src.collections.objects.collections.ObjectIterator;
+import speiger.src.collections.objects.collections.ObjectSplititerator;
+import speiger.src.collections.objects.utils.ObjectSplititerators;
+
+
+/**
+ * A Type Specific Set class to reduce boxing/unboxing
+ * @param  the keyType of elements maintained by this Collection
+ */
+public interface ObjectSet extends Set, ObjectCollection
+{	
+	@Override
+	public ObjectIterator iterator();
+	
+	@Override
+	public ObjectSet copy();
+	
+	/**
+	 * A Helper method that allows to add a element or getting the already present implement.
+	 * Allowing to make unique references reuseable.
+	 * @param o the element to add
+	 * @return either the inserted element or the present element.
+	 */
+	public T addOrGet(T o);
+	
+	/**
+	 * A Type Specific Type Splititerator to reduce boxing/unboxing
+	 * @return type specific splititerator
+	 */
+	@Override
+	default ObjectSplititerator spliterator() { return ObjectSplititerators.createSplititerator(this, 0); }
+}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/utils/ObjectArrays.java b/src/main/java/speiger/src/collections/objects/utils/ObjectArrays.java
new file mode 100644
index 000000000..314148959
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/utils/ObjectArrays.java
@@ -0,0 +1,1571 @@
+package speiger.src.collections.objects.utils;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.concurrent.RecursiveAction;
+import java.util.Comparator;
+import java.util.function.IntFunction;
+
+import speiger.src.collections.objects.collections.ObjectIterator;
+import speiger.src.collections.objects.utils.ObjectIterators;
+import speiger.src.collections.objects.utils.ObjectCollections;
+import speiger.src.collections.utils.SanityChecks;
+
+/**
+ * A Helper class for Arrays
+ */
+public class ObjectArrays
+{
+	/** Default Limit for Insertion/Selection Sort */
+	public static final int BASE_THRESHOLD = 16;
+	/** Default Threshold for Multithreaded Sorting Algorythm options*/
+	public static final int PARALLEL_THRESHOLD = 8192;
+	
+	/** Empty Array Reference used for Uninitialized Collections */
+	public static final Object[] EMPTY_ARRAY = new Object[0];
+	
+	/**
+	 * Function to create a new Array of a given size
+	 * @param clz the class type of array that is requested
+	 * @param length the lenght the array should be.
+	 * @param  the keyType of array that the operation should be applied
+	 * @return a Array with the requested type and length
+	 */
+	public static  T[] newArray(Class clz, int length) {
+		if(clz == Object.class) return (T[])new Object[length];
+		return (T[]) java.lang.reflect.Array.newInstance(clz, length);
+	}
+	
+	/**
+	 * A Helper function that pours all elements of a iterator into a Array
+	 * @param iter the elements that should be gathered.
+	 * @param  the keyType of array that the operation should be applied
+	 * @return array with all elements of the iterator
+	 */
+	public static  T[] pour(ObjectIterator iter) {
+		return pour(iter, Integer.MAX_VALUE);
+	}
+	
+	/**
+	 * A Helper function that pours all elements of a iterator into a Array
+	 * @param iter the elements that should be gathered.
+	 * @param max how many elements should be added
+	 * @param  the keyType of array that the operation should be applied
+	 * @return array with all requested elements of the iterator
+	 */
+	public static  T[] pour(ObjectIterator iter, int max) {
+		ObjectCollections.CollectionWrapper list = ObjectCollections.wrapper();
+		ObjectIterators.pour(iter, list, max);
+		return list.toArray((T[])new Object[list.size()]);
+	}
+	
+	/**
+	 * A Helper function that pours all elements of a iterator into a Array
+	 * @param iter the elements that should be gathered.
+	 * @param  the keyType of array that the operation should be applied
+	 * @param action that is creating the Array to be poured into
+	 * @return array with all elements of the iterator
+	 */
+	public static  E[] pour(ObjectIterator iter, IntFunction action) {
+		return pour(iter, Integer.MAX_VALUE, action);
+	}
+	
+	/**
+	 * A Helper function that pours all elements of a iterator into a Array
+	 * @param iter the elements that should be gathered.
+	 * @param max how many elements should be added
+	 * @param action that is creating the Array to be poured into
+	 * @param  the keyType of array that the operation should be applied
+	 * @return array with all requested elements of the iterator
+	 */
+	public static  E[] pour(ObjectIterator iter, int max, IntFunction action) {
+		ObjectCollections.CollectionWrapper list = ObjectCollections.wrapper();
+		ObjectIterators.pour(iter, list, max);
+		return list.toArray(action.apply(list.size()));
+	}
+	
+	
+	/**
+	 * Method to validate if the current value is the lowest value in the heap
+	 * @param data the current heap.
+	 * @param size the size of the heap
+	 * @param index the index that should be validated
+	 * @param comp the comparator to sort the heap. Can be null
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the index the element was shifted to
+	 */
+	public static  int shiftDown(T[] data, int size, int index, Comparator comp) {
+		int half = size >>> 1;
+		T value = data[index];
+		if(comp != null) {
+			while(index < half) {
+				int child = (index << 1) + 1;
+				T childValue = data[child];
+				int right = child+1;
+				if(right < size && comp.compare(data[right], childValue) < 0) childValue = data[child = right];
+				if(comp.compare(value, childValue) <= 0) break;
+				data[index] = childValue;
+				index = child;
+			}
+		}
+		else {
+			while(index < half) {
+				int child = (index << 1) + 1;
+				T childValue = data[child];
+				int right = child+1;
+				if(right < size && ((Comparable)data[right]).compareTo((T)childValue) < 0) childValue = data[child = right];
+				if(((Comparable)value).compareTo((T)childValue) <= 0) break;
+				data[index] = childValue;
+				index = child;
+			}
+		}
+		data[index] = value;
+		return index;
+	}
+	
+	/**
+	 * Method to sort a specific value into the heap.
+	 * @param data the heap itself.
+	 * @param index that should be heapified.
+	 * @param comp the comparator to sort the heap. Can be null
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the index the element was shifted to
+	 */
+	public static  int shiftUp(T[] data, int index, Comparator comp) {
+		T value = data[index];
+		if(comp != null) {
+			while(index > 0) {
+				int parent = (index - 1) >>> 1;
+				T parentValue = data[parent];
+				if(comp.compare(value, parentValue) >= 0) break;
+				data[index] = parentValue;
+				index = parent;
+			}
+		}
+		else {
+			while(index > 0) {
+				int parent = (index - 1) >>> 1;
+				T parentValue = data[parent];
+				if(((Comparable)value).compareTo((T)parentValue) >= 0) break;
+				data[index] = parentValue;
+				index = parent;
+			}
+		}
+		data[index] = value;
+		return index;
+	}
+	
+	/**
+	 * Helper function to create a Heap out of an array.
+	 * @param data the array to heapify
+	 * @param size the current size of elements within the array.
+	 * @param comp the Comparator to sort the array. Can be null
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the input array
+	 */
+	public static  T[] heapify(T[] data, int size, Comparator comp) {
+		for(int i = (size >>> 1) - 1;i>=0;shiftDown(data, size, i--, comp));
+		return data;
+	}
+	
+	/**
+	 * Simple Shuffle method for Arrays.
+	 * @param array the elements that should be shuffled
+	 * @param  the keyType of array that the operation should be applied
+	 * @note This uses the SanityChecks#getRandom
+	 * @return the provided sorted array
+	 */
+	public static  T[] shuffle(T[] array) {
+		return shuffle(array, SanityChecks.getRandom());
+	}
+	
+	/**
+	 * Simple Shuffle method for Arrays.
+	 * @param array the elements that should be shuffled
+	 * @param length the length of the array
+	 * @param  the keyType of array that the operation should be applied
+	 * @note This uses the SanityChecks#getRandom
+	 * @return the provided sorted array
+	 */
+	public static  T[] shuffle(T[] array, int length) {
+		return shuffle(array, 0, length, SanityChecks.getRandom());
+	}
+	
+	/**
+	 * Simple Shuffle method for Arrays.
+	 * @param array the elements that should be shuffled
+	 * @param offset the start array
+	 * @param length the length of the array
+	 * @param  the keyType of array that the operation should be applied
+	 * @note This uses the SanityChecks#getRandom
+	 * @return the provided sorted array
+	 */
+	public static  T[] shuffle(T[] array, int offset, int length) {
+		return shuffle(array, offset, length, SanityChecks.getRandom());
+	}
+	
+	/**
+	 * Simple Shuffle method for Arrays.
+	 * @param array the elements that should be shuffled
+	 * @param random the Random Number Generator that should be used for the shuffling
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the provided sorted array
+	 */
+	public static  T[] shuffle(T[] array, Random random) {
+		for(int i = array.length-1; i>=0;i--) {
+			int p = random.nextInt(i + 1);
+			T t = array[i];
+			array[i] = array[p];
+			array[p] = t;
+		}
+		return array;
+	}
+	
+	/**
+	 * Simple Shuffle method for Arrays.
+	 * @param array the elements that should be shuffled
+	 * @param length the length of the array
+	 * @param random the Random Number Generator that should be used for the shuffling
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the provided sorted array
+	 */
+	public static  T[] shuffle(T[] array, int length, Random random) {
+		return shuffle(array, 0, length, random);
+	}
+	
+	/**
+	 * Simple Shuffle method for Arrays.
+	 * @param array the elements that should be shuffled
+	 * @param offset the start array
+	 * @param length the length of the array
+	 * @param random the Random Number Generator that should be used for the shuffling
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the provided sorted array
+	 */
+	public static  T[] shuffle(T[] array, int offset, int length, Random random) {
+		for(int i = length-1; i>=0;i--) {
+			int p = offset + random.nextInt(i + 1);
+			T t = array[offset+i];
+			array[offset+i] = array[p];
+			array[p] = t;
+		}
+		return array;
+	}
+	
+	/**
+	 * Simple Array Reversal method
+	 * @param array the Array that should flip
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the provided array
+	 */
+	public static  T[] reverse(T[] array) {
+		return reverse(array, 0, array.length);
+	}
+	
+	/**
+	 * Simple Array Reversal method
+	 * @param array the Array that should flip
+	 * @param length the length of the array
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the provided array
+	 */
+	public static  T[] reverse(T[] array, int length) {
+		return reverse(array, 0, length);
+	}
+	
+	/**
+	 * Simple Array Reversal method
+	 * @param array the Array that should flip
+	 * @param length the length of the array
+	 * @param offset the start of the array
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the provided array
+	 */
+	public static  T[] reverse(T[] array, int offset, int length) {
+		  for (int i = offset, mid = offset + length >> 1, j = offset + length - 1; i < mid; i++, j--) {
+			  T temp = array[i];
+			  array[i] = array[j];
+			  array[j] = temp;
+		  }
+		  return array;
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator,
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Stable sort referres to Mergesort or Insertionsort
+	 * @param array the array that needs to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 * @param comp the Comparator that decides the sorting order
+	 * @return input array.
+	 */
+	public static  T[] stableSort(T[] array, Comparator comp) {
+		stableSort(array, 0, array.length, comp);
+		return array;
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator,
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Stable sort referres to Mergesort or Insertionsort
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void stableSort(T[] array, int length, Comparator comp) {
+		stableSort(array, 0, length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator,
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Stable sort referres to Mergesort or Insertionsort
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void stableSort(T[] array, int from, int to, Comparator comp) {
+		mergeSort(array, null, from, to, comp);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order, 
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Stable sort referres to Mergesort or Insertionsort
+	 * @param array the array that needs to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] stableSort(T[] array) {
+		stableSort(array, 0, array.length);
+		return array;
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order, 
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Stable sort referres to Mergesort or Insertionsort
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void stableSort(T[] array, int length) {
+		stableSort(array, 0, length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order, 
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Stable sort referres to Mergesort or Insertionsort
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void stableSort(T[] array, int from, int to) {
+		mergeSort(array, null, from, to);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator,
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Unstable sort referres to QuickSort or SelectionSort
+	 * @param array the array that needs to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] unstableSort(T[] array, Comparator comp) {
+		unstableSort(array, 0, array.length, comp);
+		return array;
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator,
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Unstable sort referres to QuickSort or SelectionSort
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void unstableSort(T[] array, int length, Comparator comp) {
+		unstableSort(array, 0, length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator,
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Unstable sort referres to QuickSort or SelectionSort
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void unstableSort(T[] array, int from, int to, Comparator comp) {
+		quickSort(array, from, to, comp);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order, 
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Unstable sort referres to QuickSort or SelectionSort
+	 * @param array the array that needs to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] unstableSort(T[] array) {
+		unstableSort(array, 0, array.length);
+		return array;
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order, 
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Unstable sort referres to QuickSort or SelectionSort
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void unstableSort(T[] array, int length) {
+		unstableSort(array, 0, length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order, 
+	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
+	 * Unstable sort referres to QuickSort or SelectionSort
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void unstableSort(T[] array, int from, int to) {
+		quickSort(array, from, to);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort,
+	 * @param array the array that needs to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] insertionSort(T[] array, Comparator comp) {
+		insertionSort(array, 0, array.length, comp);
+		return array;
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort,
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void insertionSort(T[] array, int length, Comparator comp) {
+		insertionSort(array, 0, length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort,
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void insertionSort(T[] array, int from, int to, Comparator comp) {
+		for (int i = from+1;i= from && comp.compare(current, array[j]) < 0) {
+				array[j+1] = array[j--];
+			}
+			array[j+1] = current;
+		}
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using InsertionSort, 
+	 * @param array the array that needs to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] insertionSort(T[] array) {
+		insertionSort(array, 0, array.length);
+		return array;
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using InsertionSort,
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void insertionSort(T[] array, int length) {
+		insertionSort(array, 0, length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using InsertionSort,
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void insertionSort(T[] array, int from, int to) {
+		for (int i = from+1;i= from && ((Comparable)current).compareTo((T)array[j]) < 0) {
+				array[j+1] = array[j--];
+			}
+			array[j+1] = current;
+		}
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort,
+	 * @param array the array that needs to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] selectionSort(T[] array, Comparator comp) {
+		selectionSort(array, 0, array.length, comp);
+		return array;
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort,
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void selectionSort(T[] array, int length, Comparator comp) {
+		selectionSort(array, 0, length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort,
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void selectionSort(T[] array, int from, int to, Comparator comp) {
+		for (int i = from; i < to; i++) {
+			T min = array[i];
+			int minId = i;
+			for(int j = i+1; j < to; j++) {
+				if(comp.compare(array[j], min) < 0) {
+					min = array[j];
+					minId = j;
+				}
+			}
+			T temp = array[i];
+			array[i] = min;
+			array[minId] = temp;
+		}
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Selection Sort, 
+	 * @param array the array that needs to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] selectionSort(T[] array) {
+		selectionSort(array, 0, array.length);
+		return array;
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Selection Sort,
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void selectionSort(T[] array, int length) {
+		selectionSort(array, 0, length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Selection Sort,
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void selectionSort(T[] array, int from, int to) {
+		for (int i = from; i < to; i++) {
+			T min = array[i];
+			int minId = i;
+			for(int j = i+1; j < to; j++) {
+				if(((Comparable)array[j]).compareTo((T)min) < 0) {
+					min = array[j];
+					minId = j;
+				}
+			}
+			T temp = array[i];
+			array[i] = min;
+			array[minId] = temp;
+		}
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort,
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] mergeSort(T[] array, Comparator comp) {
+		mergeSort(array, null, 0, array.length, comp);
+		return array;
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort,
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void mergeSort(T[] array, int length, Comparator comp) {
+		mergeSort(array, null, 0, length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort,
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @param supp the auxillary array that is used to simplify the sorting
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void mergeSort(T[] array, T[] supp, int from, int to, Comparator comp) {
+		if(to - from < BASE_THRESHOLD) {
+			insertionSort(array, from, to, comp);
+			return;
+		}
+		if(supp == null) supp = Arrays.copyOf(array, to);
+		int mid = (from + to) >>> 1;
+		mergeSort(supp, array, from, mid, comp);
+		mergeSort(supp, array, mid, to, comp);
+		if(comp.compare(supp[mid - 1], supp[mid]) <= 0)
+		{
+			System.arraycopy(supp, from, array, from, to - from);
+			return;
+		}
+		for(int p = from, q = mid;from < to;from++) {
+			if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++];
+			else array[from] = supp[q++];
+		}
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Merge Sort, 
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] mergeSort(T[] array) {
+		mergeSort(array, null, 0, array.length);
+		return array;
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Merge Sort,
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void mergeSort(T[] array, int length) {
+		mergeSort(array, null, 0, length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Merge Sort,
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @param supp the auxillary array that is used to simplify the sorting
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void mergeSort(T[] array, T[] supp, int from, int to) {
+		if(to - from < BASE_THRESHOLD) {
+			insertionSort(array, from, to);
+			return;
+		}
+		if(supp == null) supp = Arrays.copyOf(array, to);
+		int mid = (from + to) >>> 1;
+		mergeSort(supp, array, from, mid);
+		mergeSort(supp, array, mid, to);
+		if(((Comparable)supp[mid - 1]).compareTo((T)supp[mid]) <= 0)
+		{
+			System.arraycopy(supp, from, array, from, to - from);
+			return;
+		}
+		for(int p = from, q = mid;from < to;from++) {
+			if(q >= to || p < mid && ((Comparable)supp[p]).compareTo((T)supp[q]) < 0) array[from] = supp[p++];
+			else array[from] = supp[q++];
+		}
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using a Parallel Merge Sort,
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMergeSort(T[] array, Comparator comp) {
+		parallelMergeSort(array, null, 0, array.length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort,
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMergeSort(T[] array, int length, Comparator comp) {
+		parallelMergeSort(array, null, 0, length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort,
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @param supp the auxillary array that is used to simplify the sorting
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param comp the Comparator that decides the sorting order
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMergeSort(T[] array, T[] supp, int from, int to, Comparator comp) {
+		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
+			SanityChecks.invokeTask(new MergeSortActionComp<>(array, supp, from, to, comp));
+			return;
+		}
+		mergeSort(array, supp, from, to, comp);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Parallel Merge Sort, 
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMergeSort(T[] array) {
+		parallelMergeSort(array, null, 0, array.length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Parallel Merge Sort,
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMergeSort(T[] array, int length) {
+		parallelMergeSort(array, null, 0, length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Parallel Merge Sort,
+	 * This implementation was copied from FastUtil with a couple custom optimizations
+	 * @param array the array that needs to be sorted
+	 * @param supp the auxillary array that is used to simplify the sorting
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMergeSort(T[] array, T[] supp, int from, int to) {
+		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
+			SanityChecks.invokeTask(new MergeSortAction<>(array, supp, from, to));
+			return;
+		}
+		mergeSort(array, supp, from, to);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort,
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast.
+	 * @param array the array that needs to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void memFreeMergeSort(T[] array, Comparator comp) {
+		memFreeMergeSort(array, 0, array.length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort,
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast.
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void memFreeMergeSort(T[] array, int length, Comparator comp) {
+		memFreeMergeSort(array, 0, length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort,
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast.
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void memFreeMergeSort(T[] array, int from, int to, Comparator comp) {
+		if(to - from < BASE_THRESHOLD) {
+			insertionSort(array, from, to, comp);
+			return;
+		}
+		int mid = (from + to) >>> 1;
+		memFreeMergeSort(array, from, mid, comp);
+		memFreeMergeSort(array, mid, to, comp);
+		if(comp.compare(array[mid - 1], array[mid]) <= 0)
+			return;
+		for(int i = from, j = mid, compare;i < j && j < to;) {
+			if((compare = comp.compare(array[i], array[j])) < 0)
+				i++;
+			else if(compare == 0) swap(array, ++i, j);
+			else {
+				int k = j;
+				for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++);
+				if(j == k) {
+					swap(array, i++, j);
+					continue;
+				}
+				else if(j + 1 == k) {
+					T value = array[j];
+					System.arraycopy(array, i, array, i+1, j - i);
+					array[i] = value;
+					i++;
+					j++;
+					continue;
+				}
+				T[] data = (T[])new Object[k - j];
+				System.arraycopy(array, j, data, 0, data.length);
+				System.arraycopy(array, i, array, i+data.length, j - i);
+				System.arraycopy(data, 0, array, i, data.length);
+				i+=data.length;
+				j+=data.length;
+			}
+		}
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Memory Free Merge Sort, 
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
+	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
+	 * It does stack allocate tiny amounts of data for shifting around elements.
+	 * @author Speiger
+	 * @param array the array that needs to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] memFreeMergeSort(T[] array) {
+		memFreeMergeSort(array, 0, array.length);
+		return array;
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Memory Free Merge Sort, 
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
+	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
+	 * It does stack allocate tiny amounts of data for shifting around elements.
+	 * @author Speiger
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void memFreeMergeSort(T[] array, int length) {
+		memFreeMergeSort(array, 0, length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Memory Free Merge Sort, 
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
+	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
+	 * It does stack allocate tiny amounts of data for shifting around elements.
+	 * @author Speiger
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void memFreeMergeSort(T[] array, int from, int to) {
+		if(to - from < BASE_THRESHOLD) {
+			insertionSort(array, from, to);
+			return;
+		}
+		int mid = (from + to) >>> 1;
+		memFreeMergeSort(array, from, mid);
+		memFreeMergeSort(array, mid, to);
+		if(((Comparable)array[mid - 1]).compareTo((T)array[mid]) <= 0)
+			return;
+		for(int i = from, j = mid, comp;i < j && j < to;) {
+			if((comp = ((Comparable)array[i]).compareTo((T)array[j])) < 0)
+				i++;
+			else if(comp == 0) swap(array, ++i, j);
+			else {
+				int k = j;
+				for(;k < to - 1 && ((Comparable)array[i]).compareTo((T)array[k + 1]) > 0;k++);
+				if(j == k) {
+					swap(array, i++, j);
+					continue;
+				}
+				else if(j + 1 == k) {
+					T value = array[j];
+					System.arraycopy(array, i, array, i+1, j - i);
+					array[i] = value;
+					i++;
+					j++;
+					continue;
+				}
+				T[] data = (T[])new Object[k - j];
+				System.arraycopy(array, j, data, 0, data.length);
+				System.arraycopy(array, i, array, i+data.length, j - i);
+				System.arraycopy(data, 0, array, i, data.length);
+				i+=data.length;
+				j+=data.length;
+			}
+		}
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort,
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
+	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
+	 * It does stack allocate tiny amounts of data for shifting around elements.
+	 * @author Speiger
+	 * @param array the array that needs to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMemFreeMergeSort(T[] array, Comparator comp) {
+		parallelMemFreeMergeSort(array, 0, array.length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort,
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
+	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
+	 * It does stack allocate tiny amounts of data for shifting around elements.
+	 * @author Speiger
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMemFreeMergeSort(T[] array, int length, Comparator comp) {
+		parallelMemFreeMergeSort(array, 0, length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort,
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
+	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
+	 * It does stack allocate tiny amounts of data for shifting around elements.
+	 * @author Speiger
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param comp the Comparator that decides the sorting order
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMemFreeMergeSort(T[] array, int from, int to, Comparator comp) {
+		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
+			SanityChecks.invokeTask(new MemFreeMergeSortActionComp<>(array, from, to, comp));
+			return;
+		}
+		memFreeMergeSort(array, from, to, comp);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, 
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
+	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
+	 * It does stack allocate tiny amounts of data for shifting around elements.
+	 * @author Speiger
+	 * @param array the array that needs to be sorted
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMemFreeMergeSort(T[] array) {
+		parallelMemFreeMergeSort(array, 0, array.length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort,
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
+	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
+	 * It does stack allocate tiny amounts of data for shifting around elements.
+	 * @author Speiger
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMemFreeMergeSort(T[] array, int length) {
+		parallelMemFreeMergeSort(array, 0, length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort,
+	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
+	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
+	 * It does stack allocate tiny amounts of data for shifting around elements.
+	 * @author Speiger
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void parallelMemFreeMergeSort(T[] array, int from, int to) {
+		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
+			SanityChecks.invokeTask(new MemFreeMergeSortAction<>(array, from, to));
+			return;
+		}
+		memFreeMergeSort(array, from, to);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort,
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] quickSort(T[] array, Comparator comp) {
+		quickSort(array, 0, array.length, comp);
+		return array;
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort,
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void quickSort(T[] array, int length, Comparator comp) {
+		quickSort(array, 0, length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort,
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void quickSort(T[] array, int from, int to, Comparator comp) {
+		int length = to - from;
+		if(length <= 0) return;
+		if(length < BASE_THRESHOLD) {
+			selectionSort(array, from, to, comp);
+			return;			
+		}
+		T pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)];
+		int a = from, b = a, c = to - 1, d = c;
+		for(int compare;;swap(array, b++, c--)) {
+			for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) {
+				if(compare == 0) swap(array, a++, b);
+			}
+			for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) {
+				if(compare == 0) swap(array, c, d--);
+			}
+			if(b>c) break;
+		}
+		swap(array, from, b, Math.min(a - from, b - a)); 
+		swap(array, b, to, Math.min(d - c, to - d - 1));
+		if((length = b - a) > 1) quickSort(array, from, from + length, comp);
+		if((length = d - c) > 1) quickSort(array, to - length, to, comp);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Quick Sort, 
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 * @return input array
+	 */
+	public static  T[] quickSort(T[] array) {
+		quickSort(array, 0, array.length);
+		return array;
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Quick Sort,
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void quickSort(T[] array, int length) {
+		quickSort(array, 0, length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Quick Sort,
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param  the keyType of array that the operation should be applied
+	 */
+	public static  void quickSort(T[] array, int from, int to) {
+		int length = to - from;
+		if(length <= 0) return;
+		if(length < BASE_THRESHOLD) {
+			selectionSort(array, from, to);
+			return;			
+		}
+		T pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)];
+		int a = from, b = a, c = to - 1, d = c;
+		for(int comp = 0;;swap(array, b++, c--)) {
+			for(;b<=c && (comp = ((Comparable)array[b]).compareTo((T)pivot)) <= 0;b++) {
+				if(comp == 0) swap(array, a++, b);
+			}
+			for(;c>=b && (comp = ((Comparable)array[c]).compareTo((T)pivot)) >= 0;c--) {
+				if(comp == 0) swap(array, c, d--);
+			}
+			if(b>c) break;
+		}
+		swap(array, from, b, Math.min(a - from, b - a)); 
+		swap(array, b, to, Math.min(d - c, to - d - 1));
+		if((length = b - a) > 1) quickSort(array, from, from + length);
+		if((length = d - c) > 1) quickSort(array, to - length, to);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort,
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 */
+	public static  void parallelQuickSort(T[] array, Comparator comp) {
+		parallelQuickSort(array, 0, array.length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort,
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 */
+	public static  void parallelQuickSort(T[] array, int length, Comparator comp) {
+		parallelQuickSort(array, 0, length, comp);
+	}
+	
+	/**
+	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort,
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param comp the Comparator that decides the sorting order
+	 * @param  the keyType of array that the operation should be applied
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 */
+	public static  void parallelQuickSort(T[] array, int from, int to, Comparator comp) {
+		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
+			SanityChecks.invokeTask(new QuickSortActionComp<>(array, from, to, comp));
+			return;
+		}
+		quickSort(array, from, to, comp);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Parallel Quick Sort, 
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 */
+	public static  void parallelQuickSort(T[] array) {
+		parallelQuickSort(array, 0, array.length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Parallel Quick Sort,
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param length the maxmium size of the array to be sorted
+	 * @param  the keyType of array that the operation should be applied
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 */
+	public static  void parallelQuickSort(T[] array, int length) {
+		parallelQuickSort(array, 0, length);
+	}
+	
+	/**
+	 * Sorts an array according to the natural ascending order using Parallel Quick Sort,
+	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
+	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
+	 * @param array the array that needs to be sorted
+	 * @param from where the array should be sorted from
+	 * @param to where the array should be sorted to
+	 * @param  the keyType of array that the operation should be applied
+	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
+	 */
+	public static  void parallelQuickSort(T[] array, int from, int to) {
+		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
+			SanityChecks.invokeTask(new QuickSortAction<>(array, from, to));
+			return;
+		}
+		quickSort(array, from, to);
+	}
+	
+	static  void swap(T[] a, int from, int to) {
+		T t = a[from];
+		a[from] = a[to];
+		a[to] = t;
+	}
+	
+	static  void swap(T[] a, int from, int to, int length) {
+		to -= length;
+		for(int i = 0;i int subMedium(T[] data, int a, int b, int c, int length, Comparator comp) {
+		return medium(data, medium(data, a, a + length, a + (length * 2), comp), medium(data, b - length, b, b + length, comp), medium(data, c - (length * 2), c - length, c, comp), comp);
+	}
+	
+	static  int medium(T[] data, int a, int b, int c, Comparator comp) {
+		return comp.compare(data[a], data[b]) < 0 ? (comp.compare(data[b], data[c]) < 0 ? b : comp.compare(data[a], data[c]) < 0 ? c : a) : (comp.compare(data[b], data[c]) > 0 ? b : comp.compare(data[a], data[c]) > 0 ? c : a);
+	}
+	
+	static  int subMedium(T[] data, int a, int b, int c, int length) {
+		return medium(data, medium(data, a, a + length, a + (length * 2)), medium(data, b - length, b, b + length), medium(data, c - (length * 2), c - length, c));
+	}
+	
+	static  int medium(T[] data, int a, int b, int c) {
+		return ((Comparable)data[a]).compareTo((T)data[b]) < 0 ? (((Comparable)data[b]).compareTo((T)data[c]) < 0 ? b : ((Comparable)data[a]).compareTo((T)data[c]) < 0 ? c : a) : (((Comparable)data[b]).compareTo((T)data[c]) > 0 ? b : ((Comparable)data[a]).compareTo((T)data[c]) > 0 ? c : a);
+	}
+	
+	static class QuickSortAction extends RecursiveAction {
+		private static final long serialVersionUID = 0L;
+		T[] array;
+		int from;
+		int to;
+		
+		QuickSortAction(T[] array, int from, int to)
+		{
+			this.array = array;
+			this.from = from;
+			this.to = to;
+		}
+		
+		@Override
+		protected void compute()
+		{
+			int length = to - from;
+			if(length <= 0) return;
+			if(length < BASE_THRESHOLD) {
+				selectionSort(array, from, to);
+				return;			
+			}
+			T pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)];
+			int a = from, b = a, c = to - 1, d = c;
+			for(int comp = 0;;swap(array, b++, c--)) {
+				for(;b<=c && (comp = ((Comparable)array[b]).compareTo((T)pivot)) <= 0;b++) {
+					if(comp == 0) swap(array, a++, b);
+				}
+				for(;c>=b && (comp = ((Comparable)array[c]).compareTo((T)pivot)) >= 0;c--) {
+					if(comp == 0) swap(array, c, d--);
+				}
+				if(b>c) break;
+			}
+			swap(array, from, b, Math.min(a - from, b - a)); 
+			swap(array, b, to, Math.min(d - c, to - d - 1));
+			if(b - a > 1 && d - c > 1) invokeAll(new QuickSortAction<>(array, from, from + (b - a)), new QuickSortAction<>(array, to - (d - c), to));
+			else if(b - a > 1) new QuickSortAction<>(array, from, from + (b - a)).invoke();
+			else if(d - c > 1) new QuickSortAction<>(array, to - (d - c), to).invoke();
+		}
+	}
+	
+	static class QuickSortActionComp extends RecursiveAction {
+		private static final long serialVersionUID = 0L;
+		T[] array;
+		int from;
+		int to;
+		Comparator comp;
+		
+		QuickSortActionComp(T[] array, int from, int to, Comparator comp)
+		{
+			this.array = array;
+			this.from = from;
+			this.to = to;
+			this.comp = comp;
+		}
+		
+		@Override
+		protected void compute()
+		{
+			int length = to - from;
+			if(length <= 0) return;
+			if(length < BASE_THRESHOLD) {
+				selectionSort(array, from, to, comp);
+				return;			
+			}
+			T pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)];
+			int a = from, b = a, c = to - 1, d = c;
+			for(int compare;;swap(array, b++, c--)) {
+				for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) {
+					if(compare == 0) swap(array, a++, b);
+				}
+				for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) {
+					if(compare == 0) swap(array, c, d--);
+				}
+				if(b>c) break;
+			}
+			swap(array, from, b, Math.min(a - from, b - a)); 
+			swap(array, b, to, Math.min(d - c, to - d - 1));
+			if(b - a > 1 && d - c > 1) invokeAll(new QuickSortActionComp<>(array, from, from + (b - a), comp), new QuickSortActionComp<>(array, to - (d - c), to, comp));
+			else if(b - a > 1) new QuickSortActionComp<>(array, from, from + (b - a), comp).invoke();
+			else if(d - c > 1) new QuickSortActionComp<>(array, to - (d - c), to, comp).invoke();
+		}
+	}
+	
+	static class MergeSortAction extends RecursiveAction {
+		private static final long serialVersionUID = 0L;
+		T[] array;
+		T[] supp;
+		int from;
+		int to;
+		
+		MergeSortAction(T[] array, T[] supp, int from, int to)
+		{
+			this.array = array;
+			this.supp = supp;
+			this.from = from;
+			this.to = to;
+		}
+		
+		@Override
+		protected void compute()
+		{
+			if(to - from < BASE_THRESHOLD) {
+				insertionSort(array, from, to);
+				return;
+			}
+			if(supp == null) supp = Arrays.copyOf(array, to);
+			int mid = (from + to) >>> 1;
+			invokeAll(new MergeSortAction<>(supp, array, from, mid), new MergeSortAction<>(supp, array, mid, to));
+			if(((Comparable)supp[mid - 1]).compareTo((T)supp[mid]) <= 0)
+			{
+				System.arraycopy(supp, from, array, from, to - from);
+				return;
+			}
+			for(int p = from, q = mid;from < to;from++) {
+				if(q >= to || p < mid && ((Comparable)supp[p]).compareTo((T)supp[q]) < 0) array[from] = supp[p++];
+				else array[from] = supp[q++];
+			}
+		}
+	}
+	
+	static class MergeSortActionComp extends RecursiveAction {
+		private static final long serialVersionUID = 0L;
+		T[] array;
+		T[] supp;
+		int from;
+		int to;
+		Comparator comp;
+		
+		MergeSortActionComp(T[] array, T[] supp, int from, int to, Comparator comp)
+		{
+			this.array = array;
+			this.supp = supp;
+			this.from = from;
+			this.to = to;
+			this.comp = comp;
+		}
+		
+		@Override
+		protected void compute()
+		{
+			if(to - from < BASE_THRESHOLD) {
+				insertionSort(array, from, to, comp);
+				return;
+			}
+			if(supp == null) supp = Arrays.copyOf(array, to);
+			int mid = (from + to) >>> 1;
+			invokeAll(new MergeSortActionComp<>(supp, array, from, mid, comp), new MergeSortActionComp<>(supp, array, mid, to, comp));
+			if(comp.compare(supp[mid - 1], supp[mid]) <= 0)
+			{
+				System.arraycopy(supp, from, array, from, to - from);
+				return;
+			}
+			for(int p = from, q = mid;from < to;from++) {
+				if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++];
+				else array[from] = supp[q++];
+			}
+		}
+	}
+	
+	static class MemFreeMergeSortAction extends RecursiveAction {
+		private static final long serialVersionUID = 0L;
+		T[] array;
+		int from;
+		int to;
+		
+		MemFreeMergeSortAction(T[] array, int from, int to)
+		{
+			this.array = array;
+			this.from = from;
+			this.to = to;
+		}
+		
+		@Override
+		protected void compute()
+		{
+			if(to - from < BASE_THRESHOLD) {
+				insertionSort(array, from, to);
+				return;
+			}
+			int mid = (from + to) >>> 1;
+			invokeAll(new MemFreeMergeSortAction<>(array, from, mid), new MemFreeMergeSortAction<>(array, mid, to));
+			if(((Comparable)array[mid - 1]).compareTo((T)array[mid]) <= 0)
+				return;
+			for(int i = from, j = mid, comp;i < j && j < to;) {
+				if((comp = ((Comparable)array[i]).compareTo((T)array[j])) < 0)
+					i++;
+				else if(comp == 0) swap(array, ++i, j);
+				else {
+					int k = j;
+					for(;k < to - 1 && ((Comparable)array[i]).compareTo((T)array[k + 1]) > 0;k++);
+					if(j == k) {
+						swap(array, i++, j);
+						continue;
+					}
+					else if(j + 1 == k) {
+						T value = array[j];
+						System.arraycopy(array, i, array, i+1, j - i);
+						array[i] = value;
+						i++;
+						j++;
+						continue;
+					}
+					T[] data = (T[])new Object[k - j];
+					System.arraycopy(array, j, data, 0, data.length);
+					System.arraycopy(array, i, array, i+data.length, j - i);
+					System.arraycopy(data, 0, array, i, data.length);
+					i+=data.length;
+					j+=data.length;
+				}
+			}
+		}
+	}
+	
+	static class MemFreeMergeSortActionComp extends RecursiveAction {
+		private static final long serialVersionUID = 0L;
+		T[] array;
+		int from;
+		int to;
+		Comparator comp;
+		
+		MemFreeMergeSortActionComp(T[] array, int from, int to, Comparator comp)
+		{
+			this.array = array;
+			this.from = from;
+			this.to = to;
+			this.comp = comp;
+		}
+		
+		@Override
+		protected void compute()
+		{
+			if(to - from < BASE_THRESHOLD) {
+				insertionSort(array, from, to, comp);
+				return;
+			}
+			int mid = (from + to) >>> 1;
+			invokeAll(new MemFreeMergeSortActionComp<>(array, from, mid, comp), new MemFreeMergeSortActionComp<>(array, mid, to, comp));
+
+			if(comp.compare(array[mid - 1], array[mid]) <= 0)
+				return;
+			for(int i = from, j = mid, compare;i < j && j < to;) {
+				if((compare = comp.compare(array[i], array[j])) < 0)
+					i++;
+				else if(compare == 0) swap(array, ++i, j);
+				else {
+					int k = j;
+					for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++);
+					if(j == k) {
+						swap(array, i++, j);
+						continue;
+					}
+					else if(j + 1 == k) {
+						T value = array[j];
+						System.arraycopy(array, i, array, i+1, j - i);
+						array[i] = value;
+						i++;
+						j++;
+						continue;
+					}
+					T[] data = (T[])new Object[k - j];
+					System.arraycopy(array, j, data, 0, data.length);
+					System.arraycopy(array, i, array, i+data.length, j - i);
+					System.arraycopy(data, 0, array, i, data.length);
+					i+=data.length;
+					j+=data.length;
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/utils/ObjectCollections.java b/src/main/java/speiger/src/collections/objects/utils/ObjectCollections.java
new file mode 100644
index 000000000..77df1ee3e
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/utils/ObjectCollections.java
@@ -0,0 +1,802 @@
+package speiger.src.collections.objects.utils;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Comparator;
+import java.util.function.BiFunction;
+import java.util.function.Predicate;
+import java.util.function.Consumer;
+
+import speiger.src.collections.objects.collections.AbstractObjectCollection;
+import speiger.src.collections.objects.collections.ObjectCollection;
+import speiger.src.collections.objects.collections.ObjectIterator;
+import speiger.src.collections.objects.utils.ObjectArrays;
+import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator;
+import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
+import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
+import speiger.src.collections.utils.HashUtil;
+import speiger.src.collections.utils.ITrimmable;
+import speiger.src.collections.utils.SanityChecks;
+
+/**
+ * A Helper class for Collections
+ */
+public class ObjectCollections
+{
+	/**
+	 * Empty Collection Reference
+	 */
+	public static final ObjectCollection EMPTY = new EmptyCollection<>();
+	
+	/**
+	 * Returns a Immutable EmptyCollection instance that is automatically casted.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return an empty collection
+	 */
+	public static  ObjectCollection empty() {
+		return (ObjectCollection)EMPTY;
+	}
+	
+	/**
+	 * Returns a Immutable Collection instance based on the instance given.
+	 * @param c that should be made immutable/unmodifiable
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a unmodifiable collection wrapper. If the Collection already a unmodifiable wrapper then it just returns itself.
+	 */
+	public static  ObjectCollection unmodifiable(ObjectCollection c) {
+		return c instanceof UnmodifiableCollection ? c : new UnmodifiableCollection<>(c);
+	}
+	
+	/**
+	 * Returns a synchronized Collection instance based on the instance given.
+	 * @param c that should be synchronized
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself.
+	 */
+	public static  ObjectCollection synchronize(ObjectCollection c) {
+		return c instanceof SynchronizedCollection ? c : new SynchronizedCollection<>(c);
+	}
+	
+	/**
+	 * Returns a synchronized Collection instance based on the instance given.
+	 * @param c that should be synchronized
+	 * @param mutex is the controller of the synchronization block.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself.
+	 */
+	public static  ObjectCollection synchronize(ObjectCollection c, Object mutex) {
+		return c instanceof SynchronizedCollection ? c : new SynchronizedCollection<>(c, mutex);
+	}
+	
+	/**
+	 * Creates a Singleton Collection of a given element
+	 * @param element the element that should be converted into a singleton collection
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a singletoncollection of the given element
+	 */
+	public static  ObjectCollection singleton(T element) {
+		return new SingletonCollection<>(element);
+	}
+	
+	protected static  CollectionWrapper wrapper() {
+		return new CollectionWrapper<>();
+	}
+	
+	protected static  CollectionWrapper wrapper(int size) {
+		return new CollectionWrapper<>(size);
+	}
+	
+	protected static  DistinctCollectionWrapper distinctWrapper() {
+		return new DistinctCollectionWrapper<>();
+	}
+	
+	protected static  DistinctCollectionWrapper distinctWrapper(int size) {
+		return new DistinctCollectionWrapper<>(size);
+	}
+	
+	protected static class CollectionWrapper extends AbstractObjectCollection implements ITrimmable {
+		T[] elements;
+		int size = 0;
+		
+		public CollectionWrapper() {
+			this(10);
+		}
+		
+		public CollectionWrapper(int size) {
+			if(size < 0) throw new IllegalStateException("Size has to be 0 or greater");
+			elements = (T[])new Object[size];
+		}
+		
+		@Override
+		public boolean add(T o) {
+			if(size >= elements.length) elements = Arrays.copyOf(elements, (int)Math.min((long)elements.length + (elements.length >> 1), SanityChecks.MAX_ARRAY_SIZE));
+			elements[size++] = o;
+			return true;
+		}
+		
+		public T get(int index) {
+			if(index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+			return elements[index];
+		}
+		
+		@Override
+		public boolean remove(Object e) {
+			for(int i = 0;i= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+			size--;
+			if(index != size) System.arraycopy(elements, index+1, elements, index, size - index);
+		}
+		
+		@Override
+		public ObjectIterator iterator() {
+			return new ObjectIterator() {
+				int index = 0;
+				int lastReturned = -1;
+				
+				@Override
+				public boolean hasNext() {
+					return index < size;
+				}
+				
+				@Override
+				public T next() {
+					int i = index++;
+					return elements[(lastReturned = i)];
+				}
+				
+				@Override
+				public void remove() {
+					if(lastReturned == -1) throw new IllegalStateException();
+					removeIndex(lastReturned);
+					index = lastReturned;
+					lastReturned = -1;
+				}
+			};
+		}
+		
+		@Override
+		public int size() {
+			return size;
+		}
+		
+		@Override
+		public void clear() {
+			for(int i = 0;i c) {
+			if(c != null) ObjectArrays.stableSort(elements, size, c);
+			else ObjectArrays.stableSort(elements, size);
+		}
+
+		public void unstableSort(Comparator c) {
+			if(c != null) ObjectArrays.unstableSort(elements, size, c);
+			else ObjectArrays.unstableSort(elements, size);
+		}
+		
+		@Override
+		public void forEach(Consumer action) {
+			Objects.requireNonNull(action);
+			for(int i = 0;i void forEach(E input, ObjectObjectConsumer action) {
+			Objects.requireNonNull(action);
+			for(int i = 0;i size() || size() == elements.length) return false;
+			int value = Math.max(size, size());
+			elements = value == 0 ? (T[])ObjectArrays.EMPTY_ARRAY : Arrays.copyOf(elements, value);
+			return true;
+		}
+		
+		@Override
+		public void clearAndTrim(int size) {
+			if(elements.length <= size) {
+				clear();
+				return;
+			}
+			elements = size == 0 ? (T[])ObjectArrays.EMPTY_ARRAY : (T[])new Object[size];
+			this.size = size;
+		}
+		
+		@Override
+		public Object[] toArray() {
+			Object[] obj = new Object[size];
+			for(int i = 0;i E[] toArray(E[] a) {
+			if(a == null) a = (E[])new Object[size];
+			else if(a.length < size) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), size);
+	        System.arraycopy(elements, 0, a, 0, size);
+			if (a.length > size) a[size] = null;
+			return a;
+		}
+		
+	}
+	
+	protected static class DistinctCollectionWrapper extends AbstractObjectCollection {
+		T[] keys;
+		boolean containsNull;
+		int minCapacity;
+		int nullIndex;
+		int maxFill;
+		int mask;
+		int size;
+		
+		public DistinctCollectionWrapper() {
+			this(HashUtil.DEFAULT_MIN_CAPACITY);
+		}
+		
+		public DistinctCollectionWrapper(int size) {
+			if(minCapacity < 0)	throw new IllegalStateException("Minimum Capacity is negative. This is not allowed");
+			minCapacity = nullIndex = HashUtil.arraySize(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR);
+			mask = nullIndex - 1;
+			maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1);
+			keys = (T[])new Object[nullIndex + 1];
+		}
+
+		@Override
+		public boolean add(T o) {
+			if(o == null) {
+				if(containsNull) return false;
+				containsNull = true;
+			}
+			else {
+				int pos = HashUtil.mix(Objects.hashCode(o)) & mask;
+				T current = keys[pos];
+				if(current != null) {
+					if(Objects.equals(current, o)) return false;
+					while((current = keys[pos = (++pos & mask)]) != null)
+						if(Objects.equals(current, o)) return false;
+				}
+				keys[pos] = o;
+			}
+			if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, HashUtil.DEFAULT_LOAD_FACTOR));
+			return true;
+		}
+		
+		@Override
+		public boolean contains(Object o) {
+			if(o == null) return containsNull;
+			int pos = HashUtil.mix(o.hashCode()) & mask;
+			T current = keys[pos];
+			if(current == null) return false;
+			if(Objects.equals(o, current)) return true;
+			while(true) {
+				if((current = keys[pos = (++pos & mask)]) == null) return false;
+				else if(Objects.equals(o, current)) return true;
+			}
+		}
+
+		@Override
+		public boolean remove(Object o) {
+			if(o == null) return (containsNull ? removeNullIndex() : false);
+			int pos = HashUtil.mix(o.hashCode()) & mask;
+			T current = keys[pos];
+			if(current == null) return false;
+			if(Objects.equals(o, current)) return removeIndex(pos);
+			while(true) {
+				if((current = keys[pos = (++pos & mask)]) == null) return false;
+				else if(Objects.equals(o, current)) return removeIndex(pos);
+			}
+		}
+
+		protected boolean removeIndex(int pos) {
+			if(pos == nullIndex) return containsNull ? removeNullIndex() : false;
+			keys[pos] = null;
+			size--;
+			shiftKeys(pos);
+			if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
+			return true;
+		}
+		
+		protected boolean removeNullIndex() {
+			containsNull = false;
+			keys[nullIndex] = null;
+			size--;
+			if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
+			return true;
+		}
+		
+		@Override
+		public ObjectIterator iterator() {
+			return new SetIterator();
+		}
+		
+		@Override
+		public void forEach(Consumer action) {
+			if(size() <= 0) return;
+			if(containsNull) action.accept(keys[nullIndex]);
+			for(int i = nullIndex-1;i>=0;i--) {
+				if(keys[i] != null) action.accept(keys[i]);
+			}
+		}
+		
+		@Override
+		public DistinctCollectionWrapper copy() {
+			DistinctCollectionWrapper set = new DistinctCollectionWrapper<>(0);
+			set.minCapacity = minCapacity;
+			set.mask = mask;
+			set.maxFill = maxFill;
+			set.nullIndex = nullIndex;
+			set.containsNull = containsNull;
+			set.size = size;
+			set.keys = Arrays.copyOf(keys, keys.length);
+			return set;
+		}
+		
+		protected void shiftKeys(int startPos) {
+			int slot, last;
+			T current;
+			while(true) {
+				startPos = ((last = startPos) + 1) & mask;
+				while(true){
+					if((current = keys[startPos]) == null) {
+						keys[last] = null;
+						return;
+					}
+					slot = HashUtil.mix(Objects.hashCode(current)) & mask;
+					if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
+					startPos = ++startPos & mask;
+				}
+				keys[last] = current;
+			}
+		}
+		
+		protected void rehash(int newSize) {
+			int newMask = newSize - 1;
+			T[] newKeys = (T[])new Object[newSize + 1];
+			for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) {
+				while(true) {
+					if(--i < 0) throw new ConcurrentModificationException("Set was modified during rehash");
+					if(keys[i] != null) break;
+				}
+				if(newKeys[pos = HashUtil.mix(Objects.hashCode(keys[i])) & newMask] != null)
+					while(newKeys[pos = (++pos & newMask)] != null);
+				newKeys[pos] = keys[i];
+			}
+			nullIndex = newSize;
+			mask = newMask;
+			maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1);
+			keys = newKeys;
+		}
+		
+		@Override
+		public void clear() {
+			if(size == 0) return;
+			size = 0;
+			containsNull = false;
+			Arrays.fill(keys, null);
+		}
+		
+		@Override
+		public int size() {
+			return size;
+		}
+		
+		private class SetIterator implements ObjectIterator {
+			int pos = nullIndex;
+			int returnedPos = -1;
+			int lastReturned = -1;
+			int nextIndex = Integer.MIN_VALUE;
+			boolean returnNull = containsNull;
+			T[] wrapped = null;
+			int wrappedIndex = 0;
+			
+			@Override
+			public boolean hasNext() {
+				if(nextIndex == Integer.MIN_VALUE) {
+					if(returnNull) {
+						returnNull = false;
+						nextIndex = nullIndex;
+					}
+					else
+					{
+						while(true) {
+							if(--pos < 0) {
+								if(wrapped == null || wrappedIndex <= -pos - 1) break;
+								nextIndex = -pos - 1;
+								break;
+							}
+							if(keys[pos] != null){
+								nextIndex = pos;
+								break;
+							}
+						}
+					}
+				}
+				return nextIndex != Integer.MIN_VALUE;
+			}
+			
+			@Override
+			public T next() {
+				if(!hasNext()) throw new NoSuchElementException();
+				returnedPos = pos;
+				if(nextIndex < 0){
+					lastReturned = Integer.MAX_VALUE;
+					T value = wrapped[nextIndex];
+					nextIndex = Integer.MIN_VALUE;
+					return value;
+				}
+				T value = keys[(lastReturned = nextIndex)];
+				nextIndex = Integer.MIN_VALUE;
+				return value;
+			}
+			
+			@Override
+			public void remove() {
+				if(lastReturned == -1) throw new IllegalStateException();
+				if(lastReturned == nullIndex) {
+					containsNull = false;
+					keys[nullIndex] = null;
+				}
+				else if(returnedPos >= 0) shiftKeys(returnedPos);
+				else {
+					DistinctCollectionWrapper.this.remove(wrapped[-returnedPos - 1]);
+					lastReturned = -1;
+					return;
+				}
+				size--;
+				lastReturned = -1;
+			}
+			
+			private void shiftKeys(int startPos) {
+				int slot, last;
+				T current;
+				while(true) {
+					startPos = ((last = startPos) + 1) & mask;
+					while(true){
+						if((current = keys[startPos]) == null) {
+							keys[last] = null;
+							return;
+						}
+						slot = HashUtil.mix(Objects.hashCode(current)) & mask;
+						if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
+						startPos = ++startPos & mask;
+					}
+					if(startPos < last) addWrapper(keys[startPos]);
+					keys[last] = current;
+				}
+			}
+			
+			private void addWrapper(T value) {
+				if(wrapped == null) wrapped = (T[])new Object[2];
+				else if(wrappedIndex >= wrapped.length) {
+					T[] newArray = (T[])new Object[wrapped.length * 2];
+					System.arraycopy(wrapped, 0, newArray, 0, wrapped.length);
+					wrapped = newArray;
+				}
+				wrapped[wrappedIndex++] = value;
+			}
+		}
+	}
+	
+	private static class SingletonCollection extends AbstractObjectCollection
+	{
+		T element;
+		
+		SingletonCollection(T element) {
+			this.element = element;
+		}
+		
+		@Override
+		public boolean add(T o) { throw new UnsupportedOperationException(); }
+		@Override
+		public ObjectIterator iterator()
+		{
+			return new ObjectIterator() {
+				boolean next = true;
+				@Override
+				public boolean hasNext() { return next; }
+				@Override
+				public T next() {
+					if(!hasNext()) throw new NoSuchElementException();
+					next = false;
+					return element;
+				}
+			};
+		}
+		
+		@Override
+		public boolean equals(Object o) {
+			if (o == this)
+				return true;
+			if (!(o instanceof Collection))
+				return false;
+			Collection l = (Collection)o;
+			if(l.size() != size()) return false;
+			Iterator iter = l.iterator();
+			if (iter.hasNext() && !Objects.equals(element, iter.next())) {
+				return false;
+			}
+			return !iter.hasNext();
+		}
+		
+		@Override
+		public int hashCode() {
+			return Objects.hashCode(element);
+		}
+		
+		@Override
+		public int size() { return 1; }
+		
+		@Override
+		public SingletonCollection copy() { return new SingletonCollection<>(element); }
+	}
+	
+	/**
+	 * Synchronized Collection Wrapper for the synchronizedCollection function
+	 * @param  the keyType of elements maintained by this Collection
+	 */
+	public static class SynchronizedCollection implements ObjectCollection {
+		ObjectCollection c;
+		protected Object mutex;
+		
+		SynchronizedCollection(ObjectCollection c) {
+			this.c = c;
+			mutex = this;
+		}
+		
+		SynchronizedCollection(ObjectCollection c, Object mutex) {
+			this.c = c;
+			this.mutex = mutex;
+		}
+		
+		@Override
+		public boolean add(T o) { synchronized(mutex) { return c.add(o); } }
+		@Override
+		public boolean addAll(Collection c) { synchronized(mutex) { return this.c.addAll(c); } }
+		@Override
+		public boolean addAll(ObjectCollection c) { synchronized(mutex) { return this.c.addAll(c); } }
+		@Override
+		public boolean addAll(T[] e, int offset, int length) { synchronized(mutex) { return c.addAll(e, offset, length); } }
+		@Override
+		public boolean contains(Object o) { synchronized(mutex) { return c.contains(o); } }
+		@Override
+		public boolean containsAll(Collection c) { synchronized(mutex) { return this.c.containsAll(c); } }
+		
+		@Override
+		public boolean containsAny(Collection c) { synchronized(mutex) { return this.c.containsAny(c); } }
+		
+		@Override
+		public boolean containsAll(ObjectCollection c) { synchronized(mutex) { return this.c.containsAll(c); } }
+		
+		@Override
+		public boolean containsAny(ObjectCollection c) { synchronized(mutex) { return this.c.containsAny(c); } }
+		
+		@Override
+		public int size() { synchronized(mutex) { return c.size(); } }
+		
+		@Override
+		public boolean isEmpty() { synchronized(mutex) { return c.isEmpty(); } }
+		
+		@Override
+		public ObjectIterator iterator() {
+			return c.iterator();
+		}
+		
+		@Override
+		public ObjectCollection copy() { synchronized(mutex) { return c.copy(); } }
+		
+		@Override
+		public boolean remove(Object o) { synchronized(mutex) { return c.remove(o); } }
+		@Override
+		public boolean removeAll(Collection c) { synchronized(mutex) { return this.c.removeAll(c); } }
+		@Override
+		public boolean retainAll(Collection c) { synchronized(mutex) { return this.c.retainAll(c); } }
+		@Override
+		public boolean removeAll(ObjectCollection c) { synchronized(mutex) { return this.c.removeAll(c); } }
+		@Override
+		public boolean removeAll(ObjectCollection c, Consumer r) { synchronized(mutex) { return this.c.removeAll(c, r); } }
+		@Override
+		public boolean retainAll(ObjectCollection c) { synchronized(mutex) { return this.c.retainAll(c); } }
+		@Override
+		public boolean retainAll(ObjectCollection c, Consumer r) { synchronized(mutex) { return this.c.retainAll(c, r); } }
+		@Override
+		public void clear() { synchronized(mutex) { c.clear(); } }
+		@Override
+		public Object[] toArray() { synchronized(mutex) { return c.toArray(); } }
+		@Override
+		public  E[] toArray(E[] a) { synchronized(mutex) { return c.toArray(a); } }
+		@Override
+		public void forEach(Consumer action) { synchronized(mutex) { c.forEach(action); } }
+		@Override
+		public void forEachIndexed(IntObjectConsumer action) { synchronized(mutex) { c.forEachIndexed(action); } }
+		@Override
+		public int hashCode() { synchronized(mutex) { return c.hashCode(); } }
+		@Override
+		public boolean equals(Object obj) {
+			if(obj == this) return true;
+			synchronized(mutex) { return c.equals(obj); } 
+		}
+		@Override
+		public String toString() { synchronized(mutex) { return c.toString(); } }
+		@Override
+		public  void forEach(E input, ObjectObjectConsumer action) { synchronized(mutex) { c.forEach(input, action); } }
+		@Override
+		public boolean matchesAny(Predicate filter) { synchronized(mutex) { return c.matchesAny(filter); } }
+		@Override
+		public boolean matchesNone(Predicate filter) { synchronized(mutex) { return c.matchesNone(filter); } }
+		@Override
+		public boolean matchesAll(Predicate filter) { synchronized(mutex) { return c.matchesAll(filter); } }
+		public  E reduce(E identity, BiFunction operator) { synchronized(mutex) { return c.reduce(identity, operator); } }
+		@Override
+		public T reduce(ObjectObjectUnaryOperator operator) { synchronized(mutex) { return c.reduce(operator); } }
+		@Override
+		public T findFirst(Predicate filter) { synchronized(mutex) { return c.findFirst(filter); } }
+		@Override
+		public int count(Predicate filter) { synchronized(mutex) { return c.count(filter); } }
+	}
+	
+	/**
+	 * Unmodifyable Collection Wrapper for the unmodifyableCollection method
+	 * @param  the keyType of elements maintained by this Collection
+	 */
+	public static class UnmodifiableCollection implements ObjectCollection {
+		ObjectCollection c;
+		
+		UnmodifiableCollection(ObjectCollection c) {
+			this.c = c;
+		}
+		
+		@Override
+		public boolean add(T o) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean addAll(Collection c) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean addAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean addAll(T[] e, int offset, int length) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean contains(Object o) { return c.contains(o); }
+		@Override
+		public boolean containsAll(ObjectCollection c) { return this.c.containsAll(c); }
+		@Override
+		public boolean containsAny(ObjectCollection c) { return this.c.containsAny(c); }
+		@Override
+		public boolean containsAny(Collection c) { return this.c.containsAny(c); }
+		@Override
+		public boolean containsAll(Collection c) { return this.c.containsAll(c); }
+		@Override
+		public int size() { return c.size(); }
+		@Override
+		public boolean isEmpty() { return c.isEmpty(); }
+		@Override
+		public ObjectIterator iterator() { return ObjectIterators.unmodifiable(c.iterator()); }
+		@Override
+		public ObjectCollection copy() { return c.copy(); }
+		@Override
+		@Deprecated
+		public boolean remove(Object o) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean removeAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean removeAll(ObjectCollection c, Consumer r) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean retainAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean retainAll(ObjectCollection c, Consumer r) { throw new UnsupportedOperationException(); }
+		@Override
+		public void clear() { throw new UnsupportedOperationException(); }
+		@Override
+		public Object[] toArray() { return c.toArray(); }
+		@Override
+		public  E[] toArray(E[] a) { return c.toArray(a); }
+		@Override
+		public void forEach(Consumer action) { c.forEach(action); }
+		@Override
+		public void forEachIndexed(IntObjectConsumer action) { c.forEachIndexed(action); }
+		@Override
+		public int hashCode() { return c.hashCode(); }
+		@Override
+		public boolean equals(Object obj) { return obj == this || c.equals(obj); }
+		@Override
+		public String toString() { return c.toString(); }
+		@Override
+		public  void forEach(E input, ObjectObjectConsumer action) { c.forEach(input, action); }
+		@Override
+		public boolean matchesAny(Predicate filter) { return c.matchesAny(filter); }
+		@Override
+		public boolean matchesNone(Predicate filter) { return c.matchesNone(filter); }
+		@Override
+		public boolean matchesAll(Predicate filter) { return c.matchesAll(filter); }
+		public  E reduce(E identity, BiFunction operator) { return c.reduce(identity, operator); }
+		@Override
+		public T reduce(ObjectObjectUnaryOperator operator) { return c.reduce(operator); }
+		@Override
+		public T findFirst(Predicate filter) { return c.findFirst(filter); }
+		@Override
+		public int count(Predicate filter) { return c.count(filter); }
+	}
+	
+	/**
+	 * Empty Collection implementation for the empty collection function
+	 * @param  the keyType of elements maintained by this Collection
+	 */
+	public static class EmptyCollection extends AbstractObjectCollection {
+		@Override
+		public boolean add(T o) { throw new UnsupportedOperationException(); }
+		
+		@Override
+		public boolean addAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean addAll(T[] e, int offset, int length) { throw new UnsupportedOperationException(); }
+		
+		@Override
+		public boolean contains(Object o) { return false; }
+		@Override
+		public boolean containsAny(Collection c) { return false; }
+		@Override
+		public boolean containsAll(Collection c) { return c.isEmpty(); }
+		@Override
+		public int hashCode() { return 0; }
+		
+		@Override
+		public boolean equals(Object o) {
+			if(o == this) return true;
+		  	if(!(o instanceof Collection)) return false;
+		  	return ((Collection)o).isEmpty();
+		}
+		
+		@Override
+		@Deprecated
+		public boolean remove(Object o) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean removeAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
+		@Override
+		public boolean retainAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
+		@Override
+		public Object[] toArray() { return ObjectArrays.EMPTY_ARRAY; }
+		@Override
+		public  E[] toArray(E[] a) {
+			if(a != null && a.length > 0)
+				a[0] = null;
+			return a;
+		}
+		@Override
+		public ObjectIterator iterator() { return ObjectIterators.empty(); }
+		@Override
+		public void clear() {}
+		@Override
+		public int size() { return 0; }
+		@Override
+		public EmptyCollection copy() { return this; }
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/utils/ObjectIterables.java b/src/main/java/speiger/src/collections/objects/utils/ObjectIterables.java
new file mode 100644
index 000000000..374376ec7
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/utils/ObjectIterables.java
@@ -0,0 +1,496 @@
+package speiger.src.collections.objects.utils;
+
+import java.util.Objects;
+import java.util.Comparator;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+import speiger.src.collections.objects.collections.ObjectIterable;
+import speiger.src.collections.objects.collections.ObjectCollection;
+import speiger.src.collections.objects.collections.ObjectIterator;
+import speiger.src.collections.objects.functions.function.UnaryOperator;
+import speiger.src.collections.utils.ISizeProvider;
+
+/**
+ * A Helper class for Iterables
+ */
+public class ObjectIterables
+{
+	/**
+	 * A Helper function that maps a Java-Iterable into a new Type.
+	 * @param iterable the iterable that should be mapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type.
+	 * @return a iterable that is mapped to a new result
+	 */
+	public static  ObjectIterable map(Iterable iterable, UnaryOperator mapper) {
+		return new MappedIterable<>(wrap(iterable), mapper);
+	}
+	
+	/**
+	 * A Helper function that maps a Iterable into a new Type.
+	 * @param iterable the iterable that should be mapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type.
+	 * @return a iterable that is mapped to a new result
+	 */
+	public static  ObjectIterable map(ObjectIterable iterable, UnaryOperator mapper) {
+		return new MappedIterable<>(iterable, mapper);
+	}
+	
+	/**
+	 * A Helper function that flatMaps a Java-Iterable into a new Type.
+	 * @param iterable the iterable that should be flatMapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type supplier.
+	 * @param  The return type.
+	 * @return a iterable that is flatMapped to a new result
+	 */
+	public static > ObjectIterable flatMap(Iterable iterable, UnaryOperator mapper) {
+		return new FlatMappedIterable<>(wrap(iterable), mapper);
+	}
+	
+	/**
+	 * A Helper function that flatMaps a Iterable into a new Type.
+	 * @param iterable the iterable that should be flatMapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type supplier.
+	 * @param  The return type.
+	 * @return a iterable that is flatMapped to a new result
+	 */
+	public static > ObjectIterable flatMap(ObjectIterable iterable, UnaryOperator mapper) {
+		return new FlatMappedIterable<>(iterable, mapper);
+	}
+	
+	/**
+	 * A Helper function that flatMaps a Java-Iterable into a new Type.
+	 * @param iterable the iterable that should be flatMapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type.
+	 * @return a iterable that is flatMapped to a new result
+	 */
+	public static  ObjectIterable arrayFlatMap(Iterable iterable, UnaryOperator mapper) {
+		return new FlatMappedArrayIterable<>(wrap(iterable), mapper);
+	}
+	
+	/**
+	 * A Helper function that flatMaps a Iterable into a new Type.
+	 * @param iterable the iterable that should be flatMapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type.
+	 * @return a iterable that is flatMapped to a new result
+	 */
+	public static  ObjectIterable arrayFlatMap(ObjectIterable iterable, UnaryOperator mapper) {
+		return new FlatMappedArrayIterable<>(iterable, mapper);
+	}
+	
+	/**
+	 * A Helper function that filters out all desired elements from a Java-Iterable
+	 * @param iterable that should be filtered.
+	 * @param filter the filter that decides that should be let through
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a filtered iterable
+	 */
+	public static  ObjectIterable filter(Iterable iterable, Predicate filter) {
+		return new FilteredIterable<>(wrap(iterable), filter);
+	}
+	
+	/**
+	 * A Helper function that filters out all desired elements
+	 * @param iterable that should be filtered.
+	 * @param filter the filter that decides that should be let through
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a filtered iterable
+	 */
+	public static  ObjectIterable filter(ObjectIterable iterable, Predicate filter) {
+		return new FilteredIterable<>(iterable, filter);
+	}
+	
+	/**
+	 * A Helper function that filters out all duplicated elements.
+	 * @param iterable that should be distinct
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a distinct iterable
+	 */
+	public static  ObjectIterable distinct(ObjectIterable iterable) {
+		return new DistinctIterable<>(iterable);
+	}
+	
+	/**
+	 * A Helper function that filters out all duplicated elements from a Java Iterable.
+	 * @param iterable that should be distinct
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a distinct iterable
+	 */
+	public static  ObjectIterable distinct(Iterable iterable) {
+		return new DistinctIterable<>(wrap(iterable));
+	}
+	
+	/**
+	 * A Helper function that repeats the Iterable a specific amount of times
+	 * @param iterable that should be repeated
+	 * @param repeats the amount of times the iterable should be repeated
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a repeating iterable
+	 */
+	public static  ObjectIterable repeat(ObjectIterable iterable, int repeats) {
+		return new RepeatingIterable<>(iterable, repeats);
+	}
+	
+	/**
+	 * A Helper function that repeats the Iterable a specific amount of times from a Java Iterable
+	 * @param iterable that should be repeated
+	 * @param repeats the amount of times the iterable should be repeated
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a repeating iterable
+	 */
+	public static  ObjectIterable repeat(Iterable iterable, int repeats) {
+		return new RepeatingIterable<>(wrap(iterable), repeats);
+	}
+	
+	/**
+	 * A Helper function that hard limits the Iterable to a specific size
+	 * @param iterable that should be limited
+	 * @param limit the amount of elements it should be limited to
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a limited iterable
+	 */
+	public static  ObjectIterable limit(ObjectIterable iterable, long limit) {
+		return new LimitedIterable<>(iterable, limit);
+	}
+	
+	/**
+	 * A Helper function that hard limits the Iterable to a specific size from a Java Iterable
+	 * @param iterable that should be limited
+	 * @param limit the amount of elements it should be limited to
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a limited iterable
+	 */
+	public static  ObjectIterable limit(Iterable iterable, long limit) {
+		return new LimitedIterable<>(wrap(iterable), limit);
+	}
+	
+	/**
+	 * A Helper function that sorts the Iterable.
+	 * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it.
+	 * @param iterable that should be sorted
+	 * @param sorter that sorts the iterable. Can be null.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a sorted iterable.
+	 */
+	public static  ObjectIterable sorted(ObjectIterable iterable, Comparator sorter) {
+		return new SortedIterable<>(iterable, sorter);
+	}
+	
+	/**
+	 * A Helper function that sorts the Iterable from a Java Iterable
+	 * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it.
+	 * @param iterable that should be sorted
+	 * @param sorter that sorts the iterable. Can be null.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a sorted iterable.
+	 */
+	public static  ObjectIterable sorted(Iterable iterable, Comparator sorter) {
+		return new SortedIterable<>(wrap(iterable), sorter);
+	}
+	
+	/**
+	 * A Helper function that allows to preview the result of a Iterable.
+	 * @param iterable that should be peeked at
+	 * @param action callback that receives the value before the iterable returns it
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a peeked iterable
+	 */
+	public static  ObjectIterable peek(ObjectIterable iterable, Consumer action) {
+		return new PeekIterable<>(iterable, action);
+	}
+	
+	/**
+	 * A Helper function that allows to preview the result of a Iterable from a Java Iterable
+	 * @param iterable that should be peeked at
+	 * @param action callback that receives the value before the iterable returns it
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a peeked iterable
+	 */
+	public static  ObjectIterable peek(Iterable iterable, Consumer action) {
+		return new PeekIterable<>(wrap(iterable), action);
+	}
+	
+	/**
+	 * A Wrapper function that wraps a Java-Iterable into a Type Specific Iterable
+	 * @param iterable that should be wrapped
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a type specific iterable
+	 */
+	public static  ObjectIterable wrap(Iterable iterable) {
+		return new WrappedIterable<>(iterable);
+	}
+	
+	private static class WrappedIterable implements ObjectIterable, ISizeProvider
+	{
+		Iterable iterable;
+		
+		public WrappedIterable(Iterable iterable) {
+			this.iterable = iterable;
+		}
+		
+		public ObjectIterator iterator() {
+			return ObjectIterators.wrap(iterable.iterator());
+		}
+		
+		@Override
+		public int size() {
+			ISizeProvider prov = ISizeProvider.of(iterable);
+			return prov == null ? -1 : prov.size();
+		}
+		
+		public void forEach(Consumer action) {
+			Objects.requireNonNull(action);
+			iterable.forEach(action);
+		}
+	}
+	
+	private static class MappedIterable implements ObjectIterable, ISizeProvider
+	{
+		ObjectIterable iterable;
+		UnaryOperator mapper;
+		
+		MappedIterable(ObjectIterable iterable, UnaryOperator mapper) {
+			this.iterable = iterable;
+			this.mapper = mapper;
+		}
+		
+		public ObjectIterator iterator() {
+			return ObjectIterators.map(iterable.iterator(), mapper);
+		}
+		
+		@Override
+		public int size() {
+			ISizeProvider prov = ISizeProvider.of(this);
+			return prov == null ? -1 : prov.size();
+		}
+		
+		@Override
+		public void forEach(Consumer action) {
+			Objects.requireNonNull(action);
+			iterable.forEach(E -> action.accept(mapper.apply(E)));
+		}
+	}
+	
+	private static class FlatMappedIterable> implements ObjectIterable
+	{
+		ObjectIterable iterable;
+		UnaryOperator mapper;
+		
+		FlatMappedIterable(ObjectIterable iterable, UnaryOperator mapper) {
+			this.iterable = iterable;
+			this.mapper = mapper;
+		}
+		
+		@Override
+		public ObjectIterator iterator() {
+			return ObjectIterators.flatMap(iterable.iterator(), mapper);
+		}
+		
+		@Override
+		public void forEach(Consumer action) {
+			Objects.requireNonNull(action);
+			iterable.forEach(E -> mapper.apply(E).forEach(action));
+		}
+		
+	}
+	
+	private static class FlatMappedArrayIterable implements ObjectIterable
+	{
+		ObjectIterable iterable;
+		UnaryOperator mapper;
+		
+		FlatMappedArrayIterable(ObjectIterable iterable, UnaryOperator mapper) {
+			this.iterable = iterable;
+			this.mapper = mapper;
+		}
+		
+		@Override
+		public ObjectIterator iterator() {
+			return ObjectIterators.arrayFlatMap(iterable.iterator(), mapper);
+		}
+		
+		@Override
+		public void forEach(Consumer action) {
+			Objects.requireNonNull(action);
+			iterable.forEach(E -> {
+				T[] array = mapper.apply(E);
+				for(int i = 0,m=array.length;i implements ObjectIterable, ISizeProvider
+	{
+		ObjectIterable iterable;
+		int repeats;
+		
+		public RepeatingIterable(ObjectIterable iterable, int repeats) {
+			this.iterable = iterable;
+			this.repeats = repeats;
+		}
+		
+		@Override
+		public ObjectIterator iterator() {
+			return ObjectIterators.repeat(iterable.iterator(), repeats);
+		}
+		
+		@Override
+		public int size() {
+			ISizeProvider prov = ISizeProvider.of(iterable);
+			return prov == null ? -1 : prov.size() * (repeats+1);
+		}
+		
+		@Override
+		public void forEach(Consumer action) {
+			Objects.requireNonNull(action);
+			ObjectCollection repeater = ObjectCollections.wrapper();
+			iterable.forEach(T -> {action.accept(T); repeater.add(T);});
+			for(int i = 0;i implements ObjectIterable
+	{
+		ObjectIterable iterable;
+		Predicate filter;
+		
+		public FilteredIterable(ObjectIterable iterable, Predicate filter) {
+			this.iterable = iterable;
+			this.filter = filter;
+		}
+		
+		@Override
+		public ObjectIterator iterator() {
+			return ObjectIterators.filter(iterable.iterator(), filter);
+		}
+		
+		public void forEach(Consumer action) {
+			Objects.requireNonNull(action);
+			iterable.forEach(T -> { if(!filter.test(T)) action.accept(T); } );
+		}
+	}
+	
+	private static class LimitedIterable implements ObjectIterable, ISizeProvider
+	{
+		ObjectIterable iterable;
+		long limit;
+		
+		public LimitedIterable(ObjectIterable iterable, long limit) {
+			this.iterable = iterable;
+			this.limit = limit;
+		}
+		
+		@Override
+		public ObjectIterator iterator() {
+			return ObjectIterators.limit(iterable.iterator(), limit);
+		}
+		
+		@Override
+		public int size() {
+			ISizeProvider prov = ISizeProvider.of(iterable);
+			return prov == null ? -1 : (int)Math.min(prov.size(), limit);
+		}
+		
+		public void forEach(Consumer action) {
+			Objects.requireNonNull(action);
+			AtomicLong counter = new AtomicLong();
+			iterable.forEach(T -> {
+				if(counter.get() >= limit) return;
+				counter.incrementAndGet();
+				action.accept(T);
+			});
+		}
+	}
+	
+	private static class SortedIterable implements ObjectIterable, ISizeProvider
+	{
+		ObjectIterable iterable;
+		Comparator sorter;
+		
+		public SortedIterable(ObjectIterable iterable, Comparator sorter) {
+			this.iterable = iterable;
+			this.sorter = sorter;
+		}
+		
+		@Override
+		public ObjectIterator iterator() {
+			return ObjectIterators.sorted(iterable.iterator(), sorter);
+		}
+		
+		@Override
+		public int size() {
+			ISizeProvider prov = ISizeProvider.of(iterable);
+			return prov == null ? -1 : prov.size();
+		}
+		
+		@Override
+		public void forEach(Consumer action) {
+			Objects.requireNonNull(action);
+			ObjectCollections.CollectionWrapper wrapper = ObjectCollections.wrapper();
+			iterable.forEach(wrapper::add);
+			wrapper.unstableSort(sorter);
+			wrapper.forEach(action);
+		}
+	}
+	
+	private static class DistinctIterable implements ObjectIterable
+	{
+		ObjectIterable iterable;
+		
+		public DistinctIterable(ObjectIterable iterable) {
+			this.iterable = iterable;
+		}
+		
+		@Override
+		public ObjectIterator iterator() {
+			return ObjectIterators.distinct(iterable.iterator());
+		}
+		
+		public void forEach(Consumer action) {
+			Objects.requireNonNull(action);
+			ObjectCollection filtered = ObjectCollections.distinctWrapper();
+			iterable.forEach(T -> { if(filtered.add(T)) action.accept(T); });
+		}
+	}
+	
+	private static class PeekIterable implements ObjectIterable, ISizeProvider
+	{
+		ObjectIterable iterable;
+		Consumer action;
+		
+		public PeekIterable(ObjectIterable iterable, Consumer action) {
+			this.iterable = iterable;
+			this.action = action;
+		}
+		
+		@Override
+		public ObjectIterator iterator() {
+			return ObjectIterators.peek(iterable.iterator(), action);
+		}
+		
+		@Override
+		public int size() {
+			ISizeProvider prov = ISizeProvider.of(iterable);
+			return prov == null ? -1 : prov.size();
+		}
+		
+		public void forEach(Consumer action) {
+			Objects.requireNonNull(action);
+			iterable.forEach(this.action.andThen(action));
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/utils/ObjectIterators.java b/src/main/java/speiger/src/collections/objects/utils/ObjectIterators.java
new file mode 100644
index 000000000..4c71ec876
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/utils/ObjectIterators.java
@@ -0,0 +1,1019 @@
+package speiger.src.collections.objects.utils;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Comparator;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+import speiger.src.collections.objects.collections.ObjectIterator;
+import speiger.src.collections.objects.functions.function.UnaryOperator;
+import speiger.src.collections.objects.lists.ObjectList;
+import speiger.src.collections.objects.lists.ObjectArrayList;
+
+import speiger.src.collections.objects.lists.ObjectListIterator;
+import speiger.src.collections.objects.collections.ObjectBidirectionalIterator;
+import speiger.src.collections.objects.collections.ObjectCollection;
+
+/**
+ * A Helper class for Iterators
+ */
+public class ObjectIterators
+{
+	/**
+	 * Empty Iterator Reference
+	 */
+	private static final EmptyIterator EMPTY = new EmptyIterator<>();
+	
+	/**
+	 * Returns a Immutable EmptyIterator instance that is automatically casted.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return an empty iterator
+	 */
+	public static  EmptyIterator empty() {
+		return (EmptyIterator)EMPTY;
+	}
+	
+	/**
+	 * Inverter function for Bidirectional Iterators
+	 * @param it the iterator that should be inverted
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a Inverted Bidirectional Iterator. If it was inverted then it just gives back the original reference
+	 */
+	public static  ObjectBidirectionalIterator invert(ObjectBidirectionalIterator it) {
+		return it instanceof ReverseBiIterator ? ((ReverseBiIterator)it).it : new ReverseBiIterator<>(it);
+	}
+	
+	/**
+	 * Inverter function for List Iterators
+	 * @param it the iterator that should be inverted
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a Inverted List Iterator. If it was inverted then it just gives back the original reference
+	 */
+	public static  ObjectListIterator invert(ObjectListIterator it) {
+		return it instanceof ReverseListIterator ? ((ReverseListIterator)it).it : new ReverseListIterator<>(it);
+	}
+	
+	/**
+	 * Returns a Immutable Iterator instance based on the instance given.
+	 * @param iterator that should be made immutable/unmodifiable
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself.
+	 */
+	public static  ObjectIterator unmodifiable(ObjectIterator iterator) {
+		return iterator instanceof UnmodifiableIterator ? iterator : new UnmodifiableIterator<>(iterator);
+	}
+	
+	/**
+	 * Returns a Immutable Iterator instance based on the instance given.
+	 * @param iterator that should be made immutable/unmodifiable
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself.
+	 */
+	public static  ObjectBidirectionalIterator unmodifiable(ObjectBidirectionalIterator iterator) {
+		return iterator instanceof UnmodifiableBiIterator ? iterator : new UnmodifiableBiIterator<>(iterator);
+	}
+	
+	/**
+	 * Returns a Immutable ListIterator instance based on the instance given.
+	 * @param iterator that should be made immutable/unmodifiable
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a unmodifiable listiterator wrapper. If the ListIterator already a unmodifiable wrapper then it just returns itself.
+	 */
+	public static  ObjectListIterator unmodifiable(ObjectListIterator iterator) {
+		return iterator instanceof UnmodifiableListIterator ? iterator : new UnmodifiableListIterator<>(iterator);
+	}
+	
+	/**
+	 * A Helper function that maps a Java-Iterator into a new Type.
+	 * @param iterator that should be mapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type.
+	 * @return a iterator that is mapped to a new result
+	 */
+	public static  ObjectIterator map(Iterator iterator, UnaryOperator mapper) {
+		return new MappedIterator<>(wrap(iterator), mapper);
+	}
+	
+	/**
+	 * A Helper function that maps a Iterator into a new Type.
+	 * @param iterator that should be mapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type.
+	 * @return a iterator that is mapped to a new result
+	 */
+	public static  ObjectIterator map(ObjectIterator iterator, UnaryOperator mapper) {
+		return new MappedIterator<>(iterator, mapper);
+	}
+	
+	/**
+	 * A Helper function that flatMaps a Java-Iterator into a new Type.
+	 * @param iterator that should be flatMapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type supplier.
+	 * @param  The return type.
+	 * @return a iterator that is flatMapped to a new result
+	 */
+	public static > ObjectIterator flatMap(Iterator iterator, UnaryOperator mapper) {
+		return new FlatMappedIterator<>(wrap(iterator), mapper);
+	}
+	
+	/**
+	 * A Helper function that flatMaps a Iterator into a new Type.
+	 * @param iterator that should be flatMapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type supplier.
+	 * @param  The return type.
+	 * @return a iterator that is flatMapped to a new result
+	 */
+	public static > ObjectIterator flatMap(ObjectIterator iterator, UnaryOperator mapper) {
+		return new FlatMappedIterator<>(iterator, mapper);
+	}
+	
+	/**
+	 * A Helper function that flatMaps a Java-Iterator into a new Type.
+	 * @param iterator that should be flatMapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type.
+	 * @return a iterator that is flatMapped to a new result
+	 */
+	public static  ObjectIterator arrayFlatMap(Iterator iterator, UnaryOperator mapper) {
+		return new FlatMappedArrayIterator<>(wrap(iterator), mapper);
+	}
+	
+	/**
+	 * A Helper function that flatMaps a Iterator into a new Type.
+	 * @param iterator that should be flatMapped
+	 * @param mapper the function that decides what the result turns into.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @param  The return type.
+	 * @return a iterator that is flatMapped to a new result
+	 */
+	public static  ObjectIterator arrayFlatMap(ObjectIterator iterator, UnaryOperator mapper) {
+		return new FlatMappedArrayIterator<>(iterator, mapper);
+	}
+	
+	/**
+	 * A Helper function that filters out all desired elements from a Java-Iterator
+	 * @param iterator that should be filtered.
+	 * @param filter the filter that decides that should be let through
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a filtered iterator
+	 */
+	public static  ObjectIterator filter(Iterator iterator, Predicate filter) {
+		return new FilteredIterator<>(wrap(iterator), filter);
+	}
+	
+	/**
+	 * A Helper function that filters out all desired elements
+	 * @param iterator that should be filtered.
+	 * @param filter the filter that decides that should be let through
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a filtered iterator
+	 */
+	public static  ObjectIterator filter(ObjectIterator iterator, Predicate filter) {
+		return new FilteredIterator<>(iterator, filter);
+	}
+	
+	/**
+	 * A Helper function that filters out all duplicated elements.
+	 * @param iterator that should be distinct
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a distinct iterator
+	 */
+	public static  ObjectIterator distinct(ObjectIterator iterator) {
+		return new DistinctIterator<>(iterator);
+	}
+	
+	/**
+	 * A Helper function that filters out all duplicated elements from a Java Iterator.
+	 * @param iterator that should be distinct
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a distinct iterator
+	 */
+	public static  ObjectIterator distinct(Iterator iterator) {
+		return new DistinctIterator<>(wrap(iterator));
+	}
+	
+	/**
+	 * A Helper function that repeats the Iterator a specific amount of times
+	 * @param iterator that should be repeated
+	 * @param repeats the amount of times the iterator should be repeated
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a repeating iterator
+	 */
+	public static  ObjectIterator repeat(ObjectIterator iterator, int repeats) {
+		return new RepeatingIterator<>(iterator, repeats);
+	}
+	
+	/**
+	 * A Helper function that repeats the Iterator a specific amount of times from a Java Iterator
+	 * @param iterator that should be repeated
+	 * @param repeats the amount of times the iterator should be repeated
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a repeating iterator
+	 */
+	public static  ObjectIterator repeat(Iterator iterator, int repeats) {
+		return new RepeatingIterator<>(wrap(iterator), repeats);
+	}
+	
+	/**
+	 * A Helper function that hard limits the Iterator to a specific size
+	 * @param iterator that should be limited
+	 * @param limit the amount of elements it should be limited to
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a limited iterator
+	 */
+	public static  ObjectIterator limit(ObjectIterator iterator, long limit) {
+		return new LimitedIterator<>(iterator, limit);
+	}
+	
+	/**
+	 * A Helper function that hard limits the Iterator to a specific size from a Java Iterator
+	 * @param iterator that should be limited
+	 * @param limit the amount of elements it should be limited to
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a limited iterator
+	 */
+	public static  ObjectIterator limit(Iterator iterator, long limit) {
+		return new LimitedIterator<>(wrap(iterator), limit);
+	}
+	
+	/**
+	 * A Helper function that sorts the Iterator beforehand.
+	 * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it.
+	 * @param iterator that should be sorted.
+	 * @param sorter the sorter of the iterator. Can be null.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a new sorted iterator
+	 */
+	public static  ObjectIterator sorted(ObjectIterator iterator, Comparator sorter) {
+		return new SortedIterator<>(iterator, sorter);
+	}
+	
+	/**
+	 * A Helper function that sorts the Iterator beforehand from a Java Iterator.
+	 * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it.
+	 * @param iterator that should be sorted.
+	 * @param sorter the sorter of the iterator. Can be null.
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a new sorted iterator
+	 */
+	public static  ObjectIterator sorted(Iterator iterator, Comparator sorter) {
+		return new SortedIterator<>(wrap(iterator), sorter);
+	}
+	
+	/**
+	 * A Helper function that allows to preview the result of a Iterator.
+	 * @param iterator that should be peeked at
+	 * @param action callback that receives the value before the iterator returns it
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a peeked iterator
+	 */
+	public static  ObjectIterator peek(ObjectIterator iterator, Consumer action) {
+		return new PeekIterator<>(iterator, action);
+	}
+	
+	/**
+	 * A Helper function that allows to preview the result of a Iterator  from a Java Iterator
+	 * @param iterator that should be peeked at
+	 * @param action callback that receives the value before the iterator returns it
+	 * @param  the keyType of elements maintained by this Collection
+	 * @return a peeked iterator
+	 */
+	public static  ObjectIterator peek(Iterator iterator, Consumer action) {
+		return new PeekIterator<>(wrap(iterator), action);
+	}
+	
+	/**
+	 * Helper function to convert a Object Iterator into a Primitive Iterator
+	 * @param iterator that should be converted to a unboxing iterator
+	 * @param  the keyType of array that the operation should be applied
+	 * @return a primitive iterator
+	 */
+	public static  ObjectIterator wrap(Iterator iterator) {
+		return iterator instanceof ObjectIterator ? (ObjectIterator)iterator : new IteratorWrapper<>(iterator);
+	}
+	
+	/**
+	 * Returns a Array Wrapping iterator
+	 * @param a the array that should be wrapped
+	 * @param  the keyType of array that the operation should be applied
+	 * @return a Iterator that is wrapping a array.
+	 */
+	public static  ArrayIterator wrap(T... a) {
+		return wrap(a, 0, a.length);
+	}
+	
+	/**
+	 * Returns a Array Wrapping iterator
+	 * @param a the array that should be wrapped.
+	 * @param start the index to be started from.
+	 * @param end the index that should be ended.
+	 * @param  the keyType of array that the operation should be applied
+	 * @return a Iterator that is wrapping a array.
+	 */
+	public static  ArrayIterator wrap(T[] a, int start, int end) {
+		return new ArrayIterator<>(a, start, end);
+	}
+	
+	/**
+	 * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted
+	 * @param a where the elements should be inserted
+	 * @param i the source iterator
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the amount of elements that were inserted into the array.
+	 */
+	public static  int unwrap(T[] a, Iterator i) {
+		return unwrap(a, i, 0, a.length);
+	}
+	
+	/**
+	 * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted
+	 * @param a where the elements should be inserted
+	 * @param i the source iterator
+	 * @param offset the array offset where the start should be
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the amount of elements that were inserted into the array.
+	 */
+	public static  int unwrap(T[] a, Iterator i, int offset) {
+		return unwrap(a, i, offset, a.length - offset);
+	}
+	
+	/**
+	 * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted
+	 * @param a where the elements should be inserted
+	 * @param i the source iterator
+	 * @param offset the array offset where the start should be
+	 * @param max the maximum values that should be extracted from the source
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the amount of elements that were inserted into the array.
+	 * @throws IllegalStateException if max is smaller the 0 or if the maximum index is larger then the array
+	 */
+	public static  int unwrap(T[] a, Iterator i, int offset, int max) {
+		if(max < 0) throw new IllegalStateException("The max size is smaller then 0");
+		if(offset + max > a.length) throw new IllegalStateException("largest array index exceeds array size");
+		int index = 0;
+		for(;index the keyType of array that the operation should be applied
+	 * @return the amount of elements that were inserted into the array.
+	 */
+	public static  int unwrap(T[] a, ObjectIterator i) {
+		return unwrap(a, i, 0, a.length);
+	}
+	
+	/**
+	 * A Primitive iterator variant of the ObjectIterators unwrap function
+	 * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted
+	 * @param a where the elements should be inserted
+	 * @param i the source iterator
+	 * @param offset the array offset where the start should be
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the amount of elements that were inserted into the array.
+	 */
+	public static  int unwrap(T[] a, ObjectIterator i, int offset) {
+		return unwrap(a, i, offset, a.length - offset);
+	}
+	
+	/**
+	 * A Primitive iterator variant of the ObjectIterators unwrap function
+	 * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted
+	 * @param a where the elements should be inserted
+	 * @param i the source iterator
+	 * @param offset the array offset where the start should be
+	 * @param max the maximum values that should be extracted from the source
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the amount of elements that were inserted into the array.
+	 * @throws IllegalStateException if max is smaller the 0 or if the maximum index is larger then the array
+	 */
+	public static  int unwrap(T[] a, ObjectIterator i, int offset, int max) {
+		if(max < 0) throw new IllegalStateException("The max size is smaller then 0");
+		if(offset + max > a.length) throw new IllegalStateException("largest array index exceeds array size");
+		int index = 0;
+		for(;index the keyType of array that the operation should be applied
+	 * @return A list of all elements of the Iterator
+	 */
+	public static  ObjectList pour(ObjectIterator iter) {
+		return pour(iter, Integer.MAX_VALUE);
+	}
+	
+	/**
+	 * A Helper function to pours all elements of a Iterator into a List
+	 * @param iter the elements that should be poured into list.
+	 * @param max the maximum amount of elements that should be collected
+	 * @param  the keyType of array that the operation should be applied
+	 * @return A list of all requested elements of the Iterator
+	 */
+	public static  ObjectList pour(ObjectIterator iter, int max) {
+		ObjectArrayList list = new ObjectArrayList<>();
+		pour(iter, list, max);
+		list.trim();
+		return list;
+	}
+	
+	/**
+	 * A Helper function to pours all elements of a Iterator into a Collection
+	 * @param iter the elements that should be poured into list.
+	 * @param c the collection where the elements should be poured into
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the amount of elements that were added
+	 */
+	public static  int pour(ObjectIterator iter, ObjectCollection c) {
+		return pour(iter, c, Integer.MAX_VALUE);
+	}
+	
+	/**
+	 * A Helper function to pours all elements of a Iterator into a Collection
+	 * @param iter the elements that should be poured into list.
+	 * @param c the collection where the elements should be poured into
+	 * @param max the maximum amount of elements that should be collected
+	 * @param  the keyType of array that the operation should be applied
+	 * @return the amount of elements that were added
+	 */
+	public static  int pour(ObjectIterator iter, ObjectCollection c, int max) {
+		if(max < 0) throw new IllegalStateException("Max is negative");
+		int done = 0;
+		for(;done the keyType of array that the operation should be applied
+	 * @return iterator of the inputted iterators
+	 */
+	public static  ObjectIterator concat(ObjectIterator... array) {
+		return concat(array, 0, array.length);
+	}
+	
+	/**
+	 * Helper Iterator that concats other iterators together
+	 * @param array the Iterators that should be concatenated
+	 * @param offset where to start within the array
+	 * @param length the length of the array
+	 * @param  the keyType of array that the operation should be applied
+	 * @return iterator of the inputted iterators
+	 */
+	public static  ObjectIterator concat(ObjectIterator[] array, int offset, int length) {
+		return new ConcatIterator<>(array, offset, length);
+	}
+	
+	private static class IteratorWrapper implements ObjectIterator
+	{
+		Iterator iter;
+		
+		public IteratorWrapper(Iterator iter) {
+			this.iter = iter;
+		}
+		
+		@Override
+		public boolean hasNext() {
+			return iter.hasNext();
+		}
+		
+		@Override
+		public T next() {
+			return iter.next();
+		}
+		
+	}
+	
+	private static class ConcatIterator implements ObjectIterator
+	{
+		ObjectIterator[] iters;
+		int offset;
+		int lastOffset = -1;
+		int length;
+		
+		public ConcatIterator(ObjectIterator[] iters, int offset, int length) {
+			this.iters = iters;
+			this.offset = offset;
+			this.length = length;
+			find();
+		}
+		
+		private void find() {
+			for(;length != 0 && !iters[offset].hasNext();length--, offset++);
+		}
+		
+		@Override
+		public boolean hasNext() {
+			return length > 0;
+		}
+		
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			T result = iters[lastOffset = offset].next();
+			find();
+			return result;
+		}
+		
+		@Override
+		public void remove() {
+			if(lastOffset == -1) throw new IllegalStateException();
+			iters[lastOffset].remove();
+			lastOffset = -1;
+		}
+	}
+	
+	private static class ReverseBiIterator implements ObjectBidirectionalIterator {
+		ObjectBidirectionalIterator it;
+		
+		ReverseBiIterator(ObjectBidirectionalIterator it) {
+			this.it = it;
+		}
+		
+		@Override
+		public T next() { return it.previous(); }
+		@Override
+		public boolean hasNext() { return it.hasPrevious(); }
+		@Override
+		public boolean hasPrevious() { return it.hasNext(); }
+		@Override
+		public T previous() { return it.next(); }
+		@Override
+		public void remove() { it.remove(); }
+	}
+	
+	private static class ReverseListIterator implements ObjectListIterator {
+		ObjectListIterator it;
+		
+		ReverseListIterator(ObjectListIterator it) {
+			this.it = it;
+		}
+	
+		@Override
+		public T next() { return it.previous(); }
+		@Override
+		public boolean hasNext() { return it.hasPrevious(); }
+		@Override
+		public boolean hasPrevious() { return it.hasNext(); }
+		@Override
+		public T previous() { return it.next(); }
+		@Override
+		public void remove() { it.remove(); }
+		@Override
+		public int nextIndex() { return it.previousIndex(); }
+		@Override
+		public int previousIndex() { return it.nextIndex(); }
+		@Override
+		public void set(T e) { it.set(e); }
+		@Override
+		public void add(T e) { it.add(e); }
+	}
+	
+	private static class UnmodifiableListIterator implements ObjectListIterator
+	{
+		ObjectListIterator iter;
+	
+		UnmodifiableListIterator(ObjectListIterator iter) {
+			this.iter = iter;
+		}
+		
+		@Override
+		public boolean hasNext() {
+			return iter.hasNext();
+		}
+		
+		@Override
+		public boolean hasPrevious() {
+			return iter.hasPrevious();
+		}
+		
+		@Override
+		public int nextIndex() {
+			return iter.nextIndex();
+		}
+		
+		@Override
+		public int previousIndex() {
+			return iter.previousIndex();
+		}
+		
+		@Override
+		public void remove() { throw new UnsupportedOperationException(); }
+		
+		@Override
+		public T previous() {
+			return iter.previous();
+		}
+		
+		@Override
+		public T next() {
+			return iter.next();
+		}
+
+		@Override
+		public void set(T e) { throw new UnsupportedOperationException(); }
+		
+		@Override
+		public void add(T e) { throw new UnsupportedOperationException(); }
+	}
+	
+	private static class UnmodifiableBiIterator implements ObjectBidirectionalIterator
+	{
+		ObjectBidirectionalIterator iter;
+		
+		UnmodifiableBiIterator(ObjectBidirectionalIterator iter) {
+			this.iter = iter;
+		}
+		
+		@Override
+		public T next() {
+			return iter.next();
+		}
+		
+		@Override
+		public boolean hasNext() {
+			return iter.hasNext();
+		}
+		
+		@Override
+		public boolean hasPrevious() {
+			return iter.hasPrevious();
+		}
+		
+		@Override
+		public T previous() {
+			return iter.previous();
+		}
+	}
+	
+	private static class UnmodifiableIterator implements ObjectIterator
+	{
+		ObjectIterator iterator;
+	
+		UnmodifiableIterator(ObjectIterator iterator) {
+			this.iterator = iterator;
+		}
+		
+		@Override
+		public boolean hasNext() {
+			return iterator.hasNext();
+		}
+		
+		@Override
+		public T next() {
+			return iterator.next();
+		}
+	}
+	
+	private static class EmptyIterator implements ObjectListIterator
+	{
+		@Override
+		public boolean hasNext() { return false; }
+		@Override
+		public T next() { throw new NoSuchElementException(); }
+		@Override
+		public boolean hasPrevious() { return false; }
+		@Override
+		public T previous() { throw new NoSuchElementException(); }
+		@Override
+		public int nextIndex() { return 0; }
+		@Override
+		public int previousIndex() { return -1; }
+		@Override
+		public void remove() { throw new UnsupportedOperationException(); }
+		@Override
+		public void set(T e) { throw new UnsupportedOperationException(); }
+		@Override
+		public void add(T e) { throw new UnsupportedOperationException(); }
+	}
+	
+	private static class ArrayIterator implements ObjectIterator
+	{
+		T[] a;
+		int from;
+		int to;
+		
+		ArrayIterator(T[] a, int from, int to) {
+			this.a = a;
+			this.from = from;
+			this.to = to;
+		}
+		
+		@Override
+		public boolean hasNext() {
+			return from < to;
+		}
+		
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			return a[from++];
+		}
+		
+		@Override
+		public int skip(int amount) {
+			if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed");
+			int left = Math.min(amount, to - from);
+			from += left;
+			return amount - left;
+		}
+	}
+	
+	private static class MappedIterator implements ObjectIterator
+	{
+		ObjectIterator iterator;
+		UnaryOperator mapper;
+		
+		MappedIterator(ObjectIterator iterator, UnaryOperator mapper) {
+			this.iterator = iterator;
+			this.mapper = mapper;
+		}
+		
+		@Override
+		public boolean hasNext() {
+			return iterator.hasNext();
+		}
+		
+		@Override
+		public T next() {
+			return mapper.apply(iterator.next());
+		}
+		
+		@Override
+		public int skip(int amount) {
+			return iterator.skip(amount);
+		}
+	}
+	
+	private static class FlatMappedIterator> implements ObjectIterator
+	{
+		ObjectIterator iterator;
+		Iterator last = null;
+		UnaryOperator mapper;
+		boolean foundNext = false;
+		
+		FlatMappedIterator(ObjectIterator iterator, UnaryOperator mapper) {
+			this.iterator = iterator;
+			this.mapper = mapper;
+		}
+		
+		void compute() {
+			if(foundNext) return;
+			foundNext = true;
+			while(iterator.hasNext()) {
+				if(last != null && last.hasNext()) return;
+				last = mapper.apply(iterator.next()).iterator();
+			}
+		}
+		
+		@Override
+		public boolean hasNext() {
+			compute();
+			return last != null && last.hasNext();
+		}
+		
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			T result = last.next();
+			foundNext = false;
+			return result;
+		}
+	}
+	
+	private static class FlatMappedArrayIterator implements ObjectIterator
+	{
+		ObjectIterator iterator;
+		Iterator last = null;
+		UnaryOperator mapper;
+		boolean foundNext = false;
+		
+		FlatMappedArrayIterator(ObjectIterator iterator, UnaryOperator mapper) {
+			this.iterator = iterator;
+			this.mapper = mapper;
+		}
+		
+		void compute() {
+			if(foundNext) return;
+			foundNext = true;
+			while(iterator.hasNext()) {
+				if(last != null && last.hasNext()) return;
+				last = ObjectIterators.wrap(mapper.apply(iterator.next()));
+			}
+		}
+		
+		@Override
+		public boolean hasNext() {
+			compute();
+			return last != null && last.hasNext();
+		}
+		
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			T result = last.next();
+			foundNext = false;
+			return result;
+		}
+	}
+	
+	private static class RepeatingIterator implements ObjectIterator
+	{
+		final int repeats;
+		int index = 0;
+		ObjectIterator iter;
+		ObjectCollection repeater = ObjectCollections.wrapper();
+		
+		public RepeatingIterator(ObjectIterator iter, int repeat) {
+			this.iter = iter;
+			this.repeats = repeat;
+		}
+		
+		@Override
+		public boolean hasNext() {
+			if(iter.hasNext()) return true;
+			if(index < repeats) {
+				index++;
+				iter = repeater.iterator();
+				return iter.hasNext();
+			}
+			return false;
+		}
+
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			T value = iter.next();
+			if(index == 0) repeater.add(value);
+			return value;
+		}
+	}
+	
+	private static class SortedIterator implements ObjectIterator
+	{
+		ObjectIterator iterator;
+		Comparator sorter;
+		ObjectCollections.CollectionWrapper sortedElements = null;
+		int index = 0;
+		
+		public SortedIterator(ObjectIterator iterator, Comparator sorter) {
+			this.iterator = iterator;
+			this.sorter = sorter;
+		}
+		
+		@Override
+		public boolean hasNext() {
+			if(sortedElements == null) {
+				boolean hasNext = iterator.hasNext();
+				if(hasNext) {
+					sortedElements = ObjectCollections.wrapper();
+					pour(iterator, sortedElements);
+				}
+				else sortedElements = ObjectCollections.wrapper();
+				if(hasNext) sortedElements.unstableSort(sorter);
+			}
+			return index < sortedElements.size();
+		}
+		
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			return sortedElements.get(index++);
+		}
+	}
+	
+	private static class DistinctIterator implements ObjectIterator
+	{
+		ObjectIterator iterator;
+		ObjectCollection filtered = ObjectCollections.distinctWrapper();
+		T lastFound;
+		boolean foundNext = false;
+		
+		public DistinctIterator(ObjectIterator iterator) {
+			this.iterator = iterator;
+		}
+		
+		void compute() {
+			if(foundNext) return;
+			while(iterator.hasNext()) {
+				lastFound = iterator.next();
+				if(filtered.add(lastFound)) {
+					foundNext = true;
+					break;
+				}
+			}
+		}
+		
+		@Override
+		public boolean hasNext() {
+			compute();
+			return foundNext;
+		}
+		
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			foundNext = false;
+			return lastFound;
+		}
+	}
+	
+	private static class FilteredIterator implements ObjectIterator
+	{
+		ObjectIterator iterator;
+		Predicate filter;
+		T lastFound;
+		boolean foundNext = false;
+		
+		public FilteredIterator(ObjectIterator iterator, Predicate filter) {
+			this.iterator = iterator;
+			this.filter = filter;
+		}
+		
+		void compute() {
+			if(foundNext) return;
+			while(iterator.hasNext()) {
+				lastFound = iterator.next();
+				if(filter.test(lastFound)) {
+					foundNext = true;
+					break;
+				}
+			}
+		}
+		
+		@Override
+		public boolean hasNext() {
+			compute();
+			return foundNext;
+		}
+		
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			foundNext = false;
+			return lastFound;
+		}
+	}
+	
+	private static class LimitedIterator implements ObjectIterator
+	{
+		ObjectIterator iterator;
+		long limit;
+		
+		public LimitedIterator(ObjectIterator iterator, long limit) {
+			this.iterator = iterator;
+			this.limit = limit;
+		}
+		
+		@Override
+		public boolean hasNext() {
+			return limit > 0 && iterator.hasNext();
+		}
+		
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			limit--;
+			return iterator.next();
+		}
+	}
+	
+	private static class PeekIterator implements ObjectIterator
+	{
+		ObjectIterator iterator;
+		Consumer action;
+		
+		public PeekIterator(ObjectIterator iterator, Consumer action) {
+			this.iterator = iterator;
+			this.action = action;
+		}
+		
+		@Override
+		public boolean hasNext() {
+			return iterator.hasNext();
+		}
+		
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			T result = iterator.next();
+			action.accept(result);
+			return result;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/utils/ObjectSplititerators.java b/src/main/java/speiger/src/collections/objects/utils/ObjectSplititerators.java
new file mode 100644
index 000000000..cd12f4940
--- /dev/null
+++ b/src/main/java/speiger/src/collections/objects/utils/ObjectSplititerators.java
@@ -0,0 +1,242 @@
+package speiger.src.collections.objects.utils;
+
+import java.util.Comparator;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+
+import speiger.src.collections.objects.collections.ObjectCollection;
+import speiger.src.collections.objects.collections.ObjectIterator;
+import speiger.src.collections.objects.collections.ObjectSplititerator;
+import speiger.src.collections.utils.SanityChecks;
+
+/**
+ * Helper class that provides SplitIterators for normal and stream usage
+ */
+public class ObjectSplititerators
+{
+	/**
+	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
+	* @param array that should be wrapped into a split iterator
+	* @param characteristics characteristics properties of this spliterator's  source or elements.
+	* @param  the keyType of elements maintained by this Collection
+	* @return a Type Specific SplitIterator
+	*/
+	public static  ObjectSplititerator createArraySplititerator(T[] array, int characteristics) { return createArraySplititerator(array, 0, array.length, characteristics);}
+	/**
+	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
+	* @param array that should be wrapped into a split iterator
+	* @param size the maximum index within the array
+	* @param characteristics characteristics properties of this spliterator's  source or elements.
+	* @param  the keyType of elements maintained by this Collection
+	* @return a Type Specific SplitIterator
+	* @throws IllegalStateException if the size is outside of the array size
+	*/
+	public static  ObjectSplititerator createArraySplititerator(T[] array, int size, int characteristics) { return createArraySplititerator(array, 0, size, characteristics);}
+	/**
+	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
+	* @param array that should be wrapped into a split iterator
+	* @param offset the starting index of the array
+	* @param size the maximum index within the array
+	* @param characteristics characteristics properties of this spliterator's  source or elements.
+	* @param  the keyType of elements maintained by this Collection
+	* @return a Type Specific SplitIterator
+	* @throws IllegalStateException the offset and size are outside of the arrays range
+	*/
+	public static  ObjectSplititerator createArraySplititerator(T[] array, int offset, int size, int characteristics) {
+		SanityChecks.checkArrayCapacity(array.length, offset, size);
+		return new TypeArraySplitIterator<>(array, offset, size, characteristics);
+	}
+	
+	/**
+	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
+	* @param collection the collection that should be wrapped in a split iterator
+	* @param characteristics characteristics properties of this spliterator's  source or elements.
+	* @param  the keyType of elements maintained by this Collection
+	* @return a Type Specific SplitIterator
+	*/
+	public static  ObjectSplititerator createSplititerator(ObjectCollection collection, int characteristics) {
+		return new TypeIteratorSpliterator<>(collection, characteristics);
+	}
+	
+	/**
+	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
+	* @param iterator the Iterator that should be wrapped in a split iterator
+	* @param characteristics characteristics properties of this spliterator's source or elements.
+	* @param  the keyType of elements maintained by this Collection
+	* @return a Type Specific SplitIterator
+	*/
+	public static  ObjectSplititerator createUnknownSplititerator(ObjectIterator iterator, int characteristics) {
+		return new TypeIteratorSpliterator<>(iterator, characteristics);
+	}
+	
+	/**
+	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
+	* @param iterator the collection that should be wrapped in a split iterator
+	* @param size the amount of elements in the iterator
+	* @param characteristics characteristics properties of this spliterator's  source or elements.
+	* @param  the keyType of elements maintained by this Collection
+	* @return a Type Specific SplitIterator
+	*/
+	public static  ObjectSplititerator createSizedSplititerator(ObjectIterator iterator, long size, int characteristics) {
+		return new TypeIteratorSpliterator<>(iterator, size, characteristics);
+	}
+	
+	static class TypeIteratorSpliterator implements ObjectSplititerator {
+		static final int BATCH_UNIT = 1 << 10;
+		static final int MAX_BATCH = 1 << 25;
+		private final ObjectCollection collection;
+		private ObjectIterator it;
+		private final int characteristics;
+		private long est;
+		private int batch;
+	
+		TypeIteratorSpliterator(ObjectCollection collection, int characteristics) {
+			this.collection = collection;
+			it = null;
+			this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+								? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+								: characteristics;
+		}
+	
+		TypeIteratorSpliterator(ObjectIterator iterator, long size, int characteristics) {
+			collection = null;
+			it = iterator;
+			est = size;
+			this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+								? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+								: characteristics;
+		}
+		
+		TypeIteratorSpliterator(ObjectIterator iterator, int characteristics) {
+			collection = null;
+			it = iterator;
+			est = Long.MAX_VALUE;
+			this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+		}
+		
+		private ObjectIterator iterator()
+		{
+			if (it == null) {
+				it = collection.iterator();
+				est = collection.size();
+			}
+			return it;
+		}
+		
+		@Override
+		public ObjectSplititerator trySplit() {
+			ObjectIterator i = iterator();
+			if (est > 1 && i.hasNext()) {
+				int n = Math.min(batch + BATCH_UNIT, Math.min((int)est, MAX_BATCH));
+				T[] a = (T[])new Object[n];
+				int j = 0;
+				do { a[j] = i.next(); } while (++j < n && i.hasNext());
+				batch = j;
+				if (est != Long.MAX_VALUE)
+					est -= j;
+				return new TypeArraySplitIterator<>(a, 0, j, characteristics);
+			}
+			return null;
+		}
+		
+		@Override
+		public void forEachRemaining(Consumer action) {
+			if (action == null) throw new NullPointerException();
+			iterator().forEachRemaining(action);
+		}
+		
+		@Override
+		public boolean tryAdvance(Consumer action) {
+			if (action == null) throw new NullPointerException();
+			ObjectIterator iter = iterator();
+			if (iter.hasNext()) {
+				action.accept(iter.next());
+				return true;
+			}
+			return false;
+		}
+		
+		@Override
+		public long estimateSize() {
+			iterator();
+			return est;
+		}
+	
+		@Override
+		public int characteristics() { return characteristics; }
+		
+		@Override
+		public Comparator getComparator() {
+			if (hasCharacteristics(4)) //Sorted
+				return null;
+			throw new IllegalStateException();
+		}
+	
+		@Override
+		public T next() { return iterator().next(); }
+	
+		@Override
+		public boolean hasNext() { return iterator().hasNext(); }
+	}
+	
+	static final class TypeArraySplitIterator implements ObjectSplititerator {
+		private final T[] array;
+		private int index;
+		private final int fence; 
+		private final int characteristics;
+		
+		public TypeArraySplitIterator(T[] array, int origin, int fence, int additionalCharacteristics) {
+			this.array = array;
+			index = origin;
+			this.fence = fence;
+			characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+		}
+		
+		@Override
+		public ObjectSplititerator trySplit() {
+			int lo = index, mid = (lo + fence) >>> 1;
+			return (lo >= mid) ? null : new TypeArraySplitIterator<>(array, lo, index = mid, characteristics);
+		}
+		
+		@Override
+		public void forEachRemaining(Consumer action) {
+			if (action == null) throw new NullPointerException();
+			T[] a; int i, hi;
+			if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) {
+				do { action.accept(a[i]); } while (++i < hi);
+			}
+		}
+		
+		@Override
+		public boolean tryAdvance(Consumer action) {
+			if (action == null) throw new NullPointerException();
+			if (index >= 0 && index < fence) {
+				action.accept(array[index++]);
+				return true;
+			}
+			return false;
+		}
+		
+		@Override
+		public long estimateSize() { return fence - index; }
+		@Override
+		public int characteristics() { return characteristics; }
+		@Override
+		public Comparator getComparator() {
+			if (hasCharacteristics(4)) //Sorted
+				return null;
+			throw new IllegalStateException();
+		}
+		
+		@Override
+		public T next() {
+			if(!hasNext()) throw new NoSuchElementException();
+			return array[index++];
+		}
+		
+		@Override
+		public boolean hasNext() { return index < fence; }
+	}
+	
+}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/shorts/functions/ShortComparator.java b/src/main/java/speiger/src/collections/shorts/functions/ShortComparator.java
new file mode 100644
index 000000000..dfa237c3f
--- /dev/null
+++ b/src/main/java/speiger/src/collections/shorts/functions/ShortComparator.java
@@ -0,0 +1,70 @@
+package speiger.src.collections.shorts.functions;
+
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * Type-Specific Class for Comparator to reduce (un)boxing
+ */
+public interface ShortComparator extends Comparator 
+{
+	/**
+	 * Type-Specific compare function to reduce (un)boxing
+	 * @param o1 the first object to be compared.
+	 * @param o2 the second object to be compared.
+	 * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
+	 * @see Comparator#compare(Object, Object)
+	 */
+	int compare(short o1, short o2);
+	
+	/** {@inheritDoc}
+	 * 

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default int compare(Short o1, Short o2) { + return compare(o1.shortValue(), o2.shortValue()); + } + + /** + * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator + * @param c comparator to convert + * @return the wrapper of the comparator + * @throws NullPointerException if the comparator is null + */ + public static ShortComparator of(Comparator c) { + Objects.requireNonNull(c); + return (K, V) -> c.compare(Short.valueOf(K), Short.valueOf(V)); + } + + @Override + public default ShortComparator reversed() { + return new Reversed(this); + } + + /** + * A Type Specific Reversed Comparator to reduce boxing/unboxing + */ + static class Reversed implements ShortComparator + { + ShortComparator original; + + /** + * default constructor + * @param original that is going to be reversed + */ + public Reversed(ShortComparator original) { + this.original = original; + } + + public int compare(short o1, short o2) { + return original.compare(o2, o1); + } + + @Override + public ShortComparator reversed() { + return original; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/ShortConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/ShortConsumer.java new file mode 100644 index 000000000..d43229902 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/ShortConsumer.java @@ -0,0 +1,48 @@ +package speiger.src.collections.shorts.functions; + +import java.util.Objects; +import java.util.function.Consumer; +/** + * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +@FunctionalInterface +public interface ShortConsumer extends Consumer +{ + /** + * Type-Specific function to reduce (un)boxing. + * Performs this operation on the given argument. + * + * @param t the input argument + */ + void accept(short t); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced consumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ShortConsumer andThen(ShortConsumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(T);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Short t) { accept(t.shortValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ShortConsumer andThen(Consumer after) { + Objects.requireNonNull(after); + return T -> {accept(T); after.accept(Short.valueOf(T));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/ShortSupplier.java b/src/main/java/speiger/src/collections/shorts/functions/ShortSupplier.java new file mode 100644 index 000000000..23dc04d87 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/ShortSupplier.java @@ -0,0 +1,12 @@ +package speiger.src.collections.shorts.functions; + +/** + * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface + */ +public interface ShortSupplier +{ + /** + * @return the supplied value + */ + public short getAsInt(); +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortBooleanConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortBooleanConsumer.java new file mode 100644 index 000000000..1fff26b27 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortBooleanConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.shorts.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ShortBooleanConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(short k, boolean v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ShortBooleanConsumer andThen(ShortBooleanConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Short k, Boolean v) { accept(k.shortValue(), v.booleanValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ShortBooleanConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Boolean.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortByteConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortByteConsumer.java new file mode 100644 index 000000000..692bf44ef --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortByteConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.shorts.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ShortByteConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(short k, byte v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ShortByteConsumer andThen(ShortByteConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Short k, Byte v) { accept(k.shortValue(), v.byteValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ShortByteConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Byte.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortCharConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortCharConsumer.java new file mode 100644 index 000000000..c8b5f5a59 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortCharConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.shorts.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ShortCharConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(short k, char v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ShortCharConsumer andThen(ShortCharConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Short k, Character v) { accept(k.shortValue(), v.charValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ShortCharConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Character.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortDoubleConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortDoubleConsumer.java new file mode 100644 index 000000000..bfde026df --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortDoubleConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.shorts.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ShortDoubleConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(short k, double v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ShortDoubleConsumer andThen(ShortDoubleConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Short k, Double v) { accept(k.shortValue(), v.doubleValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ShortDoubleConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Double.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortFloatConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortFloatConsumer.java new file mode 100644 index 000000000..5ee2a25ae --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortFloatConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.shorts.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ShortFloatConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(short k, float v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ShortFloatConsumer andThen(ShortFloatConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Short k, Float v) { accept(k.shortValue(), v.floatValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ShortFloatConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Float.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortIntConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortIntConsumer.java new file mode 100644 index 000000000..60879a58f --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortIntConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.shorts.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ShortIntConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(short k, int v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ShortIntConsumer andThen(ShortIntConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Short k, Integer v) { accept(k.shortValue(), v.intValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ShortIntConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Integer.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortLongConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortLongConsumer.java new file mode 100644 index 000000000..557d0922b --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortLongConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.shorts.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ShortLongConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(short k, long v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ShortLongConsumer andThen(ShortLongConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Short k, Long v) { accept(k.shortValue(), v.longValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ShortLongConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Long.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortObjectConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortObjectConsumer.java new file mode 100644 index 000000000..a75fa69ac --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortObjectConsumer.java @@ -0,0 +1,50 @@ +package speiger.src.collections.shorts.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + * @param the keyType of elements maintained by this Collection + */ +public interface ShortObjectConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(short k, V v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ShortObjectConsumer andThen(ShortObjectConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Short k, V v) { accept(k.shortValue(), v); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ShortObjectConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), V);}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortShortConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortShortConsumer.java new file mode 100644 index 000000000..a89551445 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortShortConsumer.java @@ -0,0 +1,49 @@ +package speiger.src.collections.shorts.functions.consumer; + +import java.util.Objects; +import java.util.function.BiConsumer; + +/** + * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. + */ +public interface ShortShortConsumer extends BiConsumer +{ + /** + * A Type Specific operation method to reduce boxing/unboxing + * Performs this operation on the given arguments. + * + * @param k the first input argument + * @param v the second input argument + */ + void accept(short k, short v); + + /** + * Type Specific sequencing method to reduce boxing/unboxing. + * @param after a operation that should be performed afterwards + * @return a sequenced biconsumer that does 2 operations + * @throws NullPointerException if after is null + */ + public default ShortShortConsumer andThen(ShortShortConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(K, V);}; + } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default void accept(Short k, Short v) { accept(k.shortValue(), v.shortValue()); } + + /** {@inheritDoc} + *

This default implementation delegates to the corresponding type-specific function. + * @deprecated Please use the corresponding type-specific function instead. + */ + @Override + @Deprecated + default ShortShortConsumer andThen(BiConsumer after) { + Objects.requireNonNull(after); + return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Short.valueOf(V));}; + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2ByteFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2ByteFunction.java new file mode 100644 index 000000000..d1fc90e0c --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/Short2ByteFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.shorts.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Short2ByteFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public byte applyAsByte(short k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2CharFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2CharFunction.java new file mode 100644 index 000000000..a0a56b4fc --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/Short2CharFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.shorts.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Short2CharFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public char applyAsChar(short k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2DoubleFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2DoubleFunction.java new file mode 100644 index 000000000..0418c9793 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/Short2DoubleFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.shorts.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Short2DoubleFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public double applyAsDouble(short k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2FloatFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2FloatFunction.java new file mode 100644 index 000000000..c25f58373 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/Short2FloatFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.shorts.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Short2FloatFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public float applyAsFloat(short k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2IntFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2IntFunction.java new file mode 100644 index 000000000..84826457d --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/Short2IntFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.shorts.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Short2IntFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public int applyAsInt(short k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2LongFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2LongFunction.java new file mode 100644 index 000000000..47b227a1a --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/Short2LongFunction.java @@ -0,0 +1,17 @@ +package speiger.src.collections.shorts.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface Short2LongFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public long applyAsLong(short k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortBooleanUnaryOperator.java new file mode 100644 index 000000000..a6c3220ab --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortBooleanUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.shorts.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ShortBooleanUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public boolean applyAsBoolean(short k, boolean v); + + @Override + public default Boolean apply(Short k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.shortValue(), v.booleanValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortByteUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortByteUnaryOperator.java new file mode 100644 index 000000000..e12c739d9 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortByteUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.shorts.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ShortByteUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public byte applyAsByte(short k, byte v); + + @Override + public default Byte apply(Short k, Byte v) { return Byte.valueOf(applyAsByte(k.shortValue(), v.byteValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortCharUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortCharUnaryOperator.java new file mode 100644 index 000000000..0a5d1a286 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortCharUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.shorts.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ShortCharUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public char applyAsChar(short k, char v); + + @Override + public default Character apply(Short k, Character v) { return Character.valueOf(applyAsChar(k.shortValue(), v.charValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortDoubleUnaryOperator.java new file mode 100644 index 000000000..b3419fe04 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortDoubleUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.shorts.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ShortDoubleUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public double applyAsDouble(short k, double v); + + @Override + public default Double apply(Short k, Double v) { return Double.valueOf(applyAsDouble(k.shortValue(), v.doubleValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortFloatUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortFloatUnaryOperator.java new file mode 100644 index 000000000..ef16ee0e0 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortFloatUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.shorts.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ShortFloatUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public float applyAsFloat(short k, float v); + + @Override + public default Float apply(Short k, Float v) { return Float.valueOf(applyAsFloat(k.shortValue(), v.floatValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortFunction.java new file mode 100644 index 000000000..ce0291457 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortFunction.java @@ -0,0 +1,18 @@ +package speiger.src.collections.shorts.functions.function; + + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + * @param the keyType of elements maintained by this Collection + */ +@FunctionalInterface +public interface ShortFunction +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public V apply(short k); + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortIntUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortIntUnaryOperator.java new file mode 100644 index 000000000..29a3485d4 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortIntUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.shorts.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ShortIntUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public int applyAsInt(short k, int v); + + @Override + public default Integer apply(Short k, Integer v) { return Integer.valueOf(applyAsInt(k.shortValue(), v.intValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortLongUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortLongUnaryOperator.java new file mode 100644 index 000000000..17fb01764 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortLongUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.shorts.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ShortLongUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public long applyAsLong(short k, long v); + + @Override + public default Long apply(Short k, Long v) { return Long.valueOf(applyAsLong(k.shortValue(), v.longValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortObjectUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortObjectUnaryOperator.java new file mode 100644 index 000000000..a53ec6984 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortObjectUnaryOperator.java @@ -0,0 +1,23 @@ +package speiger.src.collections.shorts.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + * @param the keyType of elements maintained by this Collection + */ +public interface ShortObjectUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public V apply(short k, V v); + + @Override + public default V apply(Short k, V v) { return apply(k.shortValue(), v); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortPredicate.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortPredicate.java new file mode 100644 index 000000000..26a64eba8 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortPredicate.java @@ -0,0 +1,62 @@ +package speiger.src.collections.shorts.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface ShortPredicate +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public boolean test(short k); + + /** + * Creates a Always true function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static ShortPredicate alwaysTrue() { + return T -> true; + } + + /** + * Creates a Always false function that may be useful if you don't need to process information or just want a default. + * @return a default returning function + */ + public static ShortPredicate alwaysFalse() { + return T -> false; + } + + /** + * A Type specific and-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a and comparason + */ + public default ShortPredicate andType(ShortPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) && other.test(T); + } + + /** + * A type specific inverter function + * @return the same function but inverts the result + */ + public default ShortPredicate negate() { + return T -> !test(T); + } + + /** + * A Type specific or-function helper function that reduces boxing/unboxing + * @param other the other function that should be merged with. + * @return a function that compares values in a or comparason + */ + public default ShortPredicate orType(ShortPredicate other) { + Objects.requireNonNull(other); + return T -> test(T) || other.test(T); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortShortUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortShortUnaryOperator.java new file mode 100644 index 000000000..fc9633fb5 --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortShortUnaryOperator.java @@ -0,0 +1,22 @@ +package speiger.src.collections.shorts.functions.function; + +import java.util.function.BiFunction; + +/** + * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing + */ +public interface ShortShortUnaryOperator extends BiFunction +{ + /** + * A Type Specifc apply method to reduce boxing/unboxing. + * Applies this function to the given arguments. + * + * @param k the first function argument + * @param v the second function argument + * @return the function result + */ + public short applyAsShort(short k, short v); + + @Override + public default Short apply(Short k, Short v) { return Short.valueOf(applyAsShort(k.shortValue(), v.shortValue())); } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortUnaryOperator.java new file mode 100644 index 000000000..6a31fc66b --- /dev/null +++ b/src/main/java/speiger/src/collections/shorts/functions/function/ShortUnaryOperator.java @@ -0,0 +1,54 @@ +package speiger.src.collections.shorts.functions.function; + +import java.util.Objects; + +/** + * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. + */ +@FunctionalInterface +public interface ShortUnaryOperator +{ + /** + * Type Specific get function to reduce boxing/unboxing + * @param k the value that should be processed + * @return the result of the function + */ + public short applyAsShort(short k); + + /** + * Creates a Default function that returns the input provided. + * @return a input returning function + */ + public static ShortUnaryOperator identity() { + return T -> T; + } + + /** + * Returns a composed function that first applies the {@code before} + * function to its input, and then applies this function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param before the function that should be used first + * @return a composed function with a different starting function. + */ + public default ShortUnaryOperator compose(ShortUnaryOperator before) { + Objects.requireNonNull(before); + return T -> applyAsShort(before.applyAsShort(T)); + } + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + * If evaluation of either function throws an exception, it is relayed to + * the caller of the composed function. + * + * @param after the function that should be used last + * @return a composed function with a different starting function. + */ + public default ShortUnaryOperator andThen(ShortUnaryOperator after) { + Objects.requireNonNull(after); + return T -> after.applyAsShort(applyAsShort(T)); + } + +} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/utils/HashUtil.java b/src/main/java/speiger/src/collections/utils/HashUtil.java new file mode 100644 index 000000000..c2dd14363 --- /dev/null +++ b/src/main/java/speiger/src/collections/utils/HashUtil.java @@ -0,0 +1,96 @@ +package speiger.src.collections.utils; + +/** + * Helper class that is used for HashMap functions reduce duplicated code + */ +public class HashUtil +{ + /** Minimum HashMap Capacity */ + public static final int DEFAULT_MIN_CAPACITY = 16; + /** Minimum ConcurrentHashMap Concurrency */ + public static final int DEFAULT_MIN_CONCURRENCY = 4; + /** Default HashMap Load Factor */ + public static final float DEFAULT_LOAD_FACTOR = 0.75F; + /** HashMap Load Factor with reduced hash collisions but more memory usage */ + public static final float FAST_LOAD_FACTOR = 0.5F; + /** HashMap Load Factor with minimal hash collisions but more memory usage */ + public static final float FASTER_LOAD_FACTOR = 0.25F; + + /** 232 · φ, φ = (√5 − 1)/2. */ + private static final int INT_PHI = 0x9E3779B9; + /** The reciprocal of {@link #INT_PHI} modulo 232. */ + private static final int INV_INT_PHI = 0x144cbc89; + + /** Quickly mixes the bits of an integer. + * + *

This method mixes the bits of the argument by multiplying by the golden ratio and + * xorshifting the result. It is borrowed from Koloboke, + * + * @param x an integer. + * @return a hash value obtained by mixing the bits of {@code x}. + * @see #invMix(int) + */ + public static int mix(final int x) { + final int h = x * INT_PHI; + return h ^ (h >>> 16); + } + + /** The inverse of {@link #mix(int)}. This method is mainly useful to create unit tests. + * + * @param x an integer. + * @return a value that passed through {@link #mix(int)} would give {@code x}. + */ + public static int invMix(final int x) { + return (x ^ x >>> 16) * INV_INT_PHI; + } + + /** + * Function that rounds up to the closest power of 2 + * A modified version of https://stackoverflow.com/a/466242 + * @param x that should be converted to the next power of two + * @return the input number rounded up to the next power of two + */ + public static int nextPowerOfTwo(int x) { + return 1 << (32 - Integer.numberOfLeadingZeros(x - 1)); + } + + /** + * Function that rounds up to the closest power of 2 + * A modified version of https://stackoverflow.com/a/466242 + * @param x that should be converted to the next power of two + * @return the input number rounded up to the next power of two + */ + public static long nextPowerOfTwo(long x) { + return 1L << (64 - Long.numberOfLeadingZeros(x - 1)); + } + + /** + * Function that finds out how many bits are required to store the number Provided + * @param value to get the required bits to store. + * @return the required bits to store that number + * @note Really useful for compression. Reducing data that is inserted into a GZIP algorithm. + */ + public static int getRequiredBits(int value) { + return Integer.bitCount(nextPowerOfTwo(value+1)-1); + } + + /** + * Function that finds out how many bits are required to store the number Provided + * @param value to get the required bits to store. + * @return the required bits to store that number + * @note Really useful for compression. Reducing data that is inserted into a GZIP algorithm. + */ + public static int getRequiredBits(long value) { + return Long.bitCount(nextPowerOfTwo(value+1L)-1L); + } + + /** + * Helper function that creates the ideal array size for HashMap + * @param size the original array size + * @param loadFactor the load factor + * @return the new array size + */ + public static int arraySize(int size, float loadFactor) { + return (int)Math.min(1 << 30, Math.max(2, nextPowerOfTwo((long)Math.ceil(size / loadFactor)))); + } +} diff --git a/src/main/java/speiger/src/collections/utils/IArray.java b/src/main/java/speiger/src/collections/utils/IArray.java new file mode 100644 index 000000000..826e9bafd --- /dev/null +++ b/src/main/java/speiger/src/collections/utils/IArray.java @@ -0,0 +1,20 @@ +package speiger.src.collections.utils; + +import java.util.RandomAccess; + +/** + * A Helper interface that allows to detect if the Underlying implementation is + * using a Array. This allows to read methods through synchronization layers. + * Also it implements {@link RandomAccess} and {@link ITrimmable} + */ +public interface IArray extends RandomAccess, ITrimmable +{ + /** + * Increases the capacity of this implementation instance, if necessary, + * to ensure that it can hold at least the number of elements specified by + * the minimum capacity argument. + * + * @param size the desired minimum capacity + */ + public void ensureCapacity(int size); +} diff --git a/src/main/java/speiger/src/collections/utils/ISizeProvider.java b/src/main/java/speiger/src/collections/utils/ISizeProvider.java new file mode 100644 index 000000000..0833ca3ac --- /dev/null +++ b/src/main/java/speiger/src/collections/utils/ISizeProvider.java @@ -0,0 +1,46 @@ +package speiger.src.collections.utils; + +import java.util.Collection; + +/** + * @author Speiger + * + * This Interface is a Helper class to allow transfer the information through Iterators, without forcing a Implementation of a size method through it. + * This is mainly used to optimize the toArray function. + * + */ +public interface ISizeProvider +{ + /** @return the size of the implementing Collection */ + public int size(); + + /** + * Gets a SizeProvider given the Iterable. May return null if it isn't a Collection or a SizeProvider. + * @param iter the Iterable that you want the size of. + * @return a SizeProvider if it is one or if it is a JavaCollection + */ + public static ISizeProvider of(Iterable iter) { + if(iter instanceof ISizeProvider) return (ISizeProvider)iter; + if(iter instanceof Collection) return new CollectionSize((Collection)iter); + return null; + } + + /** + * Collection implementation of the SizeProvider + */ + static class CollectionSize implements ISizeProvider + { + Collection collection; + + public CollectionSize(Collection collection) + { + this.collection = collection; + } + + @Override + public int size() + { + return collection.size(); + } + } +} diff --git a/src/main/java/speiger/src/collections/utils/ITrimmable.java b/src/main/java/speiger/src/collections/utils/ITrimmable.java new file mode 100644 index 000000000..8026ee1bc --- /dev/null +++ b/src/main/java/speiger/src/collections/utils/ITrimmable.java @@ -0,0 +1,37 @@ +package speiger.src.collections.utils; + +/** + * Interface that allows to test for if a collection is trimmable. + * This also allows that synchronization-wrappers are trimmable without extracting the original collection. + */ +public interface ITrimmable +{ + /** + * Trims the original collection down to the size of the current elements + * @return if the internal array has been trimmed. + */ + public default boolean trim() { + return trim(0); + } + + /** + * Trims the original collection down to the size of the current elements or the requested size depending which is bigger + * @param size the requested trim size. + * @return if the internal array has been trimmed. + */ + public boolean trim(int size); + + /** + * Trims the collection down to the original size and clears all present elements with it. + */ + public default void clearAndTrim() { + clearAndTrim(0); + } + + /** + * Trims the collection down to the requested size and clears all elements while doing so + * @param size the amount of elements that should be allowed + * @note this will enforce minimum size of the collection itself + */ + public void clearAndTrim(int size); +} diff --git a/src/main/java/speiger/src/collections/utils/SanityChecks.java b/src/main/java/speiger/src/collections/utils/SanityChecks.java new file mode 100644 index 000000000..b19d48707 --- /dev/null +++ b/src/main/java/speiger/src/collections/utils/SanityChecks.java @@ -0,0 +1,178 @@ +package speiger.src.collections.utils; + +import java.util.Random; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; + +/** + * Helper class that provides functions that are shared within the library. + * On top of that it provides some helper functions that allow control of some internals of the Library + */ +public class SanityChecks +{ + /** Max Possible ArraySize without the JVM Crashing */ + public static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + private static ForkJoinPool WORK_POOL = ForkJoinPool.commonPool(); + private static boolean FORCE_IGNORE_PARALLELISM = false; + private static ThreadLocal RANDOM = ThreadLocal.withInitial(Random::new); + private static ThreadLocal FORCE_ASYNC = ThreadLocal.withInitial(() -> false); + private static ThreadLocal FORCE_TASK_POOL = ThreadLocal.withInitial(() -> false); + + /** + * Internal function to cast a Integer to a Byte + * @param value that should be turned into a byte + * @return the value as a byte + * @throws IllegalStateException if the value does not fit within a byte + */ + public static byte castToByte(int value) { + if(value > Byte.MAX_VALUE || value < Byte.MIN_VALUE) throw new IllegalStateException("Value ["+value+"] out of Byte[-128,127] range"); + return (byte)value; + } + + /** + * Internal function to cast a Integer to a Short + * @param value that should be turned into a short + * @return the value as a short + * @throws IllegalStateException if the value does not fit within a short + */ + public static short castToShort(int value) { + if(value > Short.MAX_VALUE || value < Short.MIN_VALUE) throw new IllegalStateException("Value ["+value+"] out of Short[-32768,32767] range"); + return (short)value; + } + + /** + * Internal function to cast a Integer to a Character + * @param value that should be turned into a char + * @return the value as a char + * @throws IllegalStateException if the value does not fit within a char + */ + public static char castToChar(int value) { + if(value > Character.MAX_VALUE || value < Character.MIN_VALUE) throw new IllegalStateException("Value ["+value+"] out of Character[0,65535] range"); + return (char)value; + } + + /** + * Internal function to cast a Double to a Double + * @param value that should be turned into a float + * @return the value as a float + * @throws IllegalStateException if the value does not fit within a float + */ + public static float castToFloat(double value) { + if(Double.isNaN(value)) return Float.NaN; + if(Double.isInfinite(value)) return value > 0 ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY; + if(value < -Float.MAX_VALUE || value > Float.MAX_VALUE) throw new IllegalStateException("Value ["+value+"] out of Float range"); + return (float)value; + } + + /** + * Internal function that checks if the given array-size is big enough for the access. + * @param arraySize the size of the Array + * @param offset the offset of the access + * @param accessSize the length of the access + * @throws IllegalStateException if offset or accessSize is negative or the range goes out of the array-size + */ + public static void checkArrayCapacity(int arraySize, int offset, int accessSize) { + if(offset < 0) throw new IndexOutOfBoundsException("Offset is negative ("+offset+")"); + else if(accessSize < 0) throw new IllegalArgumentException("Size is negative ("+accessSize+")"); + else if(arraySize < offset + accessSize) throw new IndexOutOfBoundsException("Index (" + (offset + accessSize) + ") is not in size (" + arraySize + ")"); + } + + /** + * Returns if the current thread-pool can handle Multi-threading tasks + * @return true if the thread-count is bigger the 1 + */ + public static boolean canParallelTask() { + return getPool().getParallelism() > 1 || FORCE_IGNORE_PARALLELISM; + } + + /** + * Helper method to start a ForkJoinTask. This method will await the finalization of said task + * @param task the Task to invoke + * @param the type of the task + */ + public static void invokeTask(ForkJoinTask task) { + if(FORCE_ASYNC.get().booleanValue()) invokeAsyncTask(task); + else getPool().invoke(task); + } + + /** + * Helper method to start a ForkJoinTask. This method will not await the finalization of said task + * @param task the Task to invoke + * @param the type of the task + */ + public static void invokeAsyncTask(ForkJoinTask task) { + getPool().execute(task); + } + + /** + * A Helper method to start a Async Task. This method will not await the finalization of said task + * @param task the Task to invoke + */ + public static void invokeAsyncTask(Runnable task) { + getPool().execute(task); + } + + /** + * Helper method to control what ForkJoinPool is being used for any given task. + * @note this method is not thread-save. It is only there to provide control over how Library specific Threaded tasks are handled. + * @param pool The ForkJoinPool that should receive the tasks. If null {@link ForkJoinPool#commonPool()} is set instead + */ + public static void setWorkPool(ForkJoinPool pool) { + WORK_POOL = pool == null ? ForkJoinPool.commonPool() : pool; + } + + private static ForkJoinPool getPool() { + if(FORCE_TASK_POOL.get().booleanValue()) { + ForkJoinPool pool = ForkJoinTask.getPool(); + if(pool != null) return pool; + } + return WORK_POOL; + } + + /** + * Helper method to detect if the Current Thread forces not to await task completion. + * @return if the Current Thread has not to await task completion. + */ + public static boolean isForcedAsync() { + return FORCE_ASYNC.get().booleanValue(); + } + + /** + * Helper method to detect if the current thread forces to execute tasks in the current Thread-pool if it is a ForkJoinPool. + * @return if the task checks the current pool to be executed in if it is valid. + */ + public static boolean isForcedTaskPool() { + return FORCE_TASK_POOL.get().booleanValue(); + } + + /** + * Helper method to decide if the current thread should forcefully not wait on tasks to be completed. + * @param value it tasks should not be awaited for + */ + public static void setForcedAsync(boolean value) { + FORCE_ASYNC.set(Boolean.valueOf(value)); + } + + /** + * Helper method to decide if it should be checked for if the current thread is a ThreadPool Worker (ForkJoinPool Worker to be specific) and if tasks should be delegated into it. + * @param value if the current thread should check if it is a ThreadPoolWorker. + */ + public static void setForcedTaskPool(boolean value) { + FORCE_TASK_POOL.set(Boolean.valueOf(value)); + } + + /** + * Helper method to decide if Parallelism should be checked or not. + * @param value if the Parallelism should be ignored + */ + public static void setForceIgnoreParallelism(boolean value) { + FORCE_IGNORE_PARALLELISM = value; + } + + /** + * @return Thread Specific Random needed for internal functions in this library. + */ + public static Random getRandom() { + return RANDOM.get(); + } +} diff --git a/src/main/java/speiger/src/collections/utils/Stack.java b/src/main/java/speiger/src/collections/utils/Stack.java new file mode 100644 index 000000000..fa878c9c6 --- /dev/null +++ b/src/main/java/speiger/src/collections/utils/Stack.java @@ -0,0 +1,62 @@ +package speiger.src.collections.utils; + + +/** + * The Stack Interface represents the Last-In-First-Out layout (LIFO). + * It provides a simple {@link #push(Object)}, {@link #pop()} function, + * with a fast {@link #clear()} function. + * The {@link #peek(int)} function allows to view the contents of the stack (top to bottom). + * @param the type of elements maintained by this Collection + */ +public interface Stack +{ + /** + * Inserts a given Object on top of the stack + * @param e the Object to insert + */ + public void push(T e); + + /** + * Removes the Object on top of the stack. + * @return the element that is on top of the stack + * @throws ArrayIndexOutOfBoundsException if the stack is empty + */ + public T pop(); + + /** + * Provides the amount of elements currently in the stack + * @return amount of elements in the list + */ + public int size(); + + + /** + * @return if the stack is empty + */ + public default boolean isEmpty() { + return size() == 0; + } + + /** + * Clears the stack + */ + public void clear(); + + /** + * Provides the Object on top of the stack + * @return the element that is on top of the stack + * @throws ArrayIndexOutOfBoundsException if the stack is empty + */ + public default T top() { + return peek(0); + } + + /** + * Provides the Selected Object from the stack. + * Top to bottom + * @param index of the element that should be provided + * @return the element that was requested + * @throws ArrayIndexOutOfBoundsException if the index is out of bounds + */ + public T peek(int index); +} diff --git a/src/main/java/zone/rong/rongasm/api/CaptureSet.java b/src/main/java/zone/rong/rongasm/api/CaptureSet.java new file mode 100644 index 000000000..429600892 --- /dev/null +++ b/src/main/java/zone/rong/rongasm/api/CaptureSet.java @@ -0,0 +1,34 @@ +package zone.rong.rongasm.api; + +import speiger.src.collections.objects.sets.ObjectOpenHashSet; + +import java.util.HashSet; +import java.util.Set; + +public class CaptureSet extends HashSet { + + private final Set backingCaptures; + + public CaptureSet() { + super(); + this.backingCaptures = new ObjectOpenHashSet<>(); + } + + public CaptureSet(Set populate) { + this(); + addAll(populate); + } + + public void addCapture(K capture) { + this.backingCaptures.add(capture); + } + + public boolean put(K k) { + return super.add(k); + } + + @Override + public boolean add(K k) { + return this.backingCaptures.contains(k) || super.add(k); + } +} diff --git a/src/main/java/zone/rong/rongasm/api/DummyMap.java b/src/main/java/zone/rong/rongasm/api/DummyMap.java new file mode 100644 index 000000000..c7e9f35ac --- /dev/null +++ b/src/main/java/zone/rong/rongasm/api/DummyMap.java @@ -0,0 +1,50 @@ +package zone.rong.rongasm.api; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +/** + * Used as a ImmutableMap-like structure, but with the methods not throwing UnsupportedOperationException + */ +public class DummyMap implements Map { + + private static final DummyMap INSTANCE = new DummyMap<>(); + private static final Set SET_INSTANCE = Collections.newSetFromMap(INSTANCE); + + @SuppressWarnings("unchecked") + public static Map of() { + return (DummyMap) INSTANCE; + } + + @SuppressWarnings("unchecked") + public static Set asSet() { + return (Set) SET_INSTANCE; + } + + public int size() { return 0; } + + public boolean isEmpty() { return true; } + + public boolean containsKey(Object key) { return false; } + + public boolean containsValue(Object value) { return false; } + + public V get(Object key) { return null; } + + public V put(K key, V value) { return value; } + + public V remove(Object key) { return null; } + + public void putAll(Map m) { } + + public void clear() { } + + public Set keySet() { return Collections.emptySet(); } + + public Collection values() { return Collections.emptySet(); } + + public Set entrySet() { return Collections.emptySet(); } + +} diff --git a/src/main/java/zone/rong/rongasm/api/LoliHelpers.java b/src/main/java/zone/rong/rongasm/api/LoliHelpers.java new file mode 100644 index 000000000..228e72d53 --- /dev/null +++ b/src/main/java/zone/rong/rongasm/api/LoliHelpers.java @@ -0,0 +1,40 @@ +package zone.rong.rongasm.api; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import net.minecraft.launchwrapper.Launch; +import net.minecraft.launchwrapper.LaunchClassLoader; +import org.embeddedt.archaicfix.ArchaicLogger; + +import java.util.Map; + +public class LoliHelpers { + private static final boolean noClassCache = false; + private static final boolean weakClassCache = true; + private static final boolean noResourceCache = false; + private static final boolean weakResourceCache = true; + public static void cleanupLaunchClassLoader() { + try { + ArchaicLogger.LOGGER.info("Cleaning up LaunchClassLoader"); + if (noClassCache) { + LoliReflector.resolveFieldSetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader, DummyMap.of()); + } else if (weakClassCache) { + Map> oldClassCache = (Map>) LoliReflector.resolveFieldGetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader); + Cache> newClassCache = CacheBuilder.newBuilder().concurrencyLevel(2).weakValues().build(); + newClassCache.putAll(oldClassCache); + LoliReflector.resolveFieldSetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader, newClassCache.asMap()); + } + if (noResourceCache) { + LoliReflector.resolveFieldSetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader, new ResourceCache()); + LoliReflector.resolveFieldSetter(LaunchClassLoader.class, "negativeResourceCache").invokeExact(Launch.classLoader, DummyMap.asSet()); + } else if (weakResourceCache) { + Map oldResourceCache = (Map) LoliReflector.resolveFieldGetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader); + Cache newResourceCache = CacheBuilder.newBuilder().concurrencyLevel(2).weakValues().build(); + newResourceCache.putAll(oldResourceCache); + LoliReflector.resolveFieldSetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader, newResourceCache.asMap()); + } + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } +} diff --git a/src/main/java/zone/rong/rongasm/api/LoliReflector.java b/src/main/java/zone/rong/rongasm/api/LoliReflector.java new file mode 100644 index 000000000..9dda4b6c6 --- /dev/null +++ b/src/main/java/zone/rong/rongasm/api/LoliReflector.java @@ -0,0 +1,245 @@ +package zone.rong.rongasm.api; + +import com.google.common.base.Preconditions; +import cpw.mods.fml.relauncher.ReflectionHelper; +import net.minecraft.launchwrapper.Launch; +import net.minecraft.launchwrapper.LaunchClassLoader; +import org.objectweb.asm.Type; + +import java.io.InputStream; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.*; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * Helper class for Reflection nonsense. + */ +public class LoliReflector { + + public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + private static final MethodHandle classLoader$DefineClass = resolveMethod(ClassLoader.class, "defineClass", String.class, byte[].class, int.class, int.class); + private static final CaptureSet transformerExclusions; + + static { + CaptureSet captureSet = new CaptureSet<>(); + try { + captureSet = new CaptureSet<>(((Set) resolveFieldGetter(LaunchClassLoader.class, "transformerExceptions").invokeExact(Launch.classLoader))); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + transformerExclusions = captureSet; + try { + resolveFieldSetter(LaunchClassLoader.class, "transformerExceptions").invoke(Launch.classLoader, transformerExclusions); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + public static Class defineMixinClass(String className, byte[] classBytes) { + try { + // defineClass(Launch.classLoader, className, classBytes); + Map resourceCache = (Map) resolveFieldGetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader); + if (resourceCache instanceof ResourceCache) { + ((ResourceCache) resourceCache).add(className, classBytes); + } else { + resourceCache.put(className, classBytes); + } + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + return null; + } + + public static Class defineClass(CL classLoader, Class clazz) { + String name = Type.getInternalName(clazz); + InputStream byteStream = clazz.getResourceAsStream('/' + name + ".class"); + try { + byte[] classBytes = new byte[byteStream.available()]; + final int bytesRead = byteStream.read(classBytes); + Preconditions.checkState(bytesRead == classBytes.length); + return (Class) classLoader$DefineClass.invokeExact(classLoader, name.replace('/', '.'), classBytes, 0, classBytes.length); + } catch (Throwable e) { + e.printStackTrace(); + } + return clazz; + } + + public static Class defineClass(CL classLoader, String name, byte[] classBytes) { + try { + return (Class) classLoader$DefineClass.invokeExact(classLoader, name, classBytes, 0, classBytes.length); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + return null; + } + + public static MethodHandle resolveCtor(Class clazz, Class... args) { + try { + Constructor ctor = clazz.getDeclaredConstructor(args); + ctor.setAccessible(true); + return LOOKUP.unreflectConstructor(ctor); + } catch (IllegalAccessException | NoSuchMethodException e) { + e.printStackTrace(); + return null; + } + } + + public static Constructor getCtor(Class clazz, Class... args) { + try { + Constructor ctor = clazz.getDeclaredConstructor(args); + ctor.setAccessible(true); + return ctor; + } catch (NoSuchMethodException e) { + e.printStackTrace(); + return null; + } + } + + public static MethodHandle resolveMethod(Class clazz, String methodName, Class... args) { + try { + Method method = clazz.getDeclaredMethod(methodName, args); + method.setAccessible(true); + return LOOKUP.unreflect(method); + } catch (IllegalAccessException | NoSuchMethodException e) { + e.printStackTrace(); + return null; + } + } + + public static Method getMethod(Class clazz, String methodName, Class... args) { + try { + Method method = clazz.getDeclaredMethod(methodName, args); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + e.printStackTrace(); + return null; + } + } + + @SuppressWarnings("unchecked") + public static MethodHandle resolveMethod(Class clazz, String methodName, String obfMethodName, Class... args) { + try { + return LOOKUP.unreflect(ReflectionHelper.findMethod((Class)clazz, null, new String[] { methodName, obfMethodName }, args)); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return null; + } + } + + @SuppressWarnings("unchecked") + public static Method getMethod(Class clazz, String methodName, String obfMethodName, Class... args) { + return ReflectionHelper.findMethod((Class)clazz, null, new String[] { methodName, obfMethodName }, args); + } + + public static MethodHandle resolveFieldGetter(Class clazz, String fieldName) { + try { + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + /* + if (LoliLoadingPlugin.isVMOpenJ9) { + fixOpenJ9PrivateStaticFinalRestraint(field); + } + */ + return LOOKUP.unreflectGetter(field); + } catch (Throwable e) { + e.printStackTrace(); + return null; + } + } + + public static MethodHandle resolveFieldSetter(Class clazz, String fieldName) { + try { + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + /* + if (LoliLoadingPlugin.isVMOpenJ9) { + fixOpenJ9PrivateStaticFinalRestraint(field); + } + */ + return LOOKUP.unreflectSetter(field); + } catch (Throwable e) { + e.printStackTrace(); + return null; + } + } + + public static MethodHandle resolveFieldGetter(Class clazz, String fieldName, String obfFieldName) { + try { + return LOOKUP.unreflectGetter(ReflectionHelper.findField(clazz, fieldName, obfFieldName)); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return null; + } + } + + public static MethodHandle resolveFieldSetter(Class clazz, String fieldName, String obfFieldName) { + try { + return LOOKUP.unreflectSetter(ReflectionHelper.findField(clazz, fieldName, obfFieldName)); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return null; + } + } + + public static Field getField(Class clazz, String fieldName) { + try { + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + /* + if (LoliLoadingPlugin.isVMOpenJ9) { + fixOpenJ9PrivateStaticFinalRestraint(field); + } + */ + return field; + } catch (Throwable e) { + e.printStackTrace(); + return null; + } + } + + public static Field getField(Class clazz, String fieldName, String obfFieldName) { + return ReflectionHelper.findField(clazz, fieldName, obfFieldName); + } + + public static boolean doesClassExist(String className) { + try { + Class.forName(className); + return true; + } catch (ClassNotFoundException ignored) { } + return false; + } + + public static boolean doesTweakExist(String tweakName) { + return ((List) Launch.blackboard.get("TweakClasses")).contains(tweakName); + } + + public static Optional> getClass(String className) { + try { + return Optional.of(Class.forName(className)); + } catch (ClassNotFoundException ignored) { } + return Optional.empty(); + } + + public static void removeTransformerExclusion(String transformerExclusion) { + if (!transformerExclusions.remove(transformerExclusion)) { + transformerExclusions.addCapture(transformerExclusion); + } + } + + public static void addTransformerExclusion(String transformerExclusion) { + transformerExclusions.put(transformerExclusion); + } + + private static void fixOpenJ9PrivateStaticFinalRestraint(Field field) throws Throwable { + Field modifiers = Field.class.getDeclaredField("modifiers"); + modifiers.setAccessible(true); + LOOKUP.unreflectSetter(modifiers).invokeExact(field, field.getModifiers() & ~Modifier.FINAL); + } + +} diff --git a/src/main/java/zone/rong/rongasm/api/LoliStringPool.java b/src/main/java/zone/rong/rongasm/api/LoliStringPool.java new file mode 100644 index 000000000..19564d132 --- /dev/null +++ b/src/main/java/zone/rong/rongasm/api/LoliStringPool.java @@ -0,0 +1,142 @@ +package zone.rong.rongasm.api; + +import org.embeddedt.archaicfix.ArchaicLogger; +import speiger.src.collections.ints.maps.impl.misc.Int2ObjectArrayMap; +import speiger.src.collections.objects.sets.ObjectOpenHashSet; + +import java.util.Locale; + +public class LoliStringPool { + + public static final int FILE_PERMISSIONS_ID = 1; + + private static final Int2ObjectArrayMap POOLS = new Int2ObjectArrayMap<>(); + + static { + establishPool(-1, 12288, "", " "); + POOLS.setDefaultReturnValue(POOLS.get(-1)); + } + + public static void establishPool(int poolId, int expectedSize, String... startingValues) { + if (POOLS.containsKey(poolId)) { + return; + } + POOLS.put(poolId, new Internal(poolId, expectedSize, startingValues)); + } + + public static Internal purgePool(int poolId) { + return POOLS.remove(poolId); + } + + public static int getSize() { + return POOLS.getDefaultReturnValue().internalPool.size(); + } + + public static int getSize(int pool) { + return POOLS.get(pool).internalPool.size(); + } + + public static long getDeduplicatedCount() { + return POOLS.getDefaultReturnValue().deduplicatedCount; + } + + public static long getDeduplicatedCount(int pool) { + return POOLS.get(pool).deduplicatedCount; + } + + public static String canonicalize(String string) { + synchronized (POOLS) { + return POOLS.getDefaultReturnValue().addOrGet(string); + } + } + + public static String unsafe$Canonicalize(String string) { + return POOLS.getDefaultReturnValue().addOrGet(string); + } + + @SuppressWarnings("unused") + public static String lowerCaseAndCanonicalize(String string) { + synchronized (POOLS) { + return POOLS.getDefaultReturnValue().addOrGet(string.toLowerCase(Locale.ROOT)); + } + } + + @SuppressWarnings("unused") + public static String unsafe$LowerCaseAndCanonicalize(String string) { + return POOLS.getDefaultReturnValue().addOrGet(string.toLowerCase(Locale.ROOT)); + } + + public static String canonicalize(String string, int poolId, boolean checkMainPool) { + if (checkMainPool) { + synchronized (POOLS) { + ObjectOpenHashSet internalPool = POOLS.get(poolId).internalPool; + String canonicalized = internalPool.contains(string) ? internalPool.addOrGet(string) : null; + if (canonicalized != null) { + return canonicalized; + } + } + } + synchronized (POOLS) { + return POOLS.get(poolId).addOrGet(string); + } + } + + public static String unsafe$Canonicalize(String string, int poolId, boolean checkMainPool) { + if (checkMainPool) { + ObjectOpenHashSet internalPool = POOLS.get(poolId).internalPool; + String canonicalized = internalPool.contains(string) ? internalPool.addOrGet(string) : null; + if (canonicalized != null) { + return canonicalized; + } + } + return POOLS.get(poolId).addOrGet(string); + } + + public static class EventHandler { + /* + @SubscribeEvent + public void onDebugList(RenderGameOverlayEvent.Text event) { + Minecraft minecraft = Minecraft.getMinecraft(); + if (minecraft.gameSettings.showDebugInfo) { + ArrayList list = event.left; + if (!list.get(list.size() - 1).equals("")) { + list.add(""); + } + int size = getSize(); + long deduplicatedCount = getDeduplicatedCount(); + list.add(String.format("%s%s%s: %s strings processed. %s unique, %s deduplicated.", EnumChatFormatting.AQUA, "", EnumChatFormatting.RESET, deduplicatedCount, size, deduplicatedCount - size)); + } + } + */ + } + + + + static class Internal { + + final int id; + final ObjectOpenHashSet internalPool; + + long deduplicatedCount; + + @SuppressWarnings("all") + Internal(int id, int expectedSize, String... startingValues) { + this.id = id; + this.internalPool = new ObjectOpenHashSet<>(expectedSize); + for (String startingValue : startingValues) { + this.internalPool.add(startingValue); + } + } + + String addOrGet(String string) { + deduplicatedCount++; + return internalPool.addOrGet(string); + } + + @Override + protected void finalize() { + ArchaicLogger.LOGGER.warn("Clearing LoliStringPool {}", id); + } + } + +} diff --git a/src/main/java/zone/rong/rongasm/api/ResourceCache.java b/src/main/java/zone/rong/rongasm/api/ResourceCache.java new file mode 100644 index 000000000..f1907e33c --- /dev/null +++ b/src/main/java/zone/rong/rongasm/api/ResourceCache.java @@ -0,0 +1,15 @@ +package zone.rong.rongasm.api; + +import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap; + +public class ResourceCache extends Object2ObjectOpenHashMap { + + public byte[] add(String s, byte[] bytes) { + return super.put(s, bytes); + } + + @Override + public byte[] put(String s, byte[] bytes) { + return bytes; + } +} diff --git a/src/main/resources/META-INF/archaicfix_at.cfg b/src/main/resources/META-INF/archaicfix_at.cfg new file mode 100644 index 000000000..98506732f --- /dev/null +++ b/src/main/resources/META-INF/archaicfix_at.cfg @@ -0,0 +1,71 @@ +# TODO: most of these can be compile-time only +# bugs.MixinEnchantmentHelper +public net.minecraft.enchantment.EnchantmentHelper$IModifier +public net.minecraft.enchantment.EnchantmentHelper$ModifierDamage +public net.minecraft.enchantment.EnchantmentHelper$ModifierLiving +public net.minecraft.enchantment.EnchantmentHelper$HurtIterator +public net.minecraft.enchantment.EnchantmentHelper$DamageIterator +public net.minecraft.enchantment.EnchantmentHelper$ModifierDamage ()V +public net.minecraft.enchantment.EnchantmentHelper$ModifierLiving ()V +public net.minecraft.enchantment.EnchantmentHelper$HurtIterator ()V +public net.minecraft.enchantment.EnchantmentHelper$DamageIterator ()V + +public net.minecraft.client.gui.inventory.GuiContainerCreative$ContainerCreative + +public net.minecraft.client.gui.GuiButton field_146123_n # hovered +public-f net.minecraft.client.resources.SkinManager$2 field_152636_b + +public net.minecraft.nbt.NBTTagList field_74747_a # tagList + +public net.minecraft.network.play.server.S0CPacketSpawnPlayer field_148956_c +public net.minecraft.network.play.server.S0CPacketSpawnPlayer field_148953_d +public net.minecraft.network.play.server.S0CPacketSpawnPlayer field_148954_e + +public net.minecraft.network.play.server.S11PacketSpawnExperienceOrb field_148990_b +public net.minecraft.network.play.server.S11PacketSpawnExperienceOrb field_148991_c +public net.minecraft.network.play.server.S11PacketSpawnExperienceOrb field_148988_d + +public net.minecraft.client.renderer.RenderGlobal field_72768_k # sortedWorldRenderers +public net.minecraft.client.renderer.RenderGlobal field_72765_l # worldRenderers +public net.minecraft.client.renderer.RenderGlobal field_72751_K # renderersLoaded +public net.minecraft.client.renderer.RenderGlobal field_72739_F # renderDistanceChunks +public net.minecraft.client.renderer.RenderGlobal field_72742_B # maxBlockX +public net.minecraft.client.renderer.RenderGlobal field_72780_y # minBlockX +public net.minecraft.client.renderer.RenderGlobal field_72743_C # maxBlockY +public net.minecraft.client.renderer.RenderGlobal field_72779_z # minBlockY +public net.minecraft.client.renderer.RenderGlobal field_72737_D # maxBlockZ +public net.minecraft.client.renderer.RenderGlobal field_72741_A # minBlockZ +public net.minecraft.client.renderer.RenderGlobal field_72766_m # renderChunksWide +public net.minecraft.client.renderer.RenderGlobal field_72763_n # renderChunksTall +public net.minecraft.client.renderer.RenderGlobal field_72764_o # renderChunksDeep +public net.minecraft.client.renderer.RenderGlobal field_72769_h # theWorld +public net.minecraft.client.renderer.RenderGlobal field_72767_j # worldRenderersToUpdate +public net.minecraft.client.renderer.RenderGlobal field_72753_P # dummyRenderInt +public net.minecraft.client.renderer.RenderGlobal field_72744_L # renderersBeingClipped +public net.minecraft.client.renderer.RenderGlobal field_72745_M # renderersBeingOccluded +public net.minecraft.client.renderer.RenderGlobal field_72746_N # renderersBeingRendered +public net.minecraft.client.renderer.RenderGlobal field_72747_O # renderersSkippingRenderPass +public net.minecraft.client.renderer.RenderGlobal field_72777_q # mc +public net.minecraft.client.renderer.RenderGlobal field_72749_I # countEntitiesRendered +public net.minecraft.client.renderer.RenderGlobal field_72750_J # countEntitiesHidden +public net.minecraft.client.renderer.RenderGlobal field_72752_Q # worldRenderersCheckIndex +public net.minecraft.client.renderer.RenderGlobal field_147603_i # prevChunkSortX +public net.minecraft.client.renderer.RenderGlobal field_147600_j # prevChunkSortY +public net.minecraft.client.renderer.RenderGlobal field_147601_k # prevChunkSortZ +public net.minecraft.client.renderer.RenderGlobal field_147596_f # prevRenderSortX +public net.minecraft.client.renderer.RenderGlobal field_147597_g # prevRenderSortY +public net.minecraft.client.renderer.RenderGlobal field_147602_h # prevRenderSortZ +public net.minecraft.client.renderer.RenderGlobal field_72754_S # allRenderLists +public net.minecraft.client.renderer.RenderGlobal field_72757_g # frustumCheckOffset + +public net.minecraft.client.renderer.RenderGlobal func_72722_c(III)V # markRenderersForNewPosition +public net.minecraft.client.renderer.RenderGlobal func_72733_a(ID)V # renderAllRenderLists +public net.minecraft.client.renderer.RenderGlobal func_72712_a()V # loadRenderers +public net.minecraft.client.renderer.RenderGlobal func_72724_a(IIID)I # renderSortedRenderers + +public net.minecraft.client.renderer.WorldRenderer field_78915_A # isInitialized +public net.minecraft.client.renderer.EntityRenderer field_78510_Z #renderEndNanoTime + +public net.minecraft.client.multiplayer.PlayerControllerMP field_78779_k #currentGameType + +public net.minecraft.world.World field_72993_I # activeChunkSet \ No newline at end of file diff --git a/src/main/resources/ModulSettings.json b/src/main/resources/ModulSettings.json new file mode 100644 index 000000000..3832a22ee --- /dev/null +++ b/src/main/resources/ModulSettings.json @@ -0,0 +1,2624 @@ +{ + "Async": false, + "Base": true, + "Collection": true, + "Function": true, + "List": true, + "Map": true, + "Pair": true, + "PriorityQueue": true, + "Set": true, + "Boolean": { + "Enabled": false, + "Base": { + "Enabled": false + }, + "Boolean": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Byte": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Short": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Character": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Integer": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Long": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Float": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Double": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Object": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Collection": { + "Enabled": false, + "IArray": false, + "Splititerators": false, + "Strategy": false, + "Streams": true + }, + "PriorityQueue": { + "Enabled": false, + "ArrayPrioQueue": false, + "Dequeue": false, + "FiFoQueue": false, + "HeapQueue": false, + "Implementations": false, + "Wrappers": false + }, + "List": { + "Enabled": false, + "ArrayList": false, + "CopyOnWriteList": false, + "ImmutableList": false, + "Implementations": false, + "LinkedList": false, + "Wrappers": false + }, + "Async": { + "Enabled": false + } + }, + "Byte": { + "Enabled": false, + "Base": { + "Enabled": false + }, + "Boolean": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Byte": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Short": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Character": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Integer": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Long": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Float": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Double": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Object": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Collection": { + "Enabled": false, + "IArray": false, + "Splititerators": false, + "Strategy": false, + "Streams": true + }, + "PriorityQueue": { + "Enabled": false, + "ArrayPrioQueue": false, + "Dequeue": false, + "FiFoQueue": false, + "HeapQueue": false, + "Implementations": false, + "Wrappers": false + }, + "List": { + "Enabled": false, + "ArrayList": false, + "CopyOnWriteList": false, + "ImmutableList": false, + "Implementations": false, + "LinkedList": false, + "Wrappers": false + }, + "Set": { + "Enabled": false, + "AVLTreeSet": false, + "ArraySet": false, + "CustomHashSet": false, + "HashSet": false, + "ImmutableSet": false, + "Implementations": false, + "LinkedCustomHashSet": false, + "LinkedHashSet": false, + "OrderedSet": false, + "RBTreeSet": false, + "SortedSet": false, + "Wrappers": false + }, + "Async": { + "Enabled": false + } + }, + "Short": { + "Enabled": false, + "Base": { + "Enabled": false + }, + "Boolean": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Byte": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Short": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Character": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Integer": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Long": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Float": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Double": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Object": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Collection": { + "Enabled": false, + "IArray": false, + "Splititerators": false, + "Strategy": false, + "Streams": true + }, + "PriorityQueue": { + "Enabled": false, + "ArrayPrioQueue": false, + "Dequeue": false, + "FiFoQueue": false, + "HeapQueue": false, + "Implementations": false, + "Wrappers": false + }, + "List": { + "Enabled": false, + "ArrayList": false, + "CopyOnWriteList": false, + "ImmutableList": false, + "Implementations": false, + "LinkedList": false, + "Wrappers": false + }, + "Set": { + "Enabled": false, + "AVLTreeSet": false, + "ArraySet": false, + "CustomHashSet": false, + "HashSet": false, + "ImmutableSet": false, + "Implementations": false, + "LinkedCustomHashSet": false, + "LinkedHashSet": false, + "OrderedSet": false, + "RBTreeSet": false, + "SortedSet": false, + "Wrappers": false + }, + "Async": { + "Enabled": false + } + }, + "Character": { + "Enabled": false, + "Base": { + "Enabled": false + }, + "Boolean": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Byte": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Short": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Character": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Integer": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Long": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Float": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Double": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Object": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Collection": { + "Enabled": false, + "IArray": false, + "Splititerators": false, + "Strategy": false, + "Streams": true + }, + "PriorityQueue": { + "Enabled": false, + "ArrayPrioQueue": false, + "Dequeue": false, + "FiFoQueue": false, + "HeapQueue": false, + "Implementations": false, + "Wrappers": false + }, + "List": { + "Enabled": false, + "ArrayList": false, + "CopyOnWriteList": false, + "ImmutableList": false, + "Implementations": false, + "LinkedList": false, + "Wrappers": false + }, + "Set": { + "Enabled": false, + "AVLTreeSet": false, + "ArraySet": false, + "CustomHashSet": false, + "HashSet": false, + "ImmutableSet": false, + "Implementations": false, + "LinkedCustomHashSet": false, + "LinkedHashSet": false, + "OrderedSet": false, + "RBTreeSet": false, + "SortedSet": false, + "Wrappers": false + }, + "Async": { + "Enabled": false + } + }, + "Integer": { + "Enabled": true, + "Base": { + "Enabled": true + }, + "Boolean": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Byte": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Short": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Character": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Integer": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Long": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Float": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Double": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Object": { + "Enabled": true, + "Function": { + "Enabled": true + }, + "Map": { + "Enabled": true, + "AVLTreeMap": false, + "ArrayMap": true, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": true, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": true, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Collection": { + "Enabled": true, + "IArray": true, + "Splititerators": true, + "Strategy": false, + "Streams": true + }, + "PriorityQueue": { + "Enabled": false, + "ArrayPrioQueue": false, + "Dequeue": false, + "FiFoQueue": false, + "HeapQueue": false, + "Implementations": false, + "Wrappers": false + }, + "List": { + "Enabled": false, + "ArrayList": false, + "CopyOnWriteList": false, + "ImmutableList": false, + "Implementations": false, + "LinkedList": false, + "Wrappers": false + }, + "Set": { + "Enabled": true, + "AVLTreeSet": false, + "ArraySet": false, + "CustomHashSet": false, + "HashSet": false, + "ImmutableSet": false, + "Implementations": false, + "LinkedCustomHashSet": false, + "LinkedHashSet": false, + "OrderedSet": true, + "RBTreeSet": false, + "SortedSet": false, + "Wrappers": false + }, + "Async": { + "Enabled": false + } + }, + "Long": { + "Enabled": true, + "Base": { + "Enabled": true + }, + "Boolean": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Byte": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Short": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Character": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Integer": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Long": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Float": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Double": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Object": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Collection": { + "Enabled": true, + "IArray": false, + "Splititerators": true, + "Strategy": false, + "Streams": true + }, + "PriorityQueue": { + "Enabled": false, + "ArrayPrioQueue": false, + "Dequeue": false, + "FiFoQueue": false, + "HeapQueue": false, + "Implementations": false, + "Wrappers": false + }, + "List": { + "Enabled": false, + "ArrayList": false, + "CopyOnWriteList": false, + "ImmutableList": false, + "Implementations": false, + "LinkedList": false, + "Wrappers": false + }, + "Set": { + "Enabled": true, + "AVLTreeSet": false, + "ArraySet": false, + "CustomHashSet": false, + "HashSet": true, + "ImmutableSet": false, + "Implementations": true, + "LinkedCustomHashSet": false, + "LinkedHashSet": false, + "OrderedSet": false, + "RBTreeSet": false, + "SortedSet": false, + "Wrappers": false + }, + "Async": { + "Enabled": false + } + }, + "Float": { + "Enabled": false, + "Base": { + "Enabled": false + }, + "Boolean": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Byte": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Short": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Character": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Integer": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Long": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Float": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Double": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Object": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Collection": { + "Enabled": false, + "IArray": false, + "Splititerators": false, + "Strategy": false, + "Streams": true + }, + "PriorityQueue": { + "Enabled": false, + "ArrayPrioQueue": false, + "Dequeue": false, + "FiFoQueue": false, + "HeapQueue": false, + "Implementations": false, + "Wrappers": false + }, + "List": { + "Enabled": false, + "ArrayList": false, + "CopyOnWriteList": false, + "ImmutableList": false, + "Implementations": false, + "LinkedList": false, + "Wrappers": false + }, + "Set": { + "Enabled": false, + "AVLTreeSet": false, + "ArraySet": false, + "CustomHashSet": false, + "HashSet": false, + "ImmutableSet": false, + "Implementations": false, + "LinkedCustomHashSet": false, + "LinkedHashSet": false, + "OrderedSet": false, + "RBTreeSet": false, + "SortedSet": false, + "Wrappers": false + }, + "Async": { + "Enabled": false + } + }, + "Double": { + "Enabled": false, + "Base": { + "Enabled": false + }, + "Boolean": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Byte": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Short": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Character": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Integer": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Long": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Float": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Double": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Object": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Collection": { + "Enabled": false, + "IArray": false, + "Splititerators": false, + "Strategy": false, + "Streams": true + }, + "PriorityQueue": { + "Enabled": false, + "ArrayPrioQueue": false, + "Dequeue": false, + "FiFoQueue": false, + "HeapQueue": false, + "Implementations": false, + "Wrappers": false + }, + "List": { + "Enabled": false, + "ArrayList": false, + "CopyOnWriteList": false, + "ImmutableList": false, + "Implementations": false, + "LinkedList": false, + "Wrappers": false + }, + "Set": { + "Enabled": false, + "AVLTreeSet": false, + "ArraySet": false, + "CustomHashSet": false, + "HashSet": false, + "ImmutableSet": false, + "Implementations": false, + "LinkedCustomHashSet": false, + "LinkedHashSet": false, + "OrderedSet": false, + "RBTreeSet": false, + "SortedSet": false, + "Wrappers": false + }, + "Async": { + "Enabled": false + } + }, + "Object": { + "Enabled": true, + "Base": { + "Enabled": true + }, + "Boolean": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Byte": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Short": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Character": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Integer": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Long": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Float": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Double": { + "Enabled": false, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": false, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": false, + "ImmutableMap": false, + "Implementations": false, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Object": { + "Enabled": true, + "Function": { + "Enabled": false + }, + "Map": { + "Enabled": true, + "AVLTreeMap": false, + "ArrayMap": false, + "ConcurrentMap": false, + "CustomHashMap": false, + "EnumMap": false, + "HashMap": true, + "ImmutableMap": false, + "Implementations": true, + "LinkedCustomHashMap": false, + "LinkedEnumMap": false, + "LinkedHashMap": false, + "OrderedMap": false, + "RBTreeMap": false, + "SortedMap": false, + "Wrappers": false + }, + "Pair": { + "Enabled": false, + "Immutable": false, + "Mutable": false + } + }, + "Collection": { + "Enabled": true, + "IArray": false, + "Splititerators": true, + "Strategy": false, + "Streams": true + }, + "PriorityQueue": { + "Enabled": false, + "ArrayPrioQueue": false, + "Dequeue": false, + "FiFoQueue": false, + "HeapQueue": false, + "Implementations": false, + "Wrappers": false + }, + "List": { + "Enabled": true, + "ArrayList": true, + "CopyOnWriteList": false, + "ImmutableList": false, + "Implementations": true, + "LinkedList": false, + "Wrappers": false + }, + "Set": { + "Enabled": true, + "AVLTreeSet": false, + "ArraySet": false, + "CustomHashSet": false, + "HashSet": true, + "ImmutableSet": false, + "Implementations": true, + "LinkedCustomHashSet": false, + "LinkedHashSet": false, + "OrderedSet": true, + "RBTreeSet": false, + "SortedSet": false, + "Wrappers": false + }, + "Async": { + "Enabled": false + } + } +} diff --git a/src/main/resources/letsencrypt/isrg-root-x2.pem b/src/main/resources/letsencrypt/isrg-root-x2.pem new file mode 100644 index 000000000..7d903edc9 --- /dev/null +++ b/src/main/resources/letsencrypt/isrg-root-x2.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- diff --git a/src/main/resources/letsencrypt/isrgrootx1.pem b/src/main/resources/letsencrypt/isrgrootx1.pem new file mode 100644 index 000000000..b85c8037f --- /dev/null +++ b/src/main/resources/letsencrypt/isrgrootx1.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- diff --git a/src/main/resources/mixins.archaicfix.early.json b/src/main/resources/mixins.archaicfix.early.json new file mode 100644 index 000000000..e092697c0 --- /dev/null +++ b/src/main/resources/mixins.archaicfix.early.json @@ -0,0 +1,8 @@ +{ + "required": true, + "minVersion": "0.7.11", + "package": "org.embeddedt.archaicfix.mixins", + "refmap": "mixins.archaicfix.refmap.json", + "target": "@env(DEFAULT)", + "compatibilityLevel": "JAVA_8" +} \ No newline at end of file diff --git a/src/main/resources/mixins.archaicfix.json b/src/main/resources/mixins.archaicfix.json new file mode 100644 index 000000000..b4e0f892b --- /dev/null +++ b/src/main/resources/mixins.archaicfix.json @@ -0,0 +1,9 @@ +{ + "required": true, + "minVersion": "0.7.11", + "package": "org.embeddedt.archaicfix.mixins", + "refmap": "mixins.archaicfix.refmap.json", + "target": "@env(DEFAULT)", + "compatibilityLevel": "JAVA_8" +} + diff --git a/src/main/resources/mixins.archaicfix.late.json b/src/main/resources/mixins.archaicfix.late.json new file mode 100644 index 000000000..b4e0f892b --- /dev/null +++ b/src/main/resources/mixins.archaicfix.late.json @@ -0,0 +1,9 @@ +{ + "required": true, + "minVersion": "0.7.11", + "package": "org.embeddedt.archaicfix.mixins", + "refmap": "mixins.archaicfix.refmap.json", + "target": "@env(DEFAULT)", + "compatibilityLevel": "JAVA_8" +} + diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta new file mode 100644 index 000000000..0c5f6bcaf --- /dev/null +++ b/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "pack_format": 1, + "description": "ArchaicFix resources" + } +} \ No newline at end of file diff --git a/src/main/resources/resourcepacks/vanilla_overrides/assets/minecraft/textures/blocks/double_plant_grass_bottom.png b/src/main/resources/resourcepacks/vanilla_overrides/assets/minecraft/textures/blocks/double_plant_grass_bottom.png new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/resources/resourcepacks/vanilla_overrides/assets/minecraft/textures/blocks/double_plant_grass_top.png b/src/main/resources/resourcepacks/vanilla_overrides/assets/minecraft/textures/blocks/double_plant_grass_top.png new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/resources/resourcepacks/vanilla_overrides/assets/minecraft/textures/blocks/tallgrass.png b/src/main/resources/resourcepacks/vanilla_overrides/assets/minecraft/textures/blocks/tallgrass.png new file mode 100644 index 000000000..e69de29bb From d5b7bac56e034cfd1bb18de4303936e5b6182a5f Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 24 Sep 2023 09:19:14 -0700 Subject: [PATCH 004/301] Get NotFine & Arhcaic mixins working. --- .../angelica/loading/AngelicaLateMixins.java | 61 + .../angelica/loading/AngelicaTweaker.java | 80 +- .../angelica/mixins/ArchaicMixins.java | 177 ++ .../angelica/mixins/TargetedMod.java | 11 + .../client/core/AccessorSplashProgress.java | 10 +- .../archaic}/client/core/MixinBlockFence.java | 2 +- .../client/core/MixinChunkProviderClient.java | 4 +- .../client/core/MixinEntityRenderer.java | 3 +- .../client/core/MixinFMLClientHandler.java | 2 +- .../client/core/MixinGuiBeaconButton.java | 7 +- .../archaic}/client/core/MixinGuiButton.java | 2 +- .../client/core/MixinGuiCreateWorld.java | 6 +- .../client/core/MixinGuiIngameForge.java | 2 +- .../client/core/MixinIntegratedServer.java | 2 +- .../archaic}/client/core/MixinMinecraft.java | 16 +- .../core/MixinNetHandlerLoginClient.java | 2 +- .../core/MixinNetHandlerPlayClient.java | 4 +- .../archaic}/client/core/MixinRenderItem.java | 7 +- .../client/core/MixinSkinManager.java | 2 +- .../client/core/MixinSplashProgress.java | 57 +- .../core/MixinThreadDownloadImageData.java | 4 +- .../client/core/MixinWorldRenderer.java | 10 +- .../client/lighting/MixinChunkCache.java | 2 +- .../client/lighting/MixinMinecraft.java | 2 +- .../archaic}/client/lighting/MixinWorld.java | 3 +- .../archaic}/client/occlusion/MixinChunk.java | 12 +- .../client/occlusion/MixinEntityRenderer.java | 2 +- .../occlusion/MixinGuiVideoSettings.java | 2 +- .../client/occlusion/MixinRenderGlobal.java | 12 +- .../client/occlusion/MixinWorldRenderer.java | 13 +- .../renderdistance/MixinGameSettings.java | 3 +- .../renderdistance/MixinRenderGlobal.java | 8 +- .../threadedupdates/MixinRenderBlocks.java | 4 +- .../threadedupdates/MixinTessellator.java | 6 +- .../MixinTessellator_Debug.java | 2 +- .../threadedupdates/MixinWorldRenderer.java | 4 +- .../MixinPlayerChunkViewerManager.java | 2 +- .../common/core/AccessorEntityLiving.java | 2 +- .../archaic}/common/core/MixinASMData.java | 8 +- .../common/core/MixinAxisAlignedBB.java | 2 +- .../archaic}/common/core/MixinBlock.java | 6 +- .../archaic}/common/core/MixinChunk.java | 36 +- .../common/core/MixinChunkProviderHell.java | 2 +- .../common/core/MixinChunkProviderServer.java | 18 +- .../common/core/MixinEmbeddedChannel.java | 14 +- .../common/core/MixinEnchantmentHelper.java | 2 +- .../common/core/MixinEntityLiving.java | 28 + .../common/core/MixinEntityPlayerMP.java | 4 +- .../common/core/MixinEntityTrackerEntry.java | 7 +- .../common/core/MixinEntityVillager.java | 2 +- .../common/core/MixinEntityXPOrb.java | 2 +- .../common/core/MixinForgeChunkManager.java | 2 +- .../common/core/MixinLongHashMap.java | 3 +- .../common/core/MixinMapGenStructure.java | 13 +- .../common/core/MixinMaterialLiquid.java | 2 +- .../common/core/MixinMerchantRecipe.java | 2 +- .../common/core/MixinModCandidate.java | 6 +- .../core/MixinNetHandlerPlayServer.java | 2 +- .../common/core/MixinNetworkDispatcher.java | 6 +- .../common/core/MixinNetworkManager.java | 5 +- .../common/core/MixinNextTickListEntry.java | 2 +- .../core/MixinObjectIntIdentityMap.java | 2 +- .../common/core/MixinSpawnerAnimals.java | 15 +- .../common/core/MixinStructureStart.java | 6 +- .../archaic}/common/core/MixinWorld.java | 105 +- .../common/core/MixinWorldChunkManager.java | 2 +- .../common/core/MixinWorldServer.java | 19 +- .../extrautils/MixinEventHandlerServer.java | 2 +- .../extrautils/MixinEventHandlerSiege.java | 2 +- .../extrautils/MixinItemDivisionSigil.java | 2 +- .../extrautils/MixinTileEntityTrashCan.java | 2 +- .../lighting/MixinAnvilChunkLoader.java | 2 +- .../archaic}/common/lighting/MixinChunk.java | 8 +- .../lighting/MixinChunkProviderServer.java | 5 +- .../common/lighting/MixinChunkVanilla.java | 6 +- .../lighting/MixinExtendedBlockStorage.java | 2 +- .../lighting/MixinSPacketChunkData.java | 2 +- .../common/lighting/MixinWorld_Lighting.java | 4 +- .../renderdistance/MixinPlayerManager.java | 3 +- .../notfine}/clouds/MixinEntityRenderer.java | 2 +- .../notfine}/clouds/MixinGameSettings.java | 2 +- .../notfine}/clouds/MixinRenderGlobal.java | 2 +- .../early/notfine}/clouds/MixinWorldType.java | 2 +- .../notfine}/glint/MixinItemRenderer.java | 2 +- .../notfine}/glint/MixinRenderBiped.java | 2 +- .../early/notfine}/glint/MixinRenderItem.java | 2 +- .../notfine}/glint/MixinRenderPlayer.java | 2 +- .../early/notfine}/gui/MixinGuiSlot.java | 2 +- .../notfine}/leaves/MixinBlockLeaves.java | 2 +- .../notfine}/leaves/MixinBlockLeavesBase.java | 2 +- .../particles/MixinBlockEnchantmentTable.java | 2 +- .../particles/MixinEffectRenderer.java | 2 +- .../notfine}/particles/MixinWorldClient.java | 2 +- .../particles/MixinWorldProvider.java | 2 +- .../notfine/renderer}/MixinRenderGlobal.java | 4 +- .../notfine/settings}/MixinGameSettings.java | 2 +- .../notfine}/toggle/MixinEntityRenderer.java | 2 +- .../early/notfine}/toggle/MixinGuiIngame.java | 2 +- .../early/notfine}/toggle/MixinRender.java | 2 +- .../notfine}/toggle/MixinRenderItem.java | 2 +- .../early/renderer/MixinRenderGlobal.java | 113 +- .../botania/MixinBlockSpecialFlower.java | 2 +- .../common/mrtjp/MixinBlockUpdateHandler.java | 2 +- .../client/journeymap/MixinTileDrawStep.java | 2 +- .../thaumcraft}/MixinBlockMagicalLeaves.java | 2 +- .../twilightforest}/MixinBlockTFLeaves.java | 21 +- .../twilightforest}/MixinBlockTFLeaves3.java | 21 +- .../MixinBlockTFMagicLeaves.java | 34 +- .../witchery}/MixinBlockWitchLeaves.java | 21 +- .../mixinplugin/NotFineEarlyMixins.java | 83 - .../mixinplugin/NotFineLateMixins.java | 59 - .../org/embeddedt/archaicfix/ArchaicCore.java | 91 - .../org/embeddedt/archaicfix/ArchaicFix.java | 121 +- .../org/embeddedt/archaicfix/FixHelper.java | 44 +- .../archaicfix/LeftClickEventHandler.java | 89 - .../archaicfix/asm/ArchaicTransformer.java | 22 - .../archaicfix/asm/LateMixinPlugin.java | 41 - .../org/embeddedt/archaicfix/asm/Mixin.java | 164 -- .../embeddedt/archaicfix/asm/TargetedMod.java | 39 - .../transformer/ThreadedBlockTransformer.java | 88 - .../asm/transformer/VampirismTransformer.java | 56 - .../archaicfix/block/ThreadedBlockData.java | 2 - .../archaicfix/config/ArchaicConfig.java | 52 +- .../config/ConfigurationManager.java | 19 +- .../config/IConfigElementProxy.java | 1 + .../archaicfix/config/SimpleGuiConfig.java | 2 +- .../archaicfix/ducks/IArchaicWorld.java | 7 - .../helpers/BuiltInResourcePack.java | 78 +- .../archaicfix/helpers/DragonAPIHelper.java | 1 - .../archaicfix/helpers/LetsEncryptHelper.java | 58 - .../helpers/LoadControllerHelper.java | 7 +- .../archaicfix/helpers/OreDictIterator.java | 7 +- .../helpers/WorldRendererDistanceHelper.java | 2 - .../IAcceleratedRecipe.java | 3 +- .../IArchaicNetworkManager.java | 2 +- .../ILazyChunkProviderServer.java | 2 +- .../{ducks => interfaces}/IPendingChunk.java | 2 +- .../{ducks => interfaces}/IWorldRenderer.java | 2 +- .../core/MixinGuiContainerCreative.java | 127 - .../optifine/MixinVersionCheckThread.java | 16 - .../mixins/common/core/MixinEntity.java | 23 - .../mixins/common/core/MixinEntityItem.java | 55 - .../mixins/common/core/MixinEntityLiving.java | 102 - .../common/core/MixinOreDictionary.java | 41 - .../common/core/MixinShapedOreRecipe.java | 55 - .../common/core/MixinShapedRecipes.java | 36 - .../common/core/MixinShapelessOreRecipe.java | 52 - .../common/core/MixinShapelessRecipes.java | 44 - .../common/lighting/fastcraft/MixinChunk.java | 35 - .../fastcraft/MixinChunkProviderServer.java | 15 - .../common/lighting/fastcraft/MixinWorld.java | 14 - .../embeddedt/archaicfix/mixins/generate.sh | 16 - .../archaicfix/occlusion/CameraInfo.java | 11 +- .../archaicfix/occlusion/ChunkThread.java | 13 +- .../DefaultRendererUpdateOrderProvider.java | 3 +- .../occlusion/OcclusionHelpers.java | 6 - .../occlusion/OcclusionRenderer.java | 90 +- .../archaicfix/occlusion/OcclusionWorker.java | 27 +- .../archaicfix/occlusion/SetVisibility.java | 39 +- .../archaicfix/occlusion/VisGraph.java | 141 +- .../{ => interfaces}/ICulledChunk.java | 2 +- .../IRenderGlobalListener.java | 2 +- .../IRendererUpdateOrderProvider.java | 8 +- .../{ => interfaces}/IWorldRenderer.java | 4 +- .../occlusion/util/LinkedHashList.java | 10 +- .../archaicfix/proxy/ClientProxy.java | 4 +- .../archaicfix/proxy/CommonProxy.java | 4 +- .../archaicfix/recipe/RecipeCacheLoader.java | 2 +- .../ThreadedChunkUpdateHelper.java | 20 +- .../{LoliHelpers.java => RongHelpers.java} | 16 +- ...{LoliReflector.java => RongReflector.java} | 23 +- .../{LoliStringPool.java => StringPool.java} | 2 +- src/main/resources/ModulSettings.json | 2624 ----------------- .../resources/letsencrypt/isrg-root-x2.pem | 14 - src/main/resources/letsencrypt/isrgrootx1.pem | 31 - src/main/resources/mcmod.info | 18 + .../resources/mixins.archaicfix.early.json | 8 - src/main/resources/mixins.archaicfix.json | 9 - .../resources/mixins.archaicfix.late.json | 9 - src/main/resources/mixins.notfine.early.json | 8 - src/main/resources/mixins.notfine.json | 11 - src/main/resources/mixins.notfine.late.json | 8 - src/main/resources/pack.mcmeta | 4 +- 183 files changed, 934 insertions(+), 5187 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/AccessorSplashProgress.java (64%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinBlockFence.java (91%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinChunkProviderClient.java (80%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinEntityRenderer.java (79%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinFMLClientHandler.java (92%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinGuiBeaconButton.java (61%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinGuiButton.java (92%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinGuiCreateWorld.java (82%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinGuiIngameForge.java (92%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinIntegratedServer.java (93%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinMinecraft.java (87%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinNetHandlerLoginClient.java (92%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinNetHandlerPlayClient.java (95%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinRenderItem.java (78%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinSkinManager.java (93%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinSplashProgress.java (76%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinThreadDownloadImageData.java (93%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/core/MixinWorldRenderer.java (89%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/lighting/MixinChunkCache.java (92%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/lighting/MixinMinecraft.java (94%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/lighting/MixinWorld.java (91%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/occlusion/MixinChunk.java (90%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/occlusion/MixinEntityRenderer.java (91%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/occlusion/MixinGuiVideoSettings.java (86%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/occlusion/MixinRenderGlobal.java (93%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/occlusion/MixinWorldRenderer.java (85%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/renderdistance/MixinGameSettings.java (84%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/renderdistance/MixinRenderGlobal.java (88%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/threadedupdates/MixinRenderBlocks.java (97%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/threadedupdates/MixinTessellator.java (93%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/threadedupdates/MixinTessellator_Debug.java (95%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/client/threadedupdates/MixinWorldRenderer.java (97%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/chickenchunks/MixinPlayerChunkViewerManager.java (94%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/AccessorEntityLiving.java (81%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinASMData.java (76%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinAxisAlignedBB.java (94%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinBlock.java (89%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinChunk.java (77%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinChunkProviderHell.java (92%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinChunkProviderServer.java (60%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinEmbeddedChannel.java (91%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinEnchantmentHelper.java (96%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinEntityPlayerMP.java (95%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinEntityTrackerEntry.java (91%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinEntityVillager.java (95%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinEntityXPOrb.java (86%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinForgeChunkManager.java (94%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinLongHashMap.java (81%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinMapGenStructure.java (57%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinMaterialLiquid.java (86%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinMerchantRecipe.java (93%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinModCandidate.java (90%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinNetHandlerPlayServer.java (90%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinNetworkDispatcher.java (89%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinNetworkManager.java (86%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinNextTickListEntry.java (95%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinObjectIntIdentityMap.java (93%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinSpawnerAnimals.java (68%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinStructureStart.java (76%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinWorld.java (52%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinWorldChunkManager.java (96%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/core/MixinWorldServer.java (74%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/extrautils/MixinEventHandlerServer.java (91%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/extrautils/MixinEventHandlerSiege.java (89%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/extrautils/MixinItemDivisionSigil.java (92%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/extrautils/MixinTileEntityTrashCan.java (89%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/lighting/MixinAnvilChunkLoader.java (96%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/lighting/MixinChunk.java (98%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/lighting/MixinChunkProviderServer.java (89%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/lighting/MixinChunkVanilla.java (92%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/lighting/MixinExtendedBlockStorage.java (97%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/lighting/MixinSPacketChunkData.java (94%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/lighting/MixinWorld_Lighting.java (94%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/early/archaic}/common/renderdistance/MixinPlayerManager.java (83%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/clouds/MixinEntityRenderer.java (93%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/clouds/MixinGameSettings.java (88%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/clouds/MixinRenderGlobal.java (99%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/clouds/MixinWorldType.java (87%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/glint/MixinItemRenderer.java (92%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/glint/MixinRenderBiped.java (92%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/glint/MixinRenderItem.java (97%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/glint/MixinRenderPlayer.java (92%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/gui/MixinGuiSlot.java (92%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/leaves/MixinBlockLeaves.java (96%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/leaves/MixinBlockLeavesBase.java (91%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/particles/MixinBlockEnchantmentTable.java (96%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/particles/MixinEffectRenderer.java (98%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/particles/MixinWorldClient.java (90%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/particles/MixinWorldProvider.java (90%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine/renderer}/MixinRenderGlobal.java (88%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine/settings}/MixinGameSettings.java (99%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/toggle/MixinEntityRenderer.java (92%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/toggle/MixinGuiIngame.java (91%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/toggle/MixinRender.java (92%) rename src/main/java/{jss/notfine/mixins/early/minecraft => com/gtnewhorizons/angelica/mixins/early/notfine}/toggle/MixinRenderItem.java (93%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/late/archaic}/common/botania/MixinBlockSpecialFlower.java (90%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/late/archaic}/common/mrtjp/MixinBlockUpdateHandler.java (92%) rename src/main/java/{org/embeddedt/archaicfix/mixins => com/gtnewhorizons/angelica/mixins/late}/client/journeymap/MixinTileDrawStep.java (88%) rename src/main/java/{jss/notfine/mixins/late/thaumcraft/leaves => com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft}/MixinBlockMagicalLeaves.java (96%) rename src/main/java/{jss/notfine/mixins/late/twilightforest/leaves => com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest}/MixinBlockTFLeaves.java (69%) rename src/main/java/{jss/notfine/mixins/late/twilightforest/leaves => com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest}/MixinBlockTFLeaves3.java (66%) rename src/main/java/{jss/notfine/mixins/late/twilightforest/leaves => com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest}/MixinBlockTFMagicLeaves.java (64%) rename src/main/java/{jss/notfine/mixins/late/witchery/leaves => com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery}/MixinBlockWitchLeaves.java (77%) delete mode 100644 src/main/java/jss/notfine/mixinplugin/NotFineEarlyMixins.java delete mode 100644 src/main/java/jss/notfine/mixinplugin/NotFineLateMixins.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/ArchaicCore.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/LeftClickEventHandler.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/asm/ArchaicTransformer.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/asm/LateMixinPlugin.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/asm/Mixin.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/asm/TargetedMod.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/asm/transformer/ThreadedBlockTransformer.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/asm/transformer/VampirismTransformer.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/ducks/IArchaicWorld.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/LetsEncryptHelper.java rename src/main/java/org/embeddedt/archaicfix/{ducks => interfaces}/IAcceleratedRecipe.java (71%) rename src/main/java/org/embeddedt/archaicfix/{ducks => interfaces}/IArchaicNetworkManager.java (78%) rename src/main/java/org/embeddedt/archaicfix/{ducks => interfaces}/ILazyChunkProviderServer.java (70%) rename src/main/java/org/embeddedt/archaicfix/{ducks => interfaces}/IPendingChunk.java (81%) rename src/main/java/org/embeddedt/archaicfix/{ducks => interfaces}/IWorldRenderer.java (59%) delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiContainerCreative.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/client/optifine/MixinVersionCheckThread.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntity.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityItem.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityLiving.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinOreDictionary.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedOreRecipe.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedRecipes.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessOreRecipe.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessRecipes.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunk.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunkProviderServer.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinWorld.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/mixins/generate.sh rename src/main/java/org/embeddedt/archaicfix/occlusion/{ => interfaces}/ICulledChunk.java (77%) rename src/main/java/org/embeddedt/archaicfix/occlusion/{ => interfaces}/IRenderGlobalListener.java (80%) rename src/main/java/org/embeddedt/archaicfix/occlusion/{ => interfaces}/IRendererUpdateOrderProvider.java (92%) rename src/main/java/org/embeddedt/archaicfix/occlusion/{ => interfaces}/IWorldRenderer.java (59%) rename src/main/java/zone/rong/rongasm/api/{LoliHelpers.java => RongHelpers.java} (80%) rename src/main/java/zone/rong/rongasm/api/{LoliReflector.java => RongReflector.java} (91%) rename src/main/java/zone/rong/rongasm/api/{LoliStringPool.java => StringPool.java} (99%) delete mode 100644 src/main/resources/ModulSettings.json delete mode 100644 src/main/resources/letsencrypt/isrg-root-x2.pem delete mode 100644 src/main/resources/letsencrypt/isrgrootx1.pem delete mode 100644 src/main/resources/mixins.archaicfix.early.json delete mode 100644 src/main/resources/mixins.archaicfix.json delete mode 100644 src/main/resources/mixins.archaicfix.late.json delete mode 100644 src/main/resources/mixins.notfine.early.json delete mode 100644 src/main/resources/mixins.notfine.json delete mode 100644 src/main/resources/mixins.notfine.late.json diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java index 3bb7f6545..bb6ced6f1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java @@ -2,12 +2,24 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Set; import com.gtnewhorizon.gtnhmixins.ILateMixinLoader; import com.gtnewhorizon.gtnhmixins.LateMixin; +import com.gtnewhorizons.angelica.mixins.ArchaicMixins; import com.gtnewhorizons.angelica.mixins.Mixins; +import com.gtnewhorizons.angelica.mixins.TargetedMod; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.versioning.ArtifactVersion; +import cpw.mods.fml.common.versioning.DefaultArtifactVersion; +import cpw.mods.fml.common.versioning.InvalidVersionSpecificationException; +import cpw.mods.fml.common.versioning.VersionRange; + +import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.coreMods; @LateMixin public class AngelicaLateMixins implements ILateMixinLoader { @@ -31,7 +43,56 @@ public List getMixins(Set loadedMods) { } } AngelicaTweaker.LOGGER.info("Not loading the following LATE mixins: {}", notLoading.toString()); + mixins.addAll(getNotFineMixins(loadedMods)); + mixins.addAll(getArchaicMixins(loadedMods)); return mixins; } + private List getNotFineMixins(Set loadedMods) { + final List mixins = new ArrayList<>(); + + if(loadedMods.contains("Thaumcraft")) { + mixins.add("leaves.thaumcraft.MixinBlockMagicalLeaves"); + } + + if(loadedMods.contains("TwilightForest")) { + mixins.add("leaves.twilightforest.MixinBlockTFLeaves"); + mixins.add("leaves.twilightforest.MixinBlockTFLeaves3"); + + //Non-GTNH Twilight Forest builds will break horribly with this mixin. + boolean modernBuild = false; + try { + ArtifactVersion accepted = new DefaultArtifactVersion("TwilightForest", VersionRange.createFromVersionSpec("[2.3.8.18,)")); + ModContainer mc = Loader.instance().getIndexedModList().get("TwilightForest"); + if(mc != null) modernBuild = accepted.containsVersion(mc.getProcessedVersion()); + } catch (InvalidVersionSpecificationException ignored) {} + + if(modernBuild) { + mixins.add("leaves.twilightforest.MixinBlockTFMagicLeaves"); + } + } + + if(loadedMods.contains("witchery")) { + mixins.add("leaves.witchery.MixinBlockWitchLeaves"); + } + return mixins; + } + + public List getArchaicMixins(Set loadedMods) { + List mixins = new ArrayList<>(); + Set validMods = new HashSet<>(coreMods); + HashMap modById = new HashMap<>(); + for(TargetedMod t : TargetedMod.values()) { + if(t.getModId() != null) modById.put(t.getModId(), t); + } + for(String modId : loadedMods) { + TargetedMod t = modById.get(modId); + if(t != null) validMods.add(t); + } + for(ArchaicMixins mixin : ArchaicMixins.values()) { + if(mixin.getPhase() == ArchaicMixins.Phase.LATE && mixin.shouldLoadSide() && mixin.getFilter().test(validMods)) + mixins.addAll(mixin.getMixins()); + } + return mixins; + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index c15d47410..5810e2d97 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -2,12 +2,20 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import com.google.common.collect.ImmutableMap; +import com.gtnewhorizons.angelica.mixins.ArchaicMixins; +import com.gtnewhorizons.angelica.mixins.TargetedMod; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.embeddedt.archaicfix.config.ConfigException; +import org.embeddedt.archaicfix.config.ConfigurationManager; import org.spongepowered.asm.launch.GlobalProperties; import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper; @@ -22,6 +30,14 @@ public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader { public static final Logger LOGGER = LogManager.getLogger("angelica"); + static { + try { + ConfigurationManager.registerConfig(ArchaicConfig.class); + } catch (ConfigException e) { + throw new RuntimeException(e); + } + } + @Override public String[] getASMTransformerClass() { List tweakClasses = GlobalProperties.get(MixinServiceLaunchWrapper.BLACKBOARD_KEY_TWEAKCLASSES); @@ -69,7 +85,69 @@ public List getMixins(Set loadedCoreMods) { } } } - LOGGER.info("Not loading the following EARLY mixins: {}", notLoading.toString()); + LOGGER.info("Not loading the following EARLY mixins: {}", notLoading); + mixins.addAll(getNotFineMixins(loadedCoreMods)); + mixins.addAll(getArchaicMixins(loadedCoreMods)); return mixins; } + + private List getNotFineMixins(Set loadedCoreMods) { + final List mixins = new ArrayList<>(); + mixins.add("notfine.clouds.MixinEntityRenderer"); + mixins.add("notfine.clouds.MixinGameSettings"); + mixins.add("notfine.clouds.MixinRenderGlobal"); + mixins.add("notfine.clouds.MixinWorldType"); + + mixins.add("notfine.glint.MixinItemRenderer"); + mixins.add("notfine.glint.MixinRenderBiped"); + mixins.add("notfine.glint.MixinRenderItem"); + mixins.add("notfine.glint.MixinRenderPlayer"); + + mixins.add("notfine.gui.MixinGuiSlot"); + + mixins.add("notfine.leaves.MixinBlockLeaves"); + mixins.add("notfine.leaves.MixinBlockLeavesBase"); + + mixins.add("notfine.particles.MixinBlockEnchantmentTable"); + mixins.add("notfine.particles.MixinEffectRenderer"); + mixins.add("notfine.particles.MixinWorldClient"); + mixins.add("notfine.particles.MixinWorldProvider"); + + mixins.add("notfine.toggle.MixinGuiIngame"); + mixins.add("notfine.toggle.MixinEntityRenderer"); + mixins.add("notfine.toggle.MixinRender"); + mixins.add("notfine.toggle.MixinRenderItem"); + + mixins.add("notfine.settings.MixinGameSettings"); + mixins.add("notfine.renderer.MixinRenderGlobal"); + return mixins; + } + + private static final ImmutableMap MODS_BY_CLASS = ImmutableMap.builder() + .put("optifine.OptiFineForgeTweaker", TargetedMod.OPTIFINE) + .put("fastcraft.Tweaker", TargetedMod.FASTCRAFT) + .put("cofh.asm.LoadingPlugin", TargetedMod.COFHCORE) + .build(); + public static final Set coreMods = new HashSet<>(); + + private static void detectCoreMods(Set loadedCoreMods) { + MODS_BY_CLASS.forEach((key, value) -> { + if (loadedCoreMods.contains(key)) + coreMods.add(value); + }); + } + + public List getArchaicMixins(Set loadedCoreMods) { + List mixins = new ArrayList<>(); + detectCoreMods(loadedCoreMods); + LOGGER.info("Detected coremods: [" + coreMods.stream().map(TargetedMod::name).collect(Collectors.joining(", ")) + "]"); + for(ArchaicMixins mixin : ArchaicMixins.values()) { + if(mixin.getPhase() == ArchaicMixins.Phase.EARLY && mixin.shouldLoadSide() && mixin.getFilter().test(coreMods)) { + mixins.addAll(mixin.getMixins()); + } + } + return mixins; + } + + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java new file mode 100644 index 000000000..472fa5824 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java @@ -0,0 +1,177 @@ +package com.gtnewhorizons.angelica.mixins; + +import cpw.mods.fml.relauncher.FMLLaunchHandler; +import lombok.Getter; +import org.embeddedt.archaicfix.config.ArchaicConfig; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public enum ArchaicMixins { + // COMMON MIXINS + common_chickenchunks_MixinPlayerChunkViewerManager(Side.COMMON, Phase.EARLY, require(TargetedMod.CHICKENCHUNKS), "chickenchunks.MixinPlayerChunkViewerManager"), + common_core(Side.COMMON, Phase.EARLY, always(), + "core.AccessorEntityLiving", + "core.MixinASMData", + "core.MixinAxisAlignedBB", + "core.MixinBlock", + "core.MixinChunk", + "core.MixinChunkProviderHell", + "core.MixinChunkProviderServer", + "core.MixinEnchantmentHelper", + "core.MixinEntityLiving", + "core.MixinEntityPlayerMP", + "core.MixinEntityTrackerEntry", + "core.MixinEntityVillager", + "core.MixinEntityXPOrb", + "core.MixinForgeChunkManager", + "core.MixinLongHashMap", + "core.MixinMapGenStructure", + "core.MixinMaterialLiquid", + "core.MixinMerchantRecipe", + "core.MixinSpawnerAnimals", + "core.MixinStructureStart", + "core.MixinWorld", + "core.MixinWorldChunkManager", + "core.MixinWorldServer" + ), + common_core_client(Side.CLIENT, Phase.EARLY, always(), + "core.AccessorSplashProgress", + "core.MixinBlockFence", + "core.MixinChunkProviderClient", + "core.MixinEntityRenderer", + "core.MixinFMLClientHandler", + "core.MixinGuiBeaconButton", + "core.MixinGuiButton", + "core.MixinGuiCreateWorld", + "core.MixinGuiIngameForge", + "core.MixinIntegratedServer", + "core.MixinMinecraft", + "core.MixinNetHandlerPlayClient", + "core.MixinSplashProgress", + "core.MixinThreadDownloadImageData", + "core.MixinRenderItem" + ), + + common_core_MixinModCandidate(Side.COMMON, Phase.EARLY, avoid(TargetedMod.COFHCORE), "core.MixinModCandidate"), + common_core_MixinNetworkDispatcher(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetworkDispatcher"), + common_core_MixinNetworkManager(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetworkManager"), + common_core_MixinEmbeddedChannel(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinEmbeddedChannel"), + common_core_MixinNetHandlerPlayServer(Side.COMMON, Phase.EARLY, always(), "core.MixinNetHandlerPlayServer"), + common_core_MixinObjectIntIdentityMap(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.optimizeObjectIntIdentityMap, "core.MixinObjectIntIdentityMap"), + + common_mrtjp_MixinBlockUpdateHandler(Side.COMMON, Phase.LATE, require(TargetedMod.MRTJPCORE), "mrtjp.MixinBlockUpdateHandler"), + + // CLIENT MIXINS + + + + client_core_MixinSkinManager(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.fixSkinMemoryLeak, "core.MixinSkinManager"), + client_core_MixinWorldRenderer(Side.CLIENT, Phase.EARLY, m -> !Boolean.parseBoolean(System.getProperty("archaicFix.disableMC129", "false")), "core.MixinWorldRenderer"), + + client_core_MixinNetHandlerLoginClient(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetHandlerLoginClient"), + + client_lighting_client(Side.CLIENT, Phase.EARLY, phosphor(), + "lighting.MixinMinecraft", + "lighting.MixinWorld", + "lighting.MixinChunkCache"), + + client_lighting_common(Side.COMMON, Phase.EARLY, phosphor(), + "lighting.MixinAnvilChunkLoader", + "lighting.MixinChunk", + "lighting.MixinChunkProviderServer", + "lighting.MixinChunkVanilla", + "lighting.MixinExtendedBlockStorage", + "lighting.MixinSPacketChunkData", + "lighting.MixinWorld_Lighting"), + + client_occlusion(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.enableOcclusionTweaks, + "occlusion.MixinChunk", + "occlusion.MixinEntityRenderer", + "occlusion.MixinRenderGlobal", + "occlusion.MixinGuiVideoSettings", + "occlusion.MixinWorldRenderer"), + + client_renderdistance(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.raiseMaxRenderDistance, + "renderdistance.MixinGameSettings", + "renderdistance.MixinRenderGlobal", + "renderdistance.MixinPlayerManager"), + + client_threadedupdates(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks, + "threadedupdates.MixinRenderBlocks", + "threadedupdates.MixinWorldRenderer", + "threadedupdates.MixinTessellator"), + client_threadedupdates_MixinTessellator_Debug(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks && Boolean.parseBoolean(System.getProperty("archaicfix.debug.verifyTessellatorAccessThread")), "threadedupdates.MixinTessellator_Debug"), + + + common_botania_MixinBlockSpecialFlower(Side.COMMON, Phase.LATE, require(TargetedMod.BOTANIA), "botania.MixinBlockSpecialFlower"), + + common_extrautils(Side.COMMON, Phase.LATE, require(TargetedMod.EXTRAUTILS), + "extrautils.MixinEventHandlerSiege", + "extrautils.MixinEventHandlerServer", + "extrautils.MixinItemDivisionSigil", + "extrautils.MixinTileEntityTrashCan"), + + client_journeymap_MixinTileDrawStep(Side.CLIENT, Phase.LATE, require(TargetedMod.JOURNEYMAP).and(m -> ArchaicConfig.removeJourneymapDebug), "journeymap.MixinTileDrawStep"), + + + // The modFilter argument is a predicate, so you can also use the .and(), .or(), and .negate() methods to mix and match multiple predicates. + ; + + @Getter + public final Side side; + @Getter + public final Phase phase; + + @Getter + public final Predicate> filter; + private final List mixinClasses = new ArrayList<>(); + + ArchaicMixins(Side side, Phase phase, Predicate> filter, String... mixinClasses) { + this.side = side; + this.phase = phase; + this.filter = filter; + this.mixinClasses.addAll(Arrays.asList(mixinClasses)); + } + + static Predicate> phosphor() { + return m -> ArchaicConfig.enablePhosphor; + } + + static Predicate> require(TargetedMod in) { + return modList -> modList.contains(in); + } + + static Predicate> avoid(TargetedMod in) { + return modList -> !modList.contains(in); + } + + static Predicate> always() { + return m -> true; + } + + enum Side { + COMMON, + CLIENT + } + + public enum Phase { + EARLY, + LATE + } + + public boolean shouldLoadSide() { + return (side == Side.COMMON + || (side == Side.CLIENT && FMLLaunchHandler.side().isClient())); + } + + public List getMixins() { + return this.mixinClasses.stream().map((m) -> "archaic." + side.name().toLowerCase(Locale.ROOT) + "." + m).collect(Collectors.toList()); + + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java index 15df372a1..90d6a4646 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java @@ -1,5 +1,7 @@ package com.gtnewhorizons.angelica.mixins; +import lombok.Getter; + public enum TargetedMod { VANILLA("Minecraft", null), @@ -7,14 +9,23 @@ public enum TargetedMod { OPTIFINE("Optifine", "optifine.OptiFineForgeTweaker", "Optifine"), GTNHLIB("GTNHLib", "com.gtnewhorizon.gtnhlib.core.GTNHLibCore", "gtnhlib"), LWJGL3IFY("lwjgl3ify", "me.eigenraven.lwjgl3ify.core.Lwjgl3ifyCoremod", "lwjgl3ify"), + CHICKENCHUNKS("ChickenChunks", null, "ChickenChunks"), + MRTJPCORE("MrTJPCore", null, "MrTJPCoreMod"), + BOTANIA("Botania", null, "Botania"), + COFHCORE("CoFHCore", "cofh.asm.LoadingPlugin", "CoFHCore"), + EXTRAUTILS("ExtraUtilities", null, "ExtraUtilities"), + JOURNEYMAP("JourneyMap", null, "journeymap"), PROJECTRED_ILLUMINATION("ProjectRed Illumination", null, "ProjRed|Illumination"), SMART_RENDER("Smart Render", null, "SmartRender"); /** The "name" in the @Mod annotation */ + @Getter public final String modName; /** Class that implements the IFMLLoadingPlugin interface */ + @Getter public final String coreModClass; /** The "modid" in the @Mod annotation */ + @Getter public final String modId; TargetedMod(String modName, String coreModClass) { diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/AccessorSplashProgress.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/AccessorSplashProgress.java similarity index 64% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/AccessorSplashProgress.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/AccessorSplashProgress.java index 87ca659ce..5c2fd7d08 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/AccessorSplashProgress.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/AccessorSplashProgress.java @@ -1,22 +1,20 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import cpw.mods.fml.client.SplashProgress; -import net.minecraft.client.gui.FontRenderer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(SplashProgress.class) public interface AccessorSplashProgress { - @Accessor("barBorderColor") + @Accessor(value="barBorderColor", remap = false) static int getBarBorderColor() { throw new AssertionError(); } - @Accessor("barBackgroundColor") + @Accessor(value="barBackgroundColor", remap = false) static int getBarBackgroundColor() { throw new AssertionError(); } - @Accessor("fontColor") + @Accessor(value="fontColor", remap = false) static int getFontColor() { throw new AssertionError(); } diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinBlockFence.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinBlockFence.java similarity index 91% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinBlockFence.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinBlockFence.java index f0734996c..452d83efd 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinBlockFence.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinBlockFence.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.block.Block; import net.minecraft.block.BlockFence; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinChunkProviderClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinChunkProviderClient.java similarity index 80% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinChunkProviderClient.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinChunkProviderClient.java index 758eafc3f..fc3aff13e 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinChunkProviderClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinChunkProviderClient.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ChunkProviderClient; @@ -12,7 +12,7 @@ public class MixinChunkProviderClient { @Inject(method = "loadChunk", at = @At("HEAD")) private void onChunkLoad(int x, int z, CallbackInfoReturnable cir) { - if(!Minecraft.getMinecraft().func_152345_ab()) + if(!Minecraft.getMinecraft().func_152345_ab/*isCallingFromMinecraftThread*/()) throw new IllegalStateException("Attempted to load a chunk off-thread!"); } } diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinEntityRenderer.java similarity index 79% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinEntityRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinEntityRenderer.java index 4371178aa..ca3af32bc 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinEntityRenderer.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.EntityRenderer; @@ -11,6 +11,7 @@ @Mixin(value = EntityRenderer.class, priority = 1500) public abstract class MixinEntityRenderer { /** @reason Makes the third-person view camera pass through non-solid blocks (fixes https://bugs.mojang.com/browse/MC-30845) */ + // Note: Overlaps with https://github.com/GTNewHorizons/Hodgepodge/blob/master/src/main/java/com/mitchej123/hodgepodge/mixins/early/minecraft/MixinEntityRenderer.java @Redirect(method = "orientCamera", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;rayTraceBlocks(Lnet/minecraft/util/Vec3;Lnet/minecraft/util/Vec3;)Lnet/minecraft/util/MovingObjectPosition;")) private MovingObjectPosition rayTraceBlocks(WorldClient world, Vec3 from, Vec3 to) { return world.func_147447_a(from, to, false, true, true); diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinFMLClientHandler.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinFMLClientHandler.java similarity index 92% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinFMLClientHandler.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinFMLClientHandler.java index bacd69d92..5893d3ece 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinFMLClientHandler.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinFMLClientHandler.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import cpw.mods.fml.client.FMLClientHandler; import cpw.mods.fml.client.GuiModList; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiBeaconButton.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiBeaconButton.java similarity index 61% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiBeaconButton.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiBeaconButton.java index d64462f07..5d010882f 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiBeaconButton.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiBeaconButton.java @@ -1,7 +1,6 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.inventory.GuiBeacon; import net.minecraft.client.renderer.OpenGlHelper; import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; @@ -14,8 +13,8 @@ public class MixinGuiBeaconButton { /** * Make transparent beacon buttons look right (e.g. with Modernity). */ - @Inject(method = "func_146112_a", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/inventory/GuiBeacon$Button;func_73729_b(IIIIII)V", ordinal = 1), require = 0) - private void enableTransparency(Minecraft p_146112_1_, int p_146112_2_, int p_146112_3_, CallbackInfo ci) { + @Inject(method = "drawButton", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/inventory/GuiBeacon$Button;drawTexturedModalRect(IIIIII)V", ordinal = 1), require = 0) + private void enableTransparency(Minecraft minecraft, int x, int y, CallbackInfo ci) { GL11.glEnable(GL11.GL_BLEND); OpenGlHelper.glBlendFunc(770, 771, 1, 0); } diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiButton.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiButton.java similarity index 92% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiButton.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiButton.java index 2c6873014..0b08439ef 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiButton.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiButton.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiOptionSlider; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiCreateWorld.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiCreateWorld.java similarity index 82% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiCreateWorld.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiCreateWorld.java index 41b0c44d3..147b81c4f 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiCreateWorld.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiCreateWorld.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.gui.GuiCreateWorld; import net.minecraft.world.storage.ISaveFormat; @@ -6,7 +6,6 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(GuiCreateWorld.class) public class MixinGuiCreateWorld { @@ -14,8 +13,7 @@ public class MixinGuiCreateWorld { private static void useNumberForCopies(ISaveFormat format, String worldName, CallbackInfoReturnable cir) { int index = 1; String finalWorldName = worldName; - while (format.getWorldInfo(finalWorldName) != null) - { + while (format.getWorldInfo(finalWorldName) != null) { finalWorldName = worldName + " (" + index + ")"; index++; } diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiIngameForge.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiIngameForge.java similarity index 92% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiIngameForge.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiIngameForge.java index e008cea40..1ce5841f3 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiIngameForge.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiIngameForge.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import cpw.mods.fml.common.ModContainer; import net.minecraft.world.biome.BiomeGenBase; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinIntegratedServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinIntegratedServer.java similarity index 93% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinIntegratedServer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinIntegratedServer.java index 56eb029db..e13628f32 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinIntegratedServer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinIntegratedServer.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.settings.GameSettings; import net.minecraft.server.integrated.IntegratedServer; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinMinecraft.java similarity index 87% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinMinecraft.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinMinecraft.java index 60bbf489e..476bb1e3b 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinMinecraft.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinMinecraft.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; @@ -28,6 +28,7 @@ public abstract class MixinMinecraft { private boolean getFancyGrass(GameSettings gameSettings) { return true; } + /** @reason Removes a call to {@link System#gc()} to make world loading as fast as possible */ @Inject(method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V", at = @At(value = "INVOKE", target = "Ljava/lang/System;gc()V"), cancellable = true) private void onSystemGC(WorldClient worldClient, String reason, CallbackInfo ci) { @@ -46,14 +47,11 @@ private void displayWorkingScreen(Minecraft mc, GuiScreen in) { @Inject(method = "launchIntegratedServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/integrated/IntegratedServer;func_147137_ag()Lnet/minecraft/network/NetworkSystem;", ordinal = 0), cancellable = true) private void checkServerStopped(CallbackInfo ci) { - try - { + try { Thread.sleep(200L); } - catch (InterruptedException interruptedexception) - { - ; - } + catch (InterruptedException ignored) {} + if(this.theIntegratedServer.isServerStopped()) { loadWorld(null); displayGuiScreen(null); @@ -61,8 +59,4 @@ private void checkServerStopped(CallbackInfo ci) { } } - @Redirect(method = "runGameLoop", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/Display;isActive()Z", remap = false)) - private boolean alwaysHaveDisplayActive() { - return true; - } } diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerLoginClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerLoginClient.java similarity index 92% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerLoginClient.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerLoginClient.java index 6e97f2c0a..5e5179dbe 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerLoginClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerLoginClient.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.network.NetHandlerLoginClient; import net.minecraft.network.NetworkManager; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerPlayClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerPlayClient.java similarity index 95% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerPlayClient.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerPlayClient.java index ab136a039..6ec605280 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinNetHandlerPlayClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerPlayClient.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; @@ -28,4 +28,4 @@ private void onGuiDisplayJoin(Minecraft mc, GuiScreen guiScreenIn) { private void onGuiDisplayRespawn(Minecraft mc, GuiScreen guiScreenIn) { mc.displayGuiScreen(ArchaicConfig.hideDownloadingTerrainScreen ? null : guiScreenIn); } -} \ No newline at end of file +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinRenderItem.java similarity index 78% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinRenderItem.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinRenderItem.java index 85249f939..6e096bb5b 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinRenderItem.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.renderer.entity.RenderItem; import net.minecraft.client.settings.GameSettings; @@ -11,9 +11,6 @@ public class MixinRenderItem { @Redirect(method = "renderDroppedItem(Lnet/minecraft/entity/item/EntityItem;Lnet/minecraft/util/IIcon;IFFFFI)V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z")) private boolean forceFancyGraphics(GameSettings settings) { - if(ArchaicConfig.forceFancyItems) - return true; - else - return settings.fancyGraphics; + return ArchaicConfig.forceFancyItems || settings.fancyGraphics; } } diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSkinManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSkinManager.java similarity index 93% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSkinManager.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSkinManager.java index 51ae4892a..9ba6ab4e2 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSkinManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSkinManager.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.resources.SkinManager; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSplashProgress.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSplashProgress.java similarity index 76% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSplashProgress.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSplashProgress.java index 48e93bc40..55c7059c7 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinSplashProgress.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSplashProgress.java @@ -1,9 +1,7 @@ /* * Based off SplashProgress from Forge 14.23.5.2860. */ -package org.embeddedt.archaicfix.mixins.client.core; - -import static org.lwjgl.opengl.GL11.*; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import com.gtnewhorizons.angelica.Tags; import cpw.mods.fml.client.SplashProgress; @@ -12,6 +10,7 @@ import org.embeddedt.archaicfix.ArchaicLogger; import org.embeddedt.archaicfix.config.ArchaicConfig; import org.lwjgl.opengl.Display; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -20,6 +19,14 @@ import java.lang.reflect.Field; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; +import static org.lwjgl.opengl.GL11.glDisable; +import static org.lwjgl.opengl.GL11.glEnable; +import static org.lwjgl.opengl.GL11.glPopMatrix; +import static org.lwjgl.opengl.GL11.glPushMatrix; +import static org.lwjgl.opengl.GL11.glScalef; +import static org.lwjgl.opengl.GL11.glTranslatef; + @Mixin(targets = { "cpw/mods/fml/client/SplashProgress$3" }) public class MixinSplashProgress { private static final int memoryGoodColor = 0x78CB34; @@ -55,24 +62,22 @@ private void injectDrawMemoryBar(CallbackInfo ci) { } } - @Shadow - private void setColor(int color) { - - } + @Shadow(remap = false) + private void setColor(int color) {} - @Shadow - private void drawBox(int w, int h) { + @Shadow(remap = false) + private void drawBox(int w, int h) {} - } - @Shadow + @Final + @Shadow(remap = false) private int barWidth, barHeight, textHeight2; private void drawMemoryBar() { - int maxMemory = bytesToMb(Runtime.getRuntime().maxMemory()); - int totalMemory = bytesToMb(Runtime.getRuntime().totalMemory()); - int freeMemory = bytesToMb(Runtime.getRuntime().freeMemory()); - int usedMemory = totalMemory - freeMemory; - float usedMemoryPercent = usedMemory / (float) maxMemory; + final int maxMemory = bytesToMb(Runtime.getRuntime().maxMemory()); + final int totalMemory = bytesToMb(Runtime.getRuntime().totalMemory()); + final int freeMemory = bytesToMb(Runtime.getRuntime().freeMemory()); + final int usedMemory = totalMemory - freeMemory; + final float usedMemoryPercent = usedMemory / (float) maxMemory; glPushMatrix(); // title - message @@ -93,24 +98,18 @@ private void drawMemoryBar() { drawBox(barWidth - 2, barHeight - 2); // slidy part - long time = System.currentTimeMillis(); - if (usedMemoryPercent > memoryColorPercent || (time - memoryColorChangeTime > 1000)) - { + final long time = System.currentTimeMillis(); + if (usedMemoryPercent > memoryColorPercent || (time - memoryColorChangeTime > 1000)) { memoryColorChangeTime = time; memoryColorPercent = usedMemoryPercent; } - int memoryBarColor; - if (memoryColorPercent < 0.75f) - { + final int memoryBarColor; + if (memoryColorPercent < 0.75f) { memoryBarColor = memoryGoodColor; - } - else if (memoryColorPercent < 0.85f) - { + } else if (memoryColorPercent < 0.85f) { memoryBarColor = memoryWarnColor; - } - else - { + } else { memoryBarColor = memoryLowColor; } setColor(memoryLowColor); @@ -122,7 +121,7 @@ else if (memoryColorPercent < 0.85f) drawBox((barWidth - 2) * (usedMemory) / (maxMemory), barHeight - 2); // progress text - String progress = getMemoryString(usedMemory) + " / " + getMemoryString(maxMemory); + final String progress = getMemoryString(usedMemory) + " / " + getMemoryString(maxMemory); glTranslatef(((float)barWidth - 2) / 2 - fontRenderer.getStringWidth(progress), 2, 0); setColor(AccessorSplashProgress.getFontColor()); glScalef(2, 2, 1); diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinThreadDownloadImageData.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinThreadDownloadImageData.java similarity index 93% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinThreadDownloadImageData.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinThreadDownloadImageData.java index d4fbeed9e..b962c8daf 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinThreadDownloadImageData.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinThreadDownloadImageData.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import com.google.common.util.concurrent.ThreadFactoryBuilder; import net.minecraft.client.renderer.ThreadDownloadImageData; @@ -21,4 +21,4 @@ public final class MixinThreadDownloadImageData { private void onThreadStart(Thread thread) { EXECUTOR.execute(thread); } -} \ No newline at end of file +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinWorldRenderer.java similarity index 89% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinWorldRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinWorldRenderer.java index 3d7e1d228..7fcb205c6 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinWorldRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinWorldRenderer.java @@ -1,9 +1,9 @@ -package org.embeddedt.archaicfix.mixins.client.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.entity.Entity; -import org.embeddedt.archaicfix.ducks.IWorldRenderer; +import org.embeddedt.archaicfix.interfaces.IWorldRenderer; import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -11,6 +11,8 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.Arrays; + /* MC-129 */ @Mixin(WorldRenderer.class) public abstract class MixinWorldRenderer implements IWorldRenderer { @@ -38,9 +40,7 @@ public abstract class MixinWorldRenderer implements IWorldRenderer { */ @Inject(method = "markDirty", at = @At("TAIL")) private void forceRender(CallbackInfo ci) { - for(int i = 0; i < this.skipRenderPass.length; i++) { - this.skipRenderPass[i] = false; - } + Arrays.fill(this.skipRenderPass, false); } /** diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinChunkCache.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinChunkCache.java similarity index 92% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinChunkCache.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinChunkCache.java index 5849765ab..14227f6ce 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinChunkCache.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinChunkCache.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.lighting; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.lighting; import net.minecraft.world.ChunkCache; import net.minecraft.world.EnumSkyBlock; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinMinecraft.java similarity index 94% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinMinecraft.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinMinecraft.java index c57732b4d..9e0110f17 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinMinecraft.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinMinecraft.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.lighting; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.lighting; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinWorld.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java similarity index 91% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinWorld.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java index 5f754691b..90c3892e7 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/lighting/MixinWorld.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.lighting; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.lighting; import net.minecraft.block.Block; import net.minecraft.world.EnumSkyBlock; @@ -12,7 +12,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(World.class) public abstract class MixinWorld { diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinChunk.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinChunk.java similarity index 90% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinChunk.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinChunk.java index bbe0d27d7..31f00e9dd 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinChunk.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinChunk.java @@ -1,16 +1,16 @@ -package org.embeddedt.archaicfix.mixins.client.occlusion; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.occlusion; import net.minecraft.block.Block; -import net.minecraft.client.Minecraft; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; -import org.embeddedt.archaicfix.occlusion.ICulledChunk; import org.embeddedt.archaicfix.occlusion.ChunkThread; +import org.embeddedt.archaicfix.occlusion.interfaces.ICulledChunk; import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; import org.embeddedt.archaicfix.occlusion.VisGraph; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +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.CallbackInfo; @@ -23,9 +23,9 @@ public abstract class MixinChunk implements ICulledChunk { @Shadow public World worldObj; @Shadow @Final public int xPosition; @Shadow @Final public int zPosition; - private VisGraph[] visibility; + @Unique private VisGraph[] visibility; - private static ChunkThread worker = new ChunkThread(); + @Unique private static final ChunkThread worker = new ChunkThread(); static { worker.start(); } @@ -46,7 +46,6 @@ public Chunk buildCulledSides() { } - @Inject(method = "(Lnet/minecraft/world/World;II)V", at = @At("RETURN")) private void onInit(World p_i1995_1_, int p_i1995_2_, int p_i1995_3_, CallbackInfo ci) { visibility = new VisGraph[16]; @@ -60,6 +59,7 @@ public VisGraph[] getVisibility() { return visibility; } + @Unique boolean checkPosSolid(int x, int y, int z, Block block) { if (y > 255 || y < 0) diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinEntityRenderer.java similarity index 91% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinEntityRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinEntityRenderer.java index 779f419d8..8f23d95ea 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinEntityRenderer.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.occlusion; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.occlusion; import net.minecraft.client.renderer.EntityRenderer; import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinGuiVideoSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinGuiVideoSettings.java similarity index 86% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinGuiVideoSettings.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinGuiVideoSettings.java index 2d7b4ff35..360f8b57b 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinGuiVideoSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinGuiVideoSettings.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.occlusion; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.occlusion; import net.minecraft.client.gui.GuiVideoSettings; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinRenderGlobal.java similarity index 93% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinRenderGlobal.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinRenderGlobal.java index bf9ee8ede..0d7ce3f16 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinRenderGlobal.java @@ -1,13 +1,16 @@ -package org.embeddedt.archaicfix.mixins.client.occlusion; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.occlusion; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; -import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.culling.ICamera; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; -import org.embeddedt.archaicfix.occlusion.*; +import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; +import org.embeddedt.archaicfix.occlusion.OcclusionRenderer; +import org.embeddedt.archaicfix.occlusion.OcclusionWorker; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.injection.At; @@ -16,7 +19,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import java.util.*; +import java.util.Comparator; +import java.util.List; @Mixin(value = RenderGlobal.class, priority = -2) public abstract class MixinRenderGlobal { diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java similarity index 85% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinWorldRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java index ff67550d1..da44b48fa 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/occlusion/MixinWorldRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java @@ -1,15 +1,16 @@ -package org.embeddedt.archaicfix.mixins.client.occlusion; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.occlusion; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.shader.TesselatorVertexState; import net.minecraft.entity.EntityLivingBase; import net.minecraft.world.World; import net.minecraft.world.chunk.EmptyChunk; -import org.embeddedt.archaicfix.occlusion.IWorldRenderer; +import org.embeddedt.archaicfix.occlusion.interfaces.IWorldRenderer; import org.embeddedt.archaicfix.occlusion.OcclusionWorker; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +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.CallbackInfo; @@ -38,10 +39,10 @@ public class MixinWorldRenderer implements IWorldRenderer { @Shadow private TesselatorVertexState vertexState; - private boolean arch$isInUpdateList; - private boolean arch$isFrustumCheckPending; + @Unique private boolean arch$isInUpdateList; + @Unique private boolean arch$isFrustumCheckPending; - private OcclusionWorker.CullInfo arch$cullInfo; + @Unique private OcclusionWorker.CullInfo arch$cullInfo; @Inject(method = "*", at = @At("RETURN")) private void init(CallbackInfo ci) { @@ -56,7 +57,7 @@ private void resetOcclusionFlag(CallbackInfo ci) { @Inject(method = "updateRenderer", at = @At(value = "FIELD", opcode = Opcodes.PUTSTATIC, target = "Lnet/minecraft/world/chunk/Chunk;isLit:Z", ordinal = 0), cancellable = true) private void bailOnEmptyChunk(EntityLivingBase view, CallbackInfo ci) { if(worldObj.getChunkFromBlockCoords(posX, posZ) instanceof EmptyChunk) { - if (tileEntityRenderers.size() > 0) { + if (!tileEntityRenderers.isEmpty()) { tileEntities.removeAll(tileEntityRenderers); tileEntityRenderers.clear(); } diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinGameSettings.java similarity index 84% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinGameSettings.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinGameSettings.java index ec56ad989..69966ccc3 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinGameSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinGameSettings.java @@ -1,7 +1,6 @@ -package org.embeddedt.archaicfix.mixins.client.renderdistance; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.renderdistance; import net.minecraft.client.settings.GameSettings; -import org.embeddedt.archaicfix.ArchaicFix; import org.embeddedt.archaicfix.config.ArchaicConfig; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.Constant; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinRenderGlobal.java similarity index 88% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinRenderGlobal.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinRenderGlobal.java index be865da8f..343b0851f 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/renderdistance/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinRenderGlobal.java @@ -1,22 +1,16 @@ -package org.embeddedt.archaicfix.mixins.client.renderdistance; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.renderdistance; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.RenderList; -import org.embeddedt.archaicfix.ArchaicFix; import org.embeddedt.archaicfix.config.ArchaicConfig; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.nio.Buffer; -import java.nio.IntBuffer; - @Mixin(value = RenderGlobal.class, priority = -10) public class MixinRenderGlobal { @Shadow private RenderList[] allRenderLists; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinRenderBlocks.java similarity index 97% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinRenderBlocks.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinRenderBlocks.java index 386b87032..7bb976ed7 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinRenderBlocks.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinRenderBlocks.java @@ -1,11 +1,11 @@ -package org.embeddedt.archaicfix.mixins.client.threadedupdates; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.threadedupdates; import net.minecraft.block.Block; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.Tessellator; import net.minecraftforge.client.ForgeHooksClient; -import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; import org.embeddedt.archaicfix.threadedupdates.IRendererUpdateResultHolder; +import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; import org.embeddedt.archaicfix.threadedupdates.api.ThreadedChunkUpdates; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator.java similarity index 93% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator.java index aa79c87ec..0f445c800 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.threadedupdates; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.threadedupdates; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.shader.TesselatorVertexState; @@ -12,7 +12,7 @@ import java.nio.ByteBuffer; import java.util.Arrays; -@Mixin(Tessellator.class) +@Mixin(value = Tessellator.class, priority = 1001) public abstract class MixinTessellator implements ICapturableTessellator { @Shadow @@ -28,7 +28,7 @@ public abstract class MixinTessellator implements ICapturableTessellator { @Shadow private boolean isDrawing; - @Shadow private int rawBufferSize; + @Shadow(remap = false) private int rawBufferSize; @Shadow private boolean hasTexture; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator_Debug.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator_Debug.java similarity index 95% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator_Debug.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator_Debug.java index cc519a891..9004d08aa 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinTessellator_Debug.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator_Debug.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.threadedupdates; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.threadedupdates; import net.minecraft.client.renderer.Tessellator; import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinWorldRenderer.java similarity index 97% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinWorldRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinWorldRenderer.java index c77099a57..344b81ff5 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/threadedupdates/MixinWorldRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinWorldRenderer.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.threadedupdates; +package com.gtnewhorizons.angelica.mixins.early.archaic.client.threadedupdates; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderBlocks; @@ -6,9 +6,9 @@ import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.entity.EntityLivingBase; import net.minecraft.world.ChunkCache; -import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; import org.embeddedt.archaicfix.threadedupdates.ICapturableTessellator; import org.embeddedt.archaicfix.threadedupdates.IRendererUpdateResultHolder; +import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/chickenchunks/MixinPlayerChunkViewerManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/chickenchunks/MixinPlayerChunkViewerManager.java similarity index 94% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/chickenchunks/MixinPlayerChunkViewerManager.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/chickenchunks/MixinPlayerChunkViewerManager.java index 93b84739c..c17ce3cd8 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/chickenchunks/MixinPlayerChunkViewerManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/chickenchunks/MixinPlayerChunkViewerManager.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.chickenchunks; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.chickenchunks; import codechicken.chunkloader.PlayerChunkViewerManager; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/AccessorEntityLiving.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/AccessorEntityLiving.java similarity index 81% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/AccessorEntityLiving.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/AccessorEntityLiving.java index 60dce2c7d..59215a3a63 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/AccessorEntityLiving.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/AccessorEntityLiving.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.entity.EntityLiving; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinASMData.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinASMData.java similarity index 76% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinASMData.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinASMData.java index 971edb482..47393852a 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinASMData.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinASMData.java @@ -1,11 +1,11 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import cpw.mods.fml.common.discovery.ASMDataTable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import zone.rong.rongasm.api.LoliStringPool; +import zone.rong.rongasm.api.StringPool; @Mixin(value = ASMDataTable.ASMData.class, remap = false) public class MixinASMData { @@ -15,11 +15,11 @@ public class MixinASMData { @Redirect(method = "", at = @At(value = "FIELD", target = "Lcpw/mods/fml/common/discovery/ASMDataTable$ASMData;annotationName:Ljava/lang/String;")) private void canonicalizeAnnotation(ASMDataTable.ASMData instance, String value) { - this.annotationName = value == null ? null : LoliStringPool.canonicalize(value); + this.annotationName = value == null ? null : StringPool.canonicalize(value); } @Redirect(method = "", at = @At(value = "FIELD", target = "Lcpw/mods/fml/common/discovery/ASMDataTable$ASMData;className:Ljava/lang/String;")) private void canonicalizeClassName(ASMDataTable.ASMData instance, String value) { - this.className = value == null ? null : LoliStringPool.canonicalize(value); + this.className = value == null ? null : StringPool.canonicalize(value); } } diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinAxisAlignedBB.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinAxisAlignedBB.java similarity index 94% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinAxisAlignedBB.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinAxisAlignedBB.java index b59bd5a1a..22420f75e 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinAxisAlignedBB.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinAxisAlignedBB.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.util.AxisAlignedBB; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinBlock.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinBlock.java similarity index 89% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinBlock.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinBlock.java index d5db2c59a..a8d2dd1f8 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinBlock.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinBlock.java @@ -1,21 +1,17 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.relauncher.Side; import net.minecraft.block.Block; -import net.minecraft.block.material.Material; import net.minecraft.server.MinecraftServer; import org.embeddedt.archaicfix.block.ThreadedBlockData; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.lang.ref.WeakReference; -import java.util.WeakHashMap; @Mixin(Block.class) public class MixinBlock { diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunk.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java similarity index 77% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunk.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java index 46f9b7be2..4a949b5e6 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunk.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java @@ -1,6 +1,5 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; -import com.google.common.collect.Iterators; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.ModContainer; import net.minecraft.entity.Entity; @@ -13,20 +12,22 @@ import net.minecraft.world.chunk.IChunkProvider; import org.embeddedt.archaicfix.ArchaicLogger; import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.ducks.IArchaicWorld; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; @Mixin(value = Chunk.class, priority = 1100) public class MixinChunk { + @Shadow @Final private List[] entityLists; @Shadow @Final private World worldObj; @@ -40,9 +41,8 @@ public class MixinChunk { public void handlePlayerChunkUnload(CallbackInfo ci) { final List players = new ArrayList<>(); for (final List list : entityLists) { - for(final Entity entity : list) { - if(entity instanceof EntityPlayer) - players.add((EntityPlayer)entity); + for (final Entity entity : list) { + if (entity instanceof EntityPlayer) players.add((EntityPlayer) entity); } } for (final EntityPlayer player : players) { @@ -50,26 +50,16 @@ public void handlePlayerChunkUnload(CallbackInfo ci) { } } - @Redirect(method = "onChunkUnload", at = @At(value = "INVOKE", target = "Ljava/util/Collection;iterator()Ljava/util/Iterator;", ordinal = 0)) - private Iterator markTEForUnload(Collection instance) { - if(ArchaicConfig.fixTEUnloadLag) { - ((IArchaicWorld)this.worldObj).arch$markTileEntitiesInChunkForRemoval((Chunk)(Object)this); - return Iterators.emptyIterator(); - } - return instance.iterator(); - } - @Inject(method = "getBiomeGenForWorldCoords", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/biome/WorldChunkManager;getBiomeGenAt(II)Lnet/minecraft/world/biome/BiomeGenBase;"), cancellable = true) private void avoidBiomeGenOnClient(int p_76591_1_, int p_76591_2_, WorldChunkManager p_76591_3_, CallbackInfoReturnable cir) { - if(this.worldObj.isRemote) { + if (this.worldObj.isRemote) { cir.setReturnValue(BiomeGenBase.ocean); } } private static LinkedList arch$populatingChunk = new LinkedList<>(); // keep track of cascading chunk generation during chunk population - private void logCascadingWorldGeneration() - { + private void logCascadingWorldGeneration() { ModContainer activeModContainer = Loader.instance().activeModContainer(); String format = "{} loaded a new chunk {} in dimension {} ({}) while populating chunk {}, causing cascading worldgen lag."; @@ -82,14 +72,14 @@ private void logCascadingWorldGeneration() ArchaicLogger.LOGGER.warn("Please report this to the mod's issue tracker. This log can be disabled in the ArchaicFix config."); } - if(ArchaicConfig.logCascadingWorldgenStacktrace) { + if (ArchaicConfig.logCascadingWorldgenStacktrace) { ArchaicLogger.LOGGER.warn("Stacktrace", new Exception("Cascading world generation")); } } @Inject(method = "populateChunk", at = @At("HEAD")) private void savePopulatingChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int x, int z, CallbackInfo ci) { - if(arch$populatingChunk.size() > 0 && ArchaicConfig.logCascadingWorldgen) logCascadingWorldGeneration(); + if (arch$populatingChunk.size() > 0 && ArchaicConfig.logCascadingWorldgen) logCascadingWorldGeneration(); arch$populatingChunk.push(new ChunkCoordIntPair(x, z)); } @@ -98,4 +88,4 @@ private void restorePopulatingChunk(IChunkProvider p_76624_1_, IChunkProvider p_ arch$populatingChunk.pop(); } -} \ No newline at end of file +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderHell.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderHell.java similarity index 92% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderHell.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderHell.java index c890f5e51..e73e1a1d0 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderHell.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderHell.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.world.World; import net.minecraft.world.gen.ChunkProviderHell; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderServer.java similarity index 60% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderServer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderServer.java index 2dbcdde6a..3b2cc0f90 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinChunkProviderServer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderServer.java @@ -1,37 +1,25 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.world.WorldServer; import net.minecraft.world.biome.WorldChunkManager; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.IChunkProvider; import net.minecraft.world.gen.ChunkProviderServer; -import net.minecraftforge.common.DimensionManager; -import org.embeddedt.archaicfix.config.ArchaicConfig; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - @Mixin(ChunkProviderServer.class) public abstract class MixinChunkProviderServer { @Shadow public WorldServer worldObj; - @Redirect(method = "unloadChunksIfNotNearSpawn", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/common/DimensionManager;shouldLoadSpawn(I)Z", remap = false)) - private boolean neverLoadSpawn(int dim) { - return !ArchaicConfig.disableSpawnChunks && DimensionManager.shouldLoadSpawn(dim); - } - @Redirect(method = "originalLoadChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/IChunkProvider;provideChunk(II)Lnet/minecraft/world/chunk/Chunk;", remap = true), remap = false) private Chunk populateChunkWithBiomes(IChunkProvider instance, int chunkX, int chunkZ) { - Chunk chunk = instance.provideChunk(chunkX, chunkZ); + final Chunk chunk = instance.provideChunk(chunkX, chunkZ); if(chunk != null) { - WorldChunkManager manager = chunk.worldObj.getWorldChunkManager(); + final WorldChunkManager manager = chunk.worldObj.getWorldChunkManager(); for(int z = 0; z < 16; z++) { for(int x = 0; x < 16; x++) { chunk.getBiomeGenForWorldCoords(x, z, manager); diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEmbeddedChannel.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEmbeddedChannel.java similarity index 91% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEmbeddedChannel.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEmbeddedChannel.java index 8003eaeab..5c9150cc7 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEmbeddedChannel.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEmbeddedChannel.java @@ -1,10 +1,12 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; -import io.netty.channel.*; +import io.netty.channel.AbstractChannel; +import io.netty.channel.Channel; +import io.netty.channel.ChannelConfig; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelPromise; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.util.ReferenceCountUtil; -import io.netty.util.internal.PlatformDependent; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -23,9 +25,9 @@ protected MixinEmbeddedChannel(Channel parent) { super(parent); } - @Shadow public abstract ChannelConfig config(); + @Shadow(remap = false) public abstract ChannelConfig config(); - @Shadow private Throwable lastException; + @Shadow(remap = false) private Throwable lastException; /** * Used to simulate socket buffers. When autoRead is false, all inbound information will be temporarily stored here. */ diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEnchantmentHelper.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEnchantmentHelper.java similarity index 96% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEnchantmentHelper.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEnchantmentHelper.java index a1a766760..5a1cc35b6 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEnchantmentHelper.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEnchantmentHelper.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java new file mode 100644 index 000000000..5b9e32ff4 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java @@ -0,0 +1,28 @@ +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; + +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import org.embeddedt.archaicfix.config.ArchaicConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(EntityLiving.class) +public abstract class MixinEntityLiving extends EntityLivingBase { + public MixinEntityLiving(World p_i1594_1_) { + super(p_i1594_1_); + } + + @ModifyConstant(method = "despawnEntity", constant = @Constant(doubleValue = 16384.0D)) + private double lowerHardRange(double old) { + if(!ArchaicConfig.fixMobSpawnsAtLowRenderDist) + return old; + if(worldObj.isRemote) + return old; + if(((WorldServer)worldObj).func_73046_m().getConfigurationManager().getViewDistance() < 10) + return 96 * 96; + return old; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityPlayerMP.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityPlayerMP.java similarity index 95% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityPlayerMP.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityPlayerMP.java index 32a28df44..94f09e4c6 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityPlayerMP.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityPlayerMP.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import com.mojang.authlib.GameProfile; import net.minecraft.entity.player.EntityPlayer; @@ -30,4 +30,4 @@ public abstract class MixinEntityPlayerMP extends EntityPlayer { private void afterInit(MinecraftServer server, WorldServer worldIn, GameProfile profile, ItemInWorldManager interactionManagerIn, CallbackInfo ci) { stepHeight = 0.7F; } -} \ No newline at end of file +} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityTrackerEntry.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityTrackerEntry.java similarity index 91% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityTrackerEntry.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityTrackerEntry.java index 3875d6a91..31969e627 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityTrackerEntry.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityTrackerEntry.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLeashKnot; @@ -6,7 +6,10 @@ import net.minecraft.entity.item.EntityItemFrame; import net.minecraft.entity.projectile.EntityArrow; import net.minecraft.network.Packet; -import net.minecraft.network.play.server.*; +import net.minecraft.network.play.server.S0CPacketSpawnPlayer; +import net.minecraft.network.play.server.S0EPacketSpawnObject; +import net.minecraft.network.play.server.S11PacketSpawnExperienceOrb; +import net.minecraft.network.play.server.S18PacketEntityTeleport; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityVillager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityVillager.java similarity index 95% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityVillager.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityVillager.java index aed1415d7..b8b30e925 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityVillager.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityVillager.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.entity.passive.EntityVillager; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityXPOrb.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityXPOrb.java similarity index 86% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityXPOrb.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityXPOrb.java index 12fb48bfa..b5268bb42 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityXPOrb.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityXPOrb.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.entity.item.EntityXPOrb; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinForgeChunkManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinForgeChunkManager.java similarity index 94% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinForgeChunkManager.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinForgeChunkManager.java index ec0ee71d4..d58e49e5f 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinForgeChunkManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinForgeChunkManager.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import cpw.mods.fml.common.Loader; import net.minecraft.world.World; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinLongHashMap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinLongHashMap.java similarity index 81% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinLongHashMap.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinLongHashMap.java index 6541b3246..28bb99fb0 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinLongHashMap.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinLongHashMap.java @@ -1,9 +1,8 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.util.LongHashMap; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; @Mixin(LongHashMap.class) public abstract class MixinLongHashMap { diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMapGenStructure.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMapGenStructure.java similarity index 57% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMapGenStructure.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMapGenStructure.java index 6a7a3a6e4..6013317b7 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMapGenStructure.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMapGenStructure.java @@ -1,20 +1,13 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import com.google.common.collect.ImmutableList; -import net.minecraft.world.World; import net.minecraft.world.gen.structure.MapGenStructure; -import net.minecraft.world.gen.structure.StructureBoundingBox; -import net.minecraft.world.gen.structure.StructureStart; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; +import java.util.Collection; +import java.util.Map; @Mixin(MapGenStructure.class) public abstract class MixinMapGenStructure { diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMaterialLiquid.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMaterialLiquid.java similarity index 86% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMaterialLiquid.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMaterialLiquid.java index 411057068..5bb6564b1 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMaterialLiquid.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMaterialLiquid.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.block.material.MapColor; import net.minecraft.block.material.Material; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMerchantRecipe.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMerchantRecipe.java similarity index 93% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMerchantRecipe.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMerchantRecipe.java index ae0ffca89..a336af4fa 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinMerchantRecipe.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMerchantRecipe.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.item.ItemStack; import net.minecraft.village.MerchantRecipe; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinModCandidate.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinModCandidate.java similarity index 90% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinModCandidate.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinModCandidate.java index fc7186399..48339583a 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinModCandidate.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinModCandidate.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import cpw.mods.fml.common.discovery.ASMDataTable; import cpw.mods.fml.common.discovery.ModCandidate; @@ -8,7 +8,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import speiger.src.collections.objects.sets.ObjectOpenHashSet; -import zone.rong.rongasm.api.LoliStringPool; +import zone.rong.rongasm.api.StringPool; import java.util.ArrayList; import java.util.List; @@ -39,7 +39,7 @@ public void addClassEntry(String name) { className = className.replace('/','.'); int pkgIdx = className.lastIndexOf('.'); if (pkgIdx > -1) { - String pkg = LoliStringPool.canonicalize(className.substring(0, pkgIdx)); + String pkg = StringPool.canonicalize(className.substring(0, pkgIdx)); packageSet.add(pkg); table.registerPackage((ModCandidate)(Object)this, pkg); } diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetHandlerPlayServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetHandlerPlayServer.java similarity index 90% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetHandlerPlayServer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetHandlerPlayServer.java index bc34f7478..c7481e813 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetHandlerPlayServer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetHandlerPlayServer.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.network.NetHandlerPlayServer; import org.embeddedt.archaicfix.config.ArchaicConfig; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkDispatcher.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkDispatcher.java similarity index 89% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkDispatcher.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkDispatcher.java index 5b69f9038..02e824999 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkDispatcher.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkDispatcher.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import cpw.mods.fml.common.network.handshake.NetworkDispatcher; import cpw.mods.fml.relauncher.Side; @@ -6,7 +6,7 @@ import net.minecraft.network.EnumConnectionState; import net.minecraft.network.NetworkManager; import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.ducks.IArchaicNetworkManager; +import org.embeddedt.archaicfix.interfaces.IArchaicNetworkManager; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -15,7 +15,7 @@ @Mixin(NetworkDispatcher.class) public class MixinNetworkDispatcher { - @Shadow @Final private Side side; + @Shadow(remap = false) @Final private Side side; @Redirect(method = "clientListenForServerHandshake", at = @At(value = "INVOKE", remap = true, target = "Lnet/minecraft/network/NetworkManager;setConnectionState(Lnet/minecraft/network/EnumConnectionState;)V")) diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkManager.java similarity index 86% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkManager.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkManager.java index 7c520bab0..560d04e55 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNetworkManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkManager.java @@ -1,10 +1,9 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import io.netty.channel.Channel; -import io.netty.util.AttributeKey; import net.minecraft.network.EnumConnectionState; import net.minecraft.network.NetworkManager; -import org.embeddedt.archaicfix.ducks.IArchaicNetworkManager; +import org.embeddedt.archaicfix.interfaces.IArchaicNetworkManager; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNextTickListEntry.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNextTickListEntry.java similarity index 95% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNextTickListEntry.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNextTickListEntry.java index 3b58110c6..081fbb361 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinNextTickListEntry.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNextTickListEntry.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.block.Block; import net.minecraft.world.NextTickListEntry; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinObjectIntIdentityMap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinObjectIntIdentityMap.java similarity index 93% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinObjectIntIdentityMap.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinObjectIntIdentityMap.java index 57b566272..29448a5b9 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinObjectIntIdentityMap.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinObjectIntIdentityMap.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.util.ObjectIntIdentityMap; import org.embeddedt.archaicfix.helpers.UnexpectionalObjectArrayList; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinSpawnerAnimals.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinSpawnerAnimals.java similarity index 68% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinSpawnerAnimals.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinSpawnerAnimals.java index a0c3d8474..da4df4f0b 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinSpawnerAnimals.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinSpawnerAnimals.java @@ -1,22 +1,17 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.IEntityLivingData; -import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.SpawnerAnimals; import net.minecraft.world.World; -import net.minecraft.world.WorldServer; -import net.minecraft.world.chunk.IChunkProvider; import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngineHelpers; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.*; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; +import org.spongepowered.asm.mixin.injection.Redirect; import java.util.HashMap; -import java.util.Iterator; @Mixin(SpawnerAnimals.class) public class MixinSpawnerAnimals { diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinStructureStart.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinStructureStart.java similarity index 76% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinStructureStart.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinStructureStart.java index b48081314..8ad5c5517 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinStructureStart.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinStructureStart.java @@ -1,16 +1,12 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; -import net.minecraft.world.World; -import net.minecraft.world.gen.structure.StructureBoundingBox; import net.minecraft.world.gen.structure.StructureComponent; import net.minecraft.world.gen.structure.StructureStart; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import java.util.LinkedList; -import java.util.Random; @Mixin(StructureStart.class) public class MixinStructureStart { diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorld.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorld.java similarity index 52% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorld.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorld.java index 07ec0be73..2595d5701 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorld.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorld.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import com.google.common.collect.ImmutableSet; import cpw.mods.fml.common.FMLCommonHandler; @@ -7,57 +7,33 @@ import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.MathHelper; -import net.minecraft.world.ChunkCoordIntPair; -import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.biome.WorldChunkManager; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.IChunkProvider; -import net.minecraft.world.storage.WorldInfo; -import net.minecraftforge.common.ForgeChunkManager; import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.ducks.IArchaicWorld; import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngineHelpers; -import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; -import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import speiger.src.collections.longs.collections.LongCollection; -import speiger.src.collections.longs.sets.LongOpenHashSet; -import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Set; @Mixin(World.class) -public abstract class MixinWorld implements IArchaicWorld { +public abstract class MixinWorld { @Shadow public boolean isRemote; - @Shadow public EnumDifficulty difficultySetting; - - @Shadow public abstract float getCurrentMoonPhaseFactor(); - - @Shadow protected WorldInfo worldInfo; - @Shadow public List playerEntities; - @Shadow public abstract Chunk getChunkFromChunkCoords(int p_72964_1_, int p_72964_2_); - @Shadow protected IChunkProvider chunkProvider; - @Shadow public List loadedTileEntityList; - private LongCollection tileEntitiesChunkToBeRemoved = new LongOpenHashSet(); - @Redirect(method = "getBiomeGenForCoordsBody", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/biome/WorldChunkManager;getBiomeGenAt(II)Lnet/minecraft/world/biome/BiomeGenBase;")) private BiomeGenBase skipBiomeGenOnClient(WorldChunkManager manager, int x, int z) { if(this.isRemote) @@ -66,33 +42,6 @@ private BiomeGenBase skipBiomeGenOnClient(WorldChunkManager manager, int x, int return manager.getBiomeGenAt(x, z); } - /** - * @reason Remove regional difficulty and make it based on overall world time instead. (From TMCW) - * @author embeddedt - */ - @Inject(method = "func_147473_B", at = @At("HEAD"), cancellable = true) - public void func_147473_B(int p_147473_1_, int p_147473_2_, int p_147473_3_, CallbackInfoReturnable cir) { - if(!ArchaicConfig.betterRegionalDifficulty) - return; - float factor = this.worldInfo != null ? ((float)this.worldInfo.getWorldTotalTime() / 7200000.0F) : 0; - factor += this.getCurrentMoonPhaseFactor() * 0.25F; - - EnumDifficulty difficulty = this.difficultySetting; - if(difficulty == null) - difficulty = EnumDifficulty.NORMAL; - - if (difficulty == EnumDifficulty.EASY || difficulty == EnumDifficulty.PEACEFUL) - { - factor *= 0.5F; - } - else if (difficulty == EnumDifficulty.HARD) - { - factor *= 2.0F; - } - - cir.setReturnValue(MathHelper.clamp_float(factor, 0.0F, (float)difficulty.getDifficultyId() * 0.5F)); - } - private Set entityOptimizationIgnoreSet = null; @Inject(method = "updateEntityWithOptionalForce", at = @At(value = "FIELD", target = "Lnet/minecraft/entity/Entity;lastTickPosX:D", ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) @@ -134,20 +83,16 @@ private void saveInactiveChunks(CallbackInfo ci) { int activeDistance = ArchaicConfig.optimizeBlockTickingDistance; - for (int i = 0; i < this.playerEntities.size(); ++i) - { - entityplayer = (EntityPlayer)this.playerEntities.get(i); + for (Object playerEntity : this.playerEntities) { + entityplayer = (EntityPlayer) playerEntity; j = MathHelper.floor_double(entityplayer.posX / 16.0D); k = MathHelper.floor_double(entityplayer.posZ / 16.0D); - for (int offX = -renderDistance; offX <= renderDistance; ++offX) - { - for (int offZ = -renderDistance; offZ <= renderDistance; ++offZ) - { - if(Math.abs(offX) <= activeDistance && Math.abs(offZ) <= activeDistance) - continue; + for (int offX = -renderDistance; offX <= renderDistance; ++offX) { + for (int offZ = -renderDistance; offZ <= renderDistance; ++offZ) { + if (Math.abs(offX) <= activeDistance && Math.abs(offZ) <= activeDistance) continue; Chunk chunk = LightingEngineHelpers.getLoadedChunk(this.chunkProvider, offX + j, offZ + k); - if(chunk != null && !chunk.func_150802_k()) { + if (chunk != null && !chunk.func_150802_k()) { chunk.func_150804_b(false); } } @@ -155,38 +100,4 @@ private void saveInactiveChunks(CallbackInfo ci) { } } - @Override - public void arch$markTileEntitiesInChunkForRemoval(Chunk chunk) - { - if (!chunk.chunkTileEntityMap.isEmpty()) - { - long pos = ChunkCoordIntPair.chunkXZ2Int(chunk.xPosition, chunk.zPosition); - this.tileEntitiesChunkToBeRemoved.add(pos); - } - } - - @Inject(method = "updateEntities", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/world/World;field_147481_N:Z", ordinal = 1)) - private void removeInUnloaded(CallbackInfo ci) { - if (ArchaicConfig.fixTEUnloadLag && !this.tileEntitiesChunkToBeRemoved.isEmpty()) - { - java.util.function.Predicate isInChunk = (tileEntity) -> - { - long tileChunkPos = ChunkCoordIntPair.chunkXZ2Int(tileEntity.xCoord >> 4, tileEntity.zCoord >> 4); - return this.tileEntitiesChunkToBeRemoved.contains(tileChunkPos); - }; - java.util.function.Predicate isInChunkDoUnload = (tileEntity) -> - { - boolean inChunk = isInChunk.test(tileEntity); - if (inChunk) - { - tileEntity.onChunkUnload(); - } - return inChunk; - }; - this.loadedTileEntityList.removeIf(isInChunkDoUnload); - this.tileEntitiesChunkToBeRemoved.clear(); - } - } - - } diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldChunkManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldChunkManager.java similarity index 96% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldChunkManager.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldChunkManager.java index f468d4698..6f6a9e928 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldChunkManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldChunkManager.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeCache; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldServer.java similarity index 74% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldServer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldServer.java index e6688567a..c2dde92bc 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinWorldServer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldServer.java @@ -1,21 +1,20 @@ -package org.embeddedt.archaicfix.mixins.common.core; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; -import com.google.common.collect.Iterators; import net.minecraft.profiler.Profiler; -import net.minecraft.world.*; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import net.minecraft.world.World; +import net.minecraft.world.WorldProvider; +import net.minecraft.world.WorldServer; +import net.minecraft.world.WorldSettings; import net.minecraft.world.gen.ChunkProviderServer; import net.minecraft.world.storage.ISaveHandler; import org.embeddedt.archaicfix.config.ArchaicConfig; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.*; +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; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import java.util.Iterator; -import java.util.Set; @Mixin(WorldServer.class) public abstract class MixinWorldServer extends World { diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerServer.java similarity index 91% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerServer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerServer.java index 8e318fdb1..aa0e9f4e1 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerServer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerServer.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.extrautils; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.extrautils; import com.rwtema.extrautils.EventHandlerServer; import net.minecraft.block.Block; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerSiege.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerSiege.java similarity index 89% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerSiege.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerSiege.java index f0d992b0a..2b2edcc7b 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinEventHandlerSiege.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerSiege.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.extrautils; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.extrautils; import com.rwtema.extrautils.EventHandlerSiege; import net.minecraft.tileentity.TileEntityBeacon; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinItemDivisionSigil.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinItemDivisionSigil.java similarity index 92% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinItemDivisionSigil.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinItemDivisionSigil.java index 4366282a5..9efc873ab 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinItemDivisionSigil.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinItemDivisionSigil.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.extrautils; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.extrautils; import com.rwtema.extrautils.item.ItemDivisionSigil; import net.minecraft.block.Block; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinTileEntityTrashCan.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinTileEntityTrashCan.java similarity index 89% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinTileEntityTrashCan.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinTileEntityTrashCan.java index 9cc5b4db2..01e26fab5 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/extrautils/MixinTileEntityTrashCan.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinTileEntityTrashCan.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.extrautils; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.extrautils; import com.rwtema.extrautils.tileentity.TileEntityTrashCan; import net.minecraft.nbt.NBTTagCompound; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinAnvilChunkLoader.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinAnvilChunkLoader.java similarity index 96% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinAnvilChunkLoader.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinAnvilChunkLoader.java index e84f9c8b6..ddaa240ce 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinAnvilChunkLoader.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinAnvilChunkLoader.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.lighting; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunk.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunk.java similarity index 98% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunk.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunk.java index 5ea219cf6..39fbd7874 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunk.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunk.java @@ -1,7 +1,6 @@ -package org.embeddedt.archaicfix.mixins.common.lighting; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; import net.minecraft.block.Block; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.EnumSkyBlock; @@ -79,11 +78,8 @@ private int getBlockLightOpacity(int x, int y, int z) { @Overwrite public void relightBlock(int x, int y, int z) { int i = this.heightMap[z << 4 | x] & 255; - int j = i; - if (y > i) { - j = y; - } + int j = Math.max(y, i); while (j > 0 && this.getBlockLightOpacity(x, j - 1, z) == 0) { --j; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkProviderServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkProviderServer.java similarity index 89% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkProviderServer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkProviderServer.java index f5dfbeed9..6ac270127 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkProviderServer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkProviderServer.java @@ -1,16 +1,13 @@ -package org.embeddedt.archaicfix.mixins.common.lighting; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; import net.minecraft.util.IProgressUpdate; import net.minecraft.world.WorldServer; -import net.minecraft.world.chunk.Chunk; import net.minecraft.world.gen.ChunkProviderServer; import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.Set; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkVanilla.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkVanilla.java similarity index 92% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkVanilla.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkVanilla.java index 958a0cd2b..1516c8c22 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinChunkVanilla.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkVanilla.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.lighting; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; @@ -7,7 +7,9 @@ import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(value = Chunk.class) public abstract class MixinChunkVanilla { diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinExtendedBlockStorage.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinExtendedBlockStorage.java similarity index 97% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinExtendedBlockStorage.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinExtendedBlockStorage.java index 6091c2560..29bed6756 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinExtendedBlockStorage.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinExtendedBlockStorage.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.lighting; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinSPacketChunkData.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinSPacketChunkData.java similarity index 94% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinSPacketChunkData.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinSPacketChunkData.java index cfd3b849d..2e0fdff67 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinSPacketChunkData.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinSPacketChunkData.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.lighting; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; import net.minecraft.network.play.server.S21PacketChunkData; import net.minecraft.world.chunk.Chunk; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinWorld_Lighting.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinWorld_Lighting.java similarity index 94% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinWorld_Lighting.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinWorld_Lighting.java index 3d553f0cf..75197bcba 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/MixinWorld_Lighting.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinWorld_Lighting.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.lighting; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; @@ -15,7 +15,7 @@ import java.util.Set; -@Mixin(World.class) +@Mixin(value = World.class, priority = 999) public abstract class MixinWorld_Lighting implements ILightingEngineProvider { @Shadow protected Set activeChunkSet; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/renderdistance/MixinPlayerManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/renderdistance/MixinPlayerManager.java similarity index 83% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/renderdistance/MixinPlayerManager.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/renderdistance/MixinPlayerManager.java index 285196a52..03257c771 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/renderdistance/MixinPlayerManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/renderdistance/MixinPlayerManager.java @@ -1,7 +1,6 @@ -package org.embeddedt.archaicfix.mixins.common.renderdistance; +package com.gtnewhorizons.angelica.mixins.early.archaic.common.renderdistance; import net.minecraft.server.management.PlayerManager; -import org.embeddedt.archaicfix.ArchaicFix; import org.embeddedt.archaicfix.config.ArchaicConfig; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.Constant; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinEntityRenderer.java similarity index 93% rename from src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinEntityRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinEntityRenderer.java index 7f04ab5fb..c659a1578 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinEntityRenderer.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.clouds; +package com.gtnewhorizons.angelica.mixins.early.notfine.clouds; import jss.notfine.core.SettingsManager; import net.minecraft.client.renderer.EntityRenderer; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinGameSettings.java similarity index 88% rename from src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinGameSettings.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinGameSettings.java index d33bcc128..f07465695 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinGameSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinGameSettings.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.clouds; +package com.gtnewhorizons.angelica.mixins.early.notfine.clouds; import net.minecraft.client.settings.GameSettings; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java similarity index 99% rename from src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinRenderGlobal.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java index ea3e4f925..f7dc0dc9b 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.clouds; +package com.gtnewhorizons.angelica.mixins.early.notfine.clouds; import jss.notfine.core.Settings; import net.minecraft.client.Minecraft; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinWorldType.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinWorldType.java similarity index 87% rename from src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinWorldType.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinWorldType.java index 010dfc95b..7c6d8faae 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/clouds/MixinWorldType.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinWorldType.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.clouds; +package com.gtnewhorizons.angelica.mixins.early.notfine.clouds; import jss.notfine.core.Settings; import net.minecraft.world.WorldType; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinItemRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinItemRenderer.java similarity index 92% rename from src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinItemRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinItemRenderer.java index c6183e93d..dd4a11a06 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinItemRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinItemRenderer.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.glint; +package com.gtnewhorizons.angelica.mixins.early.notfine.glint; import jss.notfine.core.Settings; import net.minecraft.client.renderer.ItemRenderer; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderBiped.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderBiped.java similarity index 92% rename from src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderBiped.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderBiped.java index e68d4a230..8d69cba81 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderBiped.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderBiped.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.glint; +package com.gtnewhorizons.angelica.mixins.early.notfine.glint; import jss.notfine.core.Settings; import net.minecraft.client.renderer.entity.RenderBiped; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java similarity index 97% rename from src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderItem.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java index 0d1c726e5..59b6feb63 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.glint; +package com.gtnewhorizons.angelica.mixins.early.notfine.glint; import jss.notfine.core.Settings; import net.minecraft.item.ItemStack; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderPlayer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderPlayer.java similarity index 92% rename from src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderPlayer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderPlayer.java index 463162d29..e06315bc1 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/glint/MixinRenderPlayer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderPlayer.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.glint; +package com.gtnewhorizons.angelica.mixins.early.notfine.glint; import jss.notfine.core.Settings; import net.minecraft.client.renderer.entity.RenderPlayer; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/gui/MixinGuiSlot.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/gui/MixinGuiSlot.java similarity index 92% rename from src/main/java/jss/notfine/mixins/early/minecraft/gui/MixinGuiSlot.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/gui/MixinGuiSlot.java index e007571d6..3e2e01528 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/gui/MixinGuiSlot.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/gui/MixinGuiSlot.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.gui; +package com.gtnewhorizons.angelica.mixins.early.notfine.gui; import jss.notfine.core.Settings; import net.minecraft.client.Minecraft; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java similarity index 96% rename from src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeaves.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java index 9e7c27ce5..2eb5a00e3 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.leaves; +package com.gtnewhorizons.angelica.mixins.early.notfine.leaves; import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeavesBase.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java similarity index 91% rename from src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeavesBase.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java index 0e12f1bd9..555c0591b 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/leaves/MixinBlockLeavesBase.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.leaves; +package com.gtnewhorizons.angelica.mixins.early.notfine.leaves; import jss.notfine.util.ILeafBlock; import jss.notfine.util.LeafRenderUtil; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinBlockEnchantmentTable.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinBlockEnchantmentTable.java similarity index 96% rename from src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinBlockEnchantmentTable.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinBlockEnchantmentTable.java index 2bd6d883e..1741ffd36 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinBlockEnchantmentTable.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinBlockEnchantmentTable.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.particles; +package com.gtnewhorizons.angelica.mixins.early.notfine.particles; import java.util.Random; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinEffectRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java similarity index 98% rename from src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinEffectRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java index f8d5b7a8e..c2b7f176a 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinEffectRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.particles; +package com.gtnewhorizons.angelica.mixins.early.notfine.particles; import net.minecraft.client.particle.EffectRenderer; import net.minecraft.client.particle.EntityFX; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldClient.java similarity index 90% rename from src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldClient.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldClient.java index c480d0f4f..26d458bd6 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldClient.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.particles; +package com.gtnewhorizons.angelica.mixins.early.notfine.particles; import java.util.Random; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldProvider.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldProvider.java similarity index 90% rename from src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldProvider.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldProvider.java index c73a61d31..6e6d7b518 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/particles/MixinWorldProvider.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldProvider.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.particles; +package com.gtnewhorizons.angelica.mixins.early.notfine.particles; import jss.notfine.core.Settings; import net.minecraft.world.WorldProvider; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/renderer/MixinRenderGlobal.java similarity index 88% rename from src/main/java/jss/notfine/mixins/early/minecraft/MixinRenderGlobal.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/renderer/MixinRenderGlobal.java index b882e9fa1..4f8a186a7 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/renderer/MixinRenderGlobal.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft; +package com.gtnewhorizons.angelica.mixins.early.notfine.renderer; import jss.notfine.core.Settings; import jss.notfine.render.RenderStars; @@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(RenderGlobal.class) -public abstract class MixinRenderGlobal { +public class MixinRenderGlobal { @Inject(method = "renderSky", at = @At("HEAD"), cancellable = true) void notFine$toggleSky(CallbackInfo ci) { diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java similarity index 99% rename from src/main/java/jss/notfine/mixins/early/minecraft/MixinGameSettings.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java index fd67ce224..eee19a73f 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/MixinGameSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft; +package com.gtnewhorizons.angelica.mixins.early.notfine.settings; import jss.notfine.core.SettingsManager; import net.minecraft.client.Minecraft; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinEntityRenderer.java similarity index 92% rename from src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinEntityRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinEntityRenderer.java index 8b5664791..acfeeee91 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinEntityRenderer.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.toggle; +package com.gtnewhorizons.angelica.mixins.early.notfine.toggle; import jss.notfine.core.SettingsManager; import net.minecraft.client.renderer.EntityRenderer; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinGuiIngame.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinGuiIngame.java similarity index 91% rename from src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinGuiIngame.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinGuiIngame.java index 018970d5f..04be41fc7 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinGuiIngame.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinGuiIngame.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.toggle; +package com.gtnewhorizons.angelica.mixins.early.notfine.toggle; import jss.notfine.core.SettingsManager; import net.minecraft.client.gui.GuiIngame; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRender.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRender.java similarity index 92% rename from src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRender.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRender.java index 0fc472430..7ac1a7e0d 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRender.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRender.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.toggle; +package com.gtnewhorizons.angelica.mixins.early.notfine.toggle; import jss.notfine.core.SettingsManager; import net.minecraft.client.renderer.entity.Render; diff --git a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRenderItem.java similarity index 93% rename from src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRenderItem.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRenderItem.java index 0311bfb39..7927253e0 100644 --- a/src/main/java/jss/notfine/mixins/early/minecraft/toggle/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRenderItem.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.early.minecraft.toggle; +package com.gtnewhorizons.angelica.mixins.early.notfine.toggle; import jss.notfine.core.SettingsManager; import net.minecraft.client.renderer.entity.RenderItem; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java index a634152da..6280eb604 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java @@ -1,5 +1,7 @@ package com.gtnewhorizons.angelica.mixins.early.renderer; +import jss.notfine.core.Settings; +import jss.notfine.render.RenderStars; import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.culling.ICamera; @@ -9,6 +11,7 @@ import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -23,32 +26,21 @@ public class MixinRenderGlobal { @Inject( method = "renderEntities(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/client/renderer/culling/ICamera;F)V", - at = @At( - value = "INVOKE_STRING", - target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", - args = "ldc=entities")) + at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", args = "ldc=entities")) private void angelica$beginEntities(EntityLivingBase entity, ICamera camera, float p_147589_3_, CallbackInfo ci) { Shaders.beginEntities(); } @Inject( method = "renderEntities(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/client/renderer/culling/ICamera;F)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)Z", - ordinal = 1, - shift = At.Shift.AFTER)) + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)Z", ordinal = 1, shift = At.Shift.AFTER)) private void angelica$nextEntity(EntityLivingBase entity, ICamera camera, float p_147589_3_, CallbackInfo ci) { Shaders.nextEntity(); } @Inject( method = "renderEntities(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/client/renderer/culling/ICamera;F)V", - at = @At( - value = "INVOKE_STRING", - target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", - args = "ldc=blockentities", - shift = At.Shift.AFTER)) + at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", args = "ldc=blockentities", shift = At.Shift.AFTER)) private void angelica$endEntitiesAndBeginBlockEntities(EntityLivingBase entity, ICamera camera, float p_147589_3_, CallbackInfo ci) { Shaders.endEntities(); @@ -57,10 +49,7 @@ public class MixinRenderGlobal { @Inject( method = "renderEntities(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/client/renderer/culling/ICamera;F)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/EntityRenderer;disableLightmap(D)V", - shift = At.Shift.AFTER)) + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/EntityRenderer;disableLightmap(D)V", shift = At.Shift.AFTER)) private void angelica$endBlockEntities(EntityLivingBase entity, ICamera camera, float p_147589_3_, CallbackInfo ci) { Shaders.endBlockEntities(); @@ -69,13 +58,7 @@ public class MixinRenderGlobal { // Texture 2D @Inject( method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At( - value = "INVOKE", - target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", - remap = false, - ordinal = 0, - shift = At.Shift.AFTER), - expect = 1) + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false, ordinal = 0, shift = At.Shift.AFTER), expect = 1) private void angelica$sortandRenderDisableTexture2D(EntityLivingBase p_72719_1_, int p_72719_2_, double p_72719_3_, CallbackInfoReturnable cir) { Shaders.disableTexture2D(); @@ -83,38 +66,21 @@ public class MixinRenderGlobal { @Inject( method = "drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MovingObjectPosition;IF)V", - at = @At( - value = "INVOKE", - target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", - remap = false, - ordinal = 0, - shift = At.Shift.AFTER), - expect = 1) + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false, ordinal = 0, shift = At.Shift.AFTER), expect = 1) private void angelica$drawSelectionBoxDisableTexture2D(CallbackInfo ci) { Shaders.disableTexture2D(); } @Inject( method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At( - value = "INVOKE", - target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", - remap = false, - ordinal = 0, - shift = At.Shift.AFTER)) + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false, ordinal = 0, shift = At.Shift.AFTER)) private void angelica$sortAndRenderEnableTexture2D(CallbackInfoReturnable cir) { Shaders.enableTexture2D(); } @Inject( method = "drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MovingObjectPosition;IF)V", - at = @At( - value = "INVOKE", - target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", - remap = false, - ordinal = 1, - shift = At.Shift.AFTER), - expect = 1) + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false, ordinal = 1, shift = At.Shift.AFTER), expect = 1) private void angelica$drawSelectionBoxEnableTexture2D(EntityPlayer p_72731_1_, MovingObjectPosition p_72731_2_, int p_72731_3_, float p_72731_4_, CallbackInfo ci) { Shaders.enableTexture2D(); @@ -123,32 +89,20 @@ public class MixinRenderGlobal { // Fog @Inject( method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At( - value = "INVOKE", - target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", - remap = false, - ordinal = 3, - shift = At.Shift.AFTER)) + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false, ordinal = 3, shift = At.Shift.AFTER)) private void angelica$sortAndRenderDisableFog(CallbackInfoReturnable cir) { Shaders.disableFog(); } @Inject( method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At( - value = "INVOKE", - target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", - remap = false, - ordinal = 2, - shift = At.Shift.AFTER)) + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false, ordinal = 2, shift = At.Shift.AFTER)) private void angelica$sortAndRenderEnableFog(CallbackInfoReturnable cir) { Shaders.enableFog(); } // RenderSky - @WrapOperation( - method = "renderSky(F)V", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false)) + @WrapOperation(method = "renderSky(F)V", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false)) private void angelica$renderSkyDisable(int cap, Operation original) { original.call(cap); @@ -156,9 +110,7 @@ public class MixinRenderGlobal { else if (cap == GL11.GL_TEXTURE_2D) Shaders.disableTexture2D(); } - @WrapOperation( - method = "renderSky(F)V", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false)) + @WrapOperation(method = "renderSky(F)V", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false)) private void angelica$renderSkyEnable(int cap, Operation original) { original.call(cap); if (cap == GL11.GL_FOG) Shaders.enableFog(); @@ -167,37 +119,21 @@ public class MixinRenderGlobal { @Inject( method = "renderSky(F)V", - at = @At( - value = "INVOKE", - target = "Lorg/lwjgl/opengl/GL11;glCallList(I)V", - remap = false, - ordinal = 0, - shift = At.Shift.BEFORE, - by = 2)) + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glCallList(I)V", remap = false, ordinal = 0, shift = At.Shift.BEFORE, by = 2)) private void angelica$preSkyList(float p_72714_1_, CallbackInfo ci) { Shaders.preSkyList(); } @Inject( method = "renderSky(F)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/multiplayer/WorldClient;getCelestialAngle(F)F", - ordinal = 1, - shift = At.Shift.BY, - by = -2)) + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;getCelestialAngle(F)F", ordinal = 1, shift = At.Shift.BY, by = -2)) private void angelica$preCelestialRotate(float p_72714_1_, CallbackInfo ci) { Shaders.preCelestialRotate(); } @Inject( method = "renderSky(F)V", - at = @At( - value = "INVOKE", - target = "Lorg/lwjgl/opengl/GL11;glRotatef(FFFF)V", - remap = false, - ordinal = 9, - shift = At.Shift.AFTER)) + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glRotatef(FFFF)V", remap = false, ordinal = 9, shift = At.Shift.AFTER)) private void angelica$postCelestialRotate(float p_72714_1_, CallbackInfo ci) { Shaders.postCelestialRotate(); } @@ -225,11 +161,7 @@ public class MixinRenderGlobal { @Inject( method = "drawBlockDamageTexture(Lnet/minecraft/client/renderer/Tessellator;Lnet/minecraft/entity/EntityLivingBase;F)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/Tessellator;startDrawingQuads()V", - ordinal = 0, - shift = At.Shift.BEFORE)) + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Tessellator;startDrawingQuads()V", ordinal = 0, shift = At.Shift.BEFORE)) private void angelica$beginBlockDestroyProgress(Tessellator p_72717_1_, EntityLivingBase p_72717_2_, float p_72717_3_, CallbackInfo ci) { Shaders.beginBlockDestroyProgress(); @@ -237,14 +169,9 @@ public class MixinRenderGlobal { @Inject( method = "drawBlockDamageTexture(Lnet/minecraft/client/renderer/Tessellator;Lnet/minecraft/entity/EntityLivingBase;F)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/Tessellator;setTranslation(DDD)V", - ordinal = 1, - shift = At.Shift.AFTER)) + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Tessellator;setTranslation(DDD)V", ordinal = 1, shift = At.Shift.AFTER)) private void angelica$endBlockDestroyProgress(Tessellator p_72717_1_, EntityLivingBase p_72717_2_, float p_72717_3_, CallbackInfo ci) { Shaders.endBlockDestroyProgress(); } - } diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/botania/MixinBlockSpecialFlower.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/botania/MixinBlockSpecialFlower.java similarity index 90% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/botania/MixinBlockSpecialFlower.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/botania/MixinBlockSpecialFlower.java index bdae2023e..6348a54e5 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/botania/MixinBlockSpecialFlower.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/botania/MixinBlockSpecialFlower.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.botania; +package com.gtnewhorizons.angelica.mixins.late.archaic.common.botania; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/mrtjp/MixinBlockUpdateHandler.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/mrtjp/MixinBlockUpdateHandler.java similarity index 92% rename from src/main/java/org/embeddedt/archaicfix/mixins/common/mrtjp/MixinBlockUpdateHandler.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/mrtjp/MixinBlockUpdateHandler.java index 41e210f32..484de7740 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/mrtjp/MixinBlockUpdateHandler.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/mrtjp/MixinBlockUpdateHandler.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.common.mrtjp; +package com.gtnewhorizons.angelica.mixins.late.archaic.common.mrtjp; import mrtjp.core.world.BlockUpdateHandler$; import net.minecraft.world.ChunkCoordIntPair; diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/journeymap/MixinTileDrawStep.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/client/journeymap/MixinTileDrawStep.java similarity index 88% rename from src/main/java/org/embeddedt/archaicfix/mixins/client/journeymap/MixinTileDrawStep.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/late/client/journeymap/MixinTileDrawStep.java index f1f6dcc3a..7225991e2 100644 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/journeymap/MixinTileDrawStep.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/client/journeymap/MixinTileDrawStep.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.mixins.client.journeymap; +package com.gtnewhorizons.angelica.mixins.late.client.journeymap; import journeymap.client.render.map.TileDrawStep; import org.objectweb.asm.Opcodes; diff --git a/src/main/java/jss/notfine/mixins/late/thaumcraft/leaves/MixinBlockMagicalLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java similarity index 96% rename from src/main/java/jss/notfine/mixins/late/thaumcraft/leaves/MixinBlockMagicalLeaves.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java index e23b5da83..d20299cac 100644 --- a/src/main/java/jss/notfine/mixins/late/thaumcraft/leaves/MixinBlockMagicalLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.late.thaumcraft.leaves; +package com.gtnewhorizons.angelica.mixins.late.notfine.leaves.thaumcraft; import jss.notfine.util.ILeafBlock; import jss.notfine.core.Settings; diff --git a/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves.java similarity index 69% rename from src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves.java index a1f9f90de..23ea06ae5 100644 --- a/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.late.twilightforest.leaves; +package com.gtnewhorizons.angelica.mixins.late.notfine.leaves.twilightforest; import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; @@ -18,21 +18,14 @@ public abstract class MixinBlockTFLeaves extends BlockLeaves { public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { int renderMode = (int)Settings.MODE_LEAVES.getValue(); int maskedMeta = world.getBlockMetadata(x, y, z) & 3; - switch(renderMode) { - case -1: - renderMode = SettingsManager.leavesOpaque ? 1 : 0; - break; - case 4: - renderMode = world.getBlock( + renderMode = switch (renderMode) { + case -1 -> SettingsManager.leavesOpaque ? 1 : 0; + case 4 -> world.getBlock( x + DirectionHelper.xDirectionalIncrease[side], y + DirectionHelper.yDirectionalIncrease[side], - z + DirectionHelper.zDirectionalIncrease[side] - ) instanceof ILeafBlock ? 1 : 0; - break; - default: - renderMode = renderMode > 1 ? 0 : renderMode; - break; - } + z + DirectionHelper.zDirectionalIncrease[side]) instanceof ILeafBlock ? 1 : 0; + default -> renderMode > 1 ? 0 : renderMode; + }; maskedMeta = maskedMeta > 1 ? 0 : maskedMeta; return Blocks.leaves.field_150129_M[renderMode][maskedMeta]; } diff --git a/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves3.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves3.java similarity index 66% rename from src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves3.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves3.java index dd4f75a17..b96587565 100644 --- a/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFLeaves3.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves3.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.late.twilightforest.leaves; +package com.gtnewhorizons.angelica.mixins.late.notfine.leaves.twilightforest; import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; @@ -17,21 +17,14 @@ public abstract class MixinBlockTFLeaves3 extends BlockLeaves { @Override public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { int renderMode = (int)Settings.MODE_LEAVES.getValue(); - switch(renderMode) { - case -1: - renderMode = SettingsManager.leavesOpaque ? 1 : 0; - break; - case 4: - renderMode = world.getBlock( + renderMode = switch (renderMode) { + case -1 -> SettingsManager.leavesOpaque ? 1 : 0; + case 4 -> world.getBlock( x + DirectionHelper.xDirectionalIncrease[side], y + DirectionHelper.yDirectionalIncrease[side], - z + DirectionHelper.zDirectionalIncrease[side] - ) instanceof ILeafBlock ? 1 : 0; - break; - default: - renderMode = renderMode > 1 ? 0 : renderMode; - break; - } + z + DirectionHelper.zDirectionalIncrease[side]) instanceof ILeafBlock ? 1 : 0; + default -> renderMode > 1 ? 0 : renderMode; + }; return Blocks.leaves.field_150129_M[renderMode][0]; } diff --git a/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFMagicLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFMagicLeaves.java similarity index 64% rename from src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFMagicLeaves.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFMagicLeaves.java index 2fd81ec6f..7e41b8f27 100644 --- a/src/main/java/jss/notfine/mixins/late/twilightforest/leaves/MixinBlockTFMagicLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFMagicLeaves.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.late.twilightforest.leaves; +package com.gtnewhorizons.angelica.mixins.late.notfine.leaves.twilightforest; import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; @@ -17,30 +17,20 @@ public abstract class MixinBlockTFMagicLeaves extends BlockLeaves { public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { int renderMode = (int) Settings.MODE_LEAVES.getValue(); int maskedMeta = world.getBlockMetadata(x, y, z) & 3; - switch(renderMode) { - case -1: - renderMode = SettingsManager.leavesOpaque ? 1 : 0; - break; - case 4: - renderMode = world.getBlock( + renderMode = switch (renderMode) { + case -1 -> SettingsManager.leavesOpaque ? 1 : 0; + case 4 -> world.getBlock( x + DirectionHelper.xDirectionalIncrease[side], y + DirectionHelper.yDirectionalIncrease[side], - z + DirectionHelper.zDirectionalIncrease[side] - ) instanceof ILeafBlock ? 1 : 0; - break; - default: - renderMode = renderMode > 1 ? 0 : renderMode; - break; - } + z + DirectionHelper.zDirectionalIncrease[side]) instanceof ILeafBlock ? 1 : 0; + default -> renderMode > 1 ? 0 : renderMode; + }; maskedMeta = maskedMeta > 1 ? 0 : maskedMeta; - switch(maskedMeta) { - default: - return renderMode == 1 ? SPR_TIMELEAVES_OPAQUE : SPR_TIMELEAVES; - case 1: - return renderMode == 1 ? SPR_TRANSLEAVES_OPAQUE : SPR_TRANSLEAVES; - case 3: - return renderMode == 1 ? SPR_SORTLEAVES_OPAQUE : SPR_SORTLEAVES; - } + return switch (maskedMeta) { + default -> renderMode == 1 ? SPR_TIMELEAVES_OPAQUE : SPR_TIMELEAVES; + case 1 -> renderMode == 1 ? SPR_TRANSLEAVES_OPAQUE : SPR_TRANSLEAVES; + case 3 -> renderMode == 1 ? SPR_SORTLEAVES_OPAQUE : SPR_SORTLEAVES; + }; } @Shadow(remap = false) diff --git a/src/main/java/jss/notfine/mixins/late/witchery/leaves/MixinBlockWitchLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java similarity index 77% rename from src/main/java/jss/notfine/mixins/late/witchery/leaves/MixinBlockWitchLeaves.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java index 29d22da8a..5dcb9cbd9 100644 --- a/src/main/java/jss/notfine/mixins/late/witchery/leaves/MixinBlockWitchLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java @@ -1,4 +1,4 @@ -package jss.notfine.mixins.late.witchery.leaves; +package com.gtnewhorizons.angelica.mixins.late.notfine.leaves.witchery; import com.emoniph.witchery.blocks.BlockWitchLeaves; import jss.notfine.core.Settings; @@ -29,21 +29,14 @@ public boolean isOpaqueCube() { public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { int renderMode = (int) Settings.MODE_LEAVES.getValue(); int maskedMeta = world.getBlockMetadata(x, y, z) & 3; - switch(renderMode) { - case -1: - renderMode = SettingsManager.leavesOpaque ? 1 : 0; - break; - case 4: - renderMode = world.getBlock( + renderMode = switch (renderMode) { + case -1 -> SettingsManager.leavesOpaque ? 1 : 0; + case 4 -> world.getBlock( x + DirectionHelper.xDirectionalIncrease[side], y + DirectionHelper.yDirectionalIncrease[side], - z + DirectionHelper.zDirectionalIncrease[side] - ) instanceof ILeafBlock ? 1 : 0; - break; - default: - renderMode = renderMode > 1 ? 0 : renderMode; - break; - } + z + DirectionHelper.zDirectionalIncrease[side]) instanceof ILeafBlock ? 1 : 0; + default -> renderMode > 1 ? 0 : renderMode; + }; maskedMeta = maskedMeta > 1 ? 0 : maskedMeta; return iconsForModes[renderMode][maskedMeta]; } diff --git a/src/main/java/jss/notfine/mixinplugin/NotFineEarlyMixins.java b/src/main/java/jss/notfine/mixinplugin/NotFineEarlyMixins.java deleted file mode 100644 index 603857c67..000000000 --- a/src/main/java/jss/notfine/mixinplugin/NotFineEarlyMixins.java +++ /dev/null @@ -1,83 +0,0 @@ -package jss.notfine.mixinplugin; - -import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader; -import cpw.mods.fml.relauncher.IFMLLoadingPlugin; -import jss.notfine.NotFine; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -@IFMLLoadingPlugin.Name("NotFineEarlyMixins") -@IFMLLoadingPlugin.MCVersion("1.7.10") -public class NotFineEarlyMixins implements IFMLLoadingPlugin, IEarlyMixinLoader { - - @Override - public String getMixinConfig() { - return "mixins.notfine.early.json"; - } - - @Override - public List getMixins(Set loadedCoreMods) { - NotFine.logger.info("Kicking off NotFine early mixins."); - - List mixins = new ArrayList<>(); - - mixins.add("minecraft.clouds.MixinEntityRenderer"); - mixins.add("minecraft.clouds.MixinGameSettings"); - mixins.add("minecraft.clouds.MixinRenderGlobal"); - mixins.add("minecraft.clouds.MixinWorldType"); - - mixins.add("minecraft.glint.MixinItemRenderer"); - mixins.add("minecraft.glint.MixinRenderBiped"); - mixins.add("minecraft.glint.MixinRenderItem"); - mixins.add("minecraft.glint.MixinRenderPlayer"); - - mixins.add("minecraft.gui.MixinGuiSlot"); - - mixins.add("minecraft.leaves.MixinBlockLeaves"); - mixins.add("minecraft.leaves.MixinBlockLeavesBase"); - - mixins.add("minecraft.particles.MixinBlockEnchantmentTable"); - mixins.add("minecraft.particles.MixinEffectRenderer"); - mixins.add("minecraft.particles.MixinWorldClient"); - mixins.add("minecraft.particles.MixinWorldProvider"); - - mixins.add("minecraft.toggle.MixinGuiIngame"); - mixins.add("minecraft.toggle.MixinEntityRenderer"); - mixins.add("minecraft.toggle.MixinRender"); - mixins.add("minecraft.toggle.MixinRenderItem"); - - mixins.add("minecraft.MixinGameSettings"); - mixins.add("minecraft.MixinRenderGlobal"); - - return mixins; - } - - @Override - public String[] getASMTransformerClass() { - return null; - } - - @Override - public String getModContainerClass() { - return null; - } - - @Override - public String getSetupClass() { - return null; - } - - @Override - public void injectData(Map data) { - - } - - @Override - public String getAccessTransformerClass() { - return null; - } - -} diff --git a/src/main/java/jss/notfine/mixinplugin/NotFineLateMixins.java b/src/main/java/jss/notfine/mixinplugin/NotFineLateMixins.java deleted file mode 100644 index e1c096c74..000000000 --- a/src/main/java/jss/notfine/mixinplugin/NotFineLateMixins.java +++ /dev/null @@ -1,59 +0,0 @@ -package jss.notfine.mixinplugin; - -import com.gtnewhorizon.gtnhmixins.ILateMixinLoader; -import com.gtnewhorizon.gtnhmixins.LateMixin; -import cpw.mods.fml.common.Loader; -import cpw.mods.fml.common.ModContainer; -import cpw.mods.fml.common.versioning.ArtifactVersion; -import cpw.mods.fml.common.versioning.DefaultArtifactVersion; -import cpw.mods.fml.common.versioning.InvalidVersionSpecificationException; -import cpw.mods.fml.common.versioning.VersionRange; -import jss.notfine.NotFine; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -@LateMixin -public class NotFineLateMixins implements ILateMixinLoader { - - @Override - public String getMixinConfig() { - return "mixins.notfine.late.json"; - } - - @Override - public List getMixins(Set loadedMods) { - NotFine.logger.info("Kicking off NotFine late mixins."); - - List mixins = new ArrayList<>(); - - if(loadedMods.contains("Thaumcraft")) { - mixins.add("thaumcraft.leaves.MixinBlockMagicalLeaves"); - } - - if(loadedMods.contains("TwilightForest")) { - mixins.add("twilightforest.leaves.MixinBlockTFLeaves"); - mixins.add("twilightforest.leaves.MixinBlockTFLeaves3"); - - //Non-GTNH Twilight Forest builds will break horribly with this mixin. - boolean modernBuild = false; - try { - ArtifactVersion accepted = new DefaultArtifactVersion("TwilightForest", VersionRange.createFromVersionSpec("[2.3.8.18,)")); - ModContainer mc = Loader.instance().getIndexedModList().get("TwilightForest"); - if(mc != null) modernBuild = accepted.containsVersion(mc.getProcessedVersion()); - } catch (InvalidVersionSpecificationException ignored) { - } - if(modernBuild) { - mixins.add("twilightforest.leaves.MixinBlockTFMagicLeaves"); - } - } - - if(loadedMods.contains("witchery")) { - mixins.add("witchery.leaves.MixinBlockWitchLeaves"); - } - - return mixins; - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/ArchaicCore.java b/src/main/java/org/embeddedt/archaicfix/ArchaicCore.java deleted file mode 100644 index 08f1489c8..000000000 --- a/src/main/java/org/embeddedt/archaicfix/ArchaicCore.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.embeddedt.archaicfix; - -import com.google.common.collect.ImmutableMap; -import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader; -import cpw.mods.fml.relauncher.IFMLLoadingPlugin; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.embeddedt.archaicfix.asm.Mixin; -import org.embeddedt.archaicfix.asm.TargetedMod; -import org.embeddedt.archaicfix.asm.transformer.VampirismTransformer; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.config.ConfigException; -import org.embeddedt.archaicfix.config.ConfigurationManager; -import org.embeddedt.archaicfix.helpers.LetsEncryptHelper; - -import java.util.*; -import java.util.stream.Collectors; - -@IFMLLoadingPlugin.Name("ArchaicCore") -@IFMLLoadingPlugin.MCVersion("1.7.10") -public class ArchaicCore implements IFMLLoadingPlugin, IEarlyMixinLoader { - public static final Logger LOGGER = LogManager.getLogger("ArchaicCore"); - static { - VampirismTransformer.init(); - try { - ConfigurationManager.registerConfig(ArchaicConfig.class); - } catch(ConfigException e) { - throw new RuntimeException(e); - } - LetsEncryptHelper.replaceSSLContext(); - } - @Override - public String[] getASMTransformerClass() { - return new String[] { - "org.embeddedt.archaicfix.asm.ArchaicTransformer" - }; - } - - @Override - public String getModContainerClass() { - return null; - } - - @Override - public String getSetupClass() { - return null; - } - - @Override - public void injectData(Map data) { - - } - - @Override - public String getAccessTransformerClass() { - return null; - } - - @Override - public String getMixinConfig() { - return "mixins.archaicfix.early.json"; - } - - public static Set coreMods = new HashSet<>(); - - private static final ImmutableMap MODS_BY_CLASS = ImmutableMap.builder() - .put("optifine.OptiFineForgeTweaker", TargetedMod.OPTIFINE) - .put("fastcraft.Tweaker", TargetedMod.FASTCRAFT) - .put("cofh.asm.LoadingPlugin", TargetedMod.COFHCORE) - .build(); - - private static void detectCoreMods(Set loadedCoreMods) { - MODS_BY_CLASS.forEach((key, value) -> { - if (loadedCoreMods.contains(key)) - coreMods.add(value); - }); - } - - @Override - public List getMixins(Set loadedCoreMods) { - List mixins = new ArrayList<>(); - detectCoreMods(loadedCoreMods); - LOGGER.info("Detected coremods: [" + coreMods.stream().map(TargetedMod::name).collect(Collectors.joining(", ")) + "]"); - for(Mixin mixin : Mixin.values()) { - if(mixin.getPhase() == Mixin.Phase.EARLY && mixin.shouldLoadSide() && mixin.getFilter().test(coreMods)) { - mixins.add(mixin.getMixin()); - } - } - return mixins; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java b/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java index e0fb581aa..c7fd92506 100644 --- a/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java +++ b/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java @@ -1,29 +1,21 @@ package org.embeddedt.archaicfix; import cpw.mods.fml.common.FMLCommonHandler; -import cpw.mods.fml.common.Loader; -import cpw.mods.fml.common.SidedProxy; -import cpw.mods.fml.common.event.*; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.Mod.EventHandler; -import cpw.mods.fml.common.network.NetworkCheckHandler; +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.FMLConstructionEvent; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLLoadCompleteEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.event.FMLServerStartingEvent; import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper; -import cpw.mods.fml.relauncher.ReflectionHelper; import cpw.mods.fml.relauncher.Side; -import net.minecraft.client.Minecraft; -import net.minecraft.entity.Entity; -import net.minecraft.item.crafting.CraftingManager; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.network.NetHandlerPlayServer; import net.minecraftforge.common.MinecraftForge; import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; -import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; import org.embeddedt.archaicfix.proxy.CommonProxy; -import thaumcraft.api.ThaumcraftApi; - -import java.util.*; +import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; @Mod(modid = ArchaicFix.MODID, version = ArchaicFix.VERSION, dependencies = "required-after:gtnhmixins@[2.0.0,);", guiFactory = "org.embeddedt.archaicfix.config.ArchaicGuiConfigFactory") public class ArchaicFix @@ -33,9 +25,7 @@ public class ArchaicFix private FixHelper helper; - public static final SimpleNetworkWrapper NETWORK = NetworkRegistry.INSTANCE.newSimpleChannel("archaicfix"); - public static volatile boolean IS_VANILLA_SERVER = false; - public static boolean NEI_INSTALLED = false; + public static final SimpleNetworkWrapper NETWORK = NetworkRegistry.INSTANCE.newSimpleChannel(MODID); @SidedProxy(clientSide = "org.embeddedt.archaicfix.proxy.ClientProxy", serverSide = "org.embeddedt.archaicfix.proxy.CommonProxy") public static CommonProxy proxy; @@ -48,37 +38,22 @@ public void onConstruct(FMLConstructionEvent event) { ArchaicLogger.LOGGER.fatal("A version of GG Util that includes threaded lighting was detected. ArchaicFix has prevented launching to avoid issues. Please download a fixed version of GG Util: https://www.curseforge.com/minecraft/mc-mods/gilded-game-utils-fix."); ArchaicLogger.LOGGER.fatal("==============================================="); throw new UnsupportedOperationException("Please download a fixed version of GG Util: https://www.curseforge.com/minecraft/mc-mods/gilded-game-utils-fix"); - } catch(ClassNotFoundException e) { - - } + } catch(ClassNotFoundException ignored) {} } @EventHandler - public void preinit(FMLPreInitializationEvent event) - { - int nextID = ReflectionHelper.getPrivateValue(Entity.class, null, "field_70152_a", "nextEntityID"); - if(nextID == 0) { - ReflectionHelper.setPrivateValue(Entity.class, null, 1, "field_70152_a", "nextEntityID"); - ArchaicLogger.LOGGER.info("Fixed MC-111480"); - } - MinecraftForge.EVENT_BUS.register(new LeftClickEventHandler()); + public void preinit(FMLPreInitializationEvent event) { helper = new FixHelper(); MinecraftForge.EVENT_BUS.register(helper); FMLCommonHandler.instance().bus().register(helper); proxy.preinit(); - NEI_INSTALLED = Loader.isModLoaded("NotEnoughItems"); - //SoundSystemConfig.setNumberNormalChannels(1073741824); - //SoundSystemConfig.setNumberStreamingChannels(1073741823); } @EventHandler public void init(FMLInitializationEvent event) { - if(event.getSide() == Side.CLIENT) { - if(ArchaicConfig.enableThreadedChunkUpdates - && ArchaicConfig.enableOcclusionTweaks) { - ThreadedChunkUpdateHelper.instance = new ThreadedChunkUpdateHelper(); - ThreadedChunkUpdateHelper.instance.init(); - } + if(event.getSide() == Side.CLIENT && (ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks)) { + ThreadedChunkUpdateHelper.instance = new ThreadedChunkUpdateHelper(); + ThreadedChunkUpdateHelper.instance.init(); } } @@ -87,79 +62,9 @@ public void serverStart(FMLServerStartingEvent event) { event.registerServerCommand(new CommandDebugUpdateQueue()); } - private void printRecipeDebug() { - if(!ArchaicConfig.cacheRecipes) - return; - HashMap, Integer> recipeTypeMap = new HashMap<>(); - for(Object o : CraftingManager.getInstance().getRecipeList()) { - recipeTypeMap.compute(((IRecipe)o).getClass(), (key, oldValue) -> { - if(oldValue == null) - return 1; - else - return oldValue + 1; - }); - } - recipeTypeMap.entrySet().stream() - .sorted(Comparator.comparingInt(pair -> pair.getValue())) - .forEach(pair -> { - String acceleratedSuffix = IAcceleratedRecipe.class.isAssignableFrom(pair.getKey()) ? " (accelerated)" : ""; - ArchaicLogger.LOGGER.info("There are " + pair.getValue() + " recipes of type " + pair.getKey().getName() + acceleratedSuffix); - }); - int totalRecipes = recipeTypeMap.values().stream().reduce(0, Integer::sum); - int acceleratedRecipes = recipeTypeMap.entrySet().stream().filter(pair -> IAcceleratedRecipe.class.isAssignableFrom(pair.getKey())).map(Map.Entry::getValue).reduce(0, Integer::sum); - ArchaicLogger.LOGGER.info(acceleratedRecipes + " / " + totalRecipes + " recipes are accelerated!"); - } - - private void removeThaumcraftLeak() { - if(!Loader.isModLoaded("Thaumcraft")) { - boolean thaumcraftGhostApiPresent = false; - try { - Class.forName("thaumcraft.api.ThaumcraftApi"); - thaumcraftGhostApiPresent = true; - } catch(Exception e) { - - } - if(thaumcraftGhostApiPresent) { - try { - ArchaicLogger.LOGGER.info("Cleared " + ThaumcraftApi.objectTags.size() + " unused Thaumcraft aspects"); - ThaumcraftApi.objectTags.clear(); - } catch (IncompatibleClassChangeError e) { - ArchaicLogger.LOGGER.info("Thaumcraft does not have an objectTags field"); - } - try { - ArchaicLogger.LOGGER.info("Cleared " + ThaumcraftApi.groupedObjectTags.size() + " unused Thaumcraft grouped aspects"); - ThaumcraftApi.groupedObjectTags.clear(); - } catch (IncompatibleClassChangeError e) { - ArchaicLogger.LOGGER.info("Thaumcraft does not have a groupedObjectTags field"); - } - } - } - } - - - @EventHandler public void loadComplete(FMLLoadCompleteEvent event) { proxy.loadcomplete(); - printRecipeDebug(); - removeThaumcraftLeak(); } - @NetworkCheckHandler - public boolean doVersionCheck(Map mods, Side side) { - /* - if(mods.containsKey(Tags.MODID)) { - String otherVersion = mods.get(Tags.MODID); - if(!otherVersion.equals(Tags.VERSION)) { - ArchaicLogger.LOGGER.error("Remote side " + side + " has different version " + otherVersion); - return false; - } - } - */ - return true; - } - - public static boolean isArchaicConnection(NetHandlerPlayServer connection) { - return FixHelper.unmoddedNetHandlers.contains(connection); - } } diff --git a/src/main/java/org/embeddedt/archaicfix/FixHelper.java b/src/main/java/org/embeddedt/archaicfix/FixHelper.java index d04275984..aadd7edc5 100644 --- a/src/main/java/org/embeddedt/archaicfix/FixHelper.java +++ b/src/main/java/org/embeddedt/archaicfix/FixHelper.java @@ -1,32 +1,22 @@ package org.embeddedt.archaicfix; import cpw.mods.fml.common.eventhandler.SubscribeEvent; -import cpw.mods.fml.common.network.FMLNetworkEvent; -import cpw.mods.fml.common.network.handshake.IHandshakeState; -import io.netty.channel.ChannelHandlerContext; -import io.netty.util.Attribute; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.monster.EntitySlime; -import net.minecraft.item.crafting.CraftingManager; -import net.minecraft.network.NetHandlerPlayServer; import net.minecraftforge.event.entity.living.LivingEvent; import net.minecraftforge.oredict.OreDictionary; -import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; +import org.embeddedt.archaicfix.interfaces.IAcceleratedRecipe; import org.embeddedt.archaicfix.helpers.OreDictIterator; -import java.util.*; +import java.util.ArrayList; public class FixHelper { - public static ArrayList recipesHoldingPotentialItems = new ArrayList<>(); - public static Set unmoddedNetHandlers = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>())); - - public static Map>> handshakeStateMap = Collections.synchronizedMap(new WeakHashMap<>()); + public static final ArrayList recipesHoldingPotentialItems = new ArrayList<>(); @SubscribeEvent public void onSizeUpdate(LivingEvent.LivingUpdateEvent event) { EntityLivingBase entity = event.entityLiving; - if(entity.worldObj.isRemote && entity instanceof EntitySlime && entity.getAge() <= 1) { - EntitySlime slime = (EntitySlime)entity; + if(entity.worldObj.isRemote && entity instanceof EntitySlime slime && entity.getAge() <= 1) { float newSize = 0.6F * (float)slime.getSlimeSize(); slime.width = newSize; slime.height = newSize; @@ -43,30 +33,4 @@ public void onOreRegister(OreDictionary.OreRegisterEvent event) { recipesHoldingPotentialItems.clear(); OreDictIterator.clearCache(event.Name); } - - @SubscribeEvent - public void onClientConnect(FMLNetworkEvent.ClientConnectedToServerEvent event) { - if(!event.connectionType.equals("MODDED")) { - ArchaicLogger.LOGGER.info("Connected to vanilla server"); - ArchaicFix.IS_VANILLA_SERVER = true; - } - } - - @SubscribeEvent - public void onNetworkRegister(FMLNetworkEvent.CustomPacketRegistrationEvent event) { - if(event.operation.equals("REGISTER")) { - boolean hasArchaic = event.registrations.contains("archaicfix"); - if(event.handler instanceof NetHandlerPlayServer) { - if(!hasArchaic) { - ArchaicLogger.LOGGER.info("Player is connecting without ArchaicFix installed"); - unmoddedNetHandlers.add(event.handler); - } - - } else { - ArchaicFix.IS_VANILLA_SERVER = !hasArchaic; - if(!hasArchaic) - ArchaicLogger.LOGGER.info("Connecting to server without ArchaicFix installed"); - } - } - } } diff --git a/src/main/java/org/embeddedt/archaicfix/LeftClickEventHandler.java b/src/main/java/org/embeddedt/archaicfix/LeftClickEventHandler.java deleted file mode 100644 index daddaf3f3..000000000 --- a/src/main/java/org/embeddedt/archaicfix/LeftClickEventHandler.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.embeddedt.archaicfix; - -import cpw.mods.fml.common.eventhandler.SubscribeEvent; -import net.minecraft.block.Block; -import net.minecraft.command.IEntitySelector; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.AxisAlignedBB; -import net.minecraft.util.MovingObjectPosition; -import net.minecraft.util.Vec3; -import net.minecraft.world.World; -import net.minecraftforge.event.entity.player.PlayerInteractEvent; - -import javax.annotation.Nullable; -import java.util.List; - -public final class LeftClickEventHandler { - - public LeftClickEventHandler() {} - - @SubscribeEvent - public void onLeftClick(PlayerInteractEvent event) { - if(event.action == PlayerInteractEvent.Action.LEFT_CLICK_BLOCK) { - Block block = event.world.getBlock(event.x, event.y, event.z); - if(block.getCollisionBoundingBoxFromPool(event.world, event.x, event.y, event.z) != null) { - return; - } - - EntityPlayer entityPlayer = event.entityPlayer; - - float blockReachDistance = 4.5F; - - Vec3 from = Vec3.createVectorHelper(entityPlayer.posX, entityPlayer.posY + (double)entityPlayer.getEyeHeight(), entityPlayer.posZ); - Vec3 vec3d = entityPlayer.getLook(1.0F); - Vec3 to = from.addVector(vec3d.xCoord * blockReachDistance, vec3d.yCoord * blockReachDistance, vec3d.zCoord * blockReachDistance); - - Entity targetEntity = getEntityClosestToStartPos(entityPlayer, event.world, from, to); - - if(targetEntity != null) { - if (!event.world.isRemote) { - entityPlayer.attackTargetEntityWithCurrentItem(targetEntity); - } - event.setCanceled(true); - } - } - - - } - - private AxisAlignedBB safeGenBoundingBox(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { - return AxisAlignedBB.getBoundingBox( - Math.min(minX, maxX), - Math.min(minY, maxY), - Math.min(minZ, maxZ), - Math.max(minX, maxX), - Math.max(minY, maxY), - Math.max(minZ, maxZ) - ); - } - - private Entity getEntityClosestToStartPos(Entity entityIn, World world, Vec3 startPos, Vec3 endPos) { - Entity entity = null; - AxisAlignedBB searchBB = safeGenBoundingBox(startPos.xCoord,startPos.yCoord,startPos.zCoord, endPos.xCoord, endPos.yCoord, endPos.zCoord); - List list = world.getEntitiesWithinAABBExcludingEntity(entityIn, searchBB, new IEntitySelector() { - @Override - public boolean isEntityApplicable(Entity p_82704_1_) { - return p_82704_1_ != null && p_82704_1_.canBeCollidedWith(); - } - }); - - double d0 = 0.0D; - AxisAlignedBB axisAlignedBB; - - for(Entity entity1 : list) { - axisAlignedBB = entity1.boundingBox.expand(0.3D, 0.3D, 0.3D); - MovingObjectPosition raytraceResult = axisAlignedBB.calculateIntercept(startPos, endPos); - - if(raytraceResult != null) { - double d1 = startPos.squareDistanceTo(raytraceResult.hitVec); - - if(d1 < d0 || d0 == 0.0D) { - entity = entity1; - d0 = d1; - } - } - } - return entity; - } -} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/asm/ArchaicTransformer.java b/src/main/java/org/embeddedt/archaicfix/asm/ArchaicTransformer.java deleted file mode 100644 index ea75fe222..000000000 --- a/src/main/java/org/embeddedt/archaicfix/asm/ArchaicTransformer.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.embeddedt.archaicfix.asm; - -import net.minecraft.launchwrapper.IClassTransformer; -import org.embeddedt.archaicfix.asm.transformer.VampirismTransformer; - -import java.util.*; - -public class ArchaicTransformer implements IClassTransformer { - - private static final List transformers = Arrays.asList( - //new ThreadedBlockTransformer(), - new VampirismTransformer() - ); - - @Override - public byte[] transform(String name, String transformedName, byte[] basicClass) { - for(IClassTransformer transformer : transformers) { - basicClass = transformer.transform(name, transformedName, basicClass); - } - return basicClass; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/asm/LateMixinPlugin.java b/src/main/java/org/embeddedt/archaicfix/asm/LateMixinPlugin.java deleted file mode 100644 index bf3790a27..000000000 --- a/src/main/java/org/embeddedt/archaicfix/asm/LateMixinPlugin.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.embeddedt.archaicfix.asm; - -import com.gtnewhorizon.gtnhmixins.ILateMixinLoader; -import com.gtnewhorizon.gtnhmixins.LateMixin; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.embeddedt.archaicfix.ArchaicCore; - -import java.util.*; -import java.util.stream.Collectors; - -@LateMixin -public class LateMixinPlugin implements ILateMixinLoader { - private static final Logger LOGGER = LogManager.getLogger(); - @Override - public String getMixinConfig() { - return "mixins.archaicfix.late.json"; - } - - @Override - public List getMixins(Set loadedMods) { - List mixins = new ArrayList<>(); - Set validMods = new HashSet<>(ArchaicCore.coreMods); - HashMap modById = new HashMap<>(); - for(TargetedMod t : TargetedMod.values()) { - if(t.getModId() != null) - modById.put(t.getModId(), t); - } - for(String modId : loadedMods) { - TargetedMod t = modById.get(modId); - if(t != null) - validMods.add(t); - } - LOGGER.info("Detected mods: [" + validMods.stream().map(TargetedMod::name).collect(Collectors.joining(", ")) + "]"); - for(Mixin mixin : Mixin.values()) { - if(mixin.getPhase() == Mixin.Phase.LATE && mixin.shouldLoadSide() && mixin.getFilter().test(validMods)) - mixins.add(mixin.getMixin()); - } - return mixins; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/asm/Mixin.java b/src/main/java/org/embeddedt/archaicfix/asm/Mixin.java deleted file mode 100644 index 914941d36..000000000 --- a/src/main/java/org/embeddedt/archaicfix/asm/Mixin.java +++ /dev/null @@ -1,164 +0,0 @@ -package org.embeddedt.archaicfix.asm; - -import cpw.mods.fml.relauncher.FMLLaunchHandler; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.helpers.DragonAPIHelper; - -import java.util.Collection; -import java.util.List; -import java.util.Locale; -import java.util.function.Predicate; - -@RequiredArgsConstructor -public enum Mixin { - // COMMON MIXINS - common_chickenchunks_MixinPlayerChunkViewerManager(Side.COMMON, Phase.EARLY, require(TargetedMod.CHICKENCHUNKS), "chickenchunks.MixinPlayerChunkViewerManager"), - common_core_AccessorEntityLiving(Side.COMMON, Phase.EARLY, always(), "core.AccessorEntityLiving"), - common_core_MixinEntityPlayerMP(Side.COMMON, Phase.EARLY, always(), "core.MixinEntityPlayerMP"), - common_core_MixinWorldServer(Side.COMMON, Phase.EARLY, always(), "core.MixinWorldServer"), - common_core_MixinMapGenStructure(Side.COMMON, Phase.EARLY, always(), "core.MixinMapGenStructure"), - common_core_MixinEntityVillager(Side.COMMON, Phase.EARLY, always(), "core.MixinEntityVillager"), - common_core_MixinMerchantRecipe(Side.COMMON, Phase.EARLY, always(), "core.MixinMerchantRecipe"), - common_core_MixinAxisAlignedBB(Side.COMMON, Phase.EARLY, always(), "core.MixinAxisAlignedBB"), - common_core_MixinMaterialLiquid(Side.COMMON, Phase.EARLY, always(), "core.MixinMaterialLiquid"), - common_core_MixinChunkProviderServer(Side.COMMON, Phase.EARLY, always(), "core.MixinChunkProviderServer"), - common_core_MixinSpawnerAnimals(Side.COMMON, Phase.EARLY, always(), "core.MixinSpawnerAnimals"), - common_core_MixinShapedOreRecipe(Side.COMMON, Phase.EARLY, always(), "core.MixinShapedOreRecipe"), - common_core_MixinLongHashMap(Side.COMMON, Phase.EARLY, always(), "core.MixinLongHashMap"), - common_core_MixinBlock(Side.COMMON, Phase.EARLY, always(), "core.MixinBlock"), - common_core_MixinEnchantmentHelper(Side.COMMON, Phase.EARLY, always(), "core.MixinEnchantmentHelper"), - common_core_MixinWorldChunkManager(Side.COMMON, Phase.EARLY, always(), "core.MixinWorldChunkManager"), - common_core_MixinShapedRecipes(Side.COMMON, Phase.EARLY, always(), "core.MixinShapedRecipes"), - common_core_MixinShapelessOreRecipe(Side.COMMON, Phase.EARLY, always(), "core.MixinShapelessOreRecipe"), - common_core_MixinShapelessRecipes(Side.COMMON, Phase.EARLY, always(), "core.MixinShapelessRecipes"), - common_core_MixinEntityLiving(Side.COMMON, Phase.EARLY, always(), "core.MixinEntityLiving"), - common_core_MixinWorld(Side.COMMON, Phase.EARLY, always(), "core.MixinWorld"), - common_core_MixinEntityTrackerEntry(Side.COMMON, Phase.EARLY, always(), "core.MixinEntityTrackerEntry"), - common_core_MixinEntityXPOrb(Side.COMMON, Phase.EARLY, always(), "core.MixinEntityXPOrb"), - common_core_MixinEntityItem(Side.COMMON, Phase.EARLY, avoid(TargetedMod.SHIPSMOD).and(m -> ArchaicConfig.itemLagReduction), "core.MixinEntityItem"), - common_core_MixinEntity(Side.COMMON, Phase.EARLY, always(), "core.MixinEntity"), - common_core_MixinForgeChunkManager(Side.COMMON, Phase.EARLY, always(), "core.MixinForgeChunkManager"), - common_core_MixinChunk(Side.COMMON, Phase.EARLY, always(), "core.MixinChunk"), - common_core_MixinStructureStart(Side.COMMON, Phase.EARLY, always(), "core.MixinStructureStart"), - common_core_MixinOreDictionary(Side.COMMON, Phase.EARLY, always(), "core.MixinOreDictionary"), - common_core_MixinChunkProviderHell(Side.COMMON, Phase.EARLY, always(), "core.MixinChunkProviderHell"), - common_core_MixinASMData(Side.COMMON, Phase.EARLY, always(), "core.MixinASMData"), - common_core_MixinModCandidate(Side.COMMON, Phase.EARLY, avoid(TargetedMod.COFHCORE), "core.MixinModCandidate"), - common_core_MixinNetworkDispatcher(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetworkDispatcher"), - common_core_MixinNetworkManager(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetworkManager"), - common_core_MixinEmbeddedChannel(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinEmbeddedChannel"), - common_core_MixinNetHandlerPlayServer(Side.COMMON, Phase.EARLY, always(), "core.MixinNetHandlerPlayServer"), - common_core_MixinObjectIntIdentityMap(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.optimizeObjectIntIdentityMap, "core.MixinObjectIntIdentityMap"), - common_gt6_MixinCR(Side.COMMON, Phase.LATE, require(TargetedMod.GREGTECH6), "gt6.MixinCR"), - common_lighting_MixinAnvilChunkLoader(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinAnvilChunkLoader"), - common_lighting_MixinChunk(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinChunk"), - common_lighting_MixinChunkProviderServer(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinChunkProviderServer"), - common_lighting_MixinChunkVanilla(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinChunkVanilla"), - common_lighting_MixinExtendedBlockStorage(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinExtendedBlockStorage"), - common_lighting_MixinSPacketChunkData(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinSPacketChunkData"), - common_lighting_MixinWorld(Side.COMMON, Phase.EARLY, phosphor(), "lighting.MixinWorld_Lighting"), - common_mrtjp_MixinBlockUpdateHandler(Side.COMMON, Phase.LATE, require(TargetedMod.MRTJPCORE), "mrtjp.MixinBlockUpdateHandler"), - // CLIENT MIXINS - client_core_MixinThreadDownloadImageData(Side.CLIENT, Phase.EARLY, always(), "core.MixinThreadDownloadImageData"), - client_core_MixinBlockFence(Side.CLIENT, Phase.EARLY, always(), "core.MixinBlockFence"), - client_core_MixinEntityRenderer(Side.CLIENT, Phase.EARLY, always(), "core.MixinEntityRenderer"), - client_core_MixinGuiBeaconButton(Side.CLIENT, Phase.EARLY, always(), "core.MixinGuiBeaconButton"), - client_core_MixinGuiButton(Side.CLIENT, Phase.EARLY, always(), "core.MixinGuiButton"), - client_core_MixinGuiContainerCreative(Side.CLIENT, Phase.EARLY, always(), "core.MixinGuiContainerCreative"), - client_core_MixinIntegratedServer(Side.CLIENT, Phase.EARLY, always(), "core.MixinIntegratedServer"), - client_core_MixinSkinManager(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.fixSkinMemoryLeak, "core.MixinSkinManager"), - client_core_MixinChunkProviderClient(Side.CLIENT, Phase.EARLY, always(), "core.MixinChunkProviderClient"), - client_core_MixinWorldRenderer(Side.CLIENT, Phase.EARLY, m -> !Boolean.valueOf(System.getProperty("archaicFix.disableMC129", "false")), "core.MixinWorldRenderer"), - client_core_MixinMinecraft(Side.CLIENT, Phase.EARLY, always(), "core.MixinMinecraft"), - client_core_MixinNetHandlerPlayClient(Side.CLIENT, Phase.EARLY, always(), "core.MixinNetHandlerPlayClient"), - client_core_MixinGuiCreateWorld(Side.CLIENT, Phase.EARLY, always(), "core.MixinGuiCreateWorld"), - client_core_MixinGuiIngameForge(Side.CLIENT, Phase.EARLY, always(), "core.MixinGuiIngameForge"), - client_core_MixinFMLClientHandler(Side.CLIENT, Phase.EARLY, always(), "core.MixinFMLClientHandler"), - client_core_MixinNetHandlerLoginClient(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetHandlerLoginClient"), - client_core_MixinSplashProgress(Side.CLIENT, Phase.EARLY, always(), "core.MixinSplashProgress"), - client_core_AccessorSplashProgress(Side.CLIENT, Phase.EARLY, always(), "core.AccessorSplashProgress"), - client_core_MixinRenderItem(Side.CLIENT, Phase.EARLY, always(), "core.MixinRenderItem"), - client_lighting_MixinMinecraft(Side.CLIENT, Phase.EARLY, phosphor(), "lighting.MixinMinecraft"), - client_lighting_MixinWorld(Side.CLIENT, Phase.EARLY, phosphor(), "lighting.MixinWorld"), - client_lighting_MixinChunkCache(Side.CLIENT, Phase.EARLY, phosphor(), "lighting.MixinChunkCache"), - - client_optifine_MixinVersionCheckThread(Side.CLIENT, Phase.EARLY, require(TargetedMod.OPTIFINE).and(m -> ArchaicConfig.disableOFVersionCheck), "optifine.MixinVersionCheckThread"), - - client_occlusion_MixinChunk(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableOcclusionTweaks), "occlusion.MixinChunk"), - client_occlusion_MixinEntityRenderer(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableOcclusionTweaks), "occlusion.MixinEntityRenderer"), - client_occlusion_MixinRenderGlobal(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableOcclusionTweaks), "occlusion.MixinRenderGlobal"), - client_occlusion_MixinGuiVideoSettings(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableOcclusionTweaks), "occlusion.MixinGuiVideoSettings"), - client_occlusion_MixinWorldRenderer(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableOcclusionTweaks), "occlusion.MixinWorldRenderer"), - - client_renderdistance_MixinGameSettings(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.raiseMaxRenderDistance), "renderdistance.MixinGameSettings"), - client_renderdistance_MixinRenderGlobal(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.raiseMaxRenderDistance), "renderdistance.MixinRenderGlobal"), - common_renderdistance_MixinPlayerManager(Side.COMMON, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.raiseMaxRenderDistance), "renderdistance.MixinPlayerManager"), - - client_threadedupdates_MixinRenderBlocks(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks), "threadedupdates.MixinRenderBlocks"), - client_threadedupdates_MixinWorldRenderer(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks), "threadedupdates.MixinWorldRenderer"), - client_threadedupdates_MixinTessellator(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks), "threadedupdates.MixinTessellator"), - client_threadedupdates_MixinTessellator_Debug(Side.CLIENT, Phase.EARLY, avoid(TargetedMod.OPTIFINE).and(avoid(TargetedMod.FASTCRAFT)).and(m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks && Boolean.parseBoolean(System.getProperty("archaicfix.debug.verifyTessellatorAccessThread"))), "threadedupdates.MixinTessellator_Debug"), - - // MOD-FILTERED MIXINS - common_lighting_fastcraft_MixinChunk(Side.COMMON, Phase.EARLY, require(TargetedMod.FASTCRAFT).and(phosphor()), "lighting.fastcraft.MixinChunk"), - common_lighting_fastcraft_MixinChunkProviderServer(Side.COMMON, Phase.EARLY, require(TargetedMod.FASTCRAFT).and(phosphor()), "lighting.fastcraft.MixinChunkProviderServer"), - common_lighting_fastcraft_MixinWorld(Side.COMMON, Phase.EARLY, require(TargetedMod.FASTCRAFT).and(phosphor()), "lighting.fastcraft.MixinWorld"), - - common_botania_MixinBlockSpecialFlower(Side.COMMON, Phase.LATE, require(TargetedMod.BOTANIA), "botania.MixinBlockSpecialFlower"), - - common_extrautils_MixinEventHandlerSiege(Side.COMMON, Phase.LATE, require(TargetedMod.EXTRAUTILS), "extrautils.MixinEventHandlerSiege"), - common_extrautils_MixinEventHandlerServer(Side.COMMON, Phase.LATE, require(TargetedMod.EXTRAUTILS), "extrautils.MixinEventHandlerServer"), - common_extrautils_MixinItemDivisionSigil(Side.COMMON, Phase.LATE, require(TargetedMod.EXTRAUTILS), "extrautils.MixinItemDivisionSigil"), - common_extrautils_MixinTileEntityTrashCan(Side.COMMON, Phase.LATE, require(TargetedMod.EXTRAUTILS), "extrautils.MixinTileEntityTrashCan"), - - client_journeymap_MixinTileDrawStep(Side.CLIENT, Phase.LATE, require(TargetedMod.JOURNEYMAP).and(m -> ArchaicConfig.removeJourneymapDebug), "journeymap.MixinTileDrawStep"), - - - // The modFilter argument is a predicate, so you can also use the .and(), .or(), and .negate() methods to mix and match multiple predicates. - ; - - @Getter - public final Side side; - @Getter - public final Phase phase; - @Getter - public final Predicate> filter; - private final String mixin; - - static Predicate> phosphor() { - return m -> ArchaicConfig.enablePhosphor; - } - - static Predicate> require(TargetedMod in) { - return modList -> modList.contains(in); - } - - static Predicate> avoid(TargetedMod in) { - return modList -> !modList.contains(in); - } - - static Predicate> always() { - return m -> true; - } - - enum Side { - COMMON, - CLIENT - } - - public enum Phase { - EARLY, - LATE - } - - public boolean shouldLoadSide() { - return (side == Side.COMMON - || (side == Side.CLIENT && FMLLaunchHandler.side().isClient())); - } - - public String getMixin() { - return side.name().toLowerCase(Locale.ROOT) + "." + mixin; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/asm/TargetedMod.java b/src/main/java/org/embeddedt/archaicfix/asm/TargetedMod.java deleted file mode 100644 index ec8822361..000000000 --- a/src/main/java/org/embeddedt/archaicfix/asm/TargetedMod.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.embeddedt.archaicfix.asm; - - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.util.function.Predicate; - -@RequiredArgsConstructor -public enum TargetedMod { - CHICKENCHUNKS("ChickenChunks", "ChickenChunks"), - MRTJPCORE("MrTJPCore", "MrTJPCoreMod"), - CHUNK_PREGENERATOR("ChunkPregenerator", "chunkpregenerator"), - THERMALEXPANSION("ThermalExpansion", "ThermalExpansion"), - THERMALFOUNDATION("ThermalFoundation", "ThermalFoundation"), - GREGTECH6("GregTech", "gregtech"), - MATTEROVERDRIVE("MatterOverdrive", "mo"), - PROJECTE("ProjectE", "ProjectE"), - TC4TWEAKS("TC4Tweaks", "tc4tweak"), - FASTCRAFT("FastCraft", null), - OPTIFINE("OptiFine", null), - MEKANISM("Mekanism", "Mekanism"), - BOTANIA("Botania", "Botania"), - COFHCORE("CoFHCore", "CoFHCore"), - EXTRAUTILS("ExtraUtilities", "ExtraUtilities"), - DIVINERPG("DivineRPG", "divinerpg"), - SHIPSMOD("ShipsMod", "cuchaz.ships"), - JOURNEYMAP("JourneyMap", "journeymap"), - AM2("ArsMagica2", "arsmagica2"), - FOODPLUS("FoodPlus", "FoodPlus"), - DIVERSITY("Diversity", "diversity"), - AOA("AdventOfAscension", "nevermine") - ; - - @Getter - private final String modName; - @Getter - private final String modId; -} diff --git a/src/main/java/org/embeddedt/archaicfix/asm/transformer/ThreadedBlockTransformer.java b/src/main/java/org/embeddedt/archaicfix/asm/transformer/ThreadedBlockTransformer.java deleted file mode 100644 index 57cb40018..000000000 --- a/src/main/java/org/embeddedt/archaicfix/asm/transformer/ThreadedBlockTransformer.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.embeddedt.archaicfix.asm.transformer; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import net.minecraft.launchwrapper.IClassTransformer; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; - -import java.util.ListIterator; -import java.util.Map; -import java.util.Set; - -import static org.objectweb.asm.Opcodes.ASM5; - -public class ThreadedBlockTransformer implements IClassTransformer { - private static final Set threadedFields = ImmutableSet.of( - "minX", - "minY", - "maxX", - "maxY", - "minZ", - "maxZ" - ); - private static final Map threadedObfFields = ImmutableMap.builder() - .put("field_149759_B", "minX") - .put("field_149760_C", "minY") - .put("field_149755_E", "maxX") - .put("field_149756_F", "maxY") - .put("field_149754_D", "minZ") - .put("field_149757_G", "maxZ") - .build(); - @Override - public byte[] transform(String name, String transformedName, byte[] basicClass) { - /* FIXME this doesn't work outside dev at the moment */ - if(true) - return basicClass; - if(!transformedName.startsWith("org.embeddedt.archaicfix")) { - final ClassReader cr = new ClassReader(basicClass); - final ClassWriter cw = new ClassWriter(0); - - final ClassNode cn = new ClassNode(ASM5); - cr.accept(cn, 0); - for (MethodNode m : cn.methods) { - ListIterator insns = m.instructions.iterator(); - boolean transformed = false; - while(insns.hasNext()) { - AbstractInsnNode node = insns.next(); - if(node.getOpcode() == Opcodes.GETFIELD || node.getOpcode() == Opcodes.PUTFIELD) { - boolean isSetter = node.getOpcode() == Opcodes.PUTFIELD; - FieldInsnNode f = (FieldInsnNode)node; - if(f.owner.equals("net/minecraft/block/Block")) { - boolean obfContains = threadedObfFields.containsKey(f.name); - boolean devContains = threadedFields.contains(f.name); - if(obfContains || devContains) { - transformed = true; - ArchaicLogger.LOGGER.info("Transforming threaded block data access in {}.{}()", transformedName, m.name); - f.owner = "org/embeddedt/archaicfix/block/ThreadedBlockData"; - if(obfContains) - f.name = threadedObfFields.get(f.name); - insns.previous(); - if(isSetter) { - /* FIXME: assumes a double is at the top of the stack */ - insns.add(new InsnNode(Opcodes.DUP2_X1)); - insns.add(new InsnNode(Opcodes.POP2)); - } - String m_name = "arch$getThreadedData"; - String m_desc = "()Lorg/embeddedt/archaicfix/block/ThreadedBlockData;"; - insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "net/minecraft/block/Block", m_name, m_desc, false)); - if(isSetter) { - insns.add(new InsnNode(Opcodes.DUP_X2)); - insns.add(new InsnNode(Opcodes.POP)); - } - insns.next(); - insns.next(); - } - } - } - } - } - cn.accept(cw); - return cw.toByteArray(); - } - return basicClass; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/asm/transformer/VampirismTransformer.java b/src/main/java/org/embeddedt/archaicfix/asm/transformer/VampirismTransformer.java deleted file mode 100644 index 788e65972..000000000 --- a/src/main/java/org/embeddedt/archaicfix/asm/transformer/VampirismTransformer.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.embeddedt.archaicfix.asm.transformer; - -import cpw.mods.fml.relauncher.ReflectionHelper; -import net.minecraft.launchwrapper.IClassTransformer; -import net.minecraft.launchwrapper.Launch; -import net.minecraft.launchwrapper.LaunchClassLoader; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; - -import java.util.Set; - -import static org.objectweb.asm.Opcodes.ACC_TRANSIENT; -import static org.objectweb.asm.Opcodes.ASM5; -import static org.embeddedt.archaicfix.ArchaicLogger.LOGGER; - -public class VampirismTransformer implements IClassTransformer { - public static void init() { - try { - Set transformerExceptions = ReflectionHelper.getPrivateValue(LaunchClassLoader.class, Launch.classLoader, "transformerExceptions"); - transformerExceptions.remove("de.teamlapen.vampirism"); - } catch(Exception e) { - LOGGER.error("Failed to remove Vampirism from transformer exceptions."); - e.printStackTrace(); - } - } - - @Override - public byte[] transform(String name, String transformedName, byte[] basicClass) { - if(transformedName.equals("de.teamlapen.vampirism.generation.castle.BlockList")) { - LOGGER.info("Transforming " + transformedName + " to set Block field as transient"); - - try { - final ClassReader cr = new ClassReader(basicClass); - final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - - final ClassNode cn = new ClassNode(ASM5); - cr.accept(cn, 0); - - for (FieldNode fn : cn.fields) { - if (fn.name.equals("block") && fn.desc.equals("Lnet/minecraft/block/Block;")) { - fn.access |= ACC_TRANSIENT; - } - } - - cn.accept(cw); - return cw.toByteArray(); - } catch(Exception e) { - e.printStackTrace(); - } - } - - return basicClass; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java b/src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java index 0fee1293d..6041ebeac 100644 --- a/src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java +++ b/src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java @@ -1,7 +1,5 @@ package org.embeddedt.archaicfix.block; -import net.minecraft.block.Block; - public class ThreadedBlockData { public double minX = 0; public double minY = 0; diff --git a/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java b/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java index e3bc2f361..e5f823199 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java +++ b/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java @@ -2,13 +2,13 @@ @Config(modid = "archaicfix") public class ArchaicConfig { - @Config.Comment("Enables the 1.8-style occlusion culling originally developed by CoFHTweaks. Not compatible with OptiFine or FastCraft.") - @Config.DefaultBoolean(false) + @Config.Comment("Enables the 1.8-style occlusion culling originally developed by CoFHTweaks.") + @Config.DefaultBoolean(true) @Config.RequiresMcRestart public static boolean enableOcclusionTweaks; @Config.Comment("EXPERIMENTAL: Enables multi-threaded chunk updating. At the moment it only works if enableOcclusionTweaks is turned on.") - @Config.DefaultBoolean(false) + @Config.DefaultBoolean(true) @Config.RequiresMcRestart public static boolean enableThreadedChunkUpdates; @@ -29,40 +29,16 @@ public class ArchaicConfig { @Config.DefaultBoolean(false) public static boolean enableNewButtonAppearance; - @Config.Comment("Use a faster and asynchronous implementation of creative search.") - @Config.DefaultBoolean(true) - public static boolean asyncCreativeSearch; - @Config.Comment("Cap the integrated server render distance at a minimum of 8 chunks, and adjust despawn ranges so mobs will always despawn properly on low render distances.") @Config.DefaultBoolean(true) public static boolean fixMobSpawnsAtLowRenderDist; - @Config.Comment("Replace the regional difficulty calculation with a TMCW-style one that increases with playtime, not time per chunk.") - @Config.DefaultBoolean(false) - public static boolean betterRegionalDifficulty; - @Config.Comment("Allow 65000 block updates to be performed per tick, rather than 1000.") @Config.DefaultBoolean(true) public static boolean increaseBlockUpdateLimit; - @Config.Comment("EXPERIMENTAL: Cache matching crafting recipes to avoid needing to scan the whole list each time.") - @Config.DefaultBoolean(false) - public static boolean cacheRecipes; - - @Config.Comment("Disable spawn chunks") - @Config.DefaultBoolean(false) - public static boolean disableSpawnChunks; - - @Config.Comment("Reduce lag caused by item entities") - @Config.DefaultBoolean(true) - @Config.RequiresMcRestart - public static boolean itemLagReduction; - - @Config.Comment("Increase the amount of armor mobs wear on average. From TMCW.") - @Config.DefaultBoolean(false) - public static boolean increaseMobArmor; - @Config.Comment("Increase the maximum render distance if OptiFine and FastCraft are not installed.") + @Config.Comment("Increase the maximum render distance.") @Config.DefaultBoolean(false) public static boolean raiseMaxRenderDistance; @@ -71,10 +47,6 @@ public class ArchaicConfig { @Config.RangeInt(min = 16, max = 128) public static int newMaxRenderDistance; - @Config.Comment("EXPERIMENTAL: Replace the Thaumcraft hashing implementation. This really hasn't been tested and probably breaks everything.") - @Config.DefaultBoolean(false) - public static boolean betterThaumcraftHashing; - @Config.Comment("Log when cascading worldgen occurs.") @Config.DefaultBoolean(true) public static boolean logCascadingWorldgen; @@ -83,10 +55,6 @@ public class ArchaicConfig { @Config.DefaultBoolean(false) public static boolean logCascadingWorldgenStacktrace; - @Config.Comment("Fix instances of cascading worldgen in Mekanism.") - @Config.DefaultBoolean(true) - public static boolean fixMekanismCascadingWorldgen; - @Config.Comment("Fix instances of cascading worldgen in vanilla Minecraft. Turn this option off if you require 100% seed parity.") @Config.DefaultBoolean(true) public static boolean fixVanillaCascadingWorldgen; @@ -131,14 +99,6 @@ public class ArchaicConfig { @Config.DefaultStringList({ "Wither", "EnderDragon" }) public static String[] optimizeEntityTickingIgnoreList; - @Config.Comment("Disable OptiFine's version checker.") - @Config.DefaultBoolean(true) - public static boolean disableOFVersionCheck; - - @Config.Comment("Fix TileEntity unloading being laggy.") - @Config.DefaultBoolean(true) - public static boolean fixTEUnloadLag; - @Config.Comment("Attempt to fix hanging in SP when logging in.") @Config.DefaultBoolean(true) public static boolean fixLoginRaceCondition; @@ -179,10 +139,6 @@ public class ArchaicConfig { @Config.DefaultBoolean(false) public static boolean forceFancyItems; - @Config.Comment("Disable Food Plus' update message.") - @Config.DefaultBoolean(true) - public static boolean disableFoodPlusUpdates; - @Config.Comment("Add the Let's Encrypt root certificates to the default trust store.") @Config.DefaultBoolean(false) public static boolean enableLetsEncryptRoot; diff --git a/src/main/java/org/embeddedt/archaicfix/config/ConfigurationManager.java b/src/main/java/org/embeddedt/archaicfix/config/ConfigurationManager.java index 138fe9f86..3a7873d29 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/ConfigurationManager.java +++ b/src/main/java/org/embeddedt/archaicfix/config/ConfigurationManager.java @@ -4,6 +4,15 @@ import cpw.mods.fml.client.event.ConfigChangedEvent; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; +import lombok.val; +import net.minecraft.launchwrapper.Launch; +import net.minecraftforge.common.config.ConfigElement; +import net.minecraftforge.common.config.Configuration; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.File; import java.lang.reflect.Field; @@ -18,16 +27,6 @@ import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import lombok.SneakyThrows; -import lombok.val; -import lombok.var; -import net.minecraft.launchwrapper.Launch; -import net.minecraftforge.common.config.ConfigElement; -import net.minecraftforge.common.config.Configuration; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; /** * Class for controlling the loading of configuration files. diff --git a/src/main/java/org/embeddedt/archaicfix/config/IConfigElementProxy.java b/src/main/java/org/embeddedt/archaicfix/config/IConfigElementProxy.java index b7385d744..e272681cd 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/IConfigElementProxy.java +++ b/src/main/java/org/embeddedt/archaicfix/config/IConfigElementProxy.java @@ -4,6 +4,7 @@ import cpw.mods.fml.client.config.GuiConfigEntries; import cpw.mods.fml.client.config.GuiEditArrayEntries; import cpw.mods.fml.client.config.IConfigElement; + import java.util.List; import java.util.regex.Pattern; diff --git a/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiConfig.java b/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiConfig.java index fcc5fadeb..7e19e2094 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiConfig.java +++ b/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiConfig.java @@ -9,6 +9,6 @@ @SideOnly(Side.CLIENT) public class SimpleGuiConfig extends GuiConfig { public SimpleGuiConfig(GuiScreen parent, Class configClass, String modID, String modName) throws ConfigException { - super(parent, ConfigurationManager.getConfigElements(configClass), modID, false, false, modName + " Configuration", I18n.format("falsepatternlib.gui.config.description")); + super(parent, ConfigurationManager.getConfigElements(configClass), modID, false, false, modName + " Configuration"); } } diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/IArchaicWorld.java b/src/main/java/org/embeddedt/archaicfix/ducks/IArchaicWorld.java deleted file mode 100644 index 1f708af86..000000000 --- a/src/main/java/org/embeddedt/archaicfix/ducks/IArchaicWorld.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.embeddedt.archaicfix.ducks; - -import net.minecraft.world.chunk.Chunk; - -public interface IArchaicWorld { - void arch$markTileEntitiesInChunkForRemoval(Chunk chunk); -} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java b/src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java index 8fff01301..be4e7e080 100644 --- a/src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java +++ b/src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java @@ -1,5 +1,18 @@ package org.embeddedt.archaicfix.helpers; +import com.google.common.base.Splitter; +import com.google.common.collect.Lists; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.relauncher.ReflectionHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.AbstractResourcePack; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.client.resources.IResourcePack; +import net.minecraft.client.resources.SimpleReloadableResourceManager; +import net.minecraft.client.resources.data.IMetadataSection; +import net.minecraft.client.resources.data.IMetadataSerializer; +import org.apache.commons.io.filefilter.DirectoryFileFilter; + import java.awt.image.BufferedImage; import java.io.BufferedInputStream; import java.io.File; @@ -14,36 +27,21 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import cpw.mods.fml.relauncher.ReflectionHelper; -import org.apache.commons.io.filefilter.DirectoryFileFilter; - -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; - -import cpw.mods.fml.common.Loader; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.AbstractResourcePack; -import net.minecraft.client.resources.IResourceManager; -import net.minecraft.client.resources.IResourcePack; -import net.minecraft.client.resources.SimpleReloadableResourceManager; -import net.minecraft.client.resources.data.IMetadataSection; -import net.minecraft.client.resources.data.IMetadataSerializer; - // Inspired by ResourceManagerHelper in fabric-resource-loader-v0 public abstract class BuiltInResourcePack extends AbstractResourcePack { - + private static final Splitter entryNameSplitter = Splitter.on('/').omitEmptyStrings().limit(5); - + private String modid; private final String id; protected boolean enabled = true; - + /** *

Register a built-in resource pack. This is a resource pack located in the JAR at {@code "resourcepacks/"}. - * + * *

The resource pack is "invisible", it will not show up in the resource pack GUI. - * + * * @param id The name of the resource pack. */ public static BuiltInResourcePack register(String id) { @@ -51,7 +49,7 @@ public static BuiltInResourcePack register(String id) { inject(rp); return rp; } - + private static BuiltInResourcePack of(File file, String modid, String id) { if(file.isDirectory()) { return new BuiltInFolderResourcePack(file, modid, id); @@ -59,18 +57,18 @@ private static BuiltInResourcePack of(File file, String modid, String id) { return new BuiltInFileResourcePack(file, modid, id); } } - + public BuiltInResourcePack(File file, String modid, String id) { super(file); this.modid = modid; this.id = id; } - + @Override public String getPackName() { return modid + "/" + id; } - + @Override public IMetadataSection getPackMetadata(IMetadataSerializer p_135058_1_, String p_135058_2_) throws IOException { return null; @@ -80,11 +78,11 @@ public IMetadataSection getPackMetadata(IMetadataSerializer p_135058_1_, String public BufferedImage getPackImage() throws IOException { return null; } - + protected String getRootPath() { return "resourcepacks/" + id + "/"; } - + protected void addNamespaceIfLowerCase(Set set, String ns) { if (!ns.equals(ns.toLowerCase())) { this.logNameNotLowercase(ns); @@ -92,12 +90,12 @@ protected void addNamespaceIfLowerCase(Set set, String ns) { set.add(ns); } } - + public BuiltInResourcePack setEnabled(boolean enabled) { this.enabled = enabled; return this; } - + @SuppressWarnings("unchecked") private static void inject(IResourcePack resourcePack) { List defaultResourcePacks = ReflectionHelper.getPrivateValue(Minecraft.class, Minecraft.getMinecraft(), "defaultResourcePacks", "field_110449_ao"); @@ -107,11 +105,11 @@ private static void inject(IResourcePack resourcePack) { ((SimpleReloadableResourceManager)resMan).reloadResourcePack(resourcePack); } } - + private static class BuiltInFileResourcePack extends BuiltInResourcePack { - + private final ZipFile zipFile; - + public BuiltInFileResourcePack(File file, String modid, String id) { super(file, modid, id); try { @@ -120,11 +118,11 @@ public BuiltInFileResourcePack(File file, String modid, String id) { throw new RuntimeException(e); } } - + @Override public Set getResourceDomains() { Set domains = new HashSet<>(); - + Enumeration en = zipFile.entries(); while(en.hasMoreElements()) { ZipEntry entry = en.nextElement(); @@ -137,7 +135,7 @@ public Set getResourceDomains() { } return domains; } - + @Override protected InputStream getInputStreamByName(String name) throws IOException { return zipFile.getInputStream(zipFile.getEntry(getRootPath() + name)); @@ -147,9 +145,9 @@ protected InputStream getInputStreamByName(String name) throws IOException { protected boolean hasResourceName(String name) { return enabled && zipFile.getEntry(getRootPath() + name) != null; } - + } - + private static class BuiltInFolderResourcePack extends BuiltInResourcePack { public BuiltInFolderResourcePack(File file, String modid, String id) { @@ -159,7 +157,7 @@ public BuiltInFolderResourcePack(File file, String modid, String id) { @Override public Set getResourceDomains() { Set domains = new HashSet<>(); - + File assetsDir = new File(this.resourcePackFile, getRootPath() + "assets/"); if(assetsDir.isDirectory()) { File[] files = assetsDir.listFiles((FileFilter)DirectoryFileFilter.DIRECTORY); @@ -167,7 +165,7 @@ public Set getResourceDomains() { addNamespaceIfLowerCase(domains, file.getName()); } } - + return domains; } @@ -180,7 +178,7 @@ protected InputStream getInputStreamByName(String name) throws IOException { protected boolean hasResourceName(String name) { return enabled && new File(this.resourcePackFile, getRootPath() + "/" + name).isFile(); } - + } - + } diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java index a1a87c1d7..57ed2f195 100644 --- a/src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java +++ b/src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java @@ -2,7 +2,6 @@ import org.apache.commons.lang3.tuple.Pair; -import java.io.IOException; import java.io.InputStream; import java.util.Properties; diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/LetsEncryptHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/LetsEncryptHelper.java deleted file mode 100644 index f51dd7f27..000000000 --- a/src/main/java/org/embeddedt/archaicfix/helpers/LetsEncryptHelper.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.embeddedt.archaicfix.helpers; - -import org.embeddedt.archaicfix.ArchaicLogger; -import org.embeddedt.archaicfix.config.ArchaicConfig; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; - -/** - * Add Let's Encrypt root certificates to the default SSLContext. - * CurseForge launcher uses the vanilla JDK for 1.7.10, which is version 8u51. - * This version does not include these certificates, support for ISRG Root X1 was added in 8u141. - * Based on LetsEncryptCraft by Cloudhunter (MIT) - */ -public class LetsEncryptHelper { - private LetsEncryptHelper() {} - @SuppressWarnings("java:S6437") - public static void replaceSSLContext() { - if (!ArchaicConfig.enableLetsEncryptRoot) { - return; - } - - try (InputStream x1 = LetsEncryptHelper.class.getResourceAsStream("/letsencrypt/isrgrootx1.pem"); - InputStream x2 = LetsEncryptHelper.class.getResourceAsStream("/letsencrypt/isrg-root-x2.pem")) { - KeyStore merged = KeyStore.getInstance(KeyStore.getDefaultType()); - Path cacerts = Paths.get(System.getProperty("java.home"),"lib", "security", "cacerts"); - merged.load(Files.newInputStream(cacerts), "changeit".toCharArray()); - - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - Certificate cx1 = cf.generateCertificate(x1); - merged.setCertificateEntry("archaicfix-isrgx1", cx1); - - Certificate cx2 = cf.generateCertificate(x2); - merged.setCertificateEntry("archaicfix-isrgx2", cx2); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - tmf.init(merged); - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, tmf.getTrustManagers(), null); - SSLContext.setDefault(sslContext); - ArchaicLogger.LOGGER.info("[LetsEncryptHelper] Added certificates to trust store."); - } catch (IOException e) { - ArchaicLogger.LOGGER.error("[LetsEncryptHelper] Failed to load certificates from classpath.", e); - } catch (GeneralSecurityException e) { - ArchaicLogger.LOGGER.error("[LetsEncryptHelper] Failed to load default keystore.", e); - } - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/LoadControllerHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/LoadControllerHelper.java index cafad649a..880942f7c 100644 --- a/src/main/java/org/embeddedt/archaicfix/helpers/LoadControllerHelper.java +++ b/src/main/java/org/embeddedt/archaicfix/helpers/LoadControllerHelper.java @@ -2,7 +2,12 @@ import com.google.common.collect.ListMultimap; import com.google.common.eventbus.EventBus; -import cpw.mods.fml.common.*; +import cpw.mods.fml.common.LoadController; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.MetadataCollection; +import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.ModMetadata; +import cpw.mods.fml.common.ObfuscationReflectionHelper; import cpw.mods.fml.common.versioning.ArtifactVersion; import cpw.mods.fml.common.versioning.VersionRange; diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java b/src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java index 272a40560..a8503f8ab 100644 --- a/src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java +++ b/src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java @@ -1,13 +1,14 @@ package org.embeddedt.archaicfix.helpers; -import gnu.trove.map.hash.TIntObjectHashMap; -import lombok.var; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraftforge.oredict.OreDictionary; import org.apache.commons.lang3.tuple.Pair; -import java.util.*; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; /** * Provides a facility to iterate over a subset of the accelerated ore dictionary. diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java index 2a4fe76b5..86f96c516 100644 --- a/src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java +++ b/src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java @@ -1,9 +1,7 @@ package org.embeddedt.archaicfix.helpers; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.entity.Entity; -import org.embeddedt.archaicfix.config.ArchaicConfig; public class WorldRendererDistanceHelper { /** diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/IAcceleratedRecipe.java b/src/main/java/org/embeddedt/archaicfix/interfaces/IAcceleratedRecipe.java similarity index 71% rename from src/main/java/org/embeddedt/archaicfix/ducks/IAcceleratedRecipe.java rename to src/main/java/org/embeddedt/archaicfix/interfaces/IAcceleratedRecipe.java index 4b51b2ddc..533ae66fd 100644 --- a/src/main/java/org/embeddedt/archaicfix/ducks/IAcceleratedRecipe.java +++ b/src/main/java/org/embeddedt/archaicfix/interfaces/IAcceleratedRecipe.java @@ -1,8 +1,7 @@ -package org.embeddedt.archaicfix.ducks; +package org.embeddedt.archaicfix.interfaces; import net.minecraft.item.Item; -import java.util.Collection; import java.util.Set; public interface IAcceleratedRecipe { diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/IArchaicNetworkManager.java b/src/main/java/org/embeddedt/archaicfix/interfaces/IArchaicNetworkManager.java similarity index 78% rename from src/main/java/org/embeddedt/archaicfix/ducks/IArchaicNetworkManager.java rename to src/main/java/org/embeddedt/archaicfix/interfaces/IArchaicNetworkManager.java index 6f998d3ae..785e14683 100644 --- a/src/main/java/org/embeddedt/archaicfix/ducks/IArchaicNetworkManager.java +++ b/src/main/java/org/embeddedt/archaicfix/interfaces/IArchaicNetworkManager.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.ducks; +package org.embeddedt.archaicfix.interfaces; import net.minecraft.network.EnumConnectionState; diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/ILazyChunkProviderServer.java b/src/main/java/org/embeddedt/archaicfix/interfaces/ILazyChunkProviderServer.java similarity index 70% rename from src/main/java/org/embeddedt/archaicfix/ducks/ILazyChunkProviderServer.java rename to src/main/java/org/embeddedt/archaicfix/interfaces/ILazyChunkProviderServer.java index abe3d5bb8..e496af8e6 100644 --- a/src/main/java/org/embeddedt/archaicfix/ducks/ILazyChunkProviderServer.java +++ b/src/main/java/org/embeddedt/archaicfix/interfaces/ILazyChunkProviderServer.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.ducks; +package org.embeddedt.archaicfix.interfaces; public interface ILazyChunkProviderServer { boolean dropLazyChunk(int x, int z, Runnable runnable); diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/IPendingChunk.java b/src/main/java/org/embeddedt/archaicfix/interfaces/IPendingChunk.java similarity index 81% rename from src/main/java/org/embeddedt/archaicfix/ducks/IPendingChunk.java rename to src/main/java/org/embeddedt/archaicfix/interfaces/IPendingChunk.java index 57c69af82..5e7722709 100644 --- a/src/main/java/org/embeddedt/archaicfix/ducks/IPendingChunk.java +++ b/src/main/java/org/embeddedt/archaicfix/interfaces/IPendingChunk.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.ducks; +package org.embeddedt.archaicfix.interfaces; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.ChunkCoordIntPair; diff --git a/src/main/java/org/embeddedt/archaicfix/ducks/IWorldRenderer.java b/src/main/java/org/embeddedt/archaicfix/interfaces/IWorldRenderer.java similarity index 59% rename from src/main/java/org/embeddedt/archaicfix/ducks/IWorldRenderer.java rename to src/main/java/org/embeddedt/archaicfix/interfaces/IWorldRenderer.java index 91583d172..da6a7b519 100644 --- a/src/main/java/org/embeddedt/archaicfix/ducks/IWorldRenderer.java +++ b/src/main/java/org/embeddedt/archaicfix/interfaces/IWorldRenderer.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.ducks; +package org.embeddedt.archaicfix.interfaces; public interface IWorldRenderer { boolean arch$isInView(); diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiContainerCreative.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiContainerCreative.java deleted file mode 100644 index 531e3b653..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/core/MixinGuiContainerCreative.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.embeddedt.archaicfix.mixins.client.core; - -import com.google.common.collect.ImmutableList; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiTextField; -import net.minecraft.client.gui.inventory.GuiContainerCreative; -import net.minecraft.client.renderer.InventoryEffectRenderer; -import net.minecraft.creativetab.CreativeTabs; -import net.minecraft.enchantment.Enchantment; -import net.minecraft.init.Items; -import net.minecraft.inventory.Container; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import org.embeddedt.archaicfix.ArchaicFix; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.helpers.NEISearchHelper; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ForkJoinPool; -import java.util.function.Function; -import java.util.stream.Collectors; - -@Mixin(GuiContainerCreative.class) -public abstract class MixinGuiContainerCreative extends InventoryEffectRenderer { - private static List initialCreativeItems = null; - private static final ForkJoinPool creativeSearchPool = new ForkJoinPool(); - private static final Function VANILLA_SUPPLIER = stack -> String.join("", stack.getTooltip(Minecraft.getMinecraft().thePlayer, Minecraft.getMinecraft().gameSettings.advancedItemTooltips)).toLowerCase(); - - @Shadow private static int selectedTabIndex; - - @Shadow private GuiTextField searchField; - - @Shadow private float currentScroll; - - private int debounceTicks = 0; - private boolean needSearchUpdate = false; - private boolean firstSearch = true; - - public MixinGuiContainerCreative(Container p_i1089_1_) { - super(p_i1089_1_); - } - - @Inject(method = "updateCreativeSearch", at = @At(value = "HEAD"), cancellable = true) - private void asyncSearch(CallbackInfo ci) { - if(ArchaicConfig.asyncCreativeSearch) { - ci.cancel(); - needSearchUpdate = true; - if(firstSearch) { - debounceTicks = 0; - firstSearch = false; - } else - debounceTicks = 5; - } - } - - @Inject(method = "updateScreen", at = @At(value = "TAIL")) - private void performRealSearch(CallbackInfo ci) { - if(ArchaicConfig.asyncCreativeSearch && needSearchUpdate) { - String search = this.searchField.getText().toLowerCase(); - if(search.length() == 0) - debounceTicks = 0; - debounceTicks--; - if(debounceTicks <= 0) { - needSearchUpdate = false; - GuiContainerCreative.ContainerCreative containercreative = (GuiContainerCreative.ContainerCreative)this.inventorySlots; - CreativeTabs tab = CreativeTabs.creativeTabArray[selectedTabIndex]; - if (tab.hasSearchBar() && tab != CreativeTabs.tabAllSearch) { - tab.displayAllReleventItems(containercreative.itemList); - } else { - List filteredItems; - if(initialCreativeItems == null) { - initialCreativeItems = new ArrayList<>(); - for (Object o : Item.itemRegistry) { - Item item = (Item) o; - - if (item != null && item.getCreativeTab() != null) { - try { - item.getSubItems(item, null, initialCreativeItems); - } catch(Exception e) { - ArchaicLogger.LOGGER.error("Item " + item + " threw an error while populating the creative item list!", e); - } - } - } - for(Enchantment enchantment : Enchantment.enchantmentsList) { - if (enchantment != null && enchantment.type != null) - { - Items.enchanted_book.func_92113_a(enchantment, initialCreativeItems); - } - } - } - if(search.length() > 0) { - try { - Function nameSupplier = ArchaicFix.NEI_INSTALLED ? new NEISearchHelper() : VANILLA_SUPPLIER; - filteredItems = creativeSearchPool.submit(() -> - initialCreativeItems.parallelStream() - .filter(stack -> { - String s = nameSupplier.apply(stack); - if(s != null) - return s.contains(search); - else - return false; - }) - .collect(Collectors.toList()) - ).get(); - } catch (ExecutionException | InterruptedException e) { - e.printStackTrace(); - filteredItems = ImmutableList.of(); - } - } else - filteredItems = initialCreativeItems; - containercreative.itemList.clear(); - containercreative.itemList.addAll(filteredItems); - containercreative.scrollTo(0.0F); - this.currentScroll = 0.0F; - } - } - } - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/client/optifine/MixinVersionCheckThread.java b/src/main/java/org/embeddedt/archaicfix/mixins/client/optifine/MixinVersionCheckThread.java deleted file mode 100644 index a36bd31c1..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/client/optifine/MixinVersionCheckThread.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.embeddedt.archaicfix.mixins.client.optifine; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Pseudo; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Pseudo -@Mixin(targets = {"VersionCheckThread"}, remap = false) -public abstract class MixinVersionCheckThread extends Thread { - @Inject(method = "run", at = @At("HEAD"), cancellable = true) - private void skipCheck(CallbackInfo ci) { - ci.cancel(); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntity.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntity.java deleted file mode 100644 index e3af7f62c..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntity.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.embeddedt.archaicfix.mixins.common.core; - -import net.minecraft.entity.Entity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(Entity.class) -public abstract class MixinEntity { - @Shadow public float fallDistance; - - /** - * @reason Fixes a vanilla bug where the entity's fall distance is not updated before invoking the - * block's onFallenUpon when it falls on the ground, meaning that the last fall state update won't - * be included in the fall distance. - */ - @Inject(method = "updateFallState", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;fall(F)V")) - private void beforeOnFallenUpon(double distanceFallenThisTick, boolean isOnGround, CallbackInfo ci) { - if (distanceFallenThisTick < 0) fallDistance -= distanceFallenThisTick; - } -} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityItem.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityItem.java deleted file mode 100644 index eca548f03..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityItem.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.embeddedt.archaicfix.mixins.common.core; - -import net.minecraft.entity.Entity; -import net.minecraft.entity.item.EntityItem; -import net.minecraft.world.World; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(EntityItem.class) -public abstract class MixinEntityItem extends Entity { - @Shadow public int age; - - private double arch$oldMotionX, arch$oldMotionY, arch$oldMotionZ; - - private boolean arch$movedThisTick; - - public MixinEntityItem(World p_i1582_1_) { - super(p_i1582_1_); - } - - private boolean arch$shouldItemMove() { - if(!this.onGround) - return true; - double horzMotion = this.motionX * this.motionX + this.motionZ * this.motionZ; - if(horzMotion > 1.0e-5f) - return true; - return (this.age + this.getEntityId()) % 4 == 0; - } - - @Redirect(method = "onUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/item/EntityItem;moveEntity(DDD)V", ordinal = 0)) - private void moveIfNecessary(EntityItem item, double x, double y, double z) { - arch$movedThisTick = arch$shouldItemMove(); - if(arch$movedThisTick) - item.moveEntity(x, y, z); - else { - arch$oldMotionX = item.motionX; - arch$oldMotionY = item.motionY; - arch$oldMotionZ = item.motionZ; - } - } - - @Inject(method = "onUpdate", at = @At(value = "FIELD", target = "Lnet/minecraft/entity/item/EntityItem;age:I", opcode = Opcodes.PUTFIELD)) - private void restoreVelocityIfNotMoving(CallbackInfo ci) { - if(!arch$movedThisTick) { - this.motionX = arch$oldMotionX; - this.motionY = arch$oldMotionY; - this.motionZ = arch$oldMotionZ; - } - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityLiving.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityLiving.java deleted file mode 100644 index 860dce8cd..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinEntityLiving.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.embeddedt.archaicfix.mixins.common.core; - -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.world.World; -import net.minecraft.world.WorldServer; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -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; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(EntityLiving.class) -public abstract class MixinEntityLiving extends EntityLivingBase { - @Shadow public static Item getArmorItemForSlot(int p_82161_0_, int p_82161_1_) { - throw new AssertionError(); - } - - @Shadow public abstract ItemStack func_130225_q(int p_130225_1_); - - @Shadow protected float[] equipmentDropChances; - - public MixinEntityLiving(World p_i1594_1_) { - super(p_i1594_1_); - } - - @ModifyConstant(method = "despawnEntity", constant = @Constant(doubleValue = 16384.0D)) - private double lowerHardRange(double old) { - if(!ArchaicConfig.fixMobSpawnsAtLowRenderDist) - return old; - if(worldObj.isRemote) - return old; - if(((WorldServer)worldObj).func_73046_m().getConfigurationManager().getViewDistance() < 10) - return 96 * 96; - return old; - } - - /** - * @reason Higher armor chances (from TMCW). - * @author embeddedt - */ - @Inject(method = "addRandomArmor", at = @At("HEAD"), cancellable = true) - public void addRandomArmor(CallbackInfo ci) - { - if(!ArchaicConfig.increaseMobArmor) - return; - float var1 = this.worldObj.func_147462_b(this.posX, this.posY, this.posZ); - - if (this.rand.nextFloat() < var1 * 0.2F) - { - float var2 = 0.4F / (var1 * 2.0F + 1.0F); - int var3 = this.rand.nextInt(2); - - if (this.rand.nextFloat() < 0.2F) - { - ++var3; - } - - if (this.rand.nextFloat() < 0.2F) - { - ++var3; - } - - if (this.rand.nextFloat() < 0.2F) - { - ++var3; - } - - for (int var4 = 3; var4 >= 0; --var4) - { - ItemStack var5 = this.func_130225_q(var4); - - if (var4 < 3 && this.rand.nextFloat() < var2) - { - break; - } - - if (var5 == null) - { - Item var6 = getArmorItemForSlot(var4 + 1, var3); - - if (var6 != null) - { - this.setCurrentItemOrArmor(var4 + 1, new ItemStack(var6)); - - if (var3 == 5) - { - this.equipmentDropChances[var4 + 1] = 0.1F; - } - } - } - } - } - ci.cancel(); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinOreDictionary.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinOreDictionary.java deleted file mode 100644 index 2e1dd9b0d..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinOreDictionary.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.embeddedt.archaicfix.mixins.common.core; - -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraftforge.oredict.OreDictionary; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.ArrayList; - -@Mixin(OreDictionary.class) -public class MixinOreDictionary { - /* - @Redirect(method = "registerOreImpl", at = @At(value = "INVOKE", target = "Ljava/util/ArrayList;add(Ljava/lang/Object;)Z"), remap = false) - private static boolean addOreSorted(ArrayList list, Object o) { - ItemStack stack = (ItemStack)o; - int low = 0; - int high = list.size() - 1; - int targetId = Item.getIdFromItem(stack.getItem()); - Integer finalIndex = null; - while(low <= high) { - int mid = (low + high) / 2; - ItemStack option = list.get(mid); - int id = Item.getIdFromItem(option.getItem()); - if(id < targetId) - low = mid + 1; - else if(id > targetId) - high = mid - 1; - else { - finalIndex = mid; - break; - } - } - if(finalIndex == null) - finalIndex = low; - list.add(finalIndex, stack); - return true; - } - */ -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedOreRecipe.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedOreRecipe.java deleted file mode 100644 index a258c51ba..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedOreRecipe.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.embeddedt.archaicfix.mixins.common.core; - -import com.google.common.collect.ImmutableSet; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraftforge.oredict.ShapedOreRecipe; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.embeddedt.archaicfix.FixHelper; -import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.*; - -/** - * Enhances ShapedOreRecipe to support recipe acceleration. This benefits a lot of mods which make use of this class - * or a subclass. - */ -@Mixin(ShapedOreRecipe.class) -public class MixinShapedOreRecipe implements IAcceleratedRecipe { - @Shadow(remap = false) private Object[] input; - private Set allPossibleInputs = null; - - private void genMatchCache() { - ImmutableSet.Builder builder = ImmutableSet.builder(); - for(Object o : input) { - if(o instanceof ItemStack) { - if(((ItemStack)o).getItem() != null) - builder.add(((ItemStack) o).getItem()); - } else if(o instanceof ArrayList) { - for(ItemStack stack : ((ArrayList)o)) { - if(stack.getItem() != null) - builder.add(stack.getItem()); - } - } else if(o != null) { - ArchaicLogger.LOGGER.warn("Couldn't optimize input value: " + o); - return; - } - } - allPossibleInputs = builder.build(); - FixHelper.recipesHoldingPotentialItems.add(this); - } - - @Override - public Set getPotentialItems() { - if(allPossibleInputs == null) - genMatchCache(); - return allPossibleInputs; - } - - @Override - public void invalidatePotentialItems() { - allPossibleInputs = null; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedRecipes.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedRecipes.java deleted file mode 100644 index ec0d29962..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapedRecipes.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.embeddedt.archaicfix.mixins.common.core; - -import com.google.common.collect.ImmutableSet; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.ShapedRecipes; -import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.Set; - -@Mixin(ShapedRecipes.class) -public class MixinShapedRecipes implements IAcceleratedRecipe { - private Set allPossibleItems; - @Inject(method = "", at = @At("RETURN")) - private void collectItems(int w, int h, ItemStack[] stacks, ItemStack out, CallbackInfo ci) { - ImmutableSet.Builder builder = ImmutableSet.builder(); - for(ItemStack stack : stacks) { - if(stack != null && stack.getItem() != null) - builder.add(stack.getItem()); - } - allPossibleItems = builder.build(); - } - @Override - public Set getPotentialItems() { - return allPossibleItems; - } - - @Override - public void invalidatePotentialItems() { - /* No-op, the set of items is fixed for this recipe */ - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessOreRecipe.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessOreRecipe.java deleted file mode 100644 index 2671e2c24..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessOreRecipe.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.embeddedt.archaicfix.mixins.common.core; - -import com.google.common.collect.ImmutableSet; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraftforge.oredict.ShapelessOreRecipe; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.embeddedt.archaicfix.FixHelper; -import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.ArrayList; -import java.util.Set; - -@Mixin(ShapelessOreRecipe.class) -public class MixinShapelessOreRecipe implements IAcceleratedRecipe { - @Shadow(remap = false) private ArrayList input; - private Set allPossibleInputs = null; - - private void genMatchCache() { - allPossibleInputs = null; - ImmutableSet.Builder builder = ImmutableSet.builder(); - for(Object o : input) { - if(o instanceof ItemStack) { - if(((ItemStack)o).getItem() != null) - builder.add(((ItemStack) o).getItem()); - } else if(o instanceof ArrayList) { - for(ItemStack stack : ((ArrayList)o)) { - if(stack.getItem() != null) - builder.add(stack.getItem()); - } - } else if(o != null) { - ArchaicLogger.LOGGER.warn("Couldn't optimize input value: " + o); - return; - } - } - allPossibleInputs = builder.build(); - FixHelper.recipesHoldingPotentialItems.add(this); - } - - @Override - public Set getPotentialItems() { - if(allPossibleInputs == null) - genMatchCache(); - return allPossibleInputs; - } - - public void invalidatePotentialItems() { - allPossibleInputs = null; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessRecipes.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessRecipes.java deleted file mode 100644 index f51e7570c..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/core/MixinShapelessRecipes.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.embeddedt.archaicfix.mixins.common.core; - -import com.google.common.collect.ImmutableSet; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.ShapelessRecipes; -import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.List; -import java.util.Set; - -@Mixin(ShapelessRecipes.class) -public class MixinShapelessRecipes implements IAcceleratedRecipe { - @Shadow @Final public List recipeItems; - - private Set allPossibleItems; - - @Inject(method = "", at = @At("RETURN")) - public void buildItemCache(ItemStack p_i1918_1_, List p_i1918_2_, CallbackInfo ci) - { - ImmutableSet.Builder builder = ImmutableSet.builder(); - for(Object stack : recipeItems) { - if(stack != null && ((ItemStack)stack).getItem() != null) - builder.add(((ItemStack)stack).getItem()); - } - allPossibleItems = builder.build(); - } - - @Override - public Set getPotentialItems() { - return allPossibleItems; - } - - @Override - public void invalidatePotentialItems() { - /* No-op, fixed set of items */ - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunk.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunk.java deleted file mode 100644 index 7e8400305..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunk.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.embeddedt.archaicfix.mixins.common.lighting.fastcraft; - -import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(Chunk.class) -public abstract class MixinChunk { - @Shadow protected abstract void relightBlock(int p_76615_1_, int p_76615_2_, int p_76615_3_); - - @Shadow protected abstract void recheckGaps(boolean p_150803_1_); - - @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;c(Lnet/minecraft/world/chunk/Chunk;III)V", remap = false), require = 0) - private void doBlockLight(Chunk chunk, int x, int y, int z) { - this.relightBlock(x, y, z); - } - - @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;a(Lnet/minecraft/world/chunk/Chunk;)V", remap = false), require = 0) - private void usePhosphorLightPopulation(Chunk chunk) { - chunk.func_150809_p(); - } - - @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;b(Lnet/minecraft/world/chunk/Chunk;Z)V", remap = false), require = 0) - private void usePhosphorRecheckGaps(Chunk chunk, boolean isRemote) { - this.recheckGaps(isRemote); - } - - @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;d(Lnet/minecraft/world/World;III)Z", remap = false), require = 0) - private boolean updateLightUsingPhosphor(World world, int x, int y, int z) { - return world.func_147451_t(x, y, z); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunkProviderServer.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunkProviderServer.java deleted file mode 100644 index 87d538073..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinChunkProviderServer.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.embeddedt.archaicfix.mixins.common.lighting.fastcraft; - -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.gen.ChunkProviderServer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(ChunkProviderServer.class) -public class MixinChunkProviderServer { - @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;a(Lnet/minecraft/world/chunk/Chunk;)V", remap = false), require = 0) - private void usePhosphorLightPopulation(Chunk chunk) { - chunk.func_150809_p(); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinWorld.java b/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinWorld.java deleted file mode 100644 index dcc0a76cd..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/common/lighting/fastcraft/MixinWorld.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.embeddedt.archaicfix.mixins.common.lighting.fastcraft; - -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(World.class) -public class MixinWorld { - @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lfastcraft/H;d(Lnet/minecraft/world/World;III)Z", remap = false), require = 0) - private boolean updateLightUsingPhosphor(World world, int x, int y, int z) { - return world.func_147451_t(x, y, z); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/mixins/generate.sh b/src/main/java/org/embeddedt/archaicfix/mixins/generate.sh deleted file mode 100644 index 8e36c5cb2..000000000 --- a/src/main/java/org/embeddedt/archaicfix/mixins/generate.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -perform_generation() { -pushd $1 &>/dev/null -side=$(echo $1 | awk '{ print toupper($0) }') -find * -name \*.java | while read -r line; do -pkgname=$(echo $line | sed 's;/;.;g' | sed 's/.java$//g') -enumname=$(echo $pkgname | sed 's/\./_/g') -echo " ${1}_${enumname}(Side.$side, always(), \"$pkgname\")," -done -popd &>/dev/null -} - -echo " // COMMON MIXINS" -perform_generation common -echo " // CLIENT MIXINS" -perform_generation client diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java b/src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java index 00985c753..88345d111 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java @@ -1,23 +1,14 @@ package org.embeddedt.archaicfix.occlusion; import lombok.Getter; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.ActiveRenderInfo; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.MathHelper; -import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.GL11; -import org.lwjgl.util.vector.Matrix4f; -import org.lwjgl.util.vector.Vector3f; -import org.lwjgl.util.vector.Vector4f; - -import java.nio.FloatBuffer; public class CameraInfo { @Getter - private static CameraInfo instance = new CameraInfo(); + private static final CameraInfo instance = new CameraInfo(); /** The transformed eye position, which takes the third person camera offset into account. */ @Getter diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java b/src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java index 8ee9d56e4..b8e8d55b1 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java @@ -1,18 +1,18 @@ package org.embeddedt.archaicfix.occlusion; import net.minecraft.world.chunk.Chunk; +import org.embeddedt.archaicfix.occlusion.interfaces.ICulledChunk; import org.embeddedt.archaicfix.occlusion.util.LinkedHashList; import org.embeddedt.archaicfix.occlusion.util.SynchronizedIdentityLinkedHashList; public class ChunkThread extends Thread { public ChunkThread() { - super("Chunk Worker"); } - public LinkedHashList loaded = new SynchronizedIdentityLinkedHashList(); - public LinkedHashList modified = new SynchronizedIdentityLinkedHashList(); + public LinkedHashList loaded = new SynchronizedIdentityLinkedHashList<>(); + public LinkedHashList modified = new SynchronizedIdentityLinkedHashList<>(); @Override public void run() { @@ -20,7 +20,7 @@ public void run() { for (;;) { int i = 0; boolean work = false; - for (; loaded.size() > 0; ++i) { + for (; !loaded.isEmpty(); ++i) { Chunk chunk = ((ICulledChunk)loaded.shift()).buildCulledSides(); if (chunk != null) { modified.add(chunk); @@ -30,7 +30,7 @@ public void run() { Thread.yield(); } } - for (i = 0; modified.size() > 0; ++i) { + for (i = 0; !modified.isEmpty(); ++i) { Chunk chunk = modified.shift(); if (loaded.contains(chunk)) { continue; @@ -49,8 +49,7 @@ public void run() { OcclusionHelpers.worker.dirty = work; try { Thread.sleep(30); - } catch (InterruptedException e) { - } + } catch (InterruptedException ignored) {} } } } diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java b/src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java index 2d756cfb8..7e91f0c50 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java @@ -1,6 +1,7 @@ package org.embeddedt.archaicfix.occlusion; import net.minecraft.client.renderer.WorldRenderer; +import org.embeddedt.archaicfix.occlusion.interfaces.IRendererUpdateOrderProvider; import java.util.List; @@ -28,4 +29,4 @@ public void cleanup(List worldRenderersToUpdateList) { worldRenderersToUpdateList.subList(0, lastUpdatedIndex).clear(); } -} \ No newline at end of file +} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java index 896f3b913..f437a239c 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java @@ -1,10 +1,5 @@ package org.embeddedt.archaicfix.occlusion; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.util.EnumFacing; -import net.minecraft.world.chunk.Chunk; import org.embeddedt.archaicfix.occlusion.util.IntStack; public class OcclusionHelpers { @@ -27,7 +22,6 @@ public static void init() { public static IntStack deferredAreas = new IntStack(6 * 1024); public static synchronized void updateArea(int x, int y, int z, int x2, int y2, int z2) { - // backwards so it's more logical to extract deferredAreas.add(z2); deferredAreas.add(y2); diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java index 247199a19..c58aee41a 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java @@ -1,12 +1,5 @@ package org.embeddedt.archaicfix.occlusion; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import org.embeddedt.archaicfix.helpers.WorldRendererDistanceHelper; - import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiVideoSettings; import net.minecraft.client.renderer.RenderGlobal; @@ -22,12 +15,22 @@ import net.minecraft.util.MathHelper; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.EmptyChunk; +import org.embeddedt.archaicfix.helpers.WorldRendererDistanceHelper; +import org.embeddedt.archaicfix.occlusion.interfaces.ICulledChunk; +import org.embeddedt.archaicfix.occlusion.interfaces.IRenderGlobalListener; +import org.embeddedt.archaicfix.occlusion.interfaces.IRendererUpdateOrderProvider; +import org.embeddedt.archaicfix.occlusion.interfaces.IWorldRenderer; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; public class OcclusionRenderer { private final Minecraft mc; private final RenderGlobal rg; - + private Thread clientThread; private ArrayList worldRenderersToUpdateList; @@ -41,22 +44,22 @@ public class OcclusionRenderer { private int renderersNeedUpdate; private boolean resortUpdateList; - + private IRendererUpdateOrderProvider rendererUpdateOrderProvider; private List eventListeners; /* Make sure other threads can see changes to this */ private volatile boolean deferNewRenderUpdates; - + public OcclusionRenderer(RenderGlobal renderGlobal) { this.rg = renderGlobal; this.mc = renderGlobal.mc; } - + public RenderGlobal getRenderGlobal() { return rg; } - + /** * If the update list is not queued for a full resort (e.g. when the player moves or renderers have their positions * changed), uses binary search to add the renderer in the update queue at the appropriate place. Otherwise, @@ -71,7 +74,7 @@ private void addRendererToUpdateQueue(WorldRenderer wr) { resortUpdateList = true; return; } - if(worldRenderersToUpdateList.size() > 0) { + if(!worldRenderersToUpdateList.isEmpty()) { double targetDistance = WorldRendererDistanceHelper.betterDistanceSquared(mc.renderViewEntity, wr); int low = 0; int high = worldRenderersToUpdateList.size() - 1; @@ -97,7 +100,7 @@ private void addRendererToUpdateQueue(WorldRenderer wr) { } } } - + public void handleOffthreadUpdate(int x1, int y1, int z1, int x2, int y2, int z2) { if(deferNewRenderUpdates || Thread.currentThread() != clientThread) { OcclusionHelpers.updateArea(x1, y1, z1, x2, y2, z2); @@ -105,7 +108,7 @@ public void handleOffthreadUpdate(int x1, int y1, int z1, int x2, int y2, int z2 internalMarkBlockUpdate(x1, y1, z1, x2, y2, z2); } } - + public void internalMarkBlockUpdate(int x1, int y1, int z1, int x2, int y2, int z2) { int xStart = MathHelper.bucketInt(x1, 16); int yStart = MathHelper.bucketInt(y1, 16); @@ -137,12 +140,10 @@ public void internalMarkBlockUpdate(int x1, int y1, int z1, int x2, int y2, int if (!worldrenderer.needsUpdate || (worldrenderer.isVisible && !((IWorldRenderer)worldrenderer).arch$isInUpdateList())) { worldrenderer.markDirty(); - //if (worldrenderer.distanceToEntitySquared(mc.renderViewEntity) <= 2883.0F) { - Chunk chunk = rg.theWorld.getChunkFromBlockCoords(worldrenderer.posX, worldrenderer.posZ); - if (((ICulledChunk) chunk).getVisibility()[worldrenderer.posY >> 4].isRenderDirty()) { - rebuild = true; - } - //} + Chunk chunk = rg.theWorld.getChunkFromBlockCoords(worldrenderer.posX, worldrenderer.posZ); + if (((ICulledChunk) chunk).getVisibility()[worldrenderer.posY >> 4].isRenderDirty()) { + rebuild = true; + } addRendererToUpdateQueue(worldrenderer); } else { for(IRenderGlobalListener l : eventListeners) l.onDirtyRendererChanged(worldrenderer); @@ -167,15 +168,13 @@ public boolean skipRenderingIfNotVisible(RenderManager instance, Entity entity, } public String getDebugInfoRenders() { - StringBuilder r = new StringBuilder(3 + 4 + 1 + 4 + 1 + 6 + 5 + 4 + 5 + 4 + 5 + 4 + 5 + 4 + 5 + 3 + 5 + 3 + 5 + 4); - r.append("C: ").append(rg.renderersBeingRendered).append('/').append(rg.renderersLoaded).append('/').append(rg.worldRenderers.length); - r.append(". F: ").append(rg.renderersBeingClipped); - r.append(", O: ").append(rg.renderersBeingOccluded); - r.append(", E: ").append(rg.renderersSkippingRenderPass); - r.append(", I: ").append(rg.dummyRenderInt); - r.append("; U: ").append(renderersNeedUpdate); - r.append(", N: ").append(rg.worldRenderersToUpdate.size()); - return r.toString(); + return "C: " + rg.renderersBeingRendered + '/' + rg.renderersLoaded + '/' + rg.worldRenderers.length + + ". F: " + rg.renderersBeingClipped + + ", O: " + rg.renderersBeingOccluded + + ", E: " + rg.renderersSkippingRenderPass + + ", I: " + rg.dummyRenderInt + + "; U: " + renderersNeedUpdate + + ", N: " + rg.worldRenderersToUpdate.size(); } public void initBetterLists() { @@ -206,7 +205,7 @@ public boolean sortAndAddRendererUpdateQueue(List instance, Object renderer) { throw new AssertionError("Transformer applied to the wrong List.clear method"); } } - + private static int fixPos(int pos, int amt) { int r = Math.floorDiv(pos, 16) % amt; if(r < 0) { @@ -214,7 +213,7 @@ private static int fixPos(int pos, int amt) { } return r; } - + public WorldRenderer getRenderer(int x, int y, int z) { if ((y - 15) > rg.maxBlockY || y < rg.minBlockY || (x - 15) > rg.maxBlockX || x < rg.minBlockX || (z - 15) > rg.maxBlockZ || z < rg.minBlockZ) return null; @@ -242,7 +241,7 @@ private boolean rebuildChunks(EntityLivingBase view, long deadline) { rendererUpdateOrderProvider.prepare(worldRenderersToUpdateList); for (int c = 0; updates < updateLimit && rendererUpdateOrderProvider.hasNext(worldRenderersToUpdateList); ++c) { WorldRenderer worldrenderer = rendererUpdateOrderProvider.next(worldRenderersToUpdateList); - + ((IWorldRenderer)worldrenderer).arch$setInUpdateList(false); if (!(worldrenderer.isInFrustum & worldrenderer.isVisible) && !OcclusionHelpers.DEBUG_LAZY_CHUNK_UPDATES) { @@ -273,7 +272,7 @@ private boolean rebuildChunks(EntityLivingBase view, long deadline) { public void performCullingUpdates(EntityLivingBase view, boolean p_72716_2_) { rg.theWorld.theProfiler.startSection("deferred_updates"); - while(OcclusionHelpers.deferredAreas.size() > 0) { + while(!OcclusionHelpers.deferredAreas.isEmpty()) { OcclusionHelpers.processUpdate(this); } rg.theWorld.theProfiler.endStartSection("rebuild"); @@ -312,15 +311,15 @@ public void performCullingUpdates(EntityLivingBase view, boolean p_72716_2_) { } rg.theWorld.theProfiler.endStartSection("scan"); - int yaw = MathHelper.floor_float(view.rotationYaw + 45) >> 4; - int pitch = MathHelper.floor_float(view.rotationPitch + 45) >> 4; +// int yaw = MathHelper.floor_float(view.rotationYaw + 45) >> 4; +// int pitch = MathHelper.floor_float(view.rotationPitch + 45) >> 4; if (OcclusionHelpers.worker.dirty || cameraRotated || OcclusionHelpers.DEBUG_ALWAYS_RUN_OCCLUSION) { OcclusionHelpers.worker.run(true); PreviousActiveRenderInfo.update(); } rg.theWorld.theProfiler.endSection(); } - + public void resetLoadedRenderers() { if(rg.theWorld != null) { rg.renderersLoaded = 0; @@ -333,7 +332,7 @@ public void resetOcclusionWorker() { OcclusionHelpers.worker.dirty = true; } } - + public void updateRendererNeighbors() { if(rg.worldRenderers == null) return; for(int i = 0; i < rg.worldRenderers.length; i++) { @@ -354,7 +353,7 @@ public void updateRendererNeighbors() { } } } - + public void pushWorkerRenderer(WorldRenderer wr) { if(!(mc.theWorld.getChunkFromBlockCoords(wr.posX, wr.posZ) instanceof EmptyChunk)) addRendererToUpdateQueue(wr); @@ -376,7 +375,7 @@ public void setPositionAndMarkInvisible(WorldRenderer wr, int x, int y, int z) { } } - public void runWorker(int p_72722_1_, int p_72722_2_, int p_72722_3_) { + public void runWorker(int x, int y, int z) { updateRendererNeighbors(); OcclusionHelpers.worker.run(true); } @@ -450,8 +449,8 @@ public int sortAndRender(int start, int end, int pass, double tick) { CameraInfo cam = CameraInfo.getInstance(); RenderList[] allRenderLists = rg.allRenderLists; - for (int i = 0; i < allRenderLists.length; ++i) { - allRenderLists[i].resetList(); + for (RenderList allRenderList : allRenderLists) { + allRenderList.resetList(); } int loopStart = start; @@ -470,8 +469,7 @@ public int sortAndRender(int start, int end, int pass, double tick) { int renderersNotInitialized = 0, renderersBeingClipped = 0, renderersBeingOccluded = 0; int renderersBeingRendered = 0, renderersSkippingRenderPass = 0, renderersNeedUpdate = 0; WorldRenderer[] worldRenderers = rg.worldRenderers; - for (int i = 0, e = worldRenderers.length; i < e; ++i) { - WorldRenderer rend = worldRenderers[i]; + for (WorldRenderer rend : worldRenderers) { if (!rend.isInitialized) { ++renderersNotInitialized; } else if (!rend.isInFrustum) { @@ -561,7 +559,7 @@ public void clipRenderersByFrustum(ICamera p_72729_1_, float p_72729_2_) { OcclusionHelpers.worker.dirtyFrustumRenderers = 0; } } - + public void arch$setRendererUpdateOrderProvider(IRendererUpdateOrderProvider orderProvider) { this.rendererUpdateOrderProvider = orderProvider; } @@ -573,7 +571,7 @@ public void clipRenderersByFrustum(ICamera p_72729_1_, float p_72729_2_) { private static double distanceSquared(double x1, double y1, double z1, double x2, double y2, double z2) { return Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2); } - + private static boolean isChunkEmpty(Chunk chunk) { return chunk == null || chunk.isEmpty(); } diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java index 8b2ed300e..f8c397ae8 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java @@ -1,7 +1,5 @@ package org.embeddedt.archaicfix.occlusion; -import static org.embeddedt.archaicfix.occlusion.OcclusionHelpers.DEBUG_PRINT_QUEUE_ITERATIONS; - import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.RenderGlobal; @@ -10,6 +8,7 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.EnumFacing; import net.minecraft.util.MathHelper; +import org.embeddedt.archaicfix.occlusion.interfaces.IWorldRenderer; import java.util.ArrayList; import java.util.Arrays; @@ -17,13 +16,11 @@ import java.util.List; import java.util.stream.Stream; +import static org.embeddedt.archaicfix.occlusion.OcclusionHelpers.DEBUG_PRINT_QUEUE_ITERATIONS; + public class OcclusionWorker { public OcclusionWorker() { - - /*for (int i = 0; i < fStack.length; ++i) { - fStack[i] = new Frustrum(); - }//*/ } public void setWorld(RenderGlobal rg, WorldClient world) { @@ -54,11 +51,11 @@ public void setWorld(RenderGlobal rg, WorldClient world) { private RenderGlobal getRender() { return getExtendedRender().getRenderGlobal(); } - + private OcclusionRenderer getExtendedRender() { return OcclusionHelpers.renderer; } - + public void run(boolean immediate) { frame++; queue.clear(); @@ -161,12 +158,12 @@ private void seedQueue(Frustrum frustum) { int level = viewY > 5 ? 250 : 5; center = extendedRender.getRenderer(viewX, level, viewZ); if (center != null) { - StepDirection pos = viewY < 5 ? StepDirection.UP : StepDirection.DOWN; { CullInfo ci = ((IWorldRenderer) center).arch$getCullInfo(); ci.init(StepDirection.NONE, (byte) 0); queue.add(ci); } + boolean allNull = false; theWorld.theProfiler.startSection("gather_world"); for (int size = 1; !allNull; ++size) { @@ -266,8 +263,7 @@ public enum StepDirection { StepDirection[] bias = DIRECTIONS_BIAS[i]; int j = 0, xor = pos.ordinal() & 1; switch (pos) { - case DOWN: - case UP: + case DOWN, UP: bias[j++] = pos; bias[j++] = DIRECTIONS[NORTH.ordinal() ^ xor]; bias[j++] = DIRECTIONS[SOUTH.ordinal() ^ xor]; @@ -275,8 +271,7 @@ public enum StepDirection { bias[j++] = DIRECTIONS[WEST.ordinal() ^ xor]; bias[j++] = pos.getOpposite(); break; - case WEST: - case EAST: + case WEST, EAST: bias[j++] = pos; bias[j++] = DIRECTIONS[NORTH.ordinal() ^ xor]; bias[j++] = DIRECTIONS[SOUTH.ordinal() ^ xor]; @@ -284,8 +279,7 @@ public enum StepDirection { bias[j++] = DIRECTIONS[DOWN.ordinal() ^ xor]; bias[j++] = pos.getOpposite(); break; - case NORTH: - case SOUTH: + case NORTH, SOUTH: bias[j++] = pos; bias[j++] = DIRECTIONS[EAST.ordinal() ^ xor]; bias[j++] = DIRECTIONS[WEST.ordinal() ^ xor]; @@ -293,8 +287,7 @@ public enum StepDirection { bias[j++] = DIRECTIONS[DOWN.ordinal() ^ xor]; bias[j++] = pos.getOpposite(); break; - case NONE: - case NONE_opp: + case NONE, NONE_opp: break; } } diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java b/src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java index 359d85f5b..3ce9d917e 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java @@ -1,26 +1,21 @@ package org.embeddedt.archaicfix.occlusion; -import java.util.Iterator; -import java.util.Set; - import net.minecraft.util.EnumFacing; +import java.util.Set; + public class SetVisibility { private static final int COUNT_FACES = EnumFacing.values().length; public static long setManyVisible(long bitSet, Set faces) { - Iterator iterator = faces.iterator(); - while (iterator.hasNext()) { - EnumFacing enumfacing = iterator.next(); - Iterator iterator1 = faces.iterator(); + for (EnumFacing enumfacing : faces) { - while (iterator1.hasNext()) { - EnumFacing enumfacing1 = iterator1.next(); - bitSet = setVisible(bitSet, enumfacing, enumfacing1, true); - } - } + for (EnumFacing enumfacing1 : faces) { + bitSet = setVisible(bitSet, enumfacing, enumfacing1, true); + } + } return bitSet; } @@ -41,7 +36,7 @@ private static long setBit(long bitSet, int index, boolean value) { } public static boolean isVisible(long bitSet, EnumFacing from, EnumFacing to) { - return from == null || to == null ? true : (bitSet & (1L << (from.ordinal() + to.ordinal() * COUNT_FACES))) != 0; + return from == null || to == null || (bitSet & (1L << (from.ordinal() + to.ordinal() * COUNT_FACES))) != 0; } public static String toString(long bitSet) { @@ -68,16 +63,14 @@ public static String toString(long bitSet) { EnumFacing[] aenumfacing1 = EnumFacing.values(); int k = aenumfacing1.length; - for (int l = 0; l < k; ++l) { - EnumFacing enumfacing1 = aenumfacing1[l]; - - if (enumfacing == enumfacing1) { - stringbuilder.append(" "); - } else { - boolean flag = isVisible(bitSet, enumfacing, enumfacing1); - stringbuilder.append(' ').append(flag ? 'Y' : 'n'); - } - } + for (EnumFacing enumfacing1 : aenumfacing1) { + if (enumfacing == enumfacing1) { + stringbuilder.append(" "); + } else { + boolean flag = isVisible(bitSet, enumfacing, enumfacing1); + stringbuilder.append(' ').append(flag ? 'Y' : 'n'); + } + } stringbuilder.append('\n'); } diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java b/src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java index 23dd219d8..560e404fc 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java @@ -1,12 +1,13 @@ package org.embeddedt.archaicfix.occlusion; +import lombok.Getter; +import net.minecraft.util.EnumFacing; +import org.embeddedt.archaicfix.occlusion.util.IntStack; + import java.util.BitSet; import java.util.EnumSet; import java.util.Set; -import net.minecraft.util.EnumFacing; -import org.embeddedt.archaicfix.occlusion.util.IntStack; - public class VisGraph { private static final int X_OFFSET = (int) Math.pow(16.0D, 0.0D); @@ -16,13 +17,13 @@ public class VisGraph { public static final long ALL_VIS = 0xFFFFFFFFFFFFFFFFL; static { - int var2 = 0; + int i = 0; - for (int var3 = 0; var3 < 16; ++var3) { - for (int var4 = 0; var4 < 16; ++var4) { - for (int var5 = 0; var5 < 16; ++var5) { - if (var3 == 0 || var3 == 15 || var4 == 0 || var4 == 15 || var5 == 0 || var5 == 15) { - EDGES[var2++] = getIndex(var3, var4, var5); + for (int x = 0; x < 16; ++x) { + for (int y = 0; y < 16; ++y) { + for (int z = 0; z < 16; ++z) { + if (x == 0 || x == 15 || y == 0 || y == 15 || z == 0 || z == 15) { + EDGES[i++] = getIndex(x, y, z); } } } @@ -38,22 +39,18 @@ public class VisGraph { private final BitSet opaqueBlocks = new BitSet(4096); private final BitSet visibleBlocks = new BitSet(4096); private short transparentBlocks = 4096; - private boolean dirty = true, computedVis = true; + @Getter + private boolean dirty = true, computedVis = true; /** Accessing this class's fields is slow, so we let the visibility value be referenced directly. */ - private long[] visibility = new long[]{ALL_VIS}; + private final long[] visibility = new long[]{ALL_VIS}; private static int getIndex(int x, int y, int z) { return x << 0 | y << 8 | z << 4; } - public boolean isDirty() { - - return dirty; - } - - public boolean isRenderDirty() { + public boolean isRenderDirty() { if (isDirty()) { return true; @@ -98,14 +95,12 @@ public void computeVisibility() { visibleBlocks.andNot(visibleBlocks); visibleBlocks.or(opaqueBlocks); IntStack linkedlist = new IntStack(1024, 512); - for (int j = 0; j < i; ++j) { - int k = edges[j]; - - if (!opaqueBlocks.get(k)) { - setvisibility = SetVisibility.setManyVisible(setvisibility, computeVisibleFacingsFrom(k, linkedlist)); - } - linkedlist.setSize(0); - } + for (int k : edges) { + if (!opaqueBlocks.get(k)) { + setvisibility = SetVisibility.setManyVisible(setvisibility, computeVisibleFacingsFrom(k, linkedlist)); + } + linkedlist.setSize(0); + } } visibility[0] = setvisibility; @@ -129,20 +124,19 @@ private EnumSet computeVisibleFacingsFrom(int index, IntStack linkedlist) { blocks.set(index, true); EnumFacing[] facings = EnumFacing.values(); - int k = facings.length; + final int k = facings.length; while (!linkedlist.isEmpty()) { int j = linkedlist.poll(); addSides(j, enumset); - for (int l = 0; l < k; ++l) { - EnumFacing face = facings[l]; - int i1 = stepTo(j, face); + for (EnumFacing face : facings) { + int i1 = stepTo(j, face); - if (i1 >= 0 && !blocks.get(i1)) { - blocks.set(i1, true); - linkedlist.add(i1); - } - } + if (i1 >= 0 && !blocks.get(i1)) { + blocks.set(i1, true); + linkedlist.add(i1); + } + } } return enumset; @@ -177,46 +171,45 @@ private void addSides(int index, Set set) { private int stepTo(int index, EnumFacing side) { - switch (side) { - case DOWN: - if ((index >> 8 & 15) == 0) { - return -1; - } - - return index - Y_OFFSET; - case UP: - if ((index >> 8 & 15) == 15) { - return -1; - } - - return index + Y_OFFSET; - case NORTH: - if ((index >> 4 & 15) == 0) { - return -1; - } - - return index - Z_OFFSET; - case SOUTH: - if ((index >> 4 & 15) == 15) { - return -1; - } - - return index + Z_OFFSET; - case EAST: /* WEST */ - if ((index >> 0 & 15) == 0) { - return -1; - } - - return index - X_OFFSET; - case WEST: /* EAST */ - if ((index >> 0 & 15) == 15) { - return -1; - } - - return index + X_OFFSET; - default: - return -1; - } + return switch (side) { + case DOWN -> { + if ((index >> 8 & 15) == 0) { + yield -1; + } + yield index - Y_OFFSET; + } + case UP -> { + if ((index >> 8 & 15) == 15) { + yield -1; + } + yield index + Y_OFFSET; + } + case NORTH -> { + if ((index >> 4 & 15) == 0) { + yield -1; + } + yield index - Z_OFFSET; + } + case SOUTH -> { + if ((index >> 4 & 15) == 15) { + yield -1; + } + yield index + Z_OFFSET; + } + case EAST -> { + if ((index >> 0 & 15) == 0) { + yield -1; + } + yield index - X_OFFSET; + } + case WEST -> { + if ((index >> 0 & 15) == 15) { + yield -1; + } + yield index + X_OFFSET; + } + default -> -1; + }; } } diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/ICulledChunk.java b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/ICulledChunk.java similarity index 77% rename from src/main/java/org/embeddedt/archaicfix/occlusion/ICulledChunk.java rename to src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/ICulledChunk.java index 44bfa9448..df2033a91 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/ICulledChunk.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/ICulledChunk.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.occlusion; +package org.embeddedt.archaicfix.occlusion.interfaces; import net.minecraft.world.chunk.Chunk; import org.embeddedt.archaicfix.occlusion.VisGraph; diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/IRenderGlobalListener.java b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRenderGlobalListener.java similarity index 80% rename from src/main/java/org/embeddedt/archaicfix/occlusion/IRenderGlobalListener.java rename to src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRenderGlobalListener.java index b7877789f..ecc4bb185 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/IRenderGlobalListener.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRenderGlobalListener.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.occlusion; +package org.embeddedt.archaicfix.occlusion.interfaces; import net.minecraft.client.renderer.WorldRenderer; diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/IRendererUpdateOrderProvider.java b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRendererUpdateOrderProvider.java similarity index 92% rename from src/main/java/org/embeddedt/archaicfix/occlusion/IRendererUpdateOrderProvider.java rename to src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRendererUpdateOrderProvider.java index 52a3785e2..4ab0894d5 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/IRendererUpdateOrderProvider.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRendererUpdateOrderProvider.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.occlusion; +package org.embeddedt.archaicfix.occlusion.interfaces; import net.minecraft.client.renderer.WorldRenderer; @@ -7,12 +7,12 @@ /** Provides a traversal order of the elements of RenderGlobal#worldRenderersToUpdate. Ideally, the order should be from * the closest renderer to the farthest. */ public interface IRendererUpdateOrderProvider { - + /** Prepare providing a batch of renderers. */ void prepare(List worldRenderersToUpdateList); - + boolean hasNext(List worldRenderersToUpdateList); - + WorldRenderer next(List worldRenderersToUpdateList); /** End the batch. Remove the renderers that were provided during the batch from worldRenderersToUpdate */ diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/IWorldRenderer.java b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IWorldRenderer.java similarity index 59% rename from src/main/java/org/embeddedt/archaicfix/occlusion/IWorldRenderer.java rename to src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IWorldRenderer.java index a80592260..fac2dd407 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/IWorldRenderer.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IWorldRenderer.java @@ -1,4 +1,6 @@ -package org.embeddedt.archaicfix.occlusion; +package org.embeddedt.archaicfix.occlusion.interfaces; + +import org.embeddedt.archaicfix.occlusion.OcclusionWorker; public interface IWorldRenderer { diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java index e2385d4e0..582bd1334 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java @@ -3,7 +3,15 @@ import com.google.common.base.Objects; import com.google.common.primitives.Ints; -import java.util.*; +import java.util.AbstractCollection; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; @SuppressWarnings("unchecked") public class LinkedHashList extends AbstractCollection implements List, Cloneable, java.io.Serializable { diff --git a/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java b/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java index a078367cf..f4c00d48a 100644 --- a/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java +++ b/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java @@ -26,7 +26,7 @@ import org.embeddedt.archaicfix.helpers.BuiltInResourcePack; import org.embeddedt.archaicfix.helpers.SoundDeviceThread; import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; -import zone.rong.rongasm.api.LoliStringPool; +import zone.rong.rongasm.api.StringPool; import java.lang.management.ManagementFactory; import java.util.Locale; @@ -40,7 +40,7 @@ public void preinit() { Minecraft.memoryReserve = new byte[0]; if(ArchaicConfig.enableOcclusionTweaks) OcclusionHelpers.init(); - MinecraftForge.EVENT_BUS.register(new LoliStringPool.EventHandler()); + MinecraftForge.EVENT_BUS.register(new StringPool.EventHandler()); MinecraftForge.EVENT_BUS.register(this); FMLCommonHandler.instance().bus().register(this); if(ArchaicConfig.modernizeTextures) { diff --git a/src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java b/src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java index fd65160e2..00dd86310 100644 --- a/src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java +++ b/src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java @@ -2,7 +2,7 @@ import ca.fxco.memoryleakfix.MemoryLeakFix; import org.embeddedt.archaicfix.config.ArchaicConfig; -import zone.rong.rongasm.api.LoliHelpers; +import zone.rong.rongasm.api.RongHelpers; public class CommonProxy { public void preinit() { @@ -13,6 +13,6 @@ public void loadcomplete() { if(ArchaicConfig.clearMixinCache) MemoryLeakFix.forceLoadAllMixinsAndClearSpongePoweredCache(); if(ArchaicConfig.clearLaunchLoaderCache) - LoliHelpers.cleanupLaunchClassLoader(); + RongHelpers.cleanupLaunchClassLoader(); } } diff --git a/src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java b/src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java index cf78615e0..41496df0a 100644 --- a/src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java +++ b/src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java @@ -4,7 +4,7 @@ import net.minecraft.item.Item; import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.IRecipe; -import org.embeddedt.archaicfix.ducks.IAcceleratedRecipe; +import org.embeddedt.archaicfix.interfaces.IAcceleratedRecipe; import java.util.List; import java.util.Set; diff --git a/src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java b/src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java index 7dc5e55f6..fe4a0930a 100644 --- a/src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java +++ b/src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java @@ -1,7 +1,5 @@ package org.embeddedt.archaicfix.threadedupdates; -import static org.embeddedt.archaicfix.ArchaicLogger.LOGGER; - import com.google.common.base.Preconditions; import lombok.SneakyThrows; import net.minecraft.block.Block; @@ -13,12 +11,20 @@ import net.minecraft.client.shader.TesselatorVertexState; import net.minecraft.world.ChunkCache; import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.occlusion.IRenderGlobalListener; -import org.embeddedt.archaicfix.occlusion.IRendererUpdateOrderProvider; +import org.embeddedt.archaicfix.occlusion.interfaces.IRenderGlobalListener; +import org.embeddedt.archaicfix.occlusion.interfaces.IRendererUpdateOrderProvider; import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; -import java.util.*; -import java.util.concurrent.*; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingDeque; + +import static org.embeddedt.archaicfix.ArchaicLogger.LOGGER; public class ThreadedChunkUpdateHelper implements IRenderGlobalListener { @@ -287,7 +293,7 @@ private static void debugLog(String msg) { LOGGER.trace(msg); } } - + public static class UpdateTask { public boolean started; public boolean cancelled; diff --git a/src/main/java/zone/rong/rongasm/api/LoliHelpers.java b/src/main/java/zone/rong/rongasm/api/RongHelpers.java similarity index 80% rename from src/main/java/zone/rong/rongasm/api/LoliHelpers.java rename to src/main/java/zone/rong/rongasm/api/RongHelpers.java index 228e72d53..be7255863 100644 --- a/src/main/java/zone/rong/rongasm/api/LoliHelpers.java +++ b/src/main/java/zone/rong/rongasm/api/RongHelpers.java @@ -8,7 +8,7 @@ import java.util.Map; -public class LoliHelpers { +public class RongHelpers { private static final boolean noClassCache = false; private static final boolean weakClassCache = true; private static final boolean noResourceCache = false; @@ -17,21 +17,21 @@ public static void cleanupLaunchClassLoader() { try { ArchaicLogger.LOGGER.info("Cleaning up LaunchClassLoader"); if (noClassCache) { - LoliReflector.resolveFieldSetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader, DummyMap.of()); + RongReflector.resolveFieldSetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader, DummyMap.of()); } else if (weakClassCache) { - Map> oldClassCache = (Map>) LoliReflector.resolveFieldGetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader); + Map> oldClassCache = (Map>) RongReflector.resolveFieldGetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader); Cache> newClassCache = CacheBuilder.newBuilder().concurrencyLevel(2).weakValues().build(); newClassCache.putAll(oldClassCache); - LoliReflector.resolveFieldSetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader, newClassCache.asMap()); + RongReflector.resolveFieldSetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader, newClassCache.asMap()); } if (noResourceCache) { - LoliReflector.resolveFieldSetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader, new ResourceCache()); - LoliReflector.resolveFieldSetter(LaunchClassLoader.class, "negativeResourceCache").invokeExact(Launch.classLoader, DummyMap.asSet()); + RongReflector.resolveFieldSetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader, new ResourceCache()); + RongReflector.resolveFieldSetter(LaunchClassLoader.class, "negativeResourceCache").invokeExact(Launch.classLoader, DummyMap.asSet()); } else if (weakResourceCache) { - Map oldResourceCache = (Map) LoliReflector.resolveFieldGetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader); + Map oldResourceCache = (Map) RongReflector.resolveFieldGetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader); Cache newResourceCache = CacheBuilder.newBuilder().concurrencyLevel(2).weakValues().build(); newResourceCache.putAll(oldResourceCache); - LoliReflector.resolveFieldSetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader, newResourceCache.asMap()); + RongReflector.resolveFieldSetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader, newResourceCache.asMap()); } } catch (Throwable throwable) { throwable.printStackTrace(); diff --git a/src/main/java/zone/rong/rongasm/api/LoliReflector.java b/src/main/java/zone/rong/rongasm/api/RongReflector.java similarity index 91% rename from src/main/java/zone/rong/rongasm/api/LoliReflector.java rename to src/main/java/zone/rong/rongasm/api/RongReflector.java index 9dda4b6c6..896a92f21 100644 --- a/src/main/java/zone/rong/rongasm/api/LoliReflector.java +++ b/src/main/java/zone/rong/rongasm/api/RongReflector.java @@ -18,7 +18,7 @@ /** * Helper class for Reflection nonsense. */ -public class LoliReflector { +public class RongReflector { public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); @@ -141,11 +141,6 @@ public static MethodHandle resolveFieldGetter(Class clazz, String fieldName) try { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); - /* - if (LoliLoadingPlugin.isVMOpenJ9) { - fixOpenJ9PrivateStaticFinalRestraint(field); - } - */ return LOOKUP.unreflectGetter(field); } catch (Throwable e) { e.printStackTrace(); @@ -157,11 +152,6 @@ public static MethodHandle resolveFieldSetter(Class clazz, String fieldName) try { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); - /* - if (LoliLoadingPlugin.isVMOpenJ9) { - fixOpenJ9PrivateStaticFinalRestraint(field); - } - */ return LOOKUP.unreflectSetter(field); } catch (Throwable e) { e.printStackTrace(); @@ -191,11 +181,6 @@ public static Field getField(Class clazz, String fieldName) { try { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); - /* - if (LoliLoadingPlugin.isVMOpenJ9) { - fixOpenJ9PrivateStaticFinalRestraint(field); - } - */ return field; } catch (Throwable e) { e.printStackTrace(); @@ -236,10 +221,4 @@ public static void addTransformerExclusion(String transformerExclusion) { transformerExclusions.put(transformerExclusion); } - private static void fixOpenJ9PrivateStaticFinalRestraint(Field field) throws Throwable { - Field modifiers = Field.class.getDeclaredField("modifiers"); - modifiers.setAccessible(true); - LOOKUP.unreflectSetter(modifiers).invokeExact(field, field.getModifiers() & ~Modifier.FINAL); - } - } diff --git a/src/main/java/zone/rong/rongasm/api/LoliStringPool.java b/src/main/java/zone/rong/rongasm/api/StringPool.java similarity index 99% rename from src/main/java/zone/rong/rongasm/api/LoliStringPool.java rename to src/main/java/zone/rong/rongasm/api/StringPool.java index 19564d132..6f827eca6 100644 --- a/src/main/java/zone/rong/rongasm/api/LoliStringPool.java +++ b/src/main/java/zone/rong/rongasm/api/StringPool.java @@ -6,7 +6,7 @@ import java.util.Locale; -public class LoliStringPool { +public class StringPool { public static final int FILE_PERMISSIONS_ID = 1; diff --git a/src/main/resources/ModulSettings.json b/src/main/resources/ModulSettings.json deleted file mode 100644 index 3832a22ee..000000000 --- a/src/main/resources/ModulSettings.json +++ /dev/null @@ -1,2624 +0,0 @@ -{ - "Async": false, - "Base": true, - "Collection": true, - "Function": true, - "List": true, - "Map": true, - "Pair": true, - "PriorityQueue": true, - "Set": true, - "Boolean": { - "Enabled": false, - "Base": { - "Enabled": false - }, - "Boolean": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Byte": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Short": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Character": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Integer": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Long": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Float": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Double": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Object": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Collection": { - "Enabled": false, - "IArray": false, - "Splititerators": false, - "Strategy": false, - "Streams": true - }, - "PriorityQueue": { - "Enabled": false, - "ArrayPrioQueue": false, - "Dequeue": false, - "FiFoQueue": false, - "HeapQueue": false, - "Implementations": false, - "Wrappers": false - }, - "List": { - "Enabled": false, - "ArrayList": false, - "CopyOnWriteList": false, - "ImmutableList": false, - "Implementations": false, - "LinkedList": false, - "Wrappers": false - }, - "Async": { - "Enabled": false - } - }, - "Byte": { - "Enabled": false, - "Base": { - "Enabled": false - }, - "Boolean": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Byte": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Short": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Character": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Integer": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Long": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Float": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Double": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Object": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Collection": { - "Enabled": false, - "IArray": false, - "Splititerators": false, - "Strategy": false, - "Streams": true - }, - "PriorityQueue": { - "Enabled": false, - "ArrayPrioQueue": false, - "Dequeue": false, - "FiFoQueue": false, - "HeapQueue": false, - "Implementations": false, - "Wrappers": false - }, - "List": { - "Enabled": false, - "ArrayList": false, - "CopyOnWriteList": false, - "ImmutableList": false, - "Implementations": false, - "LinkedList": false, - "Wrappers": false - }, - "Set": { - "Enabled": false, - "AVLTreeSet": false, - "ArraySet": false, - "CustomHashSet": false, - "HashSet": false, - "ImmutableSet": false, - "Implementations": false, - "LinkedCustomHashSet": false, - "LinkedHashSet": false, - "OrderedSet": false, - "RBTreeSet": false, - "SortedSet": false, - "Wrappers": false - }, - "Async": { - "Enabled": false - } - }, - "Short": { - "Enabled": false, - "Base": { - "Enabled": false - }, - "Boolean": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Byte": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Short": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Character": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Integer": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Long": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Float": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Double": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Object": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Collection": { - "Enabled": false, - "IArray": false, - "Splititerators": false, - "Strategy": false, - "Streams": true - }, - "PriorityQueue": { - "Enabled": false, - "ArrayPrioQueue": false, - "Dequeue": false, - "FiFoQueue": false, - "HeapQueue": false, - "Implementations": false, - "Wrappers": false - }, - "List": { - "Enabled": false, - "ArrayList": false, - "CopyOnWriteList": false, - "ImmutableList": false, - "Implementations": false, - "LinkedList": false, - "Wrappers": false - }, - "Set": { - "Enabled": false, - "AVLTreeSet": false, - "ArraySet": false, - "CustomHashSet": false, - "HashSet": false, - "ImmutableSet": false, - "Implementations": false, - "LinkedCustomHashSet": false, - "LinkedHashSet": false, - "OrderedSet": false, - "RBTreeSet": false, - "SortedSet": false, - "Wrappers": false - }, - "Async": { - "Enabled": false - } - }, - "Character": { - "Enabled": false, - "Base": { - "Enabled": false - }, - "Boolean": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Byte": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Short": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Character": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Integer": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Long": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Float": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Double": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Object": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Collection": { - "Enabled": false, - "IArray": false, - "Splititerators": false, - "Strategy": false, - "Streams": true - }, - "PriorityQueue": { - "Enabled": false, - "ArrayPrioQueue": false, - "Dequeue": false, - "FiFoQueue": false, - "HeapQueue": false, - "Implementations": false, - "Wrappers": false - }, - "List": { - "Enabled": false, - "ArrayList": false, - "CopyOnWriteList": false, - "ImmutableList": false, - "Implementations": false, - "LinkedList": false, - "Wrappers": false - }, - "Set": { - "Enabled": false, - "AVLTreeSet": false, - "ArraySet": false, - "CustomHashSet": false, - "HashSet": false, - "ImmutableSet": false, - "Implementations": false, - "LinkedCustomHashSet": false, - "LinkedHashSet": false, - "OrderedSet": false, - "RBTreeSet": false, - "SortedSet": false, - "Wrappers": false - }, - "Async": { - "Enabled": false - } - }, - "Integer": { - "Enabled": true, - "Base": { - "Enabled": true - }, - "Boolean": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Byte": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Short": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Character": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Integer": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Long": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Float": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Double": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Object": { - "Enabled": true, - "Function": { - "Enabled": true - }, - "Map": { - "Enabled": true, - "AVLTreeMap": false, - "ArrayMap": true, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": true, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": true, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Collection": { - "Enabled": true, - "IArray": true, - "Splititerators": true, - "Strategy": false, - "Streams": true - }, - "PriorityQueue": { - "Enabled": false, - "ArrayPrioQueue": false, - "Dequeue": false, - "FiFoQueue": false, - "HeapQueue": false, - "Implementations": false, - "Wrappers": false - }, - "List": { - "Enabled": false, - "ArrayList": false, - "CopyOnWriteList": false, - "ImmutableList": false, - "Implementations": false, - "LinkedList": false, - "Wrappers": false - }, - "Set": { - "Enabled": true, - "AVLTreeSet": false, - "ArraySet": false, - "CustomHashSet": false, - "HashSet": false, - "ImmutableSet": false, - "Implementations": false, - "LinkedCustomHashSet": false, - "LinkedHashSet": false, - "OrderedSet": true, - "RBTreeSet": false, - "SortedSet": false, - "Wrappers": false - }, - "Async": { - "Enabled": false - } - }, - "Long": { - "Enabled": true, - "Base": { - "Enabled": true - }, - "Boolean": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Byte": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Short": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Character": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Integer": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Long": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Float": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Double": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Object": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Collection": { - "Enabled": true, - "IArray": false, - "Splititerators": true, - "Strategy": false, - "Streams": true - }, - "PriorityQueue": { - "Enabled": false, - "ArrayPrioQueue": false, - "Dequeue": false, - "FiFoQueue": false, - "HeapQueue": false, - "Implementations": false, - "Wrappers": false - }, - "List": { - "Enabled": false, - "ArrayList": false, - "CopyOnWriteList": false, - "ImmutableList": false, - "Implementations": false, - "LinkedList": false, - "Wrappers": false - }, - "Set": { - "Enabled": true, - "AVLTreeSet": false, - "ArraySet": false, - "CustomHashSet": false, - "HashSet": true, - "ImmutableSet": false, - "Implementations": true, - "LinkedCustomHashSet": false, - "LinkedHashSet": false, - "OrderedSet": false, - "RBTreeSet": false, - "SortedSet": false, - "Wrappers": false - }, - "Async": { - "Enabled": false - } - }, - "Float": { - "Enabled": false, - "Base": { - "Enabled": false - }, - "Boolean": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Byte": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Short": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Character": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Integer": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Long": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Float": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Double": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Object": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Collection": { - "Enabled": false, - "IArray": false, - "Splititerators": false, - "Strategy": false, - "Streams": true - }, - "PriorityQueue": { - "Enabled": false, - "ArrayPrioQueue": false, - "Dequeue": false, - "FiFoQueue": false, - "HeapQueue": false, - "Implementations": false, - "Wrappers": false - }, - "List": { - "Enabled": false, - "ArrayList": false, - "CopyOnWriteList": false, - "ImmutableList": false, - "Implementations": false, - "LinkedList": false, - "Wrappers": false - }, - "Set": { - "Enabled": false, - "AVLTreeSet": false, - "ArraySet": false, - "CustomHashSet": false, - "HashSet": false, - "ImmutableSet": false, - "Implementations": false, - "LinkedCustomHashSet": false, - "LinkedHashSet": false, - "OrderedSet": false, - "RBTreeSet": false, - "SortedSet": false, - "Wrappers": false - }, - "Async": { - "Enabled": false - } - }, - "Double": { - "Enabled": false, - "Base": { - "Enabled": false - }, - "Boolean": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Byte": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Short": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Character": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Integer": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Long": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Float": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Double": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Object": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Collection": { - "Enabled": false, - "IArray": false, - "Splititerators": false, - "Strategy": false, - "Streams": true - }, - "PriorityQueue": { - "Enabled": false, - "ArrayPrioQueue": false, - "Dequeue": false, - "FiFoQueue": false, - "HeapQueue": false, - "Implementations": false, - "Wrappers": false - }, - "List": { - "Enabled": false, - "ArrayList": false, - "CopyOnWriteList": false, - "ImmutableList": false, - "Implementations": false, - "LinkedList": false, - "Wrappers": false - }, - "Set": { - "Enabled": false, - "AVLTreeSet": false, - "ArraySet": false, - "CustomHashSet": false, - "HashSet": false, - "ImmutableSet": false, - "Implementations": false, - "LinkedCustomHashSet": false, - "LinkedHashSet": false, - "OrderedSet": false, - "RBTreeSet": false, - "SortedSet": false, - "Wrappers": false - }, - "Async": { - "Enabled": false - } - }, - "Object": { - "Enabled": true, - "Base": { - "Enabled": true - }, - "Boolean": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Byte": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Short": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Character": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Integer": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Long": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Float": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Double": { - "Enabled": false, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": false, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": false, - "ImmutableMap": false, - "Implementations": false, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Object": { - "Enabled": true, - "Function": { - "Enabled": false - }, - "Map": { - "Enabled": true, - "AVLTreeMap": false, - "ArrayMap": false, - "ConcurrentMap": false, - "CustomHashMap": false, - "EnumMap": false, - "HashMap": true, - "ImmutableMap": false, - "Implementations": true, - "LinkedCustomHashMap": false, - "LinkedEnumMap": false, - "LinkedHashMap": false, - "OrderedMap": false, - "RBTreeMap": false, - "SortedMap": false, - "Wrappers": false - }, - "Pair": { - "Enabled": false, - "Immutable": false, - "Mutable": false - } - }, - "Collection": { - "Enabled": true, - "IArray": false, - "Splititerators": true, - "Strategy": false, - "Streams": true - }, - "PriorityQueue": { - "Enabled": false, - "ArrayPrioQueue": false, - "Dequeue": false, - "FiFoQueue": false, - "HeapQueue": false, - "Implementations": false, - "Wrappers": false - }, - "List": { - "Enabled": true, - "ArrayList": true, - "CopyOnWriteList": false, - "ImmutableList": false, - "Implementations": true, - "LinkedList": false, - "Wrappers": false - }, - "Set": { - "Enabled": true, - "AVLTreeSet": false, - "ArraySet": false, - "CustomHashSet": false, - "HashSet": true, - "ImmutableSet": false, - "Implementations": true, - "LinkedCustomHashSet": false, - "LinkedHashSet": false, - "OrderedSet": true, - "RBTreeSet": false, - "SortedSet": false, - "Wrappers": false - }, - "Async": { - "Enabled": false - } - } -} diff --git a/src/main/resources/letsencrypt/isrg-root-x2.pem b/src/main/resources/letsencrypt/isrg-root-x2.pem deleted file mode 100644 index 7d903edc9..000000000 --- a/src/main/resources/letsencrypt/isrg-root-x2.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw -CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg -R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 -MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT -ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw -EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW -+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 -ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI -zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW -tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 -/q4AaOeMSQ+2b1tbFfLn ------END CERTIFICATE----- diff --git a/src/main/resources/letsencrypt/isrgrootx1.pem b/src/main/resources/letsencrypt/isrgrootx1.pem deleted file mode 100644 index b85c8037f..000000000 --- a/src/main/resources/letsencrypt/isrgrootx1.pem +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index 6718e4cb6..bad248d9b 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -45,6 +45,24 @@ "dependencies": [], "dependants": [], "useDependencyInformation": true + }, + { + "modid": "archaicfix", + "name": "ArchaicFix", + "description": "Swiss army knife of bugfixes for 1.7.", + "version": "${modVersion}", + "mcversion": "${minecraftVersion}", + "url": "", + "updateUrl": "", + "authorList": [ + "embeddedt" + ], + "credits": "The Forge and FML guys, for making this example", + "logoFile": "", + "screenshots": [], + "dependencies": [ + "required-after:gtnhmixins@[2.0.0,)" + ] } ] } diff --git a/src/main/resources/mixins.archaicfix.early.json b/src/main/resources/mixins.archaicfix.early.json deleted file mode 100644 index e092697c0..000000000 --- a/src/main/resources/mixins.archaicfix.early.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "required": true, - "minVersion": "0.7.11", - "package": "org.embeddedt.archaicfix.mixins", - "refmap": "mixins.archaicfix.refmap.json", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_8" -} \ No newline at end of file diff --git a/src/main/resources/mixins.archaicfix.json b/src/main/resources/mixins.archaicfix.json deleted file mode 100644 index b4e0f892b..000000000 --- a/src/main/resources/mixins.archaicfix.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "required": true, - "minVersion": "0.7.11", - "package": "org.embeddedt.archaicfix.mixins", - "refmap": "mixins.archaicfix.refmap.json", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_8" -} - diff --git a/src/main/resources/mixins.archaicfix.late.json b/src/main/resources/mixins.archaicfix.late.json deleted file mode 100644 index b4e0f892b..000000000 --- a/src/main/resources/mixins.archaicfix.late.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "required": true, - "minVersion": "0.7.11", - "package": "org.embeddedt.archaicfix.mixins", - "refmap": "mixins.archaicfix.refmap.json", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_8" -} - diff --git a/src/main/resources/mixins.notfine.early.json b/src/main/resources/mixins.notfine.early.json deleted file mode 100644 index 1972bac32..000000000 --- a/src/main/resources/mixins.notfine.early.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "required": true, - "minVersion": "0.7.11", - "package": "jss.notfine.mixins.early", - "refmap": "mixins.angelica.refmap.json", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_8" -} diff --git a/src/main/resources/mixins.notfine.json b/src/main/resources/mixins.notfine.json deleted file mode 100644 index ca3673361..000000000 --- a/src/main/resources/mixins.notfine.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "required": true, - "minVersion": "0.7.11", - "package": "jss.notfine.mixins", - "refmap": "mixins.angelica.refmap.json", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_8", - "mixins": [], - "client": [], - "server": [] -} diff --git a/src/main/resources/mixins.notfine.late.json b/src/main/resources/mixins.notfine.late.json deleted file mode 100644 index 97b6700dd..000000000 --- a/src/main/resources/mixins.notfine.late.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "required": true, - "minVersion": "0.7.11", - "package": "jss.notfine.mixins.late", - "refmap": "mixins.angelica.refmap.json", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_8" -} diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index 0c5f6bcaf..1c6bd064a 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { "pack_format": 1, - "description": "ArchaicFix resources" + "description": "Angelica resources" } -} \ No newline at end of file +} From 7aae4f7fce41247d42eb42d290efbc29df1dd5be Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 24 Sep 2023 11:45:23 -0700 Subject: [PATCH 005/301] Address mixin conflicts, disable threaded chunk updates as the current Shaders implementation isn't threadsafe --- .../archaic/client/core/MixinRenderItem.java | 2 +- .../early/notfine/glint/MixinRenderItem.java | 7 +------ .../early/notfine/toggle/MixinRenderItem.java | 8 ++------ .../mixins/early/renderer/MixinRenderGlobal.java | 15 +++++++++------ .../archaicfix/config/ArchaicConfig.java | 8 ++------ .../archaicfix/occlusion/OcclusionRenderer.java | 5 ++--- 6 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinRenderItem.java index 6e096bb5b..a53d65137 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinRenderItem.java @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -@Mixin(RenderItem.class) +@Mixin(value = RenderItem.class, priority = 1001) public class MixinRenderItem { @Redirect(method = "renderDroppedItem(Lnet/minecraft/entity/item/EntityItem;Lnet/minecraft/util/IIcon;IFFFFI)V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z")) private boolean forceFancyGraphics(GameSettings settings) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java index 59b6feb63..b6b58e4fb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java @@ -64,12 +64,7 @@ private void renderGlint(int unused, int posX, int posY, int width, int height) @Redirect( method = "renderDroppedItem(Lnet/minecraft/entity/item/EntityItem;Lnet/minecraft/util/IIcon;IFFFFI)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/item/ItemStack;hasEffect(I)Z" - ), - remap = false - ) + at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;hasEffect(I)Z"), remap = false) private boolean notFine$toggleGlint(ItemStack stack, int pass) { return Settings.MODE_GLINT_WORLD.isValueBase() && stack.hasEffect(pass); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRenderItem.java index 7927253e0..67311d331 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRenderItem.java @@ -13,12 +13,8 @@ abstract public class MixinRenderItem { @Redirect( method = "renderDroppedItem(Lnet/minecraft/entity/item/EntityItem;Lnet/minecraft/util/IIcon;IFFFFI)V", - at = @At( - value = "FIELD", - target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", - opcode = Opcodes.GETFIELD - ), - allow = 1 + at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", opcode = Opcodes.GETFIELD), + allow = 1, expect = 0 ) private boolean notFine$toggleDroppedItemDetail(GameSettings settings) { return SettingsManager.droppedItemDetail; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java index 6280eb604..969fb5cc5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java @@ -58,9 +58,9 @@ public class MixinRenderGlobal { // Texture 2D @Inject( method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false, ordinal = 0, shift = At.Shift.AFTER), expect = 1) - private void angelica$sortandRenderDisableTexture2D(EntityLivingBase p_72719_1_, int p_72719_2_, double p_72719_3_, - CallbackInfoReturnable cir) { + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false, ordinal = 0, shift = At.Shift.AFTER), expect = 0) + private void angelica$sortandRenderDisableTexture2D(EntityLivingBase p_72719_1_, int p_72719_2_, double p_72719_3_, CallbackInfoReturnable cir) { + // Note: Conflicts with OcclusionRenderer Shaders.disableTexture2D(); } @@ -73,8 +73,9 @@ public class MixinRenderGlobal { @Inject( method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false, ordinal = 0, shift = At.Shift.AFTER)) + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false, ordinal = 0, shift = At.Shift.AFTER), expect = 0) private void angelica$sortAndRenderEnableTexture2D(CallbackInfoReturnable cir) { + // Note: Conflicts with OcclusionRenderer Shaders.enableTexture2D(); } @@ -89,15 +90,17 @@ public class MixinRenderGlobal { // Fog @Inject( method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false, ordinal = 3, shift = At.Shift.AFTER)) + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false, ordinal = 3, shift = At.Shift.AFTER), expect = 0) private void angelica$sortAndRenderDisableFog(CallbackInfoReturnable cir) { + // Note: Conflicts with OcclusionRenderer Shaders.disableFog(); } @Inject( method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false, ordinal = 2, shift = At.Shift.AFTER)) + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false, ordinal = 2, shift = At.Shift.AFTER), expect = 0) private void angelica$sortAndRenderEnableFog(CallbackInfoReturnable cir) { + // Note: Conflicts with OcclusionRenderer Shaders.enableFog(); } diff --git a/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java b/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java index e5f823199..eb771862e 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java +++ b/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java @@ -7,8 +7,8 @@ public class ArchaicConfig { @Config.RequiresMcRestart public static boolean enableOcclusionTweaks; - @Config.Comment("EXPERIMENTAL: Enables multi-threaded chunk updating. At the moment it only works if enableOcclusionTweaks is turned on.") - @Config.DefaultBoolean(true) + @Config.Comment("EXPERIMENTAL: Enables multi-threaded chunk updating. At the moment it only works if enableOcclusionTweaks is turned on. Doesn't currently work with Shaders") + @Config.DefaultBoolean(false) @Config.RequiresMcRestart public static boolean enableThreadedChunkUpdates; @@ -67,10 +67,6 @@ public class ArchaicConfig { @Config.DefaultBoolean(true) public static boolean clearLaunchLoaderCache; - @Config.Comment("Only show GT6 tooltip data when Shift is pressed.") - @Config.DefaultBoolean(true) - public static boolean hideGT6TooltipDataBehindKey; - @Config.Comment("Fix the 'TickNextTick list out of synch' error.") @Config.DefaultBoolean(true) public static boolean fixTickListSynchronization; diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java index c58aee41a..7093f7c83 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java @@ -386,8 +386,7 @@ public int sortAndRender(EntityLivingBase view, int pass, double tick) { rg.theWorld.theProfiler.startSection("sortchunks"); - if (this.mc.gameSettings.renderDistanceChunks != rg.renderDistanceChunks && !(this.mc.currentScreen instanceof GuiVideoSettings)) - { + if (this.mc.gameSettings.renderDistanceChunks != rg.renderDistanceChunks && !(this.mc.currentScreen instanceof GuiVideoSettings)) { rg.loadRenderers(); } @@ -400,7 +399,7 @@ public int sortAndRender(EntityLivingBase view, int pass, double tick) { rg.worldRenderersCheckIndex = (rg.worldRenderersCheckIndex + 1) % rg.renderersLoaded; WorldRenderer rend = sortedWorldRenderers[rg.worldRenderersCheckIndex]; - if ((rend.isInFrustum & rend.isVisible) & (rend.needsUpdate || !rend.isInitialized) & !(this.mc.theWorld.getChunkFromBlockCoords(rend.posX, rend.posZ) instanceof EmptyChunk)) { + if ((rend.isInFrustum && rend.isVisible) && (rend.needsUpdate || !rend.isInitialized) && !(this.mc.theWorld.getChunkFromBlockCoords(rend.posX, rend.posZ) instanceof EmptyChunk)) { addRendererToUpdateQueue(rend); } } From b1a5162aabc81b554bda7a7d80f87daf81b4af34 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 26 Sep 2023 20:26:29 -0700 Subject: [PATCH 006/301] Misc - Add credits Update mcmod.info Update buildscript, use Primitive collections as a dep instead of directly including it Fewer static imports --- README.MD | 24 +- build.gradle | 73 +- dependencies.gradle | 9 + .../gtnewhorizons/angelica/AngelicaMod.java | 1 + .../angelica/client/Shaders.java | 2038 ++++++----------- .../angelica/client/gui/GuiShaders.java | 13 +- .../angelica/loading/AngelicaTweaker.java | 16 + .../angelica/transform/ACTEntityRenderer.java | 10 +- .../world/lighting/LightingHooks.java | 25 +- .../booleans/functions/BooleanComparator.java | 70 - .../booleans/functions/BooleanConsumer.java | 48 - .../booleans/functions/BooleanSupplier.java | 12 - .../consumer/BooleanBooleanConsumer.java | 49 - .../consumer/BooleanByteConsumer.java | 49 - .../consumer/BooleanCharConsumer.java | 49 - .../consumer/BooleanDoubleConsumer.java | 49 - .../consumer/BooleanFloatConsumer.java | 49 - .../consumer/BooleanIntConsumer.java | 49 - .../consumer/BooleanLongConsumer.java | 49 - .../consumer/BooleanObjectConsumer.java | 50 - .../consumer/BooleanShortConsumer.java | 49 - .../function/Boolean2ByteFunction.java | 17 - .../function/Boolean2CharFunction.java | 17 - .../function/Boolean2DoubleFunction.java | 17 - .../function/Boolean2FloatFunction.java | 17 - .../function/Boolean2IntFunction.java | 17 - .../function/Boolean2LongFunction.java | 17 - .../function/Boolean2ShortFunction.java | 17 - .../function/BooleanBooleanUnaryOperator.java | 22 - .../function/BooleanByteUnaryOperator.java | 22 - .../function/BooleanCharUnaryOperator.java | 22 - .../function/BooleanDoubleUnaryOperator.java | 22 - .../function/BooleanFloatUnaryOperator.java | 22 - .../functions/function/BooleanFunction.java | 18 - .../function/BooleanIntUnaryOperator.java | 22 - .../function/BooleanLongUnaryOperator.java | 22 - .../function/BooleanObjectUnaryOperator.java | 23 - .../functions/function/BooleanPredicate.java | 98 - .../function/BooleanShortUnaryOperator.java | 22 - .../bytes/functions/ByteComparator.java | 70 - .../bytes/functions/ByteConsumer.java | 48 - .../bytes/functions/ByteSupplier.java | 12 - .../consumer/ByteBooleanConsumer.java | 49 - .../functions/consumer/ByteByteConsumer.java | 49 - .../functions/consumer/ByteCharConsumer.java | 49 - .../consumer/ByteDoubleConsumer.java | 49 - .../functions/consumer/ByteFloatConsumer.java | 49 - .../functions/consumer/ByteIntConsumer.java | 49 - .../functions/consumer/ByteLongConsumer.java | 49 - .../consumer/ByteObjectConsumer.java | 50 - .../functions/consumer/ByteShortConsumer.java | 49 - .../functions/function/Byte2CharFunction.java | 17 - .../function/Byte2DoubleFunction.java | 17 - .../function/Byte2FloatFunction.java | 17 - .../functions/function/Byte2IntFunction.java | 17 - .../functions/function/Byte2LongFunction.java | 17 - .../function/Byte2ShortFunction.java | 17 - .../function/ByteBooleanUnaryOperator.java | 22 - .../function/ByteByteUnaryOperator.java | 22 - .../function/ByteCharUnaryOperator.java | 22 - .../function/ByteDoubleUnaryOperator.java | 22 - .../function/ByteFloatUnaryOperator.java | 22 - .../functions/function/ByteFunction.java | 18 - .../function/ByteIntUnaryOperator.java | 22 - .../function/ByteLongUnaryOperator.java | 22 - .../function/ByteObjectUnaryOperator.java | 23 - .../functions/function/BytePredicate.java | 62 - .../function/ByteShortUnaryOperator.java | 22 - .../functions/function/ByteUnaryOperator.java | 54 - .../chars/functions/CharComparator.java | 70 - .../chars/functions/CharConsumer.java | 48 - .../chars/functions/CharSupplier.java | 12 - .../consumer/CharBooleanConsumer.java | 49 - .../functions/consumer/CharByteConsumer.java | 49 - .../functions/consumer/CharCharConsumer.java | 49 - .../consumer/CharDoubleConsumer.java | 49 - .../functions/consumer/CharFloatConsumer.java | 49 - .../functions/consumer/CharIntConsumer.java | 49 - .../functions/consumer/CharLongConsumer.java | 49 - .../consumer/CharObjectConsumer.java | 50 - .../functions/consumer/CharShortConsumer.java | 49 - .../functions/function/Char2ByteFunction.java | 17 - .../function/Char2DoubleFunction.java | 17 - .../function/Char2FloatFunction.java | 17 - .../functions/function/Char2IntFunction.java | 17 - .../functions/function/Char2LongFunction.java | 17 - .../function/Char2ShortFunction.java | 17 - .../function/CharBooleanUnaryOperator.java | 22 - .../function/CharByteUnaryOperator.java | 22 - .../function/CharCharUnaryOperator.java | 22 - .../function/CharDoubleUnaryOperator.java | 22 - .../function/CharFloatUnaryOperator.java | 22 - .../functions/function/CharFunction.java | 18 - .../function/CharIntUnaryOperator.java | 22 - .../function/CharLongUnaryOperator.java | 22 - .../function/CharObjectUnaryOperator.java | 23 - .../functions/function/CharPredicate.java | 62 - .../function/CharShortUnaryOperator.java | 22 - .../functions/function/CharUnaryOperator.java | 54 - .../doubles/functions/DoubleComparator.java | 70 - .../doubles/functions/DoubleConsumer.java | 59 - .../doubles/functions/DoubleSupplier.java | 12 - .../consumer/DoubleBooleanConsumer.java | 49 - .../consumer/DoubleByteConsumer.java | 49 - .../consumer/DoubleCharConsumer.java | 49 - .../consumer/DoubleDoubleConsumer.java | 49 - .../consumer/DoubleFloatConsumer.java | 49 - .../functions/consumer/DoubleIntConsumer.java | 49 - .../consumer/DoubleLongConsumer.java | 49 - .../consumer/DoubleObjectConsumer.java | 50 - .../consumer/DoubleShortConsumer.java | 49 - .../function/Double2ByteFunction.java | 17 - .../function/Double2CharFunction.java | 17 - .../function/Double2FloatFunction.java | 17 - .../function/Double2IntFunction.java | 17 - .../function/Double2LongFunction.java | 17 - .../function/Double2ShortFunction.java | 17 - .../function/DoubleBooleanUnaryOperator.java | 22 - .../function/DoubleByteUnaryOperator.java | 22 - .../function/DoubleCharUnaryOperator.java | 22 - .../function/DoubleDoubleUnaryOperator.java | 13 - .../function/DoubleFloatUnaryOperator.java | 22 - .../functions/function/DoubleFunction.java | 18 - .../function/DoubleIntUnaryOperator.java | 22 - .../function/DoubleLongUnaryOperator.java | 22 - .../function/DoubleObjectUnaryOperator.java | 23 - .../functions/function/DoublePredicate.java | 72 - .../function/DoubleShortUnaryOperator.java | 22 - .../function/DoubleUnaryOperator.java | 54 - .../floats/functions/FloatComparator.java | 70 - .../floats/functions/FloatConsumer.java | 48 - .../floats/functions/FloatSupplier.java | 12 - .../consumer/FloatBooleanConsumer.java | 49 - .../functions/consumer/FloatByteConsumer.java | 49 - .../functions/consumer/FloatCharConsumer.java | 49 - .../consumer/FloatDoubleConsumer.java | 49 - .../consumer/FloatFloatConsumer.java | 49 - .../functions/consumer/FloatIntConsumer.java | 49 - .../functions/consumer/FloatLongConsumer.java | 49 - .../consumer/FloatObjectConsumer.java | 50 - .../consumer/FloatShortConsumer.java | 49 - .../function/Float2ByteFunction.java | 17 - .../function/Float2CharFunction.java | 17 - .../function/Float2DoubleFunction.java | 17 - .../functions/function/Float2IntFunction.java | 17 - .../function/Float2LongFunction.java | 17 - .../function/Float2ShortFunction.java | 17 - .../function/FloatBooleanUnaryOperator.java | 22 - .../function/FloatByteUnaryOperator.java | 22 - .../function/FloatCharUnaryOperator.java | 22 - .../function/FloatDoubleUnaryOperator.java | 22 - .../function/FloatFloatUnaryOperator.java | 22 - .../functions/function/FloatFunction.java | 18 - .../function/FloatIntUnaryOperator.java | 22 - .../function/FloatLongUnaryOperator.java | 22 - .../function/FloatObjectUnaryOperator.java | 23 - .../functions/function/FloatPredicate.java | 62 - .../function/FloatShortUnaryOperator.java | 22 - .../function/FloatUnaryOperator.java | 54 - .../collections/AbstractIntCollection.java | 252 -- .../collections/IntBidirectionalIterator.java | 52 - .../ints/collections/IntCollection.java | 279 --- .../ints/collections/IntIterable.java | 314 --- .../ints/collections/IntIterator.java | 88 - .../ints/collections/IntSplititerator.java | 19 - .../ints/collections/IntStack.java | 62 - .../ints/functions/IntComparator.java | 70 - .../ints/functions/IntConsumer.java | 59 - .../ints/functions/IntSupplier.java | 12 - .../consumer/IntBooleanConsumer.java | 49 - .../functions/consumer/IntByteConsumer.java | 49 - .../functions/consumer/IntCharConsumer.java | 49 - .../functions/consumer/IntDoubleConsumer.java | 49 - .../functions/consumer/IntFloatConsumer.java | 49 - .../functions/consumer/IntIntConsumer.java | 49 - .../functions/consumer/IntLongConsumer.java | 49 - .../functions/consumer/IntObjectConsumer.java | 50 - .../functions/consumer/IntShortConsumer.java | 49 - .../functions/function/Int2ByteFunction.java | 17 - .../functions/function/Int2CharFunction.java | 17 - .../function/Int2DoubleFunction.java | 17 - .../functions/function/Int2FloatFunction.java | 17 - .../functions/function/Int2LongFunction.java | 17 - .../functions/function/Int2ShortFunction.java | 17 - .../function/IntBooleanUnaryOperator.java | 22 - .../function/IntByteUnaryOperator.java | 22 - .../function/IntCharUnaryOperator.java | 22 - .../function/IntDoubleUnaryOperator.java | 22 - .../function/IntFloatUnaryOperator.java | 22 - .../ints/functions/function/IntFunction.java | 18 - .../function/IntIntUnaryOperator.java | 13 - .../function/IntLongUnaryOperator.java | 22 - .../function/IntObjectUnaryOperator.java | 23 - .../ints/functions/function/IntPredicate.java | 72 - .../function/IntShortUnaryOperator.java | 22 - .../functions/function/IntUnaryOperator.java | 54 - .../ints/lists/IntListIterator.java | 65 - .../maps/abstracts/AbstractInt2ObjectMap.java | 451 ---- .../maps/impl/misc/Int2ObjectArrayMap.java | 1296 ----------- .../ints/maps/interfaces/Int2ObjectMap.java | 679 ------ .../maps/interfaces/Int2ObjectOrderedMap.java | 115 - .../collections/ints/sets/AbstractIntSet.java | 41 - .../collections/ints/sets/IntOrderedSet.java | 88 - .../src/collections/ints/sets/IntSet.java | 58 - .../src/collections/ints/utils/IIntArray.java | 29 - .../src/collections/ints/utils/IntArrays.java | 1527 ------------ .../ints/utils/IntCollections.java | 892 -------- .../collections/ints/utils/IntIterables.java | 485 ---- .../collections/ints/utils/IntIterators.java | 1003 -------- .../ints/utils/IntSplititerators.java | 461 ---- .../collections/AbstractLongCollection.java | 252 -- .../LongBidirectionalIterator.java | 52 - .../longs/collections/LongCollection.java | 279 --- .../longs/collections/LongIterable.java | 314 --- .../longs/collections/LongIterator.java | 88 - .../longs/collections/LongSplititerator.java | 19 - .../longs/collections/LongStack.java | 62 - .../longs/functions/LongComparator.java | 70 - .../longs/functions/LongConsumer.java | 59 - .../longs/functions/LongSupplier.java | 12 - .../consumer/LongBooleanConsumer.java | 49 - .../functions/consumer/LongByteConsumer.java | 49 - .../functions/consumer/LongCharConsumer.java | 49 - .../consumer/LongDoubleConsumer.java | 49 - .../functions/consumer/LongFloatConsumer.java | 49 - .../functions/consumer/LongIntConsumer.java | 49 - .../functions/consumer/LongLongConsumer.java | 49 - .../consumer/LongObjectConsumer.java | 50 - .../functions/consumer/LongShortConsumer.java | 49 - .../functions/function/Long2ByteFunction.java | 17 - .../functions/function/Long2CharFunction.java | 17 - .../function/Long2DoubleFunction.java | 17 - .../function/Long2FloatFunction.java | 17 - .../functions/function/Long2IntFunction.java | 17 - .../function/Long2ShortFunction.java | 17 - .../function/LongBooleanUnaryOperator.java | 22 - .../function/LongByteUnaryOperator.java | 22 - .../function/LongCharUnaryOperator.java | 22 - .../function/LongDoubleUnaryOperator.java | 22 - .../function/LongFloatUnaryOperator.java | 22 - .../functions/function/LongFunction.java | 18 - .../function/LongIntUnaryOperator.java | 22 - .../function/LongLongUnaryOperator.java | 13 - .../function/LongObjectUnaryOperator.java | 23 - .../functions/function/LongPredicate.java | 72 - .../function/LongShortUnaryOperator.java | 22 - .../functions/function/LongUnaryOperator.java | 54 - .../longs/lists/LongListIterator.java | 65 - .../longs/sets/AbstractLongSet.java | 41 - .../longs/sets/LongOpenHashSet.java | 635 ----- .../src/collections/longs/sets/LongSet.java | 58 - .../collections/longs/utils/LongArrays.java | 1527 ------------ .../longs/utils/LongCollections.java | 892 -------- .../longs/utils/LongIterables.java | 485 ---- .../longs/utils/LongIterators.java | 1003 -------- .../longs/utils/LongSplititerators.java | 461 ---- .../collections/AbstractObjectCollection.java | 167 -- .../ObjectBidirectionalIterator.java | 34 - .../objects/collections/ObjectCollection.java | 181 -- .../objects/collections/ObjectIterable.java | 297 --- .../objects/collections/ObjectIterator.java | 36 - .../collections/ObjectSplititerator.java | 15 - .../objects/functions/ObjectSupplier.java | 13 - .../consumer/ObjectBooleanConsumer.java | 50 - .../consumer/ObjectByteConsumer.java | 50 - .../consumer/ObjectCharConsumer.java | 50 - .../consumer/ObjectDoubleConsumer.java | 50 - .../consumer/ObjectFloatConsumer.java | 50 - .../functions/consumer/ObjectIntConsumer.java | 50 - .../consumer/ObjectLongConsumer.java | 50 - .../consumer/ObjectObjectConsumer.java | 33 - .../consumer/ObjectShortConsumer.java | 50 - .../function/ObjectBooleanUnaryOperator.java | 23 - .../function/ObjectByteUnaryOperator.java | 23 - .../function/ObjectCharUnaryOperator.java | 23 - .../function/ObjectDoubleUnaryOperator.java | 23 - .../function/ObjectFloatUnaryOperator.java | 23 - .../function/ObjectIntUnaryOperator.java | 23 - .../function/ObjectLongUnaryOperator.java | 23 - .../function/ObjectObjectUnaryOperator.java | 13 - .../function/ObjectShortUnaryOperator.java | 23 - .../objects/functions/function/Predicate.java | 75 - .../functions/function/ToByteFunction.java | 18 - .../functions/function/ToCharFunction.java | 18 - .../functions/function/ToDoubleFunction.java | 18 - .../functions/function/ToFloatFunction.java | 18 - .../functions/function/ToIntFunction.java | 18 - .../functions/function/ToLongFunction.java | 18 - .../functions/function/ToShortFunction.java | 18 - .../functions/function/UnaryOperator.java | 59 - .../objects/lists/AbstractObjectList.java | 493 ---- .../objects/lists/ObjectArrayList.java | 888 ------- .../collections/objects/lists/ObjectList.java | 238 -- .../objects/lists/ObjectListIterator.java | 13 - .../abstracts/AbstractObject2ObjectMap.java | 426 ---- .../impl/hash/Object2ObjectOpenHashMap.java | 1258 ---------- .../maps/interfaces/Object2ObjectMap.java | 534 ----- .../objects/sets/AbstractObjectSet.java | 46 - .../objects/sets/ObjectOpenHashSet.java | 609 ----- .../objects/sets/ObjectOrderedSet.java | 89 - .../collections/objects/sets/ObjectSet.java | 37 - .../objects/utils/ObjectArrays.java | 1571 ------------- .../objects/utils/ObjectCollections.java | 802 ------- .../objects/utils/ObjectIterables.java | 496 ---- .../objects/utils/ObjectIterators.java | 1019 --------- .../objects/utils/ObjectSplititerators.java | 242 -- .../shorts/functions/ShortComparator.java | 70 - .../shorts/functions/ShortConsumer.java | 48 - .../shorts/functions/ShortSupplier.java | 12 - .../consumer/ShortBooleanConsumer.java | 49 - .../functions/consumer/ShortByteConsumer.java | 49 - .../functions/consumer/ShortCharConsumer.java | 49 - .../consumer/ShortDoubleConsumer.java | 49 - .../consumer/ShortFloatConsumer.java | 49 - .../functions/consumer/ShortIntConsumer.java | 49 - .../functions/consumer/ShortLongConsumer.java | 49 - .../consumer/ShortObjectConsumer.java | 50 - .../consumer/ShortShortConsumer.java | 49 - .../function/Short2ByteFunction.java | 17 - .../function/Short2CharFunction.java | 17 - .../function/Short2DoubleFunction.java | 17 - .../function/Short2FloatFunction.java | 17 - .../functions/function/Short2IntFunction.java | 17 - .../function/Short2LongFunction.java | 17 - .../function/ShortBooleanUnaryOperator.java | 22 - .../function/ShortByteUnaryOperator.java | 22 - .../function/ShortCharUnaryOperator.java | 22 - .../function/ShortDoubleUnaryOperator.java | 22 - .../function/ShortFloatUnaryOperator.java | 22 - .../functions/function/ShortFunction.java | 18 - .../function/ShortIntUnaryOperator.java | 22 - .../function/ShortLongUnaryOperator.java | 22 - .../function/ShortObjectUnaryOperator.java | 23 - .../functions/function/ShortPredicate.java | 62 - .../function/ShortShortUnaryOperator.java | 22 - .../function/ShortUnaryOperator.java | 54 - .../src/collections/utils/HashUtil.java | 96 - .../speiger/src/collections/utils/IArray.java | 20 - .../src/collections/utils/ISizeProvider.java | 46 - .../src/collections/utils/ITrimmable.java | 37 - .../src/collections/utils/SanityChecks.java | 178 -- .../speiger/src/collections/utils/Stack.java | 62 - .../zone/rong/rongasm/api/RongReflector.java | 4 +- src/main/resources/mcmod.info | 2 +- 344 files changed, 827 insertions(+), 34801 deletions(-) delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/BooleanComparator.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/BooleanConsumer.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/BooleanSupplier.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanBooleanConsumer.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanByteConsumer.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanCharConsumer.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanDoubleConsumer.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanFloatConsumer.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanIntConsumer.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanLongConsumer.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanObjectConsumer.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanShortConsumer.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ByteFunction.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2CharFunction.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2DoubleFunction.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2FloatFunction.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2IntFunction.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2LongFunction.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ShortFunction.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanBooleanUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanByteUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanCharUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanDoubleUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanFloatUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanFunction.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanIntUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanLongUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanObjectUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanPredicate.java delete mode 100644 src/main/java/speiger/src/collections/booleans/functions/function/BooleanShortUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/ByteComparator.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/ByteConsumer.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/ByteSupplier.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteBooleanConsumer.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteByteConsumer.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteCharConsumer.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteDoubleConsumer.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteFloatConsumer.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteIntConsumer.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteLongConsumer.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteObjectConsumer.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/consumer/ByteShortConsumer.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2CharFunction.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2DoubleFunction.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2FloatFunction.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2IntFunction.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2LongFunction.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/Byte2ShortFunction.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteBooleanUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteByteUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteCharUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteDoubleUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteFloatUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteFunction.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteIntUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteLongUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteObjectUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/BytePredicate.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteShortUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/bytes/functions/function/ByteUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/CharComparator.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/CharConsumer.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/CharSupplier.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharBooleanConsumer.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharByteConsumer.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharCharConsumer.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharDoubleConsumer.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharFloatConsumer.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharIntConsumer.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharLongConsumer.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharObjectConsumer.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/consumer/CharShortConsumer.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2ByteFunction.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2DoubleFunction.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2FloatFunction.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2IntFunction.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2LongFunction.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/Char2ShortFunction.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharBooleanUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharByteUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharCharUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharDoubleUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharFloatUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharFunction.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharIntUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharLongUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharObjectUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharPredicate.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharShortUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/chars/functions/function/CharUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/DoubleComparator.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/DoubleConsumer.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/DoubleSupplier.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleBooleanConsumer.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleByteConsumer.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleCharConsumer.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleDoubleConsumer.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleFloatConsumer.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleIntConsumer.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleLongConsumer.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleObjectConsumer.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleShortConsumer.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2ByteFunction.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2CharFunction.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2FloatFunction.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2IntFunction.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2LongFunction.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/Double2ShortFunction.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleBooleanUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleByteUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleCharUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleDoubleUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleFloatUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleFunction.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleIntUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleLongUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleObjectUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoublePredicate.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleShortUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/doubles/functions/function/DoubleUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/FloatComparator.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/FloatConsumer.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/FloatSupplier.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatBooleanConsumer.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatByteConsumer.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatCharConsumer.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatDoubleConsumer.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatFloatConsumer.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatIntConsumer.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatLongConsumer.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatObjectConsumer.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/consumer/FloatShortConsumer.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2ByteFunction.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2CharFunction.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2DoubleFunction.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2IntFunction.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2LongFunction.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/Float2ShortFunction.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatBooleanUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatByteUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatCharUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatDoubleUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatFloatUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatFunction.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatIntUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatLongUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatObjectUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatPredicate.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatShortUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/floats/functions/function/FloatUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/ints/collections/AbstractIntCollection.java delete mode 100644 src/main/java/speiger/src/collections/ints/collections/IntBidirectionalIterator.java delete mode 100644 src/main/java/speiger/src/collections/ints/collections/IntCollection.java delete mode 100644 src/main/java/speiger/src/collections/ints/collections/IntIterable.java delete mode 100644 src/main/java/speiger/src/collections/ints/collections/IntIterator.java delete mode 100644 src/main/java/speiger/src/collections/ints/collections/IntSplititerator.java delete mode 100644 src/main/java/speiger/src/collections/ints/collections/IntStack.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/IntComparator.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/IntConsumer.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/IntSupplier.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntBooleanConsumer.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntByteConsumer.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntCharConsumer.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntDoubleConsumer.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntFloatConsumer.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntIntConsumer.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntLongConsumer.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntObjectConsumer.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/consumer/IntShortConsumer.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2ByteFunction.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2CharFunction.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2DoubleFunction.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2FloatFunction.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2LongFunction.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/Int2ShortFunction.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntBooleanUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntByteUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntCharUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntDoubleUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntFloatUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntFunction.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntIntUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntLongUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntObjectUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntPredicate.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntShortUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/ints/functions/function/IntUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/ints/lists/IntListIterator.java delete mode 100644 src/main/java/speiger/src/collections/ints/maps/abstracts/AbstractInt2ObjectMap.java delete mode 100644 src/main/java/speiger/src/collections/ints/maps/impl/misc/Int2ObjectArrayMap.java delete mode 100644 src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectMap.java delete mode 100644 src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectOrderedMap.java delete mode 100644 src/main/java/speiger/src/collections/ints/sets/AbstractIntSet.java delete mode 100644 src/main/java/speiger/src/collections/ints/sets/IntOrderedSet.java delete mode 100644 src/main/java/speiger/src/collections/ints/sets/IntSet.java delete mode 100644 src/main/java/speiger/src/collections/ints/utils/IIntArray.java delete mode 100644 src/main/java/speiger/src/collections/ints/utils/IntArrays.java delete mode 100644 src/main/java/speiger/src/collections/ints/utils/IntCollections.java delete mode 100644 src/main/java/speiger/src/collections/ints/utils/IntIterables.java delete mode 100644 src/main/java/speiger/src/collections/ints/utils/IntIterators.java delete mode 100644 src/main/java/speiger/src/collections/ints/utils/IntSplititerators.java delete mode 100644 src/main/java/speiger/src/collections/longs/collections/AbstractLongCollection.java delete mode 100644 src/main/java/speiger/src/collections/longs/collections/LongBidirectionalIterator.java delete mode 100644 src/main/java/speiger/src/collections/longs/collections/LongCollection.java delete mode 100644 src/main/java/speiger/src/collections/longs/collections/LongIterable.java delete mode 100644 src/main/java/speiger/src/collections/longs/collections/LongIterator.java delete mode 100644 src/main/java/speiger/src/collections/longs/collections/LongSplititerator.java delete mode 100644 src/main/java/speiger/src/collections/longs/collections/LongStack.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/LongComparator.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/LongConsumer.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/LongSupplier.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongBooleanConsumer.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongByteConsumer.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongCharConsumer.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongDoubleConsumer.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongFloatConsumer.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongIntConsumer.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongLongConsumer.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongObjectConsumer.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/consumer/LongShortConsumer.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2ByteFunction.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2CharFunction.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2DoubleFunction.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2FloatFunction.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2IntFunction.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/Long2ShortFunction.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongBooleanUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongByteUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongCharUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongDoubleUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongFloatUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongFunction.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongIntUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongLongUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongObjectUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongPredicate.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongShortUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/longs/functions/function/LongUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/longs/lists/LongListIterator.java delete mode 100644 src/main/java/speiger/src/collections/longs/sets/AbstractLongSet.java delete mode 100644 src/main/java/speiger/src/collections/longs/sets/LongOpenHashSet.java delete mode 100644 src/main/java/speiger/src/collections/longs/sets/LongSet.java delete mode 100644 src/main/java/speiger/src/collections/longs/utils/LongArrays.java delete mode 100644 src/main/java/speiger/src/collections/longs/utils/LongCollections.java delete mode 100644 src/main/java/speiger/src/collections/longs/utils/LongIterables.java delete mode 100644 src/main/java/speiger/src/collections/longs/utils/LongIterators.java delete mode 100644 src/main/java/speiger/src/collections/longs/utils/LongSplititerators.java delete mode 100644 src/main/java/speiger/src/collections/objects/collections/AbstractObjectCollection.java delete mode 100644 src/main/java/speiger/src/collections/objects/collections/ObjectBidirectionalIterator.java delete mode 100644 src/main/java/speiger/src/collections/objects/collections/ObjectCollection.java delete mode 100644 src/main/java/speiger/src/collections/objects/collections/ObjectIterable.java delete mode 100644 src/main/java/speiger/src/collections/objects/collections/ObjectIterator.java delete mode 100644 src/main/java/speiger/src/collections/objects/collections/ObjectSplititerator.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/ObjectSupplier.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectBooleanConsumer.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectByteConsumer.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectCharConsumer.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectDoubleConsumer.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectFloatConsumer.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectIntConsumer.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectLongConsumer.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectObjectConsumer.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/consumer/ObjectShortConsumer.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectBooleanUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectByteUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectCharUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectDoubleUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectFloatUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectIntUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectLongUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectObjectUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ObjectShortUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/Predicate.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToByteFunction.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToCharFunction.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToDoubleFunction.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToFloatFunction.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToIntFunction.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToLongFunction.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/ToShortFunction.java delete mode 100644 src/main/java/speiger/src/collections/objects/functions/function/UnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/objects/lists/AbstractObjectList.java delete mode 100644 src/main/java/speiger/src/collections/objects/lists/ObjectArrayList.java delete mode 100644 src/main/java/speiger/src/collections/objects/lists/ObjectList.java delete mode 100644 src/main/java/speiger/src/collections/objects/lists/ObjectListIterator.java delete mode 100644 src/main/java/speiger/src/collections/objects/maps/abstracts/AbstractObject2ObjectMap.java delete mode 100644 src/main/java/speiger/src/collections/objects/maps/impl/hash/Object2ObjectOpenHashMap.java delete mode 100644 src/main/java/speiger/src/collections/objects/maps/interfaces/Object2ObjectMap.java delete mode 100644 src/main/java/speiger/src/collections/objects/sets/AbstractObjectSet.java delete mode 100644 src/main/java/speiger/src/collections/objects/sets/ObjectOpenHashSet.java delete mode 100644 src/main/java/speiger/src/collections/objects/sets/ObjectOrderedSet.java delete mode 100644 src/main/java/speiger/src/collections/objects/sets/ObjectSet.java delete mode 100644 src/main/java/speiger/src/collections/objects/utils/ObjectArrays.java delete mode 100644 src/main/java/speiger/src/collections/objects/utils/ObjectCollections.java delete mode 100644 src/main/java/speiger/src/collections/objects/utils/ObjectIterables.java delete mode 100644 src/main/java/speiger/src/collections/objects/utils/ObjectIterators.java delete mode 100644 src/main/java/speiger/src/collections/objects/utils/ObjectSplititerators.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/ShortComparator.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/ShortConsumer.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/ShortSupplier.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortBooleanConsumer.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortByteConsumer.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortCharConsumer.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortDoubleConsumer.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortFloatConsumer.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortIntConsumer.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortLongConsumer.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortObjectConsumer.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/consumer/ShortShortConsumer.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2ByteFunction.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2CharFunction.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2DoubleFunction.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2FloatFunction.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2IntFunction.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/Short2LongFunction.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortBooleanUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortByteUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortCharUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortDoubleUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortFloatUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortFunction.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortIntUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortLongUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortObjectUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortPredicate.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortShortUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/shorts/functions/function/ShortUnaryOperator.java delete mode 100644 src/main/java/speiger/src/collections/utils/HashUtil.java delete mode 100644 src/main/java/speiger/src/collections/utils/IArray.java delete mode 100644 src/main/java/speiger/src/collections/utils/ISizeProvider.java delete mode 100644 src/main/java/speiger/src/collections/utils/ITrimmable.java delete mode 100644 src/main/java/speiger/src/collections/utils/SanityChecks.java delete mode 100644 src/main/java/speiger/src/collections/utils/Stack.java diff --git a/README.MD b/README.MD index f78940a10..284a25f7b 100644 --- a/README.MD +++ b/README.MD @@ -1,19 +1,13 @@ # Angelica -the little angle that supports shaders while saving your fps from a certain death - boubou +The little Angel that supports shaders while saving your fps from a certain death -boubou Not yet in an usable state -Original build instructions obtained via minecraftforums archeology: -``` -Developing environment - - Extract forge src to forge folder. Run "gradlew setupDecompWorkspace setupDevWorkspace" until it succeeded, then "gradlew build", then "gradlew eclipse". - - Delete everything in src\main folder inside forge folder. - - Extract smc-2.3.18-mc1.7.10-src.7z to src\main folder. - - Read patch file shadersmod-mcf.patch - - Find %userprofile%\.gradle\caches\minecraft\net\minecraftforge\forge\*\forgeSrc-*-sources.jar and extract it somewhere. - -- Select files that need to be patched and copy them to src\main with correct folder structure. - - Apply patch shadersmod-mcf.patch - - In eclipse, add java_dev folder as another source folder. - - In eclipse, exclude InitNames in src folder from build path. Use InitNames in java_dev folder instead. - - Find %userprofile%\.gradle\caches\modules-2\files-2.1\net.minecraftforge\forge\*\*\forge-*-userdev.jar and extract conf\*.csv and conf\*.srg in it to forge\conf and rename packaged.srg to joined.srg. -``` +# Credits +* Original ShaderMods: karyonix, sonic ether, id_miner, daxnitro +* Includes graphic enhancements from ArchaicFix by embeddedt - https://github.com/embeddedt/ArchaicFix under the [LGPL and other licenses](https://github.com/embeddedt/ArchaicFix/blob/main/LICENSE.md) +* Includes modified version of Notfine by jss2a98aj - https://github.com/jss2a98aj/NotFine under the LGPL +* Includes backported code from [Occulus](https://github.com/Asek3/Oculus) and [Iris](https://github.com/IrisShaders/Iris) under the LGPL +* eigenraven and vlaetansky for getting the original ShaderMod compiling again +* eigenraven, Caedis, glowredman, and mitchej123 for the conversion of ASM to Mixin + diff --git a/build.gradle b/build.gradle index b894d6477..6a54d13b0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -//version: 1692122114 +//version: 1695474595 /* DO NOT CHANGE THIS FILE! Also, you may replace this file at any time if there is an update available. @@ -89,6 +89,23 @@ def out = services.get(StyledTextOutputFactory).create('an-output') def projectJavaVersion = JavaLanguageVersion.of(8) boolean disableSpotless = project.hasProperty("disableSpotless") ? project.disableSpotless.toBoolean() : false +boolean disableCheckstyle = project.hasProperty("disableCheckstyle") ? project.disableCheckstyle.toBoolean() : false + +final String CHECKSTYLE_CONFIG = """ + + + + + + + + + + + +""" checkPropertyExists("modName") checkPropertyExists("modId") @@ -140,6 +157,17 @@ if (!disableSpotless) { apply from: Blowdryer.file('spotless.gradle') } +if (!disableCheckstyle) { + apply plugin: 'checkstyle' + tasks.named("checkstylePatchedMc") { enabled = false } + tasks.named("checkstyleMcLauncher") { enabled = false } + tasks.named("checkstyleIdeVirtualMain") { enabled = false } + tasks.named("checkstyleInjectedTags") { enabled = false } + checkstyle { + config = resources.text.fromString(CHECKSTYLE_CONFIG) + } +} + String javaSourceDir = "src/main/java/" String scalaSourceDir = "src/main/scala/" String kotlinSourceDir = "src/main/kotlin/" @@ -600,15 +628,10 @@ repositories { } maven { name = "ic2" - url = "https://maven.ic2.player.to/" - metadataSources { - mavenPom() - artifact() + url = getURL("https://maven.ic2.player.to/", "https://maven2.ic2.player.to/") + content { + includeGroup "net.industrial-craft" } - } - maven { - name = "ic2-mirror" - url = "https://maven2.ic2.player.to/" metadataSources { mavenPom() artifact() @@ -770,23 +793,14 @@ ext.java17PatchDependenciesCfg = configurations.create("java17PatchDependencies" } dependencies { - def lwjgl3ifyVersion = '1.4.0' - def asmVersion = '9.4' + def lwjgl3ifyVersion = '1.5.0' if (modId != 'lwjgl3ify') { java17Dependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}") } if (modId != 'hodgepodge') { - java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.2.26') + java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.3.5') } - java17PatchDependencies('net.minecraft:launchwrapper:1.17.2') {transitive = false} - java17PatchDependencies("org.ow2.asm:asm:${asmVersion}") - java17PatchDependencies("org.ow2.asm:asm-commons:${asmVersion}") - java17PatchDependencies("org.ow2.asm:asm-tree:${asmVersion}") - java17PatchDependencies("org.ow2.asm:asm-analysis:${asmVersion}") - java17PatchDependencies("org.ow2.asm:asm-util:${asmVersion}") - java17PatchDependencies('org.ow2.asm:asm-deprecated:7.1') - java17PatchDependencies("org.apache.commons:commons-lang3:3.12.0") java17PatchDependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}:forgePatches") {transitive = false} } @@ -1576,6 +1590,25 @@ def getSecondaryArtifacts() { return secondaryArtifacts } +def getURL(String main, String fallback) { + return pingURL(main, 10000) ? main : fallback +} + +// credit: https://stackoverflow.com/a/3584332 +def pingURL(String url, int timeout) { + url = url.replaceFirst("^https", "http") // Otherwise an exception may be thrown on invalid SSL certificates. + try { + HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection() + connection.setConnectTimeout(timeout) + connection.setReadTimeout(timeout) + connection.setRequestMethod("HEAD") + int responseCode = connection.getResponseCode() + return 200 <= responseCode && responseCode <= 399 + } catch (IOException ignored) { + return false + } +} + // For easier scripting of things that require variables defined earlier in the buildscript if (file('addon.late.gradle.kts').exists()) { apply from: 'addon.late.gradle.kts' diff --git a/dependencies.gradle b/dependencies.gradle index 9e70962d1..032618a66 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -38,6 +38,14 @@ dependencies { compileOnly(sourceSets.compileStubs.output) compileStubs(sourceSets.compileStubsStubs.output) + // Iris Shaders + implementation('org.jetbrains:annotations:24.0.1') + implementation("it.unimi.dsi:fastutil:8.2.1") + implementation("org.joml:joml:1.10.5") + implementation("org.anarres:jcpp:1.4.14") + compileOnly "org.apache.ant:ant:1.8.2" + + compileOnly("com.github.GTNewHorizons:ProjectRed:4.7.12-GTNH:dev") compileOnly(files("dependencies/SmartRender-1.7.10-2.1-dev.jar")) @@ -52,6 +60,7 @@ dependencies { // ArchaicFix Deps + implementation("com.github.Speiger:Primitive-Collections:0.9.0") compileOnly("curse.maven:chickenchunks-229316:2233250") compileOnly "thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev" compileOnly('curse.maven:cofh-core-69162:2388751') diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index dc345d6f4..dad800ef2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -15,6 +15,7 @@ acceptedMinecraftVersions = "[1.7.10]", acceptableRemoteVersions = "*") public class AngelicaMod { + @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { if (event.getSide() == Side.CLIENT) { diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index 51d24d951..245ee9f1a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -3,6 +3,75 @@ package com.gtnewhorizons.angelica.client; +import com.gtnewhorizons.angelica.Tags; +import com.gtnewhorizons.angelica.client.shaders.config.ShadersConfig; +import com.gtnewhorizons.angelica.client.shaders.gl.shader.StandardMacros; +import com.gtnewhorizons.angelica.client.shaders.shaderpack.ShaderPack; +import com.gtnewhorizons.angelica.client.shaders.shaderpack.option.values.MutableOptionValues; +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import com.gtnewhorizons.angelica.mixins.interfaces.IModelRenderer; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.entity.RendererLivingEntity; +import net.minecraft.client.renderer.texture.ITextureObject; +import net.minecraft.client.settings.GameSettings; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.Vec3; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.ContextCapabilities; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL14; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GLContext; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import java.util.zip.ZipException; + import static org.lwjgl.opengl.ARBFragmentShader.GL_FRAGMENT_SHADER_ARB; import static org.lwjgl.opengl.ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB; import static org.lwjgl.opengl.ARBShaderObjects.glAttachObjectARB; @@ -38,159 +107,9 @@ import static org.lwjgl.opengl.EXTFramebufferObject.glDeleteFramebuffersEXT; import static org.lwjgl.opengl.EXTFramebufferObject.glFramebufferTexture2DEXT; import static org.lwjgl.opengl.EXTFramebufferObject.glGenFramebuffersEXT; -import static org.lwjgl.opengl.GL11.GL_ALPHA_TEST; -import static org.lwjgl.opengl.GL11.GL_ALWAYS; -import static org.lwjgl.opengl.GL11.GL_BLEND; -import static org.lwjgl.opengl.GL11.GL_CLAMP; -import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; -import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; -import static org.lwjgl.opengl.GL11.GL_DEPTH_COMPONENT; -import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST; -import static org.lwjgl.opengl.GL11.GL_FOG; -import static org.lwjgl.opengl.GL11.GL_LEQUAL; -import static org.lwjgl.opengl.GL11.GL_LINEAR; -import static org.lwjgl.opengl.GL11.GL_LINEAR_MIPMAP_LINEAR; -import static org.lwjgl.opengl.GL11.GL_LUMINANCE; -import static org.lwjgl.opengl.GL11.GL_MODELVIEW; -import static org.lwjgl.opengl.GL11.GL_MODELVIEW_MATRIX; -import static org.lwjgl.opengl.GL11.GL_NEAREST; -import static org.lwjgl.opengl.GL11.GL_NEAREST_MIPMAP_NEAREST; -import static org.lwjgl.opengl.GL11.GL_NONE; -import static org.lwjgl.opengl.GL11.GL_NO_ERROR; -import static org.lwjgl.opengl.GL11.GL_PROJECTION; -import static org.lwjgl.opengl.GL11.GL_PROJECTION_MATRIX; -import static org.lwjgl.opengl.GL11.GL_QUADS; -import static org.lwjgl.opengl.GL11.GL_RGB16; -import static org.lwjgl.opengl.GL11.GL_RGB8; -import static org.lwjgl.opengl.GL11.GL_RGBA; -import static org.lwjgl.opengl.GL11.GL_RGBA16; -import static org.lwjgl.opengl.GL11.GL_RGBA8; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T; -import static org.lwjgl.opengl.GL11.GL_TRUE; -import static org.lwjgl.opengl.GL11.glBegin; -import static org.lwjgl.opengl.GL11.glBindTexture; -import static org.lwjgl.opengl.GL11.glClear; -import static org.lwjgl.opengl.GL11.glClearColor; -import static org.lwjgl.opengl.GL11.glColor4f; -import static org.lwjgl.opengl.GL11.glColorMask; -import static org.lwjgl.opengl.GL11.glCopyTexSubImage2D; -import static org.lwjgl.opengl.GL11.glDeleteTextures; -import static org.lwjgl.opengl.GL11.glDepthFunc; -import static org.lwjgl.opengl.GL11.glDepthMask; -import static org.lwjgl.opengl.GL11.glDisable; -import static org.lwjgl.opengl.GL11.glEnable; -import static org.lwjgl.opengl.GL11.glEnd; -import static org.lwjgl.opengl.GL11.glFlush; -import static org.lwjgl.opengl.GL11.glGenTextures; -import static org.lwjgl.opengl.GL11.glGetError; -import static org.lwjgl.opengl.GL11.glGetFloat; -import static org.lwjgl.opengl.GL11.glGetInteger; -import static org.lwjgl.opengl.GL11.glLoadIdentity; -import static org.lwjgl.opengl.GL11.glMatrixMode; -import static org.lwjgl.opengl.GL11.glOrtho; -import static org.lwjgl.opengl.GL11.glPopMatrix; -import static org.lwjgl.opengl.GL11.glPushMatrix; -import static org.lwjgl.opengl.GL11.glReadBuffer; -import static org.lwjgl.opengl.GL11.glReadPixels; -import static org.lwjgl.opengl.GL11.glRotatef; -import static org.lwjgl.opengl.GL11.glTexCoord2f; -import static org.lwjgl.opengl.GL11.glTexImage2D; -import static org.lwjgl.opengl.GL11.glTexParameterf; -import static org.lwjgl.opengl.GL11.glTexParameteri; -import static org.lwjgl.opengl.GL11.glTranslatef; -import static org.lwjgl.opengl.GL11.glVertex3f; -import static org.lwjgl.opengl.GL11.glViewport; -import static org.lwjgl.opengl.GL13.GL_TEXTURE0; -import static org.lwjgl.opengl.GL13.GL_TEXTURE1; -import static org.lwjgl.opengl.GL13.GL_TEXTURE11; -import static org.lwjgl.opengl.GL13.GL_TEXTURE12; -import static org.lwjgl.opengl.GL13.GL_TEXTURE13; -import static org.lwjgl.opengl.GL13.GL_TEXTURE14; -import static org.lwjgl.opengl.GL13.GL_TEXTURE2; -import static org.lwjgl.opengl.GL13.GL_TEXTURE3; -import static org.lwjgl.opengl.GL13.GL_TEXTURE4; -import static org.lwjgl.opengl.GL13.GL_TEXTURE5; -import static org.lwjgl.opengl.GL13.GL_TEXTURE6; -import static org.lwjgl.opengl.GL13.GL_TEXTURE7; -import static org.lwjgl.opengl.GL13.glActiveTexture; -import static org.lwjgl.opengl.GL14.GL_DEPTH_TEXTURE_MODE; -import static org.lwjgl.opengl.GL14.GL_TEXTURE_COMPARE_MODE; -import static org.lwjgl.opengl.GL20.GL_MAX_DRAW_BUFFERS; -import static org.lwjgl.opengl.GL20.GL_MAX_TEXTURE_IMAGE_UNITS; -import static org.lwjgl.opengl.GL20.GL_VALIDATE_STATUS; -import static org.lwjgl.opengl.GL20.glDrawBuffers; -import static org.lwjgl.opengl.GL20.glGetProgrami; -import static org.lwjgl.opengl.GL30.GL_COMPARE_REF_TO_TEXTURE; -import static org.lwjgl.opengl.GL30.GL_R16; -import static org.lwjgl.opengl.GL30.GL_R32F; -import static org.lwjgl.opengl.GL30.GL_R8; -import static org.lwjgl.opengl.GL30.GL_RG16; -import static org.lwjgl.opengl.GL30.GL_RG32F; -import static org.lwjgl.opengl.GL30.GL_RG8; -import static org.lwjgl.opengl.GL30.GL_RGB32F; -import static org.lwjgl.opengl.GL30.GL_RGBA32F; -import static org.lwjgl.opengl.GL30.glGenerateMipmap; import static org.lwjgl.util.glu.GLU.gluErrorString; import static org.lwjgl.util.glu.GLU.gluPerspective; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import net.minecraft.block.Block; -import net.minecraft.block.material.Material; -import net.minecraft.client.Minecraft; -import net.minecraft.client.model.ModelBase; -import net.minecraft.client.model.ModelRenderer; -import net.minecraft.client.renderer.EntityRenderer; -import net.minecraft.client.renderer.RenderBlocks; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.entity.Render; -import net.minecraft.client.renderer.entity.RenderManager; -import net.minecraft.client.renderer.entity.RendererLivingEntity; -import net.minecraft.client.renderer.texture.ITextureObject; -import net.minecraft.client.settings.GameSettings; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ChatComponentText; -import net.minecraft.util.Vec3; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.ContextCapabilities; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL12; -import org.lwjgl.opengl.GLContext; - -import com.gtnewhorizons.angelica.Tags; -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; -import com.gtnewhorizons.angelica.mixins.interfaces.IModelRenderer; - -// import org.lwjgl.opengl.ARBVertexProgram; - public class Shaders { public static final String versionString = Tags.VERSION; @@ -329,7 +248,7 @@ public class Shaders { private static int dfb = 0; private static int sfb = 0; - private static int[] gbuffersFormat = new int[MaxColorBuffers]; + private static final int[] gbuffersFormat = new int[MaxColorBuffers]; // Program stuff @@ -389,20 +308,20 @@ public class Shaders { ProgramNone, // shadow }; - private static int[] programsID = new int[ProgramCount]; - private static int[] programsRef = new int[ProgramCount]; + private static final int[] programsID = new int[ProgramCount]; + private static final int[] programsRef = new int[ProgramCount]; private static int programIDCopyDepth = 0; - private static String[] programsDrawBufSettings = new String[ProgramCount]; + private static final String[] programsDrawBufSettings = new String[ProgramCount]; private static String newDrawBufSetting = null; - private static IntBuffer[] programsDrawBuffers = new IntBuffer[ProgramCount]; + private static final IntBuffer[] programsDrawBuffers = new IntBuffer[ProgramCount]; static IntBuffer activeDrawBuffers = null; - private static String[] programsColorAtmSettings = new String[ProgramCount]; + private static final String[] programsColorAtmSettings = new String[ProgramCount]; private static String newColorAtmSetting = null; private static String activeColorAtmSettings = null; - private static int[] programsCompositeMipmapSetting = new int[ProgramCount]; + private static final int[] programsCompositeMipmapSetting = new int[ProgramCount]; private static int newCompositeMipmapSetting = 0; private static int activeCompositeMipmapSetting = 0; @@ -479,12 +398,7 @@ public class Shaders { private static int noiseTextureResolution = 256; // direct buffers - private static final int bigBufferSize = (16 * 12 + MaxColorBuffers - + MaxDepthBuffers - + MaxShadowColorBuffers - + MaxShadowDepthBuffers - + MaxDrawBuffers * 8 - + MaxDrawBuffers * ProgramCount) * 4; + private static final int bigBufferSize = (16 * 12 + MaxColorBuffers + MaxDepthBuffers + MaxShadowColorBuffers + MaxShadowDepthBuffers + MaxDrawBuffers * 8 + MaxDrawBuffers * ProgramCount) * 4; private static final ByteBuffer bigBuffer = (ByteBuffer) BufferUtils.createByteBuffer(bigBufferSize).limit(0); private static final FloatBuffer previousProjection = nextFloatBuffer(16); @@ -551,59 +465,9 @@ private static IntBuffer[] nextIntBufferArray(int count, int size) { return aib; } - /* - * static void checkForUpdate() { if (!shadersdir.exists()) shadersdir.mkdir(); lastversion = version; int lastcheck - * = 0; File updatecheck = new File(shadersdir,"updatecheck.cfg"); try { if (updatecheck.exists()) { BufferedReader - * bufferedreader2 = new BufferedReader(new FileReader(updatecheck)); for (String s = ""; (s = - * bufferedreader2.readLine()) != null;) { try { String as[] = s.split(":"); int vv; if - * (as[0].equals("updateinterval")) { vv = Integer.parseInt(as[1]); if (vv < 0 || ( vv > 0 && vv < 24 ) || vv > 736) - * { System.out.println("[Shaders] Skipping bad option: updateinterval, range is: 0, 24-736"); } else { - * updateinterval = vv; } } else if (as[0].equals("lastcheck")) { lastcheck = Integer.parseInt(as[1]); } else if - * (as[0].equals("lastversion")) { lastversion = Integer.parseInt(as[1]); } } catch (Exception exception1) { - * System.out.println("[Shaders] "+(new StringBuilder()).append("Skipping bad option: ").append(s).toString()); } } - * bufferedreader2.close(); } } catch(Exception ex){} if (updateinterval > 0) { try { if (lastversion > version) { - * updatenotify(versiontostring(lastversion)); - * System.out.println("[Shaders] New version "+versiontostring(lastversion) - * +" of the GLSL Shaders OF mod is available, go to "+ siteurl +" to download."); } else { int currenthours = (int) - * (System.currentTimeMillis() / 3600000); if (currenthours - lastcheck > updateinterval ) { - * System.out.println("[Shaders] Checking for updates. Last checked "+Integer.toString(currenthours - - * lastcheck)+" hours ago."); lastcheck = currenthours; try { URL url = new URL( updatecheckurl ); - * HttpURLConnection.setFollowRedirects(true); HttpURLConnection uconn; uconn = (HttpURLConnection) - * url.openConnection(); uconn.setConnectTimeout(2500); uconn.setReadTimeout(1500); try { uconn.connect(); } catch - * (SocketTimeoutException excep) { System.out.println("[Shaders] Failed to connect to " + updatecheckurl); return; - * } BufferedReader bufferedreader2 = new BufferedReader(new InputStreamReader( uconn.getInputStream())); for - * (String s = ""; (s = bufferedreader2.readLine()) != null;) { try { String as[] = s.split(":"); if - * (as[1].equals("lastversion")) { lastversion = Integer.parseInt(as[2]); break; } } catch (Exception exception1){} - * } bufferedreader2.close(); } catch (Exception exception) { System.out.println("[Shaders] Failed to download " + - * updatecheckurl); return; } BufferedWriter bufferedwriter2 = new BufferedWriter(new FileWriter(updatecheck)); - * bufferedwriter2.write("updateinterval:"+updateinterval); bufferedwriter2.newLine(); - * bufferedwriter2.write("lastcheck:"+Integer.toString(lastcheck)); bufferedwriter2.newLine(); - * bufferedwriter2.write("lastversion:"+Integer.toString(lastversion)); bufferedwriter2.newLine(); - * bufferedwriter2.close(); if (lastversion > version) { updatenotify(versiontostring(lastversion)); - * System.out.println("[Shaders] New version "+versiontostring(lastversion) - * +" of the GLSL Shaders OF mod is available, go to "+ siteurl +" to download."); } } } } catch (Exception - * exception) { System.out.println("[Shaders] Failed to load GLSL Shaders update file."); - * exception.printStackTrace(); } } } public static void updatenotify(String lastversion) { try { frame = new - * JFrame("GLSL Shaders OF mod update"); } catch(Exception e) { return; } Color bgcolor=new Color(194,205,234); - * Color txcolor=new Color(50,50,50); frame.setLocation(20,20); JLabel label=new - * JLabel("New version of the GLSL Shaders OF mod is available! (v"+lastversion+") "); JPanel panel = new JPanel(); - * panel.setBackground(bgcolor); label.setForeground(txcolor); label.setFont(new Font("Dialog", 1, 14)); - * panel.add(label); if( java.awt.Desktop.isDesktopSupported() ) { JButton button; final java.awt.Desktop desktop = - * java.awt.Desktop.getDesktop(); if( desktop.isSupported( java.awt.Desktop.Action.BROWSE ) ) { button = new - * JButton("Download"); button.setActionCommand("BPUPD"); } else { button = new JButton("Copy URL to Clipboard"); - * button.setActionCommand("CPURL"); } button.setFont(new Font("Dialog", 1, 14)); button.addActionListener(new - * ButtonListener()); panel.add(button); } frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - * frame.getContentPane().add(panel); frame.pack(); frame.setFocusableWindowState(false); frame.setVisible(true); - * frame.setFocusableWindowState(true); } static class ButtonListener implements ActionListener { ButtonListener() { - * } public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); if (cmd == "BPUPD") { try { - * java.net.URI uri = new java.net.URI( siteurl ); java.awt.Desktop.getDesktop().browse( uri ); frame.dispose(); } - * catch ( Exception exx ) {} } else if (cmd == "CPURL") { StringSelection ss = new StringSelection(siteurl); - * Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, null); } } } - */ - public static void loadConfig() { AngelicaTweaker.LOGGER.info("[Shaders] Loading configuration."); - try { + try { if (!shaderpacksdir.exists()) shaderpacksdir.mkdir(); } catch (Exception e) { AngelicaTweaker.LOGGER.warn("[Shaders] Failed openning shaderpacks directory."); @@ -616,18 +480,17 @@ public static void loadConfig() { FileReader reader = new FileReader(configFile); shadersConfig.load(reader); reader.close(); - } catch (Exception e) {} + } catch (Exception ignored) {} } if (!configFile.exists()) { try { storeConfig(); - } catch (Exception e) {} + } catch (Exception ignored) {} } configNormalMap = Boolean.parseBoolean(shadersConfig.getProperty("normalMapEnabled", "true")); configSpecularMap = Boolean.parseBoolean(shadersConfig.getProperty("specularMapEnabled", "true")); - configTweakBlockDamage = Boolean.parseBoolean( - shadersConfig.getProperty("tweakBlockDamage", shadersConfig.getProperty("dtweak", "false"))); + configTweakBlockDamage = Boolean.parseBoolean(shadersConfig.getProperty("tweakBlockDamage", shadersConfig.getProperty("dtweak", "false"))); configCloudShadow = Boolean.parseBoolean(shadersConfig.getProperty("cloudShadow", "true")); configHandDepthMul = Float.parseFloat(shadersConfig.getProperty("handDepthMul", "0.125")); configRenderResMul = Float.parseFloat(shadersConfig.getProperty("renderResMul", "1.0")); @@ -635,10 +498,8 @@ public static void loadConfig() { configShadowClipFrustrum = Boolean.parseBoolean(shadersConfig.getProperty("shadowClipFrustrum", "true")); configOldLighting = Boolean.parseBoolean(shadersConfig.getProperty("oldLighting", "false")); configTexMinFilB = Integer.parseInt(shadersConfig.getProperty("TexMinFilB", "0")) % texMinFilRange; - configTexMinFilN = Integer.parseInt(shadersConfig.getProperty("TexMinFilN", Integer.toString(configTexMinFilB))) - % texMinFilRange; - configTexMinFilS = Integer.parseInt(shadersConfig.getProperty("TexMinFilS", Integer.toString(configTexMinFilB))) - % texMinFilRange; + configTexMinFilN = Integer.parseInt(shadersConfig.getProperty("TexMinFilN", Integer.toString(configTexMinFilB))) % texMinFilRange; + configTexMinFilS = Integer.parseInt(shadersConfig.getProperty("TexMinFilS", Integer.toString(configTexMinFilB))) % texMinFilRange; configTexMagFilB = Integer.parseInt(shadersConfig.getProperty("TexMagFilB", "0")) % texMagFilRange; configTexMagFilN = Integer.parseInt(shadersConfig.getProperty("TexMagFilN", "0")) % texMagFilRange; configTexMagFilS = Integer.parseInt(shadersConfig.getProperty("TexMagFilS", "0")) % texMagFilRange; @@ -667,7 +528,7 @@ public static void storeConfig() { FileWriter writer = new FileWriter(configFile); shadersConfig.store(writer, null); writer.close(); - } catch (Exception ex) {} + } catch (Exception ignored) {} } public static void setShaderPack(String par1name) { @@ -704,125 +565,6 @@ public static void loadShaderPack() { } } - // public static void loadShader0() - // { - // Set shaderfiles = new HashSet(); - // for (int si = 1; si < 10; si++) - // { - // shaderfiles.add(programNames[si]+".fsh"); - // shaderfiles.add(programNames[si]+".vsh"); - // } - // - // try - // { - // - // ZipInputStream inp = new ZipInputStream(new FileInputStream(currentshader)); - // System.out.println("[Shaders] Shader selected: " + currentshadername); - // boolean found = false; - // - // ZipEntry entry = inp.getNextEntry(); - // while(entry != null ) - // { - // if (entry.isDirectory()) - // { - // if (entry.getName().toLowerCase().contains("shaders/contents/files/shaders/")) - // { - // found = true; - // break; - // } - // } - // entry = inp.getNextEntry(); - // } - // - // if (!found) - // { - // inp.close(); - // inp = new ZipInputStream(new FileInputStream(currentshader)); - // entry = inp.getNextEntry(); - // while(entry != null ) - // { - // if (entry.isDirectory()) - // { - // if (entry.getName().toLowerCase().contains("shaders/")) - // { - // found = true; - // break; - // } - // } - // entry = inp.getNextEntry(); - // } - // } - // - // if (!found) - // { - // inp.close(); - // inp = new ZipInputStream(new FileInputStream(currentshader)); - // entry = inp.getNextEntry(); - // } - // - // byte[] buf = new byte[1024]; - // int n; - // String zipfile; - // String zippath = ""; - // String zippathfile; - // - // FileOutputStream fileoutputstream, fileoutputstream2; - // boolean seusrc5tweak = false; - // - // while(entry != null && shaderfiles.size() > 0) - // { - // zipfile = new File(entry.getName()).getName(); - // if (shaderfiles.contains(zipfile) && !entry.isDirectory()) - // { - // zippathfile = new File(entry.getName()).getPath(); - // if (shaderfiles.size() == 18) - // { - // zippath = zippathfile.substring(0,zippathfile.length()-zipfile.length()); - // } - // if (zippathfile.equals(zippath+zipfile)) - // { - // shaderfiles.remove(zipfile); - // if (zipfile.equals("gbuffers_water.vsh") && entry.getCrc() == 2530345120L ) seusrc5tweak = true; - // - // fileoutputstream = new FileOutputStream(shadersdir + File.separator + "temp" + File.separator + zipfile); - // while ((n = inp.read(buf, 0, 1024)) > -1) fileoutputstream.write(buf, 0, n); - // fileoutputstream.close(); - // System.out.println("[Shaders] Shader loaded: " + zippathfile); - // } - // } - // entry = inp.getNextEntry(); - // } - // inp.close(); - // - // if (seusrc5tweak) - // { - // new File(shadersdir + File.separator + "temp" + File.separator + "gbuffers_water.fsh").delete(); - // new File(shadersdir + File.separator + "temp" + File.separator + "gbuffers_water.vsh").delete(); - // FileInputStream file = new FileInputStream(shadersdir + File.separator + "temp" + File.separator + - // "gbuffers_textured_lit.fsh"); - // FileOutputStream file2 = new FileOutputStream(shadersdir + File.separator + "temp" + File.separator + - // "gbuffers_water.fsh",false); - // while ((n = file.read(buf, 0, 1024)) > -1) file2.write(buf, 0, n); - // file.close(); - // file2.close(); - // file = new FileInputStream(shadersdir + File.separator + "temp" + File.separator + - // "gbuffers_textured_lit.vsh"); - // file2 = new FileOutputStream(shadersdir + File.separator + "temp" + File.separator + - // "gbuffers_water.vsh",false); - // while ((n = file.read(buf, 0, 1024)) > -1) file2.write(buf, 0, n); - // file.close(); - // file2.close(); - // System.out.println("[Shaders] Detected SEUS v10 RC5, copied gbuffers_textured_lit. to gbuffers_water."); - // } - // } - // catch (Exception exc) - // {} - // - // isInitialized = false; - // if (shaderfiles.size() == 18 ) System.out.println("[Shaders] No Shader found in: " + currentshadername); - // else System.out.println("[Shaders] Shader loaded: " + currentshadername); - // } - public static List listofShaders() { List list = new ArrayList<>(); list.add(packNameNone); @@ -837,7 +579,7 @@ public static List listofShaders() { list.add(name); } } - } catch (Exception e) {} + } catch (Exception ignored) {} return list; } @@ -858,29 +600,15 @@ public static int checkFramebufferStatus(String location) { } public static int checkGLError(String location) { - int errorCode = glGetError(); - if (errorCode != GL_NO_ERROR) { + int errorCode = GL11.glGetError(); + if (errorCode != GL11.GL_NO_ERROR) { boolean skipPrint = false; - // if (location.equals("updatechunks")) { - // if (updateChunksErrorRecorded) { - // skipPrint = true; - // } else { - // updateChunksErrorRecorded = true; - // } - // } if (!skipPrint) { if (errorCode == GL_INVALID_FRAMEBUFFER_OPERATION_EXT) { int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - AngelicaTweaker.LOGGER.error( - String.format( - "GL error 0x%04X: %s (Fb status 0x%04X) at %s", - errorCode, - gluErrorString(errorCode), - status, - location)); + AngelicaTweaker.LOGGER.error(String.format("GL error 0x%04X: %s (Fb status 0x%04X) at %s", errorCode, gluErrorString(errorCode), status, location)); } else { - AngelicaTweaker.LOGGER.error( - String.format("GL error 0x%04X: %s at %s", errorCode, gluErrorString(errorCode), location)); + AngelicaTweaker.LOGGER.error(String.format("GL error 0x%04X: %s at %s", errorCode, gluErrorString(errorCode), location)); } } } @@ -888,30 +616,17 @@ public static int checkGLError(String location) { } public static int checkGLError(String location, String info) { - int errorCode = glGetError(); - if (errorCode != GL_NO_ERROR) { - AngelicaTweaker.LOGGER.error( - String.format( - "GL error 0x%04x: %s at %s %s", - errorCode, - gluErrorString(errorCode), - location, - info)); + int errorCode = GL11.glGetError(); + if (errorCode != GL11.GL_NO_ERROR) { + AngelicaTweaker.LOGGER.error(String.format("GL error 0x%04x: %s at %s %s", errorCode, gluErrorString(errorCode), location, info)); } return errorCode; } public static int checkGLError(String location, String info1, String info2) { - int errorCode = glGetError(); - if (errorCode != GL_NO_ERROR) { - AngelicaTweaker.LOGGER.error( - String.format( - "GL error 0x%04x: %s at %s %s %s", - errorCode, - gluErrorString(errorCode), - location, - info1, - info2)); + int errorCode = GL11.glGetError(); + if (errorCode != GL11.GL_NO_ERROR) { + AngelicaTweaker.LOGGER.error(String.format("GL error 0x%04x: %s at %s %s %s", errorCode, gluErrorString(errorCode), location, info1, info2)); } return errorCode; } @@ -954,235 +669,220 @@ public static void updateBlockLightLevel() { } public static void init() { - if (!isInitialized) { - mc = Minecraft.getMinecraft(); - checkGLError("Shaders.init pre"); - capabilities = GLContext.getCapabilities(); - AngelicaTweaker.LOGGER.debug( - "[Shaders] OpenGL 2.0 = " + toStringYN(capabilities.OpenGL20) - + " 2.1 = " - + toStringYN(capabilities.OpenGL21) - + " 3.0 = " - + toStringYN(capabilities.OpenGL30) - + " 3.2 = " - + toStringYN(capabilities.OpenGL32)); - if (!capabilities.OpenGL21) { - printChatAndLogError("[Shaders] No OpenGL 2.1."); - } - if (!capabilities.GL_EXT_framebuffer_object) { - printChatAndLogError("[Shaders] No EXT_framebuffer_object."); - } - if (!capabilities.OpenGL20 || !capabilities.GL_EXT_framebuffer_object) { - printChatAndLogError("[Shaders] Your GPU is not compatible with the Shaders mod."); - } - - hasGlGenMipmap = capabilities.OpenGL30; - dfbDrawBuffers.position(0).limit(MaxDrawBuffers); - dfbColorTextures.position(0).limit(MaxColorBuffers); - dfbDepthTextures.position(0).limit(MaxDepthBuffers); - sfbDrawBuffers.position(0).limit(MaxDrawBuffers); - sfbDepthTextures.position(0).limit(MaxShadowDepthBuffers); - sfbColorTextures.position(0).limit(MaxShadowColorBuffers); - - int maxDrawBuffers = glGetInteger(GL_MAX_DRAW_BUFFERS); - int maxColorAttach = glGetInteger(GL_MAX_COLOR_ATTACHMENTS_EXT); - AngelicaTweaker.LOGGER.debug("[Shaders] GL_MAX_DRAW_BUFFERS = " + maxDrawBuffers); - AngelicaTweaker.LOGGER.debug("[Shaders] GL_MAX_COLOR_ATTACHMENTS_EXT = " + maxColorAttach); - AngelicaTweaker.LOGGER - .debug("[Shaders] GL_MAX_TEXTURE_IMAGE_UNITS = " + glGetInteger(GL_MAX_TEXTURE_IMAGE_UNITS)); - - usedColorBuffers = 4; - usedDepthBuffers = 1; - usedShadowColorBuffers = 0; - usedShadowDepthBuffers = 0; - usedColorAttachs = 1; - usedDrawBuffers = 1; - Arrays.fill(gbuffersFormat, GL_RGBA); - Arrays.fill(shadowHardwareFilteringEnabled, false); - Arrays.fill(shadowMipmapEnabled, false); - Arrays.fill(shadowFilterNearest, false); - Arrays.fill(shadowColorMipmapEnabled, false); - Arrays.fill(shadowColorFilterNearest, false); - centerDepthSmoothEnabled = false; - noiseTextureEnabled = false; - sunPathRotation = 0f; - shadowIntervalSize = 2.0f; - aoLevel = 0.8f; - blockAoLight = 1.0f - aoLevel; - useEntityAttrib = false; - useMidTexCoordAttrib = false; - useMultiTexCoord3Attrib = false; - waterShadowEnabled = false; - updateChunksErrorRecorded = false; - updateBlockLightLevel(); - - for (int i = 0; i < ProgramCount; ++i) { - if (programNames[i] == "") { - programsID[i] = programsRef[i] = 0; - programsDrawBufSettings[i] = null; - programsColorAtmSettings[i] = null; - programsCompositeMipmapSetting[i] = 0; + if (isInitialized) { + return; + } + mc = Minecraft.getMinecraft(); + checkGLError("Shaders.init pre"); + capabilities = GLContext.getCapabilities(); + AngelicaTweaker.LOGGER.debug( + "[Shaders] OpenGL 2.0 = " + toStringYN(capabilities.OpenGL20) + + " 2.1 = " + toStringYN(capabilities.OpenGL21) + + " 3.0 = " + toStringYN(capabilities.OpenGL30) + + " 3.2 = " + toStringYN(capabilities.OpenGL32)); + if (!capabilities.OpenGL21) { + printChatAndLogError("[Shaders] No OpenGL 2.1."); + } + if (!capabilities.GL_EXT_framebuffer_object) { + printChatAndLogError("[Shaders] No EXT_framebuffer_object."); + } + if (!capabilities.OpenGL20 || !capabilities.GL_EXT_framebuffer_object) { + printChatAndLogError("[Shaders] Your GPU is not compatible with the Shaders mod."); + } + + hasGlGenMipmap = capabilities.OpenGL30; + dfbDrawBuffers.position(0).limit(MaxDrawBuffers); + dfbColorTextures.position(0).limit(MaxColorBuffers); + dfbDepthTextures.position(0).limit(MaxDepthBuffers); + sfbDrawBuffers.position(0).limit(MaxDrawBuffers); + sfbDepthTextures.position(0).limit(MaxShadowDepthBuffers); + sfbColorTextures.position(0).limit(MaxShadowColorBuffers); + + int maxDrawBuffers = GL11.glGetInteger(GL20.GL_MAX_DRAW_BUFFERS); + int maxColorAttach = GL11.glGetInteger(GL_MAX_COLOR_ATTACHMENTS_EXT); + AngelicaTweaker.LOGGER.debug("[Shaders] GL_MAX_DRAW_BUFFERS = " + maxDrawBuffers); + AngelicaTweaker.LOGGER.debug("[Shaders] GL_MAX_COLOR_ATTACHMENTS_EXT = " + maxColorAttach); + AngelicaTweaker.LOGGER.debug("[Shaders] GL_MAX_TEXTURE_IMAGE_UNITS = " + GL11.glGetInteger(GL20.GL_MAX_TEXTURE_IMAGE_UNITS)); + + usedColorBuffers = 4; + usedDepthBuffers = 1; + usedShadowColorBuffers = 0; + usedShadowDepthBuffers = 0; + usedColorAttachs = 1; + usedDrawBuffers = 1; + Arrays.fill(gbuffersFormat, GL11.GL_RGBA); + // Arrays.fill(gbuffersClear, true); + Arrays.fill(shadowHardwareFilteringEnabled, false); + Arrays.fill(shadowMipmapEnabled, false); + Arrays.fill(shadowFilterNearest, false); + Arrays.fill(shadowColorMipmapEnabled, false); + Arrays.fill(shadowColorFilterNearest, false); + centerDepthSmoothEnabled = false; + noiseTextureEnabled = false; + sunPathRotation = 0f; + shadowIntervalSize = 2.0f; + aoLevel = 0.8f; + blockAoLight = 1.0f - aoLevel; + useEntityAttrib = false; + useMidTexCoordAttrib = false; + useMultiTexCoord3Attrib = false; + waterShadowEnabled = false; + updateChunksErrorRecorded = false; + updateBlockLightLevel(); + + for (int i = 0; i < ProgramCount; ++i) { + if (programNames[i].isEmpty()) { + programsID[i] = programsRef[i] = 0; + programsDrawBufSettings[i] = null; + programsColorAtmSettings[i] = null; + programsCompositeMipmapSetting[i] = 0; + } else { + newDrawBufSetting = null; + newColorAtmSetting = null; + newCompositeMipmapSetting = 0; + final String str = "/shaders/" + programNames[i]; + int pr = setupProgram( i, str + ".vsh", str + ".fsh"); + programsID[i] = programsRef[i] = pr; + programsDrawBufSettings[i] = (pr != 0) ? newDrawBufSetting : null; + programsColorAtmSettings[i] = (pr != 0) ? newColorAtmSetting : null; + programsCompositeMipmapSetting[i] = (pr != 0) ? newCompositeMipmapSetting : 0; + } + } + + for (int p = 0; p < ProgramCount; ++p) { + if (p == ProgramFinal) { + programsDrawBuffers[p] = null; + } else if (programsID[p] == 0) { + if (p == ProgramShadow) { + programsDrawBuffers[p] = drawBuffersNone; } else { - newDrawBufSetting = null; - newColorAtmSetting = null; - newCompositeMipmapSetting = 0; - int pr = setupProgram( - i, - "/shaders/" + programNames[i] + ".vsh", - "/shaders/" + programNames[i] + ".fsh"); - programsID[i] = programsRef[i] = pr; - programsDrawBufSettings[i] = (pr != 0) ? newDrawBufSetting : null; - programsColorAtmSettings[i] = (pr != 0) ? newColorAtmSetting : null; - programsCompositeMipmapSetting[i] = (pr != 0) ? newCompositeMipmapSetting : 0; + programsDrawBuffers[p] = drawBuffersColorAtt0; } - } - - Map drawBuffersMap = new HashMap<>(); - for (int p = 0; p < ProgramCount; ++p) { - if (p == ProgramFinal) { - programsDrawBuffers[p] = null; - } else if (programsID[p] == 0) { - if (p == ProgramShadow) { - programsDrawBuffers[p] = drawBuffersNone; - } else { - programsDrawBuffers[p] = drawBuffersColorAtt0; + } else { + String str = programsDrawBufSettings[p]; + if (str != null) { + IntBuffer intbuf = drawBuffersBuffer[p]; + int numDB = str.length(); + if (numDB > usedDrawBuffers) { + usedDrawBuffers = numDB; } - } else { - String str = programsDrawBufSettings[p]; - if (str != null) { - IntBuffer intbuf = drawBuffersBuffer[p]; - int numDB = str.length(); - if (numDB > usedDrawBuffers) { - usedDrawBuffers = numDB; - } - if (numDB > maxDrawBuffers) { - numDB = maxDrawBuffers; - } - programsDrawBuffers[p] = intbuf; - intbuf.limit(numDB); - for (int i = 0; i < numDB; ++i) { - int d = GL_NONE; - if (str.length() > i) { - int ca = str.charAt(i) - '0'; - if (p != ProgramShadow) { - if (ca >= 0 && ca <= 7) { - d = ca + GL_COLOR_ATTACHMENT0_EXT; - if (ca > usedColorAttachs) { - usedColorAttachs = ca; - } - if (ca > usedColorBuffers) { - usedColorBuffers = ca; - } + if (numDB > maxDrawBuffers) { + numDB = maxDrawBuffers; + } + programsDrawBuffers[p] = intbuf; + intbuf.limit(numDB); + for (int i = 0; i < numDB; ++i) { + int d = GL11.GL_NONE; + if (str.length() > i) { + int ca = str.charAt(i) - '0'; + if (p != ProgramShadow) { + if (ca >= 0 && ca <= 7) { + d = ca + GL_COLOR_ATTACHMENT0_EXT; + if (ca > usedColorAttachs) { + usedColorAttachs = ca; + } + if (ca > usedColorBuffers) { + usedColorBuffers = ca; } - } else { - if (ca >= 0 && ca <= 1) { - d = ca + GL_COLOR_ATTACHMENT0_EXT; - if (ca > usedShadowColorBuffers) { - usedShadowColorBuffers = ca; - } + } + } else { + if (ca >= 0 && ca <= 1) { + d = ca + GL_COLOR_ATTACHMENT0_EXT; + if (ca > usedShadowColorBuffers) { + usedShadowColorBuffers = ca; } } } - intbuf.put(i, d); } + intbuf.put(i, d); + } + } else { + if (p != ProgramShadow) { + programsDrawBuffers[p] = dfbDrawBuffers; + usedDrawBuffers = usedColorBuffers; } else { - if (p != ProgramShadow) { - programsDrawBuffers[p] = dfbDrawBuffers; - usedDrawBuffers = usedColorBuffers; - } else { - programsDrawBuffers[p] = sfbDrawBuffers; - } + programsDrawBuffers[p] = sfbDrawBuffers; } } } + } - // if (programIDCopyDepth==0) - // programIDCopyDepth = setupProgramCopyDepth(); + // TO DO: add color attachment option + usedColorAttachs = usedColorBuffers; - // TO DO: add color attachment option - usedColorAttachs = usedColorBuffers; + shadowPassInterval = (usedShadowDepthBuffers > 0) ? 1 : 0; + shouldSkipDefaultShadow = (usedShadowDepthBuffers > 0); - shadowPassInterval = (usedShadowDepthBuffers > 0) ? 1 : 0; - shouldSkipDefaultShadow = (usedShadowDepthBuffers > 0); + dfbDrawBuffers.position(0).limit(usedDrawBuffers); + dfbColorTextures.position(0).limit(usedColorBuffers); + // dfbRenderBuffers.limit(colorAttachments); - dfbDrawBuffers.position(0).limit(usedDrawBuffers); - dfbColorTextures.position(0).limit(usedColorBuffers); - // dfbRenderBuffers.limit(colorAttachments); + for (int i = 0; i < usedDrawBuffers; ++i) { + dfbDrawBuffers.put(i, GL_COLOR_ATTACHMENT0_EXT + i); + } - for (int i = 0; i < usedDrawBuffers; ++i) { - dfbDrawBuffers.put(i, GL_COLOR_ATTACHMENT0_EXT + i); - } + if (usedDrawBuffers > maxDrawBuffers) { + printChatAndLogError( + "[Shaders] Not enough draw buffers! Requires " + usedDrawBuffers + + ". Has " + + maxDrawBuffers + + "."); + } - if (usedDrawBuffers > maxDrawBuffers) { - printChatAndLogError( - "[Shaders] Not enough draw buffers! Requires " + usedDrawBuffers - + ". Has " - + maxDrawBuffers - + "."); - } - // if (usedColorBuffers > maxColorAttach) { - // printChatAndLogError("[Shaders] Not enough color attachment! Requires "+ usedColorBuffers + ". Has " + - // maxColorAttach + "."); - // } - - sfbDrawBuffers.position(0).limit(usedShadowColorBuffers); - for (int i = 0; i < usedShadowColorBuffers; ++i) { - sfbDrawBuffers.put(i, GL_COLOR_ATTACHMENT0_EXT + i); - } + sfbDrawBuffers.position(0).limit(usedShadowColorBuffers); + for (int i = 0; i < usedShadowColorBuffers; ++i) { + sfbDrawBuffers.put(i, GL_COLOR_ATTACHMENT0_EXT + i); + } - // Use programBackups for missing programs - for (int i = 0; i < ProgramCount; ++i) { - int n = i; - while (programsID[n] == 0 && programBackups[n] != n) n = programBackups[n]; - if (n != i && i != ProgramShadow) { - programsID[i] = programsID[n]; - programsDrawBufSettings[i] = programsDrawBufSettings[n]; - programsDrawBuffers[i] = programsDrawBuffers[n]; - } + // Use programBackups for missing programs + for (int i = 0; i < ProgramCount; ++i) { + int n = i; + while (programsID[n] == 0 && programBackups[n] != n) n = programBackups[n]; + if (n != i && i != ProgramShadow) { + programsID[i] = programsID[n]; + programsDrawBufSettings[i] = programsDrawBufSettings[n]; + programsDrawBuffers[i] = programsDrawBuffers[n]; } + } - // printIntBuffer("dfb drawbuffers",dfbDrawBuffers); - // printIntBuffer("sfb drawbuffers",sfbDrawBuffers); - // printIntBuffer("pgshadow drawbf",programsDrawBuffers[ProgramShadow]); + // printIntBuffer("dfb drawbuffers",dfbDrawBuffers); + // printIntBuffer("sfb drawbuffers",sfbDrawBuffers); + // printIntBuffer("pgshadow drawbf",programsDrawBuffers[ProgramShadow]); - // setup scene frame buffer and textures - resize(); + // setup scene frame buffer and textures + resize(); - // setup shadow frame buffer and texture - resizeShadow(); + // setup shadow frame buffer and texture + resizeShadow(); - if (noiseTextureEnabled) setupNoiseTexture(); + if (noiseTextureEnabled) setupNoiseTexture(); - if (defaultTexture == null) defaultTexture = ShadersTex.createDefaultTexture(); - // TextureNM texBlocks = (TextureNM)textureManager.textureMapBlocks.getTexture(); - // TextureNM texItems = (TextureNM)textureManager.textureMapBlocks.getTexture(); - // terrainTextureIdArray = new int[] { texBlocks.getGlTextureId(), texBlocks.normalMap.getGlTextureId(), - // texBlocks.specularMap.getGlTextureId() }; - // textureIdMap.put(terrainTextureIdArray[0], terrainTextureIdArray); - // int[] itemsTextureIdArray; - // itemsTextureIdArray = new int[] { texItems.getGlTextureId(), texItems.normalMap.getGlTextureId(), - // texItems.specularMap.getGlTextureId() }; - // textureIdMap.put(itemsTextureIdArray[0], itemsTextureIdArray); + if (defaultTexture == null) defaultTexture = ShadersTex.createDefaultTexture(); + // TextureNM texBlocks = (TextureNM)textureManager.textureMapBlocks.getTexture(); + // TextureNM texItems = (TextureNM)textureManager.textureMapBlocks.getTexture(); + // terrainTextureIdArray = new int[] { texBlocks.getGlTextureId(), texBlocks.normalMap.getGlTextureId(), + // texBlocks.specularMap.getGlTextureId() }; + // textureIdMap.put(terrainTextureIdArray[0], terrainTextureIdArray); + // int[] itemsTextureIdArray; + // itemsTextureIdArray = new int[] { texItems.getGlTextureId(), texItems.normalMap.getGlTextureId(), + // texItems.specularMap.getGlTextureId() }; + // textureIdMap.put(itemsTextureIdArray[0], itemsTextureIdArray); - isInitialized = true; + isInitialized = true; - resetDisplayList(); - if (notFirstInit) { - mc.ingameGUI.getChatGUI().printChatMessage(new ChatComponentText("Shaders initialized.")); - } - checkGLError("Shaders.init"); + resetDisplayList(); + if (notFirstInit) { + mc.ingameGUI.getChatGUI().printChatMessage(new ChatComponentText("Shaders initialized.")); } + checkGLError("Shaders.init"); } public static void resetDisplayList() { ++numberResetDisplayList; AngelicaTweaker.LOGGER.debug("Reset model renderers"); if (Shaders.useMidTexCoordAttrib || Shaders.useMultiTexCoord3Attrib) { - Iterator it = RenderManager.instance.entityRenderMap.values().iterator(); - while (it.hasNext()) { - Render ren = it.next(); - if (ren instanceof RendererLivingEntity) { - RendererLivingEntity rle = (RendererLivingEntity) ren; + for (Render ren : RenderManager.instance.entityRenderMap.values()) { + if (ren instanceof RendererLivingEntity rle) { // System.out.format("Reset %s\n", rle.toString()); resetDisplayListModel(rle.mainModel); resetDisplayListModel(rle.renderPassModel); @@ -1195,9 +895,7 @@ public static void resetDisplayList() { public static void resetDisplayListModel(ModelBase mbase) { if (mbase != null) { - Iterator it = mbase.boxList.iterator(); - while (it.hasNext()) { - ModelRenderer obj = it.next(); + for (ModelRenderer obj : mbase.boxList) { if (obj != null) { resetDisplayListModelRenderer(obj); } @@ -1207,16 +905,7 @@ public static void resetDisplayListModel(ModelBase mbase) { public static void resetDisplayListModelRenderer(ModelRenderer mrr) { ((IModelRenderer) mrr).angelica$resetDisplayList(); - // if (mrr.compiled) - // { - // GLAllocation.deleteDisplayLists(mrr.displayList); - // mrr.displayList = 0; - // mrr.compiled = false; - // if (mrr instanceof ModelRotationRenderer) { - // ModelRotationRenderer mrt = (ModelRotationRenderer)mrr; - // mrt.compiled = false; - // } - // } + if (mrr.childModels != null) { for (int i = 0, n = mrr.childModels.size(); i < n; ++i) { resetDisplayListModelRenderer((ModelRenderer) mrr.childModels.get(i)); @@ -1226,142 +915,64 @@ public static void resetDisplayListModelRenderer(ModelRenderer mrr) { // ---------------------------------------- - // private static final String shaderCodeCopyDepthV = - // "#version 120\n"+ - // "varying vec4 texcoord;\n"+ - // "void main()\n"+ - // "{\n"+ - // " texcoord = gl_MultiTexCoord0;\n"+ - // " gl_Position = ftransform();\n"+ - // "}\n" - // ; - // private static final String shaderCodeCopyDepthF = - // "#version 120\n"+ - // "varying vec4 texcoord;\n"+ - // "uniform sampler2D depthtex0;\n"+ - // "void main()\n"+ - // "{\n"+ - // " gl_FragDepth = texture2D(depthtex0,texcoord.st).r;\n"+ - // " gl_FragColor = texture2D(depthtex0,texcoord.st);\n"+ - // "}\n" - // ; - // - // private static int setupProgramCopyDepth() { - // int program = glCreateProgramObjectARB(); - // if (program !=0) { - // int vShader = createVertShaderFromCode(shaderCodeCopyDepthV); - // int fShader = createFragShaderFromCode(shaderCodeCopyDepthF); - // if (vShader != 0 || fShader != 0) { - // if (vShader != 0) { - // glAttachObjectARB(program, vShader); - // } - // if (fShader != 0) { - // glAttachObjectARB(program, fShader); - // } - // glLinkProgramARB(program); - // if (vShader != 0) { - // glDetachObjectARB(program, vShader); - // glDeleteObjectARB(vShader); - // } - // if (fShader != 0) { - // glDetachObjectARB(program, fShader); - // glDeleteObjectARB(fShader); - // } - // int valid = glGetProgrami(program, GL_VALIDATE_STATUS); // glGetProgrami in LWJGL 3.0+ - // if (valid == GL_TRUE) { - // System.out.println("Program copydepth created"); - // } else { - // printChatAndLogError("[Shaders] Error : Invalid program copydepth"); - // glDeleteObjectARB(program); - // program = 0; - // } - // } else { - // glDeleteObjectARB(program); - // program = 0; - // } - // } - // return program; - // } - // - // - // private static int createVertShaderFromCode(String code) { - // int vertShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); - // if (vertShader == 0) { - // return 0; - // } - // glShaderSourceARB(vertShader, code); - // glCompileShaderARB(vertShader); - // printLogInfo(vertShader,"copydepth vert"); - // return vertShader; - // } - // - // - // private static int createFragShaderFromCode(String code) { - // int fragShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); - // if (fragShader == 0) { - // return 0; - // } - // glShaderSourceARB(fragShader, code); - // glCompileShaderARB(fragShader); - // printLogInfo(fragShader,"copydepth frag"); - // return fragShader; - // } - - private static int setupProgram(int program, String vShaderPath, String fShaderPath) { + private static int setupProgram(int program, String vShaderPath, String fShaderPath) { checkGLError("pre setupProgram"); int programid = glCreateProgramObjectARB(); checkGLError("create"); - if (programid != 0) { - progUseEntityAttrib = false; - progUseMidTexCoordAttrib = false; - int vShader = createVertShader(vShaderPath); - int fShader = createFragShader(fShaderPath); - checkGLError("create"); - if (vShader != 0 || fShader != 0) { - if (vShader != 0) { - glAttachObjectARB(programid, vShader); - checkGLError("attach"); - } - if (fShader != 0) { - glAttachObjectARB(programid, fShader); - checkGLError("attach"); - } - if (progUseEntityAttrib) { - glBindAttribLocationARB(programid, entityAttrib, "mc_Entity"); - checkGLError("mc_Entity"); - } - if (progUseMidTexCoordAttrib) { - glBindAttribLocationARB(programid, midTexCoordAttrib, "mc_midTexCoord"); - checkGLError("mc_midTexCoord"); - } - glLinkProgramARB(programid); - if (vShader != 0) { - glDetachObjectARB(programid, vShader); - glDeleteObjectARB(vShader); - } - if (fShader != 0) { - glDetachObjectARB(programid, fShader); - glDeleteObjectARB(fShader); - } - programsID[program] = programid; - useProgram(program); - glValidateProgramARB(programid); - useProgram(ProgramNone); - printLogInfo(programid, vShaderPath + "," + fShaderPath); - int valid = glGetProgrami(programid, GL_VALIDATE_STATUS); - if (valid == GL_TRUE) { - AngelicaTweaker.LOGGER.debug("Program " + programNames[program] + " loaded"); - } else { - printChatAndLogError("[Shaders] Error : Invalid program " + programNames[program]); - glDeleteObjectARB(programid); - programid = 0; - } - } else { - glDeleteObjectARB(programid); - programid = 0; - } - } - return programid; + if (programid == 0) { + return programid; + } + progUseEntityAttrib = false; + progUseMidTexCoordAttrib = false; + int vShader = createVertShader(vShaderPath); + int fShader = createFragShader(fShaderPath); + checkGLError("create"); + if (vShader == 0 && fShader == 0) { + glDeleteObjectARB(programid); + programid = 0; + return programid; + } + + if (vShader != 0) { + glAttachObjectARB(programid, vShader); + checkGLError("attach"); + } + if (fShader != 0) { + glAttachObjectARB(programid, fShader); + checkGLError("attach"); + } + if (progUseEntityAttrib) { + glBindAttribLocationARB(programid, entityAttrib, "mc_Entity"); + checkGLError("mc_Entity"); + } + if (progUseMidTexCoordAttrib) { + glBindAttribLocationARB(programid, midTexCoordAttrib, "mc_midTexCoord"); + checkGLError("mc_midTexCoord"); + } + glLinkProgramARB(programid); + if (vShader != 0) { + glDetachObjectARB(programid, vShader); + glDeleteObjectARB(vShader); + } + if (fShader != 0) { + glDetachObjectARB(programid, fShader); + glDeleteObjectARB(fShader); + } + programsID[program] = programid; + useProgram(program); + glValidateProgramARB(programid); + useProgram(ProgramNone); + printLogInfo(programid, vShaderPath + "," + fShaderPath); + int valid = GL20.glGetProgrami(programid, GL20.GL_VALIDATE_STATUS); + if (valid == GL11.GL_TRUE) { + AngelicaTweaker.LOGGER.debug("Program " + programNames[program] + " loaded"); + } else { + printChatAndLogError("[Shaders] Error : Invalid program " + programNames[program]); + glDeleteObjectARB(programid); + programid = 0; + } + + return programid; } private static InputStream locateShaderStream(String path) { @@ -1382,6 +993,7 @@ private static String getPreprocessedShaderSources(String filename) { final String basename = (lastSlash == -1) ? "/" : filename.substring(0, lastSlash + 1); try (InputStream is = locateShaderStream(filename)) { if (is == null) { + AngelicaTweaker.LOGGER.debug("PreprocessedShader not found: " + filename); throw new FileNotFoundException(filename); } String source = IOUtils.toString(is, StandardCharsets.UTF_8).replace("\r\n", "\n"); @@ -1414,7 +1026,6 @@ private static int createVertShader(String filename) { processVertShaderLine(line); } } catch (Exception e) { - e.printStackTrace(); glDeleteObjectARB(vertShader); return 0; } @@ -1458,7 +1069,6 @@ private static int createFragShader(String filename) { processFragShaderLine(line, filename); } } catch (Exception e) { - e.printStackTrace(); glDeleteObjectARB(fragShader); return 0; } @@ -1495,7 +1105,7 @@ private static void processFragShaderLine(String line, String filename) { } else if (line.matches("uniform [ _a-zA-Z0-9]+ depthtex2;.*")) { if (usedDepthBuffers < 3) usedDepthBuffers = 3; } else if (line.matches("uniform [ _a-zA-Z0-9]+ gdepth;.*")) { - if (gbuffersFormat[1] == GL_RGBA) gbuffersFormat[1] = GL_RGBA32F; + if (gbuffersFormat[1] == GL11.GL_RGBA) gbuffersFormat[1] = GL30.GL_RGBA32F; } else if (usedColorBuffers < 5 && line.matches("uniform [ _a-zA-Z0-9]+ gaux1;.*")) { usedColorBuffers = 5; } else if (usedColorBuffers < 6 && line.matches("uniform [ _a-zA-Z0-9]+ gaux2;.*")) { @@ -1692,13 +1302,13 @@ private static void processFragShaderLine(String line, String filename) { // gaux4 } else if (line.matches("/\\* GAUX4FORMAT:RGBA32F \\*/.*")) { AngelicaTweaker.LOGGER.debug("gaux4 format : RGB32AF"); - gbuffersFormat[7] = GL_RGBA32F; + gbuffersFormat[7] = GL30.GL_RGBA32F; } else if (line.matches("/\\* GAUX4FORMAT:RGB32F \\*/.*")) { AngelicaTweaker.LOGGER.debug("gaux4 format : RGB32F"); - gbuffersFormat[7] = GL_RGB32F; + gbuffersFormat[7] = GL30.GL_RGB32F; } else if (line.matches("/\\* GAUX4FORMAT:RGB16 \\*/.*")) { AngelicaTweaker.LOGGER.debug("gaux4 format : RGB16"); - gbuffersFormat[7] = GL_RGB16; + gbuffersFormat[7] = GL11.GL_RGB16; // Mipmap stuff } else if (line.matches("[ \t]*const[ \t]*bool[ \t]*\\w+MipmapEnabled[ \t]*=[ \t]*true[ \t]*;.*")) { @@ -1711,16 +1321,11 @@ private static void processFragShaderLine(String line, String filename) { int bufferindex = getBufferIndexFromString(name); if (bufferindex >= 0) { newCompositeMipmapSetting |= (1 << bufferindex); - AngelicaTweaker.LOGGER.debug( - "{} mipmap enabled for {}", - name, - filename); + AngelicaTweaker.LOGGER.debug("{} mipmap enabled for {}", name, filename); } } } else if (line.matches("/\\* DRAWBUFFERS:[0-7N]* \\*/.*")) { - String[] parts = line.split( - "(:| )", - 4); + String[] parts = line.split("(:| )", 4); newDrawBufSetting = parts[2]; } } @@ -1748,7 +1353,7 @@ public static void setDrawBuffers(IntBuffer drawBuffers) { if (activeDrawBuffers != drawBuffers) { // printIntBuffer("setDrawBuffers", drawBuffers); activeDrawBuffers = drawBuffers; - glDrawBuffers(drawBuffers); + GL20.glDrawBuffers(drawBuffers); } else { // printIntBuffer("setDrawBf skip", drawBuffers); } @@ -1939,7 +1544,7 @@ public static void useProgram(int program) { public static void setProgramUniform1i(String name, int x) { int gp = programsID[activeProgram]; - if (gp != GL_NONE) { + if (gp != GL11.GL_NONE) { int uniform = glGetUniformLocationARB(gp, name); glUniform1iARB(uniform, x); if (enableShadersDebug) checkGLError(programNames[activeProgram], name); @@ -1948,7 +1553,7 @@ public static void setProgramUniform1i(String name, int x) { public static void setProgramUniform2i(String name, int x, int y) { int gp = programsID[activeProgram]; - if (gp != GL_NONE) { + if (gp != GL11.GL_NONE) { int uniform = glGetUniformLocationARB(gp, name); glUniform2iARB(uniform, x, y); if (enableShadersDebug) checkGLError(programNames[activeProgram], name); @@ -1957,7 +1562,7 @@ public static void setProgramUniform2i(String name, int x, int y) { public static void setProgramUniform1f(String name, float x) { int gp = programsID[activeProgram]; - if (gp != GL_NONE) { + if (gp != GL11.GL_NONE) { int uniform = glGetUniformLocationARB(gp, name); glUniform1fARB(uniform, x); if (enableShadersDebug) checkGLError(programNames[activeProgram], name); @@ -1966,7 +1571,7 @@ public static void setProgramUniform1f(String name, float x) { public static void setProgramUniform3f(String name, float x, float y, float z) { int gp = programsID[activeProgram]; - if (gp != GL_NONE) { + if (gp != GL11.GL_NONE) { int uniform = glGetUniformLocationARB(gp, name); glUniform3fARB(uniform, x, y, z); if (enableShadersDebug) checkGLError(programNames[activeProgram], name); @@ -1975,7 +1580,7 @@ public static void setProgramUniform3f(String name, float x, float y, float z) { public static void setProgramUniformMatrix4ARB(String name, boolean transpose, FloatBuffer matrix) { int gp = programsID[activeProgram]; - if (gp != GL_NONE && matrix != null) { + if (gp != GL11.GL_NONE && matrix != null) { int uniform = glGetUniformLocationARB(gp, name); glUniformMatrix4ARB(uniform, transpose, matrix); if (enableShadersDebug) checkGLError(programNames[activeProgram], name); @@ -1983,30 +1588,32 @@ public static void setProgramUniformMatrix4ARB(String name, boolean transpose, F } private static int getBufferIndexFromString(String name) { - if (name.equals("colortex0") || name.equals("gcolor")) return 0; - else if (name.equals("colortex1") || name.equals("gdepth")) return 1; - else if (name.equals("colortex2") || name.equals("gnormal")) return 2; - else if (name.equals("colortex3") || name.equals("composite")) return 3; - else if (name.equals("colortex4") || name.equals("gaux1")) return 4; - else if (name.equals("colortex5") || name.equals("gaux2")) return 5; - else if (name.equals("colortex6") || name.equals("gaux3")) return 6; - else if (name.equals("colortex7") || name.equals("gaux4")) return 7; - else return -1; + return switch (name) { + case "colortex0", "gcolor" -> 0; + case "colortex1", "gdepth" -> 1; + case "colortex2", "gnormal" -> 2; + case "colortex3", "composite" -> 3; + case "colortex4", "gaux1" -> 4; + case "colortex5", "gaux2" -> 5; + case "colortex6", "gaux3" -> 6; + case "colortex7", "gaux4" -> 7; + default -> -1; + }; } private static int getTextureFormatFromString(String par) { - if (par.matches("[ \t]*R8[ \t]*")) return GL_R8; - else if (par.matches("[ \t]*RG8[ \t]*")) return GL_RG8; - else if (par.matches("[ \t]*RGB8[ \t]*")) return GL_RGB8; - else if (par.matches("[ \t]*RGBA8[ \t]*")) return GL_RGBA8; - else if (par.matches("[ \t]*R16[ \t]*")) return GL_R16; - else if (par.matches("[ \t]*RG16[ \t]*")) return GL_RG16; - else if (par.matches("[ \t]*RGB16[ \t]*")) return GL_RGB16; - else if (par.matches("[ \t]*RGBA16[ \t]*")) return GL_RGBA16; - else if (par.matches("[ \t]*R32F[ \t]*")) return GL_R32F; - else if (par.matches("[ \t]*RG32F[ \t]*")) return GL_RG32F; - else if (par.matches("[ \t]*RGB32F[ \t]*")) return GL_RGB32F; - else if (par.matches("[ \t]*RGBA32F[ \t]*")) return GL_RGBA32F; + if (par.matches("[ \t]*R8[ \t]*")) return GL30.GL_R8; + else if (par.matches("[ \t]*RG8[ \t]*")) return GL30.GL_RG8; + else if (par.matches("[ \t]*RGB8[ \t]*")) return GL11.GL_RGB8; + else if (par.matches("[ \t]*RGBA8[ \t]*")) return GL11.GL_RGBA8; + else if (par.matches("[ \t]*R16[ \t]*")) return GL30.GL_R16; + else if (par.matches("[ \t]*RG16[ \t]*")) return GL30.GL_RG16; + else if (par.matches("[ \t]*RGB16[ \t]*")) return GL11.GL_RGB16; + else if (par.matches("[ \t]*RGBA16[ \t]*")) return GL11.GL_RGBA16; + else if (par.matches("[ \t]*R32F[ \t]*")) return GL30.GL_R32F; + else if (par.matches("[ \t]*RG32F[ \t]*")) return GL30.GL_RG32F; + else if (par.matches("[ \t]*RGB32F[ \t]*")) return GL30.GL_RGB32F; + else if (par.matches("[ \t]*RGBA32F[ \t]*")) return GL30.GL_RGBA32F; else return 0; } @@ -2021,70 +1628,66 @@ private static IntBuffer fillIntBufferZero(IntBuffer buf) { } public static void uninit() { - if (isInitialized) { - checkGLError("Shaders.uninit pre"); - for (int i = 0; i < ProgramCount; ++i) { - if (programsRef[i] != 0) { - glDeleteObjectARB(programsRef[i]); - checkGLError("del programRef"); - } - programsRef[i] = 0; - programsID[i] = 0; - programsDrawBufSettings[i] = null; - programsDrawBuffers[i] = null; - programsCompositeMipmapSetting[i] = 0; - } - if (dfb != 0) { - glDeleteFramebuffersEXT(dfb); - dfb = 0; - checkGLError("del dfb"); - } - if (sfb != 0) { - glDeleteFramebuffersEXT(sfb); - sfb = 0; - checkGLError("del sfb"); - } - // glDeleteRenderbuffersEXT(dfbDepthBuffer); dfbDepthBuffer = 0; - // if (dfbRenderBuffers != null) { - // glDeleteRenderbuffersEXT(dfbRenderBuffers); - // fillIntBufferZero(dfbRenderBuffers); - // } - if (dfbDepthTextures != null) { - glDeleteTextures(dfbDepthTextures); - fillIntBufferZero(dfbDepthTextures); - checkGLError("del dfbDepthTextures"); - } - if (dfbColorTextures != null) { - glDeleteTextures(dfbColorTextures); - fillIntBufferZero(dfbColorTextures); - checkGLError("del dfbTextures"); - } - if (sfbDepthTextures != null) { - glDeleteTextures(sfbDepthTextures); - fillIntBufferZero(sfbDepthTextures); - checkGLError("del shadow depth"); - } - if (sfbColorTextures != null) { - glDeleteTextures(sfbColorTextures); - fillIntBufferZero(sfbColorTextures); - checkGLError("del shadow color"); - } - if (dfbDrawBuffers != null) { - fillIntBufferZero(dfbDrawBuffers); - } - if (noiseTexture != null) { - noiseTexture.destroy(); - noiseTexture = null; + if (!isInitialized) { + return; + } + checkGLError("Shaders.uninit pre"); + for (int i = 0; i < ProgramCount; ++i) { + if (programsRef[i] != 0) { + glDeleteObjectARB(programsRef[i]); + checkGLError("del programRef"); } + programsRef[i] = 0; + programsID[i] = 0; + programsDrawBufSettings[i] = null; + programsDrawBuffers[i] = null; + programsCompositeMipmapSetting[i] = 0; + } + if (dfb != 0) { + glDeleteFramebuffersEXT(dfb); + dfb = 0; + checkGLError("del dfb"); + } + if (sfb != 0) { + glDeleteFramebuffersEXT(sfb); + sfb = 0; + checkGLError("del sfb"); + } + if (dfbDepthTextures != null) { + GL11.glDeleteTextures(dfbDepthTextures); + fillIntBufferZero(dfbDepthTextures); + checkGLError("del dfbDepthTextures"); + } + if (dfbColorTextures != null) { + GL11.glDeleteTextures(dfbColorTextures); + fillIntBufferZero(dfbColorTextures); + checkGLError("del dfbTextures"); + } + if (sfbDepthTextures != null) { + GL11.glDeleteTextures(sfbDepthTextures); + fillIntBufferZero(sfbDepthTextures); + checkGLError("del shadow depth"); + } + if (sfbColorTextures != null) { + GL11.glDeleteTextures(sfbColorTextures); + fillIntBufferZero(sfbColorTextures); + checkGLError("del shadow color"); + } + if (dfbDrawBuffers != null) { + fillIntBufferZero(dfbDrawBuffers); + } + if (noiseTexture != null) { + noiseTexture.destroy(); + noiseTexture = null; + } - AngelicaTweaker.LOGGER.trace("UNINIT"); + AngelicaTweaker.LOGGER.trace("UNINIT"); - shadowPassInterval = 0; - shouldSkipDefaultShadow = false; - isInitialized = false; - notFirstInit = true; - checkGLError("Shaders.uninit"); - } + shadowPassInterval = 0; + shouldSkipDefaultShadow = false; + isInitialized = false; + notFirstInit = true; + checkGLError("Shaders.uninit"); } public static void scheduleResize() { @@ -2115,35 +1718,35 @@ private static void resizeShadow() { private static void setupFrameBuffer() { if (dfb != 0) { glDeleteFramebuffersEXT(dfb); - glDeleteTextures(dfbDepthTextures); - glDeleteTextures(dfbColorTextures); + GL11.glDeleteTextures(dfbDepthTextures); + GL11.glDeleteTextures(dfbColorTextures); } dfb = glGenFramebuffersEXT(); - glGenTextures((IntBuffer) dfbDepthTextures.clear().limit(usedDepthBuffers)); - glGenTextures((IntBuffer) dfbColorTextures.clear().limit(usedColorBuffers)); + GL11.glGenTextures((IntBuffer) dfbDepthTextures.clear().limit(usedDepthBuffers)); + GL11.glGenTextures((IntBuffer) dfbColorTextures.clear().limit(usedColorBuffers)); dfbDepthTextures.position(0); dfbColorTextures.position(0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dfb); - glDrawBuffers(GL_NONE); - glReadBuffer(GL_NONE); + GL20.glDrawBuffers(GL11.GL_NONE); + GL11.glReadBuffer(GL11.GL_NONE); for (int i = 0; i < usedDepthBuffers; ++i) { - glBindTexture(GL_TEXTURE_2D, dfbDepthTextures.get(i)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); - glTexImage2D( - GL_TEXTURE_2D, + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(i)); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_DEPTH_TEXTURE_MODE, GL11.GL_LUMINANCE); + GL11.glTexImage2D( + GL11.GL_TEXTURE_2D, 0, - GL_DEPTH_COMPONENT, + GL11.GL_DEPTH_COMPONENT, renderWidth, renderHeight, 0, - GL_DEPTH_COMPONENT, + GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (ByteBuffer) null); } @@ -2151,35 +1754,21 @@ private static void setupFrameBuffer() { glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_TEXTURE_2D, + GL11.GL_TEXTURE_2D, dfbDepthTextures.get(0), 0); - glDrawBuffers(dfbDrawBuffers); - glReadBuffer(GL_NONE); + GL20.glDrawBuffers(dfbDrawBuffers); + GL11.glReadBuffer(GL11.GL_NONE); checkGLError("FT d"); for (int i = 0; i < usedColorBuffers; ++i) { - glBindTexture(GL_TEXTURE_2D, dfbColorTextures.get(i)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D( - GL_TEXTURE_2D, - 0, - gbuffersFormat[i], - renderWidth, - renderHeight, - 0, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - (ByteBuffer) null); - glFramebufferTexture2DEXT( - GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT + i, - GL_TEXTURE_2D, - dfbColorTextures.get(i), - 0); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(i)); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0, gbuffersFormat[i], renderWidth, renderHeight, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (ByteBuffer) null); + glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL11.GL_TEXTURE_2D, dfbColorTextures.get(i), 0); checkGLError("FT c"); } @@ -2188,23 +1777,9 @@ private static void setupFrameBuffer() { if (status == GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT) { printChatAndLogError("Failed using multiple internal formats in frame buffer."); for (int i = 0; i < usedColorBuffers; ++i) { - glBindTexture(GL_TEXTURE_2D, dfbColorTextures.get(i)); - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_RGBA, - renderWidth, - renderHeight, - 0, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - (ByteBuffer) null); - glFramebufferTexture2DEXT( - GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT + i, - GL_TEXTURE_2D, - dfbColorTextures.get(i), - 0); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(i)); + GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, renderWidth, renderHeight, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (ByteBuffer) null); + glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL11.GL_TEXTURE_2D, dfbColorTextures.get(i), 0); checkGLError("FT c"); } status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); @@ -2213,7 +1788,7 @@ private static void setupFrameBuffer() { } } - glBindTexture(GL_TEXTURE_2D, 0); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { printChatAndLogError("Failed creating framebuffer! (Status " + status + ")"); @@ -2229,17 +1804,17 @@ private static void setupShadowFrameBuffer() { if (sfb != 0) { glDeleteFramebuffersEXT(sfb); - glDeleteTextures(sfbDepthTextures); - glDeleteTextures(sfbColorTextures); + GL11.glDeleteTextures(sfbDepthTextures); + GL11.glDeleteTextures(sfbColorTextures); } sfb = glGenFramebuffersEXT(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sfb); - glDrawBuffers(GL_NONE); - glReadBuffer(GL_NONE); + GL20.glDrawBuffers(GL11.GL_NONE); + GL11.glReadBuffer(GL11.GL_NONE); - glGenTextures((IntBuffer) sfbDepthTextures.clear().limit(usedShadowDepthBuffers)); - glGenTextures((IntBuffer) sfbColorTextures.clear().limit(usedShadowColorBuffers)); + GL11.glGenTextures((IntBuffer) sfbDepthTextures.clear().limit(usedShadowDepthBuffers)); + GL11.glGenTextures((IntBuffer) sfbColorTextures.clear().limit(usedShadowColorBuffers)); // printIntBuffer(sfbDepthTextures); // printIntBuffer(sfbColorTextures); sfbDepthTextures.position(0); @@ -2247,61 +1822,33 @@ private static void setupShadowFrameBuffer() { // depth for (int i = 0; i < usedShadowDepthBuffers; ++i) { - glBindTexture(GL_TEXTURE_2D, sfbDepthTextures.get(i)); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - int filter = shadowFilterNearest[i] ? GL_NEAREST : GL_LINEAR; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbDepthTextures.get(i)); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); + int filter = shadowFilterNearest[i] ? GL11.GL_NEAREST : GL11.GL_LINEAR; + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter); if (shadowHardwareFilteringEnabled[i]) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_DEPTH_COMPONENT, - shadowMapWidth, - shadowMapHeight, - 0, - GL_DEPTH_COMPONENT, - GL11.GL_FLOAT, - (FloatBuffer) null); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_COMPARE_MODE, GL30.GL_COMPARE_REF_TO_TEXTURE); + GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0, GL11.GL_DEPTH_COMPONENT, shadowMapWidth, shadowMapHeight, 0, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (FloatBuffer) null); } - glFramebufferTexture2DEXT( - GL_FRAMEBUFFER_EXT, - GL_DEPTH_ATTACHMENT_EXT, - GL_TEXTURE_2D, - sfbDepthTextures.get(0), - 0); + glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, sfbDepthTextures.get(0), 0); checkGLError("FT sd"); // color shadow for (int i = 0; i < usedShadowColorBuffers; ++i) { - glBindTexture(GL_TEXTURE_2D, sfbColorTextures.get(i)); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - int filter = shadowColorFilterNearest[i] ? GL_NEAREST : GL_LINEAR; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_RGBA, - shadowMapWidth, - shadowMapHeight, - 0, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - (ByteBuffer) null); - glFramebufferTexture2DEXT( - GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT + i, - GL_TEXTURE_2D, - sfbColorTextures.get(i), - 0); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbColorTextures.get(i)); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); + GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); + int filter = shadowColorFilterNearest[i] ? GL11.GL_NEAREST : GL11.GL_LINEAR; + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter); + GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, shadowMapWidth, shadowMapHeight, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (ByteBuffer) null); + glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL11.GL_TEXTURE_2D, sfbColorTextures.get(i), 0); checkGLError("FT sc"); } - glBindTexture(GL_TEXTURE_2D, 0); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { @@ -2311,16 +1858,6 @@ private static void setupShadowFrameBuffer() { } } - /* - * public static void linkTextureNormalMap(int tex0, int tex2, int tex3) { textureIdMap_n.put(tex0, tex2); - * textureIdMap_s.put(tex0, tex3); int[] ast0,ast2,ast3; if (tex0 < Tessellator.atlasSubTextures.length && (ast0 = - * Tessellator.atlasSubTextures[tex0]) != null) { if (tex2 < Tessellator.atlasSubTextures.length && (ast2 = - * Tessellator.atlasSubTextures[tex2]) != null) for (int it = 0, size = Math.min(ast0.length,ast2.length); it < - * size; ++it) textureIdMap_n.put(ast0[it], ast2[it]); if (tex3 < Tessellator.atlasSubTextures.length && (ast3 = - * Tessellator.atlasSubTextures[tex3]) != null) for (int it = 0, size = Math.min(ast0.length,ast3.length); it < - * size; ++it) textureIdMap_s.put(ast0[it], ast3[it]); } } - */ - public static void beginRender(Minecraft minecraft, float f, long l) { if (isShadowPass) { return; @@ -2389,75 +1926,53 @@ public static void beginRender(Minecraft minecraft, float f, long l) { skyColorB = (float) skyColorV.zCoord; } - // Determine average color - // { - // int searchWidth = renderWidth / 2; - // int searchHeight = renderHeight / 2; - // - // ByteBuffer colorByteBuffer = ByteBuffer.allocateDirect(searchWidth * searchHeight * 4 * 3); - // glReadPixels((renderWidth / 2) - (searchWidth / 2), (renderHeight / 2) - (searchHeight / 2), searchWidth, - // searchHeight, GL11.GL_RGB, GL11.GL_FLOAT, colorByteBuffer); - // - // colorByteBuffer.order(ByteOrder.LITTLE_ENDIAN); - // - // - // float averageColor = 0.0f; - // for (int i = 0; i < searchWidth; i++) { - // for (int j = 0; j < searchHeight; j++) { - // averageColor += colorByteBuffer.getFloat(i * 4 + (searchWidth * 4 * 3 * j)); - // } - // } - // - // System.out.println("Color: " + averageColor / (searchWidth * searchHeight)); - // - // } isRenderingWorld = true; isCompositeRendered = false; isHandRendered = false; if (usedShadowDepthBuffers >= 1) { - glActiveTexture(GL_TEXTURE4); - glBindTexture(GL_TEXTURE_2D, sfbDepthTextures.get(0)); + GL13.glActiveTexture(GL13.GL_TEXTURE4); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbDepthTextures.get(0)); if (usedShadowDepthBuffers >= 2) { - glActiveTexture(GL_TEXTURE5); - glBindTexture(GL_TEXTURE_2D, sfbDepthTextures.get(1)); + GL13.glActiveTexture(GL13.GL_TEXTURE5); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbDepthTextures.get(1)); } } for (int i = 0; i < 4 && 4 + i < usedColorBuffers; ++i) { - glActiveTexture(GL_TEXTURE7 + i); - glBindTexture(GL_TEXTURE_2D, dfbColorTextures.get(4 + i)); + GL13.glActiveTexture(GL13.GL_TEXTURE7 + i); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(4 + i)); } - glActiveTexture(GL_TEXTURE6); - glBindTexture(GL_TEXTURE_2D, dfbDepthTextures.get(0)); + GL13.glActiveTexture(GL13.GL_TEXTURE6); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(0)); if (usedDepthBuffers >= 2) { - glActiveTexture(GL_TEXTURE11); - glBindTexture(GL_TEXTURE_2D, dfbDepthTextures.get(1)); + GL13.glActiveTexture(GL13.GL_TEXTURE11); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(1)); if (usedDepthBuffers >= 3) { - glActiveTexture(GL_TEXTURE12); - glBindTexture(GL_TEXTURE_2D, dfbDepthTextures.get(2)); + GL13.glActiveTexture(GL13.GL_TEXTURE12); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(2)); } } for (int i = 0; i < usedShadowColorBuffers; ++i) { - glActiveTexture(GL_TEXTURE13 + i); - glBindTexture(GL_TEXTURE_2D, sfbColorTextures.get(i)); + GL13.glActiveTexture(GL13.GL_TEXTURE13 + i); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbColorTextures.get(i)); } if (noiseTextureEnabled) { - glActiveTexture(GL_TEXTURE0 + noiseTexture.textureUnit); - glBindTexture(GL_TEXTURE_2D, noiseTexture.getID()); + GL13.glActiveTexture(GL13.GL_TEXTURE0 + noiseTexture.textureUnit); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, noiseTexture.getID()); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); } - glActiveTexture(GL_TEXTURE0); + GL13.glActiveTexture(GL13.GL_TEXTURE0); previousCameraPosition[0] = cameraPosition[0]; previousCameraPosition[1] = cameraPosition[1]; @@ -2491,13 +2006,13 @@ public static void beginRender(Minecraft minecraft, float f, long l) { shadowPassCounter = shadowPassInterval; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sfb); - glDrawBuffers(programsDrawBuffers[ProgramShadow]); + GL20.glDrawBuffers(programsDrawBuffers[ProgramShadow]); useProgram(ProgramShadow); mc.entityRenderer.renderWorld(f, l); - glFlush(); + GL11.glFlush(); isShadowPass = false; @@ -2507,45 +2022,45 @@ public static void beginRender(Minecraft minecraft, float f, long l) { if (hasGlGenMipmap) { if (usedShadowDepthBuffers >= 1) { if (shadowMipmapEnabled[0]) { - glActiveTexture(GL_TEXTURE4); - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri( - GL_TEXTURE_2D, - GL_TEXTURE_MIN_FILTER, - shadowFilterNearest[0] ? GL_NEAREST_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); + GL13.glActiveTexture(GL13.GL_TEXTURE4); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); + GL11.glTexParameteri( + GL11.GL_TEXTURE_2D, + GL11.GL_TEXTURE_MIN_FILTER, + shadowFilterNearest[0] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); } if (usedShadowDepthBuffers >= 2) { if (shadowMipmapEnabled[1]) { - glActiveTexture(GL_TEXTURE5); - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri( - GL_TEXTURE_2D, - GL_TEXTURE_MIN_FILTER, - shadowFilterNearest[1] ? GL_NEAREST_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); + GL13.glActiveTexture(GL13.GL_TEXTURE5); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); + GL11.glTexParameteri( + GL11.GL_TEXTURE_2D, + GL11.GL_TEXTURE_MIN_FILTER, + shadowFilterNearest[1] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); } } - glActiveTexture(GL_TEXTURE0); + GL13.glActiveTexture(GL13.GL_TEXTURE0); } if (usedShadowColorBuffers >= 1) { if (shadowColorMipmapEnabled[0]) { - glActiveTexture(GL_TEXTURE13); - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri( - GL_TEXTURE_2D, - GL_TEXTURE_MIN_FILTER, - shadowColorFilterNearest[0] ? GL_NEAREST_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); + GL13.glActiveTexture(GL13.GL_TEXTURE13); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); + GL11.glTexParameteri( + GL11.GL_TEXTURE_2D, + GL11.GL_TEXTURE_MIN_FILTER, + shadowColorFilterNearest[0] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); } if (usedShadowColorBuffers >= 2) { if (shadowColorMipmapEnabled[1]) { - glActiveTexture(GL_TEXTURE14); - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri( - GL_TEXTURE_2D, - GL_TEXTURE_MIN_FILTER, - shadowColorFilterNearest[1] ? GL_NEAREST_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); + GL13.glActiveTexture(GL13.GL_TEXTURE14); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); + GL11.glTexParameteri( + GL11.GL_TEXTURE_2D, + GL11.GL_TEXTURE_MIN_FILTER, + shadowColorFilterNearest[1] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); } } - glActiveTexture(GL_TEXTURE0); + GL13.glActiveTexture(GL13.GL_TEXTURE0); } } @@ -2596,52 +2111,36 @@ public static void setClearColor(float red, float green, float blue, float alpha } public static void clearRenderBuffer() { - // clearColorR = fogColorR; - // clearColorG = fogColorG; - // clearColorB = fogColorB; - if (isShadowPass) { - // No need to clear shadow depth 1. It will be overwritten. - // if (waterShadowEnabled) { - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, - // sfbDepthTextures.get(1), 0); - // glClear(GL_DEPTH_BUFFER_BIT); - // } checkGLError("shadow clear pre"); - glFramebufferTexture2DEXT( - GL_FRAMEBUFFER_EXT, - GL_DEPTH_ATTACHMENT_EXT, - GL_TEXTURE_2D, - sfbDepthTextures.get(0), - 0); - glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, sfbDepthTextures.get(0), 0); GL11.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // printIntBuffer(programsDrawBuffers[ProgramShadow]); - glDrawBuffers(programsDrawBuffers[ProgramShadow]); + GL20.glDrawBuffers(programsDrawBuffers[ProgramShadow]); checkFramebufferStatus("shadow clear"); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); checkGLError("shadow clear"); return; } checkGLError("clear pre"); /* - * glDrawBuffers(dfbDrawBuffers); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | - * GL_DEPTH_BUFFER_BIT); + * glDrawBuffers(dfbDrawBuffers); GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | + * GL11.GL_DEPTH_BUFFER_BIT); */ - glDrawBuffers(GL_COLOR_ATTACHMENT0_EXT); - // glClearColor(clearColorR, clearColorG, clearColorB, 1.0f); - // glClearColor(1f, 0f, 0f, 1.0f); // for debug - glClear(GL_COLOR_BUFFER_BIT); + GL20.glDrawBuffers(GL_COLOR_ATTACHMENT0_EXT); + // GL11.glClearColor(clearColorR, clearColorG, clearColorB, 1.0f); + // GL11.glClearColor(1f, 0f, 0f, 1.0f); // for debug + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); - glDrawBuffers(GL_COLOR_ATTACHMENT1_EXT); - glClearColor(1.0f, 1.0f, 1.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + GL20.glDrawBuffers(GL_COLOR_ATTACHMENT1_EXT); + GL11.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); for (int i = 2; i < usedColorBuffers; ++i) { - glDrawBuffers(GL_COLOR_ATTACHMENT0_EXT + i); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); + GL20.glDrawBuffers(GL_COLOR_ATTACHMENT0_EXT + i); + GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); } setDrawBuffers(dfbDrawBuffers); @@ -2660,39 +2159,33 @@ public static void setCamera(float f) { cameraPosition[1] = y; cameraPosition[2] = z; - glGetFloat(GL_PROJECTION_MATRIX, (FloatBuffer) projection.position(0)); + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, (FloatBuffer) projection.position(0)); invertMat4x((FloatBuffer) projection.position(0), (FloatBuffer) projectionInverse.position(0)); projection.position(0); projectionInverse.position(0); - glGetFloat(GL_MODELVIEW_MATRIX, (FloatBuffer) modelView.position(0)); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, (FloatBuffer) modelView.position(0)); invertMat4x((FloatBuffer) modelView.position(0), (FloatBuffer) modelViewInverse.position(0)); modelView.position(0); modelViewInverse.position(0); if (isShadowPass) { - glViewport(0, 0, shadowMapWidth, shadowMapHeight); + GL11.glViewport(0, 0, shadowMapWidth, shadowMapHeight); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glLoadIdentity(); if (shadowMapIsOrtho) { - glOrtho( - -shadowMapHalfPlane, - shadowMapHalfPlane, - -shadowMapHalfPlane, - shadowMapHalfPlane, - 0.05f, - 256.0f); + GL11.glOrtho( -shadowMapHalfPlane, shadowMapHalfPlane, -shadowMapHalfPlane, shadowMapHalfPlane, 0.05f, 256.0f); } else { // just backwards compatibility. it's only used when SHADOWFOV is set in the shaders. gluPerspective(shadowMapFOV, (float) shadowMapWidth / (float) shadowMapHeight, 0.05f, 256.0f); } - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.0f, 0.0f, -100.0f); - glRotatef(90.0f, 1.0f, 0.0f, 0.0f); + GL11.glMatrixMode(GL11.GL_MODELVIEW); + GL11.glLoadIdentity(); + GL11.glTranslatef(0.0f, 0.0f, -100.0f); + GL11.glRotatef(90.0f, 1.0f, 0.0f, 0.0f); float celestialAngle = mc.theWorld.getCelestialAngle(f); sunAngle = (celestialAngle < 0.75f) ? celestialAngle + 0.25f : celestialAngle - 0.75f; float angle = celestialAngle * (-360.0f); @@ -2701,28 +2194,28 @@ public static void setCamera(float f) { : 0.0f; if (sunAngle <= 0.5) { // day time - glRotatef(angle - angleInterval, 0.0f, 0.0f, 1.0f); - glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); // rotate + GL11.glRotatef(angle - angleInterval, 0.0f, 0.0f, 1.0f); + GL11.glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); // rotate shadowAngle = sunAngle; } else { // night time - glRotatef(angle + 180.0f - angleInterval, 0.0f, 0.0f, 1.0f); - glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); // rotate + GL11.glRotatef(angle + 180.0f - angleInterval, 0.0f, 0.0f, 1.0f); + GL11.glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); // rotate shadowAngle = sunAngle - 0.5f; } if (shadowMapIsOrtho) { // reduces jitter float trans = shadowIntervalSize; float trans2 = trans / 2.0f; - glTranslatef((float) x % trans - trans2, (float) y % trans - trans2, (float) z % trans - trans2); + GL11.glTranslatef((float) x % trans - trans2, (float) y % trans - trans2, (float) z % trans - trans2); } - glGetFloat(GL_PROJECTION_MATRIX, (FloatBuffer) shadowProjection.position(0)); + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, (FloatBuffer) shadowProjection.position(0)); invertMat4x((FloatBuffer) shadowProjection.position(0), (FloatBuffer) shadowProjectionInverse.position(0)); shadowProjection.position(0); shadowProjectionInverse.position(0); - glGetFloat(GL_MODELVIEW_MATRIX, (FloatBuffer) shadowModelView.position(0)); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, (FloatBuffer) shadowModelView.position(0)); invertMat4x((FloatBuffer) shadowModelView.position(0), (FloatBuffer) shadowModelViewInverse.position(0)); shadowModelView.position(0); shadowModelViewInverse.position(0); @@ -2757,7 +2250,7 @@ public static void postCelestialRotate() { // The sun is at (0, 100, 0), and the moon is at (0, -100, 0). FloatBuffer modelView = tempMatrixDirectBuffer; modelView.clear(); - glGetFloat(GL_MODELVIEW_MATRIX, modelView); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView); modelView.get(tempMat, 0, 16); multiplyMat4xVec4(tempMat, sunPosModelView, sunPosition); multiplyMat4xVec4(tempMat, moonPosModelView, moonPosition); @@ -2768,7 +2261,7 @@ public static void setUpPosition() { // Up direction in model view while rendering sky. FloatBuffer modelView = tempMatrixDirectBuffer; modelView.clear(); - glGetFloat(GL_MODELVIEW_MATRIX, modelView); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView); modelView.get(tempMat, 0, 16); multiplyMat4xVec4(tempMat, upPosModelView, upPosition); } @@ -2792,86 +2285,22 @@ private static FloatBuffer invertMat4x(FloatBuffer matIn, FloatBuffer invMatOut) matIn.get(m); - inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - - m[9] * m[6] * m[15] - + m[9] * m[7] * m[14] - + m[13] * m[6] * m[11] - - m[13] * m[7] * m[10]; - inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] - + m[8] * m[6] * m[15] - - m[8] * m[7] * m[14] - - m[12] * m[6] * m[11] - + m[12] * m[7] * m[10]; - inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - - m[8] * m[5] * m[15] - + m[8] * m[7] * m[13] - + m[12] * m[5] * m[11] - - m[12] * m[7] * m[9]; - inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] - + m[8] * m[5] * m[14] - - m[8] * m[6] * m[13] - - m[12] * m[5] * m[10] - + m[12] * m[6] * m[9]; - inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] - + m[9] * m[2] * m[15] - - m[9] * m[3] * m[14] - - m[13] * m[2] * m[11] - + m[13] * m[3] * m[10]; - inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - - m[8] * m[2] * m[15] - + m[8] * m[3] * m[14] - + m[12] * m[2] * m[11] - - m[12] * m[3] * m[10]; - inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] - + m[8] * m[1] * m[15] - - m[8] * m[3] * m[13] - - m[12] * m[1] * m[11] - + m[12] * m[3] * m[9]; - inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - - m[8] * m[1] * m[14] - + m[8] * m[2] * m[13] - + m[12] * m[1] * m[10] - - m[12] * m[2] * m[9]; - inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - - m[5] * m[2] * m[15] - + m[5] * m[3] * m[14] - + m[13] * m[2] * m[7] - - m[13] * m[3] * m[6]; - inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] - + m[4] * m[2] * m[15] - - m[4] * m[3] * m[14] - - m[12] * m[2] * m[7] - + m[12] * m[3] * m[6]; - inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - - m[4] * m[1] * m[15] - + m[4] * m[3] * m[13] - + m[12] * m[1] * m[7] - - m[12] * m[3] * m[5]; - inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] - + m[4] * m[1] * m[14] - - m[4] * m[2] * m[13] - - m[12] * m[1] * m[6] - + m[12] * m[2] * m[5]; - inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] - + m[5] * m[2] * m[11] - - m[5] * m[3] * m[10] - - m[9] * m[2] * m[7] - + m[9] * m[3] * m[6]; - inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - - m[4] * m[2] * m[11] - + m[4] * m[3] * m[10] - + m[8] * m[2] * m[7] - - m[8] * m[3] * m[6]; - inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] - + m[4] * m[1] * m[11] - - m[4] * m[3] * m[9] - - m[8] * m[1] * m[7] - + m[8] * m[3] * m[5]; - inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - - m[4] * m[1] * m[10] - + m[4] * m[2] * m[9] - + m[8] * m[1] * m[6] - - m[8] * m[2] * m[5]; + inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]; + inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10]; + inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9]; + inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9]; + inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10]; + inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]; + inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9]; + inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9]; + inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6]; + inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6]; + inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5]; + inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5]; + inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6]; + inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6]; + inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5]; + inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5]; det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]; @@ -2890,53 +2319,53 @@ private static FloatBuffer invertMat4x(FloatBuffer matIn, FloatBuffer invMatOut) public static void genCompositeMipmap() { if (hasGlGenMipmap) { if ((activeCompositeMipmapSetting & (1 << 0)) != 0) { - glActiveTexture(GL_TEXTURE0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glGenerateMipmap(GL_TEXTURE_2D); + GL13.glActiveTexture(GL13.GL_TEXTURE0); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); } if ((activeCompositeMipmapSetting & (1 << 1)) != 0) { - glActiveTexture(GL_TEXTURE1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glGenerateMipmap(GL_TEXTURE_2D); + GL13.glActiveTexture(GL13.GL_TEXTURE1); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); } if ((activeCompositeMipmapSetting & (1 << 2)) != 0) { - glActiveTexture(GL_TEXTURE2); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glGenerateMipmap(GL_TEXTURE_2D); + GL13.glActiveTexture(GL13.GL_TEXTURE2); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); } if ((activeCompositeMipmapSetting & (1 << 3)) != 0) { - glActiveTexture(GL_TEXTURE3); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glGenerateMipmap(GL_TEXTURE_2D); + GL13.glActiveTexture(GL13.GL_TEXTURE3); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); } for (int i = 0; i < 4 && 4 + i < usedColorBuffers; ++i) { if ((activeCompositeMipmapSetting & ((1 << 4) << i)) != 0) { - glActiveTexture(GL_TEXTURE7 + i); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glGenerateMipmap(GL_TEXTURE_2D); + GL13.glActiveTexture(GL13.GL_TEXTURE7 + i); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); + GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); } } - glActiveTexture(GL_TEXTURE0); + GL13.glActiveTexture(GL13.GL_TEXTURE0); } } public static void drawComposite() { - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0.0f); - glVertex3f(0.0f, 0.0f, 0.0f); - glTexCoord2f(1.0f, 0.0f); - glVertex3f(1.0f, 0.0f, 0.0f); - glTexCoord2f(1.0f, 1.0f); - glVertex3f(1.0f, 1.0f, 0.0f); - glTexCoord2f(0.0f, 1.0f); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GL11.glBegin(GL11.GL_QUADS); + GL11.glTexCoord2f(0.0f, 0.0f); + GL11.glVertex3f(0.0f, 0.0f, 0.0f); + GL11.glTexCoord2f(1.0f, 0.0f); + GL11.glVertex3f(1.0f, 0.0f, 0.0f); + GL11.glTexCoord2f(1.0f, 1.0f); + GL11.glVertex3f(1.0f, 1.0f, 0.0f); + GL11.glTexCoord2f(0.0f, 1.0f); + GL11.glVertex3f(0.0f, 1.0f, 0.0f); + GL11.glEnd(); } public static void renderCompositeFinal() { @@ -2946,94 +2375,89 @@ public static void renderCompositeFinal() { } checkGLError("pre-renderCompositeFinal"); - // fogColorR = clearColorR; - // fogColorG = clearColorG; - // fogColorB = clearColorB; - - // glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); - - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glEnable(GL_TEXTURE_2D); - glDisable(GL_ALPHA_TEST); - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glDepthMask(false); + GL11.glPushMatrix(); + GL11.glLoadIdentity(); + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glPushMatrix(); + GL11.glLoadIdentity(); + GL11.glOrtho(0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); + + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_ALPHA_TEST); + GL11.glDisable(GL11.GL_BLEND); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glDepthFunc(GL11.GL_ALWAYS); + GL11.glDepthMask(false); // textures - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, dfbColorTextures.get(0)); + GL13.glActiveTexture(GL13.GL_TEXTURE0); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(0)); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, dfbColorTextures.get(1)); + GL13.glActiveTexture(GL13.GL_TEXTURE1); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(1)); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, dfbColorTextures.get(2)); + GL13.glActiveTexture(GL13.GL_TEXTURE2); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(2)); - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, dfbColorTextures.get(3)); + GL13.glActiveTexture(GL13.GL_TEXTURE3); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(3)); if (usedShadowDepthBuffers >= 1) { - glActiveTexture(GL_TEXTURE4); - glBindTexture(GL_TEXTURE_2D, sfbDepthTextures.get(0)); + GL13.glActiveTexture(GL13.GL_TEXTURE4); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbDepthTextures.get(0)); if (usedShadowDepthBuffers >= 2) { - glActiveTexture(GL_TEXTURE5); - glBindTexture(GL_TEXTURE_2D, sfbDepthTextures.get(1)); + GL13.glActiveTexture(GL13.GL_TEXTURE5); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbDepthTextures.get(1)); } } for (int i = 0; i < 4 && 4 + i < usedColorBuffers; ++i) { - glActiveTexture(GL_TEXTURE7 + i); - glBindTexture(GL_TEXTURE_2D, dfbColorTextures.get(4 + i)); + GL13.glActiveTexture(GL13.GL_TEXTURE7 + i); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(4 + i)); } - glActiveTexture(GL_TEXTURE6); - glBindTexture(GL_TEXTURE_2D, dfbDepthTextures.get(0)); + GL13.glActiveTexture(GL13.GL_TEXTURE6); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(0)); if (usedDepthBuffers >= 2) { - glActiveTexture(GL_TEXTURE11); - glBindTexture(GL_TEXTURE_2D, dfbDepthTextures.get(1)); + GL13.glActiveTexture(GL13.GL_TEXTURE11); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(1)); if (usedDepthBuffers >= 3) { - glActiveTexture(GL_TEXTURE12); - glBindTexture(GL_TEXTURE_2D, dfbDepthTextures.get(2)); + GL13.glActiveTexture(GL13.GL_TEXTURE12); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(2)); } } for (int i = 0; i < usedShadowColorBuffers; ++i) { - glActiveTexture(GL_TEXTURE13 + i); - glBindTexture(GL_TEXTURE_2D, sfbColorTextures.get(i)); + GL13.glActiveTexture(GL13.GL_TEXTURE13 + i); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbColorTextures.get(i)); } if (noiseTextureEnabled) { - glActiveTexture(GL_TEXTURE0 + noiseTexture.textureUnit); - glBindTexture(GL_TEXTURE_2D, noiseTexture.getID()); + GL13.glActiveTexture(GL13.GL_TEXTURE0 + noiseTexture.textureUnit); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, noiseTexture.getID()); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); } - glActiveTexture(GL_TEXTURE0); + GL13.glActiveTexture(GL13.GL_TEXTURE0); // set depth buffer glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_TEXTURE_2D, + GL11.GL_TEXTURE_2D, dfbDepthTextures.get(0), 0); // detach depth buffer - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0); + // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, 0, 0); // composite - glDrawBuffers(dfbDrawBuffers); + GL20.glDrawBuffers(dfbDrawBuffers); checkGLError("pre-composite"); for (int i = 0; i < MaxCompositePasses; ++i) { @@ -3046,7 +2470,7 @@ public static void renderCompositeFinal() { } // reattach depth buffer - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, dfbDepthTexture, 0); + // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, dfbDepthTexture, 0); // final render target isRenderingDfb = false; @@ -3055,18 +2479,18 @@ public static void renderCompositeFinal() { mc.getFramebuffer().bindFramebuffer(true); if (EntityRenderer.anaglyphEnable) { boolean maskR = (EntityRenderer.anaglyphField != 0); - glColorMask(maskR, !maskR, !maskR, true); - } - glDepthMask(true); - glClearColor(clearColorR, clearColorG, clearColorB, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glEnable(GL_TEXTURE_2D); - glDisable(GL_ALPHA_TEST); - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glDepthMask(false); + GL11.glColorMask(maskR, !maskR, !maskR, true); + } + GL11.glDepthMask(true); + GL11.glClearColor(clearColorR, clearColorG, clearColorB, 1.0f); + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_ALPHA_TEST); + GL11.glDisable(GL11.GL_BLEND); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glDepthFunc(GL11.GL_ALWAYS); + GL11.glDepthMask(false); // final checkGLError("pre-final"); @@ -3083,16 +2507,16 @@ public static void renderCompositeFinal() { // end checkGLError("renderCompositeFinal"); isCompositeRendered = true; - glEnable(GL_TEXTURE_2D); - glEnable(GL_ALPHA_TEST); - glEnable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glDepthMask(true); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glEnable(GL11.GL_BLEND); + GL11.glDepthFunc(GL11.GL_LEQUAL); + GL11.glDepthMask(true); - // glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + // GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glPopMatrix(); + GL11.glMatrixMode(GL11.GL_MODELVIEW); + GL11.glPopMatrix(); useProgram(ProgramNone); } @@ -3107,8 +2531,8 @@ public static void endRender() { if (!isCompositeRendered) renderCompositeFinal(); isRenderingWorld = false; - glColorMask(true, true, true, true); - glEnable(GL_BLEND); + GL11.glColorMask(true, true, true, true); + GL11.glEnable(GL11.GL_BLEND); useProgram(ProgramNone); checkGLError("endRender end"); @@ -3193,11 +2617,11 @@ public static void drawHorizon() { public static void preSkyList() { GL11.glColor3f(fogColorR, fogColorG, fogColorB); // GL11.glColor3f(0f, 1f, 0f); - // glDisable(GL_FOG); + // GL11.glDisable(GL11.GL_FOG); drawHorizon(); - // glEnable(GL_FOG); + // GL11.glEnable(GL11.GL_FOG); GL11.glColor3f(skyColorR, skyColorG, skyColorB); } @@ -3256,7 +2680,7 @@ public static void endClouds() { public static void beginTerrain() { if (isRenderingWorld) { if (isShadowPass) { - glDisable(GL11.GL_CULL_FACE); + GL11.glDisable(GL11.GL_CULL_FACE); } fogEnabled = true; useProgram(Shaders.ProgramTerrain); @@ -3267,7 +2691,7 @@ public static void beginTerrain() { public static void endTerrain() { if (isRenderingWorld) { if (isShadowPass) { - glEnable(GL11.GL_CULL_FACE); + GL11.glEnable(GL11.GL_CULL_FACE); } useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); // ShadersTex.bindNSTextures(defaultTexture.getMultiTexID()); // flat @@ -3294,7 +2718,7 @@ public static void beginBlockDestroyProgress() { useProgram(ProgramTerrain); if (Shaders.configTweakBlockDamage) { setDrawBuffers(drawBuffersColorAtt0); - glDepthMask(false); + GL11.glDepthMask(false); // GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA,GL11.GL_ONE,GL11.GL_ZERO); } } @@ -3302,7 +2726,7 @@ public static void beginBlockDestroyProgress() { public static void endBlockDestroyProgress() { if (isRenderingWorld) { - glDepthMask(true); + GL11.glDepthMask(true); useProgram(ProgramTexturedLit); } } @@ -3394,46 +2818,25 @@ public static void preWater() { if (isShadowPass) { if (usedShadowDepthBuffers >= 2) { // copy depth buffer to shadowtex1 - glActiveTexture(GL_TEXTURE5); + GL13.glActiveTexture(GL13.GL_TEXTURE5); checkGLError("pre copy shadow depth"); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowMapWidth, shadowMapHeight); + GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowMapWidth, shadowMapHeight); checkGLError("copy shadow depth"); - glActiveTexture(GL_TEXTURE0); + GL13.glActiveTexture(GL13.GL_TEXTURE0); } } else { if (usedDepthBuffers >= 2) { // copy depth buffer to depthtex1 - glActiveTexture(GL_TEXTURE11); + GL13.glActiveTexture(GL13.GL_TEXTURE11); checkGLError("pre copy depth"); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, renderWidth, renderHeight); + GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, renderWidth, renderHeight); checkGLError("copy depth"); - glActiveTexture(GL_TEXTURE0); + GL13.glActiveTexture(GL13.GL_TEXTURE0); } ShadersTex.bindNSTextures(defaultTexture.angelica$getMultiTexID()); // flat } } - // public static void beginWaterFancy() { - // if (isRenderingWorld) - // { - // if (!isShadowPass) { - // // program water - // useProgram(Shaders.ProgramWater); - // GL11.glEnable(GL11.GL_BLEND); - // //setDrawBuffers(drawBuffersNone); - // } - // } - // } - // - // public static void midWaterFancy() { - // if (isRenderingWorld) - // { - // if (!isShadowPass) { - // setDrawBuffers(programsDrawBuffers[Shaders.ProgramWater]); - // } - // } - // } - public static void beginWater() { if (isRenderingWorld) { if (!isShadowPass) { @@ -3450,10 +2853,10 @@ public static void beginWater() { public static void endWater() { if (isRenderingWorld) { if (isShadowPass) { - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, + // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, // sfbDepthTexture, 0); } else { - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, + // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, // dfbDepthTexture, 0); } useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); @@ -3465,14 +2868,7 @@ public static void readCenterDepth() { // Read depth buffer at center of screen for DOF if (centerDepthSmoothEnabled) { tempDirectFloatBuffer.clear(); - glReadPixels( - renderWidth / 2, - renderHeight / 2, - 1, - 1, - GL11.GL_DEPTH_COMPONENT, - GL11.GL_FLOAT, - tempDirectFloatBuffer); + GL11.glReadPixels( renderWidth / 2, renderHeight / 2, 1, 1, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, tempDirectFloatBuffer); centerDepth = tempDirectFloatBuffer.get(0); // Smooth depth value @@ -3487,17 +2883,17 @@ public static void beginWeather() { if (!isShadowPass) { if (usedDepthBuffers >= 3) { // copy depth buffer to depthtex2 - glActiveTexture(GL_TEXTURE12); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, renderWidth, renderHeight); - glActiveTexture(GL_TEXTURE0); + GL13.glActiveTexture(GL13.GL_TEXTURE12); + GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, renderWidth, renderHeight); + GL13.glActiveTexture(GL13.GL_TEXTURE0); } // GL11.glDepthMask(false); - glEnable(GL_DEPTH_TEST); - glEnable(GL_BLEND); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_ALPHA_TEST); + GL11.glEnable(GL11.GL_ALPHA_TEST); useProgram(Shaders.ProgramWeather); - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, + // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, // dfbWaterDepthTexture, 0); } @@ -3508,9 +2904,9 @@ public static void beginWeather() { public static void endWeather() { // GL11.glDepthMask(true); - glDisable(GL_BLEND); + GL11.glDisable(GL11.GL_BLEND); useProgram(ProgramTexturedLit); - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, dfbDepthTexture, 0); + // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, dfbDepthTexture, 0); // if (isShadowPass) { // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sfb); // was set to 0 in beginWeather() @@ -3532,26 +2928,26 @@ public static void applyHandDepth() { } public static void beginHand() { - // glEnable(GL_BLEND); - // glDisable(GL_BLEND); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); + // GL11.glEnable(GL11.GL_BLEND); + // GL11.glDisable(GL11.GL_BLEND); + GL11.glMatrixMode(GL11.GL_MODELVIEW); + GL11.glPushMatrix(); + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glPushMatrix(); + GL11.glMatrixMode(GL11.GL_MODELVIEW); useProgram(Shaders.ProgramHand); checkGLError("beginHand"); checkFramebufferStatus("beginHand"); } public static void endHand() { - // glDisable(GL_BLEND); + // GL11.glDisable(GL11.GL_BLEND); checkGLError("pre endHand"); checkFramebufferStatus("pre endHand"); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glPopMatrix(); + GL11.glMatrixMode(GL11.GL_MODELVIEW); + GL11.glPopMatrix(); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); // useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); checkGLError("endHand"); @@ -3570,34 +2966,34 @@ public static void endFPOverlay() { // ---------------------------------------- public static void glEnableWrapper(int cap) { - glEnable(cap); - if (cap == GL_TEXTURE_2D) enableTexture2D(); - else if (cap == GL_FOG) enableFog(); + GL11.glEnable(cap); + if (cap == GL11.GL_TEXTURE_2D) enableTexture2D(); + else if (cap == GL11.GL_FOG) enableFog(); } public static void glDisableWrapper(int cap) { - glDisable(cap); - if (cap == GL_TEXTURE_2D) disableTexture2D(); - else if (cap == GL_FOG) disableFog(); + GL11.glDisable(cap); + if (cap == GL11.GL_TEXTURE_2D) disableTexture2D(); + else if (cap == GL11.GL_FOG) disableFog(); } - public static void sglEnableT2D(int cap) { - glEnable(cap); // GL_TEXTURE_2D + public static void glEnableT2D(int cap) { + GL11.glEnable(cap); // GL11.GL_TEXTURE_2D enableTexture2D(); } - public static void sglDisableT2D(int cap) { - glDisable(cap); // GL_TEXTURE_2D + public static void glDisableT2D(int cap) { + GL11.glDisable(cap); // GL11.GL_TEXTURE_2D disableTexture2D(); } - public static void sglEnableFog(int cap) { - glEnable(cap); // GL_FOG + public static void glEnableFog(int cap) { + GL11.glEnable(cap); // GL11.GL_FOG enableFog(); } - public static void sglDisableFog(int cap) { - glDisable(cap); // GL_FOG + public static void glDisableFog(int cap) { + GL11.glDisable(cap); // GL11.GL_FOG disableFog(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShaders.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShaders.java index cf31da1ea..fee4c55f2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShaders.java @@ -247,19 +247,18 @@ protected void actionPerformed(GuiButton guiButton) { default: break; } - boolean var8 = false; + boolean openViaSystemClass = false; try { - Class var3 = Class.forName("java.awt.Desktop"); - Object var4 = var3.getMethod("getDesktop").invoke((Object) null); - var3.getMethod("browse", URI.class).invoke( - var4, (new File(mc.mcDataDir, Shaders.shaderpacksdirname)).toURI()); + Class aClass = Class.forName("java.awt.Desktop"); + Object getDesktop = aClass.getMethod("getDesktop").invoke((Object) null); + aClass.getMethod("browse", URI.class).invoke(getDesktop, (new File(mc.mcDataDir, Shaders.shaderpacksdirname)).toURI()); } catch (Throwable var5) { var5.printStackTrace(); - var8 = true; + openViaSystemClass = true; } - if (var8) { + if (openViaSystemClass) { AngelicaTweaker.LOGGER.debug("Opening via system class!"); Sys.openURL("file://" + Shaders.shaderpacksdir.getAbsolutePath()); } diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index 5810e2d97..01ba321e3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -1,5 +1,7 @@ package com.gtnewhorizons.angelica.loading; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -11,8 +13,13 @@ import com.google.common.collect.ImmutableMap; import com.gtnewhorizons.angelica.mixins.ArchaicMixins; import com.gtnewhorizons.angelica.mixins.TargetedMod; +import net.minecraft.client.Minecraft; +import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; import org.embeddedt.archaicfix.config.ArchaicConfig; import org.embeddedt.archaicfix.config.ConfigException; import org.embeddedt.archaicfix.config.ConfigurationManager; @@ -30,9 +37,18 @@ public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader { public static final Logger LOGGER = LogManager.getLogger("angelica"); +// public static boolean ENABLE_SPAM = false; // Enable for more spam + public static boolean ENABLE_SPAM = true; + static { try { + // ArchaicFix Config ConfigurationManager.registerConfig(ArchaicConfig.class); + LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + Configuration config = ctx.getConfiguration(); + LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME); + loggerConfig.setLevel(Level.DEBUG); + ctx.updateLoggers(); } catch (ConfigException e) { throw new RuntimeException(e); } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java index 76566d6fb..451db5bc4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java @@ -17,7 +17,7 @@ public class ACTEntityRenderer implements IClassTransformer { @Override public byte[] transform(String name, String transformedName, byte[] basicClass) { - AngelicaTweaker.LOGGER.debug("transforming %s %s", name, transformedName); + AngelicaTweaker.LOGGER.debug("transforming {} {}", name, transformedName); ClassReader cr = new ClassReader(basicClass); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); CVTransform cv = new CVTransform(cw); @@ -43,7 +43,7 @@ public void visit(int version, int access, String name, String signature, String @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if (Names.entityRenderer_renderHand.equalsNameDesc(name, desc)) { - AngelicaTweaker.LOGGER.trace(" patching method %s.%s%s", classname, name, desc); + AngelicaTweaker.LOGGER.trace(" patching method {}.{}{}", classname, name, desc); return new MVrenderHand(cv.visitMethod(access, name, desc, signature, exceptions)); } return cv.visitMethod(access, name, desc, signature, exceptions); @@ -63,11 +63,7 @@ public MVrenderHand(MethodVisitor mv) { public void visitMethodInsn(int opcode, String owner, String name, String desc) { // Wraps the code from GL11.glPushMatrix() to GL11.glPopMatrix() in an if(!Shaders.isHandRendered) check if (Names.equals("org/lwjgl/opengl/GL11", "glPushMatrix", "()V", owner, name, desc)) { - mv.visitFieldInsn( - Opcodes.GETSTATIC, - "com/gtnewhorizons/angelica/client/Shaders", - "isHandRendered", - "Z"); + mv.visitFieldInsn(Opcodes.GETSTATIC, "com/gtnewhorizons/angelica/client/Shaders", "isHandRendered", "Z"); mv.visitJumpInsn(Opcodes.IFNE, label); mv.visitMethodInsn(opcode, owner, name, desc); return; diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java index 536f091fe..e56bfa424 100644 --- a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java +++ b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java @@ -123,22 +123,15 @@ private static AxisDirection getAxisDirection(final EnumFacing dir, final int x, } private static EnumFacing getOpposite(EnumFacing in) { - switch(in) { - case NORTH: - return EnumFacing.SOUTH; - case SOUTH: - return EnumFacing.NORTH; - case EAST: - return EnumFacing.WEST; - case WEST: - return EnumFacing.EAST; - case DOWN: - return EnumFacing.UP; - case UP: - return EnumFacing.DOWN; - default: - throw new IllegalArgumentException(); - } + return switch (in) { + case NORTH -> EnumFacing.SOUTH; + case SOUTH -> EnumFacing.NORTH; + case EAST -> EnumFacing.WEST; + case WEST -> EnumFacing.EAST; + case DOWN -> EnumFacing.UP; + case UP -> EnumFacing.DOWN; + default -> throw new IllegalArgumentException(); + }; } private static AxisDirection getAxisDirection(EnumFacing in) { diff --git a/src/main/java/speiger/src/collections/booleans/functions/BooleanComparator.java b/src/main/java/speiger/src/collections/booleans/functions/BooleanComparator.java deleted file mode 100644 index 7c33854a8..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/BooleanComparator.java +++ /dev/null @@ -1,70 +0,0 @@ -package speiger.src.collections.booleans.functions; - -import java.util.Comparator; -import java.util.Objects; - -/** - * Type-Specific Class for Comparator to reduce (un)boxing - */ -public interface BooleanComparator extends Comparator -{ - /** - * Type-Specific compare function to reduce (un)boxing - * @param o1 the first object to be compared. - * @param o2 the second object to be compared. - * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. - * @see Comparator#compare(Object, Object) - */ - int compare(boolean o1, boolean o2); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default int compare(Boolean o1, Boolean o2) { - return compare(o1.booleanValue(), o2.booleanValue()); - } - - /** - * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator - * @param c comparator to convert - * @return the wrapper of the comparator - * @throws NullPointerException if the comparator is null - */ - public static BooleanComparator of(Comparator c) { - Objects.requireNonNull(c); - return (K, V) -> c.compare(Boolean.valueOf(K), Boolean.valueOf(V)); - } - - @Override - public default BooleanComparator reversed() { - return new Reversed(this); - } - - /** - * A Type Specific Reversed Comparator to reduce boxing/unboxing - */ - static class Reversed implements BooleanComparator - { - BooleanComparator original; - - /** - * default constructor - * @param original that is going to be reversed - */ - public Reversed(BooleanComparator original) { - this.original = original; - } - - public int compare(boolean o1, boolean o2) { - return original.compare(o2, o1); - } - - @Override - public BooleanComparator reversed() { - return original; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/BooleanConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/BooleanConsumer.java deleted file mode 100644 index c1bae90d4..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/BooleanConsumer.java +++ /dev/null @@ -1,48 +0,0 @@ -package speiger.src.collections.booleans.functions; - -import java.util.Objects; -import java.util.function.Consumer; -/** - * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -@FunctionalInterface -public interface BooleanConsumer extends Consumer -{ - /** - * Type-Specific function to reduce (un)boxing. - * Performs this operation on the given argument. - * - * @param t the input argument - */ - void accept(boolean t); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced consumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default BooleanConsumer andThen(BooleanConsumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(T);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Boolean t) { accept(t.booleanValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default BooleanConsumer andThen(Consumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(Boolean.valueOf(T));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/BooleanSupplier.java b/src/main/java/speiger/src/collections/booleans/functions/BooleanSupplier.java deleted file mode 100644 index ea1f2dcc5..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/BooleanSupplier.java +++ /dev/null @@ -1,12 +0,0 @@ -package speiger.src.collections.booleans.functions; - -/** - * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -public interface BooleanSupplier -{ - /** - * @return the supplied value - */ - public boolean getAsBoolean(); -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanBooleanConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanBooleanConsumer.java deleted file mode 100644 index edc30210f..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanBooleanConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.booleans.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface BooleanBooleanConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(boolean k, boolean v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default BooleanBooleanConsumer andThen(BooleanBooleanConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Boolean k, Boolean v) { accept(k.booleanValue(), v.booleanValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default BooleanBooleanConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Boolean.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanByteConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanByteConsumer.java deleted file mode 100644 index 5304d1866..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanByteConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.booleans.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface BooleanByteConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(boolean k, byte v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default BooleanByteConsumer andThen(BooleanByteConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Boolean k, Byte v) { accept(k.booleanValue(), v.byteValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default BooleanByteConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Byte.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanCharConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanCharConsumer.java deleted file mode 100644 index 46bfe23a5..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanCharConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.booleans.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface BooleanCharConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(boolean k, char v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default BooleanCharConsumer andThen(BooleanCharConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Boolean k, Character v) { accept(k.booleanValue(), v.charValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default BooleanCharConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Character.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanDoubleConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanDoubleConsumer.java deleted file mode 100644 index 2b03c5b36..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanDoubleConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.booleans.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface BooleanDoubleConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(boolean k, double v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default BooleanDoubleConsumer andThen(BooleanDoubleConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Boolean k, Double v) { accept(k.booleanValue(), v.doubleValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default BooleanDoubleConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Double.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanFloatConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanFloatConsumer.java deleted file mode 100644 index 26d150783..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanFloatConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.booleans.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface BooleanFloatConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(boolean k, float v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default BooleanFloatConsumer andThen(BooleanFloatConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Boolean k, Float v) { accept(k.booleanValue(), v.floatValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default BooleanFloatConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Float.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanIntConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanIntConsumer.java deleted file mode 100644 index 1268cc6c1..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanIntConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.booleans.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface BooleanIntConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(boolean k, int v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default BooleanIntConsumer andThen(BooleanIntConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Boolean k, Integer v) { accept(k.booleanValue(), v.intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default BooleanIntConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Integer.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanLongConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanLongConsumer.java deleted file mode 100644 index bd7c17fb2..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanLongConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.booleans.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface BooleanLongConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(boolean k, long v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default BooleanLongConsumer andThen(BooleanLongConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Boolean k, Long v) { accept(k.booleanValue(), v.longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default BooleanLongConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Long.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanObjectConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanObjectConsumer.java deleted file mode 100644 index 8cda2d073..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanObjectConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.booleans.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface BooleanObjectConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(boolean k, V v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default BooleanObjectConsumer andThen(BooleanObjectConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Boolean k, V v) { accept(k.booleanValue(), v); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default BooleanObjectConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), V);}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanShortConsumer.java b/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanShortConsumer.java deleted file mode 100644 index 9169b38c3..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/consumer/BooleanShortConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.booleans.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface BooleanShortConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(boolean k, short v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default BooleanShortConsumer andThen(BooleanShortConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Boolean k, Short v) { accept(k.booleanValue(), v.shortValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default BooleanShortConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Boolean.valueOf(K), Short.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ByteFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ByteFunction.java deleted file mode 100644 index e54db5048..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ByteFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Boolean2ByteFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public byte applyAsByte(boolean k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2CharFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2CharFunction.java deleted file mode 100644 index 3b17a61f4..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2CharFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Boolean2CharFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public char applyAsChar(boolean k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2DoubleFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2DoubleFunction.java deleted file mode 100644 index 312b9bc7c..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2DoubleFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Boolean2DoubleFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public double applyAsDouble(boolean k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2FloatFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2FloatFunction.java deleted file mode 100644 index 1be0cdff6..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2FloatFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Boolean2FloatFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public float applyAsFloat(boolean k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2IntFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2IntFunction.java deleted file mode 100644 index 145f4fa7d..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2IntFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Boolean2IntFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public int applyAsInt(boolean k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2LongFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2LongFunction.java deleted file mode 100644 index dc27b5080..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2LongFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Boolean2LongFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public long applyAsLong(boolean k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ShortFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ShortFunction.java deleted file mode 100644 index 0061ac27c..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/Boolean2ShortFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Boolean2ShortFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public short applyAsShort(boolean k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanBooleanUnaryOperator.java deleted file mode 100644 index 921b6718d..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanBooleanUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface BooleanBooleanUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public boolean applyAsBoolean(boolean k, boolean v); - - @Override - public default Boolean apply(Boolean k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.booleanValue(), v.booleanValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanByteUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanByteUnaryOperator.java deleted file mode 100644 index 967a61f3f..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanByteUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface BooleanByteUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public byte applyAsByte(boolean k, byte v); - - @Override - public default Byte apply(Boolean k, Byte v) { return Byte.valueOf(applyAsByte(k.booleanValue(), v.byteValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanCharUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanCharUnaryOperator.java deleted file mode 100644 index 1af5f651f..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanCharUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface BooleanCharUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public char applyAsChar(boolean k, char v); - - @Override - public default Character apply(Boolean k, Character v) { return Character.valueOf(applyAsChar(k.booleanValue(), v.charValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanDoubleUnaryOperator.java deleted file mode 100644 index b63f208dc..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanDoubleUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface BooleanDoubleUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public double applyAsDouble(boolean k, double v); - - @Override - public default Double apply(Boolean k, Double v) { return Double.valueOf(applyAsDouble(k.booleanValue(), v.doubleValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFloatUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFloatUnaryOperator.java deleted file mode 100644 index 9c6e05102..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFloatUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface BooleanFloatUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public float applyAsFloat(boolean k, float v); - - @Override - public default Float apply(Boolean k, Float v) { return Float.valueOf(applyAsFloat(k.booleanValue(), v.floatValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFunction.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFunction.java deleted file mode 100644 index ba141ca6b..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface BooleanFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public V apply(boolean k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanIntUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanIntUnaryOperator.java deleted file mode 100644 index d75ace711..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanIntUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface BooleanIntUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public int applyAsInt(boolean k, int v); - - @Override - public default Integer apply(Boolean k, Integer v) { return Integer.valueOf(applyAsInt(k.booleanValue(), v.intValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanLongUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanLongUnaryOperator.java deleted file mode 100644 index 43fdeda94..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanLongUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface BooleanLongUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public long applyAsLong(boolean k, long v); - - @Override - public default Long apply(Boolean k, Long v) { return Long.valueOf(applyAsLong(k.booleanValue(), v.longValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanObjectUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanObjectUnaryOperator.java deleted file mode 100644 index 6f6cdc12a..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanObjectUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface BooleanObjectUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public V apply(boolean k, V v); - - @Override - public default V apply(Boolean k, V v) { return apply(k.booleanValue(), v); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanPredicate.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanPredicate.java deleted file mode 100644 index b8e690fe8..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanPredicate.java +++ /dev/null @@ -1,98 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface BooleanPredicate -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public boolean test(boolean k); - - /** - * Creates a Default function that returns the input provided. - * @return a input returning function - */ - public static BooleanPredicate identity() { - return T -> T; - } - - /** - * Returns a composed function that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param before the function that should be used first - * @return a composed function with a different starting function. - */ - public default BooleanPredicate compose(BooleanPredicate before) { - Objects.requireNonNull(before); - return T -> test(before.test(T)); - } - - /** - * Returns a composed function that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param after the function that should be used last - * @return a composed function with a different starting function. - */ - public default BooleanPredicate andThen(BooleanPredicate after) { - Objects.requireNonNull(after); - return T -> after.test(test(T)); - } - - /** - * Creates a Always true function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static BooleanPredicate alwaysTrue() { - return T -> true; - } - - /** - * Creates a Always false function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static BooleanPredicate alwaysFalse() { - return T -> false; - } - - /** - * A Type specific and-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a and comparason - */ - public default BooleanPredicate andType(BooleanPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - /** - * A type specific inverter function - * @return the same function but inverts the result - */ - public default BooleanPredicate negate() { - return T -> !test(T); - } - - /** - * A Type specific or-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a or comparason - */ - public default BooleanPredicate orType(BooleanPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanShortUnaryOperator.java b/src/main/java/speiger/src/collections/booleans/functions/function/BooleanShortUnaryOperator.java deleted file mode 100644 index 5ebb8b2a6..000000000 --- a/src/main/java/speiger/src/collections/booleans/functions/function/BooleanShortUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.booleans.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface BooleanShortUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public short applyAsShort(boolean k, short v); - - @Override - public default Short apply(Boolean k, Short v) { return Short.valueOf(applyAsShort(k.booleanValue(), v.shortValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/ByteComparator.java b/src/main/java/speiger/src/collections/bytes/functions/ByteComparator.java deleted file mode 100644 index bd37bb208..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/ByteComparator.java +++ /dev/null @@ -1,70 +0,0 @@ -package speiger.src.collections.bytes.functions; - -import java.util.Comparator; -import java.util.Objects; - -/** - * Type-Specific Class for Comparator to reduce (un)boxing - */ -public interface ByteComparator extends Comparator -{ - /** - * Type-Specific compare function to reduce (un)boxing - * @param o1 the first object to be compared. - * @param o2 the second object to be compared. - * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. - * @see Comparator#compare(Object, Object) - */ - int compare(byte o1, byte o2); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default int compare(Byte o1, Byte o2) { - return compare(o1.byteValue(), o2.byteValue()); - } - - /** - * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator - * @param c comparator to convert - * @return the wrapper of the comparator - * @throws NullPointerException if the comparator is null - */ - public static ByteComparator of(Comparator c) { - Objects.requireNonNull(c); - return (K, V) -> c.compare(Byte.valueOf(K), Byte.valueOf(V)); - } - - @Override - public default ByteComparator reversed() { - return new Reversed(this); - } - - /** - * A Type Specific Reversed Comparator to reduce boxing/unboxing - */ - static class Reversed implements ByteComparator - { - ByteComparator original; - - /** - * default constructor - * @param original that is going to be reversed - */ - public Reversed(ByteComparator original) { - this.original = original; - } - - public int compare(byte o1, byte o2) { - return original.compare(o2, o1); - } - - @Override - public ByteComparator reversed() { - return original; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/ByteConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/ByteConsumer.java deleted file mode 100644 index 9b4007dd3..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/ByteConsumer.java +++ /dev/null @@ -1,48 +0,0 @@ -package speiger.src.collections.bytes.functions; - -import java.util.Objects; -import java.util.function.Consumer; -/** - * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -@FunctionalInterface -public interface ByteConsumer extends Consumer -{ - /** - * Type-Specific function to reduce (un)boxing. - * Performs this operation on the given argument. - * - * @param t the input argument - */ - void accept(byte t); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced consumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ByteConsumer andThen(ByteConsumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(T);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Byte t) { accept(t.byteValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ByteConsumer andThen(Consumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(Byte.valueOf(T));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/ByteSupplier.java b/src/main/java/speiger/src/collections/bytes/functions/ByteSupplier.java deleted file mode 100644 index de0e3f6c6..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/ByteSupplier.java +++ /dev/null @@ -1,12 +0,0 @@ -package speiger.src.collections.bytes.functions; - -/** - * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -public interface ByteSupplier -{ - /** - * @return the supplied value - */ - public byte getAsInt(); -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteBooleanConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteBooleanConsumer.java deleted file mode 100644 index 8022f911d..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteBooleanConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.bytes.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ByteBooleanConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(byte k, boolean v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ByteBooleanConsumer andThen(ByteBooleanConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Byte k, Boolean v) { accept(k.byteValue(), v.booleanValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ByteBooleanConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Boolean.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteByteConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteByteConsumer.java deleted file mode 100644 index 85ff921a3..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteByteConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.bytes.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ByteByteConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(byte k, byte v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ByteByteConsumer andThen(ByteByteConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Byte k, Byte v) { accept(k.byteValue(), v.byteValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ByteByteConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Byte.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteCharConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteCharConsumer.java deleted file mode 100644 index f1a52044f..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteCharConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.bytes.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ByteCharConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(byte k, char v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ByteCharConsumer andThen(ByteCharConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Byte k, Character v) { accept(k.byteValue(), v.charValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ByteCharConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Character.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteDoubleConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteDoubleConsumer.java deleted file mode 100644 index 6acbf3323..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteDoubleConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.bytes.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ByteDoubleConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(byte k, double v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ByteDoubleConsumer andThen(ByteDoubleConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Byte k, Double v) { accept(k.byteValue(), v.doubleValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ByteDoubleConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Double.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteFloatConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteFloatConsumer.java deleted file mode 100644 index 77b934d31..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteFloatConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.bytes.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ByteFloatConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(byte k, float v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ByteFloatConsumer andThen(ByteFloatConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Byte k, Float v) { accept(k.byteValue(), v.floatValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ByteFloatConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Float.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteIntConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteIntConsumer.java deleted file mode 100644 index c13ef686c..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteIntConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.bytes.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ByteIntConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(byte k, int v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ByteIntConsumer andThen(ByteIntConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Byte k, Integer v) { accept(k.byteValue(), v.intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ByteIntConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Integer.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteLongConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteLongConsumer.java deleted file mode 100644 index 36ea5472e..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteLongConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.bytes.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ByteLongConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(byte k, long v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ByteLongConsumer andThen(ByteLongConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Byte k, Long v) { accept(k.byteValue(), v.longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ByteLongConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Long.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteObjectConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteObjectConsumer.java deleted file mode 100644 index dfb70283f..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteObjectConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.bytes.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface ByteObjectConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(byte k, V v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ByteObjectConsumer andThen(ByteObjectConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Byte k, V v) { accept(k.byteValue(), v); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ByteObjectConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), V);}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteShortConsumer.java b/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteShortConsumer.java deleted file mode 100644 index c486aff63..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/consumer/ByteShortConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.bytes.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ByteShortConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(byte k, short v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ByteShortConsumer andThen(ByteShortConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Byte k, Short v) { accept(k.byteValue(), v.shortValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ByteShortConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Byte.valueOf(K), Short.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2CharFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2CharFunction.java deleted file mode 100644 index b543f1b7f..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2CharFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Byte2CharFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public char applyAsChar(byte k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2DoubleFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2DoubleFunction.java deleted file mode 100644 index 6f5a16064..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2DoubleFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Byte2DoubleFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public double applyAsDouble(byte k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2FloatFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2FloatFunction.java deleted file mode 100644 index 3e3776fdd..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2FloatFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Byte2FloatFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public float applyAsFloat(byte k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2IntFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2IntFunction.java deleted file mode 100644 index 1672969e9..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2IntFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Byte2IntFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public int applyAsInt(byte k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2LongFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2LongFunction.java deleted file mode 100644 index 8673498a8..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2LongFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Byte2LongFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public long applyAsLong(byte k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2ShortFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/Byte2ShortFunction.java deleted file mode 100644 index 198bdf043..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/Byte2ShortFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Byte2ShortFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public short applyAsShort(byte k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteBooleanUnaryOperator.java deleted file mode 100644 index 742120fd5..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/ByteBooleanUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ByteBooleanUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public boolean applyAsBoolean(byte k, boolean v); - - @Override - public default Boolean apply(Byte k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.byteValue(), v.booleanValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteByteUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteByteUnaryOperator.java deleted file mode 100644 index 0fb74d9c1..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/ByteByteUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ByteByteUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public byte applyAsByte(byte k, byte v); - - @Override - public default Byte apply(Byte k, Byte v) { return Byte.valueOf(applyAsByte(k.byteValue(), v.byteValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteCharUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteCharUnaryOperator.java deleted file mode 100644 index 89ff943fe..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/ByteCharUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ByteCharUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public char applyAsChar(byte k, char v); - - @Override - public default Character apply(Byte k, Character v) { return Character.valueOf(applyAsChar(k.byteValue(), v.charValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteDoubleUnaryOperator.java deleted file mode 100644 index f9e86aafe..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/ByteDoubleUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ByteDoubleUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public double applyAsDouble(byte k, double v); - - @Override - public default Double apply(Byte k, Double v) { return Double.valueOf(applyAsDouble(k.byteValue(), v.doubleValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteFloatUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteFloatUnaryOperator.java deleted file mode 100644 index 8e583645b..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/ByteFloatUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ByteFloatUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public float applyAsFloat(byte k, float v); - - @Override - public default Float apply(Byte k, Float v) { return Float.valueOf(applyAsFloat(k.byteValue(), v.floatValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteFunction.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteFunction.java deleted file mode 100644 index 8296b7ea1..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/ByteFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface ByteFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public V apply(byte k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteIntUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteIntUnaryOperator.java deleted file mode 100644 index d7f51b603..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/ByteIntUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ByteIntUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public int applyAsInt(byte k, int v); - - @Override - public default Integer apply(Byte k, Integer v) { return Integer.valueOf(applyAsInt(k.byteValue(), v.intValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteLongUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteLongUnaryOperator.java deleted file mode 100644 index 75e451569..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/ByteLongUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ByteLongUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public long applyAsLong(byte k, long v); - - @Override - public default Long apply(Byte k, Long v) { return Long.valueOf(applyAsLong(k.byteValue(), v.longValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteObjectUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteObjectUnaryOperator.java deleted file mode 100644 index 943b70045..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/ByteObjectUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface ByteObjectUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public V apply(byte k, V v); - - @Override - public default V apply(Byte k, V v) { return apply(k.byteValue(), v); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/BytePredicate.java b/src/main/java/speiger/src/collections/bytes/functions/function/BytePredicate.java deleted file mode 100644 index 7629e541f..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/BytePredicate.java +++ /dev/null @@ -1,62 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface BytePredicate -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public boolean test(byte k); - - /** - * Creates a Always true function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static BytePredicate alwaysTrue() { - return T -> true; - } - - /** - * Creates a Always false function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static BytePredicate alwaysFalse() { - return T -> false; - } - - /** - * A Type specific and-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a and comparason - */ - public default BytePredicate andType(BytePredicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - /** - * A type specific inverter function - * @return the same function but inverts the result - */ - public default BytePredicate negate() { - return T -> !test(T); - } - - /** - * A Type specific or-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a or comparason - */ - public default BytePredicate orType(BytePredicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteShortUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteShortUnaryOperator.java deleted file mode 100644 index 11e207e41..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/ByteShortUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ByteShortUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public short applyAsShort(byte k, short v); - - @Override - public default Short apply(Byte k, Short v) { return Short.valueOf(applyAsShort(k.byteValue(), v.shortValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/bytes/functions/function/ByteUnaryOperator.java b/src/main/java/speiger/src/collections/bytes/functions/function/ByteUnaryOperator.java deleted file mode 100644 index a49b4e5d7..000000000 --- a/src/main/java/speiger/src/collections/bytes/functions/function/ByteUnaryOperator.java +++ /dev/null @@ -1,54 +0,0 @@ -package speiger.src.collections.bytes.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface ByteUnaryOperator -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public byte applyAsByte(byte k); - - /** - * Creates a Default function that returns the input provided. - * @return a input returning function - */ - public static ByteUnaryOperator identity() { - return T -> T; - } - - /** - * Returns a composed function that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param before the function that should be used first - * @return a composed function with a different starting function. - */ - public default ByteUnaryOperator compose(ByteUnaryOperator before) { - Objects.requireNonNull(before); - return T -> applyAsByte(before.applyAsByte(T)); - } - - /** - * Returns a composed function that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param after the function that should be used last - * @return a composed function with a different starting function. - */ - public default ByteUnaryOperator andThen(ByteUnaryOperator after) { - Objects.requireNonNull(after); - return T -> after.applyAsByte(applyAsByte(T)); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/CharComparator.java b/src/main/java/speiger/src/collections/chars/functions/CharComparator.java deleted file mode 100644 index cd22da54f..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/CharComparator.java +++ /dev/null @@ -1,70 +0,0 @@ -package speiger.src.collections.chars.functions; - -import java.util.Comparator; -import java.util.Objects; - -/** - * Type-Specific Class for Comparator to reduce (un)boxing - */ -public interface CharComparator extends Comparator -{ - /** - * Type-Specific compare function to reduce (un)boxing - * @param o1 the first object to be compared. - * @param o2 the second object to be compared. - * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. - * @see Comparator#compare(Object, Object) - */ - int compare(char o1, char o2); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default int compare(Character o1, Character o2) { - return compare(o1.charValue(), o2.charValue()); - } - - /** - * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator - * @param c comparator to convert - * @return the wrapper of the comparator - * @throws NullPointerException if the comparator is null - */ - public static CharComparator of(Comparator c) { - Objects.requireNonNull(c); - return (K, V) -> c.compare(Character.valueOf(K), Character.valueOf(V)); - } - - @Override - public default CharComparator reversed() { - return new Reversed(this); - } - - /** - * A Type Specific Reversed Comparator to reduce boxing/unboxing - */ - static class Reversed implements CharComparator - { - CharComparator original; - - /** - * default constructor - * @param original that is going to be reversed - */ - public Reversed(CharComparator original) { - this.original = original; - } - - public int compare(char o1, char o2) { - return original.compare(o2, o1); - } - - @Override - public CharComparator reversed() { - return original; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/CharConsumer.java b/src/main/java/speiger/src/collections/chars/functions/CharConsumer.java deleted file mode 100644 index 3e657c4b0..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/CharConsumer.java +++ /dev/null @@ -1,48 +0,0 @@ -package speiger.src.collections.chars.functions; - -import java.util.Objects; -import java.util.function.Consumer; -/** - * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -@FunctionalInterface -public interface CharConsumer extends Consumer -{ - /** - * Type-Specific function to reduce (un)boxing. - * Performs this operation on the given argument. - * - * @param t the input argument - */ - void accept(char t); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced consumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default CharConsumer andThen(CharConsumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(T);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Character t) { accept(t.charValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default CharConsumer andThen(Consumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(Character.valueOf(T));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/CharSupplier.java b/src/main/java/speiger/src/collections/chars/functions/CharSupplier.java deleted file mode 100644 index 8d675dce8..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/CharSupplier.java +++ /dev/null @@ -1,12 +0,0 @@ -package speiger.src.collections.chars.functions; - -/** - * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -public interface CharSupplier -{ - /** - * @return the supplied value - */ - public char getAsInt(); -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharBooleanConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharBooleanConsumer.java deleted file mode 100644 index db31509a0..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/consumer/CharBooleanConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.chars.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface CharBooleanConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(char k, boolean v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default CharBooleanConsumer andThen(CharBooleanConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Character k, Boolean v) { accept(k.charValue(), v.booleanValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default CharBooleanConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Boolean.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharByteConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharByteConsumer.java deleted file mode 100644 index ea86de532..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/consumer/CharByteConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.chars.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface CharByteConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(char k, byte v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default CharByteConsumer andThen(CharByteConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Character k, Byte v) { accept(k.charValue(), v.byteValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default CharByteConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Byte.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharCharConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharCharConsumer.java deleted file mode 100644 index c4e922661..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/consumer/CharCharConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.chars.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface CharCharConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(char k, char v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default CharCharConsumer andThen(CharCharConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Character k, Character v) { accept(k.charValue(), v.charValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default CharCharConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Character.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharDoubleConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharDoubleConsumer.java deleted file mode 100644 index 4d27c0f36..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/consumer/CharDoubleConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.chars.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface CharDoubleConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(char k, double v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default CharDoubleConsumer andThen(CharDoubleConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Character k, Double v) { accept(k.charValue(), v.doubleValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default CharDoubleConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Double.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharFloatConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharFloatConsumer.java deleted file mode 100644 index 9e993edf5..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/consumer/CharFloatConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.chars.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface CharFloatConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(char k, float v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default CharFloatConsumer andThen(CharFloatConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Character k, Float v) { accept(k.charValue(), v.floatValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default CharFloatConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Float.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharIntConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharIntConsumer.java deleted file mode 100644 index 1668caeda..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/consumer/CharIntConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.chars.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface CharIntConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(char k, int v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default CharIntConsumer andThen(CharIntConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Character k, Integer v) { accept(k.charValue(), v.intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default CharIntConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Integer.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharLongConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharLongConsumer.java deleted file mode 100644 index 3048c08f3..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/consumer/CharLongConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.chars.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface CharLongConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(char k, long v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default CharLongConsumer andThen(CharLongConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Character k, Long v) { accept(k.charValue(), v.longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default CharLongConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Long.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharObjectConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharObjectConsumer.java deleted file mode 100644 index b03888e8c..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/consumer/CharObjectConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.chars.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface CharObjectConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(char k, V v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default CharObjectConsumer andThen(CharObjectConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Character k, V v) { accept(k.charValue(), v); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default CharObjectConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), V);}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/consumer/CharShortConsumer.java b/src/main/java/speiger/src/collections/chars/functions/consumer/CharShortConsumer.java deleted file mode 100644 index ffa3baf78..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/consumer/CharShortConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.chars.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface CharShortConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(char k, short v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default CharShortConsumer andThen(CharShortConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Character k, Short v) { accept(k.charValue(), v.shortValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default CharShortConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Character.valueOf(K), Short.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2ByteFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2ByteFunction.java deleted file mode 100644 index 16c70dd0f..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/Char2ByteFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.chars.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Char2ByteFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public byte applyAsByte(char k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2DoubleFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2DoubleFunction.java deleted file mode 100644 index a425c7559..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/Char2DoubleFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.chars.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Char2DoubleFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public double applyAsDouble(char k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2FloatFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2FloatFunction.java deleted file mode 100644 index ed1c488e5..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/Char2FloatFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.chars.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Char2FloatFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public float applyAsFloat(char k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2IntFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2IntFunction.java deleted file mode 100644 index 2e17ab27f..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/Char2IntFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.chars.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Char2IntFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public int applyAsInt(char k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2LongFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2LongFunction.java deleted file mode 100644 index 809d3e440..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/Char2LongFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.chars.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Char2LongFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public long applyAsLong(char k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/Char2ShortFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/Char2ShortFunction.java deleted file mode 100644 index 435518d5f..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/Char2ShortFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.chars.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Char2ShortFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public short applyAsShort(char k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharBooleanUnaryOperator.java deleted file mode 100644 index c5870677a..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharBooleanUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.chars.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface CharBooleanUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public boolean applyAsBoolean(char k, boolean v); - - @Override - public default Boolean apply(Character k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.charValue(), v.booleanValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharByteUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharByteUnaryOperator.java deleted file mode 100644 index 9688c32c7..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharByteUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.chars.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface CharByteUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public byte applyAsByte(char k, byte v); - - @Override - public default Byte apply(Character k, Byte v) { return Byte.valueOf(applyAsByte(k.charValue(), v.byteValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharCharUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharCharUnaryOperator.java deleted file mode 100644 index 440df1e8d..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharCharUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.chars.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface CharCharUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public char applyAsChar(char k, char v); - - @Override - public default Character apply(Character k, Character v) { return Character.valueOf(applyAsChar(k.charValue(), v.charValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharDoubleUnaryOperator.java deleted file mode 100644 index bc961f87c..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharDoubleUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.chars.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface CharDoubleUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public double applyAsDouble(char k, double v); - - @Override - public default Double apply(Character k, Double v) { return Double.valueOf(applyAsDouble(k.charValue(), v.doubleValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharFloatUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharFloatUnaryOperator.java deleted file mode 100644 index a541e9bcf..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharFloatUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.chars.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface CharFloatUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public float applyAsFloat(char k, float v); - - @Override - public default Float apply(Character k, Float v) { return Float.valueOf(applyAsFloat(k.charValue(), v.floatValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharFunction.java b/src/main/java/speiger/src/collections/chars/functions/function/CharFunction.java deleted file mode 100644 index fc0d0180f..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.chars.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface CharFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public V apply(char k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharIntUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharIntUnaryOperator.java deleted file mode 100644 index a9b5f6729..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharIntUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.chars.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface CharIntUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public int applyAsInt(char k, int v); - - @Override - public default Integer apply(Character k, Integer v) { return Integer.valueOf(applyAsInt(k.charValue(), v.intValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharLongUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharLongUnaryOperator.java deleted file mode 100644 index d5ed6c5c0..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharLongUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.chars.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface CharLongUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public long applyAsLong(char k, long v); - - @Override - public default Long apply(Character k, Long v) { return Long.valueOf(applyAsLong(k.charValue(), v.longValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharObjectUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharObjectUnaryOperator.java deleted file mode 100644 index 8c5c1b20e..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharObjectUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.chars.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface CharObjectUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public V apply(char k, V v); - - @Override - public default V apply(Character k, V v) { return apply(k.charValue(), v); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharPredicate.java b/src/main/java/speiger/src/collections/chars/functions/function/CharPredicate.java deleted file mode 100644 index 095deb2cf..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharPredicate.java +++ /dev/null @@ -1,62 +0,0 @@ -package speiger.src.collections.chars.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface CharPredicate -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public boolean test(char k); - - /** - * Creates a Always true function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static CharPredicate alwaysTrue() { - return T -> true; - } - - /** - * Creates a Always false function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static CharPredicate alwaysFalse() { - return T -> false; - } - - /** - * A Type specific and-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a and comparason - */ - public default CharPredicate andType(CharPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - /** - * A type specific inverter function - * @return the same function but inverts the result - */ - public default CharPredicate negate() { - return T -> !test(T); - } - - /** - * A Type specific or-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a or comparason - */ - public default CharPredicate orType(CharPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharShortUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharShortUnaryOperator.java deleted file mode 100644 index e407d7f90..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharShortUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.chars.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface CharShortUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public short applyAsShort(char k, short v); - - @Override - public default Short apply(Character k, Short v) { return Short.valueOf(applyAsShort(k.charValue(), v.shortValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/chars/functions/function/CharUnaryOperator.java b/src/main/java/speiger/src/collections/chars/functions/function/CharUnaryOperator.java deleted file mode 100644 index 1cb396e59..000000000 --- a/src/main/java/speiger/src/collections/chars/functions/function/CharUnaryOperator.java +++ /dev/null @@ -1,54 +0,0 @@ -package speiger.src.collections.chars.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface CharUnaryOperator -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public char applyAsChar(char k); - - /** - * Creates a Default function that returns the input provided. - * @return a input returning function - */ - public static CharUnaryOperator identity() { - return T -> T; - } - - /** - * Returns a composed function that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param before the function that should be used first - * @return a composed function with a different starting function. - */ - public default CharUnaryOperator compose(CharUnaryOperator before) { - Objects.requireNonNull(before); - return T -> applyAsChar(before.applyAsChar(T)); - } - - /** - * Returns a composed function that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param after the function that should be used last - * @return a composed function with a different starting function. - */ - public default CharUnaryOperator andThen(CharUnaryOperator after) { - Objects.requireNonNull(after); - return T -> after.applyAsChar(applyAsChar(T)); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/DoubleComparator.java b/src/main/java/speiger/src/collections/doubles/functions/DoubleComparator.java deleted file mode 100644 index 73d815452..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/DoubleComparator.java +++ /dev/null @@ -1,70 +0,0 @@ -package speiger.src.collections.doubles.functions; - -import java.util.Comparator; -import java.util.Objects; - -/** - * Type-Specific Class for Comparator to reduce (un)boxing - */ -public interface DoubleComparator extends Comparator -{ - /** - * Type-Specific compare function to reduce (un)boxing - * @param o1 the first object to be compared. - * @param o2 the second object to be compared. - * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. - * @see Comparator#compare(Object, Object) - */ - int compare(double o1, double o2); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default int compare(Double o1, Double o2) { - return compare(o1.doubleValue(), o2.doubleValue()); - } - - /** - * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator - * @param c comparator to convert - * @return the wrapper of the comparator - * @throws NullPointerException if the comparator is null - */ - public static DoubleComparator of(Comparator c) { - Objects.requireNonNull(c); - return (K, V) -> c.compare(Double.valueOf(K), Double.valueOf(V)); - } - - @Override - public default DoubleComparator reversed() { - return new Reversed(this); - } - - /** - * A Type Specific Reversed Comparator to reduce boxing/unboxing - */ - static class Reversed implements DoubleComparator - { - DoubleComparator original; - - /** - * default constructor - * @param original that is going to be reversed - */ - public Reversed(DoubleComparator original) { - this.original = original; - } - - public int compare(double o1, double o2) { - return original.compare(o2, o1); - } - - @Override - public DoubleComparator reversed() { - return original; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/DoubleConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/DoubleConsumer.java deleted file mode 100644 index d0053a087..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/DoubleConsumer.java +++ /dev/null @@ -1,59 +0,0 @@ -package speiger.src.collections.doubles.functions; - -import java.util.Objects; -import java.util.function.Consumer; -/** - * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -@FunctionalInterface -public interface DoubleConsumer extends Consumer, java.util.function.DoubleConsumer -{ - /** - * Type-Specific function to reduce (un)boxing. - * Performs this operation on the given argument. - * - * @param t the input argument - */ - void accept(double t); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced consumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default DoubleConsumer andThen(DoubleConsumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(T);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Double t) { accept(t.doubleValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default DoubleConsumer andThen(Consumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(Double.valueOf(T));}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default DoubleConsumer andThen(java.util.function.DoubleConsumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(T);}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/DoubleSupplier.java b/src/main/java/speiger/src/collections/doubles/functions/DoubleSupplier.java deleted file mode 100644 index a6cd25199..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/DoubleSupplier.java +++ /dev/null @@ -1,12 +0,0 @@ -package speiger.src.collections.doubles.functions; - -/** - * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -public interface DoubleSupplier extends java.util.function.DoubleSupplier -{ - /** - * @return the supplied value - */ - public double getAsDouble(); -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleBooleanConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleBooleanConsumer.java deleted file mode 100644 index 8acbc28be..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleBooleanConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.doubles.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface DoubleBooleanConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(double k, boolean v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default DoubleBooleanConsumer andThen(DoubleBooleanConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Double k, Boolean v) { accept(k.doubleValue(), v.booleanValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default DoubleBooleanConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Boolean.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleByteConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleByteConsumer.java deleted file mode 100644 index 05f3706cf..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleByteConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.doubles.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface DoubleByteConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(double k, byte v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default DoubleByteConsumer andThen(DoubleByteConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Double k, Byte v) { accept(k.doubleValue(), v.byteValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default DoubleByteConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Byte.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleCharConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleCharConsumer.java deleted file mode 100644 index 6c6400330..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleCharConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.doubles.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface DoubleCharConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(double k, char v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default DoubleCharConsumer andThen(DoubleCharConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Double k, Character v) { accept(k.doubleValue(), v.charValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default DoubleCharConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Character.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleDoubleConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleDoubleConsumer.java deleted file mode 100644 index f54938468..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleDoubleConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.doubles.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface DoubleDoubleConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(double k, double v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default DoubleDoubleConsumer andThen(DoubleDoubleConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Double k, Double v) { accept(k.doubleValue(), v.doubleValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default DoubleDoubleConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Double.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleFloatConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleFloatConsumer.java deleted file mode 100644 index 42cb0b24b..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleFloatConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.doubles.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface DoubleFloatConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(double k, float v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default DoubleFloatConsumer andThen(DoubleFloatConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Double k, Float v) { accept(k.doubleValue(), v.floatValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default DoubleFloatConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Float.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleIntConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleIntConsumer.java deleted file mode 100644 index aed40a7a4..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleIntConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.doubles.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface DoubleIntConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(double k, int v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default DoubleIntConsumer andThen(DoubleIntConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Double k, Integer v) { accept(k.doubleValue(), v.intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default DoubleIntConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Integer.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleLongConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleLongConsumer.java deleted file mode 100644 index 5d234c71b..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleLongConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.doubles.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface DoubleLongConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(double k, long v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default DoubleLongConsumer andThen(DoubleLongConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Double k, Long v) { accept(k.doubleValue(), v.longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default DoubleLongConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Long.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleObjectConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleObjectConsumer.java deleted file mode 100644 index 75eb69663..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleObjectConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.doubles.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface DoubleObjectConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(double k, V v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default DoubleObjectConsumer andThen(DoubleObjectConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Double k, V v) { accept(k.doubleValue(), v); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default DoubleObjectConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), V);}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleShortConsumer.java b/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleShortConsumer.java deleted file mode 100644 index c3285d7c6..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/consumer/DoubleShortConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.doubles.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface DoubleShortConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(double k, short v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default DoubleShortConsumer andThen(DoubleShortConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Double k, Short v) { accept(k.doubleValue(), v.shortValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default DoubleShortConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Double.valueOf(K), Short.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2ByteFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2ByteFunction.java deleted file mode 100644 index a82a984bb..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/Double2ByteFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Double2ByteFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public byte applyAsByte(double k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2CharFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2CharFunction.java deleted file mode 100644 index fbf78e66a..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/Double2CharFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Double2CharFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public char applyAsChar(double k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2FloatFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2FloatFunction.java deleted file mode 100644 index 55a0b494a..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/Double2FloatFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Double2FloatFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public float applyAsFloat(double k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2IntFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2IntFunction.java deleted file mode 100644 index 67953bfe4..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/Double2IntFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Double2IntFunction extends java.util.function.DoubleToIntFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public int applyAsInt(double k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2LongFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2LongFunction.java deleted file mode 100644 index 1a9b1a6cd..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/Double2LongFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Double2LongFunction extends java.util.function.DoubleToLongFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public long applyAsLong(double k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/Double2ShortFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/Double2ShortFunction.java deleted file mode 100644 index 53a07d9fc..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/Double2ShortFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Double2ShortFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public short applyAsShort(double k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleBooleanUnaryOperator.java deleted file mode 100644 index 0d49a925c..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleBooleanUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface DoubleBooleanUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public boolean applyAsBoolean(double k, boolean v); - - @Override - public default Boolean apply(Double k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.doubleValue(), v.booleanValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleByteUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleByteUnaryOperator.java deleted file mode 100644 index 756058fdd..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleByteUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface DoubleByteUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public byte applyAsByte(double k, byte v); - - @Override - public default Byte apply(Double k, Byte v) { return Byte.valueOf(applyAsByte(k.doubleValue(), v.byteValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleCharUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleCharUnaryOperator.java deleted file mode 100644 index 7510e3bca..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleCharUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface DoubleCharUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public char applyAsChar(double k, char v); - - @Override - public default Character apply(Double k, Character v) { return Character.valueOf(applyAsChar(k.doubleValue(), v.charValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleDoubleUnaryOperator.java deleted file mode 100644 index c223a05fe..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleDoubleUnaryOperator.java +++ /dev/null @@ -1,13 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ - -public interface DoubleDoubleUnaryOperator extends BiFunction, java.util.function.DoubleBinaryOperator -{ - @Override - public default Double apply(Double k, Double v) { return Double.valueOf(applyAsDouble(k.doubleValue(), v.doubleValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFloatUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFloatUnaryOperator.java deleted file mode 100644 index 9d3054cce..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFloatUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface DoubleFloatUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public float applyAsFloat(double k, float v); - - @Override - public default Float apply(Double k, Float v) { return Float.valueOf(applyAsFloat(k.doubleValue(), v.floatValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFunction.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFunction.java deleted file mode 100644 index 6c0cdbd7d..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface DoubleFunction extends java.util.function.DoubleFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public V apply(double k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleIntUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleIntUnaryOperator.java deleted file mode 100644 index 8ae3091cd..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleIntUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface DoubleIntUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public int applyAsInt(double k, int v); - - @Override - public default Integer apply(Double k, Integer v) { return Integer.valueOf(applyAsInt(k.doubleValue(), v.intValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleLongUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleLongUnaryOperator.java deleted file mode 100644 index ad41c8b72..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleLongUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface DoubleLongUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public long applyAsLong(double k, long v); - - @Override - public default Long apply(Double k, Long v) { return Long.valueOf(applyAsLong(k.doubleValue(), v.longValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleObjectUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleObjectUnaryOperator.java deleted file mode 100644 index f7e9c5af0..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleObjectUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface DoubleObjectUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public V apply(double k, V v); - - @Override - public default V apply(Double k, V v) { return apply(k.doubleValue(), v); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoublePredicate.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoublePredicate.java deleted file mode 100644 index 0a256c7f4..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoublePredicate.java +++ /dev/null @@ -1,72 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface DoublePredicate extends java.util.function.DoublePredicate -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public boolean test(double k); - - /** - * Creates a Always true function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static DoublePredicate alwaysTrue() { - return T -> true; - } - - /** - * Creates a Always false function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static DoublePredicate alwaysFalse() { - return T -> false; - } - - /** - * A Type specific and-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a and comparason - */ - public default DoublePredicate andType(DoublePredicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - @Override - @Deprecated - public default DoublePredicate and(java.util.function.DoublePredicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - @Override - public default DoublePredicate negate() { - return T -> !test(T); - } - - /** - * A Type specific or-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a or comparason - */ - public default DoublePredicate orType(DoublePredicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } - - @Override - @Deprecated - public default DoublePredicate or(java.util.function.DoublePredicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleShortUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleShortUnaryOperator.java deleted file mode 100644 index 280ed1dcc..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleShortUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface DoubleShortUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public short applyAsShort(double k, short v); - - @Override - public default Short apply(Double k, Short v) { return Short.valueOf(applyAsShort(k.doubleValue(), v.shortValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleUnaryOperator.java b/src/main/java/speiger/src/collections/doubles/functions/function/DoubleUnaryOperator.java deleted file mode 100644 index c3156b404..000000000 --- a/src/main/java/speiger/src/collections/doubles/functions/function/DoubleUnaryOperator.java +++ /dev/null @@ -1,54 +0,0 @@ -package speiger.src.collections.doubles.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface DoubleUnaryOperator extends java.util.function.DoubleUnaryOperator -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public double applyAsDouble(double k); - - /** - * Creates a Default function that returns the input provided. - * @return a input returning function - */ - public static DoubleUnaryOperator identity() { - return T -> T; - } - - /** - * Returns a composed function that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param before the function that should be used first - * @return a composed function with a different starting function. - */ - public default DoubleUnaryOperator compose(DoubleUnaryOperator before) { - Objects.requireNonNull(before); - return T -> applyAsDouble(before.applyAsDouble(T)); - } - - /** - * Returns a composed function that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param after the function that should be used last - * @return a composed function with a different starting function. - */ - public default DoubleUnaryOperator andThen(DoubleUnaryOperator after) { - Objects.requireNonNull(after); - return T -> after.applyAsDouble(applyAsDouble(T)); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/FloatComparator.java b/src/main/java/speiger/src/collections/floats/functions/FloatComparator.java deleted file mode 100644 index 5fd257c47..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/FloatComparator.java +++ /dev/null @@ -1,70 +0,0 @@ -package speiger.src.collections.floats.functions; - -import java.util.Comparator; -import java.util.Objects; - -/** - * Type-Specific Class for Comparator to reduce (un)boxing - */ -public interface FloatComparator extends Comparator -{ - /** - * Type-Specific compare function to reduce (un)boxing - * @param o1 the first object to be compared. - * @param o2 the second object to be compared. - * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. - * @see Comparator#compare(Object, Object) - */ - int compare(float o1, float o2); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default int compare(Float o1, Float o2) { - return compare(o1.floatValue(), o2.floatValue()); - } - - /** - * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator - * @param c comparator to convert - * @return the wrapper of the comparator - * @throws NullPointerException if the comparator is null - */ - public static FloatComparator of(Comparator c) { - Objects.requireNonNull(c); - return (K, V) -> c.compare(Float.valueOf(K), Float.valueOf(V)); - } - - @Override - public default FloatComparator reversed() { - return new Reversed(this); - } - - /** - * A Type Specific Reversed Comparator to reduce boxing/unboxing - */ - static class Reversed implements FloatComparator - { - FloatComparator original; - - /** - * default constructor - * @param original that is going to be reversed - */ - public Reversed(FloatComparator original) { - this.original = original; - } - - public int compare(float o1, float o2) { - return original.compare(o2, o1); - } - - @Override - public FloatComparator reversed() { - return original; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/FloatConsumer.java b/src/main/java/speiger/src/collections/floats/functions/FloatConsumer.java deleted file mode 100644 index 5e8724377..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/FloatConsumer.java +++ /dev/null @@ -1,48 +0,0 @@ -package speiger.src.collections.floats.functions; - -import java.util.Objects; -import java.util.function.Consumer; -/** - * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -@FunctionalInterface -public interface FloatConsumer extends Consumer -{ - /** - * Type-Specific function to reduce (un)boxing. - * Performs this operation on the given argument. - * - * @param t the input argument - */ - void accept(float t); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced consumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default FloatConsumer andThen(FloatConsumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(T);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Float t) { accept(t.floatValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default FloatConsumer andThen(Consumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(Float.valueOf(T));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/FloatSupplier.java b/src/main/java/speiger/src/collections/floats/functions/FloatSupplier.java deleted file mode 100644 index f0009ae9c..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/FloatSupplier.java +++ /dev/null @@ -1,12 +0,0 @@ -package speiger.src.collections.floats.functions; - -/** - * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -public interface FloatSupplier -{ - /** - * @return the supplied value - */ - public float getAsDouble(); -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatBooleanConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatBooleanConsumer.java deleted file mode 100644 index 3033a6838..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatBooleanConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.floats.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface FloatBooleanConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(float k, boolean v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default FloatBooleanConsumer andThen(FloatBooleanConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Float k, Boolean v) { accept(k.floatValue(), v.booleanValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default FloatBooleanConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Boolean.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatByteConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatByteConsumer.java deleted file mode 100644 index 6e3c3f1c4..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatByteConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.floats.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface FloatByteConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(float k, byte v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default FloatByteConsumer andThen(FloatByteConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Float k, Byte v) { accept(k.floatValue(), v.byteValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default FloatByteConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Byte.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatCharConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatCharConsumer.java deleted file mode 100644 index c6af3eab1..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatCharConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.floats.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface FloatCharConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(float k, char v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default FloatCharConsumer andThen(FloatCharConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Float k, Character v) { accept(k.floatValue(), v.charValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default FloatCharConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Character.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatDoubleConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatDoubleConsumer.java deleted file mode 100644 index 46d992a0d..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatDoubleConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.floats.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface FloatDoubleConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(float k, double v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default FloatDoubleConsumer andThen(FloatDoubleConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Float k, Double v) { accept(k.floatValue(), v.doubleValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default FloatDoubleConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Double.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatFloatConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatFloatConsumer.java deleted file mode 100644 index d13211938..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatFloatConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.floats.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface FloatFloatConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(float k, float v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default FloatFloatConsumer andThen(FloatFloatConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Float k, Float v) { accept(k.floatValue(), v.floatValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default FloatFloatConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Float.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatIntConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatIntConsumer.java deleted file mode 100644 index 6e9aef642..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatIntConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.floats.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface FloatIntConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(float k, int v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default FloatIntConsumer andThen(FloatIntConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Float k, Integer v) { accept(k.floatValue(), v.intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default FloatIntConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Integer.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatLongConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatLongConsumer.java deleted file mode 100644 index 237dc338c..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatLongConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.floats.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface FloatLongConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(float k, long v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default FloatLongConsumer andThen(FloatLongConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Float k, Long v) { accept(k.floatValue(), v.longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default FloatLongConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Long.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatObjectConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatObjectConsumer.java deleted file mode 100644 index 5d6bd04e1..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatObjectConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.floats.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface FloatObjectConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(float k, V v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default FloatObjectConsumer andThen(FloatObjectConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Float k, V v) { accept(k.floatValue(), v); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default FloatObjectConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), V);}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatShortConsumer.java b/src/main/java/speiger/src/collections/floats/functions/consumer/FloatShortConsumer.java deleted file mode 100644 index a62ea9be8..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/consumer/FloatShortConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.floats.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface FloatShortConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(float k, short v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default FloatShortConsumer andThen(FloatShortConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Float k, Short v) { accept(k.floatValue(), v.shortValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default FloatShortConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Float.valueOf(K), Short.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2ByteFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2ByteFunction.java deleted file mode 100644 index cef35f7bd..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/Float2ByteFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.floats.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Float2ByteFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public byte applyAsByte(float k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2CharFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2CharFunction.java deleted file mode 100644 index 0e29cb921..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/Float2CharFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.floats.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Float2CharFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public char applyAsChar(float k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2DoubleFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2DoubleFunction.java deleted file mode 100644 index 465bd779e..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/Float2DoubleFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.floats.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Float2DoubleFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public double applyAsDouble(float k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2IntFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2IntFunction.java deleted file mode 100644 index 76d49cee8..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/Float2IntFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.floats.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Float2IntFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public int applyAsInt(float k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2LongFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2LongFunction.java deleted file mode 100644 index 8101424f4..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/Float2LongFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.floats.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Float2LongFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public long applyAsLong(float k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/Float2ShortFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/Float2ShortFunction.java deleted file mode 100644 index 048862454..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/Float2ShortFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.floats.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Float2ShortFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public short applyAsShort(float k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatBooleanUnaryOperator.java deleted file mode 100644 index 894733145..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatBooleanUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.floats.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface FloatBooleanUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public boolean applyAsBoolean(float k, boolean v); - - @Override - public default Boolean apply(Float k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.floatValue(), v.booleanValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatByteUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatByteUnaryOperator.java deleted file mode 100644 index e0549ac62..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatByteUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.floats.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface FloatByteUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public byte applyAsByte(float k, byte v); - - @Override - public default Byte apply(Float k, Byte v) { return Byte.valueOf(applyAsByte(k.floatValue(), v.byteValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatCharUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatCharUnaryOperator.java deleted file mode 100644 index 4acb9ba38..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatCharUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.floats.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface FloatCharUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public char applyAsChar(float k, char v); - - @Override - public default Character apply(Float k, Character v) { return Character.valueOf(applyAsChar(k.floatValue(), v.charValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatDoubleUnaryOperator.java deleted file mode 100644 index 0e5c33743..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatDoubleUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.floats.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface FloatDoubleUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public double applyAsDouble(float k, double v); - - @Override - public default Double apply(Float k, Double v) { return Double.valueOf(applyAsDouble(k.floatValue(), v.doubleValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatFloatUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatFloatUnaryOperator.java deleted file mode 100644 index 9cc4df923..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatFloatUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.floats.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface FloatFloatUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public float applyAsFloat(float k, float v); - - @Override - public default Float apply(Float k, Float v) { return Float.valueOf(applyAsFloat(k.floatValue(), v.floatValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatFunction.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatFunction.java deleted file mode 100644 index 36fea4f7f..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.floats.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface FloatFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public V apply(float k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatIntUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatIntUnaryOperator.java deleted file mode 100644 index 099238999..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatIntUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.floats.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface FloatIntUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public int applyAsInt(float k, int v); - - @Override - public default Integer apply(Float k, Integer v) { return Integer.valueOf(applyAsInt(k.floatValue(), v.intValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatLongUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatLongUnaryOperator.java deleted file mode 100644 index 140169b41..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatLongUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.floats.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface FloatLongUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public long applyAsLong(float k, long v); - - @Override - public default Long apply(Float k, Long v) { return Long.valueOf(applyAsLong(k.floatValue(), v.longValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatObjectUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatObjectUnaryOperator.java deleted file mode 100644 index b44e40367..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatObjectUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.floats.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface FloatObjectUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public V apply(float k, V v); - - @Override - public default V apply(Float k, V v) { return apply(k.floatValue(), v); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatPredicate.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatPredicate.java deleted file mode 100644 index 08a95d62c..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatPredicate.java +++ /dev/null @@ -1,62 +0,0 @@ -package speiger.src.collections.floats.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface FloatPredicate -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public boolean test(float k); - - /** - * Creates a Always true function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static FloatPredicate alwaysTrue() { - return T -> true; - } - - /** - * Creates a Always false function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static FloatPredicate alwaysFalse() { - return T -> false; - } - - /** - * A Type specific and-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a and comparason - */ - public default FloatPredicate andType(FloatPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - /** - * A type specific inverter function - * @return the same function but inverts the result - */ - public default FloatPredicate negate() { - return T -> !test(T); - } - - /** - * A Type specific or-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a or comparason - */ - public default FloatPredicate orType(FloatPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatShortUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatShortUnaryOperator.java deleted file mode 100644 index 915982b5b..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatShortUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.floats.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface FloatShortUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public short applyAsShort(float k, short v); - - @Override - public default Short apply(Float k, Short v) { return Short.valueOf(applyAsShort(k.floatValue(), v.shortValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/floats/functions/function/FloatUnaryOperator.java b/src/main/java/speiger/src/collections/floats/functions/function/FloatUnaryOperator.java deleted file mode 100644 index 59c3063db..000000000 --- a/src/main/java/speiger/src/collections/floats/functions/function/FloatUnaryOperator.java +++ /dev/null @@ -1,54 +0,0 @@ -package speiger.src.collections.floats.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface FloatUnaryOperator -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public float applyAsFloat(float k); - - /** - * Creates a Default function that returns the input provided. - * @return a input returning function - */ - public static FloatUnaryOperator identity() { - return T -> T; - } - - /** - * Returns a composed function that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param before the function that should be used first - * @return a composed function with a different starting function. - */ - public default FloatUnaryOperator compose(FloatUnaryOperator before) { - Objects.requireNonNull(before); - return T -> applyAsFloat(before.applyAsFloat(T)); - } - - /** - * Returns a composed function that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param after the function that should be used last - * @return a composed function with a different starting function. - */ - public default FloatUnaryOperator andThen(FloatUnaryOperator after) { - Objects.requireNonNull(after); - return T -> after.applyAsFloat(applyAsFloat(T)); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/collections/AbstractIntCollection.java b/src/main/java/speiger/src/collections/ints/collections/AbstractIntCollection.java deleted file mode 100644 index 9223fa81c..000000000 --- a/src/main/java/speiger/src/collections/ints/collections/AbstractIntCollection.java +++ /dev/null @@ -1,252 +0,0 @@ -package speiger.src.collections.ints.collections; - -import java.util.Collection; -import java.util.Objects; -import java.util.AbstractCollection; - -import speiger.src.collections.ints.functions.IntConsumer; -import speiger.src.collections.ints.utils.IntIterators; -import speiger.src.collections.ints.utils.IntArrays; - -/** - * Abstract Type Specific Collection that reduces boxing/unboxing - */ -public abstract class AbstractIntCollection extends AbstractCollection implements IntCollection -{ - @Override - public abstract IntIterator iterator(); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public boolean add(Integer e) { return IntCollection.super.add(e); } - - @Override - public boolean addAll(IntCollection c) { - boolean modified = false; - for(IntIterator iter = c.iterator();iter.hasNext();modified |= add(iter.nextInt())); - return modified; - } - - @Override - public IntCollection copy() { throw new UnsupportedOperationException(); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public boolean contains(Object e) { return IntCollection.super.contains(e); } - - /** - * A Type-Specific implementation of contains. This implementation iterates over the elements and returns true if the value match. - * @param e the element that should be searched for. - * @return true if the value was found. - */ - @Override - public boolean contains(int e) { - for(IntIterator iter = iterator();iter.hasNext();) { if(iter.nextInt() == e) return true; } - return false; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public boolean addAll(Collection c) - { - return c instanceof IntCollection ? addAll((IntCollection)c) : super.addAll(c); - } - - /** - * A Type-Specific implementation of containsAll. This implementation iterates over all elements and checks all elements are present in the other collection. - * @param c the collection that should be checked if it contains all elements. - * @return true if all elements were found in the collection - * @throws NullPointerException if the collection is null - */ - @Override - public boolean containsAll(IntCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return true; - for(IntIterator iter = c.iterator();iter.hasNext();) - if(!contains(iter.nextInt())) - return false; - return true; - } - - @Override - public boolean containsAll(Collection c) { - Objects.requireNonNull(c); - return c instanceof IntCollection ? containsAll((IntCollection)c) : super.containsAll(c); - } - - /** - * This implementation iterates over the elements of the collection and checks if they are stored in this collection - * @param c the elements that should be checked for - * @return true if any element is in this collection - * @throws NullPointerException if the collection is null - */ - @Override - @Deprecated - public boolean containsAny(Collection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - for(Object e : c) - if(contains(e)) - return true; - return false; - } - - /** - * This implementation iterates over the elements of the collection and checks if they are stored in this collection. - * @param c the elements that should be checked for - * @return true if any element is in this collection - * @throws NullPointerException if the collection is null - */ - @Override - public boolean containsAny(IntCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - for(IntIterator iter = c.iterator();iter.hasNext();) - if(contains(iter.nextInt())) - return true; - return false; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public boolean remove(Object e) { return IntCollection.super.remove(e); } - - /** - * A Type-Specific implementation of remove. This implementation iterates over the elements until it finds the element that is searched for or it runs out of elements. - * It stops after finding the first element - * @param e the element that is searched for - * @return true if the element was found and removed. - */ - @Override - public boolean remInt(int e) { - for(IntIterator iter = iterator();iter.hasNext();) { - if(iter.nextInt() == e) { - iter.remove(); - return true; - } - } - return false; - } - - /** - * A Type-Specific implementation of removeAll. This Implementation iterates over all elements and removes them as they were found in the other collection. - * @param c the elements that should be deleted - * @return true if the collection was modified. - * @throws NullPointerException if the collection is null - */ - @Override - public boolean removeAll(IntCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - boolean modified = false; - for(IntIterator iter = iterator();iter.hasNext();) { - if(c.contains(iter.nextInt())) { - iter.remove(); - modified = true; - } - } - return modified; - } - - @Override - public boolean removeAll(IntCollection c, IntConsumer r) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - Objects.requireNonNull(r); - boolean modified = false; - for(IntIterator iter = iterator();iter.hasNext();) { - int e = iter.nextInt(); - if(c.contains(e)) { - r.accept(e); - iter.remove(); - modified = true; - } - } - return modified; - } - - /** - * A Type-Specific implementation of retainAll. This Implementation iterates over all elements and removes them as they were not found in the other collection. - * @param c the elements that should be kept - * @return true if the collection was modified. - * @throws NullPointerException if the collection is null - */ - @Override - public boolean retainAll(IntCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) { - boolean modified = !isEmpty(); - clear(); - return modified; - } - boolean modified = false; - for(IntIterator iter = iterator();iter.hasNext();) { - if(!c.contains(iter.nextInt())) { - iter.remove(); - modified = true; - } - } - return modified; - } - - @Override - public boolean retainAll(IntCollection c, IntConsumer r) { - Objects.requireNonNull(c); - Objects.requireNonNull(r); - if(c.isEmpty()) { - boolean modified = !isEmpty(); - forEach(r); - clear(); - return modified; - } - boolean modified = false; - for(IntIterator iter = iterator();iter.hasNext();) { - int e = iter.nextInt(); - if(!c.contains(e)) { - r.accept(e); - iter.remove(); - modified = true; - } - } - return modified; - } - - /** - * A Type-Specific implementation of toArray that links to {@link #toIntArray(int[])} with a newly created array. - * @return an array containing all of the elements in this collection - */ - @Override - public int[] toIntArray() { - if(isEmpty()) return IntArrays.EMPTY_ARRAY; - return toIntArray(new int[size()]); - } - - /** - * A Type-Specific implementation of toArray. This implementation iterates over all elements and unwraps them into primitive type. - * @param a array that the elements should be injected to. If null or to small a new array with the right size is created - * @return an array containing all of the elements in this collection - */ - @Override - public int[] toIntArray(int[] a) { - if(a == null || a.length < size()) a = new int[size()]; - IntIterators.unwrap(a, iterator()); - if (a.length > size()) a[size()] = 0; - return a; - } -} diff --git a/src/main/java/speiger/src/collections/ints/collections/IntBidirectionalIterator.java b/src/main/java/speiger/src/collections/ints/collections/IntBidirectionalIterator.java deleted file mode 100644 index c422b0e08..000000000 --- a/src/main/java/speiger/src/collections/ints/collections/IntBidirectionalIterator.java +++ /dev/null @@ -1,52 +0,0 @@ -package speiger.src.collections.ints.collections; - -import speiger.src.collections.objects.collections.ObjectBidirectionalIterator; -/** - * A Type-Specific {@link ObjectBidirectionalIterator} to reduce (un)boxing - */ -public interface IntBidirectionalIterator extends IntIterator, ObjectBidirectionalIterator -{ - /** - * Returns true if the Iterator has a Previous element - * @return true if the Iterator has a Previous element - */ - public boolean hasPrevious(); - - /** - * Returns the Previous element of the iterator. - * @return the Previous element of the iterator. - * @throws java.util.NoSuchElementException if the iteration has no more elements - */ - public int previousInt(); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default Integer previous() { - return Integer.valueOf(previousInt()); - } - - /** - * {@inheritDoc} - */ - @Override - default int skip(int amount) - { - return IntIterator.super.skip(amount); - } - - /** - * Reverses the Given amount of elements if possible. A Optimization function to reverse elements faster if the implementation allows it. - * @param amount the amount of elements that should be reversed - * @return the amount of elements that were reversed - */ - public default int back(int amount) { - if(amount < 0) throw new IllegalStateException("Can't go forward"); - int i = 0; - for(;i, IntIterable, ISizeProvider -{ - /** - * A Type-Specific add function to reduce (un)boxing - * @param o the element that should be added - * @return true if the element was added to the collection - */ - public boolean add(int o); - - /** - * A Type-Specific addAll function to reduce (un)boxing - * @param c the collection of elements that should be added - * @return true if elements were added into the collection - */ - public boolean addAll(IntCollection c); - - /** - * A Type-Specific Array based addAll method to reduce the amount of Wrapping - * @param e the elements that should be added - * @return if the collection was modified - */ - public default boolean addAll(int... e) { return addAll(e, 0, e.length); } - - /** - * A Type-Specific Array based addAll method to reduce the amount of Wrapping - * @param e the elements that should be added - * @param length how many elements of the array should be added - * @return if the collection was modified - */ - public default boolean addAll(int[] e, int length) { return addAll(e, 0, length); } - - /** - * A Type-Specific Array based addAll method to reduce the amount of Wrapping - * @param e the elements that should be added - * @param offset where to start within the array - * @param length how many elements of the array should be added - * @return if the collection was modified - */ - public default boolean addAll(int[] e, int offset, int length) { - if(length <= 0) return false; - SanityChecks.checkArrayCapacity(e.length, offset, length); - boolean added = false; - for(int i = 0;i c); - - /** - * A Type-Specific remove function that reduces (un)boxing. - * @param o the element that should be removed - * @return true if the element was removed - * @see Collection#remove(Object) - */ - public boolean remInt(int o); - - /** - * A Type-Specific removeAll function that reduces (un)boxing. - * @param c the collection of elements that should be removed - * @return true if any element was removed - * @see Collection#removeAll(Collection) - */ - public boolean removeAll(IntCollection c); - - /** - * A Type-Specific removeAll function that reduces (un)boxing. - * It also notifies the remover of which exact element is going to be removed. - * @param c the collection of elements that should be removed - * @param r elements that got removed - * @return true if any element was removed - * @see Collection#removeAll(Collection) - */ - public boolean removeAll(IntCollection c, IntConsumer r); - - /** - * A Type-Specific retainAll function that reduces (un)boxing. - * @param c the collection of elements that should be kept - * @return true if any element was removed - * @see Collection#retainAll(Collection) - */ - public boolean retainAll(IntCollection c); - - /** - * A Type-Specific retainAll function that reduces (un)boxing. - * It also notifies the remover of which exact element is going to be removed. - * @param c the collection of elements that should be kept - * @param r elements that got removed - * @return true if any element was removed - * @see Collection#retainAll(Collection) - */ - public boolean retainAll(IntCollection c, IntConsumer r); - - /** - * A Helper function to reduce the usage of Streams and allows to collect all elements - * @param collection that the elements should be inserted to - * @param the collection type - * @return the input with the desired elements - */ - default E pour(E collection) { - collection.addAll(this); - return collection; - } - - /** - * A Function that does a shallow clone of the Collection itself. - * This function is more optimized then a copy constructor since the Collection does not have to be unsorted/resorted. - * It can be compared to Cloneable but with less exception risk - * @return a Shallow Copy of the collection - * @note Wrappers and view collections will not support this feature - */ - public IntCollection copy(); - - /** - * A Type-Specific toArray function that delegates to {@link #toIntArray(int[])} with a newly created array. - * @return an array containing all of the elements in this collection - * @see Collection#toArray() - */ - public int[] toIntArray(); - - /** - * A Type-Specific toArray function that reduces (un)boxing. - * @param a array that the elements should be injected to. If null or to small a new array with the right size is created - * @return an array containing all of the elements in this collection - * @see Collection#toArray(Object[]) - */ - public int[] toIntArray(int[] a); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default boolean removeIf(Predicate filter) { - Objects.requireNonNull(filter); - return remIf(v -> filter.test(Integer.valueOf(v))); - } - - /** - * A Type-Specific removeIf function to reduce (un)boxing. - *

Removes elements that were selected by the filter - * @see Collection#removeIf(Predicate) - * @param filter Filters the elements that should be removed - * @return true if the collection was modified - * @throws NullPointerException if filter is null - */ - public default boolean remIf(IntPredicate filter) { - Objects.requireNonNull(filter); - boolean removed = false; - final IntIterator each = iterator(); - while (each.hasNext()) { - if (filter.test(each.nextInt())) { - each.remove(); - removed = true; - } - } - return removed; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default boolean add(Integer o) { return add(o.intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default boolean contains(Object o) { return o != null && contains(((Integer)o).intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default boolean remove(Object o) { return o != null && remInt(((Integer)o).intValue()); } - - /** - * Returns a Type-Specific Iterator to reduce (un)boxing - * @return a iterator of the collection - * @see Collection#iterator() - */ - @Override - public IntIterator iterator(); - - /** - * Creates a Wrapped Collection that is Synchronized - * @return a new Collection that is synchronized - * @see IntCollections#synchronize - */ - public default IntCollection synchronize() { return IntCollections.synchronize(this); } - - /** - * Creates a Wrapped Collection that is Synchronized - * @param mutex is the controller of the synchronization block - * @return a new Collection Wrapper that is synchronized - * @see IntCollections#synchronize - */ - public default IntCollection synchronize(Object mutex) { return IntCollections.synchronize(this, mutex); } - - /** - * Creates a Wrapped Collection that is unmodifiable - * @return a new Collection Wrapper that is unmodifiable - * @see IntCollections#unmodifiable - */ - public default IntCollection unmodifiable() { return IntCollections.unmodifiable(this); } - - /** - * Returns a Java-Type-Specific Stream to reduce boxing/unboxing. - * @return a Stream of the closest java type - */ - default IntStream primitiveStream() { return StreamSupport.intStream(IntSplititerators.createJavaSplititerator(this, 0), false); } - - /** - * Returns a Java-Type-Specific Parallel Stream to reduce boxing/unboxing. - * @return a Stream of the closest java type - */ - default IntStream parallelPrimitiveStream() { return StreamSupport.intStream(IntSplititerators.createJavaSplititerator(this, 0), true); } - - /** - * A Type Specific Type Splititerator to reduce boxing/unboxing - * @return type specific splititerator - */ - @Override - default IntSplititerator spliterator() { return IntSplititerators.createSplititerator(this, 0); } -} diff --git a/src/main/java/speiger/src/collections/ints/collections/IntIterable.java b/src/main/java/speiger/src/collections/ints/collections/IntIterable.java deleted file mode 100644 index 6cdae2d4a..000000000 --- a/src/main/java/speiger/src/collections/ints/collections/IntIterable.java +++ /dev/null @@ -1,314 +0,0 @@ -package speiger.src.collections.ints.collections; - -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.IntPredicate; - - -import speiger.src.collections.ints.functions.IntConsumer; -import speiger.src.collections.ints.functions.IntComparator; -import speiger.src.collections.objects.collections.ObjectIterable; -import speiger.src.collections.ints.functions.function.IntFunction; -import speiger.src.collections.ints.functions.consumer.IntIntConsumer; -import speiger.src.collections.objects.functions.consumer.ObjectIntConsumer; -import speiger.src.collections.ints.functions.function.IntIntUnaryOperator; - -import speiger.src.collections.ints.utils.IntArrays; -import speiger.src.collections.ints.utils.IntSplititerators; -import speiger.src.collections.ints.utils.IntIterables; -import speiger.src.collections.ints.utils.IntIterators; -import speiger.src.collections.utils.ISizeProvider; - -/** - * A Type-Specific {@link Iterable} that reduces (un)boxing - */ -public interface IntIterable extends Iterable -{ - /** - * Returns an iterator over elements of type {@code T}. - * - * @return an Iterator. - */ - @Override - IntIterator iterator(); - - /** - * A Type Specific foreach function that reduces (un)boxing - * - * @implSpec - *

The default implementation behaves as if: - *

{@code
-	 *	iterator().forEachRemaining(action);
-	 * }
- * - * @param action The action to be performed for each element - * @throws NullPointerException if the specified action is null - * @see Iterable#forEach(Consumer) - */ - default void forEach(IntConsumer action) { - Objects.requireNonNull(action); - iterator().forEachRemaining(action); - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Deprecated - @Override - default void forEach(Consumer action) { - Objects.requireNonNull(action); - iterator().forEachRemaining(action); - } - - /** - * A Indexed forEach implementation that allows you to keep track of how many elements were already iterated over. - * @param action The action to be performed for each element - * @throws NullPointerException if the specified action is null - */ - public default void forEachIndexed(IntIntConsumer action) { - Objects.requireNonNull(action); - int index = 0; - for(IntIterator iter = iterator();iter.hasNext();action.accept(index++, iter.nextInt())); - } - - /** - * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. - * @param input the object that should be included - * @param action The action to be performed for each element - * @param the generic type of the Object - * @throws NullPointerException if the specified action is null - */ - default void forEach(E input, ObjectIntConsumer action) { - Objects.requireNonNull(action); - iterator().forEachRemaining(input, action); - } - - /** - * A Type Specific Type Splititerator to reduce boxing/unboxing - * @return type specific splititerator - */ - @Override - default IntSplititerator spliterator() { return IntSplititerators.createUnknownSplititerator(iterator(), 0); } - - /** - * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. - * @param mapper the mapping function - * @param The return type. - * @return a new Iterable that returns the desired result - */ - default ObjectIterable map(IntFunction mapper) { - return IntIterables.map(this, mapper); - } - - /** - * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. - * @param mapper the flatMapping function - * @param The return type supplier. - * @param The return type. - * @return a new Iterable that returns the desired result - * @note does not support toIntArray optimizations. - */ - default > ObjectIterable flatMap(IntFunction mapper) { - return IntIterables.flatMap(this, mapper); - } - - /** - * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. - * @param mapper the flatMapping function - * @param The return type. - * @return a new Iterable that returns the desired result - * @note does not support toIntArray optimizations. - */ - default ObjectIterable arrayflatMap(IntFunction mapper) { - return IntIterables.arrayFlatMap(this, mapper); - } - - /** - * A Helper function to reduce the usage of Streams and allows to filter out unwanted elements - * @param filter the elements that should be kept. - * @return a Iterable that filtered out all unwanted elements - * @note does not support toIntArray optimizations. - */ - default IntIterable filter(IntPredicate filter) { - return IntIterables.filter(this, filter); - } - - /** - * A Helper function to reduce the usage of Streams and allows to filter out duplicated elements - * @return a Iterable that filtered out all duplicated elements - * @note does not support toIntArray optimizations. - */ - default IntIterable distinct() { - return IntIterables.distinct(this); - } - - /** - * A Helper function to reduce the usage of Streams and allows to repeat elements a desired amount of times - * @param repeats how many times the elements should be repeated - * @return a Iterable that is repeating multiple times - */ - default IntIterable repeat(int repeats) { - return IntIterables.repeat(this, repeats); - } - - /** - * A Helper function to reduce the usage of Streams and allows to limit the amount of elements - * @param limit the amount of elements it should be limited to - * @return a Iterable that is limited in length - */ - default IntIterable limit(long limit) { - return IntIterables.limit(this, limit); - } - - /** - * A Helper function to reduce the usage of Streams and allows to sort the elements - * @param sorter that sorts the elements. - * @return a Iterable that is sorted - */ - default IntIterable sorted(IntComparator sorter) { - return IntIterables.sorted(this, sorter); - } - - /** - * A Helper function to reduce the usage of Streams and allows to preview elements before they are iterated through - * @param action the action that should be applied - * @return a Peeked Iterable - */ - default IntIterable peek(IntConsumer action) { - return IntIterables.peek(this, action); - } - - /** - * A Helper function to reduce the usage of Streams and allows to collect all elements - * @param collection that the elements should be inserted to - * @param the collection type - * @return the input with the desired elements - */ - default E pour(E collection) { - IntIterators.pour(iterator(), collection); - return collection; - } - - - /** - * A Helper function that reduces the usage of streams and allows to collect all elements as a Array - * @return a new Array of all elements - */ - default int[] toIntArray() { - ISizeProvider prov = ISizeProvider.of(this); - if(prov != null) { - int size = prov.size(); - if(size >= 0) { - int[] array = new int[size]; - IntIterators.unwrap(array, iterator()); - return array; - } - } - return IntArrays.pour(iterator()); - } - - /** - * Helper function to reduce stream usage that allows to filter for any matches. - * @param filter that should be applied - * @return true if any matches were found - */ - default boolean matchesAny(IntPredicate filter) { - Objects.requireNonNull(filter); - for(IntIterator iter = iterator();iter.hasNext();) { - if(filter.test(iter.nextInt())) return true; - } - return false; - } - - /** - * Helper function to reduce stream usage that allows to filter for no matches. - * @param filter that should be applied - * @return true if no matches were found - */ - default boolean matchesNone(IntPredicate filter) { - Objects.requireNonNull(filter); - for(IntIterator iter = iterator();iter.hasNext();) { - if(filter.test(iter.nextInt())) return false; - } - return true; - } - - /** - * Helper function to reduce stream usage that allows to filter for all matches. - * @param filter that should be applied - * @return true if all matches. - */ - default boolean matchesAll(IntPredicate filter) { - Objects.requireNonNull(filter); - for(IntIterator iter = iterator();iter.hasNext();) { - if(!filter.test(iter.nextInt())) return false; - } - return true; - } - - /** - * Helper function to reduce stream usage that allows to filter for the first match. - * @param filter that should be applied - * @return the found value or the null equivalent variant. - */ - default int findFirst(IntPredicate filter) { - Objects.requireNonNull(filter); - for(IntIterator iter = iterator();iter.hasNext();) { - int entry = iter.nextInt(); - if(filter.test(entry)) return entry; - } - return 0; - } - - /** - * Performs a reduction on the - * elements of this Iterable - * @param operator the operation that should be applied - * @param identity the start value - * @return the reduction result, returns identity if nothing was found - */ - default int reduce(int identity, IntIntUnaryOperator operator) { - Objects.requireNonNull(operator); - int state = identity; - for(IntIterator iter = iterator();iter.hasNext();) { - state = operator.applyAsInt(state, iter.nextInt()); - } - return state; - } - - /** - * Performs a reduction on the - * elements of this Iterable - * @param operator the operation that should be applied - * @return the reduction result, returns null value if nothing was found - */ - default int reduce(IntIntUnaryOperator operator) { - Objects.requireNonNull(operator); - int state = 0; - boolean empty = true; - for(IntIterator iter = iterator();iter.hasNext();) { - if(empty) { - empty = false; - state = iter.nextInt(); - continue; - } - state = operator.applyAsInt(state, iter.nextInt()); - } - return state; - } - - /** - * Helper function to reduce stream usage that allows to count the valid elements. - * @param filter that should be applied - * @return the amount of Valid Elements - */ - default int count(IntPredicate filter) { - Objects.requireNonNull(filter); - int result = 0; - for(IntIterator iter = iterator();iter.hasNext();) { - if(filter.test(iter.nextInt())) result++; - } - return result; - } -} diff --git a/src/main/java/speiger/src/collections/ints/collections/IntIterator.java b/src/main/java/speiger/src/collections/ints/collections/IntIterator.java deleted file mode 100644 index 626ff1c82..000000000 --- a/src/main/java/speiger/src/collections/ints/collections/IntIterator.java +++ /dev/null @@ -1,88 +0,0 @@ -package speiger.src.collections.ints.collections; - -import java.util.Iterator; -import java.util.Objects; -import java.util.function.Consumer; - -import speiger.src.collections.ints.functions.IntConsumer; - -import speiger.src.collections.objects.functions.consumer.ObjectIntConsumer; - -/** - * A Type-Specific {@link Iterator} that reduces (un)boxing - */ -public interface IntIterator extends Iterator -{ - /** - * Returns the next element in the iteration. - * - * @return the next element in the iteration - * @throws java.util.NoSuchElementException if the iteration has no more elements - * @see Iterator#next() - */ - public int nextInt(); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default Integer next() { return Integer.valueOf(nextInt()); } - - /** - * Performs the given action for each remaining element until all elements - * have been processed or the action throws an exception. Actions are - * performed in the order of iteration, if that order is specified. - * Exceptions thrown by the action are relayed to the caller. - * - * @implSpec - *

The default implementation behaves as if: - *

{@code
-	 *	while (hasNext()) action.accept(nextInt());
-	 * }
- * - * @param action The action to be performed for each element - * @throws NullPointerException if the specified action is null - * @see Iterator#forEachRemaining(Consumer) - */ - public default void forEachRemaining(IntConsumer action) { - Objects.requireNonNull(action); - while(hasNext()) { action.accept(nextInt()); } - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Deprecated - @Override - default void forEachRemaining(Consumer action) { - Objects.requireNonNull(action); - forEachRemaining(action::accept); - } - - /** - * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. - * @param input the object that should be included - * @param action The action to be performed for each element - * @param the generic type of the Object - * @throws NullPointerException if the specified action is null - */ - default void forEachRemaining(E input, ObjectIntConsumer action) { - Objects.requireNonNull(action); - while(hasNext()) { action.accept(input, nextInt()); } - } - - /** - * Skips the Given amount of elements if possible. A Optimization function to skip elements faster if the implementation allows it. - * @param amount the amount of elements that should be skipped - * @return the amount of elements that were skipped - */ - default int skip(int amount) { - if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); - int i = 0; - for(;i, IntIterator -{ - @Override - default void forEachRemaining(IntConsumer action) { IntIterator.super.forEachRemaining(action); } - @Override - @Deprecated - default void forEachRemaining(Consumer action) { IntIterator.super.forEachRemaining(action); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/collections/IntStack.java b/src/main/java/speiger/src/collections/ints/collections/IntStack.java deleted file mode 100644 index 57731e4c5..000000000 --- a/src/main/java/speiger/src/collections/ints/collections/IntStack.java +++ /dev/null @@ -1,62 +0,0 @@ -package speiger.src.collections.ints.collections; - -import speiger.src.collections.utils.Stack; - -/** - * A Type-Specific {@link Stack} that reduces (un)boxing - */ -public interface IntStack -{ - /** - * Inserts a given Object on top of the stack - * @param e the Object to insert - * @see Stack#push(Object) - */ - public void push(int e); - - /** - * Removes the Object on top of the stack. - * @return the element that is on top of the stack - * @throws ArrayIndexOutOfBoundsException if the stack is empty - * @see Stack#pop() - */ - public int pop(); - - /** - * Provides the Object on top of the stack - * @return the element that is on top of the stack - * @throws ArrayIndexOutOfBoundsException if the stack is empty - * @see Stack#top() - */ - public default int top() { - return peek(0); - } - - /** - * Provides the Selected Object from the stack. - * Top to bottom - * @param index of the element that should be provided - * @return the element that was requested - * @throws ArrayIndexOutOfBoundsException if the index is out of bounds - * @see Stack#peek(int) - */ - public int peek(int index); - - /** - * Clears the stack - */ - public void clear(); - - /** - * Provides the amount of elements currently in the stack - * @return amount of elements in the list - */ - public int size(); - - /** - * @return if the stack is empty - */ - public default boolean isEmpty() { - return size() == 0; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/IntComparator.java b/src/main/java/speiger/src/collections/ints/functions/IntComparator.java deleted file mode 100644 index 81a78895b..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/IntComparator.java +++ /dev/null @@ -1,70 +0,0 @@ -package speiger.src.collections.ints.functions; - -import java.util.Comparator; -import java.util.Objects; - -/** - * Type-Specific Class for Comparator to reduce (un)boxing - */ -public interface IntComparator extends Comparator -{ - /** - * Type-Specific compare function to reduce (un)boxing - * @param o1 the first object to be compared. - * @param o2 the second object to be compared. - * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. - * @see Comparator#compare(Object, Object) - */ - int compare(int o1, int o2); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default int compare(Integer o1, Integer o2) { - return compare(o1.intValue(), o2.intValue()); - } - - /** - * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator - * @param c comparator to convert - * @return the wrapper of the comparator - * @throws NullPointerException if the comparator is null - */ - public static IntComparator of(Comparator c) { - Objects.requireNonNull(c); - return (K, V) -> c.compare(Integer.valueOf(K), Integer.valueOf(V)); - } - - @Override - public default IntComparator reversed() { - return new Reversed(this); - } - - /** - * A Type Specific Reversed Comparator to reduce boxing/unboxing - */ - static class Reversed implements IntComparator - { - IntComparator original; - - /** - * default constructor - * @param original that is going to be reversed - */ - public Reversed(IntComparator original) { - this.original = original; - } - - public int compare(int o1, int o2) { - return original.compare(o2, o1); - } - - @Override - public IntComparator reversed() { - return original; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/IntConsumer.java b/src/main/java/speiger/src/collections/ints/functions/IntConsumer.java deleted file mode 100644 index 0bd0e65fb..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/IntConsumer.java +++ /dev/null @@ -1,59 +0,0 @@ -package speiger.src.collections.ints.functions; - -import java.util.Objects; -import java.util.function.Consumer; -/** - * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -@FunctionalInterface -public interface IntConsumer extends Consumer, java.util.function.IntConsumer -{ - /** - * Type-Specific function to reduce (un)boxing. - * Performs this operation on the given argument. - * - * @param t the input argument - */ - void accept(int t); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced consumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default IntConsumer andThen(IntConsumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(T);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Integer t) { accept(t.intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default IntConsumer andThen(Consumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(Integer.valueOf(T));}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default IntConsumer andThen(java.util.function.IntConsumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(T);}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/IntSupplier.java b/src/main/java/speiger/src/collections/ints/functions/IntSupplier.java deleted file mode 100644 index 10d7293c8..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/IntSupplier.java +++ /dev/null @@ -1,12 +0,0 @@ -package speiger.src.collections.ints.functions; - -/** - * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -public interface IntSupplier extends java.util.function.IntSupplier -{ - /** - * @return the supplied value - */ - public int getAsInt(); -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntBooleanConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntBooleanConsumer.java deleted file mode 100644 index deb8915ca..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/consumer/IntBooleanConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.ints.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface IntBooleanConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(int k, boolean v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default IntBooleanConsumer andThen(IntBooleanConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Integer k, Boolean v) { accept(k.intValue(), v.booleanValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default IntBooleanConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Boolean.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntByteConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntByteConsumer.java deleted file mode 100644 index c5774680d..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/consumer/IntByteConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.ints.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface IntByteConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(int k, byte v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default IntByteConsumer andThen(IntByteConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Integer k, Byte v) { accept(k.intValue(), v.byteValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default IntByteConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Byte.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntCharConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntCharConsumer.java deleted file mode 100644 index 74a0ff391..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/consumer/IntCharConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.ints.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface IntCharConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(int k, char v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default IntCharConsumer andThen(IntCharConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Integer k, Character v) { accept(k.intValue(), v.charValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default IntCharConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Character.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntDoubleConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntDoubleConsumer.java deleted file mode 100644 index fb44f3df3..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/consumer/IntDoubleConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.ints.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface IntDoubleConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(int k, double v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default IntDoubleConsumer andThen(IntDoubleConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Integer k, Double v) { accept(k.intValue(), v.doubleValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default IntDoubleConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Double.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntFloatConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntFloatConsumer.java deleted file mode 100644 index 766d64158..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/consumer/IntFloatConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.ints.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface IntFloatConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(int k, float v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default IntFloatConsumer andThen(IntFloatConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Integer k, Float v) { accept(k.intValue(), v.floatValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default IntFloatConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Float.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntIntConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntIntConsumer.java deleted file mode 100644 index f8a000a33..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/consumer/IntIntConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.ints.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface IntIntConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(int k, int v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default IntIntConsumer andThen(IntIntConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Integer k, Integer v) { accept(k.intValue(), v.intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default IntIntConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Integer.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntLongConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntLongConsumer.java deleted file mode 100644 index 401e5b4f7..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/consumer/IntLongConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.ints.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface IntLongConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(int k, long v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default IntLongConsumer andThen(IntLongConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Integer k, Long v) { accept(k.intValue(), v.longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default IntLongConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Long.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntObjectConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntObjectConsumer.java deleted file mode 100644 index cfa621bcb..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/consumer/IntObjectConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.ints.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface IntObjectConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(int k, V v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default IntObjectConsumer andThen(IntObjectConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Integer k, V v) { accept(k.intValue(), v); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default IntObjectConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), V);}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/consumer/IntShortConsumer.java b/src/main/java/speiger/src/collections/ints/functions/consumer/IntShortConsumer.java deleted file mode 100644 index 254d7f669..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/consumer/IntShortConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.ints.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface IntShortConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(int k, short v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default IntShortConsumer andThen(IntShortConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Integer k, Short v) { accept(k.intValue(), v.shortValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default IntShortConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Integer.valueOf(K), Short.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2ByteFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2ByteFunction.java deleted file mode 100644 index 21c2e245b..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/Int2ByteFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.ints.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Int2ByteFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public byte applyAsByte(int k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2CharFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2CharFunction.java deleted file mode 100644 index 51a398bbe..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/Int2CharFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.ints.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Int2CharFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public char applyAsChar(int k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2DoubleFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2DoubleFunction.java deleted file mode 100644 index 2de20d298..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/Int2DoubleFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.ints.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Int2DoubleFunction extends java.util.function.IntToDoubleFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public double applyAsDouble(int k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2FloatFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2FloatFunction.java deleted file mode 100644 index ea5f500c7..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/Int2FloatFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.ints.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Int2FloatFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public float applyAsFloat(int k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2LongFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2LongFunction.java deleted file mode 100644 index 01311f37d..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/Int2LongFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.ints.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Int2LongFunction extends java.util.function.IntToLongFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public long applyAsLong(int k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/Int2ShortFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/Int2ShortFunction.java deleted file mode 100644 index 0364640e5..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/Int2ShortFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.ints.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Int2ShortFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public short applyAsShort(int k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntBooleanUnaryOperator.java deleted file mode 100644 index c733dc345..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntBooleanUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.ints.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface IntBooleanUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public boolean applyAsBoolean(int k, boolean v); - - @Override - public default Boolean apply(Integer k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.intValue(), v.booleanValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntByteUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntByteUnaryOperator.java deleted file mode 100644 index 13131d4f9..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntByteUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.ints.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface IntByteUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public byte applyAsByte(int k, byte v); - - @Override - public default Byte apply(Integer k, Byte v) { return Byte.valueOf(applyAsByte(k.intValue(), v.byteValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntCharUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntCharUnaryOperator.java deleted file mode 100644 index d77f63888..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntCharUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.ints.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface IntCharUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public char applyAsChar(int k, char v); - - @Override - public default Character apply(Integer k, Character v) { return Character.valueOf(applyAsChar(k.intValue(), v.charValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntDoubleUnaryOperator.java deleted file mode 100644 index d6abe599d..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntDoubleUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.ints.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface IntDoubleUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public double applyAsDouble(int k, double v); - - @Override - public default Double apply(Integer k, Double v) { return Double.valueOf(applyAsDouble(k.intValue(), v.doubleValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntFloatUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntFloatUnaryOperator.java deleted file mode 100644 index 5b306c323..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntFloatUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.ints.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface IntFloatUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public float applyAsFloat(int k, float v); - - @Override - public default Float apply(Integer k, Float v) { return Float.valueOf(applyAsFloat(k.intValue(), v.floatValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntFunction.java b/src/main/java/speiger/src/collections/ints/functions/function/IntFunction.java deleted file mode 100644 index 4660c7194..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.ints.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface IntFunction extends java.util.function.IntFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public V apply(int k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntIntUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntIntUnaryOperator.java deleted file mode 100644 index 6b92a8a51..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntIntUnaryOperator.java +++ /dev/null @@ -1,13 +0,0 @@ -package speiger.src.collections.ints.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ - -public interface IntIntUnaryOperator extends BiFunction, java.util.function.IntBinaryOperator -{ - @Override - public default Integer apply(Integer k, Integer v) { return Integer.valueOf(applyAsInt(k.intValue(), v.intValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntLongUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntLongUnaryOperator.java deleted file mode 100644 index 008526f80..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntLongUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.ints.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface IntLongUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public long applyAsLong(int k, long v); - - @Override - public default Long apply(Integer k, Long v) { return Long.valueOf(applyAsLong(k.intValue(), v.longValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntObjectUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntObjectUnaryOperator.java deleted file mode 100644 index 338e398b5..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntObjectUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.ints.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface IntObjectUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public V apply(int k, V v); - - @Override - public default V apply(Integer k, V v) { return apply(k.intValue(), v); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntPredicate.java b/src/main/java/speiger/src/collections/ints/functions/function/IntPredicate.java deleted file mode 100644 index 7f7c138f6..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntPredicate.java +++ /dev/null @@ -1,72 +0,0 @@ -package speiger.src.collections.ints.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface IntPredicate extends java.util.function.IntPredicate -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public boolean test(int k); - - /** - * Creates a Always true function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static IntPredicate alwaysTrue() { - return T -> true; - } - - /** - * Creates a Always false function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static IntPredicate alwaysFalse() { - return T -> false; - } - - /** - * A Type specific and-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a and comparason - */ - public default IntPredicate andType(IntPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - @Override - @Deprecated - public default IntPredicate and(java.util.function.IntPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - @Override - public default IntPredicate negate() { - return T -> !test(T); - } - - /** - * A Type specific or-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a or comparason - */ - public default IntPredicate orType(IntPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } - - @Override - @Deprecated - public default IntPredicate or(java.util.function.IntPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntShortUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntShortUnaryOperator.java deleted file mode 100644 index 2f4648aaf..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntShortUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.ints.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface IntShortUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public short applyAsShort(int k, short v); - - @Override - public default Short apply(Integer k, Short v) { return Short.valueOf(applyAsShort(k.intValue(), v.shortValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/functions/function/IntUnaryOperator.java b/src/main/java/speiger/src/collections/ints/functions/function/IntUnaryOperator.java deleted file mode 100644 index 0693d8085..000000000 --- a/src/main/java/speiger/src/collections/ints/functions/function/IntUnaryOperator.java +++ /dev/null @@ -1,54 +0,0 @@ -package speiger.src.collections.ints.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface IntUnaryOperator extends java.util.function.IntUnaryOperator -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public int applyAsInt(int k); - - /** - * Creates a Default function that returns the input provided. - * @return a input returning function - */ - public static IntUnaryOperator identity() { - return T -> T; - } - - /** - * Returns a composed function that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param before the function that should be used first - * @return a composed function with a different starting function. - */ - public default IntUnaryOperator compose(IntUnaryOperator before) { - Objects.requireNonNull(before); - return T -> applyAsInt(before.applyAsInt(T)); - } - - /** - * Returns a composed function that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param after the function that should be used last - * @return a composed function with a different starting function. - */ - public default IntUnaryOperator andThen(IntUnaryOperator after) { - Objects.requireNonNull(after); - return T -> after.applyAsInt(applyAsInt(T)); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/lists/IntListIterator.java b/src/main/java/speiger/src/collections/ints/lists/IntListIterator.java deleted file mode 100644 index 425aa06df..000000000 --- a/src/main/java/speiger/src/collections/ints/lists/IntListIterator.java +++ /dev/null @@ -1,65 +0,0 @@ -package speiger.src.collections.ints.lists; - -import java.util.ListIterator; - -import speiger.src.collections.ints.collections.IntBidirectionalIterator; - -/** - * A Type Specific ListIterator that reduces boxing/unboxing - */ -public interface IntListIterator extends ListIterator, IntBidirectionalIterator -{ - /** - * A Primitive set function to reduce (un)boxing - * @param e the element that should replace the last returned value - * @see ListIterator#set(Object) - */ - public void set(int e); - - /** - * A Primitive set function to reduce (un)boxing - * @param e the element that should be inserted before the last returned value - * @see ListIterator#set(Object) - */ - public void add(int e); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default Integer previous() { - return IntBidirectionalIterator.super.previous(); - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default Integer next() { - return IntBidirectionalIterator.super.next(); - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default void set(Integer e) { - set(e.intValue()); - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default void add(Integer e) { - add(e.intValue()); - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/maps/abstracts/AbstractInt2ObjectMap.java b/src/main/java/speiger/src/collections/ints/maps/abstracts/AbstractInt2ObjectMap.java deleted file mode 100644 index 855d3d2b9..000000000 --- a/src/main/java/speiger/src/collections/ints/maps/abstracts/AbstractInt2ObjectMap.java +++ /dev/null @@ -1,451 +0,0 @@ -package speiger.src.collections.ints.maps.abstracts; - -import java.util.AbstractMap; -import java.util.Map; -import java.util.Objects; - -import speiger.src.collections.ints.collections.IntIterator; -import speiger.src.collections.ints.functions.consumer.IntObjectConsumer; -import speiger.src.collections.ints.functions.function.IntFunction; -import speiger.src.collections.ints.functions.function.IntObjectUnaryOperator; -import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap; -import speiger.src.collections.ints.sets.AbstractIntSet; -import speiger.src.collections.ints.sets.IntSet; -import speiger.src.collections.objects.collections.AbstractObjectCollection; -import speiger.src.collections.objects.collections.ObjectCollection; -import speiger.src.collections.objects.collections.ObjectIterator; -import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator; -import speiger.src.collections.objects.functions.ObjectSupplier; -import speiger.src.collections.objects.collections.ObjectIterable; -import speiger.src.collections.objects.sets.ObjectSet; -import speiger.src.collections.utils.SanityChecks; - -/** - * A Base Implementation of a Type Specific Map to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public abstract class AbstractInt2ObjectMap extends AbstractMap implements Int2ObjectMap -{ - protected V defaultReturnValue = null; - - @Override - public V getDefaultReturnValue() { - return defaultReturnValue; - } - - @Override - public AbstractInt2ObjectMap setDefaultReturnValue(V v) { - defaultReturnValue = v; - return this; - } - - protected ObjectIterable> getFastIterable(Int2ObjectMap map) { - return map.int2ObjectEntrySet(); - } - - protected ObjectIterator> getFastIterator(Int2ObjectMap map) { - return map.int2ObjectEntrySet().iterator(); - } - - @Override - public Int2ObjectMap copy() { - throw new UnsupportedOperationException(); - } - - @Override - @Deprecated - public V put(Integer key, V value) { - return put(key.intValue(), value); - } - - @Override - public void putAll(Int2ObjectMap m) { - for(ObjectIterator> iter = getFastIterator(m);iter.hasNext();) { - Int2ObjectMap.Entry entry = iter.next(); - put(entry.getIntKey(), entry.getValue()); - } - } - - @Override - public void putAll(Map m) - { - if(m instanceof Int2ObjectMap) putAll((Int2ObjectMap)m); - else super.putAll(m); - } - - @Override - public void putAll(int[] keys, V[] values, int offset, int size) { - SanityChecks.checkArrayCapacity(keys.length, offset, size); - SanityChecks.checkArrayCapacity(values.length, offset, size); - for(int i = 0;i m) { - for(Int2ObjectMap.Entry entry : getFastIterable(m)) - putIfAbsent(entry.getIntKey(), entry.getValue()); - } - - - @Override - public boolean containsKey(int key) { - for(IntIterator iter = keySet().iterator();iter.hasNext();) - if(iter.nextInt() == key) return true; - return false; - } - - @Override - public boolean containsValue(Object value) { - for(ObjectIterator iter = values().iterator();iter.hasNext();) - if(Objects.equals(value, iter.next())) return true; - return false; - } - - @Override - public boolean replace(int key, V oldValue, V newValue) { - V curValue = get(key); - if (!Objects.equals(curValue, oldValue) || (Objects.equals(curValue, getDefaultReturnValue()) && !containsKey(key))) { - return false; - } - put(key, newValue); - return true; - } - - @Override - public V replace(int key, V value) { - V curValue; - if (!Objects.equals((curValue = get(key)), getDefaultReturnValue()) || containsKey(key)) { - curValue = put(key, value); - } - return curValue; - } - - @Override - public void replaceObjects(Int2ObjectMap m) { - for(Int2ObjectMap.Entry entry : getFastIterable(m)) - replace(entry.getIntKey(), entry.getValue()); - } - - @Override - public void replaceObjects(IntObjectUnaryOperator mappingFunction) { - Objects.requireNonNull(mappingFunction); - for(ObjectIterator> iter = getFastIterator(this);iter.hasNext();) { - Int2ObjectMap.Entry entry = iter.next(); - entry.setValue(mappingFunction.apply(entry.getIntKey(), entry.getValue())); - } - } - - @Override - public V compute(int key, IntObjectUnaryOperator mappingFunction) { - Objects.requireNonNull(mappingFunction); - V value = get(key); - V newValue = mappingFunction.apply(key, value); - if(Objects.equals(newValue, getDefaultReturnValue())) { - if(!Objects.equals(value, getDefaultReturnValue()) || containsKey(key)) { - remove(key); - return getDefaultReturnValue(); - } - return getDefaultReturnValue(); - } - put(key, newValue); - return newValue; - } - - @Override - public V computeIfAbsent(int key, IntFunction mappingFunction) { - Objects.requireNonNull(mappingFunction); - V value; - if((value = get(key)) == getDefaultReturnValue() || !containsKey(key)) { - V newValue = mappingFunction.apply(key); - if(!Objects.equals(newValue, getDefaultReturnValue())) { - put(key, newValue); - return newValue; - } - } - return value; - } - - @Override - public V supplyIfAbsent(int key, ObjectSupplier valueProvider) { - Objects.requireNonNull(valueProvider); - V value; - if((value = get(key)) == getDefaultReturnValue() || !containsKey(key)) { - V newValue = valueProvider.get(); - if(!Objects.equals(newValue, getDefaultReturnValue())) { - put(key, newValue); - return newValue; - } - } - return value; - } - - @Override - public V computeIfPresent(int key, IntObjectUnaryOperator mappingFunction) { - Objects.requireNonNull(mappingFunction); - V value; - if(!Objects.equals((value = get(key)), getDefaultReturnValue()) || containsKey(key)) { - V newValue = mappingFunction.apply(key, value); - if(!Objects.equals(newValue, getDefaultReturnValue())) { - put(key, newValue); - return newValue; - } - remove(key); - } - return getDefaultReturnValue(); - } - - @Override - public V merge(int key, V value, ObjectObjectUnaryOperator mappingFunction) { - Objects.requireNonNull(mappingFunction); - V oldValue = get(key); - V newValue = Objects.equals(oldValue, getDefaultReturnValue()) ? value : mappingFunction.apply(oldValue, value); - if(Objects.equals(newValue, getDefaultReturnValue())) remove(key); - else put(key, newValue); - return newValue; - } - - @Override - public void mergeAll(Int2ObjectMap m, ObjectObjectUnaryOperator mappingFunction) { - Objects.requireNonNull(mappingFunction); - for(Int2ObjectMap.Entry entry : getFastIterable(m)) { - int key = entry.getIntKey(); - V oldValue = get(key); - V newValue = Objects.equals(oldValue, getDefaultReturnValue()) ? entry.getValue() : mappingFunction.apply(oldValue, entry.getValue()); - if(Objects.equals(newValue, getDefaultReturnValue())) remove(key); - else put(key, newValue); - } - } - - @Override - public V get(Object key) { - return key instanceof Integer ? get(((Integer)key).intValue()) : getDefaultReturnValue(); - } - - @Override - public V getOrDefault(Object key, V defaultValue) { - return key instanceof Integer ? getOrDefault(((Integer)key).intValue(), defaultValue) : getDefaultReturnValue(); - } - - @Override - public V getOrDefault(int key, V defaultValue) { - V value = get(key); - return !Objects.equals(value, getDefaultReturnValue()) || containsKey(key) ? value : defaultValue; - } - - - @Override - public V remove(Object key) { - return key instanceof Integer ? remove(((Integer)key).intValue()) : getDefaultReturnValue(); - } - - @Override - public void forEach(IntObjectConsumer action) { - Objects.requireNonNull(action); - for(ObjectIterator> iter = getFastIterator(this);iter.hasNext();) { - Int2ObjectMap.Entry entry = iter.next(); - action.accept(entry.getIntKey(), entry.getValue()); - } - } - - @Override - public IntSet keySet() { - return new AbstractIntSet() { - @Override - public boolean remove(int o) { - return !Objects.equals(AbstractInt2ObjectMap.this.remove(o), getDefaultReturnValue()); - } - - @Override - public boolean add(int o) { - throw new UnsupportedOperationException(); - } - - @Override - public IntIterator iterator() { - return new IntIterator() { - ObjectIterator> iter = getFastIterator(AbstractInt2ObjectMap.this); - @Override - public boolean hasNext() { - return iter.hasNext(); - } - - @Override - public int nextInt() { - return iter.next().getIntKey(); - } - - @Override - public void remove() { - iter.remove(); - } - }; - } - - @Override - public int size() { - return AbstractInt2ObjectMap.this.size(); - } - - @Override - public void clear() { - AbstractInt2ObjectMap.this.clear(); - } - }; - } - - @Override - public ObjectCollection values() { - return new AbstractObjectCollection() { - @Override - public boolean add(V o) { - throw new UnsupportedOperationException(); - } - - @Override - public int size() { - return AbstractInt2ObjectMap.this.size(); - } - - @Override - public void clear() { - AbstractInt2ObjectMap.this.clear(); - } - - @Override - public ObjectIterator iterator() { - return new ObjectIterator() { - ObjectIterator> iter = getFastIterator(AbstractInt2ObjectMap.this); - @Override - public boolean hasNext() { - return iter.hasNext(); - } - - @Override - public V next() { - return iter.next().getValue(); - } - - @Override - public void remove() { - iter.remove(); - } - }; - } - }; - } - - @Override - @SuppressWarnings("rawtypes") - public ObjectSet> entrySet() { - return (ObjectSet)int2ObjectEntrySet(); - } - - @Override - public boolean equals(Object o) { - if(o == this) return true; - if(o instanceof Map) { - if(size() != ((Map)o).size()) return false; - if(o instanceof Int2ObjectMap) return int2ObjectEntrySet().containsAll(((Int2ObjectMap)o).int2ObjectEntrySet()); - return int2ObjectEntrySet().containsAll(((Map)o).entrySet()); - } - return false; - } - - @Override - public int hashCode() { - int hash = 0; - ObjectIterator> iter = getFastIterator(this); - while(iter.hasNext()) hash += iter.next().hashCode(); - return hash; - } - - /** - * A Simple Type Specific Entry class to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ - public static class BasicEntry implements Int2ObjectMap.Entry { - protected int key; - protected V value; - - /** - * A basic Empty constructor - */ - public BasicEntry() {} - /** - * A Boxed Constructor for supporting java variants - * @param key the key of a entry - * @param value the value of a entry - */ - public BasicEntry(Integer key, V value) { - this.key = key.intValue(); - this.value = value; - } - - /** - * A Type Specific Constructor - * @param key the key of a entry - * @param value the value of a entry - */ - public BasicEntry(int key, V value) { - this.key = key; - this.value = value; - } - - /** - * A Helper method for fast replacing values - * @param key the key that should be replaced - * @param value the value that should be replaced - */ - public void set(int key, V value) { - this.key = key; - this.value = value; - } - - @Override - public int getIntKey() { - return key; - } - - @Override - public V getValue() { - return value; - } - - @Override - public V setValue(V value) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean equals(Object obj) { - if(obj instanceof Map.Entry) { - if(obj instanceof Int2ObjectMap.Entry) { - Int2ObjectMap.Entry entry = (Int2ObjectMap.Entry)obj; - return key == entry.getIntKey() && Objects.equals(value, entry.getValue()); - } - Map.Entry entry = (Map.Entry)obj; - Object key = entry.getKey(); - Object value = entry.getValue(); - return key instanceof Integer && this.key == ((Integer)key).intValue() && Objects.equals(this.value, value); - } - return false; - } - - @Override - public int hashCode() { - return Integer.hashCode(key) ^ Objects.hashCode(value); - } - - @Override - public String toString() { - return Integer.toString(key) + "=" + Objects.toString(value); - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/maps/impl/misc/Int2ObjectArrayMap.java b/src/main/java/speiger/src/collections/ints/maps/impl/misc/Int2ObjectArrayMap.java deleted file mode 100644 index 2e6f09621..000000000 --- a/src/main/java/speiger/src/collections/ints/maps/impl/misc/Int2ObjectArrayMap.java +++ /dev/null @@ -1,1296 +0,0 @@ -package speiger.src.collections.ints.maps.impl.misc; - -import java.util.Arrays; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.BiFunction; -import java.util.function.Predicate; -import java.util.function.IntPredicate; - -import speiger.src.collections.ints.collections.IntBidirectionalIterator; -import speiger.src.collections.ints.functions.IntConsumer; -import speiger.src.collections.objects.functions.consumer.ObjectIntConsumer; -import speiger.src.collections.ints.functions.consumer.IntIntConsumer; -import speiger.src.collections.ints.functions.consumer.IntObjectConsumer; -import speiger.src.collections.ints.functions.consumer.IntObjectConsumer; -import speiger.src.collections.ints.functions.function.IntFunction; -import speiger.src.collections.ints.functions.function.IntObjectUnaryOperator; -import speiger.src.collections.ints.functions.function.IntIntUnaryOperator; -import speiger.src.collections.ints.lists.IntListIterator; -import speiger.src.collections.ints.maps.abstracts.AbstractInt2ObjectMap; -import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap; -import speiger.src.collections.ints.maps.interfaces.Int2ObjectOrderedMap; -import speiger.src.collections.ints.sets.AbstractIntSet; -import speiger.src.collections.ints.sets.IntOrderedSet; -import speiger.src.collections.objects.collections.AbstractObjectCollection; -import speiger.src.collections.objects.collections.ObjectCollection; -import speiger.src.collections.objects.collections.ObjectIterator; -import speiger.src.collections.objects.functions.ObjectSupplier; -import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator; -import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer; - -import speiger.src.collections.objects.collections.ObjectBidirectionalIterator; -import speiger.src.collections.objects.lists.ObjectListIterator; -import speiger.src.collections.objects.sets.AbstractObjectSet; -import speiger.src.collections.objects.sets.ObjectOrderedSet; -import speiger.src.collections.utils.HashUtil; - -/** - * A Very Specific Type Specific implementation of a ArrayMap. - * This type of map is for very specific use cases that usaully would have lead to Tupled Lists otherwise. - * It also does not allow duplication (except for array constructors) and checks from last to first. - * It is not designed to be used as a HashMap replacement due to the poor performance it would cause. - * @note in this implementation SubMaps do NOT keep track of parent changes fully. For performance reasons it will just have a start/end index and not values - * Anything within that range will be updated appropiatly a shrink/growth of elements will break SubMaps in some ways. This can be useful but be careful - * @note this implementation does not shrink and only grows. - * @param the keyType of elements maintained by this Collection - */ -public class Int2ObjectArrayMap extends AbstractInt2ObjectMap implements Int2ObjectOrderedMap -{ - /** The Backing keys array */ - protected transient int[] keys; - /** The Backing values array */ - protected transient V[] values; - /** Amount of Elements stored in the ArrayMap */ - protected int size = 0; - /** KeySet cache */ - protected IntOrderedSet keySet; - /** Values cache */ - protected ObjectCollection valuesC; - /** EntrySet cache */ - protected FastOrderedSet entrySet; - - /** - * Default Constructor - */ - public Int2ObjectArrayMap() { - this(HashUtil.DEFAULT_MIN_CAPACITY); - } - - /** - * Constructor that defines the minimum capacity - * @param minCapacity the minimum capacity the HashMap is allowed to be. - * @throws IllegalStateException if the minimum capacity is negative - */ - public Int2ObjectArrayMap(int minCapacity) { - if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); - keys = new int[minCapacity]; - values = (V[])new Object[minCapacity]; - } - - /** - * Helper constructor that allow to create a map from boxed values (it will unbox them) - * @param keys the keys that should be put into the map - * @param values the values that should be put into the map. - * @throws IllegalStateException if the keys and values do not match in length - */ - public Int2ObjectArrayMap(Integer[] keys, V[] values) { - this(keys, values, keys.length); - } - - /** - * Helper constructor that allow to create a map from boxed values (it will unbox them) with a custom length - * @param keys the keys that should be put into the map - * @param values the values that should be put into the map. - * @param length the amount of values that should be pulled from the array - * @throws IllegalStateException if the keys and values do not match in length - */ - public Int2ObjectArrayMap(Integer[] keys, V[] values, int length) { - this(length); - if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size"); - putAll(keys, values, 0, length); - } - - /** - * Helper constructor that allow to create a map from unboxed values - * @param keys the keys that should be put into the map - * @param values the values that should be put into the map. - * @throws IllegalStateException if the keys and values do not match in lenght - */ - public Int2ObjectArrayMap(int[] keys, V[] values) { - this(keys, values, keys.length); - } - - /** - * Helper constructor that allow to create a map from unboxed values - * @param keys the keys that should be put into the map - * @param values the values that should be put into the map. - * @param length the amount of values that should be pulled from the array - * @throws IllegalStateException if the keys and values do not match in lenght - */ - public Int2ObjectArrayMap(int[] keys, V[] values, int length) { - this(length); - if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size"); - putAll(keys, values, 0, length); - } - - /** - * A Helper constructor that allows to create a Map with exactly the same values as the provided map. - * @param map the values that should be present in the map - */ - public Int2ObjectArrayMap(Map map) { - this(map.size()); - putAll(map); - } - - /** - * A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map. - * @param map the values that should be present in the map - */ - public Int2ObjectArrayMap(Int2ObjectMap map) { - this(map.size()); - for(ObjectIterator> iter = getFastIterator(map);iter.hasNext();size++) { - Int2ObjectMap.Entry entry = iter.next(); - keys[size] = entry.getIntKey(); - values[size] = entry.getValue(); - } - } - - @Override - public V put(int key, V value) { - int index = findIndex(key); - if(index < 0) { - insertIndex(size++, key, value); - return getDefaultReturnValue(); - } - V oldValue = values[index]; - values[index] = value; - return oldValue; - } - - @Override - public V putIfAbsent(int key, V value) { - int index = findIndex(key); - if(index < 0) { - insertIndex(size++, key, value); - return getDefaultReturnValue(); - } - else if(Objects.equals(values[index], getDefaultReturnValue())) { - V oldValue = values[index]; - values[index] = value; - return oldValue; - } - return values[index]; - } - - @Override - public V putAndMoveToFirst(int key, V value) { - int index = findIndex(key); - if(index < 0) { - insertIndex(0, key, value); - size++; - return getDefaultReturnValue(); - } - V lastValue = values[index]; - values[index] = value; - moveIndexToFirst(index); - return lastValue; - } - - @Override - public V putAndMoveToLast(int key, V value) { - int index = findIndex(key); - if(index < 0) { - insertIndex(size++, key, value); - return getDefaultReturnValue(); - } - V lastValue = values[index]; - values[index] = value; - moveIndexToLast(index); - return lastValue; - } - - @Override - public boolean moveToFirst(int key) { - int index = findIndex(key); - if(index > 0) { - moveIndexToFirst(index); - return true; - } - return false; - } - - @Override - public boolean moveToLast(int key) { - int index = findIndex(key); - if(index >= 0 && index < size-1) { - moveIndexToLast(index); - return true; - } - return false; - } - - @Override - public boolean containsKey(int key) { - return findIndex(key) >= 0; - } - - @Override - public boolean containsKey(Object key) { - return findIndex(key) >= 0; - } - - @Override - public boolean containsValue(Object value) { - return findValue(value) >= 0; - } - - @Override - public V get(int key) { - int index = findIndex(key); - return index < 0 ? getDefaultReturnValue() : values[index]; - } - - @Override - public V getOrDefault(int key, V defaultValue) { - int index = findIndex(key); - return index < 0 ? defaultValue : values[index]; - } - - @Override - public V getAndMoveToFirst(int key) { - int index = findIndex(key); - if(index >= 0) { - V value = values[index]; - moveIndexToFirst(index); - return value; - } - return getDefaultReturnValue(); - } - - @Override - public V getAndMoveToLast(int key) { - int index = findIndex(key); - if(index >= 0) { - V value = values[index]; - moveIndexToLast(index); - return value; - } - return getDefaultReturnValue(); - } - - @Override - public int firstIntKey() { - if(size <= 0) throw new NoSuchElementException(); - return keys[0]; - } - - @Override - public int lastIntKey() { - if(size <= 0) throw new NoSuchElementException(); - return keys[size-1]; - } - - @Override - public V firstValue() { - if(size <= 0) throw new NoSuchElementException(); - return values[0]; - } - - @Override - public V lastValue() { - if(size <= 0) throw new NoSuchElementException(); - return values[size-1]; - } - - @Override - public int pollFirstIntKey() { - if(size == 0) throw new NoSuchElementException(); - int result = keys[0]; - removeIndex(0); - return result; - } - - @Override - public int pollLastIntKey() { - if(size == 0) throw new NoSuchElementException(); - int result = keys[size-1]; - removeIndex(size-1); - return result; - } - - @Override - public V remove(int key) { - int index = findIndex(key); - if(index < 0) return getDefaultReturnValue(); - V value = values[index]; - removeIndex(index); - return value; - } - - @Override - public V removeOrDefault(int key, V defaultValue) { - int index = findIndex(key); - if(index < 0) return defaultValue; - V value = values[index]; - removeIndex(index); - return value; - } - - @Override - public boolean remove(int key, V value) { - int index = findIndex(key, value); - if(index < 0) return false; - removeIndex(index); - return true; - } - - @Override - public V remove(Object key) { - int index = findIndex(key); - if(index < 0) return getDefaultReturnValue(); - V value = values[index]; - removeIndex(index); - return value; - } - - @Override - public boolean remove(Object key, Object value) { - int index = findIndex(key, value); - if(index < 0) return false; - removeIndex(index); - return true; - } - - @Override - public void forEach(IntObjectConsumer action) { - if(size() <= 0) return; - for(int i = 0;i values() { - if(valuesC == null) valuesC = new Values(); - return valuesC; - } - - @Override - public ObjectOrderedSet> int2ObjectEntrySet() { - if(entrySet == null) entrySet = new MapEntrySet(); - return entrySet; - } - - @Override - public boolean replace(int key, V oldValue, V newValue) { - int index = findIndex(key); - if(index < 0 || values[index] != oldValue) return false; - values[index] = newValue; - return true; - } - - @Override - public V replace(int key, V value) { - int index = findIndex(key); - if(index < 0) return getDefaultReturnValue(); - V oldValue = values[index]; - values[index] = value; - return oldValue; - } - - @Override - public V compute(int key, IntObjectUnaryOperator mappingFunction) { - Objects.requireNonNull(mappingFunction); - int index = findIndex(key); - if(index == -1) { - V newValue = mappingFunction.apply(key, getDefaultReturnValue()); - if(Objects.equals(newValue, getDefaultReturnValue())) return newValue; - insertIndex(size++, key, newValue); - return newValue; - } - V newValue = mappingFunction.apply(key, values[index]); - if(Objects.equals(newValue, getDefaultReturnValue())) { - removeIndex(index); - return newValue; - } - values[index] = newValue; - return newValue; - } - - @Override - public V computeIfAbsent(int key, IntFunction mappingFunction) { - Objects.requireNonNull(mappingFunction); - int index = findIndex(key); - if(index == -1) { - V newValue = mappingFunction.apply(key); - if(Objects.equals(newValue, getDefaultReturnValue())) return newValue; - insertIndex(size++, key, newValue); - return newValue; - } - V newValue = values[index]; - if(Objects.equals(newValue, getDefaultReturnValue())) { - newValue = mappingFunction.apply(key); - if(Objects.equals(newValue, getDefaultReturnValue())) return newValue; - values[index] = newValue; - } - return newValue; - } - - @Override - public V supplyIfAbsent(int key, ObjectSupplier valueProvider) { - Objects.requireNonNull(valueProvider); - int index = findIndex(key); - if(index == -1) { - V newValue = valueProvider.get(); - if(Objects.equals(newValue, getDefaultReturnValue())) return newValue; - insertIndex(size++, key, newValue); - return newValue; - } - V newValue = values[index]; - if(Objects.equals(newValue, getDefaultReturnValue())) { - newValue = valueProvider.get(); - if(Objects.equals(newValue, getDefaultReturnValue())) return newValue; - values[index] = newValue; - } - return newValue; - } - - @Override - public V computeIfPresent(int key, IntObjectUnaryOperator mappingFunction) { - Objects.requireNonNull(mappingFunction); - int index = findIndex(key); - if(index == -1 || Objects.equals(values[index], getDefaultReturnValue())) return getDefaultReturnValue(); - V newValue = mappingFunction.apply(key, values[index]); - if(Objects.equals(newValue, getDefaultReturnValue())) { - removeIndex(index); - return newValue; - } - values[index] = newValue; - return newValue; - } - - @Override - public V merge(int key, V value, ObjectObjectUnaryOperator mappingFunction) { - Objects.requireNonNull(mappingFunction); - Objects.requireNonNull(value); - int index = findIndex(key); - V newValue = index == -1 || Objects.equals(values[index], getDefaultReturnValue()) ? value : mappingFunction.apply(values[index], value); - if(Objects.equals(newValue, getDefaultReturnValue())) { - if(index >= 0) - removeIndex(index); - } - else if(index == -1) insertIndex(size++, key, newValue); - else values[index] = newValue; - return newValue; - } - - @Override - public void mergeAll(Int2ObjectMap m, ObjectObjectUnaryOperator mappingFunction) { - Objects.requireNonNull(mappingFunction); - for(Int2ObjectMap.Entry entry : getFastIterable(m)) { - int key = entry.getIntKey(); - int index = findIndex(key); - V newValue = index == -1 || Objects.equals(values[index], getDefaultReturnValue()) ? entry.getValue() : mappingFunction.apply(values[index], entry.getValue()); - if(Objects.equals(newValue, getDefaultReturnValue())) { - if(index >= 0) - removeIndex(index); - } - else if(index == -1) insertIndex(size++, key, newValue); - else values[index] = newValue; - } - } - - @Override - public int size() { - return size; - } - - @Override - public void clear() { - Arrays.fill(keys, 0, size, 0); - Arrays.fill(values, 0, size, null); - size = 0; - } - - public Int2ObjectArrayMap copy() { - Int2ObjectArrayMap map = new Int2ObjectArrayMap<>(); - map.size = size; - map.keys = Arrays.copyOf(keys, keys.length); - map.values = Arrays.copyOf(values, keys.length); - return map; - } - - protected void moveIndexToFirst(int index) { - if(index == 0) return; - int key = keys[index]; - V value = values[index]; - System.arraycopy(keys, 0, keys, 1, index); - System.arraycopy(values, 0, values, 1, index); - keys[0] = key; - values[0] = value; - } - - protected void moveIndexToLast(int index) { - if(index == size-1) return; - int key = keys[index]; - V value = values[index]; - System.arraycopy(keys, index+1, keys, index, size-index-1); - System.arraycopy(values, index+1, values, index, size-index-1); - keys[size-1] = key; - values[size-1] = value; - } - - protected void grow(int newSize) { - if(newSize < keys.length) return; - newSize = Math.max(newSize, keys.length == 0 ? 2 : keys.length * 2); - keys = Arrays.copyOf(keys, newSize); - values = Arrays.copyOf(values, newSize); - } - - protected void insertIndex(int index, int key, V value) { - grow(size+1); - if(index != size) { - System.arraycopy(keys, index, keys, index+1, size-index); - System.arraycopy(values, index, values, index+1, size-index); - } - keys[index] = key; - values[index] = value; - } - - protected void removeRange(int from, int to) { - if(from < 0 || from >= size) throw new IllegalStateException("From Element "); - int length = to - from; - if(length <= 0) return; - if(to != size) { - System.arraycopy(keys, to, keys, from, size - to); - System.arraycopy(values, to, values, from, size - to); - } - for(int i = 0;i=0;i--) - if(keys[i] == key && Objects.equals(values[i], value)) return i; - return -1; - } - - protected int findIndex(int key) { - for(int i = size-1;i>=0;i--) - if(keys[i] == key) return i; - return -1; - } - - protected int findIndex(Object key, Object value) { - for(int i = size-1;i>=0;i--) - if(Objects.equals(key, Integer.valueOf(keys[i])) && Objects.equals(value, values[i])) return i; - return -1; - } - - protected int findIndex(Object key) { - for(int i = size-1;i>=0;i--) - if(Objects.equals(key, Integer.valueOf(keys[i]))) return i; - return -1; - } - - protected int findValue(Object value) { - for(int i = size-1;i>=0;i--) - if(Objects.equals(value, values[i])) return i; - return -1; - } - - private class MapEntrySet extends AbstractObjectSet> implements FastOrderedSet { - @Override - public boolean addAndMoveToFirst(Int2ObjectMap.Entry o) { throw new UnsupportedOperationException(); } - @Override - public boolean addAndMoveToLast(Int2ObjectMap.Entry o) { throw new UnsupportedOperationException(); } - - @Override - public boolean moveToFirst(Int2ObjectMap.Entry o) { - return Int2ObjectArrayMap.this.moveToFirst(o.getIntKey()); - } - - @Override - public boolean moveToLast(Int2ObjectMap.Entry o) { - return Int2ObjectArrayMap.this.moveToLast(o.getIntKey()); - } - - @Override - public Int2ObjectMap.Entry first() { - return new BasicEntry<>(firstIntKey(), firstValue()); - } - - @Override - public Int2ObjectMap.Entry last() { - return new BasicEntry<>(lastIntKey(), lastValue()); - } - - @Override - public Int2ObjectMap.Entry pollFirst() { - BasicEntry entry = new BasicEntry<>(firstIntKey(), firstValue()); - pollFirstIntKey(); - return entry; - } - - @Override - public Int2ObjectMap.Entry pollLast() { - BasicEntry entry = new BasicEntry<>(lastIntKey(), lastValue()); - pollLastIntKey(); - return entry; - } - - @Override - public ObjectBidirectionalIterator> iterator() { - return new EntryIterator(); - } - - @Override - public ObjectBidirectionalIterator> iterator(Int2ObjectMap.Entry fromElement) { - return new EntryIterator(fromElement.getIntKey()); - } - - @Override - public ObjectBidirectionalIterator> fastIterator() { - return new FastEntryIterator(); - } - - @Override - public ObjectBidirectionalIterator> fastIterator(int fromElement) { - return new FastEntryIterator(fromElement); - } - - @Override - public MapEntrySet copy() { throw new UnsupportedOperationException(); } - - @Override - public void forEach(Consumer> action) { - Objects.requireNonNull(action); - for(int i = 0;i(keys[i], values[i])); - } - - @Override - public void fastForEach(Consumer> action) { - Objects.requireNonNull(action); - if(size() <= 0) return; - BasicEntry entry = new BasicEntry<>(); - for(int i = 0;i> action) { - Objects.requireNonNull(action); - for(int i = 0;i(keys[i], values[i])); - } - } - - @Override - public void forEach(E input, ObjectObjectConsumer> action) { - Objects.requireNonNull(action); - for(int i = 0;i(keys[i], values[i])); - } - } - - @Override - public boolean matchesAny(Predicate> filter) { - Objects.requireNonNull(filter); - if(size() <= 0) return false; - BasicEntry entry = new BasicEntry<>(); - for(int i = 0;i> filter) { - Objects.requireNonNull(filter); - if(size() <= 0) return true; - BasicEntry entry = new BasicEntry<>(); - for(int i = 0;i> filter) { - Objects.requireNonNull(filter); - if(size() <= 0) return true; - BasicEntry entry = new BasicEntry<>(); - for(int i = 0;i E reduce(E identity, BiFunction, E> operator) { - Objects.requireNonNull(operator); - E state = identity; - for(int i = 0;i(keys[i], values[i])); - } - return state; - } - - @Override - public Int2ObjectMap.Entry reduce(ObjectObjectUnaryOperator, Int2ObjectMap.Entry> operator) { - Objects.requireNonNull(operator); - Int2ObjectMap.Entry state = null; - boolean empty = true; - for(int i = 0;i(keys[i], values[i]); - continue; - } - state = operator.apply(state, new BasicEntry<>(keys[i], values[i])); - } - return state; - } - - @Override - public Int2ObjectMap.Entry findFirst(Predicate> filter) { - Objects.requireNonNull(filter); - if(size() <= 0) return null; - BasicEntry entry = new BasicEntry<>(); - for(int i = 0;i> filter) { - Objects.requireNonNull(filter); - if(size() <= 0) return 0; - int result = 0; - BasicEntry entry = new BasicEntry<>(); - for(int i = 0;i entry = (Int2ObjectMap.Entry)o; - int index = Int2ObjectArrayMap.this.findIndex(entry.getIntKey()); - if(index >= 0) return Objects.equals(entry.getValue(), Int2ObjectArrayMap.this.values[index]); - } - else { - Map.Entry entry = (Map.Entry)o; - int index = Int2ObjectArrayMap.this.findIndex(entry.getKey()); - if(index >= 0) return Objects.equals(entry.getValue(), Int2ObjectArrayMap.this.values[index]); - } - } - return false; - } - - @Override - @Deprecated - public boolean remove(Object o) { - if(o instanceof Map.Entry) { - if(o instanceof Int2ObjectMap.Entry) { - Int2ObjectMap.Entry entry = (Int2ObjectMap.Entry)o; - return Int2ObjectArrayMap.this.remove(entry.getIntKey(), entry.getValue()); - } - Map.Entry entry = (Map.Entry)o; - return Int2ObjectArrayMap.this.remove(entry.getKey(), entry.getValue()); - } - return false; - } - - @Override - public int size() { - return Int2ObjectArrayMap.this.size(); - } - - @Override - public void clear() { - Int2ObjectArrayMap.this.clear(); - } - } - - private class KeySet extends AbstractIntSet implements IntOrderedSet { - @Override - public boolean contains(int e) { return containsKey(e); } - - @Override - public boolean remove(int o) { - int oldSize = size; - Int2ObjectArrayMap.this.remove(o); - return size != oldSize; - } - - @Override - public boolean add(int o) { throw new UnsupportedOperationException(); } - @Override - public boolean addAndMoveToFirst(int o) { throw new UnsupportedOperationException(); } - @Override - public boolean addAndMoveToLast(int o) { throw new UnsupportedOperationException(); } - @Override - public boolean moveToFirst(int o) { return Int2ObjectArrayMap.this.moveToFirst(o); } - @Override - public boolean moveToLast(int o) { return Int2ObjectArrayMap.this.moveToLast(o); } - @Override - public IntListIterator iterator() { return new KeyIterator(); } - @Override - public IntBidirectionalIterator iterator(int fromElement) { return new KeyIterator(fromElement); } - @Override - public int size() { return Int2ObjectArrayMap.this.size(); } - @Override - public void clear() { Int2ObjectArrayMap.this.clear(); } - @Override - public int firstInt() { return firstIntKey(); } - @Override - public int pollFirstInt() { return pollFirstIntKey(); } - @Override - public int lastInt() { return lastIntKey(); } - @Override - public int pollLastInt() { return pollLastIntKey(); } - - @Override - public KeySet copy() { throw new UnsupportedOperationException(); } - - @Override - public void forEach(IntConsumer action) { - Objects.requireNonNull(action); - for(int i = 0;i void forEach(E input, ObjectIntConsumer action) { - Objects.requireNonNull(action); - for(int i = 0;i { - @Override - public boolean contains(Object e) { - return containsValue(e); - } - - @Override - public boolean add(V o) { - throw new UnsupportedOperationException(); - } - - @Override - public ObjectIterator iterator() { - return new ValueIterator(); - } - - @Override - public int size() { - return Int2ObjectArrayMap.this.size(); - } - - @Override - public void clear() { - Int2ObjectArrayMap.this.clear(); - } - - @Override - public void forEach(Consumer action) { - Objects.requireNonNull(action); - for(int i = 0;i action) { - Objects.requireNonNull(action); - for(int i = 0;i filter) { - Objects.requireNonNull(filter); - for(int i = 0;i filter) { - Objects.requireNonNull(filter); - for(int i = 0;i filter) { - Objects.requireNonNull(filter); - for(int i = 0;i E reduce(E identity, BiFunction operator) { - Objects.requireNonNull(operator); - E state = identity; - for(int i = 0;i operator) { - Objects.requireNonNull(operator); - V state = null; - boolean empty = true; - for(int i = 0;i filter) { - Objects.requireNonNull(filter); - for(int i = 0;i filter) { - Objects.requireNonNull(filter); - int result = 0; - for(int i = 0;i> { - MapEntry entry = new MapEntry(); - - public FastEntryIterator() {} - public FastEntryIterator(int from) { - index = findIndex(from); - } - - @Override - public Int2ObjectMap.Entry next() { - entry.index = nextEntry(); - return entry; - } - - @Override - public Int2ObjectMap.Entry previous() { - entry.index = previousEntry(); - return entry; - } - - @Override - public void set(Int2ObjectMap.Entry e) { throw new UnsupportedOperationException(); } - @Override - public void add(Int2ObjectMap.Entry e) { throw new UnsupportedOperationException(); } - } - - private class EntryIterator extends MapIterator implements ObjectListIterator> { - MapEntry entry = null; - - public EntryIterator() {} - public EntryIterator(int from) { - index = findIndex(from); - if(index == -1) throw new NoSuchElementException(); - } - - @Override - public Int2ObjectMap.Entry next() { - return entry = new MapEntry(nextEntry()); - } - - @Override - public Int2ObjectMap.Entry previous() { - return entry = new MapEntry(previousEntry()); - } - - @Override - public void remove() { - super.remove(); - if(entry != null && entry.index != -1) { - entry.index = -1; - } - } - - @Override - public void set(Int2ObjectMap.Entry e) { throw new UnsupportedOperationException(); } - @Override - public void add(Int2ObjectMap.Entry e) { throw new UnsupportedOperationException(); } - } - - private class KeyIterator extends MapIterator implements IntListIterator { - public KeyIterator() {} - public KeyIterator(int element) { - index = findIndex(element); - if(index == -1) throw new NoSuchElementException(); - } - - @Override - public int previousInt() { - return keys[previousEntry()]; - } - - @Override - public int nextInt() { - return keys[nextEntry()]; - } - - @Override - public void set(int e) { throw new UnsupportedOperationException(); } - - @Override - public void add(int e) { throw new UnsupportedOperationException(); } - } - - private class ValueIterator extends MapIterator implements ObjectListIterator { - @Override - public V previous() { - return values[previousEntry()]; - } - - @Override - public V next() { - return values[nextEntry()]; - } - - @Override - public void set(V e) { throw new UnsupportedOperationException(); } - - @Override - public void add(V e) { throw new UnsupportedOperationException(); } - } - - private class MapIterator { - int index; - int lastReturned = -1; - - public boolean hasNext() { - return index < size; - } - - public boolean hasPrevious() { - return index > 0; - } - - public int nextIndex() { - return index; - } - - public int previousIndex() { - return index-1; - } - - public void remove() { - if(lastReturned == -1) throw new IllegalStateException(); - removeIndex(lastReturned); - if(lastReturned < index) - index--; - lastReturned = -1; - } - - public int previousEntry() { - if(!hasPrevious()) throw new NoSuchElementException(); - index--; - return (lastReturned = index); - } - - public int nextEntry() { - if(!hasNext()) throw new NoSuchElementException(); - lastReturned = index; - return index++; - } - - public int skip(int amount) { - if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); - int steps = Math.min(amount, size() - index); - index += steps; - if(steps > 0) lastReturned = Math.min(index-1, size()-1); - return steps; - } - - public int back(int amount) { - if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); - int steps = Math.min(amount, index); - index -= steps; - if(steps > 0) lastReturned = Math.min(index, size()-1); - return steps; - } - } - - private class MapEntry implements Int2ObjectMap.Entry, Map.Entry { - int index = -1; - - public MapEntry() {} - public MapEntry(int index) { - this.index = index; - } - - @Override - public int getIntKey() { - return keys[index]; - } - - @Override - public V getValue() { - return values[index]; - } - - @Override - public V setValue(V value) { - V oldValue = values[index]; - values[index] = value; - return oldValue; - } - - @Override - public boolean equals(Object obj) { - if(obj instanceof Map.Entry) { - if(obj instanceof Int2ObjectMap.Entry) { - Int2ObjectMap.Entry entry = (Int2ObjectMap.Entry)obj; - return keys[index] == entry.getIntKey() && Objects.equals(values[index], entry.getValue()); - } - Map.Entry entry = (Map.Entry)obj; - Object key = entry.getKey(); - Object value = entry.getValue(); - return key instanceof Integer && keys[index] == ((Integer)key).intValue() && Objects.equals(values[index], value); - } - return false; - } - - @Override - public int hashCode() { - return Integer.hashCode(keys[index]) ^ Objects.hashCode(values[index]); - } - - @Override - public String toString() { - return Integer.toString(keys[index]) + "=" + Objects.toString(values[index]); - } - } -} diff --git a/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectMap.java b/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectMap.java deleted file mode 100644 index be6d23167..000000000 --- a/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectMap.java +++ /dev/null @@ -1,679 +0,0 @@ -package speiger.src.collections.ints.maps.interfaces; - -import java.util.Map; -import java.util.Objects; -import java.util.Collection; -import java.util.Arrays; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Function; - - -import speiger.src.collections.objects.collections.ObjectCollection; -import speiger.src.collections.ints.functions.consumer.IntObjectConsumer; -import speiger.src.collections.ints.functions.function.IntFunction; -import speiger.src.collections.ints.functions.function.IntObjectUnaryOperator; - -import speiger.src.collections.ints.maps.impl.misc.Int2ObjectArrayMap; -import speiger.src.collections.objects.collections.ObjectIterable; -import speiger.src.collections.ints.sets.IntSet; -import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator; -import speiger.src.collections.objects.functions.ObjectSupplier; -import speiger.src.collections.objects.collections.ObjectIterator; -import speiger.src.collections.objects.sets.ObjectSet; -import speiger.src.collections.utils.HashUtil; -import speiger.src.collections.utils.SanityChecks; - -/** - * A Type Specific Map that reduces memory overhead due to boxing/unboxing of Primitives - * and some extra helper functions. - * @param the keyType of elements maintained by this Collection - */ -public interface Int2ObjectMap extends Map, IntFunction -{ - /** - * Helper Class that allows to create Maps without requiring a to type out the entire implementation or know it. - * @return a MapBuilder - */ - public static MapBuilder builder() { - return MapBuilder.INSTANCE; - } - - /** - * Method to see what the default return value is. - * @return default return value - */ - public V getDefaultReturnValue(); - /** - * Method to define the default return value if a requested key isn't present - * @param v value that should be the default return value - * @return itself - */ - public Int2ObjectMap setDefaultReturnValue(V v); - - /** - * A Function that does a shallow clone of the Map itself. - * This function is more optimized then a copy constructor since the Map does not have to be unsorted/resorted. - * It can be compared to Cloneable but with less exception risk - * @return a Shallow Copy of the Map - * @note Wrappers and view Maps will not support this feature - */ - public Int2ObjectMap copy(); - - /** - * Type Specific method to reduce boxing/unboxing of values - * @param key the key that should be inserted, - * @param value the value that should be inserted - * @return the last present value or default return value. - * @see Map#put(Object, Object) - */ - public V put(int key, V value); - - /** - * A Helper method that allows to put int a Int2ObjectMap.Entry into a map. - * @param entry then Entry that should be inserted. - * @return the last present value or default return value. - */ - public default V put(Entry entry) { - return put(entry.getIntKey(), entry.getValue()); - } - - /** - * A Helper method that allows to put int a Map.Entry into a map. - * @param entry then Entry that should be inserted. - * @return the last present value or default return value. - */ - public default V put(Map.Entry entry) { - return put(entry.getKey(), entry.getValue()); - } - - /** - * Type Specific array method to bulk add elements into a map without creating a wrapper and increasing performances - * @param keys the keys that should be added - * @param values the values that should be added - * @see Map#putAll(Map) - * @throws IllegalStateException if the arrays are not the same size - */ - public default void putAll(int[] keys, V[] values) { - if(keys.length != values.length) throw new IllegalStateException("Array sizes do not match"); - putAll(keys, values, 0, keys.length); - } - - /** - * Type Specific array method to bulk add elements into a map without creating a wrapper and increasing performances - * @param keys the keys that should be added - * @param values the values that should be added - * @param offset where the to start in the array - * @param size how many elements should be added - * @see Map#putAll(Map) - * @throws IllegalStateException if the arrays are not within the range - */ - public void putAll(int[] keys, V[] values, int offset, int size); - - /** - * Type Specific Object array method to bulk add elements into a map without creating a wrapper and increasing performances - * @param keys the keys that should be added - * @param values the values that should be added - * @see Map#putAll(Map) - * @throws IllegalStateException if the arrays are not the same size - */ - public default void putAll(Integer[] keys, V[] values) { - if(keys.length != values.length) throw new IllegalStateException("Array sizes do not match"); - putAll(keys, values, 0, keys.length); - } - - /** - * Type Specific Object array method to bulk add elements into a map without creating a wrapper and increasing performances - * @param keys the keys that should be added - * @param values the values that should be added - * @param offset where the to start in the array - * @param size how many elements should be added - * @see Map#putAll(Map) - * @throws IllegalStateException if the arrays are not within the range - */ - public void putAll(Integer[] keys, V[] values, int offset, int size); - - /** - * Type Specific method to reduce boxing/unboxing of values - * @param key the key that should be inserted, - * @param value the value that should be inserted - * @return the last present value or default return value. - * @see Map#putIfAbsent(Object, Object) - */ - public V putIfAbsent(int key, V value); - - /** - * Type-Specific bulk put method put elements into the map if not present. - * @param m elements that should be added if not present. - */ - public void putAllIfAbsent(Int2ObjectMap m); - - /** - * Type Specific function for the bull putting of values - * @param m the elements that should be inserted - */ - public void putAll(Int2ObjectMap m); - - /** - * Type Specific method to reduce boxing/unboxing of values - * @param key element that is searched for - * @return if the key is present - */ - public boolean containsKey(int key); - - /** - * @see Map#containsKey(Object) - * @param key that is searched for. - * @return true if found - * @note in some implementations key does not have to be Integer but just have to support equals with Integer. - */ - @Override - public default boolean containsKey(Object key) { - return key instanceof Integer && containsKey(((Integer)key).intValue()); - } - - /** - * Type Specific remove function to reduce boxing/unboxing - * @param key the element that should be removed - * @return the value that was removed or default return value - */ - public V remove(int key); - - /** - * @see Map#remove(Object) - * @param key the element that should be removed - * @return the value that was removed or default return value - * @note in some implementations key does not have to be Integer but just have to support equals with Integer. - */ - @Override - public default V remove(Object key) { - return key instanceof Integer ? remove(((Integer)key).intValue()) : getDefaultReturnValue(); - } - - /** - * Type Specific remove function to reduce boxing/unboxing - * @param key the element that should be removed - * @param value the expected value that should be found - * @return true if the key and value was found and removed - * @see Map#remove(Object, Object) - */ - public boolean remove(int key, V value); - - /** - * @see Map#remove(Object, Object) - * @param key the element that should be removed - * @param value the expected value that should be found - * @return true if the key and value was found and removed - */ - @Override - public default boolean remove(Object key, Object value) { - return key instanceof Integer && remove(((Integer)key).intValue(), (V)value); - } - - /** - * Type-Specific Remove function with a default return value if wanted. - * @see Map#remove(Object, Object) - * @param key the element that should be removed - * @param defaultValue the value that should be returned if the entry doesn't exist - * @return the value that was removed or default value - */ - public V removeOrDefault(int key, V defaultValue); - /** - * A Type Specific replace method to replace an existing value - * @param key the element that should be searched for - * @param oldValue the expected value to be replaced - * @param newValue the value to replace the oldValue with. - * @return true if the value got replaced - * @note this fails if the value is not present even if it matches the oldValue - */ - public boolean replace(int key, V oldValue, V newValue); - /** - * A Type Specific replace method to reduce boxing/unboxing replace an existing value - * @param key the element that should be searched for - * @param value the value to replace with. - * @return the present value or default return value - * @note this fails if the value is not present - */ - public V replace(int key, V value); - - /** - * Type-Specific bulk replace method. Could be seen as putAllIfPresent - * @param m elements that should be replaced. - */ - public void replaceObjects(Int2ObjectMap m); - /** - * A Type Specific mass replace method to reduce boxing/unboxing - * @param mappingFunction operation to replace all values - */ - public void replaceObjects(IntObjectUnaryOperator mappingFunction); - /** - * A Type Specific compute method to reduce boxing/unboxing - * @param key the key that should be computed - * @param mappingFunction the operator that should generate the value - * @return the result of the computation - */ - public V compute(int key, IntObjectUnaryOperator mappingFunction); - /** - * A Type Specific compute method to reduce boxing/unboxing - * @param key the key that should be computed - * @param mappingFunction the operator that should generate the value if not present - * @return the result of the computed value or present value - */ - public V computeIfAbsent(int key, IntFunction mappingFunction); - - /** - * A Supplier based computeIfAbsent function to fill the most used usecase of this function - * @param key the key that should be computed - * @param valueProvider the value if not present - * @return the result of the computed value or present value - */ - public V supplyIfAbsent(int key, ObjectSupplier valueProvider); - /** - * A Type Specific compute method to reduce boxing/unboxing - * @param key the key that should be computed - * @param mappingFunction the operator that should generate the value if present - * @return the result of the default return value or present value - * @note if not present then compute is not executed - */ - public V computeIfPresent(int key, IntObjectUnaryOperator mappingFunction); - /** - * A Type Specific merge method to reduce boxing/unboxing - * @param key the key that should be be searched for - * @param value the value that should be merged with - * @param mappingFunction the operator that should generate the new Value - * @return the result of the merge - * @note if the result matches the default return value then the key is removed from the map - */ - public V merge(int key, V value, ObjectObjectUnaryOperator mappingFunction); - /** - * A Bulk method for merging Maps. - * @param m the entries that should be bulk added - * @param mappingFunction the operator that should generate the new Value - * @note if the result matches the default return value then the key is removed from the map - */ - public void mergeAll(Int2ObjectMap m, ObjectObjectUnaryOperator mappingFunction); - - @Override - @Deprecated - public default boolean replace(Integer key, V oldValue, V newValue) { - return replace(key.intValue(), oldValue, newValue); - } - - @Override - @Deprecated - public default V replace(Integer key, V value) { - return replace(key.intValue(), value); - } - - @Override - public default V apply(int key) { - return get(key); - } - /** - * A Type Specific get method to reduce boxing/unboxing - * @param key the key that is searched for - * @return the searched value or default return value - */ - public V get(int key); - - /** - * A Type Specific getOrDefault method to reduce boxing/unboxing - * @param key the key that is searched for - * @param defaultValue the value that should be returned if the key is not present - * @return the searched value or defaultValue value - */ - public V getOrDefault(int key, V defaultValue); - - @Override - @Deprecated - public default V get(Object key) { - return key instanceof Integer ? get(((Integer)key).intValue()) : getDefaultReturnValue(); - } - - @Override - @Deprecated - public default V getOrDefault(Object key, V defaultValue) { - V value = key instanceof Integer ? get(((Integer)key).intValue()) : getDefaultReturnValue(); - return !Objects.equals(value, getDefaultReturnValue()) || containsKey(key) ? value : defaultValue; - } - - @Override - @Deprecated - public default void replaceAll(BiFunction mappingFunction) { - Objects.requireNonNull(mappingFunction); - replaceObjects(mappingFunction instanceof IntObjectUnaryOperator ? (IntObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(Integer.valueOf(K), V)); - } - - @Override - @Deprecated - public default V compute(Integer key, BiFunction mappingFunction) { - Objects.requireNonNull(mappingFunction); - return compute(key.intValue(), mappingFunction instanceof IntObjectUnaryOperator ? (IntObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(Integer.valueOf(K), V)); - } - - @Override - @Deprecated - public default V computeIfAbsent(Integer key, Function mappingFunction) { - Objects.requireNonNull(mappingFunction); - return computeIfAbsent(key.intValue(), mappingFunction instanceof IntFunction ? (IntFunction)mappingFunction : K -> mappingFunction.apply(Integer.valueOf(K))); - } - - @Override - @Deprecated - public default V computeIfPresent(Integer key, BiFunction mappingFunction) { - Objects.requireNonNull(mappingFunction); - return computeIfPresent(key.intValue(), mappingFunction instanceof IntObjectUnaryOperator ? (IntObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(Integer.valueOf(K), V)); - } - - @Override - @Deprecated - public default V merge(Integer key, V value, BiFunction mappingFunction) { - Objects.requireNonNull(mappingFunction); - Objects.requireNonNull(value); - return merge(key.intValue(), value, mappingFunction instanceof ObjectObjectUnaryOperator ? (ObjectObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(K, V)); - } - - /** - * Type Specific forEach method to reduce boxing/unboxing - * @param action processor of the values that are iterator over - */ - public void forEach(IntObjectConsumer action); - - @Override - @Deprecated - public default void forEach(BiConsumer action) { - Objects.requireNonNull(action); - forEach(action instanceof IntObjectConsumer ? (IntObjectConsumer)action : (K, V) -> action.accept(Integer.valueOf(K), V)); - } - - @Override - public IntSet keySet(); - @Override - public ObjectCollection values(); - @Override - @Deprecated - public ObjectSet> entrySet(); - /** - * Type Sensitive EntrySet to reduce boxing/unboxing and optionally Temp Object Allocation. - * @return a EntrySet of the collection - */ - public ObjectSet> int2ObjectEntrySet(); - - @Override - @Deprecated - public default V put(Integer key, V value) { - return put(key.intValue(), value); - } - - @Override - @Deprecated - public default V putIfAbsent(Integer key, V value) { - return put(key.intValue(), value); - } - /** - * Fast Entry set that allows for a faster Entry Iterator by recycling the Entry Object and just exchanging 1 internal value - * @param the keyType of elements maintained by this Collection - */ - public interface FastEntrySet extends ObjectSet> - { - /** - * Fast iterator that recycles the given Entry object to improve speed and reduce object allocation - * @return a Recycling ObjectIterator of the given set - */ - public ObjectIterator> fastIterator(); - /** - * Fast for each that recycles the given Entry object to improve speed and reduce object allocation - * @param action the action that should be applied to each given entry - */ - public default void fastForEach(Consumer> action) { - forEach(action); - } - } - - /** - * Type Specific Map Entry that reduces boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ - public interface Entry extends Map.Entry - { - /** - * Type Specific getKey method that reduces boxing/unboxing - * @return the key of a given Entry - */ - public int getIntKey(); - public default Integer getKey() { return Integer.valueOf(getIntKey()); } - - } - - /** - * Helper class that reduces the method spam of the Map Class. - */ - public static final class MapBuilder - { - static final MapBuilder INSTANCE = new MapBuilder(); - - /** - * Starts a Map Builder that allows you to create maps as Constants a lot easier - * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen - * @param the keyType of elements maintained by this Collection - * @return a MapBuilder - */ - public BuilderCache start() { - return new BuilderCache(); - } - - /** - * Starts a Map Builder that allows you to create maps as Constants a lot easier - * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen - * @param size the expected minimum size of Elements in the Map, default is 16 - * @param the keyType of elements maintained by this Collection - * @return a MapBuilder - */ - public BuilderCache start(int size) { - return new BuilderCache(size); - } - - /** - * Starts a Map builder and puts in the Key and Value into it - * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen - * @param key the key that should be added - * @param value the value that should be added - * @param the keyType of elements maintained by this Collection - * @return a MapBuilder with the key and value stored in it. - */ - public BuilderCache put(int key, V value) { - return new BuilderCache().put(key, value); - } - - /** - * Starts a Map builder and puts in the Key and Value into it - * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen - * @param key the key that should be added - * @param value the value that should be added - * @param the keyType of elements maintained by this Collection - * @return a MapBuilder with the key and value stored in it. - */ - public BuilderCache put(Integer key, V value) { - return new BuilderCache().put(key, value); - } - - /** - * Helper function to unify code - * @param the keyType of elements maintained by this Collection - * @return a OpenHashMap - */ - public Int2ObjectArrayMap arrayMap() { - return new Int2ObjectArrayMap<>(); - } - - /** - * Helper function to unify code - * @param size the minimum capacity of the Map - * @param the keyType of elements maintained by this Collection - * @return a OpenHashMap with a mimimum capacity - */ - public Int2ObjectArrayMap arrayMap(int size) { - return new Int2ObjectArrayMap<>(size); - } - - /** - * Helper function to unify code - * @param keys the keys that should be inserted - * @param values the values that should be inserted - * @param the keyType of elements maintained by this Collection - * @throws IllegalStateException if the keys and values do not match in length - * @return a OpenHashMap thats contains the injected values - */ - public Int2ObjectArrayMap arrayMap(int[] keys, V[] values) { - return new Int2ObjectArrayMap<>(keys, values); - } - - /** - * Helper function to unify code - * @param keys the keys that should be inserted - * @param values the values that should be inserted - * @param the keyType of elements maintained by this Collection - * @throws IllegalStateException if the keys and values do not match in length - * @return a OpenHashMap thats contains the injected values - * @note the keys and values will be unboxed - */ - public Int2ObjectArrayMap arrayMap(Integer[] keys, V[] values) { - return new Int2ObjectArrayMap<>(keys, values); - } - - /** - * Helper function to unify code - * @param map that should be cloned - * @param the keyType of elements maintained by this Collection - * @return a OpenHashMap thats copies the contents of the provided map - */ - public Int2ObjectArrayMap arrayMap(Int2ObjectMap map) { - return new Int2ObjectArrayMap<>(map); - } - - /** - * Helper function to unify code - * @param map that should be cloned - * @param the keyType of elements maintained by this Collection - * @return a OpenHashMap thats copies the contents of the provided map - * @note the map will be unboxed - */ - public Int2ObjectArrayMap arrayMap(Map map) { - return new Int2ObjectArrayMap<>(map); - } - - } - - /** - * Builder Cache for allowing to buildMaps - * @param the keyType of elements maintained by this Collection - */ - public static class BuilderCache - { - int[] keys; - V[] values; - int size; - - /** - * Default Constructor - */ - public BuilderCache() { - this(HashUtil.DEFAULT_MIN_CAPACITY); - } - - /** - * Constructor providing a Minimum Capcity - * @param initialSize the requested start capacity - */ - public BuilderCache(int initialSize) { - if(initialSize < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); - keys = new int[initialSize]; - values = (V[])new Object[initialSize]; - } - - private void ensureSize(int newSize) { - if(keys.length >= newSize) return; - newSize = (int)Math.max(Math.min((long)keys.length + (keys.length >> 1), SanityChecks.MAX_ARRAY_SIZE), newSize); - keys = Arrays.copyOf(keys, newSize); - values = Arrays.copyOf(values, newSize); - } - - /** - * Helper function to add a Entry into the Map - * @param key the key that should be added - * @param value the value that should be added - * @return self - */ - public BuilderCache put(int key, V value) { - ensureSize(size+1); - keys[size] = key; - values[size] = value; - size++; - return this; - } - - /** - * Helper function to add a Entry into the Map - * @param key the key that should be added - * @param value the value that should be added - * @return self - */ - public BuilderCache put(Integer key, V value) { - return put(key.intValue(), value); - } - - /** - * Helper function to add a Entry into the Map - * @param entry the Entry that should be added - * @return self - */ - public BuilderCache put(Entry entry) { - return put(entry.getIntKey(), entry.getValue()); - } - - /** - * Helper function to add a Map to the Map - * @param map that should be added - * @return self - */ - public BuilderCache putAll(Int2ObjectMap map) { - return putAll(map.int2ObjectEntrySet()); - } - - /** - * Helper function to add a Map to the Map - * @param map that should be added - * @return self - */ - public BuilderCache putAll(Map map) { - for(Map.Entry entry : map.entrySet()) - put(entry.getKey(), entry.getValue()); - return this; - } - - /** - * Helper function to add a Collection of Entries to the Map - * @param c that should be added - * @return self - */ - public BuilderCache putAll(ObjectIterable> c) { - if(c instanceof Collection) - ensureSize(size+((Collection>)c).size()); - - for(Entry entry : c) - put(entry); - - return this; - } - - /** - * Builds the Keys and Values into a Array Map - * @return a Int2ObjectArrayMap - */ - public Int2ObjectArrayMap arrayMap() { - return new Int2ObjectArrayMap<>(keys, values, size); - } - - } -} diff --git a/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectOrderedMap.java b/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectOrderedMap.java deleted file mode 100644 index 58fcd9ca8..000000000 --- a/src/main/java/speiger/src/collections/ints/maps/interfaces/Int2ObjectOrderedMap.java +++ /dev/null @@ -1,115 +0,0 @@ -package speiger.src.collections.ints.maps.interfaces; - -import speiger.src.collections.ints.sets.IntOrderedSet; -import speiger.src.collections.objects.collections.ObjectBidirectionalIterator; -import speiger.src.collections.objects.sets.ObjectOrderedSet; -/** - * A Special Map Interface giving Access to some really usefull functions - * The Idea behind this interface is to allow access to functions that give control to the Order of elements. - * Since Linked implementations as examples can be reordered outside of the Insertion Order. - * This interface provides basic access to such functions while also providing some Sorted/NaivgableMap implementations that still fit into here. - * - * @param the keyType of elements maintained by this Collection - */ -public interface Int2ObjectOrderedMap extends Int2ObjectMap -{ - /** - * A customized put method that allows you to insert into the first index. - * @param key the key that should be inserted - * @param value the value that should be inserted - * @return the previous present or default return value - * @see java.util.Map#put(Object, Object) - */ - public V putAndMoveToFirst(int key, V value); - - /** - * A customized put method that allows you to insert into the last index. (This may be nessesary depending on the implementation) - * @param key the key that should be inserted - * @param value the value that should be inserted - * @return the previous present or default return value - * @see java.util.Map#put(Object, Object) - */ - public V putAndMoveToLast(int key, V value); - - /** - * A specific move method to move a given key/value to the first index. - * @param key that should be moved to the first index - * @return true if the value was moved. - * @note returns false if the value was not present in the first place - */ - public boolean moveToFirst(int key); - /** - * A specific move method to move a given key/value to the last index. - * @param key that should be moved to the first last - * @return true if the value was moved. - * @note returns false if the value was not present in the first place - */ - public boolean moveToLast(int key); - - /** - * A Specific get method that allows to move teh given key/value int the first index. - * @param key that is searched for - * @return the given value for the requested key or default return value - */ - public V getAndMoveToFirst(int key); - /** - * A Specific get method that allows to move teh given key/value int the last index. - * @param key that is searched for - * @return the given value for the requested key or default return value - */ - public V getAndMoveToLast(int key); - - /** - * A method to get the first Key of a Map. - * @return the first key in the map - */ - public int firstIntKey(); - /** - * A method to get and remove the first Key of a Map. - * @return the first key in the map - */ - public int pollFirstIntKey(); - /** - * A method to get the last Key of a Map. - * @return the last key in the map - */ - public int lastIntKey(); - /** - * A method to get and remove the last Key of a Map. - * @return the last key in the map - */ - public int pollLastIntKey(); - - /** - * A method to get the first Value of a Map. - * @return the first key in the map - */ - public V firstValue(); - /** - * A method to get the last Value of a Map. - * @return the last key in the map - */ - public V lastValue(); - - @Override - public Int2ObjectOrderedMap copy(); - @Override - public IntOrderedSet keySet(); - @Override - public ObjectOrderedSet> int2ObjectEntrySet(); - - /** - * Fast Ordered Entry Set that allows for a faster Entry Iterator by recycling the Entry Object and just exchanging 1 internal value - * @param the keyType of elements maintained by this Collection - */ - interface FastOrderedSet extends FastEntrySet, ObjectOrderedSet> { - @Override - public ObjectBidirectionalIterator> fastIterator(); - /** - * Fast iterator that recycles the given Entry object to improve speed and reduce object allocation - * @param fromElement that is going to be started from. - * @return a improved iterator that starts from the desired element - */ - public ObjectBidirectionalIterator> fastIterator(int fromElement); - } -} diff --git a/src/main/java/speiger/src/collections/ints/sets/AbstractIntSet.java b/src/main/java/speiger/src/collections/ints/sets/AbstractIntSet.java deleted file mode 100644 index 5f0433a54..000000000 --- a/src/main/java/speiger/src/collections/ints/sets/AbstractIntSet.java +++ /dev/null @@ -1,41 +0,0 @@ -package speiger.src.collections.ints.sets; - -import java.util.Set; - -import speiger.src.collections.ints.collections.AbstractIntCollection; -import speiger.src.collections.ints.collections.IntIterator; - -/** - * Abstract Type Specific Set that reduces boxing/unboxing - */ -public abstract class AbstractIntSet extends AbstractIntCollection implements IntSet -{ - @Override - public abstract IntIterator iterator(); - @Override - public AbstractIntSet copy() { throw new UnsupportedOperationException(); } - - @Override - public int hashCode() { - int hashCode = 0; - IntIterator i = iterator(); - while(i.hasNext()) - hashCode += Integer.hashCode(i.nextInt()); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (o == this) - return true; - if (!(o instanceof Set)) - return false; - Set l = (Set)o; - if(l.size() != size()) return false; - try { - return containsAll(l); - } catch (ClassCastException | NullPointerException unused) { - return false; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/sets/IntOrderedSet.java b/src/main/java/speiger/src/collections/ints/sets/IntOrderedSet.java deleted file mode 100644 index 2a11d0e96..000000000 --- a/src/main/java/speiger/src/collections/ints/sets/IntOrderedSet.java +++ /dev/null @@ -1,88 +0,0 @@ -package speiger.src.collections.ints.sets; - -import speiger.src.collections.ints.collections.IntBidirectionalIterator; -import speiger.src.collections.ints.collections.IntSplititerator; -import speiger.src.collections.ints.utils.IntSplititerators; - -/** - * A Special Set Interface giving Access to some really usefull functions - * The Idea behind this interface is to allow access to functions that give control to the Order of elements. - * Since Linked implementations as examples can be reordered outside of the Insertion Order. - * This interface provides basic access to such functions while also providing some Sorted/NaivgableSet implementations that still fit into here. - * - */ -public interface IntOrderedSet extends IntSet -{ - /** - * A customized add method that allows you to insert into the first index. - * @param o the element that should be inserted - * @return true if it was added - * @see java.util.Set#add(Object) - */ - public boolean addAndMoveToFirst(int o); - /** - * A customized add method that allows you to insert into the last index. - * @param o the element that should be inserted - * @return true if it was added - * @see java.util.Set#add(Object) - */ - public boolean addAndMoveToLast(int o); - - /** - * A specific move method to move a given key to the first index. - * @param o that should be moved to the first index - * @return true if the value was moved. - * @note returns false if the value was not present in the first place - */ - public boolean moveToFirst(int o); - /** - * A specific move method to move a given key to the last index. - * @param o that should be moved to the first last - * @return true if the value was moved. - * @note returns false if the value was not present in the first place - */ - public boolean moveToLast(int o); - - @Override - public IntOrderedSet copy(); - - @Override - public IntBidirectionalIterator iterator(); - - /** - * A type Specific Iterator starting from a given key - * @param fromElement the element the iterator should start from - * @return a iterator starting from the given element - * @throws java.util.NoSuchElementException if fromElement isn't found - */ - public IntBidirectionalIterator iterator(int fromElement); - - /** - * A Type Specific Type Splititerator to reduce boxing/unboxing - * @return type specific splititerator - */ - @Override - default IntSplititerator spliterator() { return IntSplititerators.createSplititerator(this, 0); } - - /** - * A method to get the first element in the set - * @return first element in the set - */ - public int firstInt(); - /** - * A method to get and remove the first element in the set - * @return first element in the set - */ - public int pollFirstInt(); - /** - * A method to get the last element in the set - * @return last element in the set - */ - public int lastInt(); - /** - * A method to get and remove the last element in the set - * @return last element in the set - */ - public int pollLastInt(); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/sets/IntSet.java b/src/main/java/speiger/src/collections/ints/sets/IntSet.java deleted file mode 100644 index 721ae0e4b..000000000 --- a/src/main/java/speiger/src/collections/ints/sets/IntSet.java +++ /dev/null @@ -1,58 +0,0 @@ -package speiger.src.collections.ints.sets; - -import java.util.Set; - -import speiger.src.collections.ints.collections.IntCollection; -import speiger.src.collections.ints.collections.IntIterator; -import speiger.src.collections.ints.collections.IntSplititerator; -import speiger.src.collections.ints.utils.IntSplititerators; - - -/** - * A Type Specific Set class to reduce boxing/unboxing - */ -public interface IntSet extends Set, IntCollection -{ - @Override - public IntIterator iterator(); - - @Override - public IntSet copy(); - - /** - * A Type Specific remove function to reduce boxing/unboxing - * @param o the element that should be removed - * @return true if the element was removed - */ - public boolean remove(int o); - - @Override - public default boolean remInt(int o) { - return remove(o); - } - - @Override - @Deprecated - public default boolean add(Integer e) { - return IntCollection.super.add(e); - } - - @Override - @Deprecated - public default boolean contains(Object o) { - return IntCollection.super.contains(o); - } - - @Override - @Deprecated - public default boolean remove(Object o) { - return IntCollection.super.remove(o); - } - - /** - * A Type Specific Type Splititerator to reduce boxing/unboxing - * @return type specific splititerator - */ - @Override - default IntSplititerator spliterator() { return IntSplititerators.createSplititerator(this, 0); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IIntArray.java b/src/main/java/speiger/src/collections/ints/utils/IIntArray.java deleted file mode 100644 index ab6a3793f..000000000 --- a/src/main/java/speiger/src/collections/ints/utils/IIntArray.java +++ /dev/null @@ -1,29 +0,0 @@ -package speiger.src.collections.ints.utils; - -import java.util.Objects; -import java.util.function.Consumer; - -import speiger.src.collections.utils.IArray; - -/** - * Type-Specific Helper class to get the underlying array of array implementations. - */ -public interface IIntArray extends IArray -{ - /** - * Provides the Underlying Array in the Implementation - * @return underlying Array - * @throws ClassCastException if the return type does not match the underlying array. (Only for Object Implementations) - */ - public int[] elements(); - - /** - * Provides the Underlying Array in the Implementation. This function exists purely because of Synchronization wrappers to help run Synchronized Code - * @param action the action that handles the array - * @throws NullPointerException if action is null - */ - public default void elements(Consumer action) { - Objects.requireNonNull(action); - action.accept(elements()); - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IntArrays.java b/src/main/java/speiger/src/collections/ints/utils/IntArrays.java deleted file mode 100644 index 5b331bfcb..000000000 --- a/src/main/java/speiger/src/collections/ints/utils/IntArrays.java +++ /dev/null @@ -1,1527 +0,0 @@ -package speiger.src.collections.ints.utils; - -import java.util.Arrays; -import java.util.Random; -import java.util.concurrent.RecursiveAction; - -import speiger.src.collections.ints.functions.IntComparator; -import speiger.src.collections.ints.collections.IntIterator; -import speiger.src.collections.ints.utils.IntIterators; -import speiger.src.collections.ints.utils.IntCollections; -import speiger.src.collections.utils.SanityChecks; - -/** - * A Helper class for Arrays - */ -public class IntArrays -{ - /** Default Limit for Insertion/Selection Sort */ - public static final int BASE_THRESHOLD = 16; - /** Default Threshold for Multithreaded Sorting Algorythm options*/ - public static final int PARALLEL_THRESHOLD = 8192; - - /** Empty Array Reference used for Uninitialized Collections */ - public static final int[] EMPTY_ARRAY = new int[0]; - - /** - * A Helper function to convert a Primitive Array to a Integer Array. - * @param a the array that should be converted - * @return a Integer Array of the input array. - */ - public static Integer[] wrap(int[] a) { - return wrap(a, 0, a.length); - } - - /** - * A Helper function to convert a Primitive Array to a Integer Array. - * @param a the array that should be converted - * @param length the maximum length that should be coverted - * @return a Integer Array of the input array. - */ - public static Integer[] wrap(int[] a, int length) { - return wrap(a, 0, length); - } - - /** - * A Helper function to convert a Primitive Array to a Integer Array. - * @param a the array that should be converted - * @param offset the starting offset of the inputarray - * @param length the maximum length that should be coverted - * @return a Integer Array of the input array. - */ - public static Integer[] wrap(int[] a, int offset, int length) { - SanityChecks.checkArrayCapacity(a.length, offset, length); - Integer[] result = new Integer[length]; - for(int i = offset;i>> 1; - int value = data[index]; - if(comp != null) { - while(index < half) { - int child = (index << 1) + 1; - int childValue = data[child]; - int right = child+1; - if(right < size && comp.compare(data[right], childValue) < 0) childValue = data[child = right]; - if(comp.compare(value, childValue) <= 0) break; - data[index] = childValue; - index = child; - } - } - else { - while(index < half) { - int child = (index << 1) + 1; - int childValue = data[child]; - int right = child+1; - if(right < size && Integer.compare(data[right], childValue) < 0) childValue = data[child = right]; - if(Integer.compare(value, childValue) <= 0) break; - data[index] = childValue; - index = child; - } - } - data[index] = value; - return index; - } - - /** - * Method to sort a specific value into the heap. - * @param data the heap itself. - * @param index that should be heapified. - * @param comp the comparator to sort the heap. Can be null - * @return the index the element was shifted to - */ - public static int shiftUp(int[] data, int index, IntComparator comp) { - int value = data[index]; - if(comp != null) { - while(index > 0) { - int parent = (index - 1) >>> 1; - int parentValue = data[parent]; - if(comp.compare(value, parentValue) >= 0) break; - data[index] = parentValue; - index = parent; - } - } - else { - while(index > 0) { - int parent = (index - 1) >>> 1; - int parentValue = data[parent]; - if(Integer.compare(value, parentValue) >= 0) break; - data[index] = parentValue; - index = parent; - } - } - data[index] = value; - return index; - } - - /** - * Helper function to create a Heap out of an array. - * @param data the array to heapify - * @param size the current size of elements within the array. - * @param comp the Comparator to sort the array. Can be null - * @return the input array - */ - public static int[] heapify(int[] data, int size, IntComparator comp) { - for(int i = (size >>> 1) - 1;i>=0;shiftDown(data, size, i--, comp)); - return data; - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @note This uses the SanityChecks#getRandom - * @return the provided sorted array - */ - public static int[] shuffle(int[] array) { - return shuffle(array, SanityChecks.getRandom()); - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @param length the length of the array - * @note This uses the SanityChecks#getRandom - * @return the provided sorted array - */ - public static int[] shuffle(int[] array, int length) { - return shuffle(array, 0, length, SanityChecks.getRandom()); - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @param offset the start array - * @param length the length of the array - * @note This uses the SanityChecks#getRandom - * @return the provided sorted array - */ - public static int[] shuffle(int[] array, int offset, int length) { - return shuffle(array, offset, length, SanityChecks.getRandom()); - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @param random the Random Number Generator that should be used for the shuffling - * @return the provided sorted array - */ - public static int[] shuffle(int[] array, Random random) { - for(int i = array.length-1; i>=0;i--) { - int p = random.nextInt(i + 1); - int t = array[i]; - array[i] = array[p]; - array[p] = t; - } - return array; - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @param length the length of the array - * @param random the Random Number Generator that should be used for the shuffling - * @return the provided sorted array - */ - public static int[] shuffle(int[] array, int length, Random random) { - return shuffle(array, 0, length, random); - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @param offset the start array - * @param length the length of the array - * @param random the Random Number Generator that should be used for the shuffling - * @return the provided sorted array - */ - public static int[] shuffle(int[] array, int offset, int length, Random random) { - for(int i = length-1; i>=0;i--) { - int p = offset + random.nextInt(i + 1); - int t = array[offset+i]; - array[offset+i] = array[p]; - array[p] = t; - } - return array; - } - - /** - * Simple Array Reversal method - * @param array the Array that should flip - * @return the provided array - */ - public static int[] reverse(int[] array) { - return reverse(array, 0, array.length); - } - - /** - * Simple Array Reversal method - * @param array the Array that should flip - * @param length the length of the array - * @return the provided array - */ - public static int[] reverse(int[] array, int length) { - return reverse(array, 0, length); - } - - /** - * Simple Array Reversal method - * @param array the Array that should flip - * @param length the length of the array - * @param offset the start of the array - * @return the provided array - */ - public static int[] reverse(int[] array, int offset, int length) { - for (int i = offset, mid = offset + length >> 1, j = offset + length - 1; i < mid; i++, j--) { - int temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array. - */ - public static int[] stableSort(int[] array, IntComparator comp) { - stableSort(array, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void stableSort(int[] array, int length, IntComparator comp) { - stableSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void stableSort(int[] array, int from, int to, IntComparator comp) { - mergeSort(array, null, from, to, comp); - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @return input array - */ - public static int[] stableSort(int[] array) { - stableSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void stableSort(int[] array, int length) { - stableSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void stableSort(int[] array, int from, int to) { - mergeSort(array, null, from, to); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array - */ - public static int[] unstableSort(int[] array, IntComparator comp) { - unstableSort(array, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void unstableSort(int[] array, int length, IntComparator comp) { - unstableSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void unstableSort(int[] array, int from, int to, IntComparator comp) { - quickSort(array, from, to, comp); - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @return input array - */ - public static int[] unstableSort(int[] array) { - unstableSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void unstableSort(int[] array, int length) { - unstableSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void unstableSort(int[] array, int from, int to) { - quickSort(array, from, to); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array - */ - public static int[] insertionSort(int[] array, IntComparator comp) { - insertionSort(array, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void insertionSort(int[] array, int length, IntComparator comp) { - insertionSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void insertionSort(int[] array, int from, int to, IntComparator comp) { - for (int i = from+1;i= from && comp.compare(current, array[j]) < 0) { - array[j+1] = array[j--]; - } - array[j+1] = current; - } - } - - /** - * Sorts an array according to the natural ascending order using InsertionSort, - * @param array the array that needs to be sorted - * @return input array - */ - public static int[] insertionSort(int[] array) { - insertionSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order using InsertionSort, - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void insertionSort(int[] array, int length) { - insertionSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using InsertionSort, - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void insertionSort(int[] array, int from, int to) { - for (int i = from+1;i= from && Integer.compare(current, array[j]) < 0) { - array[j+1] = array[j--]; - } - array[j+1] = current; - } - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array - */ - public static int[] selectionSort(int[] array, IntComparator comp) { - selectionSort(array, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void selectionSort(int[] array, int length, IntComparator comp) { - selectionSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void selectionSort(int[] array, int from, int to, IntComparator comp) { - for (int i = from; i < to; i++) { - int min = array[i]; - int minId = i; - for(int j = i+1; j < to; j++) { - if(comp.compare(array[j], min) < 0) { - min = array[j]; - minId = j; - } - } - int temp = array[i]; - array[i] = min; - array[minId] = temp; - } - } - - /** - * Sorts an array according to the natural ascending order using Selection Sort, - * @param array the array that needs to be sorted - * @return input array - */ - public static int[] selectionSort(int[] array) { - selectionSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order using Selection Sort, - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void selectionSort(int[] array, int length) { - selectionSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Selection Sort, - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void selectionSort(int[] array, int from, int to) { - for (int i = from; i < to; i++) { - int min = array[i]; - int minId = i; - for(int j = i+1; j < to; j++) { - if(Integer.compare(array[j], min) < 0) { - min = array[j]; - minId = j; - } - } - int temp = array[i]; - array[i] = min; - array[minId] = temp; - } - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array - */ - public static int[] mergeSort(int[] array, IntComparator comp) { - mergeSort(array, null, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void mergeSort(int[] array, int length, IntComparator comp) { - mergeSort(array, null, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param supp the auxillary array that is used to simplify the sorting - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void mergeSort(int[] array, int[] supp, int from, int to, IntComparator comp) { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to, comp); - return; - } - if(supp == null) supp = Arrays.copyOf(array, to); - int mid = (from + to) >>> 1; - mergeSort(supp, array, from, mid, comp); - mergeSort(supp, array, mid, to, comp); - if(comp.compare(supp[mid - 1], supp[mid]) <= 0) - { - System.arraycopy(supp, from, array, from, to - from); - return; - } - for(int p = from, q = mid;from < to;from++) { - if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; - else array[from] = supp[q++]; - } - } - - /** - * Sorts an array according to the natural ascending order using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @return input array - */ - public static int[] mergeSort(int[] array) { - mergeSort(array, null, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void mergeSort(int[] array, int length) { - mergeSort(array, null, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param supp the auxillary array that is used to simplify the sorting - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void mergeSort(int[] array, int[] supp, int from, int to) { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to); - return; - } - if(supp == null) supp = Arrays.copyOf(array, to); - int mid = (from + to) >>> 1; - mergeSort(supp, array, from, mid); - mergeSort(supp, array, mid, to); - if(Integer.compare(supp[mid - 1], supp[mid]) <= 0) - { - System.arraycopy(supp, from, array, from, to - from); - return; - } - for(int p = from, q = mid;from < to;from++) { - if(q >= to || p < mid && Integer.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; - else array[from] = supp[q++]; - } - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using a Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(int[] array, IntComparator comp) { - parallelMergeSort(array, null, 0, array.length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(int[] array, int length, IntComparator comp) { - parallelMergeSort(array, null, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param supp the auxillary array that is used to simplify the sorting - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(int[] array, int[] supp, int from, int to, IntComparator comp) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new MergeSortActionComp(array, supp, from, to, comp)); - return; - } - mergeSort(array, supp, from, to, comp); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(int[] array) { - parallelMergeSort(array, null, 0, array.length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(int[] array, int length) { - parallelMergeSort(array, null, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param supp the auxillary array that is used to simplify the sorting - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(int[] array, int[] supp, int from, int to) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new MergeSortAction(array, supp, from, to)); - return; - } - mergeSort(array, supp, from, to); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void memFreeMergeSort(int[] array, IntComparator comp) { - memFreeMergeSort(array, 0, array.length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void memFreeMergeSort(int[] array, int length, IntComparator comp) { - memFreeMergeSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void memFreeMergeSort(int[] array, int from, int to, IntComparator comp) { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to, comp); - return; - } - int mid = (from + to) >>> 1; - memFreeMergeSort(array, from, mid, comp); - memFreeMergeSort(array, mid, to, comp); - if(comp.compare(array[mid - 1], array[mid]) <= 0) - return; - for(int i = from, j = mid, compare;i < j && j < to;) { - if((compare = comp.compare(array[i], array[j])) < 0) - i++; - else if(compare == 0) swap(array, ++i, j); - else { - int k = j; - for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++); - if(j == k) { - swap(array, i++, j); - continue; - } - else if(j + 1 == k) { - int value = array[j]; - System.arraycopy(array, i, array, i+1, j - i); - array[i] = value; - i++; - j++; - continue; - } - int[] data = new int[k - j]; - System.arraycopy(array, j, data, 0, data.length); - System.arraycopy(array, i, array, i+data.length, j - i); - System.arraycopy(data, 0, array, i, data.length); - i+=data.length; - j+=data.length; - } - } - } - - /** - * Sorts an array according to the natural ascending order using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @return input array - */ - public static int[] memFreeMergeSort(int[] array) { - memFreeMergeSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void memFreeMergeSort(int[] array, int length) { - memFreeMergeSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void memFreeMergeSort(int[] array, int from, int to) { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to); - return; - } - int mid = (from + to) >>> 1; - memFreeMergeSort(array, from, mid); - memFreeMergeSort(array, mid, to); - if(Integer.compare(array[mid - 1], array[mid]) <= 0) - return; - for(int i = from, j = mid, comp;i < j && j < to;) { - if((comp = Integer.compare(array[i], array[j])) < 0) - i++; - else if(comp == 0) swap(array, ++i, j); - else { - int k = j; - for(;k < to - 1 && Integer.compare(array[i], array[k + 1]) > 0;k++); - if(j == k) { - swap(array, i++, j); - continue; - } - else if(j + 1 == k) { - int value = array[j]; - System.arraycopy(array, i, array, i+1, j - i); - array[i] = value; - i++; - j++; - continue; - } - int[] data = new int[k - j]; - System.arraycopy(array, j, data, 0, data.length); - System.arraycopy(array, i, array, i+data.length, j - i); - System.arraycopy(data, 0, array, i, data.length); - i+=data.length; - j+=data.length; - } - } - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(int[] array, IntComparator comp) { - parallelMemFreeMergeSort(array, 0, array.length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(int[] array, int length, IntComparator comp) { - parallelMemFreeMergeSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(int[] array, int from, int to, IntComparator comp) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new MemFreeMergeSortActionComp(array, from, to, comp)); - return; - } - memFreeMergeSort(array, from, to, comp); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(int[] array) { - parallelMemFreeMergeSort(array, 0, array.length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(int[] array, int length) { - parallelMemFreeMergeSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(int[] array, int from, int to) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new MemFreeMergeSortAction(array, from, to)); - return; - } - memFreeMergeSort(array, from, to); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array - */ - public static int[] quickSort(int[] array, IntComparator comp) { - quickSort(array, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void quickSort(int[] array, int length, IntComparator comp) { - quickSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void quickSort(int[] array, int from, int to, IntComparator comp) { - int length = to - from; - if(length <= 0) return; - if(length < BASE_THRESHOLD) { - selectionSort(array, from, to, comp); - return; - } - int pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)]; - int a = from, b = a, c = to - 1, d = c; - for(int compare;;swap(array, b++, c--)) { - for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) { - if(compare == 0) swap(array, a++, b); - } - for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) { - if(compare == 0) swap(array, c, d--); - } - if(b>c) break; - } - swap(array, from, b, Math.min(a - from, b - a)); - swap(array, b, to, Math.min(d - c, to - d - 1)); - if((length = b - a) > 1) quickSort(array, from, from + length, comp); - if((length = d - c) > 1) quickSort(array, to - length, to, comp); - } - - /** - * Sorts an array according to the natural ascending order using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @return input array - */ - public static int[] quickSort(int[] array) { - quickSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void quickSort(int[] array, int length) { - quickSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void quickSort(int[] array, int from, int to) { - int length = to - from; - if(length <= 0) return; - if(length < BASE_THRESHOLD) { - selectionSort(array, from, to); - return; - } - int pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)]; - int a = from, b = a, c = to - 1, d = c; - for(int comp = 0;;swap(array, b++, c--)) { - for(;b<=c && (comp = Integer.compare(array[b], pivot)) <= 0;b++) { - if(comp == 0) swap(array, a++, b); - } - for(;c>=b && (comp = Integer.compare(array[c], pivot)) >= 0;c--) { - if(comp == 0) swap(array, c, d--); - } - if(b>c) break; - } - swap(array, from, b, Math.min(a - from, b - a)); - swap(array, b, to, Math.min(d - c, to - d - 1)); - if((length = b - a) > 1) quickSort(array, from, from + length); - if((length = d - c) > 1) quickSort(array, to - length, to); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(int[] array, IntComparator comp) { - parallelQuickSort(array, 0, array.length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(int[] array, int length, IntComparator comp) { - parallelQuickSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(int[] array, int from, int to, IntComparator comp) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new QuickSortActionComp(array, from, to, comp)); - return; - } - quickSort(array, from, to, comp); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(int[] array) { - parallelQuickSort(array, 0, array.length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(int[] array, int length) { - parallelQuickSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(int[] array, int from, int to) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new QuickSortAction(array, from, to)); - return; - } - quickSort(array, from, to); - } - - static void swap(int[] a, int from, int to) { - int t = a[from]; - a[from] = a[to]; - a[to] = t; - } - - static void swap(int[] a, int from, int to, int length) { - to -= length; - for(int i = 0;i 0 ? b : comp.compare(data[a], data[c]) > 0 ? c : a); - } - - static int subMedium(int[] data, int a, int b, int c, int length) { - return medium(data, medium(data, a, a + length, a + (length * 2)), medium(data, b - length, b, b + length), medium(data, c - (length * 2), c - length, c)); - } - - static int medium(int[] data, int a, int b, int c) { - return Integer.compare(data[a], data[b]) < 0 ? (Integer.compare(data[b], data[c]) < 0 ? b : Integer.compare(data[a], data[c]) < 0 ? c : a) : (Integer.compare(data[b], data[c]) > 0 ? b : Integer.compare(data[a], data[c]) > 0 ? c : a); - } - - static class QuickSortAction extends RecursiveAction { - private static final long serialVersionUID = 0L; - int[] array; - int from; - int to; - - QuickSortAction(int[] array, int from, int to) - { - this.array = array; - this.from = from; - this.to = to; - } - - @Override - protected void compute() - { - int length = to - from; - if(length <= 0) return; - if(length < BASE_THRESHOLD) { - selectionSort(array, from, to); - return; - } - int pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)]; - int a = from, b = a, c = to - 1, d = c; - for(int comp = 0;;swap(array, b++, c--)) { - for(;b<=c && (comp = Integer.compare(array[b], pivot)) <= 0;b++) { - if(comp == 0) swap(array, a++, b); - } - for(;c>=b && (comp = Integer.compare(array[c], pivot)) >= 0;c--) { - if(comp == 0) swap(array, c, d--); - } - if(b>c) break; - } - swap(array, from, b, Math.min(a - from, b - a)); - swap(array, b, to, Math.min(d - c, to - d - 1)); - if(b - a > 1 && d - c > 1) invokeAll(new QuickSortAction(array, from, from + (b - a)), new QuickSortAction(array, to - (d - c), to)); - else if(b - a > 1) new QuickSortAction(array, from, from + (b - a)).invoke(); - else if(d - c > 1) new QuickSortAction(array, to - (d - c), to).invoke(); - } - } - - static class QuickSortActionComp extends RecursiveAction { - private static final long serialVersionUID = 0L; - int[] array; - int from; - int to; - IntComparator comp; - - QuickSortActionComp(int[] array, int from, int to, IntComparator comp) - { - this.array = array; - this.from = from; - this.to = to; - this.comp = comp; - } - - @Override - protected void compute() - { - int length = to - from; - if(length <= 0) return; - if(length < BASE_THRESHOLD) { - selectionSort(array, from, to, comp); - return; - } - int pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)]; - int a = from, b = a, c = to - 1, d = c; - for(int compare;;swap(array, b++, c--)) { - for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) { - if(compare == 0) swap(array, a++, b); - } - for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) { - if(compare == 0) swap(array, c, d--); - } - if(b>c) break; - } - swap(array, from, b, Math.min(a - from, b - a)); - swap(array, b, to, Math.min(d - c, to - d - 1)); - if(b - a > 1 && d - c > 1) invokeAll(new QuickSortActionComp(array, from, from + (b - a), comp), new QuickSortActionComp(array, to - (d - c), to, comp)); - else if(b - a > 1) new QuickSortActionComp(array, from, from + (b - a), comp).invoke(); - else if(d - c > 1) new QuickSortActionComp(array, to - (d - c), to, comp).invoke(); - } - } - - static class MergeSortAction extends RecursiveAction { - private static final long serialVersionUID = 0L; - int[] array; - int[] supp; - int from; - int to; - - MergeSortAction(int[] array, int[] supp, int from, int to) - { - this.array = array; - this.supp = supp; - this.from = from; - this.to = to; - } - - @Override - protected void compute() - { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to); - return; - } - if(supp == null) supp = Arrays.copyOf(array, to); - int mid = (from + to) >>> 1; - invokeAll(new MergeSortAction(supp, array, from, mid), new MergeSortAction(supp, array, mid, to)); - if(Integer.compare(supp[mid - 1], supp[mid]) <= 0) - { - System.arraycopy(supp, from, array, from, to - from); - return; - } - for(int p = from, q = mid;from < to;from++) { - if(q >= to || p < mid && Integer.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; - else array[from] = supp[q++]; - } - } - } - - static class MergeSortActionComp extends RecursiveAction { - private static final long serialVersionUID = 0L; - int[] array; - int[] supp; - int from; - int to; - IntComparator comp; - - MergeSortActionComp(int[] array, int[] supp, int from, int to, IntComparator comp) - { - this.array = array; - this.supp = supp; - this.from = from; - this.to = to; - this.comp = comp; - } - - @Override - protected void compute() - { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to, comp); - return; - } - if(supp == null) supp = Arrays.copyOf(array, to); - int mid = (from + to) >>> 1; - invokeAll(new MergeSortActionComp(supp, array, from, mid, comp), new MergeSortActionComp(supp, array, mid, to, comp)); - if(comp.compare(supp[mid - 1], supp[mid]) <= 0) - { - System.arraycopy(supp, from, array, from, to - from); - return; - } - for(int p = from, q = mid;from < to;from++) { - if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; - else array[from] = supp[q++]; - } - } - } - - static class MemFreeMergeSortAction extends RecursiveAction { - private static final long serialVersionUID = 0L; - int[] array; - int from; - int to; - - MemFreeMergeSortAction(int[] array, int from, int to) - { - this.array = array; - this.from = from; - this.to = to; - } - - @Override - protected void compute() - { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to); - return; - } - int mid = (from + to) >>> 1; - invokeAll(new MemFreeMergeSortAction(array, from, mid), new MemFreeMergeSortAction(array, mid, to)); - if(Integer.compare(array[mid - 1], array[mid]) <= 0) - return; - for(int i = from, j = mid, comp;i < j && j < to;) { - if((comp = Integer.compare(array[i], array[j])) < 0) - i++; - else if(comp == 0) swap(array, ++i, j); - else { - int k = j; - for(;k < to - 1 && Integer.compare(array[i], array[k + 1]) > 0;k++); - if(j == k) { - swap(array, i++, j); - continue; - } - else if(j + 1 == k) { - int value = array[j]; - System.arraycopy(array, i, array, i+1, j - i); - array[i] = value; - i++; - j++; - continue; - } - int[] data = new int[k - j]; - System.arraycopy(array, j, data, 0, data.length); - System.arraycopy(array, i, array, i+data.length, j - i); - System.arraycopy(data, 0, array, i, data.length); - i+=data.length; - j+=data.length; - } - } - } - } - - static class MemFreeMergeSortActionComp extends RecursiveAction { - private static final long serialVersionUID = 0L; - int[] array; - int from; - int to; - IntComparator comp; - - MemFreeMergeSortActionComp(int[] array, int from, int to, IntComparator comp) - { - this.array = array; - this.from = from; - this.to = to; - this.comp = comp; - } - - @Override - protected void compute() - { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to, comp); - return; - } - int mid = (from + to) >>> 1; - invokeAll(new MemFreeMergeSortActionComp(array, from, mid, comp), new MemFreeMergeSortActionComp(array, mid, to, comp)); - - if(comp.compare(array[mid - 1], array[mid]) <= 0) - return; - for(int i = from, j = mid, compare;i < j && j < to;) { - if((compare = comp.compare(array[i], array[j])) < 0) - i++; - else if(compare == 0) swap(array, ++i, j); - else { - int k = j; - for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++); - if(j == k) { - swap(array, i++, j); - continue; - } - else if(j + 1 == k) { - int value = array[j]; - System.arraycopy(array, i, array, i+1, j - i); - array[i] = value; - i++; - j++; - continue; - } - int[] data = new int[k - j]; - System.arraycopy(array, j, data, 0, data.length); - System.arraycopy(array, i, array, i+data.length, j - i); - System.arraycopy(data, 0, array, i, data.length); - i+=data.length; - j+=data.length; - } - } - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IntCollections.java b/src/main/java/speiger/src/collections/ints/utils/IntCollections.java deleted file mode 100644 index 91aeb66af..000000000 --- a/src/main/java/speiger/src/collections/ints/utils/IntCollections.java +++ /dev/null @@ -1,892 +0,0 @@ -package speiger.src.collections.ints.utils; - -import java.util.Arrays; -import java.util.Collection; -import java.util.ConcurrentModificationException; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.function.Predicate; -import java.util.function.IntPredicate; -import java.util.function.Consumer; - -import speiger.src.collections.ints.collections.AbstractIntCollection; -import speiger.src.collections.ints.collections.IntCollection; -import speiger.src.collections.ints.collections.IntIterator; -import speiger.src.collections.ints.functions.IntComparator; -import speiger.src.collections.objects.utils.ObjectArrays; -import speiger.src.collections.ints.functions.IntConsumer; -import speiger.src.collections.ints.utils.IntArrays; -import speiger.src.collections.ints.functions.function.IntIntUnaryOperator; -import speiger.src.collections.ints.functions.consumer.IntIntConsumer; -import speiger.src.collections.objects.functions.consumer.ObjectIntConsumer; -import speiger.src.collections.utils.HashUtil; -import speiger.src.collections.utils.ITrimmable; -import speiger.src.collections.utils.SanityChecks; - -/** - * A Helper class for Collections - */ -public class IntCollections -{ - /** - * Empty Collection Reference - */ - public static final IntCollection EMPTY = new EmptyCollection(); - - /** - * Returns a Immutable EmptyCollection instance that is automatically casted. - * @return an empty collection - */ - public static IntCollection empty() { - return EMPTY; - } - - /** - * Returns a Immutable Collection instance based on the instance given. - * @param c that should be made immutable/unmodifiable - * @return a unmodifiable collection wrapper. If the Collection already a unmodifiable wrapper then it just returns itself. - */ - public static IntCollection unmodifiable(IntCollection c) { - return c instanceof UnmodifiableCollection ? c : new UnmodifiableCollection(c); - } - - /** - * Returns a synchronized Collection instance based on the instance given. - * @param c that should be synchronized - * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself. - */ - public static IntCollection synchronize(IntCollection c) { - return c instanceof SynchronizedCollection ? c : new SynchronizedCollection(c); - } - - /** - * Returns a synchronized Collection instance based on the instance given. - * @param c that should be synchronized - * @param mutex is the controller of the synchronization block. - * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself. - */ - public static IntCollection synchronize(IntCollection c, Object mutex) { - return c instanceof SynchronizedCollection ? c : new SynchronizedCollection(c, mutex); - } - - /** - * Creates a Singleton Collection of a given element - * @param element the element that should be converted into a singleton collection - * @return a singletoncollection of the given element - */ - public static IntCollection singleton(int element) { - return new SingletonCollection(element); - } - - protected static CollectionWrapper wrapper() { - return new CollectionWrapper(); - } - - protected static CollectionWrapper wrapper(int size) { - return new CollectionWrapper(size); - } - - protected static DistinctCollectionWrapper distinctWrapper() { - return new DistinctCollectionWrapper(); - } - - protected static DistinctCollectionWrapper distinctWrapper(int size) { - return new DistinctCollectionWrapper(size); - } - - protected static class CollectionWrapper extends AbstractIntCollection implements ITrimmable { - int[] elements; - int size = 0; - - public CollectionWrapper() { - this(10); - } - - public CollectionWrapper(int size) { - if(size < 0) throw new IllegalStateException("Size has to be 0 or greater"); - elements = new int[size]; - } - - @Override - public boolean add(int o) { - if(size >= elements.length) elements = Arrays.copyOf(elements, (int)Math.min((long)elements.length + (elements.length >> 1), SanityChecks.MAX_ARRAY_SIZE)); - elements[size++] = o; - return true; - } - - public int getInt(int index) { - if(index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); - return elements[index]; - } - - @Override - public boolean remInt(int e) { - for(int i = 0;i= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); - size--; - if(index != size) System.arraycopy(elements, index+1, elements, index, size - index); - } - - @Override - public IntIterator iterator() { - return new IntIterator() { - int index = 0; - int lastReturned = -1; - - @Override - public boolean hasNext() { - return index < size; - } - - @Override - public int nextInt() { - int i = index++; - return elements[(lastReturned = i)]; - } - - @Override - public void remove() { - if(lastReturned == -1) throw new IllegalStateException(); - removeIndex(lastReturned); - index = lastReturned; - lastReturned = -1; - } - }; - } - - @Override - public int size() { - return size; - } - - @Override - public void clear() { - size = 0; - } - - public void sort(IntComparator c) { - if(c != null) IntArrays.stableSort(elements, size, c); - else IntArrays.stableSort(elements, size); - } - - public void unstableSort(IntComparator c) { - if(c != null) IntArrays.unstableSort(elements, size, c); - else IntArrays.unstableSort(elements, size); - } - - @Override - public void forEach(IntConsumer action) { - Objects.requireNonNull(action); - for(int i = 0;i void forEach(E input, ObjectIntConsumer action) { - Objects.requireNonNull(action); - for(int i = 0;i size() || size() == elements.length) return false; - int value = Math.max(size, size()); - elements = value == 0 ? IntArrays.EMPTY_ARRAY : Arrays.copyOf(elements, value); - return true; - } - - @Override - public void clearAndTrim(int size) { - if(elements.length <= size) { - clear(); - return; - } - elements = size == 0 ? IntArrays.EMPTY_ARRAY : new int[size]; - this.size = size; - } - - @Override - @Deprecated - public Object[] toArray() { - Object[] obj = new Object[size]; - for(int i = 0;i E[] toArray(E[] a) { - if(a == null) a = (E[])new Object[size]; - else if(a.length < size) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), size); - for(int i = 0;i size) a[size] = null; - return a; - } - - @Override - public int[] toIntArray(int[] a) { - if(a.length < size) a = new int[size]; - System.arraycopy(elements, 0, a, 0, size); - if (a.length > size) a[size] = 0; - return a; - } - } - - protected static class DistinctCollectionWrapper extends AbstractIntCollection { - int[] keys; - boolean containsNull; - int minCapacity; - int nullIndex; - int maxFill; - int mask; - int size; - - public DistinctCollectionWrapper() { - this(HashUtil.DEFAULT_MIN_CAPACITY); - } - - public DistinctCollectionWrapper(int size) { - if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); - minCapacity = nullIndex = HashUtil.arraySize(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR); - mask = nullIndex - 1; - maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1); - keys = new int[nullIndex + 1]; - } - - @Override - public boolean add(int o) { - if(o == 0) { - if(containsNull) return false; - containsNull = true; - } - else { - int pos = HashUtil.mix(Integer.hashCode(o)) & mask; - int current = keys[pos]; - if(current != 0) { - if(current == o) return false; - while((current = keys[pos = (++pos & mask)]) != 0) - if(current == o) return false; - } - keys[pos] = o; - } - if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, HashUtil.DEFAULT_LOAD_FACTOR)); - return true; - } - - @Override - public boolean contains(Object o) { - if(o == null) return false; - if(o instanceof Integer && ((Integer)o).intValue() == 0) return containsNull; - int pos = HashUtil.mix(o.hashCode()) & mask; - int current = keys[pos]; - if(current == 0) return false; - if(Objects.equals(o, Integer.valueOf(current))) return true; - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(Objects.equals(o, Integer.valueOf(current))) return true; - } - } - - @Override - public boolean remove(Object o) { - if(o == null) return false; - if(o instanceof Integer && ((Integer)o).intValue() == 0) return (containsNull ? removeNullIndex() : false); - int pos = HashUtil.mix(o.hashCode()) & mask; - int current = keys[pos]; - if(current == 0) return false; - if(Objects.equals(o, Integer.valueOf(current))) return removeIndex(pos); - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(Objects.equals(o, Integer.valueOf(current))) return removeIndex(pos); - } - } - - @Override - public boolean contains(int o) { - if(o == 0) return containsNull; - int pos = HashUtil.mix(Integer.hashCode(o)) & mask; - int current = keys[pos]; - if(current == 0) return false; - if(current == o) return true; - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(current == o) return true; - } - } - - @Override - public boolean remInt(int o) { - if(o == 0) return containsNull ? removeNullIndex() : false; - int pos = HashUtil.mix(Integer.hashCode(o)) & mask; - int current = keys[pos]; - if(current == 0) return false; - if(current == o) return removeIndex(pos); - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(current == o) return removeIndex(pos); - } - } - - protected boolean removeIndex(int pos) { - if(pos == nullIndex) return containsNull ? removeNullIndex() : false; - keys[pos] = 0; - size--; - shiftKeys(pos); - if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); - return true; - } - - protected boolean removeNullIndex() { - containsNull = false; - keys[nullIndex] = 0; - size--; - if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); - return true; - } - - @Override - public IntIterator iterator() { - return new SetIterator(); - } - - @Override - public void forEach(IntConsumer action) { - if(size() <= 0) return; - if(containsNull) action.accept(keys[nullIndex]); - for(int i = nullIndex-1;i>=0;i--) { - if(keys[i] != 0) action.accept(keys[i]); - } - } - - @Override - public DistinctCollectionWrapper copy() { - DistinctCollectionWrapper set = new DistinctCollectionWrapper(0); - set.minCapacity = minCapacity; - set.mask = mask; - set.maxFill = maxFill; - set.nullIndex = nullIndex; - set.containsNull = containsNull; - set.size = size; - set.keys = Arrays.copyOf(keys, keys.length); - return set; - } - - protected void shiftKeys(int startPos) { - int slot, last; - int current; - while(true) { - startPos = ((last = startPos) + 1) & mask; - while(true){ - if((current = keys[startPos]) == 0) { - keys[last] = 0; - return; - } - slot = HashUtil.mix(Integer.hashCode(current)) & mask; - if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; - startPos = ++startPos & mask; - } - keys[last] = current; - } - } - - protected void rehash(int newSize) { - int newMask = newSize - 1; - int[] newKeys = new int[newSize + 1]; - for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) { - while(true) { - if(--i < 0) throw new ConcurrentModificationException("Set was modified during rehash"); - if(keys[i] != 0) break; - } - if(newKeys[pos = HashUtil.mix(Integer.hashCode(keys[i])) & newMask] != 0) - while(newKeys[pos = (++pos & newMask)] != 0); - newKeys[pos] = keys[i]; - } - nullIndex = newSize; - mask = newMask; - maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1); - keys = newKeys; - } - - @Override - public void clear() { - if(size == 0) return; - size = 0; - containsNull = false; - Arrays.fill(keys, 0); - } - - @Override - public int size() { - return size; - } - - private class SetIterator implements IntIterator { - int pos = nullIndex; - int returnedPos = -1; - int lastReturned = -1; - int nextIndex = Integer.MIN_VALUE; - boolean returnNull = containsNull; - int[] wrapped = null; - int wrappedIndex = 0; - - @Override - public boolean hasNext() { - if(nextIndex == Integer.MIN_VALUE) { - if(returnNull) { - returnNull = false; - nextIndex = nullIndex; - } - else - { - while(true) { - if(--pos < 0) { - if(wrapped == null || wrappedIndex <= -pos - 1) break; - nextIndex = -pos - 1; - break; - } - if(keys[pos] != 0){ - nextIndex = pos; - break; - } - } - } - } - return nextIndex != Integer.MIN_VALUE; - } - - @Override - public int nextInt() { - if(!hasNext()) throw new NoSuchElementException(); - returnedPos = pos; - if(nextIndex < 0){ - lastReturned = Integer.MAX_VALUE; - int value = wrapped[nextIndex]; - nextIndex = Integer.MIN_VALUE; - return value; - } - int value = keys[(lastReturned = nextIndex)]; - nextIndex = Integer.MIN_VALUE; - return value; - } - - @Override - public void remove() { - if(lastReturned == -1) throw new IllegalStateException(); - if(lastReturned == nullIndex) { - containsNull = false; - keys[nullIndex] = 0; - } - else if(returnedPos >= 0) shiftKeys(returnedPos); - else { - DistinctCollectionWrapper.this.remInt(wrapped[-returnedPos - 1]); - lastReturned = -1; - return; - } - size--; - lastReturned = -1; - } - - private void shiftKeys(int startPos) { - int slot, last; - int current; - while(true) { - startPos = ((last = startPos) + 1) & mask; - while(true){ - if((current = keys[startPos]) == 0) { - keys[last] = 0; - return; - } - slot = HashUtil.mix(Integer.hashCode(current)) & mask; - if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; - startPos = ++startPos & mask; - } - if(startPos < last) addWrapper(keys[startPos]); - keys[last] = current; - } - } - - private void addWrapper(int value) { - if(wrapped == null) wrapped = new int[2]; - else if(wrappedIndex >= wrapped.length) { - int[] newArray = new int[wrapped.length * 2]; - System.arraycopy(wrapped, 0, newArray, 0, wrapped.length); - wrapped = newArray; - } - wrapped[wrappedIndex++] = value; - } - } - } - - private static class SingletonCollection extends AbstractIntCollection - { - int element; - - SingletonCollection(int element) { - this.element = element; - } - - @Override - public boolean remInt(int o) { throw new UnsupportedOperationException(); } - @Override - public boolean add(int o) { throw new UnsupportedOperationException(); } - @Override - public IntIterator iterator() - { - return new IntIterator() { - boolean next = true; - @Override - public boolean hasNext() { return next; } - @Override - public int nextInt() { - if(!hasNext()) throw new NoSuchElementException(); - next = false; - return element; - } - }; - } - - @Override - public boolean equals(Object o) { - if (o == this) - return true; - if (!(o instanceof Collection)) - return false; - Collection l = (Collection)o; - if(l.size() != size()) return false; - Iterator iter = l.iterator(); - if (iter.hasNext() && !Objects.equals(element, iter.next())) { - return false; - } - return !iter.hasNext(); - } - - @Override - public int hashCode() { - return Integer.hashCode(element); - } - - @Override - public int size() { return 1; } - - @Override - public SingletonCollection copy() { return new SingletonCollection(element); } - } - - /** - * Synchronized Collection Wrapper for the synchronizedCollection function - */ - public static class SynchronizedCollection implements IntCollection { - IntCollection c; - protected Object mutex; - - SynchronizedCollection(IntCollection c) { - this.c = c; - mutex = this; - } - - SynchronizedCollection(IntCollection c, Object mutex) { - this.c = c; - this.mutex = mutex; - } - - @Override - public boolean add(int o) { synchronized(mutex) { return c.add(o); } } - @Override - public boolean addAll(Collection c) { synchronized(mutex) { return this.c.addAll(c); } } - @Override - public boolean addAll(IntCollection c) { synchronized(mutex) { return this.c.addAll(c); } } - @Override - public boolean addAll(int[] e, int offset, int length) { synchronized(mutex) { return c.addAll(e, offset, length); } } - @Override - public boolean contains(int o) { synchronized(mutex) { return c.contains(o); } } - @Override - @Deprecated - public boolean containsAll(Collection c) { synchronized(mutex) { return this.c.containsAll(c); } } - - @Override - @Deprecated - public boolean containsAny(Collection c) { synchronized(mutex) { return this.c.containsAny(c); } } - - @Override - public boolean containsAll(IntCollection c) { synchronized(mutex) { return this.c.containsAll(c); } } - - @Override - public boolean containsAny(IntCollection c) { synchronized(mutex) { return this.c.containsAny(c); } } - - @Override - public int size() { synchronized(mutex) { return c.size(); } } - - @Override - public boolean isEmpty() { synchronized(mutex) { return c.isEmpty(); } } - - @Override - public IntIterator iterator() { - return c.iterator(); - } - - @Override - public IntCollection copy() { synchronized(mutex) { return c.copy(); } } - - @Override - @Deprecated - public boolean remove(Object o) { synchronized(mutex) { return c.remove(o); } } - @Override - @Deprecated - public boolean removeAll(Collection c) { synchronized(mutex) { return this.c.removeAll(c); } } - @Override - @Deprecated - public boolean retainAll(Collection c) { synchronized(mutex) { return this.c.retainAll(c); } } - @Override - public boolean remInt(int o) { synchronized(mutex) { return c.remInt(o); } } - @Override - public boolean removeAll(IntCollection c) { synchronized(mutex) { return this.c.removeAll(c); } } - @Override - public boolean removeAll(IntCollection c, IntConsumer r) { synchronized(mutex) { return this.c.removeAll(c, r); } } - @Override - public boolean retainAll(IntCollection c) { synchronized(mutex) { return this.c.retainAll(c); } } - @Override - public boolean retainAll(IntCollection c, IntConsumer r) { synchronized(mutex) { return this.c.retainAll(c, r); } } - @Override - public boolean remIf(IntPredicate filter){ synchronized(mutex) { return c.remIf(filter); } } - @Override - public void clear() { synchronized(mutex) { c.clear(); } } - @Override - public Object[] toArray() { synchronized(mutex) { return c.toArray(); } } - @Override - public T[] toArray(T[] a) { synchronized(mutex) { return c.toArray(a); } } - @Override - public int[] toIntArray() { synchronized(mutex) { return c.toIntArray(); } } - @Override - public int[] toIntArray(int[] a) { synchronized(mutex) { return c.toIntArray(a); } } - @Override - public void forEach(IntConsumer action) { synchronized(mutex) { c.forEach(action); } } - @Override - @Deprecated - public void forEach(Consumer action) { synchronized(mutex) { c.forEach(action); } } - @Override - public void forEachIndexed(IntIntConsumer action) { synchronized(mutex) { c.forEachIndexed(action); } } - @Override - public int hashCode() { synchronized(mutex) { return c.hashCode(); } } - @Override - public boolean equals(Object obj) { - if(obj == this) return true; - synchronized(mutex) { return c.equals(obj); } - } - @Override - public String toString() { synchronized(mutex) { return c.toString(); } } - @Override - public void forEach(E input, ObjectIntConsumer action) { synchronized(mutex) { c.forEach(input, action); } } - @Override - public boolean matchesAny(IntPredicate filter) { synchronized(mutex) { return c.matchesAny(filter); } } - @Override - public boolean matchesNone(IntPredicate filter) { synchronized(mutex) { return c.matchesNone(filter); } } - @Override - public boolean matchesAll(IntPredicate filter) { synchronized(mutex) { return c.matchesAll(filter); } } - @Override - public int reduce(int identity, IntIntUnaryOperator operator) { synchronized(mutex) { return c.reduce(identity, operator); } } - @Override - public int reduce(IntIntUnaryOperator operator) { synchronized(mutex) { return c.reduce(operator); } } - @Override - public int findFirst(IntPredicate filter) { synchronized(mutex) { return c.findFirst(filter); } } - @Override - public int count(IntPredicate filter) { synchronized(mutex) { return c.count(filter); } } - } - - /** - * Unmodifyable Collection Wrapper for the unmodifyableCollection method - */ - public static class UnmodifiableCollection implements IntCollection { - IntCollection c; - - UnmodifiableCollection(IntCollection c) { - this.c = c; - } - - @Override - public boolean add(int o) { throw new UnsupportedOperationException(); } - @Override - public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } - @Override - public boolean addAll(IntCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean addAll(int[] e, int offset, int length) { throw new UnsupportedOperationException(); } - @Override - public boolean contains(int o) { return c.contains(o); } - @Override - public boolean containsAll(IntCollection c) { return this.c.containsAll(c); } - @Override - public boolean containsAny(IntCollection c) { return this.c.containsAny(c); } - @Override - @Deprecated - public boolean containsAny(Collection c) { return this.c.containsAny(c); } - @Override - @Deprecated - public boolean containsAll(Collection c) { return this.c.containsAll(c); } - @Override - public int size() { return c.size(); } - @Override - public boolean isEmpty() { return c.isEmpty(); } - @Override - public IntIterator iterator() { return IntIterators.unmodifiable(c.iterator()); } - @Override - public IntCollection copy() { return c.copy(); } - @Override - @Deprecated - public boolean remove(Object o) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); } - @Override - public boolean remInt(int o) { throw new UnsupportedOperationException(); } - @Override - public boolean removeAll(IntCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean removeAll(IntCollection c, IntConsumer r) { throw new UnsupportedOperationException(); } - @Override - public boolean retainAll(IntCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean retainAll(IntCollection c, IntConsumer r) { throw new UnsupportedOperationException(); } - @Override - public boolean remIf(IntPredicate filter){ throw new UnsupportedOperationException(); } - @Override - public void clear() { throw new UnsupportedOperationException(); } - @Override - public Object[] toArray() { return c.toArray(); } - @Override - public T[] toArray(T[] a) { return c.toArray(a); } - @Override - public int[] toIntArray() { return c.toIntArray(); } - @Override - public int[] toIntArray(int[] a) { return c.toIntArray(a); } - @Override - public void forEach(IntConsumer action) { c.forEach(action); } - @Override - @Deprecated - public void forEach(Consumer action) { c.forEach(action); } - @Override - public void forEachIndexed(IntIntConsumer action) { c.forEachIndexed(action); } - @Override - public int hashCode() { return c.hashCode(); } - @Override - public boolean equals(Object obj) { return obj == this || c.equals(obj); } - @Override - public String toString() { return c.toString(); } - @Override - public void forEach(E input, ObjectIntConsumer action) { c.forEach(input, action); } - @Override - public boolean matchesAny(IntPredicate filter) { return c.matchesAny(filter); } - @Override - public boolean matchesNone(IntPredicate filter) { return c.matchesNone(filter); } - @Override - public boolean matchesAll(IntPredicate filter) { return c.matchesAll(filter); } - @Override - public int reduce(int identity, IntIntUnaryOperator operator) { return c.reduce(identity, operator); } - @Override - public int reduce(IntIntUnaryOperator operator) { return c.reduce(operator); } - @Override - public int findFirst(IntPredicate filter) { return c.findFirst(filter); } - @Override - public int count(IntPredicate filter) { return c.count(filter); } - } - - /** - * Empty Collection implementation for the empty collection function - */ - public static class EmptyCollection extends AbstractIntCollection { - @Override - public boolean add(int o) { throw new UnsupportedOperationException(); } - - @Override - public boolean addAll(IntCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean addAll(int[] e, int offset, int length) { throw new UnsupportedOperationException(); } - - @Override - public boolean contains(int o) { return false; } - @Override - public boolean containsAll(IntCollection c) { return c.isEmpty(); } - @Override - public boolean containsAny(IntCollection c) { return false; } - @Override - @Deprecated - public boolean containsAny(Collection c) { return false; } - @Override - @Deprecated - public boolean containsAll(Collection c) { return c.isEmpty(); } - @Override - public int hashCode() { return 0; } - - @Override - public boolean equals(Object o) { - if(o == this) return true; - if(!(o instanceof Collection)) return false; - return ((Collection)o).isEmpty(); - } - - @Override - @Deprecated - public boolean remove(Object o) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); } - @Override - public boolean remInt(int o) { throw new UnsupportedOperationException(); } - @Override - public boolean removeAll(IntCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean retainAll(IntCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean remIf(IntPredicate filter){ throw new UnsupportedOperationException(); } - @Override - public Object[] toArray() { return ObjectArrays.EMPTY_ARRAY; } - @Override - public T[] toArray(T[] a) { - if(a != null && a.length > 0) - a[0] = null; - return a; - } - - @Override - public int[] toIntArray() { return IntArrays.EMPTY_ARRAY; } - @Override - public int[] toIntArray(int[] a) { - if(a != null && a.length > 0) - a[0] = 0; - return a; - } - - @Override - public IntIterator iterator() { return IntIterators.empty(); } - @Override - public void clear() {} - @Override - public int size() { return 0; } - @Override - public EmptyCollection copy() { return this; } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IntIterables.java b/src/main/java/speiger/src/collections/ints/utils/IntIterables.java deleted file mode 100644 index 46cd7b21f..000000000 --- a/src/main/java/speiger/src/collections/ints/utils/IntIterables.java +++ /dev/null @@ -1,485 +0,0 @@ -package speiger.src.collections.ints.utils; - -import java.util.Objects; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Consumer; -import java.util.function.IntPredicate; - -import speiger.src.collections.ints.collections.IntIterable; -import speiger.src.collections.ints.collections.IntCollection; -import speiger.src.collections.objects.collections.ObjectIterable; -import speiger.src.collections.objects.collections.ObjectIterator; -import speiger.src.collections.ints.functions.IntConsumer; -import speiger.src.collections.ints.functions.IntComparator; -import speiger.src.collections.ints.collections.IntIterator; -import speiger.src.collections.ints.functions.function.IntFunction; -import speiger.src.collections.utils.ISizeProvider; - -/** - * A Helper class for Iterables - */ -public class IntIterables -{ - /** - * A Helper function that maps a Java-Iterable into a new Type. - * @param iterable the iterable that should be mapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterable that is mapped to a new result - */ - public static ObjectIterable map(Iterable iterable, IntFunction mapper) { - return new MappedIterable<>(wrap(iterable), mapper); - } - - /** - * A Helper function that maps a Iterable into a new Type. - * @param iterable the iterable that should be mapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterable that is mapped to a new result - */ - public static ObjectIterable map(IntIterable iterable, IntFunction mapper) { - return new MappedIterable<>(iterable, mapper); - } - - /** - * A Helper function that flatMaps a Java-Iterable into a new Type. - * @param iterable the iterable that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type supplier. - * @param The return type. - * @return a iterable that is flatMapped to a new result - */ - public static > ObjectIterable flatMap(Iterable iterable, IntFunction mapper) { - return new FlatMappedIterable<>(wrap(iterable), mapper); - } - - /** - * A Helper function that flatMaps a Iterable into a new Type. - * @param iterable the iterable that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type supplier. - * @param The return type. - * @return a iterable that is flatMapped to a new result - */ - public static > ObjectIterable flatMap(IntIterable iterable, IntFunction mapper) { - return new FlatMappedIterable<>(iterable, mapper); - } - - /** - * A Helper function that flatMaps a Java-Iterable into a new Type. - * @param iterable the iterable that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterable that is flatMapped to a new result - */ - public static ObjectIterable arrayFlatMap(Iterable iterable, IntFunction mapper) { - return new FlatMappedArrayIterable<>(wrap(iterable), mapper); - } - - /** - * A Helper function that flatMaps a Iterable into a new Type. - * @param iterable the iterable that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterable that is flatMapped to a new result - */ - public static ObjectIterable arrayFlatMap(IntIterable iterable, IntFunction mapper) { - return new FlatMappedArrayIterable<>(iterable, mapper); - } - - /** - * A Helper function that filters out all desired elements from a Java-Iterable - * @param iterable that should be filtered. - * @param filter the filter that decides that should be let through - * @return a filtered iterable - */ - public static IntIterable filter(Iterable iterable, IntPredicate filter) { - return new FilteredIterable(wrap(iterable), filter); - } - - /** - * A Helper function that filters out all desired elements - * @param iterable that should be filtered. - * @param filter the filter that decides that should be let through - * @return a filtered iterable - */ - public static IntIterable filter(IntIterable iterable, IntPredicate filter) { - return new FilteredIterable(iterable, filter); - } - - /** - * A Helper function that filters out all duplicated elements. - * @param iterable that should be distinct - * @return a distinct iterable - */ - public static IntIterable distinct(IntIterable iterable) { - return new DistinctIterable(iterable); - } - - /** - * A Helper function that filters out all duplicated elements from a Java Iterable. - * @param iterable that should be distinct - * @return a distinct iterable - */ - public static IntIterable distinct(Iterable iterable) { - return new DistinctIterable(wrap(iterable)); - } - - /** - * A Helper function that repeats the Iterable a specific amount of times - * @param iterable that should be repeated - * @param repeats the amount of times the iterable should be repeated - * @return a repeating iterable - */ - public static IntIterable repeat(IntIterable iterable, int repeats) { - return new RepeatingIterable(iterable, repeats); - } - - /** - * A Helper function that repeats the Iterable a specific amount of times from a Java Iterable - * @param iterable that should be repeated - * @param repeats the amount of times the iterable should be repeated - * @return a repeating iterable - */ - public static IntIterable repeat(Iterable iterable, int repeats) { - return new RepeatingIterable(wrap(iterable), repeats); - } - - /** - * A Helper function that hard limits the Iterable to a specific size - * @param iterable that should be limited - * @param limit the amount of elements it should be limited to - * @return a limited iterable - */ - public static IntIterable limit(IntIterable iterable, long limit) { - return new LimitedIterable(iterable, limit); - } - - /** - * A Helper function that hard limits the Iterable to a specific size from a Java Iterable - * @param iterable that should be limited - * @param limit the amount of elements it should be limited to - * @return a limited iterable - */ - public static IntIterable limit(Iterable iterable, long limit) { - return new LimitedIterable(wrap(iterable), limit); - } - - /** - * A Helper function that sorts the Iterable. - * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. - * @param iterable that should be sorted - * @param sorter that sorts the iterable. Can be null. - * @return a sorted iterable. - */ - public static IntIterable sorted(IntIterable iterable, IntComparator sorter) { - return new SortedIterable(iterable, sorter); - } - - /** - * A Helper function that sorts the Iterable from a Java Iterable - * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. - * @param iterable that should be sorted - * @param sorter that sorts the iterable. Can be null. - * @return a sorted iterable. - */ - public static IntIterable sorted(Iterable iterable, IntComparator sorter) { - return new SortedIterable(wrap(iterable), sorter); - } - - /** - * A Helper function that allows to preview the result of a Iterable. - * @param iterable that should be peeked at - * @param action callback that receives the value before the iterable returns it - * @return a peeked iterable - */ - public static IntIterable peek(IntIterable iterable, IntConsumer action) { - return new PeekIterable(iterable, action); - } - - /** - * A Helper function that allows to preview the result of a Iterable from a Java Iterable - * @param iterable that should be peeked at - * @param action callback that receives the value before the iterable returns it - * @return a peeked iterable - */ - public static IntIterable peek(Iterable iterable, IntConsumer action) { - return new PeekIterable(wrap(iterable), action); - } - - /** - * A Wrapper function that wraps a Java-Iterable into a Type Specific Iterable - * @param iterable that should be wrapped - * @return a type specific iterable - */ - public static IntIterable wrap(Iterable iterable) { - return new WrappedIterable(iterable); - } - - private static class WrappedIterable implements IntIterable, ISizeProvider - { - Iterable iterable; - - public WrappedIterable(Iterable iterable) { - this.iterable = iterable; - } - - public IntIterator iterator() { - return IntIterators.wrap(iterable.iterator()); - } - - @Override - public int size() { - ISizeProvider prov = ISizeProvider.of(iterable); - return prov == null ? -1 : prov.size(); - } - - @Override - public void forEach(IntConsumer action) { - Objects.requireNonNull(action); - iterable.forEach(action); - } - } - - private static class MappedIterable implements ObjectIterable, ISizeProvider - { - IntIterable iterable; - IntFunction mapper; - - MappedIterable(IntIterable iterable, IntFunction mapper) { - this.iterable = iterable; - this.mapper = mapper; - } - - public ObjectIterator iterator() { - return IntIterators.map(iterable.iterator(), mapper); - } - - @Override - public int size() { - ISizeProvider prov = ISizeProvider.of(this); - return prov == null ? -1 : prov.size(); - } - - @Override - public void forEach(Consumer action) { - Objects.requireNonNull(action); - iterable.forEach(E -> action.accept(mapper.apply(E))); - } - } - - private static class FlatMappedIterable> implements ObjectIterable - { - IntIterable iterable; - IntFunction mapper; - - FlatMappedIterable(IntIterable iterable, IntFunction mapper) { - this.iterable = iterable; - this.mapper = mapper; - } - - @Override - public ObjectIterator iterator() { - return IntIterators.flatMap(iterable.iterator(), mapper); - } - - @Override - public void forEach(Consumer action) { - Objects.requireNonNull(action); - iterable.forEach(E -> mapper.apply(E).forEach(action)); - } - - } - - private static class FlatMappedArrayIterable implements ObjectIterable - { - IntIterable iterable; - IntFunction mapper; - - FlatMappedArrayIterable(IntIterable iterable, IntFunction mapper) { - this.iterable = iterable; - this.mapper = mapper; - } - - @Override - public ObjectIterator iterator() { - return IntIterators.arrayFlatMap(iterable.iterator(), mapper); - } - - @Override - public void forEach(Consumer action) { - Objects.requireNonNull(action); - iterable.forEach(E -> { - T[] array = mapper.apply(E); - for(int i = 0,m=array.length;i { if(!filter.test(T)) action.accept(T); } ); - } - } - - private static class LimitedIterable implements IntIterable, ISizeProvider - { - IntIterable iterable; - long limit; - - public LimitedIterable(IntIterable iterable, long limit) { - this.iterable = iterable; - this.limit = limit; - } - - @Override - public IntIterator iterator() { - return IntIterators.limit(iterable.iterator(), limit); - } - - @Override - public int size() { - ISizeProvider prov = ISizeProvider.of(iterable); - return prov == null ? -1 : (int)Math.min(prov.size(), limit); - } - - @Override - public void forEach(IntConsumer action) { - Objects.requireNonNull(action); - AtomicLong counter = new AtomicLong(); - iterable.forEach(T -> { - if(counter.get() >= limit) return; - counter.incrementAndGet(); - action.accept(T); - }); - } - } - - private static class SortedIterable implements IntIterable, ISizeProvider - { - IntIterable iterable; - IntComparator sorter; - - public SortedIterable(IntIterable iterable, IntComparator sorter) { - this.iterable = iterable; - this.sorter = sorter; - } - - @Override - public IntIterator iterator() { - return IntIterators.sorted(iterable.iterator(), sorter); - } - - @Override - public int size() { - ISizeProvider prov = ISizeProvider.of(iterable); - return prov == null ? -1 : prov.size(); - } - - @Override - public void forEach(IntConsumer action) { - Objects.requireNonNull(action); - IntCollections.CollectionWrapper wrapper = IntCollections.wrapper(); - iterable.forEach(wrapper::add); - wrapper.unstableSort(sorter); - wrapper.forEach(action); - } - } - - private static class DistinctIterable implements IntIterable - { - IntIterable iterable; - - public DistinctIterable(IntIterable iterable) { - this.iterable = iterable; - } - - @Override - public IntIterator iterator() { - return IntIterators.distinct(iterable.iterator()); - } - - @Override - public void forEach(IntConsumer action) { - Objects.requireNonNull(action); - IntCollection filtered = IntCollections.distinctWrapper(); - iterable.forEach(T -> { if(filtered.add(T)) action.accept(T); }); - } - } - - private static class PeekIterable implements IntIterable, ISizeProvider - { - IntIterable iterable; - IntConsumer action; - - public PeekIterable(IntIterable iterable, IntConsumer action) { - this.iterable = iterable; - this.action = action; - } - - @Override - public IntIterator iterator() { - return IntIterators.peek(iterable.iterator(), action); - } - - @Override - public int size() { - ISizeProvider prov = ISizeProvider.of(iterable); - return prov == null ? -1 : prov.size(); - } - - @Override - public void forEach(IntConsumer action) { - Objects.requireNonNull(action); - iterable.forEach(this.action.andThen(action)); - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IntIterators.java b/src/main/java/speiger/src/collections/ints/utils/IntIterators.java deleted file mode 100644 index e0068176c..000000000 --- a/src/main/java/speiger/src/collections/ints/utils/IntIterators.java +++ /dev/null @@ -1,1003 +0,0 @@ -package speiger.src.collections.ints.utils; - -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.function.IntPredicate; - -import speiger.src.collections.ints.collections.IntIterator; -import speiger.src.collections.objects.collections.ObjectIterator; -import speiger.src.collections.objects.utils.ObjectIterators; -import speiger.src.collections.ints.functions.IntConsumer; -import speiger.src.collections.ints.functions.IntComparator; -import speiger.src.collections.ints.functions.function.IntFunction; -import speiger.src.collections.ints.lists.IntListIterator; -import speiger.src.collections.ints.collections.IntBidirectionalIterator; -import speiger.src.collections.ints.collections.IntCollection; - -/** - * A Helper class for Iterators - */ -public class IntIterators -{ - /** - * Empty Iterator Reference - */ - private static final EmptyIterator EMPTY = new EmptyIterator(); - - /** - * Returns a Immutable EmptyIterator instance that is automatically casted. - * @return an empty iterator - */ - public static EmptyIterator empty() { - return EMPTY; - } - - /** - * Inverter function for Bidirectional Iterators - * @param it the iterator that should be inverted - * @return a Inverted Bidirectional Iterator. If it was inverted then it just gives back the original reference - */ - public static IntBidirectionalIterator invert(IntBidirectionalIterator it) { - return it instanceof ReverseBiIterator ? ((ReverseBiIterator)it).it : new ReverseBiIterator(it); - } - - /** - * Inverter function for List Iterators - * @param it the iterator that should be inverted - * @return a Inverted List Iterator. If it was inverted then it just gives back the original reference - */ - public static IntListIterator invert(IntListIterator it) { - return it instanceof ReverseListIterator ? ((ReverseListIterator)it).it : new ReverseListIterator(it); - } - - /** - * Returns a Immutable Iterator instance based on the instance given. - * @param iterator that should be made immutable/unmodifiable - * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself. - */ - public static IntIterator unmodifiable(IntIterator iterator) { - return iterator instanceof UnmodifiableIterator ? iterator : new UnmodifiableIterator(iterator); - } - - /** - * Returns a Immutable Iterator instance based on the instance given. - * @param iterator that should be made immutable/unmodifiable - * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself. - */ - public static IntBidirectionalIterator unmodifiable(IntBidirectionalIterator iterator) { - return iterator instanceof UnmodifiableBiIterator ? iterator : new UnmodifiableBiIterator(iterator); - } - - /** - * Returns a Immutable ListIterator instance based on the instance given. - * @param iterator that should be made immutable/unmodifiable - * @return a unmodifiable listiterator wrapper. If the ListIterator already a unmodifiable wrapper then it just returns itself. - */ - public static IntListIterator unmodifiable(IntListIterator iterator) { - return iterator instanceof UnmodifiableListIterator ? iterator : new UnmodifiableListIterator(iterator); - } - - /** - * A Helper function that maps a Java-Iterator into a new Type. - * @param iterator that should be mapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterator that is mapped to a new result - */ - public static ObjectIterator map(Iterator iterator, IntFunction mapper) { - return new MappedIterator<>(wrap(iterator), mapper); - } - - /** - * A Helper function that maps a Iterator into a new Type. - * @param iterator that should be mapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterator that is mapped to a new result - */ - public static ObjectIterator map(IntIterator iterator, IntFunction mapper) { - return new MappedIterator<>(iterator, mapper); - } - - /** - * A Helper function that flatMaps a Java-Iterator into a new Type. - * @param iterator that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type supplier. - * @param The return type. - * @return a iterator that is flatMapped to a new result - */ - public static > ObjectIterator flatMap(Iterator iterator, IntFunction mapper) { - return new FlatMappedIterator<>(wrap(iterator), mapper); - } - - /** - * A Helper function that flatMaps a Iterator into a new Type. - * @param iterator that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type supplier. - * @param The return type. - * @return a iterator that is flatMapped to a new result - */ - public static > ObjectIterator flatMap(IntIterator iterator, IntFunction mapper) { - return new FlatMappedIterator<>(iterator, mapper); - } - - /** - * A Helper function that flatMaps a Java-Iterator into a new Type. - * @param iterator that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterator that is flatMapped to a new result - */ - public static ObjectIterator arrayFlatMap(Iterator iterator, IntFunction mapper) { - return new FlatMappedArrayIterator<>(wrap(iterator), mapper); - } - - /** - * A Helper function that flatMaps a Iterator into a new Type. - * @param iterator that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterator that is flatMapped to a new result - */ - public static ObjectIterator arrayFlatMap(IntIterator iterator, IntFunction mapper) { - return new FlatMappedArrayIterator<>(iterator, mapper); - } - - /** - * A Helper function that filters out all desired elements from a Java-Iterator - * @param iterator that should be filtered. - * @param filter the filter that decides that should be let through - * @return a filtered iterator - */ - public static IntIterator filter(Iterator iterator, IntPredicate filter) { - return new FilteredIterator(wrap(iterator), filter); - } - - /** - * A Helper function that filters out all desired elements - * @param iterator that should be filtered. - * @param filter the filter that decides that should be let through - * @return a filtered iterator - */ - public static IntIterator filter(IntIterator iterator, IntPredicate filter) { - return new FilteredIterator(iterator, filter); - } - - /** - * A Helper function that filters out all duplicated elements. - * @param iterator that should be distinct - * @return a distinct iterator - */ - public static IntIterator distinct(IntIterator iterator) { - return new DistinctIterator(iterator); - } - - /** - * A Helper function that filters out all duplicated elements from a Java Iterator. - * @param iterator that should be distinct - * @return a distinct iterator - */ - public static IntIterator distinct(Iterator iterator) { - return new DistinctIterator(wrap(iterator)); - } - - /** - * A Helper function that repeats the Iterator a specific amount of times - * @param iterator that should be repeated - * @param repeats the amount of times the iterator should be repeated - * @return a repeating iterator - */ - public static IntIterator repeat(IntIterator iterator, int repeats) { - return new RepeatingIterator(iterator, repeats); - } - - /** - * A Helper function that repeats the Iterator a specific amount of times from a Java Iterator - * @param iterator that should be repeated - * @param repeats the amount of times the iterator should be repeated - * @return a repeating iterator - */ - public static IntIterator repeat(Iterator iterator, int repeats) { - return new RepeatingIterator(wrap(iterator), repeats); - } - - /** - * A Helper function that hard limits the Iterator to a specific size - * @param iterator that should be limited - * @param limit the amount of elements it should be limited to - * @return a limited iterator - */ - public static IntIterator limit(IntIterator iterator, long limit) { - return new LimitedIterator(iterator, limit); - } - - /** - * A Helper function that hard limits the Iterator to a specific size from a Java Iterator - * @param iterator that should be limited - * @param limit the amount of elements it should be limited to - * @return a limited iterator - */ - public static IntIterator limit(Iterator iterator, long limit) { - return new LimitedIterator(wrap(iterator), limit); - } - - /** - * A Helper function that sorts the Iterator beforehand. - * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. - * @param iterator that should be sorted. - * @param sorter the sorter of the iterator. Can be null. - * @return a new sorted iterator - */ - public static IntIterator sorted(IntIterator iterator, IntComparator sorter) { - return new SortedIterator(iterator, sorter); - } - - /** - * A Helper function that sorts the Iterator beforehand from a Java Iterator. - * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. - * @param iterator that should be sorted. - * @param sorter the sorter of the iterator. Can be null. - * @return a new sorted iterator - */ - public static IntIterator sorted(Iterator iterator, IntComparator sorter) { - return new SortedIterator(wrap(iterator), sorter); - } - - /** - * A Helper function that allows to preview the result of a Iterator. - * @param iterator that should be peeked at - * @param action callback that receives the value before the iterator returns it - * @return a peeked iterator - */ - public static IntIterator peek(IntIterator iterator, IntConsumer action) { - return new PeekIterator(iterator, action); - } - - /** - * A Helper function that allows to preview the result of a Iterator from a Java Iterator - * @param iterator that should be peeked at - * @param action callback that receives the value before the iterator returns it - * @return a peeked iterator - */ - public static IntIterator peek(Iterator iterator, IntConsumer action) { - return new PeekIterator(wrap(iterator), action); - } - - /** - * Helper function to convert a Object Iterator into a Primitive Iterator - * @param iterator that should be converted to a unboxing iterator - * @return a primitive iterator - */ - public static IntIterator wrap(Iterator iterator) { - return iterator instanceof IntIterator ? (IntIterator)iterator : new IteratorWrapper(iterator); - } - - /** - * Returns a Array Wrapping iterator - * @param a the array that should be wrapped - * @return a Iterator that is wrapping a array. - */ - public static ArrayIterator wrap(int... a) { - return wrap(a, 0, a.length); - } - - /** - * Returns a Array Wrapping iterator - * @param a the array that should be wrapped. - * @param start the index to be started from. - * @param end the index that should be ended. - * @return a Iterator that is wrapping a array. - */ - public static ArrayIterator wrap(int[] a, int start, int end) { - return new ArrayIterator(a, start, end); - } - - /** - * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted - * @param a where the elements should be inserted - * @param i the source iterator - * @return the amount of elements that were inserted into the array. - */ - public static int unwrap(int[] a, Iterator i) { - return unwrap(a, i, 0, a.length); - } - - /** - * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted - * @param a where the elements should be inserted - * @param i the source iterator - * @param offset the array offset where the start should be - * @return the amount of elements that were inserted into the array. - */ - public static int unwrap(int[] a, Iterator i, int offset) { - return unwrap(a, i, offset, a.length - offset); - } - - /** - * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted - * @param a where the elements should be inserted - * @param i the source iterator - * @param offset the array offset where the start should be - * @param max the maximum values that should be extracted from the source - * @return the amount of elements that were inserted into the array. - * @throws IllegalStateException if max is smaller the 0 or if the maximum index is larger then the array - */ - public static int unwrap(int[] a, Iterator i, int offset, int max) { - if(max < 0) throw new IllegalStateException("The max size is smaller then 0"); - if(offset + max > a.length) throw new IllegalStateException("largest array index exceeds array size"); - int index = 0; - for(;index a.length) throw new IllegalStateException("largest array index exceeds array size"); - int index = 0; - for(;index a.length) throw new IllegalStateException("largest array index exceeds array size"); - int index = 0; - for(;index iter; - - public IteratorWrapper(Iterator iter) { - this.iter = iter; - } - - @Override - public boolean hasNext() { - return iter.hasNext(); - } - - @Override - public int nextInt() { - return iter.next().intValue(); - } - - @Override - @Deprecated - public Integer next() { - return iter.next(); - } - } - - private static class ConcatIterator implements IntIterator - { - IntIterator[] iters; - int offset; - int lastOffset = -1; - int length; - - public ConcatIterator(IntIterator[] iters, int offset, int length) { - this.iters = iters; - this.offset = offset; - this.length = length; - find(); - } - - private void find() { - for(;length != 0 && !iters[offset].hasNext();length--, offset++); - } - - @Override - public boolean hasNext() { - return length > 0; - } - - @Override - public int nextInt() { - if(!hasNext()) throw new NoSuchElementException(); - int result = iters[lastOffset = offset].nextInt(); - find(); - return result; - } - - @Override - public void remove() { - if(lastOffset == -1) throw new IllegalStateException(); - iters[lastOffset].remove(); - lastOffset = -1; - } - } - - private static class ReverseBiIterator implements IntBidirectionalIterator { - IntBidirectionalIterator it; - - ReverseBiIterator(IntBidirectionalIterator it) { - this.it = it; - } - - @Override - public int nextInt() { return it.previousInt(); } - @Override - public boolean hasNext() { return it.hasPrevious(); } - @Override - public boolean hasPrevious() { return it.hasNext(); } - @Override - public int previousInt() { return it.nextInt(); } - @Override - public void remove() { it.remove(); } - } - - private static class ReverseListIterator implements IntListIterator { - IntListIterator it; - - ReverseListIterator(IntListIterator it) { - this.it = it; - } - - @Override - public int nextInt() { return it.previousInt(); } - @Override - public boolean hasNext() { return it.hasPrevious(); } - @Override - public boolean hasPrevious() { return it.hasNext(); } - @Override - public int previousInt() { return it.nextInt(); } - @Override - public void remove() { it.remove(); } - @Override - public int nextIndex() { return it.previousIndex(); } - @Override - public int previousIndex() { return it.nextIndex(); } - @Override - public void set(int e) { it.set(e); } - @Override - public void add(int e) { it.add(e); } - } - - private static class UnmodifiableListIterator implements IntListIterator - { - IntListIterator iter; - - UnmodifiableListIterator(IntListIterator iter) { - this.iter = iter; - } - - @Override - public boolean hasNext() { - return iter.hasNext(); - } - - @Override - public boolean hasPrevious() { - return iter.hasPrevious(); - } - - @Override - public int nextIndex() { - return iter.nextIndex(); - } - - @Override - public int previousIndex() { - return iter.previousIndex(); - } - - @Override - public void remove() { throw new UnsupportedOperationException(); } - - @Override - public int previousInt() { - return iter.previousInt(); - } - - @Override - public int nextInt() { - return iter.nextInt(); - } - - @Override - public void set(int e) { throw new UnsupportedOperationException(); } - - @Override - public void add(int e) { throw new UnsupportedOperationException(); } - } - - private static class UnmodifiableBiIterator implements IntBidirectionalIterator - { - IntBidirectionalIterator iter; - - UnmodifiableBiIterator(IntBidirectionalIterator iter) { - this.iter = iter; - } - - @Override - public int nextInt() { - return iter.nextInt(); - } - - @Override - public boolean hasNext() { - return iter.hasNext(); - } - - @Override - public boolean hasPrevious() { - return iter.hasPrevious(); - } - - @Override - public int previousInt() { - return iter.previousInt(); - } - } - - private static class UnmodifiableIterator implements IntIterator - { - IntIterator iterator; - - UnmodifiableIterator(IntIterator iterator) { - this.iterator = iterator; - } - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public int nextInt() { - return iterator.nextInt(); - } - } - - private static class EmptyIterator implements IntListIterator - { - @Override - public boolean hasNext() { return false; } - @Override - public int nextInt() { throw new NoSuchElementException(); } - @Override - public boolean hasPrevious() { return false; } - @Override - public int previousInt() { throw new NoSuchElementException(); } - @Override - public int nextIndex() { return 0; } - @Override - public int previousIndex() { return -1; } - @Override - public void remove() { throw new UnsupportedOperationException(); } - @Override - public void set(int e) { throw new UnsupportedOperationException(); } - @Override - public void add(int e) { throw new UnsupportedOperationException(); } - } - - private static class ArrayIterator implements IntIterator - { - int[] a; - int from; - int to; - - ArrayIterator(int[] a, int from, int to) { - this.a = a; - this.from = from; - this.to = to; - } - - @Override - public boolean hasNext() { - return from < to; - } - - @Override - public int nextInt() { - if(!hasNext()) throw new NoSuchElementException(); - return a[from++]; - } - - @Override - public int skip(int amount) { - if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); - int left = Math.min(amount, to - from); - from += left; - return amount - left; - } - } - - private static class MappedIterator implements ObjectIterator - { - IntIterator iterator; - IntFunction mapper; - - MappedIterator(IntIterator iterator, IntFunction mapper) { - this.iterator = iterator; - this.mapper = mapper; - } - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public T next() { - return mapper.apply(iterator.nextInt()); - } - - @Override - public int skip(int amount) { - return iterator.skip(amount); - } - } - - private static class FlatMappedIterator> implements ObjectIterator - { - IntIterator iterator; - Iterator last = null; - IntFunction mapper; - boolean foundNext = false; - - FlatMappedIterator(IntIterator iterator, IntFunction mapper) { - this.iterator = iterator; - this.mapper = mapper; - } - - void compute() { - if(foundNext) return; - foundNext = true; - while(iterator.hasNext()) { - if(last != null && last.hasNext()) return; - last = mapper.apply(iterator.nextInt()).iterator(); - } - } - - @Override - public boolean hasNext() { - compute(); - return last != null && last.hasNext(); - } - - @Override - public T next() { - if(!hasNext()) throw new NoSuchElementException(); - T result = last.next(); - foundNext = false; - return result; - } - } - - private static class FlatMappedArrayIterator implements ObjectIterator - { - IntIterator iterator; - Iterator last = null; - IntFunction mapper; - boolean foundNext = false; - - FlatMappedArrayIterator(IntIterator iterator, IntFunction mapper) { - this.iterator = iterator; - this.mapper = mapper; - } - - void compute() { - if(foundNext) return; - foundNext = true; - while(iterator.hasNext()) { - if(last != null && last.hasNext()) return; - last = ObjectIterators.wrap(mapper.apply(iterator.nextInt())); - } - } - - @Override - public boolean hasNext() { - compute(); - return last != null && last.hasNext(); - } - - @Override - public T next() { - if(!hasNext()) throw new NoSuchElementException(); - T result = last.next(); - foundNext = false; - return result; - } - } - - private static class RepeatingIterator implements IntIterator - { - final int repeats; - int index = 0; - IntIterator iter; - IntCollection repeater = IntCollections.wrapper(); - - public RepeatingIterator(IntIterator iter, int repeat) { - this.iter = iter; - this.repeats = repeat; - } - - @Override - public boolean hasNext() { - if(iter.hasNext()) return true; - if(index < repeats) { - index++; - iter = repeater.iterator(); - return iter.hasNext(); - } - return false; - } - - @Override - public int nextInt() { - if(!hasNext()) throw new NoSuchElementException(); - int value = iter.nextInt(); - if(index == 0) repeater.add(value); - return value; - } - } - - private static class SortedIterator implements IntIterator - { - IntIterator iterator; - IntComparator sorter; - IntCollections.CollectionWrapper sortedElements = null; - int index = 0; - - public SortedIterator(IntIterator iterator, IntComparator sorter) { - this.iterator = iterator; - this.sorter = sorter; - } - - @Override - public boolean hasNext() { - if(sortedElements == null) { - boolean hasNext = iterator.hasNext(); - if(hasNext) { - sortedElements = IntCollections.wrapper(); - pour(iterator, sortedElements); - } - else sortedElements = IntCollections.wrapper(); - if(hasNext) sortedElements.unstableSort(sorter); - } - return index < sortedElements.size(); - } - - @Override - public int nextInt() { - if(!hasNext()) throw new NoSuchElementException(); - return sortedElements.getInt(index++); - } - } - - private static class DistinctIterator implements IntIterator - { - IntIterator iterator; - IntCollection filtered = IntCollections.distinctWrapper(); - int lastFound; - boolean foundNext = false; - - public DistinctIterator(IntIterator iterator) { - this.iterator = iterator; - } - - void compute() { - if(foundNext) return; - while(iterator.hasNext()) { - lastFound = iterator.nextInt(); - if(filtered.add(lastFound)) { - foundNext = true; - break; - } - } - } - - @Override - public boolean hasNext() { - compute(); - return foundNext; - } - - @Override - public int nextInt() { - if(!hasNext()) throw new NoSuchElementException(); - foundNext = false; - return lastFound; - } - } - - private static class FilteredIterator implements IntIterator - { - IntIterator iterator; - IntPredicate filter; - int lastFound; - boolean foundNext = false; - - public FilteredIterator(IntIterator iterator, IntPredicate filter) { - this.iterator = iterator; - this.filter = filter; - } - - void compute() { - if(foundNext) return; - while(iterator.hasNext()) { - lastFound = iterator.nextInt(); - if(filter.test(lastFound)) { - foundNext = true; - break; - } - } - } - - @Override - public boolean hasNext() { - compute(); - return foundNext; - } - - @Override - public int nextInt() { - if(!hasNext()) throw new NoSuchElementException(); - foundNext = false; - return lastFound; - } - } - - private static class LimitedIterator implements IntIterator - { - IntIterator iterator; - long limit; - - public LimitedIterator(IntIterator iterator, long limit) { - this.iterator = iterator; - this.limit = limit; - } - - @Override - public boolean hasNext() { - return limit > 0 && iterator.hasNext(); - } - - @Override - public int nextInt() { - if(!hasNext()) throw new NoSuchElementException(); - limit--; - return iterator.nextInt(); - } - } - - private static class PeekIterator implements IntIterator - { - IntIterator iterator; - IntConsumer action; - - public PeekIterator(IntIterator iterator, IntConsumer action) { - this.iterator = iterator; - this.action = action; - } - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public int nextInt() { - if(!hasNext()) throw new NoSuchElementException(); - int result = iterator.nextInt(); - action.accept(result); - return result; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/ints/utils/IntSplititerators.java b/src/main/java/speiger/src/collections/ints/utils/IntSplititerators.java deleted file mode 100644 index a1571f64f..000000000 --- a/src/main/java/speiger/src/collections/ints/utils/IntSplititerators.java +++ /dev/null @@ -1,461 +0,0 @@ -package speiger.src.collections.ints.utils; - -import java.util.Comparator; -import java.util.NoSuchElementException; -import java.util.Spliterator; -import java.util.Spliterator.OfInt; -import java.util.function.Consumer; - -import speiger.src.collections.ints.collections.IntCollection; -import speiger.src.collections.ints.collections.IntIterator; -import speiger.src.collections.ints.collections.IntSplititerator; -import speiger.src.collections.ints.functions.IntConsumer; -import speiger.src.collections.utils.SanityChecks; - -/** - * Helper class that provides SplitIterators for normal and stream usage - */ -public class IntSplititerators -{ - /** - * Creates A stream compatible split iterator without copying the original array or boxing - * @param array that should be wrapped into a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - */ - public static OfInt createArrayJavaSplititerator(int[] array, int characteristics) { return createArrayJavaSplititerator(array, 0, array.length, characteristics);} - /** - * Creates A stream compatible split iterator without copying the original array or boxing - * @param array that should be wrapped into a split iterator - * @param size the maximum index within the array - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - * @throws IllegalStateException if the size is outside of the array size - */ - public static OfInt createArrayJavaSplititerator(int[] array, int size, int characteristics) { return createArrayJavaSplititerator(array, 0, size, characteristics);} - /** - * Creates A stream compatible split iterator without copying the original array or boxing - * @param array that should be wrapped into a split iterator - * @param offset the starting index of the array - * @param size the maximum index within the array - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - * @throws IllegalStateException the offset and size are outside of the arrays range - */ - public static OfInt createArrayJavaSplititerator(int[] array, int offset, int size, int characteristics) { - SanityChecks.checkArrayCapacity(array.length, offset, size); - return new ArraySplitIterator(array, offset, size, characteristics); - } - - /** - * Creates a stream compatible split iterator without copying it or boxing it - * @param collection the collection that should be wrapped in a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - */ - public static OfInt createJavaSplititerator(IntCollection collection, int characteristics) { - return new IteratorSpliterator(collection, characteristics); - } - - /** - * Creates a stream compatible split iterator without copying it or boxing it - * @param iterator the Iterator that should be wrapped in a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - */ - public static OfInt createUnknownJavaSplititerator(IntIterator iterator, int characteristics) { - return new IteratorSpliterator(iterator, characteristics); - } - - /** - * Creates a stream compatible split iterator without copying it or boxing it - * @param iterator the collection that should be wrapped in a split iterator - * @param size the amount of elements in the iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - */ - public static OfInt createSizedJavaSplititerator(IntIterator iterator, long size, int characteristics) { - return new IteratorSpliterator(iterator, size, characteristics); - } - - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param array that should be wrapped into a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - */ - public static IntSplititerator createArraySplititerator(int[] array, int characteristics) { return createArraySplititerator(array, 0, array.length, characteristics);} - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param array that should be wrapped into a split iterator - * @param size the maximum index within the array - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - * @throws IllegalStateException if the size is outside of the array size - */ - public static IntSplititerator createArraySplititerator(int[] array, int size, int characteristics) { return createArraySplititerator(array, 0, size, characteristics);} - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param array that should be wrapped into a split iterator - * @param offset the starting index of the array - * @param size the maximum index within the array - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - * @throws IllegalStateException the offset and size are outside of the arrays range - */ - public static IntSplititerator createArraySplititerator(int[] array, int offset, int size, int characteristics) { - SanityChecks.checkArrayCapacity(array.length, offset, size); - return new TypeArraySplitIterator(array, offset, size, characteristics); - } - - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param collection the collection that should be wrapped in a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - */ - public static IntSplititerator createSplititerator(IntCollection collection, int characteristics) { - return new TypeIteratorSpliterator(collection, characteristics); - } - - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param iterator the Iterator that should be wrapped in a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - */ - public static IntSplititerator createUnknownSplititerator(IntIterator iterator, int characteristics) { - return new TypeIteratorSpliterator(iterator, characteristics); - } - - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param iterator the collection that should be wrapped in a split iterator - * @param size the amount of elements in the iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - */ - public static IntSplititerator createSizedSplititerator(IntIterator iterator, long size, int characteristics) { - return new TypeIteratorSpliterator(iterator, size, characteristics); - } - - static class TypeIteratorSpliterator implements IntSplititerator { - static final int BATCH_UNIT = 1 << 10; - static final int MAX_BATCH = 1 << 25; - private final IntCollection collection; - private IntIterator it; - private final int characteristics; - private long est; - private int batch; - - TypeIteratorSpliterator(IntCollection collection, int characteristics) { - this.collection = collection; - it = null; - this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 - ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED - : characteristics; - } - - TypeIteratorSpliterator(IntIterator iterator, long size, int characteristics) { - collection = null; - it = iterator; - est = size; - this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 - ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED - : characteristics; - } - - TypeIteratorSpliterator(IntIterator iterator, int characteristics) { - collection = null; - it = iterator; - est = Long.MAX_VALUE; - this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); - } - - private IntIterator iterator() - { - if (it == null) { - it = collection.iterator(); - est = collection.size(); - } - return it; - } - - @Override - public IntSplititerator trySplit() { - IntIterator i = iterator(); - if (est > 1 && i.hasNext()) { - int n = Math.min(batch + BATCH_UNIT, Math.min((int)est, MAX_BATCH)); - int[] a = new int[n]; - int j = 0; - do { a[j] = i.nextInt(); } while (++j < n && i.hasNext()); - batch = j; - if (est != Long.MAX_VALUE) - est -= j; - return new TypeArraySplitIterator(a, 0, j, characteristics); - } - return null; - } - - @Override - public void forEachRemaining(IntConsumer action) { - if (action == null) throw new NullPointerException(); - iterator().forEachRemaining(action); - } - - @Override - public boolean tryAdvance(IntConsumer action) { - if (action == null) throw new NullPointerException(); - IntIterator iter = iterator(); - if (iter.hasNext()) { - action.accept(iter.nextInt()); - return true; - } - return false; - } - - @Override - public boolean tryAdvance(Consumer action) { - if (action == null) throw new NullPointerException(); - IntIterator iter = iterator(); - if (iter.hasNext()) { - action.accept(Integer.valueOf(iter.nextInt())); - return true; - } - return false; - } - - @Override - public long estimateSize() { - iterator(); - return est; - } - - @Override - public int characteristics() { return characteristics; } - - @Override - public Comparator getComparator() { - if (hasCharacteristics(4)) //Sorted - return null; - throw new IllegalStateException(); - } - - @Override - public int nextInt() { return iterator().nextInt(); } - - @Override - public boolean hasNext() { return iterator().hasNext(); } - } - - static final class TypeArraySplitIterator implements IntSplititerator { - private final int[] array; - private int index; - private final int fence; - private final int characteristics; - - public TypeArraySplitIterator(int[] array, int origin, int fence, int additionalCharacteristics) { - this.array = array; - index = origin; - this.fence = fence; - characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; - } - - @Override - public IntSplititerator trySplit() { - int lo = index, mid = (lo + fence) >>> 1; - return (lo >= mid) ? null : new TypeArraySplitIterator(array, lo, index = mid, characteristics); - } - - @Override - public void forEachRemaining(IntConsumer action) { - if (action == null) throw new NullPointerException(); - int[] a; int i, hi; - if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) { - do { action.accept(a[i]); } while (++i < hi); - } - } - - @Override - public boolean tryAdvance(IntConsumer action) { - if (action == null) throw new NullPointerException(); - if (index >= 0 && index < fence) { - action.accept(array[index++]); - return true; - } - return false; - } - - @Override - public boolean tryAdvance(Consumer action) { - if (action == null) throw new NullPointerException(); - if (index >= 0 && index < fence) { - action.accept(Integer.valueOf(array[index++])); - return true; - } - return false; - } - - @Override - public long estimateSize() { return fence - index; } - @Override - public int characteristics() { return characteristics; } - @Override - public Comparator getComparator() { - if (hasCharacteristics(4)) //Sorted - return null; - throw new IllegalStateException(); - } - - @Override - public int nextInt() { - if(!hasNext()) throw new NoSuchElementException(); - return array[index++]; - } - - @Override - public boolean hasNext() { return index < fence; } - } - - static class IteratorSpliterator implements OfInt { - static final int BATCH_UNIT = 1 << 10; - static final int MAX_BATCH = 1 << 25; - private final IntCollection collection; - private IntIterator it; - private final int characteristics; - private long est; - private int batch; - - IteratorSpliterator(IntCollection collection, int characteristics) { - this.collection = collection; - it = null; - this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 - ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED - : characteristics; - } - - IteratorSpliterator(IntIterator iterator, long size, int characteristics) { - collection = null; - it = iterator; - est = size; - this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 - ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED - : characteristics; - } - - IteratorSpliterator(IntIterator iterator, int characteristics) { - collection = null; - it = iterator; - est = Long.MAX_VALUE; - this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); - } - - private IntIterator iterator() - { - if (it == null) { - it = collection.iterator(); - est = collection.size(); - } - return it; - } - - @Override - public OfInt trySplit() { - IntIterator i = iterator(); - if (est > 1 && i.hasNext()) { - int n = Math.min(batch + BATCH_UNIT, Math.min((int)est, MAX_BATCH)); - int[] a = new int[n]; - int j = 0; - do { a[j] = i.nextInt(); } while (++j < n && i.hasNext()); - batch = j; - if (est != Long.MAX_VALUE) - est -= j; - return new ArraySplitIterator(a, 0, j, characteristics); - } - return null; - } - - @Override - public void forEachRemaining(java.util.function.IntConsumer action) { - if (action == null) throw new NullPointerException(); - iterator().forEachRemaining(T -> action.accept(T)); - } - - @Override - public boolean tryAdvance(java.util.function.IntConsumer action) { - if (action == null) throw new NullPointerException(); - IntIterator iter = iterator(); - if (iter.hasNext()) { - action.accept(iter.nextInt()); - return true; - } - return false; - } - - @Override - public long estimateSize() { - iterator(); - return est; - } - - @Override - public int characteristics() { return characteristics; } - - @Override - public Comparator getComparator() { - if (hasCharacteristics(4)) //Sorted - return null; - throw new IllegalStateException(); - } - } - - static final class ArraySplitIterator implements OfInt { - private final int[] array; - private int index; - private final int fence; - private final int characteristics; - - public ArraySplitIterator(int[] array, int origin, int fence, int additionalCharacteristics) { - this.array = array; - index = origin; - this.fence = fence; - characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; - } - - @Override - public OfInt trySplit() { - int lo = index, mid = (lo + fence) >>> 1; - return (lo >= mid) ? null : new ArraySplitIterator(array, lo, index = mid, characteristics); - } - - @Override - public void forEachRemaining(java.util.function.IntConsumer action) { - if (action == null) throw new NullPointerException(); - int[] a; int i, hi; - if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) { - do { action.accept(a[i]); } while (++i < hi); - } - } - - @Override - public boolean tryAdvance(java.util.function.IntConsumer action) { - if (action == null) throw new NullPointerException(); - if (index >= 0 && index < fence) { - action.accept(array[index++]); - return true; - } - return false; - } - - @Override - public long estimateSize() { return fence - index; } - @Override - public int characteristics() { return characteristics; } - @Override - public Comparator getComparator() { - if (hasCharacteristics(4)) //Sorted - return null; - throw new IllegalStateException(); - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/collections/AbstractLongCollection.java b/src/main/java/speiger/src/collections/longs/collections/AbstractLongCollection.java deleted file mode 100644 index 88abe106a..000000000 --- a/src/main/java/speiger/src/collections/longs/collections/AbstractLongCollection.java +++ /dev/null @@ -1,252 +0,0 @@ -package speiger.src.collections.longs.collections; - -import java.util.Collection; -import java.util.Objects; -import java.util.AbstractCollection; - -import speiger.src.collections.longs.functions.LongConsumer; -import speiger.src.collections.longs.utils.LongIterators; -import speiger.src.collections.longs.utils.LongArrays; - -/** - * Abstract Type Specific Collection that reduces boxing/unboxing - */ -public abstract class AbstractLongCollection extends AbstractCollection implements LongCollection -{ - @Override - public abstract LongIterator iterator(); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public boolean add(Long e) { return LongCollection.super.add(e); } - - @Override - public boolean addAll(LongCollection c) { - boolean modified = false; - for(LongIterator iter = c.iterator();iter.hasNext();modified |= add(iter.nextLong())); - return modified; - } - - @Override - public LongCollection copy() { throw new UnsupportedOperationException(); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public boolean contains(Object e) { return LongCollection.super.contains(e); } - - /** - * A Type-Specific implementation of contains. This implementation iterates over the elements and returns true if the value match. - * @param e the element that should be searched for. - * @return true if the value was found. - */ - @Override - public boolean contains(long e) { - for(LongIterator iter = iterator();iter.hasNext();) { if(iter.nextLong() == e) return true; } - return false; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public boolean addAll(Collection c) - { - return c instanceof LongCollection ? addAll((LongCollection)c) : super.addAll(c); - } - - /** - * A Type-Specific implementation of containsAll. This implementation iterates over all elements and checks all elements are present in the other collection. - * @param c the collection that should be checked if it contains all elements. - * @return true if all elements were found in the collection - * @throws NullPointerException if the collection is null - */ - @Override - public boolean containsAll(LongCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return true; - for(LongIterator iter = c.iterator();iter.hasNext();) - if(!contains(iter.nextLong())) - return false; - return true; - } - - @Override - public boolean containsAll(Collection c) { - Objects.requireNonNull(c); - return c instanceof LongCollection ? containsAll((LongCollection)c) : super.containsAll(c); - } - - /** - * This implementation iterates over the elements of the collection and checks if they are stored in this collection - * @param c the elements that should be checked for - * @return true if any element is in this collection - * @throws NullPointerException if the collection is null - */ - @Override - @Deprecated - public boolean containsAny(Collection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - for(Object e : c) - if(contains(e)) - return true; - return false; - } - - /** - * This implementation iterates over the elements of the collection and checks if they are stored in this collection. - * @param c the elements that should be checked for - * @return true if any element is in this collection - * @throws NullPointerException if the collection is null - */ - @Override - public boolean containsAny(LongCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - for(LongIterator iter = c.iterator();iter.hasNext();) - if(contains(iter.nextLong())) - return true; - return false; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public boolean remove(Object e) { return LongCollection.super.remove(e); } - - /** - * A Type-Specific implementation of remove. This implementation iterates over the elements until it finds the element that is searched for or it runs out of elements. - * It stops after finding the first element - * @param e the element that is searched for - * @return true if the element was found and removed. - */ - @Override - public boolean remLong(long e) { - for(LongIterator iter = iterator();iter.hasNext();) { - if(iter.nextLong() == e) { - iter.remove(); - return true; - } - } - return false; - } - - /** - * A Type-Specific implementation of removeAll. This Implementation iterates over all elements and removes them as they were found in the other collection. - * @param c the elements that should be deleted - * @return true if the collection was modified. - * @throws NullPointerException if the collection is null - */ - @Override - public boolean removeAll(LongCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - boolean modified = false; - for(LongIterator iter = iterator();iter.hasNext();) { - if(c.contains(iter.nextLong())) { - iter.remove(); - modified = true; - } - } - return modified; - } - - @Override - public boolean removeAll(LongCollection c, LongConsumer r) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - Objects.requireNonNull(r); - boolean modified = false; - for(LongIterator iter = iterator();iter.hasNext();) { - long e = iter.nextLong(); - if(c.contains(e)) { - r.accept(e); - iter.remove(); - modified = true; - } - } - return modified; - } - - /** - * A Type-Specific implementation of retainAll. This Implementation iterates over all elements and removes them as they were not found in the other collection. - * @param c the elements that should be kept - * @return true if the collection was modified. - * @throws NullPointerException if the collection is null - */ - @Override - public boolean retainAll(LongCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) { - boolean modified = !isEmpty(); - clear(); - return modified; - } - boolean modified = false; - for(LongIterator iter = iterator();iter.hasNext();) { - if(!c.contains(iter.nextLong())) { - iter.remove(); - modified = true; - } - } - return modified; - } - - @Override - public boolean retainAll(LongCollection c, LongConsumer r) { - Objects.requireNonNull(c); - Objects.requireNonNull(r); - if(c.isEmpty()) { - boolean modified = !isEmpty(); - forEach(r); - clear(); - return modified; - } - boolean modified = false; - for(LongIterator iter = iterator();iter.hasNext();) { - long e = iter.nextLong(); - if(!c.contains(e)) { - r.accept(e); - iter.remove(); - modified = true; - } - } - return modified; - } - - /** - * A Type-Specific implementation of toArray that links to {@link #toLongArray(long[])} with a newly created array. - * @return an array containing all of the elements in this collection - */ - @Override - public long[] toLongArray() { - if(isEmpty()) return LongArrays.EMPTY_ARRAY; - return toLongArray(new long[size()]); - } - - /** - * A Type-Specific implementation of toArray. This implementation iterates over all elements and unwraps them into primitive type. - * @param a array that the elements should be injected to. If null or to small a new array with the right size is created - * @return an array containing all of the elements in this collection - */ - @Override - public long[] toLongArray(long[] a) { - if(a == null || a.length < size()) a = new long[size()]; - LongIterators.unwrap(a, iterator()); - if (a.length > size()) a[size()] = 0L; - return a; - } -} diff --git a/src/main/java/speiger/src/collections/longs/collections/LongBidirectionalIterator.java b/src/main/java/speiger/src/collections/longs/collections/LongBidirectionalIterator.java deleted file mode 100644 index e9d759f2c..000000000 --- a/src/main/java/speiger/src/collections/longs/collections/LongBidirectionalIterator.java +++ /dev/null @@ -1,52 +0,0 @@ -package speiger.src.collections.longs.collections; - -import speiger.src.collections.objects.collections.ObjectBidirectionalIterator; -/** - * A Type-Specific {@link ObjectBidirectionalIterator} to reduce (un)boxing - */ -public interface LongBidirectionalIterator extends LongIterator, ObjectBidirectionalIterator -{ - /** - * Returns true if the Iterator has a Previous element - * @return true if the Iterator has a Previous element - */ - public boolean hasPrevious(); - - /** - * Returns the Previous element of the iterator. - * @return the Previous element of the iterator. - * @throws java.util.NoSuchElementException if the iteration has no more elements - */ - public long previousLong(); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default Long previous() { - return Long.valueOf(previousLong()); - } - - /** - * {@inheritDoc} - */ - @Override - default int skip(int amount) - { - return LongIterator.super.skip(amount); - } - - /** - * Reverses the Given amount of elements if possible. A Optimization function to reverse elements faster if the implementation allows it. - * @param amount the amount of elements that should be reversed - * @return the amount of elements that were reversed - */ - public default int back(int amount) { - if(amount < 0) throw new IllegalStateException("Can't go forward"); - int i = 0; - for(;i, LongIterable, ISizeProvider -{ - /** - * A Type-Specific add function to reduce (un)boxing - * @param o the element that should be added - * @return true if the element was added to the collection - */ - public boolean add(long o); - - /** - * A Type-Specific addAll function to reduce (un)boxing - * @param c the collection of elements that should be added - * @return true if elements were added into the collection - */ - public boolean addAll(LongCollection c); - - /** - * A Type-Specific Array based addAll method to reduce the amount of Wrapping - * @param e the elements that should be added - * @return if the collection was modified - */ - public default boolean addAll(long... e) { return addAll(e, 0, e.length); } - - /** - * A Type-Specific Array based addAll method to reduce the amount of Wrapping - * @param e the elements that should be added - * @param length how many elements of the array should be added - * @return if the collection was modified - */ - public default boolean addAll(long[] e, int length) { return addAll(e, 0, length); } - - /** - * A Type-Specific Array based addAll method to reduce the amount of Wrapping - * @param e the elements that should be added - * @param offset where to start within the array - * @param length how many elements of the array should be added - * @return if the collection was modified - */ - public default boolean addAll(long[] e, int offset, int length) { - if(length <= 0) return false; - SanityChecks.checkArrayCapacity(e.length, offset, length); - boolean added = false; - for(int i = 0;i c); - - /** - * A Type-Specific remove function that reduces (un)boxing. - * @param o the element that should be removed - * @return true if the element was removed - * @see Collection#remove(Object) - */ - public boolean remLong(long o); - - /** - * A Type-Specific removeAll function that reduces (un)boxing. - * @param c the collection of elements that should be removed - * @return true if any element was removed - * @see Collection#removeAll(Collection) - */ - public boolean removeAll(LongCollection c); - - /** - * A Type-Specific removeAll function that reduces (un)boxing. - * It also notifies the remover of which exact element is going to be removed. - * @param c the collection of elements that should be removed - * @param r elements that got removed - * @return true if any element was removed - * @see Collection#removeAll(Collection) - */ - public boolean removeAll(LongCollection c, LongConsumer r); - - /** - * A Type-Specific retainAll function that reduces (un)boxing. - * @param c the collection of elements that should be kept - * @return true if any element was removed - * @see Collection#retainAll(Collection) - */ - public boolean retainAll(LongCollection c); - - /** - * A Type-Specific retainAll function that reduces (un)boxing. - * It also notifies the remover of which exact element is going to be removed. - * @param c the collection of elements that should be kept - * @param r elements that got removed - * @return true if any element was removed - * @see Collection#retainAll(Collection) - */ - public boolean retainAll(LongCollection c, LongConsumer r); - - /** - * A Helper function to reduce the usage of Streams and allows to collect all elements - * @param collection that the elements should be inserted to - * @param the collection type - * @return the input with the desired elements - */ - default E pour(E collection) { - collection.addAll(this); - return collection; - } - - /** - * A Function that does a shallow clone of the Collection itself. - * This function is more optimized then a copy constructor since the Collection does not have to be unsorted/resorted. - * It can be compared to Cloneable but with less exception risk - * @return a Shallow Copy of the collection - * @note Wrappers and view collections will not support this feature - */ - public LongCollection copy(); - - /** - * A Type-Specific toArray function that delegates to {@link #toLongArray(long[])} with a newly created array. - * @return an array containing all of the elements in this collection - * @see Collection#toArray() - */ - public long[] toLongArray(); - - /** - * A Type-Specific toArray function that reduces (un)boxing. - * @param a array that the elements should be injected to. If null or to small a new array with the right size is created - * @return an array containing all of the elements in this collection - * @see Collection#toArray(Object[]) - */ - public long[] toLongArray(long[] a); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default boolean removeIf(Predicate filter) { - Objects.requireNonNull(filter); - return remIf(v -> filter.test(Long.valueOf(v))); - } - - /** - * A Type-Specific removeIf function to reduce (un)boxing. - *

Removes elements that were selected by the filter - * @see Collection#removeIf(Predicate) - * @param filter Filters the elements that should be removed - * @return true if the collection was modified - * @throws NullPointerException if filter is null - */ - public default boolean remIf(LongPredicate filter) { - Objects.requireNonNull(filter); - boolean removed = false; - final LongIterator each = iterator(); - while (each.hasNext()) { - if (filter.test(each.nextLong())) { - each.remove(); - removed = true; - } - } - return removed; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default boolean add(Long o) { return add(o.longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default boolean contains(Object o) { return o != null && contains(((Long)o).longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default boolean remove(Object o) { return o != null && remLong(((Long)o).longValue()); } - - /** - * Returns a Type-Specific Iterator to reduce (un)boxing - * @return a iterator of the collection - * @see Collection#iterator() - */ - @Override - public LongIterator iterator(); - - /** - * Creates a Wrapped Collection that is Synchronized - * @return a new Collection that is synchronized - * @see LongCollections#synchronize - */ - public default LongCollection synchronize() { return LongCollections.synchronize(this); } - - /** - * Creates a Wrapped Collection that is Synchronized - * @param mutex is the controller of the synchronization block - * @return a new Collection Wrapper that is synchronized - * @see LongCollections#synchronize - */ - public default LongCollection synchronize(Object mutex) { return LongCollections.synchronize(this, mutex); } - - /** - * Creates a Wrapped Collection that is unmodifiable - * @return a new Collection Wrapper that is unmodifiable - * @see LongCollections#unmodifiable - */ - public default LongCollection unmodifiable() { return LongCollections.unmodifiable(this); } - - /** - * Returns a Java-Type-Specific Stream to reduce boxing/unboxing. - * @return a Stream of the closest java type - */ - default LongStream primitiveStream() { return StreamSupport.longStream(LongSplititerators.createJavaSplititerator(this, 0), false); } - - /** - * Returns a Java-Type-Specific Parallel Stream to reduce boxing/unboxing. - * @return a Stream of the closest java type - */ - default LongStream parallelPrimitiveStream() { return StreamSupport.longStream(LongSplititerators.createJavaSplititerator(this, 0), true); } - - /** - * A Type Specific Type Splititerator to reduce boxing/unboxing - * @return type specific splititerator - */ - @Override - default LongSplititerator spliterator() { return LongSplititerators.createSplititerator(this, 0); } -} diff --git a/src/main/java/speiger/src/collections/longs/collections/LongIterable.java b/src/main/java/speiger/src/collections/longs/collections/LongIterable.java deleted file mode 100644 index ad3b382fe..000000000 --- a/src/main/java/speiger/src/collections/longs/collections/LongIterable.java +++ /dev/null @@ -1,314 +0,0 @@ -package speiger.src.collections.longs.collections; - -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.LongPredicate; - - -import speiger.src.collections.longs.functions.LongConsumer; -import speiger.src.collections.longs.functions.LongComparator; -import speiger.src.collections.objects.collections.ObjectIterable; -import speiger.src.collections.longs.functions.function.LongFunction; -import speiger.src.collections.ints.functions.consumer.IntLongConsumer; -import speiger.src.collections.objects.functions.consumer.ObjectLongConsumer; -import speiger.src.collections.longs.functions.function.LongLongUnaryOperator; - -import speiger.src.collections.longs.utils.LongArrays; -import speiger.src.collections.longs.utils.LongSplititerators; -import speiger.src.collections.longs.utils.LongIterables; -import speiger.src.collections.longs.utils.LongIterators; -import speiger.src.collections.utils.ISizeProvider; - -/** - * A Type-Specific {@link Iterable} that reduces (un)boxing - */ -public interface LongIterable extends Iterable -{ - /** - * Returns an iterator over elements of type {@code T}. - * - * @return an Iterator. - */ - @Override - LongIterator iterator(); - - /** - * A Type Specific foreach function that reduces (un)boxing - * - * @implSpec - *

The default implementation behaves as if: - *

{@code
-	 *	iterator().forEachRemaining(action);
-	 * }
- * - * @param action The action to be performed for each element - * @throws NullPointerException if the specified action is null - * @see Iterable#forEach(Consumer) - */ - default void forEach(LongConsumer action) { - Objects.requireNonNull(action); - iterator().forEachRemaining(action); - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Deprecated - @Override - default void forEach(Consumer action) { - Objects.requireNonNull(action); - iterator().forEachRemaining(action); - } - - /** - * A Indexed forEach implementation that allows you to keep track of how many elements were already iterated over. - * @param action The action to be performed for each element - * @throws NullPointerException if the specified action is null - */ - public default void forEachIndexed(IntLongConsumer action) { - Objects.requireNonNull(action); - int index = 0; - for(LongIterator iter = iterator();iter.hasNext();action.accept(index++, iter.nextLong())); - } - - /** - * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. - * @param input the object that should be included - * @param action The action to be performed for each element - * @param the generic type of the Object - * @throws NullPointerException if the specified action is null - */ - default void forEach(E input, ObjectLongConsumer action) { - Objects.requireNonNull(action); - iterator().forEachRemaining(input, action); - } - - /** - * A Type Specific Type Splititerator to reduce boxing/unboxing - * @return type specific splititerator - */ - @Override - default LongSplititerator spliterator() { return LongSplititerators.createUnknownSplititerator(iterator(), 0); } - - /** - * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. - * @param mapper the mapping function - * @param The return type. - * @return a new Iterable that returns the desired result - */ - default ObjectIterable map(LongFunction mapper) { - return LongIterables.map(this, mapper); - } - - /** - * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. - * @param mapper the flatMapping function - * @param The return type supplier. - * @param The return type. - * @return a new Iterable that returns the desired result - * @note does not support toLongArray optimizations. - */ - default > ObjectIterable flatMap(LongFunction mapper) { - return LongIterables.flatMap(this, mapper); - } - - /** - * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. - * @param mapper the flatMapping function - * @param The return type. - * @return a new Iterable that returns the desired result - * @note does not support toLongArray optimizations. - */ - default ObjectIterable arrayflatMap(LongFunction mapper) { - return LongIterables.arrayFlatMap(this, mapper); - } - - /** - * A Helper function to reduce the usage of Streams and allows to filter out unwanted elements - * @param filter the elements that should be kept. - * @return a Iterable that filtered out all unwanted elements - * @note does not support toLongArray optimizations. - */ - default LongIterable filter(LongPredicate filter) { - return LongIterables.filter(this, filter); - } - - /** - * A Helper function to reduce the usage of Streams and allows to filter out duplicated elements - * @return a Iterable that filtered out all duplicated elements - * @note does not support toLongArray optimizations. - */ - default LongIterable distinct() { - return LongIterables.distinct(this); - } - - /** - * A Helper function to reduce the usage of Streams and allows to repeat elements a desired amount of times - * @param repeats how many times the elements should be repeated - * @return a Iterable that is repeating multiple times - */ - default LongIterable repeat(int repeats) { - return LongIterables.repeat(this, repeats); - } - - /** - * A Helper function to reduce the usage of Streams and allows to limit the amount of elements - * @param limit the amount of elements it should be limited to - * @return a Iterable that is limited in length - */ - default LongIterable limit(long limit) { - return LongIterables.limit(this, limit); - } - - /** - * A Helper function to reduce the usage of Streams and allows to sort the elements - * @param sorter that sorts the elements. - * @return a Iterable that is sorted - */ - default LongIterable sorted(LongComparator sorter) { - return LongIterables.sorted(this, sorter); - } - - /** - * A Helper function to reduce the usage of Streams and allows to preview elements before they are iterated through - * @param action the action that should be applied - * @return a Peeked Iterable - */ - default LongIterable peek(LongConsumer action) { - return LongIterables.peek(this, action); - } - - /** - * A Helper function to reduce the usage of Streams and allows to collect all elements - * @param collection that the elements should be inserted to - * @param the collection type - * @return the input with the desired elements - */ - default E pour(E collection) { - LongIterators.pour(iterator(), collection); - return collection; - } - - - /** - * A Helper function that reduces the usage of streams and allows to collect all elements as a Array - * @return a new Array of all elements - */ - default long[] toLongArray() { - ISizeProvider prov = ISizeProvider.of(this); - if(prov != null) { - int size = prov.size(); - if(size >= 0) { - long[] array = new long[size]; - LongIterators.unwrap(array, iterator()); - return array; - } - } - return LongArrays.pour(iterator()); - } - - /** - * Helper function to reduce stream usage that allows to filter for any matches. - * @param filter that should be applied - * @return true if any matches were found - */ - default boolean matchesAny(LongPredicate filter) { - Objects.requireNonNull(filter); - for(LongIterator iter = iterator();iter.hasNext();) { - if(filter.test(iter.nextLong())) return true; - } - return false; - } - - /** - * Helper function to reduce stream usage that allows to filter for no matches. - * @param filter that should be applied - * @return true if no matches were found - */ - default boolean matchesNone(LongPredicate filter) { - Objects.requireNonNull(filter); - for(LongIterator iter = iterator();iter.hasNext();) { - if(filter.test(iter.nextLong())) return false; - } - return true; - } - - /** - * Helper function to reduce stream usage that allows to filter for all matches. - * @param filter that should be applied - * @return true if all matches. - */ - default boolean matchesAll(LongPredicate filter) { - Objects.requireNonNull(filter); - for(LongIterator iter = iterator();iter.hasNext();) { - if(!filter.test(iter.nextLong())) return false; - } - return true; - } - - /** - * Helper function to reduce stream usage that allows to filter for the first match. - * @param filter that should be applied - * @return the found value or the null equivalent variant. - */ - default long findFirst(LongPredicate filter) { - Objects.requireNonNull(filter); - for(LongIterator iter = iterator();iter.hasNext();) { - long entry = iter.nextLong(); - if(filter.test(entry)) return entry; - } - return 0L; - } - - /** - * Performs a reduction on the - * elements of this Iterable - * @param operator the operation that should be applied - * @param identity the start value - * @return the reduction result, returns identity if nothing was found - */ - default long reduce(long identity, LongLongUnaryOperator operator) { - Objects.requireNonNull(operator); - long state = identity; - for(LongIterator iter = iterator();iter.hasNext();) { - state = operator.applyAsLong(state, iter.nextLong()); - } - return state; - } - - /** - * Performs a reduction on the - * elements of this Iterable - * @param operator the operation that should be applied - * @return the reduction result, returns null value if nothing was found - */ - default long reduce(LongLongUnaryOperator operator) { - Objects.requireNonNull(operator); - long state = 0L; - boolean empty = true; - for(LongIterator iter = iterator();iter.hasNext();) { - if(empty) { - empty = false; - state = iter.nextLong(); - continue; - } - state = operator.applyAsLong(state, iter.nextLong()); - } - return state; - } - - /** - * Helper function to reduce stream usage that allows to count the valid elements. - * @param filter that should be applied - * @return the amount of Valid Elements - */ - default int count(LongPredicate filter) { - Objects.requireNonNull(filter); - int result = 0; - for(LongIterator iter = iterator();iter.hasNext();) { - if(filter.test(iter.nextLong())) result++; - } - return result; - } -} diff --git a/src/main/java/speiger/src/collections/longs/collections/LongIterator.java b/src/main/java/speiger/src/collections/longs/collections/LongIterator.java deleted file mode 100644 index 1f19934b2..000000000 --- a/src/main/java/speiger/src/collections/longs/collections/LongIterator.java +++ /dev/null @@ -1,88 +0,0 @@ -package speiger.src.collections.longs.collections; - -import java.util.Iterator; -import java.util.Objects; -import java.util.function.Consumer; - -import speiger.src.collections.longs.functions.LongConsumer; - -import speiger.src.collections.objects.functions.consumer.ObjectLongConsumer; - -/** - * A Type-Specific {@link Iterator} that reduces (un)boxing - */ -public interface LongIterator extends Iterator -{ - /** - * Returns the next element in the iteration. - * - * @return the next element in the iteration - * @throws java.util.NoSuchElementException if the iteration has no more elements - * @see Iterator#next() - */ - public long nextLong(); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default Long next() { return Long.valueOf(nextLong()); } - - /** - * Performs the given action for each remaining element until all elements - * have been processed or the action throws an exception. Actions are - * performed in the order of iteration, if that order is specified. - * Exceptions thrown by the action are relayed to the caller. - * - * @implSpec - *

The default implementation behaves as if: - *

{@code
-	 *	while (hasNext()) action.accept(nextLong());
-	 * }
- * - * @param action The action to be performed for each element - * @throws NullPointerException if the specified action is null - * @see Iterator#forEachRemaining(Consumer) - */ - public default void forEachRemaining(LongConsumer action) { - Objects.requireNonNull(action); - while(hasNext()) { action.accept(nextLong()); } - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Deprecated - @Override - default void forEachRemaining(Consumer action) { - Objects.requireNonNull(action); - forEachRemaining(action::accept); - } - - /** - * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. - * @param input the object that should be included - * @param action The action to be performed for each element - * @param the generic type of the Object - * @throws NullPointerException if the specified action is null - */ - default void forEachRemaining(E input, ObjectLongConsumer action) { - Objects.requireNonNull(action); - while(hasNext()) { action.accept(input, nextLong()); } - } - - /** - * Skips the Given amount of elements if possible. A Optimization function to skip elements faster if the implementation allows it. - * @param amount the amount of elements that should be skipped - * @return the amount of elements that were skipped - */ - default int skip(int amount) { - if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); - int i = 0; - for(;i, LongIterator -{ - @Override - default void forEachRemaining(LongConsumer action) { LongIterator.super.forEachRemaining(action); } - @Override - @Deprecated - default void forEachRemaining(Consumer action) { LongIterator.super.forEachRemaining(action); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/collections/LongStack.java b/src/main/java/speiger/src/collections/longs/collections/LongStack.java deleted file mode 100644 index 47feba4cc..000000000 --- a/src/main/java/speiger/src/collections/longs/collections/LongStack.java +++ /dev/null @@ -1,62 +0,0 @@ -package speiger.src.collections.longs.collections; - -import speiger.src.collections.utils.Stack; - -/** - * A Type-Specific {@link Stack} that reduces (un)boxing - */ -public interface LongStack -{ - /** - * Inserts a given Object on top of the stack - * @param e the Object to insert - * @see Stack#push(Object) - */ - public void push(long e); - - /** - * Removes the Object on top of the stack. - * @return the element that is on top of the stack - * @throws ArrayIndexOutOfBoundsException if the stack is empty - * @see Stack#pop() - */ - public long pop(); - - /** - * Provides the Object on top of the stack - * @return the element that is on top of the stack - * @throws ArrayIndexOutOfBoundsException if the stack is empty - * @see Stack#top() - */ - public default long top() { - return peek(0); - } - - /** - * Provides the Selected Object from the stack. - * Top to bottom - * @param index of the element that should be provided - * @return the element that was requested - * @throws ArrayIndexOutOfBoundsException if the index is out of bounds - * @see Stack#peek(int) - */ - public long peek(int index); - - /** - * Clears the stack - */ - public void clear(); - - /** - * Provides the amount of elements currently in the stack - * @return amount of elements in the list - */ - public int size(); - - /** - * @return if the stack is empty - */ - public default boolean isEmpty() { - return size() == 0; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/LongComparator.java b/src/main/java/speiger/src/collections/longs/functions/LongComparator.java deleted file mode 100644 index 5d41f4d8b..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/LongComparator.java +++ /dev/null @@ -1,70 +0,0 @@ -package speiger.src.collections.longs.functions; - -import java.util.Comparator; -import java.util.Objects; - -/** - * Type-Specific Class for Comparator to reduce (un)boxing - */ -public interface LongComparator extends Comparator -{ - /** - * Type-Specific compare function to reduce (un)boxing - * @param o1 the first object to be compared. - * @param o2 the second object to be compared. - * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. - * @see Comparator#compare(Object, Object) - */ - int compare(long o1, long o2); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default int compare(Long o1, Long o2) { - return compare(o1.longValue(), o2.longValue()); - } - - /** - * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator - * @param c comparator to convert - * @return the wrapper of the comparator - * @throws NullPointerException if the comparator is null - */ - public static LongComparator of(Comparator c) { - Objects.requireNonNull(c); - return (K, V) -> c.compare(Long.valueOf(K), Long.valueOf(V)); - } - - @Override - public default LongComparator reversed() { - return new Reversed(this); - } - - /** - * A Type Specific Reversed Comparator to reduce boxing/unboxing - */ - static class Reversed implements LongComparator - { - LongComparator original; - - /** - * default constructor - * @param original that is going to be reversed - */ - public Reversed(LongComparator original) { - this.original = original; - } - - public int compare(long o1, long o2) { - return original.compare(o2, o1); - } - - @Override - public LongComparator reversed() { - return original; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/LongConsumer.java b/src/main/java/speiger/src/collections/longs/functions/LongConsumer.java deleted file mode 100644 index f4772ad26..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/LongConsumer.java +++ /dev/null @@ -1,59 +0,0 @@ -package speiger.src.collections.longs.functions; - -import java.util.Objects; -import java.util.function.Consumer; -/** - * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -@FunctionalInterface -public interface LongConsumer extends Consumer, java.util.function.LongConsumer -{ - /** - * Type-Specific function to reduce (un)boxing. - * Performs this operation on the given argument. - * - * @param t the input argument - */ - void accept(long t); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced consumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default LongConsumer andThen(LongConsumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(T);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Long t) { accept(t.longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default LongConsumer andThen(Consumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(Long.valueOf(T));}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default LongConsumer andThen(java.util.function.LongConsumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(T);}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/LongSupplier.java b/src/main/java/speiger/src/collections/longs/functions/LongSupplier.java deleted file mode 100644 index 224b391e2..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/LongSupplier.java +++ /dev/null @@ -1,12 +0,0 @@ -package speiger.src.collections.longs.functions; - -/** - * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -public interface LongSupplier extends java.util.function.LongSupplier -{ - /** - * @return the supplied value - */ - public long getAsLong(); -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongBooleanConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongBooleanConsumer.java deleted file mode 100644 index 1bca0ed2c..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/consumer/LongBooleanConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.longs.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface LongBooleanConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(long k, boolean v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default LongBooleanConsumer andThen(LongBooleanConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Long k, Boolean v) { accept(k.longValue(), v.booleanValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default LongBooleanConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Boolean.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongByteConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongByteConsumer.java deleted file mode 100644 index 01ae96c13..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/consumer/LongByteConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.longs.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface LongByteConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(long k, byte v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default LongByteConsumer andThen(LongByteConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Long k, Byte v) { accept(k.longValue(), v.byteValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default LongByteConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Byte.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongCharConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongCharConsumer.java deleted file mode 100644 index b312c0451..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/consumer/LongCharConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.longs.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface LongCharConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(long k, char v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default LongCharConsumer andThen(LongCharConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Long k, Character v) { accept(k.longValue(), v.charValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default LongCharConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Character.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongDoubleConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongDoubleConsumer.java deleted file mode 100644 index c00a09d39..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/consumer/LongDoubleConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.longs.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface LongDoubleConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(long k, double v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default LongDoubleConsumer andThen(LongDoubleConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Long k, Double v) { accept(k.longValue(), v.doubleValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default LongDoubleConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Double.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongFloatConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongFloatConsumer.java deleted file mode 100644 index fc6d1f454..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/consumer/LongFloatConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.longs.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface LongFloatConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(long k, float v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default LongFloatConsumer andThen(LongFloatConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Long k, Float v) { accept(k.longValue(), v.floatValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default LongFloatConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Float.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongIntConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongIntConsumer.java deleted file mode 100644 index f3a72ef27..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/consumer/LongIntConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.longs.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface LongIntConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(long k, int v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default LongIntConsumer andThen(LongIntConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Long k, Integer v) { accept(k.longValue(), v.intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default LongIntConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Integer.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongLongConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongLongConsumer.java deleted file mode 100644 index efd2d5808..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/consumer/LongLongConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.longs.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface LongLongConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(long k, long v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default LongLongConsumer andThen(LongLongConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Long k, Long v) { accept(k.longValue(), v.longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default LongLongConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Long.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongObjectConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongObjectConsumer.java deleted file mode 100644 index 756a34d76..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/consumer/LongObjectConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.longs.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface LongObjectConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(long k, V v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default LongObjectConsumer andThen(LongObjectConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Long k, V v) { accept(k.longValue(), v); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default LongObjectConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), V);}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/consumer/LongShortConsumer.java b/src/main/java/speiger/src/collections/longs/functions/consumer/LongShortConsumer.java deleted file mode 100644 index 2ed74ccb9..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/consumer/LongShortConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.longs.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface LongShortConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(long k, short v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default LongShortConsumer andThen(LongShortConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Long k, Short v) { accept(k.longValue(), v.shortValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default LongShortConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Long.valueOf(K), Short.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2ByteFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2ByteFunction.java deleted file mode 100644 index c4ea52d4d..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/Long2ByteFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.longs.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Long2ByteFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public byte applyAsByte(long k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2CharFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2CharFunction.java deleted file mode 100644 index 43ecd9821..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/Long2CharFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.longs.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Long2CharFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public char applyAsChar(long k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2DoubleFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2DoubleFunction.java deleted file mode 100644 index c860ab5cb..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/Long2DoubleFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.longs.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Long2DoubleFunction extends java.util.function.LongToDoubleFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public double applyAsDouble(long k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2FloatFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2FloatFunction.java deleted file mode 100644 index 15e07cefa..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/Long2FloatFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.longs.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Long2FloatFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public float applyAsFloat(long k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2IntFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2IntFunction.java deleted file mode 100644 index c1b2bdddd..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/Long2IntFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.longs.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Long2IntFunction extends java.util.function.LongToIntFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public int applyAsInt(long k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/Long2ShortFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/Long2ShortFunction.java deleted file mode 100644 index deb4e53cb..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/Long2ShortFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.longs.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Long2ShortFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public short applyAsShort(long k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongBooleanUnaryOperator.java deleted file mode 100644 index f5a30815a..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongBooleanUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.longs.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface LongBooleanUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public boolean applyAsBoolean(long k, boolean v); - - @Override - public default Boolean apply(Long k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.longValue(), v.booleanValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongByteUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongByteUnaryOperator.java deleted file mode 100644 index dd49dda5d..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongByteUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.longs.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface LongByteUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public byte applyAsByte(long k, byte v); - - @Override - public default Byte apply(Long k, Byte v) { return Byte.valueOf(applyAsByte(k.longValue(), v.byteValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongCharUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongCharUnaryOperator.java deleted file mode 100644 index b55597ae8..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongCharUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.longs.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface LongCharUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public char applyAsChar(long k, char v); - - @Override - public default Character apply(Long k, Character v) { return Character.valueOf(applyAsChar(k.longValue(), v.charValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongDoubleUnaryOperator.java deleted file mode 100644 index e558e3533..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongDoubleUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.longs.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface LongDoubleUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public double applyAsDouble(long k, double v); - - @Override - public default Double apply(Long k, Double v) { return Double.valueOf(applyAsDouble(k.longValue(), v.doubleValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongFloatUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongFloatUnaryOperator.java deleted file mode 100644 index 49c1edd88..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongFloatUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.longs.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface LongFloatUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public float applyAsFloat(long k, float v); - - @Override - public default Float apply(Long k, Float v) { return Float.valueOf(applyAsFloat(k.longValue(), v.floatValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongFunction.java b/src/main/java/speiger/src/collections/longs/functions/function/LongFunction.java deleted file mode 100644 index 959749882..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.longs.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface LongFunction extends java.util.function.LongFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public V apply(long k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongIntUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongIntUnaryOperator.java deleted file mode 100644 index 986b7037b..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongIntUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.longs.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface LongIntUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public int applyAsInt(long k, int v); - - @Override - public default Integer apply(Long k, Integer v) { return Integer.valueOf(applyAsInt(k.longValue(), v.intValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongLongUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongLongUnaryOperator.java deleted file mode 100644 index f0a35c2b9..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongLongUnaryOperator.java +++ /dev/null @@ -1,13 +0,0 @@ -package speiger.src.collections.longs.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ - -public interface LongLongUnaryOperator extends BiFunction, java.util.function.LongBinaryOperator -{ - @Override - public default Long apply(Long k, Long v) { return Long.valueOf(applyAsLong(k.longValue(), v.longValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongObjectUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongObjectUnaryOperator.java deleted file mode 100644 index 16d522964..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongObjectUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.longs.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface LongObjectUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public V apply(long k, V v); - - @Override - public default V apply(Long k, V v) { return apply(k.longValue(), v); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongPredicate.java b/src/main/java/speiger/src/collections/longs/functions/function/LongPredicate.java deleted file mode 100644 index 2fd7fcbde..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongPredicate.java +++ /dev/null @@ -1,72 +0,0 @@ -package speiger.src.collections.longs.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface LongPredicate extends java.util.function.LongPredicate -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public boolean test(long k); - - /** - * Creates a Always true function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static LongPredicate alwaysTrue() { - return T -> true; - } - - /** - * Creates a Always false function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static LongPredicate alwaysFalse() { - return T -> false; - } - - /** - * A Type specific and-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a and comparason - */ - public default LongPredicate andType(LongPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - @Override - @Deprecated - public default LongPredicate and(java.util.function.LongPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - @Override - public default LongPredicate negate() { - return T -> !test(T); - } - - /** - * A Type specific or-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a or comparason - */ - public default LongPredicate orType(LongPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } - - @Override - @Deprecated - public default LongPredicate or(java.util.function.LongPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongShortUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongShortUnaryOperator.java deleted file mode 100644 index d1d81cf8d..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongShortUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.longs.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface LongShortUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public short applyAsShort(long k, short v); - - @Override - public default Short apply(Long k, Short v) { return Short.valueOf(applyAsShort(k.longValue(), v.shortValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/functions/function/LongUnaryOperator.java b/src/main/java/speiger/src/collections/longs/functions/function/LongUnaryOperator.java deleted file mode 100644 index 5e74927a2..000000000 --- a/src/main/java/speiger/src/collections/longs/functions/function/LongUnaryOperator.java +++ /dev/null @@ -1,54 +0,0 @@ -package speiger.src.collections.longs.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface LongUnaryOperator extends java.util.function.LongUnaryOperator -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public long applyAsLong(long k); - - /** - * Creates a Default function that returns the input provided. - * @return a input returning function - */ - public static LongUnaryOperator identity() { - return T -> T; - } - - /** - * Returns a composed function that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param before the function that should be used first - * @return a composed function with a different starting function. - */ - public default LongUnaryOperator compose(LongUnaryOperator before) { - Objects.requireNonNull(before); - return T -> applyAsLong(before.applyAsLong(T)); - } - - /** - * Returns a composed function that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param after the function that should be used last - * @return a composed function with a different starting function. - */ - public default LongUnaryOperator andThen(LongUnaryOperator after) { - Objects.requireNonNull(after); - return T -> after.applyAsLong(applyAsLong(T)); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/lists/LongListIterator.java b/src/main/java/speiger/src/collections/longs/lists/LongListIterator.java deleted file mode 100644 index 7076dc998..000000000 --- a/src/main/java/speiger/src/collections/longs/lists/LongListIterator.java +++ /dev/null @@ -1,65 +0,0 @@ -package speiger.src.collections.longs.lists; - -import java.util.ListIterator; - -import speiger.src.collections.longs.collections.LongBidirectionalIterator; - -/** - * A Type Specific ListIterator that reduces boxing/unboxing - */ -public interface LongListIterator extends ListIterator, LongBidirectionalIterator -{ - /** - * A Primitive set function to reduce (un)boxing - * @param e the element that should replace the last returned value - * @see ListIterator#set(Object) - */ - public void set(long e); - - /** - * A Primitive set function to reduce (un)boxing - * @param e the element that should be inserted before the last returned value - * @see ListIterator#set(Object) - */ - public void add(long e); - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default Long previous() { - return LongBidirectionalIterator.super.previous(); - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default Long next() { - return LongBidirectionalIterator.super.next(); - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default void set(Long e) { - set(e.longValue()); - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public default void add(Long e) { - add(e.longValue()); - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/sets/AbstractLongSet.java b/src/main/java/speiger/src/collections/longs/sets/AbstractLongSet.java deleted file mode 100644 index 22c4ff1ae..000000000 --- a/src/main/java/speiger/src/collections/longs/sets/AbstractLongSet.java +++ /dev/null @@ -1,41 +0,0 @@ -package speiger.src.collections.longs.sets; - -import java.util.Set; - -import speiger.src.collections.longs.collections.AbstractLongCollection; -import speiger.src.collections.longs.collections.LongIterator; - -/** - * Abstract Type Specific Set that reduces boxing/unboxing - */ -public abstract class AbstractLongSet extends AbstractLongCollection implements LongSet -{ - @Override - public abstract LongIterator iterator(); - @Override - public AbstractLongSet copy() { throw new UnsupportedOperationException(); } - - @Override - public int hashCode() { - int hashCode = 0; - LongIterator i = iterator(); - while(i.hasNext()) - hashCode += Long.hashCode(i.nextLong()); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (o == this) - return true; - if (!(o instanceof Set)) - return false; - Set l = (Set)o; - if(l.size() != size()) return false; - try { - return containsAll(l); - } catch (ClassCastException | NullPointerException unused) { - return false; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/sets/LongOpenHashSet.java b/src/main/java/speiger/src/collections/longs/sets/LongOpenHashSet.java deleted file mode 100644 index 12f0307cf..000000000 --- a/src/main/java/speiger/src/collections/longs/sets/LongOpenHashSet.java +++ /dev/null @@ -1,635 +0,0 @@ -package speiger.src.collections.longs.sets; - -import java.util.Arrays; -import java.util.Collection; -import java.util.ConcurrentModificationException; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.function.LongPredicate; - -import speiger.src.collections.longs.collections.LongCollection; -import speiger.src.collections.longs.collections.LongIterator; -import speiger.src.collections.longs.utils.LongIterators; -import speiger.src.collections.longs.functions.LongConsumer; -import speiger.src.collections.ints.functions.consumer.IntLongConsumer; -import speiger.src.collections.objects.functions.consumer.ObjectLongConsumer; -import speiger.src.collections.longs.functions.function.LongLongUnaryOperator; -import speiger.src.collections.utils.HashUtil; -import speiger.src.collections.utils.ITrimmable; -import speiger.src.collections.utils.SanityChecks; - -/** - * A Type Specific Custom implementation of the HashSet - * Instead of using Wrapper Object Arrays for storing keys and values there is dedicated arrays for storing keys. - * Extra to that there is a couple quality of life functions provided - */ -public class LongOpenHashSet extends AbstractLongSet implements ITrimmable -{ - /** The Backing keys array */ - protected transient long[] keys; - /** If a null value is present */ - protected transient boolean containsNull; - /** Minimum array size the HashSet will be */ - protected transient int minCapacity; - /** Index of the Null Value */ - protected transient int nullIndex; - /** Maximum amount of Values that can be stored before the array gets expanded usually 75% */ - protected transient int maxFill; - /** Max Index that is allowed to be searched through nullIndex - 1 */ - protected transient int mask; - - /** Amount of Elements stored in the HashSet */ - protected int size; - /** How full the Array is allowed to get before resize */ - protected final float loadFactor; - - /** - * Default Constructor - */ - public LongOpenHashSet() { - this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR); - } - - /** - * Constructor that defines the minimum capacity - * @param minCapacity the minimum capacity the HashSet is allowed to be. - * @throws IllegalStateException if the minimum capacity is negative - */ - public LongOpenHashSet(int minCapacity) { - this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR); - } - - /** - * Constructor that defines the minimum capacity and load factor - * @param minCapacity the minimum capacity the HashSet is allowed to be. - * @param loadFactor the percentage of how full the backing array can be before they resize - * @throws IllegalStateException if the minimum capacity is negative - * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 - */ - public LongOpenHashSet(int minCapacity, float loadFactor) { - if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); - if(loadFactor <= 0 || loadFactor >= 1F) throw new IllegalStateException("Load Factor is not between 0 and 1"); - this.loadFactor = loadFactor; - this.minCapacity = nullIndex = HashUtil.arraySize(minCapacity, loadFactor); - mask = nullIndex - 1; - maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); - keys = new long[nullIndex + 1]; - } - - /** - * Helper constructor that allow to create a set from unboxed values - * @param array the elements that should be put into the set - */ - public LongOpenHashSet(long[] array) { - this(array, 0, array.length, HashUtil.DEFAULT_LOAD_FACTOR); - } - - /** - * Helper constructor that allow to create a set from unboxed values - * @param array the elements that should be put into the set - * @param loadFactor the percentage of how full the backing array can be before they resize - * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 - */ - public LongOpenHashSet(long[] array, float loadFactor) { - this(array, 0, array.length, loadFactor); - } - - /** - * Helper constructor that allow to create a set from unboxed values - * @param array the elements that should be put into the set - * @param offset the starting index within the array that should be used - * @param length the amount of elements used from the array - * @throws IllegalStateException if offset and length causes to step outside of the arrays range - */ - public LongOpenHashSet(long[] array, int offset, int length) { - this(array, offset, length, HashUtil.DEFAULT_LOAD_FACTOR); - } - - /** - * Helper constructor that allow to create a set from unboxed values - * @param array the elements that should be put into the set - * @param offset the starting index within the array that should be used - * @param length the amount of elements used from the array - * @param loadFactor the percentage of how full the backing array can be before they resize - * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 - * @throws IllegalStateException if offset and length causes to step outside of the arrays range - */ - public LongOpenHashSet(long[] array, int offset, int length, float loadFactor) { - this(length < 0 ? 0 : length); - SanityChecks.checkArrayCapacity(array.length, offset, length); - for(int i = 0;i collection) { - this(collection, HashUtil.DEFAULT_LOAD_FACTOR); - } - - /** - * A Helper constructor that allows to create a Set with exactly the same values as the provided collection. - * @param collection the set the elements should be added to the Set - * @param loadFactor the percentage of how full the backing array can be before they resize - * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 - */ - @Deprecated - public LongOpenHashSet(Collection collection, float loadFactor) { - this(collection.size(), loadFactor); - addAll(collection); - } - - /** - * A Helper constructor that allows to create a Set with exactly the same values as the provided collection. - * @param collection the set the elements should be added to the Set - */ - public LongOpenHashSet(LongCollection collection) { - this(collection, HashUtil.DEFAULT_LOAD_FACTOR); - } - - /** - * A Helper constructor that allows to create a Set with exactly the same values as the provided collection. - * @param collection the set the elements should be added to the Set - * @param loadFactor the percentage of how full the backing array can be before they resize - * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 - */ - public LongOpenHashSet(LongCollection collection, float loadFactor) { - this(collection.size()); - addAll(collection); - } - - /** - * A Helper constructor that allows to create a set from a iterator of an unknown size - * @param iterator the elements that should be added to the set - */ - public LongOpenHashSet(Iterator iterator) { - this(iterator, HashUtil.DEFAULT_LOAD_FACTOR); - } - - /** - * A Helper constructor that allows to create a set from a iterator of an unknown size - * @param iterator the elements that should be added to the set - * @param loadFactor the percentage of how full the backing array can be before they resize - * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 - */ - public LongOpenHashSet(Iterator iterator, float loadFactor) { - this(LongIterators.wrap(iterator), loadFactor); - } - - /** - * A Helper constructor that allows to create a set from a iterator of an unknown size - * @param iterator the elements that should be added to the set - */ - public LongOpenHashSet(LongIterator iterator) { - this(iterator, HashUtil.DEFAULT_LOAD_FACTOR); - } - - /** - * A Helper constructor that allows to create a set from a iterator of an unknown size - * @param iterator the elements that should be added to the set - * @param loadFactor the percentage of how full the backing array can be before they resize - * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 - */ - public LongOpenHashSet(LongIterator iterator, float loadFactor) { - this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor); - while(iterator.hasNext()) add(iterator.nextLong()); - } - - @Override - public boolean add(long o) { - if(o == 0) { - if(containsNull) return false; - containsNull = true; - onNodeAdded(nullIndex); - } - else { - int pos = HashUtil.mix(Long.hashCode(o)) & mask; - long current = keys[pos]; - if(current != 0) { - if(current == o) return false; - while((current = keys[pos = (++pos & mask)]) != 0) - if(current == o) return false; - } - keys[pos] = o; - onNodeAdded(pos); - } - if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor)); - return true; - } - - @Override - @Deprecated - public boolean addAll(Collection c) { - if(loadFactor <= 0.5F) ensureCapacity(c.size()); - else ensureCapacity(c.size() + size()); - return super.addAll(c); - } - - @Override - public boolean addAll(LongCollection c) { - if(loadFactor <= 0.5F) ensureCapacity(c.size()); - else ensureCapacity(c.size() + size()); - return super.addAll(c); - } - - @Override - public boolean contains(Object o) { - if(o == null) return false; - if(o instanceof Long && ((Long)o).longValue() == 0L) return containsNull; - int pos = HashUtil.mix(o.hashCode()) & mask; - long current = keys[pos]; - if(current == 0) return false; - if(Objects.equals(o, Long.valueOf(current))) return true; - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(Objects.equals(o, Long.valueOf(current))) return true; - } - } - - @Override - public boolean remove(Object o) { - if(o == null) return false; - if(o instanceof Long && ((Long)o).longValue() == 0L) return (containsNull ? removeNullIndex() : false); - int pos = HashUtil.mix(o.hashCode()) & mask; - long current = keys[pos]; - if(current == 0) return false; - if(Objects.equals(o, Long.valueOf(current))) return removeIndex(pos); - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(Objects.equals(o, Long.valueOf(current))) return removeIndex(pos); - } - } - - @Override - public boolean contains(long o) { - if(o == 0) return containsNull; - int pos = HashUtil.mix(Long.hashCode(o)) & mask; - long current = keys[pos]; - if(current == 0) return false; - if(current == o) return true; - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(current == o) return true; - } - } - - @Override - public boolean remove(long o) { - if(o == 0) return containsNull ? removeNullIndex() : false; - int pos = HashUtil.mix(Long.hashCode(o)) & mask; - long current = keys[pos]; - if(current == 0) return false; - if(current == o) return removeIndex(pos); - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(current == o) return removeIndex(pos); - } - } - - @Override - public boolean trim(int size) { - int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor))); - if(request >= nullIndex || this.size >= Math.min((int)Math.ceil(request * loadFactor), request - 1)) return false; - try { - rehash(request); - } - catch(OutOfMemoryError e) { return false; } - return true; - } - - @Override - public void clearAndTrim(int size) { - int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor))); - if(request >= nullIndex) { - clear(); - return; - } - nullIndex = request; - mask = request-1; - maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); - keys = new long[request + 1]; - this.size = 0; - containsNull = false; - } - - @Override - public void forEach(LongConsumer action) { - if(size() <= 0) return; - if(containsNull) action.accept(keys[nullIndex]); - for(int i = nullIndex-1;i>=0;i--) { - if(keys[i] != 0) action.accept(keys[i]); - } - } - - @Override - public void forEachIndexed(IntLongConsumer action) { - Objects.requireNonNull(action); - if(size() <= 0) return; - if(containsNull) action.accept(0, keys[nullIndex]); - for(int i = nullIndex-1, index = containsNull ? 1 : 0;i>=0;i--) { - if(keys[i] != 0) action.accept(index++, keys[i]); - } - } - - @Override - public void forEach(E input, ObjectLongConsumer action) { - Objects.requireNonNull(action); - if(size() <= 0) return; - if(containsNull) action.accept(input, keys[nullIndex]); - for(int i = nullIndex-1;i>=0;i--) { - if(keys[i] != 0) action.accept(input, keys[i]); - } - } - - @Override - public boolean matchesAny(LongPredicate filter) { - Objects.requireNonNull(filter); - if(size() <= 0) return false; - if(containsNull && filter.test(keys[nullIndex])) return true; - for(int i = nullIndex-1;i>=0;i--) { - if(keys[i] != 0 && filter.test(keys[i])) return true; - } - return false; - } - - @Override - public boolean matchesNone(LongPredicate filter) { - Objects.requireNonNull(filter); - if(size() <= 0) return true; - if(containsNull && filter.test(keys[nullIndex])) return false; - for(int i = nullIndex-1;i>=0;i--) { - if(keys[i] != 0 && filter.test(keys[i])) return false; - } - return true; - } - - @Override - public boolean matchesAll(LongPredicate filter) { - Objects.requireNonNull(filter); - if(size() <= 0) return true; - if(containsNull && !filter.test(keys[nullIndex])) return false; - for(int i = nullIndex-1;i>=0;i--) { - if(keys[i] != 0 && !filter.test(keys[i])) return false; - } - return true; - } - - @Override - public long reduce(long identity, LongLongUnaryOperator operator) { - Objects.requireNonNull(operator); - long state = identity; - if(containsNull) state = operator.applyAsLong(state, keys[nullIndex]); - for(int i = nullIndex-1;i>=0;i--) { - if(keys[i] == 0) continue; - state = operator.applyAsLong(state, keys[i]); - } - return state; - } - - @Override - public long reduce(LongLongUnaryOperator operator) { - Objects.requireNonNull(operator); - long state = 0L; - boolean empty = true; - if(containsNull) { - state = keys[nullIndex]; - empty = false; - } - for(int i = nullIndex-1;i>=0;i--) { - if(keys[i] == 0) continue; - if(empty) { - empty = false; - state = keys[i]; - continue; - } - state = operator.applyAsLong(state, keys[i]); - } - return state; - } - - @Override - public long findFirst(LongPredicate filter) { - Objects.requireNonNull(filter); - if(size() <= 0) return 0L; - if(containsNull && filter.test(keys[nullIndex])) return keys[nullIndex]; - for(int i = nullIndex-1;i>=0;i--) { - if(keys[i] != 0 && filter.test(keys[i])) return keys[i]; - } - return 0L; - } - - @Override - public int count(LongPredicate filter) { - Objects.requireNonNull(filter); - if(size() <= 0) return 0; - int result = 0; - if(containsNull && filter.test(keys[nullIndex])) result++; - for(int i = nullIndex-1;i>=0;i--) { - if(keys[i] != 0 && filter.test(keys[i])) result++; - } - return result; - } - - private void ensureCapacity(int newCapacity) { - int size = HashUtil.arraySize(newCapacity, loadFactor); - if(size > nullIndex) rehash(size); - } - - protected boolean removeIndex(int pos) { - if(pos == nullIndex) return containsNull ? removeNullIndex() : false; - keys[pos] = 0L; - size--; - onNodeRemoved(pos); - shiftKeys(pos); - if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); - return true; - } - - protected boolean removeNullIndex() { - containsNull = false; - keys[nullIndex] = 0L; - size--; - onNodeRemoved(nullIndex); - if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); - return true; - } - - protected void onNodeAdded(int pos) { - - } - - protected void onNodeRemoved(int pos) { - - } - - protected void onNodeMoved(int from, int to) { - - } - - protected void shiftKeys(int startPos) { - int slot, last; - long current; - while(true) { - startPos = ((last = startPos) + 1) & mask; - while(true){ - if((current = keys[startPos]) == 0) { - keys[last] = 0L; - return; - } - slot = HashUtil.mix(Long.hashCode(current)) & mask; - if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; - startPos = ++startPos & mask; - } - keys[last] = current; - onNodeMoved(startPos, last); - } - } - - protected void rehash(int newSize) { - int newMask = newSize - 1; - long[] newKeys = new long[newSize + 1]; - for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) { - while(true) { - if(--i < 0) throw new ConcurrentModificationException("Set was modified during rehash"); - if(keys[i] != 0) break; - } - if(newKeys[pos = HashUtil.mix(Long.hashCode(keys[i])) & newMask] != 0) - while(newKeys[pos = (++pos & newMask)] != 0); - newKeys[pos] = keys[i]; - } - nullIndex = newSize; - mask = newMask; - maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); - keys = newKeys; - } - - @Override - public LongIterator iterator() { - return new SetIterator(); - } - - @Override - public LongOpenHashSet copy() { - LongOpenHashSet set = new LongOpenHashSet(0, loadFactor); - set.minCapacity = minCapacity; - set.mask = mask; - set.maxFill = maxFill; - set.nullIndex = nullIndex; - set.containsNull = containsNull; - set.size = size; - set.keys = Arrays.copyOf(keys, keys.length); - return set; - } - - @Override - public void clear() { - if(size == 0) return; - size = 0; - containsNull = false; - Arrays.fill(keys, 0L); - } - - @Override - public int size() { - return size; - } - - private class SetIterator implements LongIterator { - int pos = nullIndex; - int returnedPos = -1; - int lastReturned = -1; - int nextIndex = Integer.MIN_VALUE; - boolean returnNull = containsNull; - long[] wrapped = null; - int wrappedIndex = 0; - - @Override - public boolean hasNext() { - if(nextIndex == Integer.MIN_VALUE) { - if(returnNull) { - returnNull = false; - nextIndex = nullIndex; - } - else - { - while(true) { - if(--pos < 0) { - if(wrapped == null || wrappedIndex <= -pos - 1) break; - nextIndex = -pos - 1; - break; - } - if(keys[pos] != 0){ - nextIndex = pos; - break; - } - } - } - } - return nextIndex != Integer.MIN_VALUE; - } - - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - returnedPos = pos; - if(nextIndex < 0){ - lastReturned = Integer.MAX_VALUE; - long value = wrapped[nextIndex]; - nextIndex = Integer.MIN_VALUE; - return value; - } - long value = keys[(lastReturned = nextIndex)]; - nextIndex = Integer.MIN_VALUE; - return value; - } - - @Override - public void remove() { - if(lastReturned == -1) throw new IllegalStateException(); - if(lastReturned == nullIndex) { - containsNull = false; - keys[nullIndex] = 0L; - } - else if(returnedPos >= 0) shiftKeys(returnedPos); - else { - LongOpenHashSet.this.remove(wrapped[-returnedPos - 1]); - lastReturned = -1; - return; - } - size--; - lastReturned = -1; - } - - private void shiftKeys(int startPos) { - int slot, last; - long current; - while(true) { - startPos = ((last = startPos) + 1) & mask; - while(true){ - if((current = keys[startPos]) == 0) { - keys[last] = 0L; - return; - } - slot = HashUtil.mix(Long.hashCode(current)) & mask; - if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; - startPos = ++startPos & mask; - } - if(startPos < last) addWrapper(keys[startPos]); - keys[last] = current; - } - } - - private void addWrapper(long value) { - if(wrapped == null) wrapped = new long[2]; - else if(wrappedIndex >= wrapped.length) { - long[] newArray = new long[wrapped.length * 2]; - System.arraycopy(wrapped, 0, newArray, 0, wrapped.length); - wrapped = newArray; - } - wrapped[wrappedIndex++] = value; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/sets/LongSet.java b/src/main/java/speiger/src/collections/longs/sets/LongSet.java deleted file mode 100644 index aa17eb396..000000000 --- a/src/main/java/speiger/src/collections/longs/sets/LongSet.java +++ /dev/null @@ -1,58 +0,0 @@ -package speiger.src.collections.longs.sets; - -import java.util.Set; - -import speiger.src.collections.longs.collections.LongCollection; -import speiger.src.collections.longs.collections.LongIterator; -import speiger.src.collections.longs.collections.LongSplititerator; -import speiger.src.collections.longs.utils.LongSplititerators; - - -/** - * A Type Specific Set class to reduce boxing/unboxing - */ -public interface LongSet extends Set, LongCollection -{ - @Override - public LongIterator iterator(); - - @Override - public LongSet copy(); - - /** - * A Type Specific remove function to reduce boxing/unboxing - * @param o the element that should be removed - * @return true if the element was removed - */ - public boolean remove(long o); - - @Override - public default boolean remLong(long o) { - return remove(o); - } - - @Override - @Deprecated - public default boolean add(Long e) { - return LongCollection.super.add(e); - } - - @Override - @Deprecated - public default boolean contains(Object o) { - return LongCollection.super.contains(o); - } - - @Override - @Deprecated - public default boolean remove(Object o) { - return LongCollection.super.remove(o); - } - - /** - * A Type Specific Type Splititerator to reduce boxing/unboxing - * @return type specific splititerator - */ - @Override - default LongSplititerator spliterator() { return LongSplititerators.createSplititerator(this, 0); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/utils/LongArrays.java b/src/main/java/speiger/src/collections/longs/utils/LongArrays.java deleted file mode 100644 index 76432313f..000000000 --- a/src/main/java/speiger/src/collections/longs/utils/LongArrays.java +++ /dev/null @@ -1,1527 +0,0 @@ -package speiger.src.collections.longs.utils; - -import java.util.Arrays; -import java.util.Random; -import java.util.concurrent.RecursiveAction; - -import speiger.src.collections.longs.functions.LongComparator; -import speiger.src.collections.longs.collections.LongIterator; -import speiger.src.collections.longs.utils.LongIterators; -import speiger.src.collections.longs.utils.LongCollections; -import speiger.src.collections.utils.SanityChecks; - -/** - * A Helper class for Arrays - */ -public class LongArrays -{ - /** Default Limit for Insertion/Selection Sort */ - public static final int BASE_THRESHOLD = 16; - /** Default Threshold for Multithreaded Sorting Algorythm options*/ - public static final int PARALLEL_THRESHOLD = 8192; - - /** Empty Array Reference used for Uninitialized Collections */ - public static final long[] EMPTY_ARRAY = new long[0]; - - /** - * A Helper function to convert a Primitive Array to a Long Array. - * @param a the array that should be converted - * @return a Long Array of the input array. - */ - public static Long[] wrap(long[] a) { - return wrap(a, 0, a.length); - } - - /** - * A Helper function to convert a Primitive Array to a Long Array. - * @param a the array that should be converted - * @param length the maximum length that should be coverted - * @return a Long Array of the input array. - */ - public static Long[] wrap(long[] a, int length) { - return wrap(a, 0, length); - } - - /** - * A Helper function to convert a Primitive Array to a Long Array. - * @param a the array that should be converted - * @param offset the starting offset of the inputarray - * @param length the maximum length that should be coverted - * @return a Long Array of the input array. - */ - public static Long[] wrap(long[] a, int offset, int length) { - SanityChecks.checkArrayCapacity(a.length, offset, length); - Long[] result = new Long[length]; - for(int i = offset;i>> 1; - long value = data[index]; - if(comp != null) { - while(index < half) { - int child = (index << 1) + 1; - long childValue = data[child]; - int right = child+1; - if(right < size && comp.compare(data[right], childValue) < 0) childValue = data[child = right]; - if(comp.compare(value, childValue) <= 0) break; - data[index] = childValue; - index = child; - } - } - else { - while(index < half) { - int child = (index << 1) + 1; - long childValue = data[child]; - int right = child+1; - if(right < size && Long.compare(data[right], childValue) < 0) childValue = data[child = right]; - if(Long.compare(value, childValue) <= 0) break; - data[index] = childValue; - index = child; - } - } - data[index] = value; - return index; - } - - /** - * Method to sort a specific value into the heap. - * @param data the heap itself. - * @param index that should be heapified. - * @param comp the comparator to sort the heap. Can be null - * @return the index the element was shifted to - */ - public static int shiftUp(long[] data, int index, LongComparator comp) { - long value = data[index]; - if(comp != null) { - while(index > 0) { - int parent = (index - 1) >>> 1; - long parentValue = data[parent]; - if(comp.compare(value, parentValue) >= 0) break; - data[index] = parentValue; - index = parent; - } - } - else { - while(index > 0) { - int parent = (index - 1) >>> 1; - long parentValue = data[parent]; - if(Long.compare(value, parentValue) >= 0) break; - data[index] = parentValue; - index = parent; - } - } - data[index] = value; - return index; - } - - /** - * Helper function to create a Heap out of an array. - * @param data the array to heapify - * @param size the current size of elements within the array. - * @param comp the Comparator to sort the array. Can be null - * @return the input array - */ - public static long[] heapify(long[] data, int size, LongComparator comp) { - for(int i = (size >>> 1) - 1;i>=0;shiftDown(data, size, i--, comp)); - return data; - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @note This uses the SanityChecks#getRandom - * @return the provided sorted array - */ - public static long[] shuffle(long[] array) { - return shuffle(array, SanityChecks.getRandom()); - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @param length the length of the array - * @note This uses the SanityChecks#getRandom - * @return the provided sorted array - */ - public static long[] shuffle(long[] array, int length) { - return shuffle(array, 0, length, SanityChecks.getRandom()); - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @param offset the start array - * @param length the length of the array - * @note This uses the SanityChecks#getRandom - * @return the provided sorted array - */ - public static long[] shuffle(long[] array, int offset, int length) { - return shuffle(array, offset, length, SanityChecks.getRandom()); - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @param random the Random Number Generator that should be used for the shuffling - * @return the provided sorted array - */ - public static long[] shuffle(long[] array, Random random) { - for(int i = array.length-1; i>=0;i--) { - int p = random.nextInt(i + 1); - long t = array[i]; - array[i] = array[p]; - array[p] = t; - } - return array; - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @param length the length of the array - * @param random the Random Number Generator that should be used for the shuffling - * @return the provided sorted array - */ - public static long[] shuffle(long[] array, int length, Random random) { - return shuffle(array, 0, length, random); - } - - /** - * Simple Shuffle method for Arrays. - * @param array the elements that should be shuffled - * @param offset the start array - * @param length the length of the array - * @param random the Random Number Generator that should be used for the shuffling - * @return the provided sorted array - */ - public static long[] shuffle(long[] array, int offset, int length, Random random) { - for(int i = length-1; i>=0;i--) { - int p = offset + random.nextInt(i + 1); - long t = array[offset+i]; - array[offset+i] = array[p]; - array[p] = t; - } - return array; - } - - /** - * Simple Array Reversal method - * @param array the Array that should flip - * @return the provided array - */ - public static long[] reverse(long[] array) { - return reverse(array, 0, array.length); - } - - /** - * Simple Array Reversal method - * @param array the Array that should flip - * @param length the length of the array - * @return the provided array - */ - public static long[] reverse(long[] array, int length) { - return reverse(array, 0, length); - } - - /** - * Simple Array Reversal method - * @param array the Array that should flip - * @param length the length of the array - * @param offset the start of the array - * @return the provided array - */ - public static long[] reverse(long[] array, int offset, int length) { - for (int i = offset, mid = offset + length >> 1, j = offset + length - 1; i < mid; i++, j--) { - long temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array. - */ - public static long[] stableSort(long[] array, LongComparator comp) { - stableSort(array, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void stableSort(long[] array, int length, LongComparator comp) { - stableSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void stableSort(long[] array, int from, int to, LongComparator comp) { - mergeSort(array, null, from, to, comp); - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @return input array - */ - public static long[] stableSort(long[] array) { - stableSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void stableSort(long[] array, int length) { - stableSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Stable sort referres to Mergesort or Insertionsort - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void stableSort(long[] array, int from, int to) { - mergeSort(array, null, from, to); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array - */ - public static long[] unstableSort(long[] array, LongComparator comp) { - unstableSort(array, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void unstableSort(long[] array, int length, LongComparator comp) { - unstableSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void unstableSort(long[] array, int from, int to, LongComparator comp) { - quickSort(array, from, to, comp); - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @return input array - */ - public static long[] unstableSort(long[] array) { - unstableSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void unstableSort(long[] array, int length) { - unstableSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order, - * potentially dynamically choosing an appropriate algorithm given the type and size of the array. - * Unstable sort referres to QuickSort or SelectionSort - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void unstableSort(long[] array, int from, int to) { - quickSort(array, from, to); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array - */ - public static long[] insertionSort(long[] array, LongComparator comp) { - insertionSort(array, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void insertionSort(long[] array, int length, LongComparator comp) { - insertionSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort, - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void insertionSort(long[] array, int from, int to, LongComparator comp) { - for (int i = from+1;i= from && comp.compare(current, array[j]) < 0) { - array[j+1] = array[j--]; - } - array[j+1] = current; - } - } - - /** - * Sorts an array according to the natural ascending order using InsertionSort, - * @param array the array that needs to be sorted - * @return input array - */ - public static long[] insertionSort(long[] array) { - insertionSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order using InsertionSort, - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void insertionSort(long[] array, int length) { - insertionSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using InsertionSort, - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void insertionSort(long[] array, int from, int to) { - for (int i = from+1;i= from && Long.compare(current, array[j]) < 0) { - array[j+1] = array[j--]; - } - array[j+1] = current; - } - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array - */ - public static long[] selectionSort(long[] array, LongComparator comp) { - selectionSort(array, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void selectionSort(long[] array, int length, LongComparator comp) { - selectionSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort, - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void selectionSort(long[] array, int from, int to, LongComparator comp) { - for (int i = from; i < to; i++) { - long min = array[i]; - int minId = i; - for(int j = i+1; j < to; j++) { - if(comp.compare(array[j], min) < 0) { - min = array[j]; - minId = j; - } - } - long temp = array[i]; - array[i] = min; - array[minId] = temp; - } - } - - /** - * Sorts an array according to the natural ascending order using Selection Sort, - * @param array the array that needs to be sorted - * @return input array - */ - public static long[] selectionSort(long[] array) { - selectionSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order using Selection Sort, - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void selectionSort(long[] array, int length) { - selectionSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Selection Sort, - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void selectionSort(long[] array, int from, int to) { - for (int i = from; i < to; i++) { - long min = array[i]; - int minId = i; - for(int j = i+1; j < to; j++) { - if(Long.compare(array[j], min) < 0) { - min = array[j]; - minId = j; - } - } - long temp = array[i]; - array[i] = min; - array[minId] = temp; - } - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array - */ - public static long[] mergeSort(long[] array, LongComparator comp) { - mergeSort(array, null, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void mergeSort(long[] array, int length, LongComparator comp) { - mergeSort(array, null, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param supp the auxillary array that is used to simplify the sorting - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void mergeSort(long[] array, long[] supp, int from, int to, LongComparator comp) { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to, comp); - return; - } - if(supp == null) supp = Arrays.copyOf(array, to); - int mid = (from + to) >>> 1; - mergeSort(supp, array, from, mid, comp); - mergeSort(supp, array, mid, to, comp); - if(comp.compare(supp[mid - 1], supp[mid]) <= 0) - { - System.arraycopy(supp, from, array, from, to - from); - return; - } - for(int p = from, q = mid;from < to;from++) { - if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; - else array[from] = supp[q++]; - } - } - - /** - * Sorts an array according to the natural ascending order using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @return input array - */ - public static long[] mergeSort(long[] array) { - mergeSort(array, null, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void mergeSort(long[] array, int length) { - mergeSort(array, null, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param supp the auxillary array that is used to simplify the sorting - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void mergeSort(long[] array, long[] supp, int from, int to) { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to); - return; - } - if(supp == null) supp = Arrays.copyOf(array, to); - int mid = (from + to) >>> 1; - mergeSort(supp, array, from, mid); - mergeSort(supp, array, mid, to); - if(Long.compare(supp[mid - 1], supp[mid]) <= 0) - { - System.arraycopy(supp, from, array, from, to - from); - return; - } - for(int p = from, q = mid;from < to;from++) { - if(q >= to || p < mid && Long.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; - else array[from] = supp[q++]; - } - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using a Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(long[] array, LongComparator comp) { - parallelMergeSort(array, null, 0, array.length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(long[] array, int length, LongComparator comp) { - parallelMergeSort(array, null, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param supp the auxillary array that is used to simplify the sorting - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(long[] array, long[] supp, int from, int to, LongComparator comp) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new MergeSortActionComp(array, supp, from, to, comp)); - return; - } - mergeSort(array, supp, from, to, comp); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(long[] array) { - parallelMergeSort(array, null, 0, array.length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(long[] array, int length) { - parallelMergeSort(array, null, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Merge Sort, - * This implementation was copied from FastUtil with a couple custom optimizations - * @param array the array that needs to be sorted - * @param supp the auxillary array that is used to simplify the sorting - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMergeSort(long[] array, long[] supp, int from, int to) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new MergeSortAction(array, supp, from, to)); - return; - } - mergeSort(array, supp, from, to); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void memFreeMergeSort(long[] array, LongComparator comp) { - memFreeMergeSort(array, 0, array.length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void memFreeMergeSort(long[] array, int length, LongComparator comp) { - memFreeMergeSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void memFreeMergeSort(long[] array, int from, int to, LongComparator comp) { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to, comp); - return; - } - int mid = (from + to) >>> 1; - memFreeMergeSort(array, from, mid, comp); - memFreeMergeSort(array, mid, to, comp); - if(comp.compare(array[mid - 1], array[mid]) <= 0) - return; - for(int i = from, j = mid, compare;i < j && j < to;) { - if((compare = comp.compare(array[i], array[j])) < 0) - i++; - else if(compare == 0) swap(array, ++i, j); - else { - int k = j; - for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++); - if(j == k) { - swap(array, i++, j); - continue; - } - else if(j + 1 == k) { - long value = array[j]; - System.arraycopy(array, i, array, i+1, j - i); - array[i] = value; - i++; - j++; - continue; - } - long[] data = new long[k - j]; - System.arraycopy(array, j, data, 0, data.length); - System.arraycopy(array, i, array, i+data.length, j - i); - System.arraycopy(data, 0, array, i, data.length); - i+=data.length; - j+=data.length; - } - } - } - - /** - * Sorts an array according to the natural ascending order using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @return input array - */ - public static long[] memFreeMergeSort(long[] array) { - memFreeMergeSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void memFreeMergeSort(long[] array, int length) { - memFreeMergeSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void memFreeMergeSort(long[] array, int from, int to) { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to); - return; - } - int mid = (from + to) >>> 1; - memFreeMergeSort(array, from, mid); - memFreeMergeSort(array, mid, to); - if(Long.compare(array[mid - 1], array[mid]) <= 0) - return; - for(int i = from, j = mid, comp;i < j && j < to;) { - if((comp = Long.compare(array[i], array[j])) < 0) - i++; - else if(comp == 0) swap(array, ++i, j); - else { - int k = j; - for(;k < to - 1 && Long.compare(array[i], array[k + 1]) > 0;k++); - if(j == k) { - swap(array, i++, j); - continue; - } - else if(j + 1 == k) { - long value = array[j]; - System.arraycopy(array, i, array, i+1, j - i); - array[i] = value; - i++; - j++; - continue; - } - long[] data = new long[k - j]; - System.arraycopy(array, j, data, 0, data.length); - System.arraycopy(array, i, array, i+data.length, j - i); - System.arraycopy(data, 0, array, i, data.length); - i+=data.length; - j+=data.length; - } - } - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(long[] array, LongComparator comp) { - parallelMemFreeMergeSort(array, 0, array.length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(long[] array, int length, LongComparator comp) { - parallelMemFreeMergeSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(long[] array, int from, int to, LongComparator comp) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new MemFreeMergeSortActionComp(array, from, to, comp)); - return; - } - memFreeMergeSort(array, from, to, comp); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(long[] array) { - parallelMemFreeMergeSort(array, 0, array.length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(long[] array, int length) { - parallelMemFreeMergeSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. - * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. - * It does stack allocate tiny amounts of data for shifting around elements. - * @author Speiger - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelMemFreeMergeSort(long[] array, int from, int to) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new MemFreeMergeSortAction(array, from, to)); - return; - } - memFreeMergeSort(array, from, to); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @return input array - */ - public static long[] quickSort(long[] array, LongComparator comp) { - quickSort(array, 0, array.length, comp); - return array; - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - */ - public static void quickSort(long[] array, int length, LongComparator comp) { - quickSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - */ - public static void quickSort(long[] array, int from, int to, LongComparator comp) { - int length = to - from; - if(length <= 0) return; - if(length < BASE_THRESHOLD) { - selectionSort(array, from, to, comp); - return; - } - long pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)]; - int a = from, b = a, c = to - 1, d = c; - for(int compare;;swap(array, b++, c--)) { - for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) { - if(compare == 0) swap(array, a++, b); - } - for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) { - if(compare == 0) swap(array, c, d--); - } - if(b>c) break; - } - swap(array, from, b, Math.min(a - from, b - a)); - swap(array, b, to, Math.min(d - c, to - d - 1)); - if((length = b - a) > 1) quickSort(array, from, from + length, comp); - if((length = d - c) > 1) quickSort(array, to - length, to, comp); - } - - /** - * Sorts an array according to the natural ascending order using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @return input array - */ - public static long[] quickSort(long[] array) { - quickSort(array, 0, array.length); - return array; - } - - /** - * Sorts an array according to the natural ascending order using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - */ - public static void quickSort(long[] array, int length) { - quickSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - */ - public static void quickSort(long[] array, int from, int to) { - int length = to - from; - if(length <= 0) return; - if(length < BASE_THRESHOLD) { - selectionSort(array, from, to); - return; - } - long pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)]; - int a = from, b = a, c = to - 1, d = c; - for(int comp = 0;;swap(array, b++, c--)) { - for(;b<=c && (comp = Long.compare(array[b], pivot)) <= 0;b++) { - if(comp == 0) swap(array, a++, b); - } - for(;c>=b && (comp = Long.compare(array[c], pivot)) >= 0;c--) { - if(comp == 0) swap(array, c, d--); - } - if(b>c) break; - } - swap(array, from, b, Math.min(a - from, b - a)); - swap(array, b, to, Math.min(d - c, to - d - 1)); - if((length = b - a) > 1) quickSort(array, from, from + length); - if((length = d - c) > 1) quickSort(array, to - length, to); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(long[] array, LongComparator comp) { - parallelQuickSort(array, 0, array.length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(long[] array, int length, LongComparator comp) { - parallelQuickSort(array, 0, length, comp); - } - - /** - * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @param comp the Comparator that decides the sorting order - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(long[] array, int from, int to, LongComparator comp) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new QuickSortActionComp(array, from, to, comp)); - return; - } - quickSort(array, from, to, comp); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(long[] array) { - parallelQuickSort(array, 0, array.length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param length the maxmium size of the array to be sorted - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(long[] array, int length) { - parallelQuickSort(array, 0, length); - } - - /** - * Sorts an array according to the natural ascending order using Parallel Quick Sort, - * This implementation is a custom of FastUtil quicksort but with a different code structure, - * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. - * @param array the array that needs to be sorted - * @param from where the array should be sorted from - * @param to where the array should be sorted to - * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed - */ - public static void parallelQuickSort(long[] array, int from, int to) { - if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) { - SanityChecks.invokeTask(new QuickSortAction(array, from, to)); - return; - } - quickSort(array, from, to); - } - - static void swap(long[] a, int from, int to) { - long t = a[from]; - a[from] = a[to]; - a[to] = t; - } - - static void swap(long[] a, int from, int to, int length) { - to -= length; - for(int i = 0;i 0 ? b : comp.compare(data[a], data[c]) > 0 ? c : a); - } - - static int subMedium(long[] data, int a, int b, int c, int length) { - return medium(data, medium(data, a, a + length, a + (length * 2)), medium(data, b - length, b, b + length), medium(data, c - (length * 2), c - length, c)); - } - - static int medium(long[] data, int a, int b, int c) { - return Long.compare(data[a], data[b]) < 0 ? (Long.compare(data[b], data[c]) < 0 ? b : Long.compare(data[a], data[c]) < 0 ? c : a) : (Long.compare(data[b], data[c]) > 0 ? b : Long.compare(data[a], data[c]) > 0 ? c : a); - } - - static class QuickSortAction extends RecursiveAction { - private static final long serialVersionUID = 0L; - long[] array; - int from; - int to; - - QuickSortAction(long[] array, int from, int to) - { - this.array = array; - this.from = from; - this.to = to; - } - - @Override - protected void compute() - { - int length = to - from; - if(length <= 0) return; - if(length < BASE_THRESHOLD) { - selectionSort(array, from, to); - return; - } - long pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)]; - int a = from, b = a, c = to - 1, d = c; - for(int comp = 0;;swap(array, b++, c--)) { - for(;b<=c && (comp = Long.compare(array[b], pivot)) <= 0;b++) { - if(comp == 0) swap(array, a++, b); - } - for(;c>=b && (comp = Long.compare(array[c], pivot)) >= 0;c--) { - if(comp == 0) swap(array, c, d--); - } - if(b>c) break; - } - swap(array, from, b, Math.min(a - from, b - a)); - swap(array, b, to, Math.min(d - c, to - d - 1)); - if(b - a > 1 && d - c > 1) invokeAll(new QuickSortAction(array, from, from + (b - a)), new QuickSortAction(array, to - (d - c), to)); - else if(b - a > 1) new QuickSortAction(array, from, from + (b - a)).invoke(); - else if(d - c > 1) new QuickSortAction(array, to - (d - c), to).invoke(); - } - } - - static class QuickSortActionComp extends RecursiveAction { - private static final long serialVersionUID = 0L; - long[] array; - int from; - int to; - LongComparator comp; - - QuickSortActionComp(long[] array, int from, int to, LongComparator comp) - { - this.array = array; - this.from = from; - this.to = to; - this.comp = comp; - } - - @Override - protected void compute() - { - int length = to - from; - if(length <= 0) return; - if(length < BASE_THRESHOLD) { - selectionSort(array, from, to, comp); - return; - } - long pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)]; - int a = from, b = a, c = to - 1, d = c; - for(int compare;;swap(array, b++, c--)) { - for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) { - if(compare == 0) swap(array, a++, b); - } - for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) { - if(compare == 0) swap(array, c, d--); - } - if(b>c) break; - } - swap(array, from, b, Math.min(a - from, b - a)); - swap(array, b, to, Math.min(d - c, to - d - 1)); - if(b - a > 1 && d - c > 1) invokeAll(new QuickSortActionComp(array, from, from + (b - a), comp), new QuickSortActionComp(array, to - (d - c), to, comp)); - else if(b - a > 1) new QuickSortActionComp(array, from, from + (b - a), comp).invoke(); - else if(d - c > 1) new QuickSortActionComp(array, to - (d - c), to, comp).invoke(); - } - } - - static class MergeSortAction extends RecursiveAction { - private static final long serialVersionUID = 0L; - long[] array; - long[] supp; - int from; - int to; - - MergeSortAction(long[] array, long[] supp, int from, int to) - { - this.array = array; - this.supp = supp; - this.from = from; - this.to = to; - } - - @Override - protected void compute() - { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to); - return; - } - if(supp == null) supp = Arrays.copyOf(array, to); - int mid = (from + to) >>> 1; - invokeAll(new MergeSortAction(supp, array, from, mid), new MergeSortAction(supp, array, mid, to)); - if(Long.compare(supp[mid - 1], supp[mid]) <= 0) - { - System.arraycopy(supp, from, array, from, to - from); - return; - } - for(int p = from, q = mid;from < to;from++) { - if(q >= to || p < mid && Long.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; - else array[from] = supp[q++]; - } - } - } - - static class MergeSortActionComp extends RecursiveAction { - private static final long serialVersionUID = 0L; - long[] array; - long[] supp; - int from; - int to; - LongComparator comp; - - MergeSortActionComp(long[] array, long[] supp, int from, int to, LongComparator comp) - { - this.array = array; - this.supp = supp; - this.from = from; - this.to = to; - this.comp = comp; - } - - @Override - protected void compute() - { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to, comp); - return; - } - if(supp == null) supp = Arrays.copyOf(array, to); - int mid = (from + to) >>> 1; - invokeAll(new MergeSortActionComp(supp, array, from, mid, comp), new MergeSortActionComp(supp, array, mid, to, comp)); - if(comp.compare(supp[mid - 1], supp[mid]) <= 0) - { - System.arraycopy(supp, from, array, from, to - from); - return; - } - for(int p = from, q = mid;from < to;from++) { - if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++]; - else array[from] = supp[q++]; - } - } - } - - static class MemFreeMergeSortAction extends RecursiveAction { - private static final long serialVersionUID = 0L; - long[] array; - int from; - int to; - - MemFreeMergeSortAction(long[] array, int from, int to) - { - this.array = array; - this.from = from; - this.to = to; - } - - @Override - protected void compute() - { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to); - return; - } - int mid = (from + to) >>> 1; - invokeAll(new MemFreeMergeSortAction(array, from, mid), new MemFreeMergeSortAction(array, mid, to)); - if(Long.compare(array[mid - 1], array[mid]) <= 0) - return; - for(int i = from, j = mid, comp;i < j && j < to;) { - if((comp = Long.compare(array[i], array[j])) < 0) - i++; - else if(comp == 0) swap(array, ++i, j); - else { - int k = j; - for(;k < to - 1 && Long.compare(array[i], array[k + 1]) > 0;k++); - if(j == k) { - swap(array, i++, j); - continue; - } - else if(j + 1 == k) { - long value = array[j]; - System.arraycopy(array, i, array, i+1, j - i); - array[i] = value; - i++; - j++; - continue; - } - long[] data = new long[k - j]; - System.arraycopy(array, j, data, 0, data.length); - System.arraycopy(array, i, array, i+data.length, j - i); - System.arraycopy(data, 0, array, i, data.length); - i+=data.length; - j+=data.length; - } - } - } - } - - static class MemFreeMergeSortActionComp extends RecursiveAction { - private static final long serialVersionUID = 0L; - long[] array; - int from; - int to; - LongComparator comp; - - MemFreeMergeSortActionComp(long[] array, int from, int to, LongComparator comp) - { - this.array = array; - this.from = from; - this.to = to; - this.comp = comp; - } - - @Override - protected void compute() - { - if(to - from < BASE_THRESHOLD) { - insertionSort(array, from, to, comp); - return; - } - int mid = (from + to) >>> 1; - invokeAll(new MemFreeMergeSortActionComp(array, from, mid, comp), new MemFreeMergeSortActionComp(array, mid, to, comp)); - - if(comp.compare(array[mid - 1], array[mid]) <= 0) - return; - for(int i = from, j = mid, compare;i < j && j < to;) { - if((compare = comp.compare(array[i], array[j])) < 0) - i++; - else if(compare == 0) swap(array, ++i, j); - else { - int k = j; - for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++); - if(j == k) { - swap(array, i++, j); - continue; - } - else if(j + 1 == k) { - long value = array[j]; - System.arraycopy(array, i, array, i+1, j - i); - array[i] = value; - i++; - j++; - continue; - } - long[] data = new long[k - j]; - System.arraycopy(array, j, data, 0, data.length); - System.arraycopy(array, i, array, i+data.length, j - i); - System.arraycopy(data, 0, array, i, data.length); - i+=data.length; - j+=data.length; - } - } - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/utils/LongCollections.java b/src/main/java/speiger/src/collections/longs/utils/LongCollections.java deleted file mode 100644 index 18ed50122..000000000 --- a/src/main/java/speiger/src/collections/longs/utils/LongCollections.java +++ /dev/null @@ -1,892 +0,0 @@ -package speiger.src.collections.longs.utils; - -import java.util.Arrays; -import java.util.Collection; -import java.util.ConcurrentModificationException; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.function.Predicate; -import java.util.function.LongPredicate; -import java.util.function.Consumer; - -import speiger.src.collections.longs.collections.AbstractLongCollection; -import speiger.src.collections.longs.collections.LongCollection; -import speiger.src.collections.longs.collections.LongIterator; -import speiger.src.collections.longs.functions.LongComparator; -import speiger.src.collections.objects.utils.ObjectArrays; -import speiger.src.collections.longs.functions.LongConsumer; -import speiger.src.collections.longs.utils.LongArrays; -import speiger.src.collections.longs.functions.function.LongLongUnaryOperator; -import speiger.src.collections.ints.functions.consumer.IntLongConsumer; -import speiger.src.collections.objects.functions.consumer.ObjectLongConsumer; -import speiger.src.collections.utils.HashUtil; -import speiger.src.collections.utils.ITrimmable; -import speiger.src.collections.utils.SanityChecks; - -/** - * A Helper class for Collections - */ -public class LongCollections -{ - /** - * Empty Collection Reference - */ - public static final LongCollection EMPTY = new EmptyCollection(); - - /** - * Returns a Immutable EmptyCollection instance that is automatically casted. - * @return an empty collection - */ - public static LongCollection empty() { - return EMPTY; - } - - /** - * Returns a Immutable Collection instance based on the instance given. - * @param c that should be made immutable/unmodifiable - * @return a unmodifiable collection wrapper. If the Collection already a unmodifiable wrapper then it just returns itself. - */ - public static LongCollection unmodifiable(LongCollection c) { - return c instanceof UnmodifiableCollection ? c : new UnmodifiableCollection(c); - } - - /** - * Returns a synchronized Collection instance based on the instance given. - * @param c that should be synchronized - * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself. - */ - public static LongCollection synchronize(LongCollection c) { - return c instanceof SynchronizedCollection ? c : new SynchronizedCollection(c); - } - - /** - * Returns a synchronized Collection instance based on the instance given. - * @param c that should be synchronized - * @param mutex is the controller of the synchronization block. - * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself. - */ - public static LongCollection synchronize(LongCollection c, Object mutex) { - return c instanceof SynchronizedCollection ? c : new SynchronizedCollection(c, mutex); - } - - /** - * Creates a Singleton Collection of a given element - * @param element the element that should be converted into a singleton collection - * @return a singletoncollection of the given element - */ - public static LongCollection singleton(long element) { - return new SingletonCollection(element); - } - - protected static CollectionWrapper wrapper() { - return new CollectionWrapper(); - } - - protected static CollectionWrapper wrapper(int size) { - return new CollectionWrapper(size); - } - - protected static DistinctCollectionWrapper distinctWrapper() { - return new DistinctCollectionWrapper(); - } - - protected static DistinctCollectionWrapper distinctWrapper(int size) { - return new DistinctCollectionWrapper(size); - } - - protected static class CollectionWrapper extends AbstractLongCollection implements ITrimmable { - long[] elements; - int size = 0; - - public CollectionWrapper() { - this(10); - } - - public CollectionWrapper(int size) { - if(size < 0) throw new IllegalStateException("Size has to be 0 or greater"); - elements = new long[size]; - } - - @Override - public boolean add(long o) { - if(size >= elements.length) elements = Arrays.copyOf(elements, (int)Math.min((long)elements.length + (elements.length >> 1), SanityChecks.MAX_ARRAY_SIZE)); - elements[size++] = o; - return true; - } - - public long getLong(int index) { - if(index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); - return elements[index]; - } - - @Override - public boolean remLong(long e) { - for(int i = 0;i= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); - size--; - if(index != size) System.arraycopy(elements, index+1, elements, index, size - index); - } - - @Override - public LongIterator iterator() { - return new LongIterator() { - int index = 0; - int lastReturned = -1; - - @Override - public boolean hasNext() { - return index < size; - } - - @Override - public long nextLong() { - int i = index++; - return elements[(lastReturned = i)]; - } - - @Override - public void remove() { - if(lastReturned == -1) throw new IllegalStateException(); - removeIndex(lastReturned); - index = lastReturned; - lastReturned = -1; - } - }; - } - - @Override - public int size() { - return size; - } - - @Override - public void clear() { - size = 0; - } - - public void sort(LongComparator c) { - if(c != null) LongArrays.stableSort(elements, size, c); - else LongArrays.stableSort(elements, size); - } - - public void unstableSort(LongComparator c) { - if(c != null) LongArrays.unstableSort(elements, size, c); - else LongArrays.unstableSort(elements, size); - } - - @Override - public void forEach(LongConsumer action) { - Objects.requireNonNull(action); - for(int i = 0;i void forEach(E input, ObjectLongConsumer action) { - Objects.requireNonNull(action); - for(int i = 0;i size() || size() == elements.length) return false; - int value = Math.max(size, size()); - elements = value == 0 ? LongArrays.EMPTY_ARRAY : Arrays.copyOf(elements, value); - return true; - } - - @Override - public void clearAndTrim(int size) { - if(elements.length <= size) { - clear(); - return; - } - elements = size == 0 ? LongArrays.EMPTY_ARRAY : new long[size]; - this.size = size; - } - - @Override - @Deprecated - public Object[] toArray() { - Object[] obj = new Object[size]; - for(int i = 0;i E[] toArray(E[] a) { - if(a == null) a = (E[])new Object[size]; - else if(a.length < size) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), size); - for(int i = 0;i size) a[size] = null; - return a; - } - - @Override - public long[] toLongArray(long[] a) { - if(a.length < size) a = new long[size]; - System.arraycopy(elements, 0, a, 0, size); - if (a.length > size) a[size] = 0L; - return a; - } - } - - protected static class DistinctCollectionWrapper extends AbstractLongCollection { - long[] keys; - boolean containsNull; - int minCapacity; - int nullIndex; - int maxFill; - int mask; - int size; - - public DistinctCollectionWrapper() { - this(HashUtil.DEFAULT_MIN_CAPACITY); - } - - public DistinctCollectionWrapper(int size) { - if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); - minCapacity = nullIndex = HashUtil.arraySize(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR); - mask = nullIndex - 1; - maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1); - keys = new long[nullIndex + 1]; - } - - @Override - public boolean add(long o) { - if(o == 0) { - if(containsNull) return false; - containsNull = true; - } - else { - int pos = HashUtil.mix(Long.hashCode(o)) & mask; - long current = keys[pos]; - if(current != 0) { - if(current == o) return false; - while((current = keys[pos = (++pos & mask)]) != 0) - if(current == o) return false; - } - keys[pos] = o; - } - if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, HashUtil.DEFAULT_LOAD_FACTOR)); - return true; - } - - @Override - public boolean contains(Object o) { - if(o == null) return false; - if(o instanceof Long && ((Long)o).longValue() == 0L) return containsNull; - int pos = HashUtil.mix(o.hashCode()) & mask; - long current = keys[pos]; - if(current == 0) return false; - if(Objects.equals(o, Long.valueOf(current))) return true; - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(Objects.equals(o, Long.valueOf(current))) return true; - } - } - - @Override - public boolean remove(Object o) { - if(o == null) return false; - if(o instanceof Long && ((Long)o).longValue() == 0L) return (containsNull ? removeNullIndex() : false); - int pos = HashUtil.mix(o.hashCode()) & mask; - long current = keys[pos]; - if(current == 0) return false; - if(Objects.equals(o, Long.valueOf(current))) return removeIndex(pos); - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(Objects.equals(o, Long.valueOf(current))) return removeIndex(pos); - } - } - - @Override - public boolean contains(long o) { - if(o == 0) return containsNull; - int pos = HashUtil.mix(Long.hashCode(o)) & mask; - long current = keys[pos]; - if(current == 0) return false; - if(current == o) return true; - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(current == o) return true; - } - } - - @Override - public boolean remLong(long o) { - if(o == 0) return containsNull ? removeNullIndex() : false; - int pos = HashUtil.mix(Long.hashCode(o)) & mask; - long current = keys[pos]; - if(current == 0) return false; - if(current == o) return removeIndex(pos); - while(true) { - if((current = keys[pos = (++pos & mask)]) == 0) return false; - else if(current == o) return removeIndex(pos); - } - } - - protected boolean removeIndex(int pos) { - if(pos == nullIndex) return containsNull ? removeNullIndex() : false; - keys[pos] = 0L; - size--; - shiftKeys(pos); - if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); - return true; - } - - protected boolean removeNullIndex() { - containsNull = false; - keys[nullIndex] = 0L; - size--; - if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); - return true; - } - - @Override - public LongIterator iterator() { - return new SetIterator(); - } - - @Override - public void forEach(LongConsumer action) { - if(size() <= 0) return; - if(containsNull) action.accept(keys[nullIndex]); - for(int i = nullIndex-1;i>=0;i--) { - if(keys[i] != 0) action.accept(keys[i]); - } - } - - @Override - public DistinctCollectionWrapper copy() { - DistinctCollectionWrapper set = new DistinctCollectionWrapper(0); - set.minCapacity = minCapacity; - set.mask = mask; - set.maxFill = maxFill; - set.nullIndex = nullIndex; - set.containsNull = containsNull; - set.size = size; - set.keys = Arrays.copyOf(keys, keys.length); - return set; - } - - protected void shiftKeys(int startPos) { - int slot, last; - long current; - while(true) { - startPos = ((last = startPos) + 1) & mask; - while(true){ - if((current = keys[startPos]) == 0) { - keys[last] = 0L; - return; - } - slot = HashUtil.mix(Long.hashCode(current)) & mask; - if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; - startPos = ++startPos & mask; - } - keys[last] = current; - } - } - - protected void rehash(int newSize) { - int newMask = newSize - 1; - long[] newKeys = new long[newSize + 1]; - for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) { - while(true) { - if(--i < 0) throw new ConcurrentModificationException("Set was modified during rehash"); - if(keys[i] != 0) break; - } - if(newKeys[pos = HashUtil.mix(Long.hashCode(keys[i])) & newMask] != 0) - while(newKeys[pos = (++pos & newMask)] != 0); - newKeys[pos] = keys[i]; - } - nullIndex = newSize; - mask = newMask; - maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1); - keys = newKeys; - } - - @Override - public void clear() { - if(size == 0) return; - size = 0; - containsNull = false; - Arrays.fill(keys, 0L); - } - - @Override - public int size() { - return size; - } - - private class SetIterator implements LongIterator { - int pos = nullIndex; - int returnedPos = -1; - int lastReturned = -1; - int nextIndex = Integer.MIN_VALUE; - boolean returnNull = containsNull; - long[] wrapped = null; - int wrappedIndex = 0; - - @Override - public boolean hasNext() { - if(nextIndex == Integer.MIN_VALUE) { - if(returnNull) { - returnNull = false; - nextIndex = nullIndex; - } - else - { - while(true) { - if(--pos < 0) { - if(wrapped == null || wrappedIndex <= -pos - 1) break; - nextIndex = -pos - 1; - break; - } - if(keys[pos] != 0){ - nextIndex = pos; - break; - } - } - } - } - return nextIndex != Integer.MIN_VALUE; - } - - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - returnedPos = pos; - if(nextIndex < 0){ - lastReturned = Integer.MAX_VALUE; - long value = wrapped[nextIndex]; - nextIndex = Integer.MIN_VALUE; - return value; - } - long value = keys[(lastReturned = nextIndex)]; - nextIndex = Integer.MIN_VALUE; - return value; - } - - @Override - public void remove() { - if(lastReturned == -1) throw new IllegalStateException(); - if(lastReturned == nullIndex) { - containsNull = false; - keys[nullIndex] = 0L; - } - else if(returnedPos >= 0) shiftKeys(returnedPos); - else { - DistinctCollectionWrapper.this.remLong(wrapped[-returnedPos - 1]); - lastReturned = -1; - return; - } - size--; - lastReturned = -1; - } - - private void shiftKeys(int startPos) { - int slot, last; - long current; - while(true) { - startPos = ((last = startPos) + 1) & mask; - while(true){ - if((current = keys[startPos]) == 0) { - keys[last] = 0L; - return; - } - slot = HashUtil.mix(Long.hashCode(current)) & mask; - if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; - startPos = ++startPos & mask; - } - if(startPos < last) addWrapper(keys[startPos]); - keys[last] = current; - } - } - - private void addWrapper(long value) { - if(wrapped == null) wrapped = new long[2]; - else if(wrappedIndex >= wrapped.length) { - long[] newArray = new long[wrapped.length * 2]; - System.arraycopy(wrapped, 0, newArray, 0, wrapped.length); - wrapped = newArray; - } - wrapped[wrappedIndex++] = value; - } - } - } - - private static class SingletonCollection extends AbstractLongCollection - { - long element; - - SingletonCollection(long element) { - this.element = element; - } - - @Override - public boolean remLong(long o) { throw new UnsupportedOperationException(); } - @Override - public boolean add(long o) { throw new UnsupportedOperationException(); } - @Override - public LongIterator iterator() - { - return new LongIterator() { - boolean next = true; - @Override - public boolean hasNext() { return next; } - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - next = false; - return element; - } - }; - } - - @Override - public boolean equals(Object o) { - if (o == this) - return true; - if (!(o instanceof Collection)) - return false; - Collection l = (Collection)o; - if(l.size() != size()) return false; - Iterator iter = l.iterator(); - if (iter.hasNext() && !Objects.equals(element, iter.next())) { - return false; - } - return !iter.hasNext(); - } - - @Override - public int hashCode() { - return Long.hashCode(element); - } - - @Override - public int size() { return 1; } - - @Override - public SingletonCollection copy() { return new SingletonCollection(element); } - } - - /** - * Synchronized Collection Wrapper for the synchronizedCollection function - */ - public static class SynchronizedCollection implements LongCollection { - LongCollection c; - protected Object mutex; - - SynchronizedCollection(LongCollection c) { - this.c = c; - mutex = this; - } - - SynchronizedCollection(LongCollection c, Object mutex) { - this.c = c; - this.mutex = mutex; - } - - @Override - public boolean add(long o) { synchronized(mutex) { return c.add(o); } } - @Override - public boolean addAll(Collection c) { synchronized(mutex) { return this.c.addAll(c); } } - @Override - public boolean addAll(LongCollection c) { synchronized(mutex) { return this.c.addAll(c); } } - @Override - public boolean addAll(long[] e, int offset, int length) { synchronized(mutex) { return c.addAll(e, offset, length); } } - @Override - public boolean contains(long o) { synchronized(mutex) { return c.contains(o); } } - @Override - @Deprecated - public boolean containsAll(Collection c) { synchronized(mutex) { return this.c.containsAll(c); } } - - @Override - @Deprecated - public boolean containsAny(Collection c) { synchronized(mutex) { return this.c.containsAny(c); } } - - @Override - public boolean containsAll(LongCollection c) { synchronized(mutex) { return this.c.containsAll(c); } } - - @Override - public boolean containsAny(LongCollection c) { synchronized(mutex) { return this.c.containsAny(c); } } - - @Override - public int size() { synchronized(mutex) { return c.size(); } } - - @Override - public boolean isEmpty() { synchronized(mutex) { return c.isEmpty(); } } - - @Override - public LongIterator iterator() { - return c.iterator(); - } - - @Override - public LongCollection copy() { synchronized(mutex) { return c.copy(); } } - - @Override - @Deprecated - public boolean remove(Object o) { synchronized(mutex) { return c.remove(o); } } - @Override - @Deprecated - public boolean removeAll(Collection c) { synchronized(mutex) { return this.c.removeAll(c); } } - @Override - @Deprecated - public boolean retainAll(Collection c) { synchronized(mutex) { return this.c.retainAll(c); } } - @Override - public boolean remLong(long o) { synchronized(mutex) { return c.remLong(o); } } - @Override - public boolean removeAll(LongCollection c) { synchronized(mutex) { return this.c.removeAll(c); } } - @Override - public boolean removeAll(LongCollection c, LongConsumer r) { synchronized(mutex) { return this.c.removeAll(c, r); } } - @Override - public boolean retainAll(LongCollection c) { synchronized(mutex) { return this.c.retainAll(c); } } - @Override - public boolean retainAll(LongCollection c, LongConsumer r) { synchronized(mutex) { return this.c.retainAll(c, r); } } - @Override - public boolean remIf(LongPredicate filter){ synchronized(mutex) { return c.remIf(filter); } } - @Override - public void clear() { synchronized(mutex) { c.clear(); } } - @Override - public Object[] toArray() { synchronized(mutex) { return c.toArray(); } } - @Override - public T[] toArray(T[] a) { synchronized(mutex) { return c.toArray(a); } } - @Override - public long[] toLongArray() { synchronized(mutex) { return c.toLongArray(); } } - @Override - public long[] toLongArray(long[] a) { synchronized(mutex) { return c.toLongArray(a); } } - @Override - public void forEach(LongConsumer action) { synchronized(mutex) { c.forEach(action); } } - @Override - @Deprecated - public void forEach(Consumer action) { synchronized(mutex) { c.forEach(action); } } - @Override - public void forEachIndexed(IntLongConsumer action) { synchronized(mutex) { c.forEachIndexed(action); } } - @Override - public int hashCode() { synchronized(mutex) { return c.hashCode(); } } - @Override - public boolean equals(Object obj) { - if(obj == this) return true; - synchronized(mutex) { return c.equals(obj); } - } - @Override - public String toString() { synchronized(mutex) { return c.toString(); } } - @Override - public void forEach(E input, ObjectLongConsumer action) { synchronized(mutex) { c.forEach(input, action); } } - @Override - public boolean matchesAny(LongPredicate filter) { synchronized(mutex) { return c.matchesAny(filter); } } - @Override - public boolean matchesNone(LongPredicate filter) { synchronized(mutex) { return c.matchesNone(filter); } } - @Override - public boolean matchesAll(LongPredicate filter) { synchronized(mutex) { return c.matchesAll(filter); } } - @Override - public long reduce(long identity, LongLongUnaryOperator operator) { synchronized(mutex) { return c.reduce(identity, operator); } } - @Override - public long reduce(LongLongUnaryOperator operator) { synchronized(mutex) { return c.reduce(operator); } } - @Override - public long findFirst(LongPredicate filter) { synchronized(mutex) { return c.findFirst(filter); } } - @Override - public int count(LongPredicate filter) { synchronized(mutex) { return c.count(filter); } } - } - - /** - * Unmodifyable Collection Wrapper for the unmodifyableCollection method - */ - public static class UnmodifiableCollection implements LongCollection { - LongCollection c; - - UnmodifiableCollection(LongCollection c) { - this.c = c; - } - - @Override - public boolean add(long o) { throw new UnsupportedOperationException(); } - @Override - public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } - @Override - public boolean addAll(LongCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean addAll(long[] e, int offset, int length) { throw new UnsupportedOperationException(); } - @Override - public boolean contains(long o) { return c.contains(o); } - @Override - public boolean containsAll(LongCollection c) { return this.c.containsAll(c); } - @Override - public boolean containsAny(LongCollection c) { return this.c.containsAny(c); } - @Override - @Deprecated - public boolean containsAny(Collection c) { return this.c.containsAny(c); } - @Override - @Deprecated - public boolean containsAll(Collection c) { return this.c.containsAll(c); } - @Override - public int size() { return c.size(); } - @Override - public boolean isEmpty() { return c.isEmpty(); } - @Override - public LongIterator iterator() { return LongIterators.unmodifiable(c.iterator()); } - @Override - public LongCollection copy() { return c.copy(); } - @Override - @Deprecated - public boolean remove(Object o) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); } - @Override - public boolean remLong(long o) { throw new UnsupportedOperationException(); } - @Override - public boolean removeAll(LongCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean removeAll(LongCollection c, LongConsumer r) { throw new UnsupportedOperationException(); } - @Override - public boolean retainAll(LongCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean retainAll(LongCollection c, LongConsumer r) { throw new UnsupportedOperationException(); } - @Override - public boolean remIf(LongPredicate filter){ throw new UnsupportedOperationException(); } - @Override - public void clear() { throw new UnsupportedOperationException(); } - @Override - public Object[] toArray() { return c.toArray(); } - @Override - public T[] toArray(T[] a) { return c.toArray(a); } - @Override - public long[] toLongArray() { return c.toLongArray(); } - @Override - public long[] toLongArray(long[] a) { return c.toLongArray(a); } - @Override - public void forEach(LongConsumer action) { c.forEach(action); } - @Override - @Deprecated - public void forEach(Consumer action) { c.forEach(action); } - @Override - public void forEachIndexed(IntLongConsumer action) { c.forEachIndexed(action); } - @Override - public int hashCode() { return c.hashCode(); } - @Override - public boolean equals(Object obj) { return obj == this || c.equals(obj); } - @Override - public String toString() { return c.toString(); } - @Override - public void forEach(E input, ObjectLongConsumer action) { c.forEach(input, action); } - @Override - public boolean matchesAny(LongPredicate filter) { return c.matchesAny(filter); } - @Override - public boolean matchesNone(LongPredicate filter) { return c.matchesNone(filter); } - @Override - public boolean matchesAll(LongPredicate filter) { return c.matchesAll(filter); } - @Override - public long reduce(long identity, LongLongUnaryOperator operator) { return c.reduce(identity, operator); } - @Override - public long reduce(LongLongUnaryOperator operator) { return c.reduce(operator); } - @Override - public long findFirst(LongPredicate filter) { return c.findFirst(filter); } - @Override - public int count(LongPredicate filter) { return c.count(filter); } - } - - /** - * Empty Collection implementation for the empty collection function - */ - public static class EmptyCollection extends AbstractLongCollection { - @Override - public boolean add(long o) { throw new UnsupportedOperationException(); } - - @Override - public boolean addAll(LongCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean addAll(long[] e, int offset, int length) { throw new UnsupportedOperationException(); } - - @Override - public boolean contains(long o) { return false; } - @Override - public boolean containsAll(LongCollection c) { return c.isEmpty(); } - @Override - public boolean containsAny(LongCollection c) { return false; } - @Override - @Deprecated - public boolean containsAny(Collection c) { return false; } - @Override - @Deprecated - public boolean containsAll(Collection c) { return c.isEmpty(); } - @Override - public int hashCode() { return 0; } - - @Override - public boolean equals(Object o) { - if(o == this) return true; - if(!(o instanceof Collection)) return false; - return ((Collection)o).isEmpty(); - } - - @Override - @Deprecated - public boolean remove(Object o) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } - @Override - @Deprecated - public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); } - @Override - public boolean remLong(long o) { throw new UnsupportedOperationException(); } - @Override - public boolean removeAll(LongCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean retainAll(LongCollection c) { throw new UnsupportedOperationException(); } - @Override - public boolean remIf(LongPredicate filter){ throw new UnsupportedOperationException(); } - @Override - public Object[] toArray() { return ObjectArrays.EMPTY_ARRAY; } - @Override - public T[] toArray(T[] a) { - if(a != null && a.length > 0) - a[0] = null; - return a; - } - - @Override - public long[] toLongArray() { return LongArrays.EMPTY_ARRAY; } - @Override - public long[] toLongArray(long[] a) { - if(a != null && a.length > 0) - a[0] = 0L; - return a; - } - - @Override - public LongIterator iterator() { return LongIterators.empty(); } - @Override - public void clear() {} - @Override - public int size() { return 0; } - @Override - public EmptyCollection copy() { return this; } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/utils/LongIterables.java b/src/main/java/speiger/src/collections/longs/utils/LongIterables.java deleted file mode 100644 index 651724660..000000000 --- a/src/main/java/speiger/src/collections/longs/utils/LongIterables.java +++ /dev/null @@ -1,485 +0,0 @@ -package speiger.src.collections.longs.utils; - -import java.util.Objects; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Consumer; -import java.util.function.LongPredicate; - -import speiger.src.collections.longs.collections.LongIterable; -import speiger.src.collections.longs.collections.LongCollection; -import speiger.src.collections.objects.collections.ObjectIterable; -import speiger.src.collections.objects.collections.ObjectIterator; -import speiger.src.collections.longs.functions.LongConsumer; -import speiger.src.collections.longs.functions.LongComparator; -import speiger.src.collections.longs.collections.LongIterator; -import speiger.src.collections.longs.functions.function.LongFunction; -import speiger.src.collections.utils.ISizeProvider; - -/** - * A Helper class for Iterables - */ -public class LongIterables -{ - /** - * A Helper function that maps a Java-Iterable into a new Type. - * @param iterable the iterable that should be mapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterable that is mapped to a new result - */ - public static ObjectIterable map(Iterable iterable, LongFunction mapper) { - return new MappedIterable<>(wrap(iterable), mapper); - } - - /** - * A Helper function that maps a Iterable into a new Type. - * @param iterable the iterable that should be mapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterable that is mapped to a new result - */ - public static ObjectIterable map(LongIterable iterable, LongFunction mapper) { - return new MappedIterable<>(iterable, mapper); - } - - /** - * A Helper function that flatMaps a Java-Iterable into a new Type. - * @param iterable the iterable that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type supplier. - * @param The return type. - * @return a iterable that is flatMapped to a new result - */ - public static > ObjectIterable flatMap(Iterable iterable, LongFunction mapper) { - return new FlatMappedIterable<>(wrap(iterable), mapper); - } - - /** - * A Helper function that flatMaps a Iterable into a new Type. - * @param iterable the iterable that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type supplier. - * @param The return type. - * @return a iterable that is flatMapped to a new result - */ - public static > ObjectIterable flatMap(LongIterable iterable, LongFunction mapper) { - return new FlatMappedIterable<>(iterable, mapper); - } - - /** - * A Helper function that flatMaps a Java-Iterable into a new Type. - * @param iterable the iterable that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterable that is flatMapped to a new result - */ - public static ObjectIterable arrayFlatMap(Iterable iterable, LongFunction mapper) { - return new FlatMappedArrayIterable<>(wrap(iterable), mapper); - } - - /** - * A Helper function that flatMaps a Iterable into a new Type. - * @param iterable the iterable that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterable that is flatMapped to a new result - */ - public static ObjectIterable arrayFlatMap(LongIterable iterable, LongFunction mapper) { - return new FlatMappedArrayIterable<>(iterable, mapper); - } - - /** - * A Helper function that filters out all desired elements from a Java-Iterable - * @param iterable that should be filtered. - * @param filter the filter that decides that should be let through - * @return a filtered iterable - */ - public static LongIterable filter(Iterable iterable, LongPredicate filter) { - return new FilteredIterable(wrap(iterable), filter); - } - - /** - * A Helper function that filters out all desired elements - * @param iterable that should be filtered. - * @param filter the filter that decides that should be let through - * @return a filtered iterable - */ - public static LongIterable filter(LongIterable iterable, LongPredicate filter) { - return new FilteredIterable(iterable, filter); - } - - /** - * A Helper function that filters out all duplicated elements. - * @param iterable that should be distinct - * @return a distinct iterable - */ - public static LongIterable distinct(LongIterable iterable) { - return new DistinctIterable(iterable); - } - - /** - * A Helper function that filters out all duplicated elements from a Java Iterable. - * @param iterable that should be distinct - * @return a distinct iterable - */ - public static LongIterable distinct(Iterable iterable) { - return new DistinctIterable(wrap(iterable)); - } - - /** - * A Helper function that repeats the Iterable a specific amount of times - * @param iterable that should be repeated - * @param repeats the amount of times the iterable should be repeated - * @return a repeating iterable - */ - public static LongIterable repeat(LongIterable iterable, int repeats) { - return new RepeatingIterable(iterable, repeats); - } - - /** - * A Helper function that repeats the Iterable a specific amount of times from a Java Iterable - * @param iterable that should be repeated - * @param repeats the amount of times the iterable should be repeated - * @return a repeating iterable - */ - public static LongIterable repeat(Iterable iterable, int repeats) { - return new RepeatingIterable(wrap(iterable), repeats); - } - - /** - * A Helper function that hard limits the Iterable to a specific size - * @param iterable that should be limited - * @param limit the amount of elements it should be limited to - * @return a limited iterable - */ - public static LongIterable limit(LongIterable iterable, long limit) { - return new LimitedIterable(iterable, limit); - } - - /** - * A Helper function that hard limits the Iterable to a specific size from a Java Iterable - * @param iterable that should be limited - * @param limit the amount of elements it should be limited to - * @return a limited iterable - */ - public static LongIterable limit(Iterable iterable, long limit) { - return new LimitedIterable(wrap(iterable), limit); - } - - /** - * A Helper function that sorts the Iterable. - * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. - * @param iterable that should be sorted - * @param sorter that sorts the iterable. Can be null. - * @return a sorted iterable. - */ - public static LongIterable sorted(LongIterable iterable, LongComparator sorter) { - return new SortedIterable(iterable, sorter); - } - - /** - * A Helper function that sorts the Iterable from a Java Iterable - * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. - * @param iterable that should be sorted - * @param sorter that sorts the iterable. Can be null. - * @return a sorted iterable. - */ - public static LongIterable sorted(Iterable iterable, LongComparator sorter) { - return new SortedIterable(wrap(iterable), sorter); - } - - /** - * A Helper function that allows to preview the result of a Iterable. - * @param iterable that should be peeked at - * @param action callback that receives the value before the iterable returns it - * @return a peeked iterable - */ - public static LongIterable peek(LongIterable iterable, LongConsumer action) { - return new PeekIterable(iterable, action); - } - - /** - * A Helper function that allows to preview the result of a Iterable from a Java Iterable - * @param iterable that should be peeked at - * @param action callback that receives the value before the iterable returns it - * @return a peeked iterable - */ - public static LongIterable peek(Iterable iterable, LongConsumer action) { - return new PeekIterable(wrap(iterable), action); - } - - /** - * A Wrapper function that wraps a Java-Iterable into a Type Specific Iterable - * @param iterable that should be wrapped - * @return a type specific iterable - */ - public static LongIterable wrap(Iterable iterable) { - return new WrappedIterable(iterable); - } - - private static class WrappedIterable implements LongIterable, ISizeProvider - { - Iterable iterable; - - public WrappedIterable(Iterable iterable) { - this.iterable = iterable; - } - - public LongIterator iterator() { - return LongIterators.wrap(iterable.iterator()); - } - - @Override - public int size() { - ISizeProvider prov = ISizeProvider.of(iterable); - return prov == null ? -1 : prov.size(); - } - - @Override - public void forEach(LongConsumer action) { - Objects.requireNonNull(action); - iterable.forEach(action); - } - } - - private static class MappedIterable implements ObjectIterable, ISizeProvider - { - LongIterable iterable; - LongFunction mapper; - - MappedIterable(LongIterable iterable, LongFunction mapper) { - this.iterable = iterable; - this.mapper = mapper; - } - - public ObjectIterator iterator() { - return LongIterators.map(iterable.iterator(), mapper); - } - - @Override - public int size() { - ISizeProvider prov = ISizeProvider.of(this); - return prov == null ? -1 : prov.size(); - } - - @Override - public void forEach(Consumer action) { - Objects.requireNonNull(action); - iterable.forEach(E -> action.accept(mapper.apply(E))); - } - } - - private static class FlatMappedIterable> implements ObjectIterable - { - LongIterable iterable; - LongFunction mapper; - - FlatMappedIterable(LongIterable iterable, LongFunction mapper) { - this.iterable = iterable; - this.mapper = mapper; - } - - @Override - public ObjectIterator iterator() { - return LongIterators.flatMap(iterable.iterator(), mapper); - } - - @Override - public void forEach(Consumer action) { - Objects.requireNonNull(action); - iterable.forEach(E -> mapper.apply(E).forEach(action)); - } - - } - - private static class FlatMappedArrayIterable implements ObjectIterable - { - LongIterable iterable; - LongFunction mapper; - - FlatMappedArrayIterable(LongIterable iterable, LongFunction mapper) { - this.iterable = iterable; - this.mapper = mapper; - } - - @Override - public ObjectIterator iterator() { - return LongIterators.arrayFlatMap(iterable.iterator(), mapper); - } - - @Override - public void forEach(Consumer action) { - Objects.requireNonNull(action); - iterable.forEach(E -> { - T[] array = mapper.apply(E); - for(int i = 0,m=array.length;i { if(!filter.test(T)) action.accept(T); } ); - } - } - - private static class LimitedIterable implements LongIterable, ISizeProvider - { - LongIterable iterable; - long limit; - - public LimitedIterable(LongIterable iterable, long limit) { - this.iterable = iterable; - this.limit = limit; - } - - @Override - public LongIterator iterator() { - return LongIterators.limit(iterable.iterator(), limit); - } - - @Override - public int size() { - ISizeProvider prov = ISizeProvider.of(iterable); - return prov == null ? -1 : (int)Math.min(prov.size(), limit); - } - - @Override - public void forEach(LongConsumer action) { - Objects.requireNonNull(action); - AtomicLong counter = new AtomicLong(); - iterable.forEach(T -> { - if(counter.get() >= limit) return; - counter.incrementAndGet(); - action.accept(T); - }); - } - } - - private static class SortedIterable implements LongIterable, ISizeProvider - { - LongIterable iterable; - LongComparator sorter; - - public SortedIterable(LongIterable iterable, LongComparator sorter) { - this.iterable = iterable; - this.sorter = sorter; - } - - @Override - public LongIterator iterator() { - return LongIterators.sorted(iterable.iterator(), sorter); - } - - @Override - public int size() { - ISizeProvider prov = ISizeProvider.of(iterable); - return prov == null ? -1 : prov.size(); - } - - @Override - public void forEach(LongConsumer action) { - Objects.requireNonNull(action); - LongCollections.CollectionWrapper wrapper = LongCollections.wrapper(); - iterable.forEach(wrapper::add); - wrapper.unstableSort(sorter); - wrapper.forEach(action); - } - } - - private static class DistinctIterable implements LongIterable - { - LongIterable iterable; - - public DistinctIterable(LongIterable iterable) { - this.iterable = iterable; - } - - @Override - public LongIterator iterator() { - return LongIterators.distinct(iterable.iterator()); - } - - @Override - public void forEach(LongConsumer action) { - Objects.requireNonNull(action); - LongCollection filtered = LongCollections.distinctWrapper(); - iterable.forEach(T -> { if(filtered.add(T)) action.accept(T); }); - } - } - - private static class PeekIterable implements LongIterable, ISizeProvider - { - LongIterable iterable; - LongConsumer action; - - public PeekIterable(LongIterable iterable, LongConsumer action) { - this.iterable = iterable; - this.action = action; - } - - @Override - public LongIterator iterator() { - return LongIterators.peek(iterable.iterator(), action); - } - - @Override - public int size() { - ISizeProvider prov = ISizeProvider.of(iterable); - return prov == null ? -1 : prov.size(); - } - - @Override - public void forEach(LongConsumer action) { - Objects.requireNonNull(action); - iterable.forEach(this.action.andThen(action)); - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/utils/LongIterators.java b/src/main/java/speiger/src/collections/longs/utils/LongIterators.java deleted file mode 100644 index 2355d7ae8..000000000 --- a/src/main/java/speiger/src/collections/longs/utils/LongIterators.java +++ /dev/null @@ -1,1003 +0,0 @@ -package speiger.src.collections.longs.utils; - -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.function.LongPredicate; - -import speiger.src.collections.longs.collections.LongIterator; -import speiger.src.collections.objects.collections.ObjectIterator; -import speiger.src.collections.objects.utils.ObjectIterators; -import speiger.src.collections.longs.functions.LongConsumer; -import speiger.src.collections.longs.functions.LongComparator; -import speiger.src.collections.longs.functions.function.LongFunction; -import speiger.src.collections.longs.lists.LongListIterator; -import speiger.src.collections.longs.collections.LongBidirectionalIterator; -import speiger.src.collections.longs.collections.LongCollection; - -/** - * A Helper class for Iterators - */ -public class LongIterators -{ - /** - * Empty Iterator Reference - */ - private static final EmptyIterator EMPTY = new EmptyIterator(); - - /** - * Returns a Immutable EmptyIterator instance that is automatically casted. - * @return an empty iterator - */ - public static EmptyIterator empty() { - return EMPTY; - } - - /** - * Inverter function for Bidirectional Iterators - * @param it the iterator that should be inverted - * @return a Inverted Bidirectional Iterator. If it was inverted then it just gives back the original reference - */ - public static LongBidirectionalIterator invert(LongBidirectionalIterator it) { - return it instanceof ReverseBiIterator ? ((ReverseBiIterator)it).it : new ReverseBiIterator(it); - } - - /** - * Inverter function for List Iterators - * @param it the iterator that should be inverted - * @return a Inverted List Iterator. If it was inverted then it just gives back the original reference - */ - public static LongListIterator invert(LongListIterator it) { - return it instanceof ReverseListIterator ? ((ReverseListIterator)it).it : new ReverseListIterator(it); - } - - /** - * Returns a Immutable Iterator instance based on the instance given. - * @param iterator that should be made immutable/unmodifiable - * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself. - */ - public static LongIterator unmodifiable(LongIterator iterator) { - return iterator instanceof UnmodifiableIterator ? iterator : new UnmodifiableIterator(iterator); - } - - /** - * Returns a Immutable Iterator instance based on the instance given. - * @param iterator that should be made immutable/unmodifiable - * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself. - */ - public static LongBidirectionalIterator unmodifiable(LongBidirectionalIterator iterator) { - return iterator instanceof UnmodifiableBiIterator ? iterator : new UnmodifiableBiIterator(iterator); - } - - /** - * Returns a Immutable ListIterator instance based on the instance given. - * @param iterator that should be made immutable/unmodifiable - * @return a unmodifiable listiterator wrapper. If the ListIterator already a unmodifiable wrapper then it just returns itself. - */ - public static LongListIterator unmodifiable(LongListIterator iterator) { - return iterator instanceof UnmodifiableListIterator ? iterator : new UnmodifiableListIterator(iterator); - } - - /** - * A Helper function that maps a Java-Iterator into a new Type. - * @param iterator that should be mapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterator that is mapped to a new result - */ - public static ObjectIterator map(Iterator iterator, LongFunction mapper) { - return new MappedIterator<>(wrap(iterator), mapper); - } - - /** - * A Helper function that maps a Iterator into a new Type. - * @param iterator that should be mapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterator that is mapped to a new result - */ - public static ObjectIterator map(LongIterator iterator, LongFunction mapper) { - return new MappedIterator<>(iterator, mapper); - } - - /** - * A Helper function that flatMaps a Java-Iterator into a new Type. - * @param iterator that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type supplier. - * @param The return type. - * @return a iterator that is flatMapped to a new result - */ - public static > ObjectIterator flatMap(Iterator iterator, LongFunction mapper) { - return new FlatMappedIterator<>(wrap(iterator), mapper); - } - - /** - * A Helper function that flatMaps a Iterator into a new Type. - * @param iterator that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type supplier. - * @param The return type. - * @return a iterator that is flatMapped to a new result - */ - public static > ObjectIterator flatMap(LongIterator iterator, LongFunction mapper) { - return new FlatMappedIterator<>(iterator, mapper); - } - - /** - * A Helper function that flatMaps a Java-Iterator into a new Type. - * @param iterator that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterator that is flatMapped to a new result - */ - public static ObjectIterator arrayFlatMap(Iterator iterator, LongFunction mapper) { - return new FlatMappedArrayIterator<>(wrap(iterator), mapper); - } - - /** - * A Helper function that flatMaps a Iterator into a new Type. - * @param iterator that should be flatMapped - * @param mapper the function that decides what the result turns into. - * @param The return type. - * @return a iterator that is flatMapped to a new result - */ - public static ObjectIterator arrayFlatMap(LongIterator iterator, LongFunction mapper) { - return new FlatMappedArrayIterator<>(iterator, mapper); - } - - /** - * A Helper function that filters out all desired elements from a Java-Iterator - * @param iterator that should be filtered. - * @param filter the filter that decides that should be let through - * @return a filtered iterator - */ - public static LongIterator filter(Iterator iterator, LongPredicate filter) { - return new FilteredIterator(wrap(iterator), filter); - } - - /** - * A Helper function that filters out all desired elements - * @param iterator that should be filtered. - * @param filter the filter that decides that should be let through - * @return a filtered iterator - */ - public static LongIterator filter(LongIterator iterator, LongPredicate filter) { - return new FilteredIterator(iterator, filter); - } - - /** - * A Helper function that filters out all duplicated elements. - * @param iterator that should be distinct - * @return a distinct iterator - */ - public static LongIterator distinct(LongIterator iterator) { - return new DistinctIterator(iterator); - } - - /** - * A Helper function that filters out all duplicated elements from a Java Iterator. - * @param iterator that should be distinct - * @return a distinct iterator - */ - public static LongIterator distinct(Iterator iterator) { - return new DistinctIterator(wrap(iterator)); - } - - /** - * A Helper function that repeats the Iterator a specific amount of times - * @param iterator that should be repeated - * @param repeats the amount of times the iterator should be repeated - * @return a repeating iterator - */ - public static LongIterator repeat(LongIterator iterator, int repeats) { - return new RepeatingIterator(iterator, repeats); - } - - /** - * A Helper function that repeats the Iterator a specific amount of times from a Java Iterator - * @param iterator that should be repeated - * @param repeats the amount of times the iterator should be repeated - * @return a repeating iterator - */ - public static LongIterator repeat(Iterator iterator, int repeats) { - return new RepeatingIterator(wrap(iterator), repeats); - } - - /** - * A Helper function that hard limits the Iterator to a specific size - * @param iterator that should be limited - * @param limit the amount of elements it should be limited to - * @return a limited iterator - */ - public static LongIterator limit(LongIterator iterator, long limit) { - return new LimitedIterator(iterator, limit); - } - - /** - * A Helper function that hard limits the Iterator to a specific size from a Java Iterator - * @param iterator that should be limited - * @param limit the amount of elements it should be limited to - * @return a limited iterator - */ - public static LongIterator limit(Iterator iterator, long limit) { - return new LimitedIterator(wrap(iterator), limit); - } - - /** - * A Helper function that sorts the Iterator beforehand. - * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. - * @param iterator that should be sorted. - * @param sorter the sorter of the iterator. Can be null. - * @return a new sorted iterator - */ - public static LongIterator sorted(LongIterator iterator, LongComparator sorter) { - return new SortedIterator(iterator, sorter); - } - - /** - * A Helper function that sorts the Iterator beforehand from a Java Iterator. - * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it. - * @param iterator that should be sorted. - * @param sorter the sorter of the iterator. Can be null. - * @return a new sorted iterator - */ - public static LongIterator sorted(Iterator iterator, LongComparator sorter) { - return new SortedIterator(wrap(iterator), sorter); - } - - /** - * A Helper function that allows to preview the result of a Iterator. - * @param iterator that should be peeked at - * @param action callback that receives the value before the iterator returns it - * @return a peeked iterator - */ - public static LongIterator peek(LongIterator iterator, LongConsumer action) { - return new PeekIterator(iterator, action); - } - - /** - * A Helper function that allows to preview the result of a Iterator from a Java Iterator - * @param iterator that should be peeked at - * @param action callback that receives the value before the iterator returns it - * @return a peeked iterator - */ - public static LongIterator peek(Iterator iterator, LongConsumer action) { - return new PeekIterator(wrap(iterator), action); - } - - /** - * Helper function to convert a Object Iterator into a Primitive Iterator - * @param iterator that should be converted to a unboxing iterator - * @return a primitive iterator - */ - public static LongIterator wrap(Iterator iterator) { - return iterator instanceof LongIterator ? (LongIterator)iterator : new IteratorWrapper(iterator); - } - - /** - * Returns a Array Wrapping iterator - * @param a the array that should be wrapped - * @return a Iterator that is wrapping a array. - */ - public static ArrayIterator wrap(long... a) { - return wrap(a, 0, a.length); - } - - /** - * Returns a Array Wrapping iterator - * @param a the array that should be wrapped. - * @param start the index to be started from. - * @param end the index that should be ended. - * @return a Iterator that is wrapping a array. - */ - public static ArrayIterator wrap(long[] a, int start, int end) { - return new ArrayIterator(a, start, end); - } - - /** - * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted - * @param a where the elements should be inserted - * @param i the source iterator - * @return the amount of elements that were inserted into the array. - */ - public static int unwrap(long[] a, Iterator i) { - return unwrap(a, i, 0, a.length); - } - - /** - * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted - * @param a where the elements should be inserted - * @param i the source iterator - * @param offset the array offset where the start should be - * @return the amount of elements that were inserted into the array. - */ - public static int unwrap(long[] a, Iterator i, int offset) { - return unwrap(a, i, offset, a.length - offset); - } - - /** - * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted - * @param a where the elements should be inserted - * @param i the source iterator - * @param offset the array offset where the start should be - * @param max the maximum values that should be extracted from the source - * @return the amount of elements that were inserted into the array. - * @throws IllegalStateException if max is smaller the 0 or if the maximum index is larger then the array - */ - public static int unwrap(long[] a, Iterator i, int offset, int max) { - if(max < 0) throw new IllegalStateException("The max size is smaller then 0"); - if(offset + max > a.length) throw new IllegalStateException("largest array index exceeds array size"); - int index = 0; - for(;index a.length) throw new IllegalStateException("largest array index exceeds array size"); - int index = 0; - for(;index a.length) throw new IllegalStateException("largest array index exceeds array size"); - int index = 0; - for(;index iter; - - public IteratorWrapper(Iterator iter) { - this.iter = iter; - } - - @Override - public boolean hasNext() { - return iter.hasNext(); - } - - @Override - public long nextLong() { - return iter.next().longValue(); - } - - @Override - @Deprecated - public Long next() { - return iter.next(); - } - } - - private static class ConcatIterator implements LongIterator - { - LongIterator[] iters; - int offset; - int lastOffset = -1; - int length; - - public ConcatIterator(LongIterator[] iters, int offset, int length) { - this.iters = iters; - this.offset = offset; - this.length = length; - find(); - } - - private void find() { - for(;length != 0 && !iters[offset].hasNext();length--, offset++); - } - - @Override - public boolean hasNext() { - return length > 0; - } - - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - long result = iters[lastOffset = offset].nextLong(); - find(); - return result; - } - - @Override - public void remove() { - if(lastOffset == -1) throw new IllegalStateException(); - iters[lastOffset].remove(); - lastOffset = -1; - } - } - - private static class ReverseBiIterator implements LongBidirectionalIterator { - LongBidirectionalIterator it; - - ReverseBiIterator(LongBidirectionalIterator it) { - this.it = it; - } - - @Override - public long nextLong() { return it.previousLong(); } - @Override - public boolean hasNext() { return it.hasPrevious(); } - @Override - public boolean hasPrevious() { return it.hasNext(); } - @Override - public long previousLong() { return it.nextLong(); } - @Override - public void remove() { it.remove(); } - } - - private static class ReverseListIterator implements LongListIterator { - LongListIterator it; - - ReverseListIterator(LongListIterator it) { - this.it = it; - } - - @Override - public long nextLong() { return it.previousLong(); } - @Override - public boolean hasNext() { return it.hasPrevious(); } - @Override - public boolean hasPrevious() { return it.hasNext(); } - @Override - public long previousLong() { return it.nextLong(); } - @Override - public void remove() { it.remove(); } - @Override - public int nextIndex() { return it.previousIndex(); } - @Override - public int previousIndex() { return it.nextIndex(); } - @Override - public void set(long e) { it.set(e); } - @Override - public void add(long e) { it.add(e); } - } - - private static class UnmodifiableListIterator implements LongListIterator - { - LongListIterator iter; - - UnmodifiableListIterator(LongListIterator iter) { - this.iter = iter; - } - - @Override - public boolean hasNext() { - return iter.hasNext(); - } - - @Override - public boolean hasPrevious() { - return iter.hasPrevious(); - } - - @Override - public int nextIndex() { - return iter.nextIndex(); - } - - @Override - public int previousIndex() { - return iter.previousIndex(); - } - - @Override - public void remove() { throw new UnsupportedOperationException(); } - - @Override - public long previousLong() { - return iter.previousLong(); - } - - @Override - public long nextLong() { - return iter.nextLong(); - } - - @Override - public void set(long e) { throw new UnsupportedOperationException(); } - - @Override - public void add(long e) { throw new UnsupportedOperationException(); } - } - - private static class UnmodifiableBiIterator implements LongBidirectionalIterator - { - LongBidirectionalIterator iter; - - UnmodifiableBiIterator(LongBidirectionalIterator iter) { - this.iter = iter; - } - - @Override - public long nextLong() { - return iter.nextLong(); - } - - @Override - public boolean hasNext() { - return iter.hasNext(); - } - - @Override - public boolean hasPrevious() { - return iter.hasPrevious(); - } - - @Override - public long previousLong() { - return iter.previousLong(); - } - } - - private static class UnmodifiableIterator implements LongIterator - { - LongIterator iterator; - - UnmodifiableIterator(LongIterator iterator) { - this.iterator = iterator; - } - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public long nextLong() { - return iterator.nextLong(); - } - } - - private static class EmptyIterator implements LongListIterator - { - @Override - public boolean hasNext() { return false; } - @Override - public long nextLong() { throw new NoSuchElementException(); } - @Override - public boolean hasPrevious() { return false; } - @Override - public long previousLong() { throw new NoSuchElementException(); } - @Override - public int nextIndex() { return 0; } - @Override - public int previousIndex() { return -1; } - @Override - public void remove() { throw new UnsupportedOperationException(); } - @Override - public void set(long e) { throw new UnsupportedOperationException(); } - @Override - public void add(long e) { throw new UnsupportedOperationException(); } - } - - private static class ArrayIterator implements LongIterator - { - long[] a; - int from; - int to; - - ArrayIterator(long[] a, int from, int to) { - this.a = a; - this.from = from; - this.to = to; - } - - @Override - public boolean hasNext() { - return from < to; - } - - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - return a[from++]; - } - - @Override - public int skip(int amount) { - if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); - int left = Math.min(amount, to - from); - from += left; - return amount - left; - } - } - - private static class MappedIterator implements ObjectIterator - { - LongIterator iterator; - LongFunction mapper; - - MappedIterator(LongIterator iterator, LongFunction mapper) { - this.iterator = iterator; - this.mapper = mapper; - } - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public T next() { - return mapper.apply(iterator.nextLong()); - } - - @Override - public int skip(int amount) { - return iterator.skip(amount); - } - } - - private static class FlatMappedIterator> implements ObjectIterator - { - LongIterator iterator; - Iterator last = null; - LongFunction mapper; - boolean foundNext = false; - - FlatMappedIterator(LongIterator iterator, LongFunction mapper) { - this.iterator = iterator; - this.mapper = mapper; - } - - void compute() { - if(foundNext) return; - foundNext = true; - while(iterator.hasNext()) { - if(last != null && last.hasNext()) return; - last = mapper.apply(iterator.nextLong()).iterator(); - } - } - - @Override - public boolean hasNext() { - compute(); - return last != null && last.hasNext(); - } - - @Override - public T next() { - if(!hasNext()) throw new NoSuchElementException(); - T result = last.next(); - foundNext = false; - return result; - } - } - - private static class FlatMappedArrayIterator implements ObjectIterator - { - LongIterator iterator; - Iterator last = null; - LongFunction mapper; - boolean foundNext = false; - - FlatMappedArrayIterator(LongIterator iterator, LongFunction mapper) { - this.iterator = iterator; - this.mapper = mapper; - } - - void compute() { - if(foundNext) return; - foundNext = true; - while(iterator.hasNext()) { - if(last != null && last.hasNext()) return; - last = ObjectIterators.wrap(mapper.apply(iterator.nextLong())); - } - } - - @Override - public boolean hasNext() { - compute(); - return last != null && last.hasNext(); - } - - @Override - public T next() { - if(!hasNext()) throw new NoSuchElementException(); - T result = last.next(); - foundNext = false; - return result; - } - } - - private static class RepeatingIterator implements LongIterator - { - final int repeats; - int index = 0; - LongIterator iter; - LongCollection repeater = LongCollections.wrapper(); - - public RepeatingIterator(LongIterator iter, int repeat) { - this.iter = iter; - this.repeats = repeat; - } - - @Override - public boolean hasNext() { - if(iter.hasNext()) return true; - if(index < repeats) { - index++; - iter = repeater.iterator(); - return iter.hasNext(); - } - return false; - } - - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - long value = iter.nextLong(); - if(index == 0) repeater.add(value); - return value; - } - } - - private static class SortedIterator implements LongIterator - { - LongIterator iterator; - LongComparator sorter; - LongCollections.CollectionWrapper sortedElements = null; - int index = 0; - - public SortedIterator(LongIterator iterator, LongComparator sorter) { - this.iterator = iterator; - this.sorter = sorter; - } - - @Override - public boolean hasNext() { - if(sortedElements == null) { - boolean hasNext = iterator.hasNext(); - if(hasNext) { - sortedElements = LongCollections.wrapper(); - pour(iterator, sortedElements); - } - else sortedElements = LongCollections.wrapper(); - if(hasNext) sortedElements.unstableSort(sorter); - } - return index < sortedElements.size(); - } - - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - return sortedElements.getLong(index++); - } - } - - private static class DistinctIterator implements LongIterator - { - LongIterator iterator; - LongCollection filtered = LongCollections.distinctWrapper(); - long lastFound; - boolean foundNext = false; - - public DistinctIterator(LongIterator iterator) { - this.iterator = iterator; - } - - void compute() { - if(foundNext) return; - while(iterator.hasNext()) { - lastFound = iterator.nextLong(); - if(filtered.add(lastFound)) { - foundNext = true; - break; - } - } - } - - @Override - public boolean hasNext() { - compute(); - return foundNext; - } - - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - foundNext = false; - return lastFound; - } - } - - private static class FilteredIterator implements LongIterator - { - LongIterator iterator; - LongPredicate filter; - long lastFound; - boolean foundNext = false; - - public FilteredIterator(LongIterator iterator, LongPredicate filter) { - this.iterator = iterator; - this.filter = filter; - } - - void compute() { - if(foundNext) return; - while(iterator.hasNext()) { - lastFound = iterator.nextLong(); - if(filter.test(lastFound)) { - foundNext = true; - break; - } - } - } - - @Override - public boolean hasNext() { - compute(); - return foundNext; - } - - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - foundNext = false; - return lastFound; - } - } - - private static class LimitedIterator implements LongIterator - { - LongIterator iterator; - long limit; - - public LimitedIterator(LongIterator iterator, long limit) { - this.iterator = iterator; - this.limit = limit; - } - - @Override - public boolean hasNext() { - return limit > 0 && iterator.hasNext(); - } - - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - limit--; - return iterator.nextLong(); - } - } - - private static class PeekIterator implements LongIterator - { - LongIterator iterator; - LongConsumer action; - - public PeekIterator(LongIterator iterator, LongConsumer action) { - this.iterator = iterator; - this.action = action; - } - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - long result = iterator.nextLong(); - action.accept(result); - return result; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/longs/utils/LongSplititerators.java b/src/main/java/speiger/src/collections/longs/utils/LongSplititerators.java deleted file mode 100644 index 1456acbc0..000000000 --- a/src/main/java/speiger/src/collections/longs/utils/LongSplititerators.java +++ /dev/null @@ -1,461 +0,0 @@ -package speiger.src.collections.longs.utils; - -import java.util.Comparator; -import java.util.NoSuchElementException; -import java.util.Spliterator; -import java.util.Spliterator.OfLong; -import java.util.function.Consumer; - -import speiger.src.collections.longs.collections.LongCollection; -import speiger.src.collections.longs.collections.LongIterator; -import speiger.src.collections.longs.collections.LongSplititerator; -import speiger.src.collections.longs.functions.LongConsumer; -import speiger.src.collections.utils.SanityChecks; - -/** - * Helper class that provides SplitIterators for normal and stream usage - */ -public class LongSplititerators -{ - /** - * Creates A stream compatible split iterator without copying the original array or boxing - * @param array that should be wrapped into a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - */ - public static OfLong createArrayJavaSplititerator(long[] array, int characteristics) { return createArrayJavaSplititerator(array, 0, array.length, characteristics);} - /** - * Creates A stream compatible split iterator without copying the original array or boxing - * @param array that should be wrapped into a split iterator - * @param size the maximum index within the array - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - * @throws IllegalStateException if the size is outside of the array size - */ - public static OfLong createArrayJavaSplititerator(long[] array, int size, int characteristics) { return createArrayJavaSplititerator(array, 0, size, characteristics);} - /** - * Creates A stream compatible split iterator without copying the original array or boxing - * @param array that should be wrapped into a split iterator - * @param offset the starting index of the array - * @param size the maximum index within the array - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - * @throws IllegalStateException the offset and size are outside of the arrays range - */ - public static OfLong createArrayJavaSplititerator(long[] array, int offset, int size, int characteristics) { - SanityChecks.checkArrayCapacity(array.length, offset, size); - return new ArraySplitIterator(array, offset, size, characteristics); - } - - /** - * Creates a stream compatible split iterator without copying it or boxing it - * @param collection the collection that should be wrapped in a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - */ - public static OfLong createJavaSplititerator(LongCollection collection, int characteristics) { - return new IteratorSpliterator(collection, characteristics); - } - - /** - * Creates a stream compatible split iterator without copying it or boxing it - * @param iterator the Iterator that should be wrapped in a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - */ - public static OfLong createUnknownJavaSplititerator(LongIterator iterator, int characteristics) { - return new IteratorSpliterator(iterator, characteristics); - } - - /** - * Creates a stream compatible split iterator without copying it or boxing it - * @param iterator the collection that should be wrapped in a split iterator - * @param size the amount of elements in the iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a split iterator of a Stream compatible type - */ - public static OfLong createSizedJavaSplititerator(LongIterator iterator, long size, int characteristics) { - return new IteratorSpliterator(iterator, size, characteristics); - } - - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param array that should be wrapped into a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - */ - public static LongSplititerator createArraySplititerator(long[] array, int characteristics) { return createArraySplititerator(array, 0, array.length, characteristics);} - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param array that should be wrapped into a split iterator - * @param size the maximum index within the array - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - * @throws IllegalStateException if the size is outside of the array size - */ - public static LongSplititerator createArraySplititerator(long[] array, int size, int characteristics) { return createArraySplititerator(array, 0, size, characteristics);} - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param array that should be wrapped into a split iterator - * @param offset the starting index of the array - * @param size the maximum index within the array - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - * @throws IllegalStateException the offset and size are outside of the arrays range - */ - public static LongSplititerator createArraySplititerator(long[] array, int offset, int size, int characteristics) { - SanityChecks.checkArrayCapacity(array.length, offset, size); - return new TypeArraySplitIterator(array, offset, size, characteristics); - } - - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param collection the collection that should be wrapped in a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - */ - public static LongSplititerator createSplititerator(LongCollection collection, int characteristics) { - return new TypeIteratorSpliterator(collection, characteristics); - } - - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param iterator the Iterator that should be wrapped in a split iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - */ - public static LongSplititerator createUnknownSplititerator(LongIterator iterator, int characteristics) { - return new TypeIteratorSpliterator(iterator, characteristics); - } - - /** - * Creates a Type Specific SplitIterator to reduce boxing/unboxing - * @param iterator the collection that should be wrapped in a split iterator - * @param size the amount of elements in the iterator - * @param characteristics characteristics properties of this spliterator's source or elements. - * @return a Type Specific SplitIterator - */ - public static LongSplititerator createSizedSplititerator(LongIterator iterator, long size, int characteristics) { - return new TypeIteratorSpliterator(iterator, size, characteristics); - } - - static class TypeIteratorSpliterator implements LongSplititerator { - static final int BATCH_UNIT = 1 << 10; - static final int MAX_BATCH = 1 << 25; - private final LongCollection collection; - private LongIterator it; - private final int characteristics; - private long est; - private int batch; - - TypeIteratorSpliterator(LongCollection collection, int characteristics) { - this.collection = collection; - it = null; - this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 - ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED - : characteristics; - } - - TypeIteratorSpliterator(LongIterator iterator, long size, int characteristics) { - collection = null; - it = iterator; - est = size; - this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 - ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED - : characteristics; - } - - TypeIteratorSpliterator(LongIterator iterator, int characteristics) { - collection = null; - it = iterator; - est = Long.MAX_VALUE; - this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); - } - - private LongIterator iterator() - { - if (it == null) { - it = collection.iterator(); - est = collection.size(); - } - return it; - } - - @Override - public LongSplititerator trySplit() { - LongIterator i = iterator(); - if (est > 1 && i.hasNext()) { - int n = Math.min(batch + BATCH_UNIT, Math.min((int)est, MAX_BATCH)); - long[] a = new long[n]; - int j = 0; - do { a[j] = i.nextLong(); } while (++j < n && i.hasNext()); - batch = j; - if (est != Long.MAX_VALUE) - est -= j; - return new TypeArraySplitIterator(a, 0, j, characteristics); - } - return null; - } - - @Override - public void forEachRemaining(LongConsumer action) { - if (action == null) throw new NullPointerException(); - iterator().forEachRemaining(action); - } - - @Override - public boolean tryAdvance(LongConsumer action) { - if (action == null) throw new NullPointerException(); - LongIterator iter = iterator(); - if (iter.hasNext()) { - action.accept(iter.nextLong()); - return true; - } - return false; - } - - @Override - public boolean tryAdvance(Consumer action) { - if (action == null) throw new NullPointerException(); - LongIterator iter = iterator(); - if (iter.hasNext()) { - action.accept(Long.valueOf(iter.nextLong())); - return true; - } - return false; - } - - @Override - public long estimateSize() { - iterator(); - return est; - } - - @Override - public int characteristics() { return characteristics; } - - @Override - public Comparator getComparator() { - if (hasCharacteristics(4)) //Sorted - return null; - throw new IllegalStateException(); - } - - @Override - public long nextLong() { return iterator().nextLong(); } - - @Override - public boolean hasNext() { return iterator().hasNext(); } - } - - static final class TypeArraySplitIterator implements LongSplititerator { - private final long[] array; - private int index; - private final int fence; - private final int characteristics; - - public TypeArraySplitIterator(long[] array, int origin, int fence, int additionalCharacteristics) { - this.array = array; - index = origin; - this.fence = fence; - characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; - } - - @Override - public LongSplititerator trySplit() { - int lo = index, mid = (lo + fence) >>> 1; - return (lo >= mid) ? null : new TypeArraySplitIterator(array, lo, index = mid, characteristics); - } - - @Override - public void forEachRemaining(LongConsumer action) { - if (action == null) throw new NullPointerException(); - long[] a; int i, hi; - if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) { - do { action.accept(a[i]); } while (++i < hi); - } - } - - @Override - public boolean tryAdvance(LongConsumer action) { - if (action == null) throw new NullPointerException(); - if (index >= 0 && index < fence) { - action.accept(array[index++]); - return true; - } - return false; - } - - @Override - public boolean tryAdvance(Consumer action) { - if (action == null) throw new NullPointerException(); - if (index >= 0 && index < fence) { - action.accept(Long.valueOf(array[index++])); - return true; - } - return false; - } - - @Override - public long estimateSize() { return fence - index; } - @Override - public int characteristics() { return characteristics; } - @Override - public Comparator getComparator() { - if (hasCharacteristics(4)) //Sorted - return null; - throw new IllegalStateException(); - } - - @Override - public long nextLong() { - if(!hasNext()) throw new NoSuchElementException(); - return array[index++]; - } - - @Override - public boolean hasNext() { return index < fence; } - } - - static class IteratorSpliterator implements OfLong { - static final int BATCH_UNIT = 1 << 10; - static final int MAX_BATCH = 1 << 25; - private final LongCollection collection; - private LongIterator it; - private final int characteristics; - private long est; - private int batch; - - IteratorSpliterator(LongCollection collection, int characteristics) { - this.collection = collection; - it = null; - this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 - ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED - : characteristics; - } - - IteratorSpliterator(LongIterator iterator, long size, int characteristics) { - collection = null; - it = iterator; - est = size; - this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 - ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED - : characteristics; - } - - IteratorSpliterator(LongIterator iterator, int characteristics) { - collection = null; - it = iterator; - est = Long.MAX_VALUE; - this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); - } - - private LongIterator iterator() - { - if (it == null) { - it = collection.iterator(); - est = collection.size(); - } - return it; - } - - @Override - public OfLong trySplit() { - LongIterator i = iterator(); - if (est > 1 && i.hasNext()) { - int n = Math.min(batch + BATCH_UNIT, Math.min((int)est, MAX_BATCH)); - long[] a = new long[n]; - int j = 0; - do { a[j] = i.nextLong(); } while (++j < n && i.hasNext()); - batch = j; - if (est != Long.MAX_VALUE) - est -= j; - return new ArraySplitIterator(a, 0, j, characteristics); - } - return null; - } - - @Override - public void forEachRemaining(java.util.function.LongConsumer action) { - if (action == null) throw new NullPointerException(); - iterator().forEachRemaining(T -> action.accept(T)); - } - - @Override - public boolean tryAdvance(java.util.function.LongConsumer action) { - if (action == null) throw new NullPointerException(); - LongIterator iter = iterator(); - if (iter.hasNext()) { - action.accept(iter.nextLong()); - return true; - } - return false; - } - - @Override - public long estimateSize() { - iterator(); - return est; - } - - @Override - public int characteristics() { return characteristics; } - - @Override - public Comparator getComparator() { - if (hasCharacteristics(4)) //Sorted - return null; - throw new IllegalStateException(); - } - } - - static final class ArraySplitIterator implements OfLong { - private final long[] array; - private int index; - private final int fence; - private final int characteristics; - - public ArraySplitIterator(long[] array, int origin, int fence, int additionalCharacteristics) { - this.array = array; - index = origin; - this.fence = fence; - characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; - } - - @Override - public OfLong trySplit() { - int lo = index, mid = (lo + fence) >>> 1; - return (lo >= mid) ? null : new ArraySplitIterator(array, lo, index = mid, characteristics); - } - - @Override - public void forEachRemaining(java.util.function.LongConsumer action) { - if (action == null) throw new NullPointerException(); - long[] a; int i, hi; - if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) { - do { action.accept(a[i]); } while (++i < hi); - } - } - - @Override - public boolean tryAdvance(java.util.function.LongConsumer action) { - if (action == null) throw new NullPointerException(); - if (index >= 0 && index < fence) { - action.accept(array[index++]); - return true; - } - return false; - } - - @Override - public long estimateSize() { return fence - index; } - @Override - public int characteristics() { return characteristics; } - @Override - public Comparator getComparator() { - if (hasCharacteristics(4)) //Sorted - return null; - throw new IllegalStateException(); - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/collections/AbstractObjectCollection.java b/src/main/java/speiger/src/collections/objects/collections/AbstractObjectCollection.java deleted file mode 100644 index 13080cf5c..000000000 --- a/src/main/java/speiger/src/collections/objects/collections/AbstractObjectCollection.java +++ /dev/null @@ -1,167 +0,0 @@ -package speiger.src.collections.objects.collections; - -import java.util.Collection; -import java.util.Objects; -import java.util.AbstractCollection; -import java.util.function.Consumer; - -import speiger.src.collections.objects.utils.ObjectArrays; - -/** - * Abstract Type Specific Collection that reduces boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public abstract class AbstractObjectCollection extends AbstractCollection implements ObjectCollection -{ - @Override - public abstract ObjectIterator iterator(); - - @Override - public boolean addAll(ObjectCollection c) { - boolean modified = false; - for(ObjectIterator iter = c.iterator();iter.hasNext();modified |= add(iter.next())); - return modified; - } - - @Override - public ObjectCollection copy() { throw new UnsupportedOperationException(); } - - - /** - * A Type-Specific implementation of containsAll. This implementation iterates over all elements and checks all elements are present in the other collection. - * @param c the collection that should be checked if it contains all elements. - * @return true if all elements were found in the collection - * @throws NullPointerException if the collection is null - */ - @Override - public boolean containsAll(ObjectCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return true; - for(ObjectIterator iter = c.iterator();iter.hasNext();) - if(!contains(iter.next())) - return false; - return true; - } - - @Override - public boolean containsAll(Collection c) { - Objects.requireNonNull(c); - return c instanceof ObjectCollection ? containsAll((ObjectCollection)c) : super.containsAll(c); - } - - /** - * This implementation iterates over the elements of the collection and checks if they are stored in this collection - * @param c the elements that should be checked for - * @return true if any element is in this collection - * @throws NullPointerException if the collection is null - */ - @Override - public boolean containsAny(Collection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - for(Object e : c) - if(contains(e)) - return true; - return false; - } - - /** - * This implementation iterates over the elements of the collection and checks if they are stored in this collection. - * @param c the elements that should be checked for - * @return true if any element is in this collection - * @throws NullPointerException if the collection is null - */ - @Override - public boolean containsAny(ObjectCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - for(ObjectIterator iter = c.iterator();iter.hasNext();) - if(contains(iter.next())) - return true; - return false; - } - - /** - * A Type-Specific implementation of removeAll. This Implementation iterates over all elements and removes them as they were found in the other collection. - * @param c the elements that should be deleted - * @return true if the collection was modified. - * @throws NullPointerException if the collection is null - */ - @Override - public boolean removeAll(ObjectCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - boolean modified = false; - for(ObjectIterator iter = iterator();iter.hasNext();) { - if(c.contains(iter.next())) { - iter.remove(); - modified = true; - } - } - return modified; - } - - @Override - public boolean removeAll(ObjectCollection c, Consumer r) { - Objects.requireNonNull(c); - if(c.isEmpty()) return false; - Objects.requireNonNull(r); - boolean modified = false; - for(ObjectIterator iter = iterator();iter.hasNext();) { - T e = iter.next(); - if(c.contains(e)) { - r.accept(e); - iter.remove(); - modified = true; - } - } - return modified; - } - - /** - * A Type-Specific implementation of retainAll. This Implementation iterates over all elements and removes them as they were not found in the other collection. - * @param c the elements that should be kept - * @return true if the collection was modified. - * @throws NullPointerException if the collection is null - */ - @Override - public boolean retainAll(ObjectCollection c) { - Objects.requireNonNull(c); - if(c.isEmpty()) { - boolean modified = !isEmpty(); - clear(); - return modified; - } - boolean modified = false; - for(ObjectIterator iter = iterator();iter.hasNext();) { - if(!c.contains(iter.next())) { - iter.remove(); - modified = true; - } - } - return modified; - } - - @Override - public boolean retainAll(ObjectCollection c, Consumer r) { - Objects.requireNonNull(c); - Objects.requireNonNull(r); - if(c.isEmpty()) { - boolean modified = !isEmpty(); - forEach(r); - clear(); - return modified; - } - boolean modified = false; - for(ObjectIterator iter = iterator();iter.hasNext();) { - T e = iter.next(); - if(!c.contains(e)) { - r.accept(e); - iter.remove(); - modified = true; - } - } - return modified; - } - -} diff --git a/src/main/java/speiger/src/collections/objects/collections/ObjectBidirectionalIterator.java b/src/main/java/speiger/src/collections/objects/collections/ObjectBidirectionalIterator.java deleted file mode 100644 index 1d1d77cdc..000000000 --- a/src/main/java/speiger/src/collections/objects/collections/ObjectBidirectionalIterator.java +++ /dev/null @@ -1,34 +0,0 @@ -package speiger.src.collections.objects.collections; - -/** - * This is a basically a {@link java.util.ListIterator} without the index functions. - * Allowing to have a simple Bidirectional Iterator without having to keep track of the Iteration index. - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectBidirectionalIterator extends ObjectIterator -{ - /** - * Returns true if the Iterator has a Previous element - * @return true if the Iterator has a Previous element - */ - public boolean hasPrevious(); - - /** - * Returns the Previous element of the iterator. - * @return the Previous element of the iterator. - * @throws java.util.NoSuchElementException if the iteration has no more elements - */ - public T previous(); - - /** - * Reverses the Given amount of elements if possible. A Optimization function to reverse elements faster if the implementation allows it. - * @param amount the amount of elements that should be reversed - * @return the amount of elements that were reversed - */ - public default int back(int amount) { - if(amount < 0) throw new IllegalStateException("Can't go forward"); - int i = 0; - for(;i the keyType of elements maintained by this Collection - */ -public interface ObjectCollection extends Collection, ObjectIterable, ISizeProvider -{ - /** - * A Type-Specific addAll function to reduce (un)boxing - * @param c the collection of elements that should be added - * @return true if elements were added into the collection - */ - public boolean addAll(ObjectCollection c); - - /** - * A Type-Specific Array based addAll method to reduce the amount of Wrapping - * @param e the elements that should be added - * @return if the collection was modified - */ - public default boolean addAll(T... e) { return addAll(e, 0, e.length); } - - /** - * A Type-Specific Array based addAll method to reduce the amount of Wrapping - * @param e the elements that should be added - * @param length how many elements of the array should be added - * @return if the collection was modified - */ - public default boolean addAll(T[] e, int length) { return addAll(e, 0, length); } - - /** - * A Type-Specific Array based addAll method to reduce the amount of Wrapping - * @param e the elements that should be added - * @param offset where to start within the array - * @param length how many elements of the array should be added - * @return if the collection was modified - */ - public default boolean addAll(T[] e, int offset, int length) { - if(length <= 0) return false; - SanityChecks.checkArrayCapacity(e.length, offset, length); - boolean added = false; - for(int i = 0;i c); - - /** - * A Type-Specific containsAny function to reduce (un)boxing - * @param c the collection of elements that should be tested for - * @return true if any element was found - */ - public boolean containsAny(ObjectCollection c); - - /** - * Returns true if any element of the Collection is found in the provided collection. - * A Small Optimization function to find out of any element is present when comparing collections and not all of them. - * @param c the collection of elements that should be tested for - * @return true if any element was found. - */ - public boolean containsAny(Collection c); - - /** - * A Type-Specific removeAll function that reduces (un)boxing. - * @param c the collection of elements that should be removed - * @return true if any element was removed - * @see Collection#removeAll(Collection) - */ - public boolean removeAll(ObjectCollection c); - - /** - * A Type-Specific removeAll function that reduces (un)boxing. - * It also notifies the remover of which exact element is going to be removed. - * @param c the collection of elements that should be removed - * @param r elements that got removed - * @return true if any element was removed - * @see Collection#removeAll(Collection) - */ - public boolean removeAll(ObjectCollection c, Consumer r); - - /** - * A Type-Specific retainAll function that reduces (un)boxing. - * @param c the collection of elements that should be kept - * @return true if any element was removed - * @see Collection#retainAll(Collection) - */ - public boolean retainAll(ObjectCollection c); - - /** - * A Type-Specific retainAll function that reduces (un)boxing. - * It also notifies the remover of which exact element is going to be removed. - * @param c the collection of elements that should be kept - * @param r elements that got removed - * @return true if any element was removed - * @see Collection#retainAll(Collection) - */ - public boolean retainAll(ObjectCollection c, Consumer r); - - /** - * A Helper function to reduce the usage of Streams and allows to collect all elements - * @param collection that the elements should be inserted to - * @param the collection type - * @return the input with the desired elements - */ - default > E pour(E collection) { - collection.addAll(this); - return collection; - } - - /** - * A Function that does a shallow clone of the Collection itself. - * This function is more optimized then a copy constructor since the Collection does not have to be unsorted/resorted. - * It can be compared to Cloneable but with less exception risk - * @return a Shallow Copy of the collection - * @note Wrappers and view collections will not support this feature - */ - public ObjectCollection copy(); - - /** - * A Helper function that simplifies the process of creating a new Array. - * @param action the array creation function - * @return an array containing all of the elements in this collection - * @see Collection#toArray(Object[]) - */ - default E[] toArray(IntFunction action) { - return toArray(action.apply(size())); - } - - /** - * Returns a Type-Specific Iterator to reduce (un)boxing - * @return a iterator of the collection - * @see Collection#iterator() - */ - @Override - public ObjectIterator iterator(); - - /** - * Creates a Wrapped Collection that is Synchronized - * @return a new Collection that is synchronized - * @see ObjectCollections#synchronize - */ - public default ObjectCollection synchronize() { return ObjectCollections.synchronize(this); } - - /** - * Creates a Wrapped Collection that is Synchronized - * @param mutex is the controller of the synchronization block - * @return a new Collection Wrapper that is synchronized - * @see ObjectCollections#synchronize - */ - public default ObjectCollection synchronize(Object mutex) { return ObjectCollections.synchronize(this, mutex); } - - /** - * Creates a Wrapped Collection that is unmodifiable - * @return a new Collection Wrapper that is unmodifiable - * @see ObjectCollections#unmodifiable - */ - public default ObjectCollection unmodifiable() { return ObjectCollections.unmodifiable(this); } - - - /** - * A Type Specific Type Splititerator to reduce boxing/unboxing - * @return type specific splititerator - */ - @Override - default ObjectSplititerator spliterator() { return ObjectSplititerators.createSplititerator(this, 0); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/collections/ObjectIterable.java b/src/main/java/speiger/src/collections/objects/collections/ObjectIterable.java deleted file mode 100644 index 792ba6ab0..000000000 --- a/src/main/java/speiger/src/collections/objects/collections/ObjectIterable.java +++ /dev/null @@ -1,297 +0,0 @@ -package speiger.src.collections.objects.collections; - -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Predicate; - -import java.util.function.BiFunction; -import java.util.function.IntFunction; -import java.util.Comparator; - -import speiger.src.collections.objects.functions.function.UnaryOperator; -import speiger.src.collections.ints.functions.consumer.IntObjectConsumer; -import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer; -import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator; -import speiger.src.collections.objects.lists.ObjectList; -import speiger.src.collections.objects.lists.ObjectArrayList; - -import speiger.src.collections.objects.utils.ObjectArrays; -import speiger.src.collections.objects.utils.ObjectSplititerators; -import speiger.src.collections.objects.utils.ObjectIterables; -import speiger.src.collections.objects.utils.ObjectIterators; -import speiger.src.collections.utils.ISizeProvider; - -/** - * A Type-Specific {@link Iterable} that reduces (un)boxing - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectIterable extends Iterable -{ - /** - * Returns an iterator over elements of type {@code T}. - * - * @return an Iterator. - */ - @Override - ObjectIterator iterator(); - - /** - * A Indexed forEach implementation that allows you to keep track of how many elements were already iterated over. - * @param action The action to be performed for each element - * @throws NullPointerException if the specified action is null - */ - public default void forEachIndexed(IntObjectConsumer action) { - Objects.requireNonNull(action); - int index = 0; - for(ObjectIterator iter = iterator();iter.hasNext();action.accept(index++, iter.next())); - } - - /** - * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. - * @param input the object that should be included - * @param action The action to be performed for each element - * @param the generic type of the Object - * @throws NullPointerException if the specified action is null - */ - default void forEach(E input, ObjectObjectConsumer action) { - Objects.requireNonNull(action); - iterator().forEachRemaining(input, action); - } - - /** - * A Type Specific Type Splititerator to reduce boxing/unboxing - * @return type specific splititerator - */ - @Override - default ObjectSplititerator spliterator() { return ObjectSplititerators.createUnknownSplititerator(iterator(), 0); } - - /** - * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. - * @param mapper the mapping function - * @param The return type. - * @return a new Iterable that returns the desired result - */ - default ObjectIterable map(UnaryOperator mapper) { - return ObjectIterables.map(this, mapper); - } - - /** - * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. - * @param mapper the flatMapping function - * @param The return type supplier. - * @param The return type. - * @return a new Iterable that returns the desired result - * @note does not support toArray optimizations. - */ - default > ObjectIterable flatMap(UnaryOperator mapper) { - return ObjectIterables.flatMap(this, mapper); - } - - /** - * A Helper function to reduce the usage of Streams and allows to convert a Iterable to something else. - * @param mapper the flatMapping function - * @param The return type. - * @return a new Iterable that returns the desired result - * @note does not support toArray optimizations. - */ - default ObjectIterable arrayflatMap(UnaryOperator mapper) { - return ObjectIterables.arrayFlatMap(this, mapper); - } - - /** - * A Helper function to reduce the usage of Streams and allows to filter out unwanted elements - * @param filter the elements that should be kept. - * @return a Iterable that filtered out all unwanted elements - * @note does not support toArray optimizations. - */ - default ObjectIterable filter(Predicate filter) { - return ObjectIterables.filter(this, filter); - } - - /** - * A Helper function to reduce the usage of Streams and allows to filter out duplicated elements - * @return a Iterable that filtered out all duplicated elements - * @note does not support toArray optimizations. - */ - default ObjectIterable distinct() { - return ObjectIterables.distinct(this); - } - - /** - * A Helper function to reduce the usage of Streams and allows to repeat elements a desired amount of times - * @param repeats how many times the elements should be repeated - * @return a Iterable that is repeating multiple times - */ - default ObjectIterable repeat(int repeats) { - return ObjectIterables.repeat(this, repeats); - } - - /** - * A Helper function to reduce the usage of Streams and allows to limit the amount of elements - * @param limit the amount of elements it should be limited to - * @return a Iterable that is limited in length - */ - default ObjectIterable limit(long limit) { - return ObjectIterables.limit(this, limit); - } - - /** - * A Helper function to reduce the usage of Streams and allows to sort the elements - * @param sorter that sorts the elements. - * @return a Iterable that is sorted - */ - default ObjectIterable sorted(Comparator sorter) { - return ObjectIterables.sorted(this, sorter); - } - - /** - * A Helper function to reduce the usage of Streams and allows to preview elements before they are iterated through - * @param action the action that should be applied - * @return a Peeked Iterable - */ - default ObjectIterable peek(Consumer action) { - return ObjectIterables.peek(this, action); - } - - /** - * A Helper function to reduce the usage of Streams and allows to collect all elements - * @param collection that the elements should be inserted to - * @param the collection type - * @return the input with the desired elements - */ - default > E pour(E collection) { - ObjectIterators.pour(iterator(), collection); - return collection; - } - - /** - * A Helper function that reduces the usage of streams and allows to collect all elements as a ArrayList - * @return a new ArrayList of all elements - */ - default ObjectList pourAsList() { - return pour(new ObjectArrayList<>()); - } - - - /** - * A Helper function that reduces the usage of streams and allows to collect all elements as a Array - * @param action is the creator function of said Array to ensure type is kept. - * @return a new Array of all elements - */ - default E[] toArray(IntFunction action) { - ISizeProvider prov = ISizeProvider.of(this); - if(prov != null) { - int size = prov.size(); - if(size >= 0) { - E[] array = action.apply(size); - ObjectIterators.unwrap(array, iterator()); - return array; - } - } - return ObjectArrays.pour(iterator(), action); - } - /** - * Helper function to reduce stream usage that allows to filter for any matches. - * @param filter that should be applied - * @return true if any matches were found - */ - default boolean matchesAny(Predicate filter) { - Objects.requireNonNull(filter); - for(ObjectIterator iter = iterator();iter.hasNext();) { - if(filter.test(iter.next())) return true; - } - return false; - } - - /** - * Helper function to reduce stream usage that allows to filter for no matches. - * @param filter that should be applied - * @return true if no matches were found - */ - default boolean matchesNone(Predicate filter) { - Objects.requireNonNull(filter); - for(ObjectIterator iter = iterator();iter.hasNext();) { - if(filter.test(iter.next())) return false; - } - return true; - } - - /** - * Helper function to reduce stream usage that allows to filter for all matches. - * @param filter that should be applied - * @return true if all matches. - */ - default boolean matchesAll(Predicate filter) { - Objects.requireNonNull(filter); - for(ObjectIterator iter = iterator();iter.hasNext();) { - if(!filter.test(iter.next())) return false; - } - return true; - } - - /** - * Helper function to reduce stream usage that allows to filter for the first match. - * @param filter that should be applied - * @return the found value or the null equivalent variant. - */ - default T findFirst(Predicate filter) { - Objects.requireNonNull(filter); - for(ObjectIterator iter = iterator();iter.hasNext();) { - T entry = iter.next(); - if(filter.test(entry)) return entry; - } - return null; - } - - /** - * Performs a reduction on the - * elements of this Iterable - * @param operator the operation that should be applied - * @param identity the start value - * @param the keyType of elements maintained by this Collection - * @return the reduction result, returns identity if nothing was found - */ - default E reduce(E identity, BiFunction operator) { - Objects.requireNonNull(operator); - E state = identity; - for(ObjectIterator iter = iterator();iter.hasNext();) { - state = operator.apply(state, iter.next()); - } - return state; - } - - /** - * Performs a reduction on the - * elements of this Iterable - * @param operator the operation that should be applied - * @return the reduction result, returns null value if nothing was found - */ - default T reduce(ObjectObjectUnaryOperator operator) { - Objects.requireNonNull(operator); - T state = null; - boolean empty = true; - for(ObjectIterator iter = iterator();iter.hasNext();) { - if(empty) { - empty = false; - state = iter.next(); - continue; - } - state = operator.apply(state, iter.next()); - } - return state; - } - - /** - * Helper function to reduce stream usage that allows to count the valid elements. - * @param filter that should be applied - * @return the amount of Valid Elements - */ - default int count(Predicate filter) { - Objects.requireNonNull(filter); - int result = 0; - for(ObjectIterator iter = iterator();iter.hasNext();) { - if(filter.test(iter.next())) result++; - } - return result; - } -} diff --git a/src/main/java/speiger/src/collections/objects/collections/ObjectIterator.java b/src/main/java/speiger/src/collections/objects/collections/ObjectIterator.java deleted file mode 100644 index 288121002..000000000 --- a/src/main/java/speiger/src/collections/objects/collections/ObjectIterator.java +++ /dev/null @@ -1,36 +0,0 @@ -package speiger.src.collections.objects.collections; - -import java.util.Iterator; -import java.util.Objects; -import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer; - -/** - * A Type-Specific {@link Iterator} that reduces (un)boxing - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectIterator extends Iterator -{ - /** - * Helper function to reduce Lambda usage and allow for more method references, since these are faster/cleaner. - * @param input the object that should be included - * @param action The action to be performed for each element - * @param the generic type of the Object - * @throws NullPointerException if the specified action is null - */ - default void forEachRemaining(E input, ObjectObjectConsumer action) { - Objects.requireNonNull(action); - while(hasNext()) { action.accept(input, next()); } - } - - /** - * Skips the Given amount of elements if possible. A Optimization function to skip elements faster if the implementation allows it. - * @param amount the amount of elements that should be skipped - * @return the amount of elements that were skipped - */ - default int skip(int amount) { - if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); - int i = 0; - for(;i the keyType of elements maintained by this Collection - */ -public interface ObjectSplititerator extends Spliterator, ObjectIterator -{ - @Override - default void forEachRemaining(Consumer action) { ObjectIterator.super.forEachRemaining(action); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/ObjectSupplier.java b/src/main/java/speiger/src/collections/objects/functions/ObjectSupplier.java deleted file mode 100644 index 879c06448..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/ObjectSupplier.java +++ /dev/null @@ -1,13 +0,0 @@ -package speiger.src.collections.objects.functions; - -/** - * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectSupplier extends java.util.function.Supplier -{ - /** - * @return the supplied value - */ - public T get(); -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectBooleanConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectBooleanConsumer.java deleted file mode 100644 index 2a5494190..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectBooleanConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.objects.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectBooleanConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(T k, boolean v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ObjectBooleanConsumer andThen(ObjectBooleanConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(T k, Boolean v) { accept(k, v.booleanValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ObjectBooleanConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, Boolean.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectByteConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectByteConsumer.java deleted file mode 100644 index 0893b1e86..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectByteConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.objects.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectByteConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(T k, byte v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ObjectByteConsumer andThen(ObjectByteConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(T k, Byte v) { accept(k, v.byteValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ObjectByteConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, Byte.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectCharConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectCharConsumer.java deleted file mode 100644 index e45bf7e7f..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectCharConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.objects.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectCharConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(T k, char v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ObjectCharConsumer andThen(ObjectCharConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(T k, Character v) { accept(k, v.charValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ObjectCharConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, Character.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectDoubleConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectDoubleConsumer.java deleted file mode 100644 index 6581a6fbe..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectDoubleConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.objects.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectDoubleConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(T k, double v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ObjectDoubleConsumer andThen(ObjectDoubleConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(T k, Double v) { accept(k, v.doubleValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ObjectDoubleConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, Double.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectFloatConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectFloatConsumer.java deleted file mode 100644 index 79e3bf128..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectFloatConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.objects.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectFloatConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(T k, float v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ObjectFloatConsumer andThen(ObjectFloatConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(T k, Float v) { accept(k, v.floatValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ObjectFloatConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, Float.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectIntConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectIntConsumer.java deleted file mode 100644 index 7522cc984..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectIntConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.objects.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectIntConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(T k, int v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ObjectIntConsumer andThen(ObjectIntConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(T k, Integer v) { accept(k, v.intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ObjectIntConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, Integer.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectLongConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectLongConsumer.java deleted file mode 100644 index 59317a6ac..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectLongConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.objects.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectLongConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(T k, long v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ObjectLongConsumer andThen(ObjectLongConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(T k, Long v) { accept(k, v.longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ObjectLongConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, Long.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectObjectConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectObjectConsumer.java deleted file mode 100644 index 6b17b99f6..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectObjectConsumer.java +++ /dev/null @@ -1,33 +0,0 @@ -package speiger.src.collections.objects.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectObjectConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(T k, V v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ObjectObjectConsumer andThen(ObjectObjectConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectShortConsumer.java b/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectShortConsumer.java deleted file mode 100644 index 63ea95440..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/consumer/ObjectShortConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.objects.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectShortConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(T k, short v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ObjectShortConsumer andThen(ObjectShortConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(T k, Short v) { accept(k, v.shortValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ObjectShortConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, Short.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectBooleanUnaryOperator.java deleted file mode 100644 index e8b5658c9..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ObjectBooleanUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.objects.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectBooleanUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public boolean applyAsBoolean(T k, boolean v); - - @Override - public default Boolean apply(T k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k, v.booleanValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectByteUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectByteUnaryOperator.java deleted file mode 100644 index ceddb19f4..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ObjectByteUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.objects.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectByteUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public byte applyAsByte(T k, byte v); - - @Override - public default Byte apply(T k, Byte v) { return Byte.valueOf(applyAsByte(k, v.byteValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectCharUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectCharUnaryOperator.java deleted file mode 100644 index 834d99440..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ObjectCharUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.objects.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectCharUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public char applyAsChar(T k, char v); - - @Override - public default Character apply(T k, Character v) { return Character.valueOf(applyAsChar(k, v.charValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectDoubleUnaryOperator.java deleted file mode 100644 index c13963ef7..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ObjectDoubleUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.objects.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectDoubleUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public double applyAsDouble(T k, double v); - - @Override - public default Double apply(T k, Double v) { return Double.valueOf(applyAsDouble(k, v.doubleValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectFloatUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectFloatUnaryOperator.java deleted file mode 100644 index df6d4359e..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ObjectFloatUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.objects.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectFloatUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public float applyAsFloat(T k, float v); - - @Override - public default Float apply(T k, Float v) { return Float.valueOf(applyAsFloat(k, v.floatValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectIntUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectIntUnaryOperator.java deleted file mode 100644 index b68141a2c..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ObjectIntUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.objects.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectIntUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public int applyAsInt(T k, int v); - - @Override - public default Integer apply(T k, Integer v) { return Integer.valueOf(applyAsInt(k, v.intValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectLongUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectLongUnaryOperator.java deleted file mode 100644 index 0ec8b1018..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ObjectLongUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.objects.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectLongUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public long applyAsLong(T k, long v); - - @Override - public default Long apply(T k, Long v) { return Long.valueOf(applyAsLong(k, v.longValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectObjectUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectObjectUnaryOperator.java deleted file mode 100644 index e4d6de7d7..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ObjectObjectUnaryOperator.java +++ /dev/null @@ -1,13 +0,0 @@ -package speiger.src.collections.objects.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectObjectUnaryOperator extends BiFunction -{ - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ObjectShortUnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/ObjectShortUnaryOperator.java deleted file mode 100644 index 1ec7c91c3..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ObjectShortUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.objects.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface ObjectShortUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public short applyAsShort(T k, short v); - - @Override - public default Short apply(T k, Short v) { return Short.valueOf(applyAsShort(k, v.shortValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/Predicate.java b/src/main/java/speiger/src/collections/objects/functions/function/Predicate.java deleted file mode 100644 index 988fd6967..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/Predicate.java +++ /dev/null @@ -1,75 +0,0 @@ -package speiger.src.collections.objects.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface Predicate extends java.util.function.Predicate -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public boolean test(T k); - - /** - * Creates a Always true function that may be useful if you don't need to process information or just want a default. - * @param the keyType of elements maintained by this Collection - * @return a default returning function - */ - public static Predicate alwaysTrue() { - return T -> true; - } - - /** - * Creates a Always false function that may be useful if you don't need to process information or just want a default. - * @param the keyType of elements maintained by this Collection - * @return a default returning function - */ - public static Predicate alwaysFalse() { - return T -> false; - } - - /** - * A Type specific and-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a and comparason - */ - public default Predicate andType(Predicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - @Override - @Deprecated - public default Predicate and(java.util.function.Predicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - @Override - public default Predicate negate() { - return T -> !test(T); - } - - /** - * A Type specific or-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a or comparason - */ - public default Predicate orType(Predicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } - - @Override - @Deprecated - public default Predicate or(java.util.function.Predicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToByteFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToByteFunction.java deleted file mode 100644 index 5af08681d..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ToByteFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.objects.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface ToByteFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public byte applyAsByte(T k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToCharFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToCharFunction.java deleted file mode 100644 index 5b5ccac38..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ToCharFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.objects.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface ToCharFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public char applyAsChar(T k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToDoubleFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToDoubleFunction.java deleted file mode 100644 index 27b567e09..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ToDoubleFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.objects.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface ToDoubleFunction extends java.util.function.ToDoubleFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public double applyAsDouble(T k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToFloatFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToFloatFunction.java deleted file mode 100644 index ca72c0160..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ToFloatFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.objects.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface ToFloatFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public float applyAsFloat(T k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToIntFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToIntFunction.java deleted file mode 100644 index f8c7f007e..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ToIntFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.objects.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface ToIntFunction extends java.util.function.ToIntFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public int applyAsInt(T k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToLongFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToLongFunction.java deleted file mode 100644 index 3e04c28f1..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ToLongFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.objects.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface ToLongFunction extends java.util.function.ToLongFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public long applyAsLong(T k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/ToShortFunction.java b/src/main/java/speiger/src/collections/objects/functions/function/ToShortFunction.java deleted file mode 100644 index 6e6789654..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/ToShortFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.objects.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface ToShortFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public short applyAsShort(T k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/functions/function/UnaryOperator.java b/src/main/java/speiger/src/collections/objects/functions/function/UnaryOperator.java deleted file mode 100644 index 69b19ecde..000000000 --- a/src/main/java/speiger/src/collections/objects/functions/function/UnaryOperator.java +++ /dev/null @@ -1,59 +0,0 @@ -package speiger.src.collections.objects.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface UnaryOperator extends java.util.function.Function -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public V apply(T k); - - /** - * Creates a Default function that returns the input provided. - * @param the keyType of elements maintained by this Collection - * @return a input returning function - */ - public static UnaryOperator identity() { - return T -> T; - } - - /** - * Returns a composed function that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param the keyType of elements maintained by this Collection - * @param before the function that should be used first - * @return a composed function with a different starting function. - */ - public default UnaryOperator compose(UnaryOperator before) { - Objects.requireNonNull(before); - return T -> apply(before.apply(T)); - } - - /** - * Returns a composed function that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param the keyType of elements maintained by this Collection - * @param after the function that should be used last - * @return a composed function with a different starting function. - */ - public default UnaryOperator andThen(UnaryOperator after) { - Objects.requireNonNull(after); - return T -> after.apply(apply(T)); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/lists/AbstractObjectList.java b/src/main/java/speiger/src/collections/objects/lists/AbstractObjectList.java deleted file mode 100644 index b6533836c..000000000 --- a/src/main/java/speiger/src/collections/objects/lists/AbstractObjectList.java +++ /dev/null @@ -1,493 +0,0 @@ -package speiger.src.collections.objects.lists; - -import java.util.Collection; -import java.util.List; -import java.util.ListIterator; -import java.util.NoSuchElementException; -import java.util.Objects; - -import speiger.src.collections.objects.collections.AbstractObjectCollection; -import speiger.src.collections.objects.collections.ObjectCollection; -import speiger.src.collections.objects.collections.ObjectIterator; -import speiger.src.collections.objects.collections.ObjectSplititerator; -import speiger.src.collections.objects.utils.ObjectSplititerators; -import speiger.src.collections.utils.SanityChecks; - -/** - * Abstract implementation of the {@link ObjectList} interface. - * @param the keyType of elements maintained by this Collection - */ -public abstract class AbstractObjectList extends AbstractObjectCollection implements ObjectList -{ - /** - * A Type-Specific implementation of add function that delegates to {@link List#add(int, Object)} - */ - @Override - public boolean add(T e) { - add(size(), e); - return true; - } - - /** - * A Type-Specific implementation that iterates over the elements and adds them. - * @param c the elements that wants to be added - * @return true if the list was modified - */ - @Override - public boolean addAll(ObjectCollection c) { - return addAll(size(), c); - } - - /** - * A Type-Specific implementation that iterates over the elements and adds them. - * @param c the elements that wants to be added - * @return true if the list was modified - */ - @Override - public boolean addAll(ObjectList c) { - return addAll(size(), c); - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - public boolean addAll(Collection c) - { - return c instanceof ObjectCollection ? addAll((ObjectCollection)c) : addAll(size(), c); - } - - /** - * The IndexOf implementation iterates over all elements and compares them to the search value. - * @param o the value that the index is searched for. - * @return index of the value that was searched for. -1 if not found - * @note it is highly suggested not to use this with Primitives because of boxing. But it is still supported because of ObjectComparason that are custom objects and allow to find the contents. - */ - @Override - public int indexOf(Object o) { - ObjectListIterator iter = listIterator(); - if(o == null) { - while(iter.hasNext()) { - if(iter.next() == null) - return iter.previousIndex(); - } - return -1; - } - while(iter.hasNext()) { - if(Objects.equals(o, iter.next())) - return iter.previousIndex(); - } - return -1; - } - - /** - * The lastIndexOf implementation iterates over all elements and compares them to the search value. - * @param o the value that the index is searched for. - * @return the last index of the value that was searched for. -1 if not found - * @note it is highly suggested not to use this with Primitives because of boxing. But it is still supported because of ObjectComparason that are custom objects and allow to find the contents. - */ - @Override - public int lastIndexOf(Object o) { - ObjectListIterator iter = listIterator(size()); - if(o == null) { - while(iter.hasPrevious()) { - if(iter.previous() == null) - return iter.nextIndex(); - } - return -1; - } - while(iter.hasPrevious()) { - if(Objects.equals(o, iter.previous())) - return iter.nextIndex(); - } - return -1; - } - - @Override - public boolean swapRemove(T e) { - int index = indexOf(e); - if(index == -1) return false; - swapRemove(index); - return true; - } - - /** - * Compares if the list are the same. - */ - @Override - public boolean equals(Object o) { - if (o == this) - return true; - if (!(o instanceof List)) - return false; - List l = (List)o; - if(l.size() != size()) return false; - ListIterator e1 = listIterator(); - ListIterator e2 = l.listIterator(); - while (e1.hasNext() && e2.hasNext()) { - if(!Objects.equals(e1.next(), e2.next())) - return false; - } - return !(e1.hasNext() || e2.hasNext()); - } - - /** - * Generates the hashcode based on the values stored in the list. - */ - @Override - public int hashCode() { - int hashCode = 1; - ObjectListIterator i = listIterator(); - while(i.hasNext()) - hashCode = 31 * hashCode + i.next().hashCode(); - return hashCode; - } - - @Override - public ObjectList subList(int fromIndex, int toIndex) { - SanityChecks.checkArrayCapacity(size(), fromIndex, toIndex-fromIndex); - return new SubList(this, 0, fromIndex, toIndex); - } - - @Override - public ObjectIterator iterator() { - return listIterator(0); - } - - @Override - public ObjectListIterator listIterator() { - return listIterator(0); - } - - @Override - public ObjectListIterator listIterator(int index) { - if(index < 0 || index > size()) throw new IndexOutOfBoundsException(); - return new ObjectListIter(index); - } - - @Override - public void size(int size) { - while(size > size()) add(null); - while(size < size()) remove(size() - 1); - } - - public AbstractObjectList copy() { throw new UnsupportedOperationException(); } - - private class SubList extends AbstractObjectList - { - final AbstractObjectList list; - final int parentOffset; - final int offset; - int size; - - public SubList(AbstractObjectList list, int offset, int from, int to) { - this.list = list; - this.parentOffset = from; - this.offset = offset + from; - this.size = to - from; - } - - @Override - public void add(int index, T element) { - checkAddSubRange(index); - list.add(parentOffset+index, element); - size++; - } - - @Override - public boolean addAll(int index, Collection c) { - checkAddSubRange(index); - int add = c.size(); - if(add <= 0) return false; - list.addAll(parentOffset+index, c); - this.size += add; - return true; - } - - @Override - public boolean addAll(int index, ObjectCollection c) { - checkAddSubRange(index); - int add = c.size(); - if(add <= 0) return false; - list.addAll(parentOffset+index, c); - this.size += add; - return true; - } - - @Override - public boolean addAll(int index, ObjectList c) { - checkAddSubRange(index); - int add = c.size(); - if(add <= 0) return false; - list.addAll(parentOffset+index, c); - this.size += add; - return true; - } - - @Override - public void addElements(int from, T[] a, int offset, int length) { - checkAddSubRange(from); - if(length <= 0) return; - list.addElements(parentOffset+from, a, offset, length); - this.size += length; - } - - @Override - public T[] getElements(int from, T[] a, int offset, int length) { - SanityChecks.checkArrayCapacity(size, from, length); - SanityChecks.checkArrayCapacity(a.length, offset, length); - return list.getElements(from+parentOffset, a, offset, length); - } - - @Override - public void removeElements(int from, int to) { - if(to-from <= 0) return; - checkSubRange(from); - checkAddSubRange(to); - list.removeElements(from+parentOffset, to+parentOffset); - size -= to - from; - } - - @Override - public K[] extractElements(int from, int to, Class type) { - checkSubRange(from); - checkAddSubRange(to); - K[] result = list.extractElements(from+parentOffset, to+parentOffset, type); - size -= result.length; - return result; - } - - @Override - public T get(int index) { - checkSubRange(index); - return list.get(parentOffset+index); - } - - @Override - public T set(int index, T element) { - checkSubRange(index); - return list.set(parentOffset+index, element); - } - - @Override - public T swapRemove(int index) { - checkSubRange(index); - if(index == size-1) { - T result = list.remove(parentOffset+size-1); - size--; - return result; - } - T result = list.set(index+parentOffset, list.get(parentOffset+size-1)); - list.remove(parentOffset+size-1); - size--; - return result; - } - - @Override - public T remove(int index) { - checkSubRange(index); - T result = list.remove(index+parentOffset); - size--; - return result; - } - - @Override - public int size() { - return size; - } - - @Override - public ObjectSplititerator spliterator() { return ObjectSplititerators.createSplititerator(this, 16464); } - - @Override - public ObjectListIterator listIterator(int index) { - if(index < 0 || index > size()) throw new IndexOutOfBoundsException(); - return new SubListIterator(this, index); - } - - @Override - public ObjectList subList(int fromIndex, int toIndex) { - SanityChecks.checkArrayCapacity(size, fromIndex, toIndex-fromIndex); - return new SubList(this, offset, fromIndex, toIndex); - } - - protected void checkSubRange(int index) { - if (index < 0 || index >= size) - throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); - } - - protected void checkAddSubRange(int index) { - if (index < 0 || index > size) - throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); - } - - private class SubListIterator implements ObjectListIterator - { - AbstractObjectList list; - int index; - int lastReturned = -1; - - SubListIterator(AbstractObjectList list, int index) { - this.list = list; - this.index = index; - } - - @Override - public boolean hasNext() { - return index < list.size(); - } - - @Override - public T next() { - if(!hasNext()) throw new NoSuchElementException(); - int i = index++; - return list.get((lastReturned = i)); - } - - @Override - public boolean hasPrevious() { - return index > 0; - } - - @Override - public T previous() { - if(!hasPrevious()) throw new NoSuchElementException(); - index--; - return list.get((lastReturned = index)); - } - - @Override - public int nextIndex() { - return index; - } - - @Override - public int previousIndex() { - return index-1; - } - - @Override - public void remove() { - if(lastReturned == -1) throw new IllegalStateException(); - list.remove(lastReturned); - index = lastReturned; - lastReturned = -1; - } - - @Override - public void set(T e) { - if(lastReturned == -1) throw new IllegalStateException(); - list.set(lastReturned, e); - } - - @Override - public void add(T e) { - list.add(index, e); - index++; - lastReturned = -1; - } - - @Override - public int skip(int amount) { - if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); - int steps = Math.min(amount, size() - index); - index += steps; - if(steps > 0) lastReturned = Math.min(index-1, size()-1); - return steps; - } - - @Override - public int back(int amount) { - if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); - int steps = Math.min(amount, index); - index -= steps; - if(steps > 0) lastReturned = Math.min(index, size()-1); - return steps; - } - } - } - - private class ObjectListIter implements ObjectListIterator { - int index; - int lastReturned = -1; - - ObjectListIter(int index) { - this.index = index; - } - - @Override - public boolean hasNext() { - return index < size(); - } - - @Override - public T next() { - if(!hasNext()) throw new NoSuchElementException(); - int i = index++; - return get((lastReturned = i)); - } - - @Override - public boolean hasPrevious() { - return index > 0; - } - - @Override - public T previous() { - if(!hasPrevious()) throw new NoSuchElementException(); - index--; - return get((lastReturned = index)); - } - - @Override - public int nextIndex() { - return index; - } - - @Override - public int previousIndex() { - return index-1; - } - - @Override - public void remove() { - if(lastReturned == -1) throw new IllegalStateException(); - AbstractObjectList.this.remove(lastReturned); - index = lastReturned; - lastReturned = -1; - } - - @Override - public void set(T e) { - if(lastReturned == -1) throw new IllegalStateException(); - AbstractObjectList.this.set(lastReturned, e); - } - - @Override - public void add(T e) { - AbstractObjectList.this.add(index, e); - index++; - lastReturned = -1; - } - - @Override - public int skip(int amount) { - if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); - int steps = Math.min(amount, size() - index); - index += steps; - if(steps > 0) lastReturned = Math.min(index-1, size()-1); - return steps; - } - - @Override - public int back(int amount) { - if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); - int steps = Math.min(amount, index); - index -= steps; - if(steps > 0) lastReturned = Math.min(index, size()-1); - return steps; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/objects/lists/ObjectArrayList.java b/src/main/java/speiger/src/collections/objects/lists/ObjectArrayList.java deleted file mode 100644 index a666fb1b3..000000000 --- a/src/main/java/speiger/src/collections/objects/lists/ObjectArrayList.java +++ /dev/null @@ -1,888 +0,0 @@ -package speiger.src.collections.objects.lists; - -import java.util.Arrays; -import java.util.Comparator; -import java.util.Collection; -import java.util.Iterator; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.BiFunction; -import java.util.function.Predicate; -import java.util.function.UnaryOperator; - -import speiger.src.collections.objects.collections.ObjectCollection; -import speiger.src.collections.objects.collections.ObjectIterator; -import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer; -import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator; -import speiger.src.collections.objects.utils.ObjectArrays; -import speiger.src.collections.objects.utils.ObjectArrays; -import speiger.src.collections.objects.utils.ObjectIterators; -import speiger.src.collections.utils.Stack; -import speiger.src.collections.objects.collections.ObjectSplititerator; -import speiger.src.collections.objects.utils.ObjectSplititerators; -import speiger.src.collections.utils.IArray; -import speiger.src.collections.utils.SanityChecks; - -/** - * A Type-Specific Array-based implementation of list that is written to reduce (un)boxing - * - *

This implementation is optimized to improve how data is processed with interfaces like {@link IArray}, {@link Stack} - * and with optimized functions that use type-specific implementations for primitives and optimized logic for bulkactions. - * - * @param the keyType of elements maintained by this Collection - */ -public class ObjectArrayList extends AbstractObjectList implements IArray, Stack -{ - static final int DEFAULT_ARRAY_SIZE = 10; - - /** The backing array */ - protected transient T[] data; - /** The current size of the elements stored in the backing array */ - protected int size = 0; - - /** - * Creates a new ArrayList with a Empty array. - */ - public ObjectArrayList() { - data = (T[])ObjectArrays.EMPTY_ARRAY; - } - - /** - * Creates a new ArrayList with the specific requested size - * @param size the minimum initial size of the Backing array - */ - public ObjectArrayList(int size) { - if(size < 0) throw new IllegalStateException("Size has to be 0 or greater"); - data = (T[])new Object[size]; - } - - /** - * Creates a new ArrayList a copy with the contents of the Collection. - * @param c the elements that should be added into the list - */ - public ObjectArrayList(Collection c) { - this(c.size()); - size = ObjectIterators.unwrap(data, c.iterator()); - } - - /** - * Creates a new ArrayList a copy with the contents of the Collection. - * @param c the elements that should be added into the list - */ - public ObjectArrayList(ObjectCollection c) { - this(c.size()); - size = ObjectIterators.unwrap(data, c.iterator()); - } - - /** - * Creates a new ArrayList a copy with the contents of the List. - * @param l the elements that should be added into the list - */ - public ObjectArrayList(ObjectList l) { - this(l.size()); - size = l.size(); - l.getElements(0, data, 0, size); - } - - /** - * Creates a new ArrayList with a Copy of the array - * @param a the array that should be copied - */ - public ObjectArrayList(T... a) { - this(a, 0, a.length); - } - - /** - * Creates a new ArrayList with a Copy of the array with a custom length - * @param a the array that should be copied - * @param length the desired length that should be copied - */ - public ObjectArrayList(T[] a, int length) { - this(a, 0, length); - } - - /** - * Creates a new ArrayList with a Copy of the array with in the custom range. - * @param a the array that should be copied - * @param offset the starting offset of where the array should be copied from - * @param length the desired length that should be copied - * @throws IllegalStateException if offset is smaller then 0 - * @throws IllegalStateException if the offset + length exceeds the array length - */ - public ObjectArrayList(T[] a, int offset, int length) { - this(length); - SanityChecks.checkArrayCapacity(a.length, offset, length); - System.arraycopy(a, offset, data, 0, length); - size = length; - } - - /** - * Creates a wrapped arraylist that uses the array as backing array - * @param a elements that should be wrapped - * @param the keyType of elements maintained by this Collection - * @return a Wrapped list using the input array - */ - public static ObjectArrayList wrap(T... a) { - return wrap(a, a.length); - } - - /** - * Creates a wrapped arraylist that uses the array as backing array and a custom fill size - * @param a elements that should be wrapped - * @param length the size of the elements within the array - * @param the keyType of elements maintained by this Collection - * @return a Wrapped list using the input array - */ - public static ObjectArrayList wrap(T[] a, int length) { - SanityChecks.checkArrayCapacity(a.length, 0, length); - ObjectArrayList list = new ObjectArrayList<>(); - list.data = a; - list.size = length; - return list; - } - - /** - * Creates a new ArrayList with a EmptyObject array of the Type requested - * @param c the type of the array - * @param the keyType of elements maintained by this Collection - * @return a typed List - */ - public static ObjectArrayList of(Class c) { - ObjectArrayList list = new ObjectArrayList<>(); - list.data = (T[])ObjectArrays.newArray(c, 0); - return list; - } - - /** - * Creates a new ArrayList with a EmptyObject array of the Type requested - * @param c the type of the array - * @param size the initial size of the backing array - * @param the keyType of elements maintained by this Collection - * @return a typed List - */ - public static ObjectArrayList of(Class c, int size) { - ObjectArrayList list = new ObjectArrayList<>(); - list.data = (T[])ObjectArrays.newArray(c, size); - return list; - } - - /** - * Appends the specified element to the end of this list. - * - * @param e element to be appended to this list - * @return true (as specified by {@link Collection#add}) - */ - @Override - public boolean add(T e) { - grow(size + 1); - data[size++] = e; - return true; - } - - /** - * Appends the specified element to the end of this Stack. - * @param e element to be appended to this Stack - */ - @Override - public void push(T e) { - add(e); - } - - /** - * Appends the specified element to the index of the list - * @param index the index where to append the element to - * @param e the element to append to the list - * @throws IndexOutOfBoundsException if index is outside of the lists range - */ - @Override - public void add(int index, T e) { - checkAddRange(index); - grow(size + 1); - if(index != size) System.arraycopy(data, index, data, index+1, size - index); - data[index] = e; - size++; - } - - /** - * Appends the specified elements to the index of the list. - * This function may delegate to more appropriate function if necessary - * @param index the index where to append the elements to - * @param c the elements to append to the list - * @throws IndexOutOfBoundsException if index is outside of the lists range - * @throws NullPointerException if collection contains a null element - */ - @Override - public boolean addAll(int index, Collection c) { - if(c instanceof ObjectCollection) return addAll(index, (ObjectCollection)c); - int add = c.size(); - if(add <= 0) return false; - grow(size + add); - if(index != size) System.arraycopy(data, index, data, index+add, size - index); - size+=add; - Iterator iter = c.iterator(); - while(add-- != 0) data[index++] = iter.next(); - return true; - } - - /** - * Appends the specified elements to the index of the list. - * This function may delegate to more appropriate function if necessary - * @param index the index where to append the elements to - * @param c the elements to append to the list - * @throws IndexOutOfBoundsException if index is outside of the lists range - */ - @Override - public boolean addAll(int index, ObjectCollection c) { - if(c instanceof ObjectList) return addAll(index, (ObjectList)c); - int add = c.size(); - if(add <= 0) return false; - grow(size + add); - if(index != size) System.arraycopy(data, index, data, index+add, size - index); - size+=add; - ObjectIterator iter = c.iterator(); - while(add-- != 0) data[index++] = iter.next(); - return true; - } - - /** - * Appends the specified elements to the index of the list. - * @param index the index where to append the elements to - * @param c the elements to append to the list - * @throws IndexOutOfBoundsException if index is outside of the lists range - */ - @Override - public boolean addAll(int index, ObjectList c) { - int add = c.size(); - if(add <= 0) return false; - checkAddRange(index); - grow(size + add); - if(index != size) System.arraycopy(data, index, data, index+add, size - index); - size+=add; - c.getElements(0, data, index, c.size()); - return true; - } - - @Override - public boolean addAll(T[] e, int offset, int length) { - if(length <= 0) return false; - SanityChecks.checkArrayCapacity(e.length, offset, length); - grow(size + length); - System.arraycopy(e, offset, data, size, length); - size+=length; - return true; - } - - /** - * Appends the specified array elements to the index of the list. - * @param from the index where to append the elements to - * @param a the elements to append to the list - * @param offset where to start ino the array - * @param length the amount of elements to insert - * @throws IndexOutOfBoundsException if index is outside of the lists range - */ - @Override - public void addElements(int from, T[] a, int offset, int length) { - if(length <= 0) return; - checkAddRange(from); - SanityChecks.checkArrayCapacity(a.length, offset, length); - grow(size + length); - if(from != size) System.arraycopy(data, from, data, from+length, size - from); - size+=length; - System.arraycopy(a, offset, data, from, length); - } - - /** - * A function to fast fetch elements from the list - * @param from index where the list should be fetching elements from - * @param a the array where the values should be inserted to - * @param offset the startIndex of where the array should be written to - * @param length the number of elements the values should be fetched from - * @return the inputArray - * @throws NullPointerException if the array is null - * @throws IndexOutOfBoundsException if from is outside of the lists range - * @throws IllegalStateException if offset or length are smaller then 0 or exceed the array length - */ - @Override - public T[] getElements(int from, T[] a, int offset, int length) { - SanityChecks.checkArrayCapacity(size, from, length); - SanityChecks.checkArrayCapacity(a.length, offset, length); - System.arraycopy(data, from, a, offset, length); - return a; - } - - /** - * a function to fast remove elements from the list. - * @param from the start index of where the elements should be removed from (inclusive) - * @param to the end index of where the elements should be removed to (exclusive) - */ - @Override - public void removeElements(int from, int to) { - checkRange(from); - checkAddRange(to); - int length = to - from; - if(length <= 0) return; - if(to != size) System.arraycopy(data, to, data, from, size - to); - size -= length; - for(int i = 0;i K[] extractElements(int from, int to, Class type) { - checkRange(from); - checkAddRange(to); - int length = to - from; - if(length <= 0) return ObjectArrays.newArray(type, 0); - K[] a = ObjectArrays.newArray(type, length); - System.arraycopy(data, from, a, 0, length); - if(to != size) System.arraycopy(data, to, data, from, size - to); - size -= length; - for(int i = 0;i=0;i--) - if(data[i] == null) return i; - return -1; - } - for(int i = size - 1;i>=0;i--) { - if(Objects.equals(o, data[i])) return i; - } - return -1; - } - - /** - * Sorts the elements specified by the Natural order either by using the Comparator or the elements - * @param c the sorter of the elements, can be null - * @see java.util.List#sort(Comparator) - */ - @Override - public void sort(Comparator c) { - if(c != null) ObjectArrays.stableSort(data, size, c); - else ObjectArrays.stableSort(data, size); - } - - /** - * Sorts the elements specified by the Natural order either by using the Comparator or the elements using a unstable sort - * @param c the sorter of the elements, can be null - * @see java.util.List#sort(Comparator) - */ - @Override - public void unstableSort(Comparator c) { - if(c != null) ObjectArrays.unstableSort(data, size, c); - else ObjectArrays.unstableSort(data, size); - } - - /** - * A Type-Specific get function to reduce (un)boxing - * @param index the index of the element to fetch - * @return the value of the requested index - * @throws IndexOutOfBoundsException if the index is out of range - */ - @Override - public T get(int index) { - checkRange(index); - return data[index]; - } - - /** - * Provides the Selected Object from the stack. - * Top to bottom - * @param index of the element that should be provided - * @return the element that was requested - * @throws ArrayIndexOutOfBoundsException if the index is out of bounds - * @see Stack#peek(int) - */ - @Override - public T peek(int index) { - checkRange((size() - 1) - index); - return data[(size() - 1) - index]; - } - - /** - * A Type Specific foreach function that reduces (un)boxing - * - * @implSpec - *

The default implementation behaves as if: - *

{@code
-	 * 	for(int i = 0;i
-	 *
-	 * @param action The action to be performed for each element
-	 * @throws NullPointerException if the specified action is null
-	 * @see Iterable#forEach(Consumer)
-	 */
-	@Override
-	public void forEach(Consumer action) {
-		Objects.requireNonNull(action);
-		for(int i = 0;i void forEach(E input, ObjectObjectConsumer action) {
-		Objects.requireNonNull(action);
-		for(int i = 0;i filter) {
-		Objects.requireNonNull(filter);
-		for(int i = 0;i filter) {
-		Objects.requireNonNull(filter);
-		for(int i = 0;i filter) {
-		Objects.requireNonNull(filter);
-		for(int i = 0;i filter) {
-		Objects.requireNonNull(filter);
-		for(int i = 0;i E reduce(E identity, BiFunction operator) {
-		Objects.requireNonNull(operator);
-		E state = identity;
-		for(int i = 0;i operator) {
-		Objects.requireNonNull(operator);
-		T state = null;
-		boolean empty = true;
-		for(int i = 0;i filter) {
-		Objects.requireNonNull(filter);
-		int result = 0;
-		for(int i = 0;i o) {
-		Objects.requireNonNull(o);
-		for(int i = 0;i c) {
-		if(c.isEmpty()) return false;
-		boolean modified = false;
-		int j = 0;
-		for(int i = 0;i c) {
-		if(c.isEmpty()) {
-			boolean modifed = size > 0;
-			clear();
-			return modifed;
-		}
-		boolean modified = false;
-		int j = 0;
-		for(int i = 0;i filter) {
-		Objects.requireNonNull(filter);
-		boolean modified = false;
-		int j = 0;
-		for(int i = 0;i c) {
-		if(c.isEmpty()) return false;
-		boolean modified = false;
-		int j = 0;
-		for(int i = 0;i c, Consumer r) {
-		if(c.isEmpty()) return false;
-		int j = 0;
-		for(int i = 0;i c) {
-		if(c.isEmpty()) {
-			boolean modifed = size > 0;
-			clear();
-			return modifed;
-		}
-		boolean modified = false;
-		int j = 0;
-		for(int i = 0;i c, Consumer r) {
-		if(c.isEmpty()) {
-			boolean modifed = size > 0;
-			forEach(r);
-			clear();
-			return modifed;
-		}
-		int j = 0;
-		for(int i = 0;i E[] toArray(E[] a) {
-		if(a == null) a = (E[])new Object[size];
-		else if(a.length < size) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), size);
-        System.arraycopy(data, 0, a, 0, size);
-		if (a.length > size) a[size] = null;
-		return a;
-	}
-
-	/**
-	 * A function to return the size of the list
-	 * @return the size of elements in the list
-	 */
-	@Override
-	public int size() {
-		return size;
-	}
-
-	/**
-	 * A function to ensure the elements are within the requested size.
-	 * If smaller then the stored elements they get removed as needed.
-	 * If bigger it is ensured that enough room is provided depending on the implementation
-	 * @param size the requested amount of elements/room for elements
-	 */
-	@Override
-	public void size(int size) {
-		if(size > data.length)
-			data = Arrays.copyOf(data, size);
-		else if(size < size() && size >= 0)
-			Arrays.fill(data, size, size(), null);
-		this.size = size;
-	}
-
-	/**
-	 * A function to clear all elements in the list.
-	 */
-	@Override
-	public void clear() {
-		for(int i = 0;i size() || size() == data.length) return false;
-		int value = Math.max(size, size());
-		data = value == 0 ? (T[])ObjectArrays.EMPTY_ARRAY : Arrays.copyOf(data, value);
-		return true;
-	}
-
-	/**
-	 * Trims the collection down to the requested size and clears all elements while doing so
-	 * @param size the amount of elements that should be allowed
-	 * @note this will enforce minimum size of the collection itself
-	 */
-	@Override
-	public void clearAndTrim(int size) {
-		if(data.length <= size) {
-			clear();
-			return;
-		}
-		data = size == 0 ? (T[])ObjectArrays.EMPTY_ARRAY : (T[])new Object[size];
-		this.size = size;
-	}
-
-	/**
-	 * Increases the capacity of this implementation instance, if necessary,
-	 * to ensure that it can hold at least the number of elements specified by
-	 * the minimum capacity argument.
-	 *
-	 * @param size the desired minimum capacity
-	 */
-	@Override
-	public void ensureCapacity(int size) {
-		grow(size);
-	}
-
-	@Override
-	public ObjectArrayList copy() {
-		ObjectArrayList list = new ObjectArrayList<>();
-		list.data = Arrays.copyOf(data, data.length);
-		list.size = size;
-		return list;
-	}
-
-	protected void grow(int capacity) {
-		if(capacity <= data.length) return;
-		data = Arrays.copyOf(data, data == ObjectArrays.EMPTY_ARRAY ? Math.max(DEFAULT_ARRAY_SIZE, capacity) : (int)Math.max(Math.min((long)data.length + (data.length >> 1), SanityChecks.MAX_ARRAY_SIZE), capacity));
-	}
-
-	protected void checkRange(int index) {
-		if (index < 0 || index >= size)
-			throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
-	}
-
-	protected void checkAddRange(int index) {
-		if (index < 0 || index > size)
-			throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
-	}
-
-	/**
-	 * A Type Specific Type Splititerator to reduce boxing/unboxing
-	 * @return type specific splititerator
-	 * @note characteristics are ordered, sized, subsized
-	 */
-	@Override
-	public ObjectSplititerator spliterator() { return ObjectSplititerators.createArraySplititerator(data, size, 16464); }
-}
diff --git a/src/main/java/speiger/src/collections/objects/lists/ObjectList.java b/src/main/java/speiger/src/collections/objects/lists/ObjectList.java
deleted file mode 100644
index dcfe8cd9f..000000000
--- a/src/main/java/speiger/src/collections/objects/lists/ObjectList.java
+++ /dev/null
@@ -1,238 +0,0 @@
-package speiger.src.collections.objects.lists;
-
-import java.util.List;
-
-import java.util.Objects;
-import java.util.Comparator;
-import java.util.function.UnaryOperator;
-
-import speiger.src.collections.objects.collections.ObjectCollection;
-import speiger.src.collections.objects.collections.ObjectSplititerator;
-import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
-import speiger.src.collections.objects.utils.ObjectArrays;
-import speiger.src.collections.objects.utils.ObjectSplititerators;
-
-/**
- * A Type Specific List interface that reduces boxing/unboxing and adds a couple extra quality of life features
- * @param  the keyType of elements maintained by this Collection
- */
-public interface ObjectList extends ObjectCollection, List
-{
-	/**
-	 * A Helper function that will only add elements if it is not present.
-	 * @param e the element to add
-	 * @return true if the list was modified
-	 */
-	public default boolean addIfAbsent(T e) {
-		if(indexOf(e) == -1) return add(e);
-		return false;
-	}
-
-	/**
-	 * A Helper function that will only add elements if it is present.
-	 * @param e the element to add
-	 * @return true if the list was modified
-	 */
-	public default boolean addIfPresent(T e) {
-		if(indexOf(e) != -1) return add(e);
-		return false;
-	}
-
-	/**
-	 * A Type-Specific addAll Function to reduce (un)boxing
-	 * @param c the elements that need to be added
-	 * @param index index at which the specified elements is to be inserted
-	 * @return true if the list was modified
-	 * @see List#addAll(int, java.util.Collection)
-	 */
-	public boolean addAll(int index, ObjectCollection c);
-
-	/**
-	 * A Type-Specific and optimized addAll function that allows a faster transfer of elements
-	 * @param c the elements that need to be added
-	 * @return true if the list was modified
-	 */
-	public boolean addAll(ObjectList c);
-
-	/**
-	 * A Type-Specific and optimized addAll function that allows a faster transfer of elements
-	 * @param c the elements that need to be added
-	 * @param index index at which the specified elements is to be inserted
-	 * @return true if the list was modified
-	 */
-	public boolean addAll(int index, ObjectList c);
-
-	/**
-	 * A function to replace all values in the list
-	 * @param o the action to replace the values
-	 * @throws NullPointerException if o is null
-	 */
-	@Override
-	public default void replaceAll(UnaryOperator o) {
-		Objects.requireNonNull(o);
-		ObjectListIterator iter = listIterator();
-		while (iter.hasNext()) iter.set(o.apply(iter.next()));
-	}
-
-	/**
-	 * A function to fast add elements to the list
-	 * @param a the elements that should be added
-	 * @throws IndexOutOfBoundsException if from is outside of the lists range
-	 */
-	public default void addElements(T... a) { addElements(size(), a, 0, a.length); }
-
-	/**
-	 * A function to fast add elements to the list
-	 * @param from the index where the elements should be added into the list
-	 * @param a the elements that should be added
-	 * @throws IndexOutOfBoundsException if from is outside of the lists range
-	 */
-	public default void addElements(int from, T... a) { addElements(from, a, 0, a.length); }
-
-	/**
-	 * A function to fast add elements to the list
-	 * @param from the index where the elements should be added into the list
-	 * @param a the elements that should be added
-	 * @param offset the start index of the array should be read from
-	 * @param length how many elements should be read from
-	 * @throws IndexOutOfBoundsException if from is outside of the lists range
-	 */
-	public void addElements(int from, T[] a, int offset, int length);
-
-	/**
-	 * A function to fast fetch elements from the list
-	 * @param from index where the list should be fetching elements from
-	 * @param a the array where the values should be inserted to
-	 * @return the inputArray
-	 * @throws NullPointerException if the array is null
-	 * @throws IndexOutOfBoundsException if from is outside of the lists range
-	 * @throws IllegalStateException if offset or length are smaller then 0 or exceed the array length
-	 */
-	public default T[] getElements(int from, T[] a) { return getElements(from, a, 0, a.length); }
-
-	/**
-	 * A function to fast fetch elements from the list
-	 * @param from index where the list should be fetching elements from
-	 * @param a the array where the values should be inserted to
-	 * @param offset the startIndex of where the array should be written to
-	 * @param length the number of elements the values should be fetched from
-	 * @return the inputArray
-	 * @throws NullPointerException if the array is null
-	 * @throws IndexOutOfBoundsException if from is outside of the lists range
-	 * @throws IllegalStateException if offset or length are smaller then 0 or exceed the array length
-	 */
-	public T[] getElements(int from, T[] a, int offset, int length);
-
-	/**
-	 * a function to fast remove elements from the list.
-	 * @param from the start index of where the elements should be removed from (inclusive)
-	 * @param to the end index of where the elements should be removed to (exclusive)
-	 */
-	public void removeElements(int from, int to);
-
-	/**
-	 * A Highly Optimized remove function that removes the desired element.
-	 * But instead of shifting the elements to the left it moves the last element to the removed space.
-	 * @param index the index of the element to be removed
-	 * @return the element previously at the specified position
-	 */
-	public T swapRemove(int index);
-
-	/**
-	 * A Highly Optimized remove function that removes the desired element.
-	 * But instead of shifting the elements to the left it moves the last element to the removed space.
-	 * @param e the element that should be removed
-	 * @return true if the element was removed
-	 */
-	public boolean swapRemove(T e);
-
-	/**
-	 * A function to fast extract elements out of the list, this removes the elements that were fetched.
-	 * @param from the start index of where the elements should be fetched from (inclusive)
-	 * @param to the end index of where the elements should be fetched to (exclusive)
-	 * @param type the type of the OutputArray
-	 * @return a array of the elements that were fetched
-	 * @param  the keyType of elements maintained by this Collection
- 	 */
-	public  K[] extractElements(int from, int to, Class type);
-
-	/**
-	 * Sorts the elements specified by the Natural order either by using the Comparator or the elements
-	 * @see List#sort(Comparator)
-	 */
-	@Override
-	public default void sort(Comparator c) {
-		T[] array = (T[])toArray();
-		if(c != null) ObjectArrays.stableSort(array, c);
-		else ObjectArrays.stableSort(array);
-		ObjectListIterator iter = listIterator();
-		for (int i = 0,m=size();i c) {
-		T[] array = (T[])toArray();
-		if(c != null) ObjectArrays.unstableSort(array, c);
-		else ObjectArrays.unstableSort(array);
-		ObjectListIterator iter = listIterator();
-		for (int i = 0,m=size();i action) {
-		Objects.requireNonNull(action);
-		for(int i = 0,m=size();i listIterator();
-
-	/**
-	 * A Type-Specific Iterator of listIterator
-	 * @see List#listIterator(int)
-	 */
-	@Override
-	public ObjectListIterator listIterator(int index);
-
-	/**
-	 * A Type-Specific List of subList
-	 * @see List#subList(int, int)
-	 */
-	@Override
-	public ObjectList subList(int from, int to);
-
-	/**
-	 * A function to ensure the elements are within the requested size.
-	 * If smaller then the stored elements they get removed as needed.
-	 * If bigger it is ensured that enough room is provided depending on the implementation
-	 * @param size the requested amount of elements/room for elements
-	 */
-	public void size(int size);
-
-	@Override
-	public ObjectList copy();
-	/**
-	 * A Type Specific Type Splititerator to reduce boxing/unboxing
-	 * @return type specific splititerator
-	 */
-	@Override
-	default ObjectSplititerator spliterator() { return ObjectSplititerators.createSplititerator(this, 0); }
-}
diff --git a/src/main/java/speiger/src/collections/objects/lists/ObjectListIterator.java b/src/main/java/speiger/src/collections/objects/lists/ObjectListIterator.java
deleted file mode 100644
index 87e6d421f..000000000
--- a/src/main/java/speiger/src/collections/objects/lists/ObjectListIterator.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package speiger.src.collections.objects.lists;
-
-import java.util.ListIterator;
-
-import speiger.src.collections.objects.collections.ObjectBidirectionalIterator;
-
-/**
- * A Type Specific ListIterator that reduces boxing/unboxing
- * @param  the keyType of elements maintained by this Collection
- */
-public interface ObjectListIterator extends ListIterator, ObjectBidirectionalIterator
-{
-}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/maps/abstracts/AbstractObject2ObjectMap.java b/src/main/java/speiger/src/collections/objects/maps/abstracts/AbstractObject2ObjectMap.java
deleted file mode 100644
index 8f6964218..000000000
--- a/src/main/java/speiger/src/collections/objects/maps/abstracts/AbstractObject2ObjectMap.java
+++ /dev/null
@@ -1,426 +0,0 @@
-package speiger.src.collections.objects.maps.abstracts;
-
-import java.util.AbstractMap;
-import java.util.Map;
-import java.util.Objects;
-
-import speiger.src.collections.objects.collections.ObjectIterator;
-import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
-import speiger.src.collections.objects.functions.function.UnaryOperator;
-import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator;
-import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
-import speiger.src.collections.objects.sets.AbstractObjectSet;
-import speiger.src.collections.objects.sets.ObjectSet;
-import speiger.src.collections.objects.collections.AbstractObjectCollection;
-import speiger.src.collections.objects.collections.ObjectCollection;
-import speiger.src.collections.objects.functions.ObjectSupplier;
-import speiger.src.collections.objects.collections.ObjectIterable;
-import speiger.src.collections.utils.SanityChecks;
-
-/**
- * A Base Implementation of a Type Specific Map to reduce boxing/unboxing
- * @param  the keyType of elements maintained by this Collection
- * @param  the keyType of elements maintained by this Collection
- */
-public abstract class AbstractObject2ObjectMap extends AbstractMap implements Object2ObjectMap
-{
-	protected V defaultReturnValue = null;
-	
-	@Override
-	public V getDefaultReturnValue() {
-		return defaultReturnValue;
-	}
-	
-	@Override
-	public AbstractObject2ObjectMap setDefaultReturnValue(V v) {
-		defaultReturnValue = v;
-		return this;
-	}
-	
-	protected ObjectIterable> getFastIterable(Object2ObjectMap map) {
-		return map.object2ObjectEntrySet();
-	}
-	
-	protected ObjectIterator> getFastIterator(Object2ObjectMap map) {
-		return map.object2ObjectEntrySet().iterator();
-	}
-	
-	@Override
-	public Object2ObjectMap copy() { 
-		throw new UnsupportedOperationException();
-	}
-	
-	@Override
-	public void putAll(Object2ObjectMap m) {
-		for(ObjectIterator> iter = getFastIterator(m);iter.hasNext();) {
-			Object2ObjectMap.Entry entry = iter.next();
-			put(entry.getKey(), entry.getValue());
-		}
-	}
-	
-	@Override
-	public void putAll(Map m)
-	{
-		if(m instanceof Object2ObjectMap) putAll((Object2ObjectMap)m);
-		else super.putAll(m);
-	}
-	
-	@Override
-	public void putAll(T[] keys, V[] values, int offset, int size) {
-		SanityChecks.checkArrayCapacity(keys.length, offset, size);
-		SanityChecks.checkArrayCapacity(values.length, offset, size);
-		for(int i = 0;i m) {
-		for(Object2ObjectMap.Entry entry : getFastIterable(m))
-			putIfAbsent(entry.getKey(), entry.getValue());
-	}
-	
-	
-	@Override
-	public boolean containsKey(Object key) {
-		for(ObjectIterator iter = keySet().iterator();iter.hasNext();)
-			if(Objects.equals(key, iter.next())) return true;
-		return false;
-	}
-	
-	@Override
-	public boolean containsValue(Object value) {
-		for(ObjectIterator iter = values().iterator();iter.hasNext();)
-			if(Objects.equals(value, iter.next())) return true;
-		return false;
-	}
-	
-	@Override
-	public boolean replace(T key, V oldValue, V newValue) {
-		V curValue = getObject(key);
-		if (!Objects.equals(curValue, oldValue) || (Objects.equals(curValue, getDefaultReturnValue()) && !containsKey(key))) {
-			return false;
-		}
-		put(key, newValue);
-		return true;
-	}
-
-	@Override
-	public V replace(T key, V value) {
-		V curValue;
-		if (!Objects.equals((curValue = getObject(key)), getDefaultReturnValue()) || containsKey(key)) {
-			curValue = put(key, value);
-		}
-		return curValue;
-	}
-	
-	@Override
-	public void replaceObjects(Object2ObjectMap m) {
-		for(Object2ObjectMap.Entry entry : getFastIterable(m))
-			replace(entry.getKey(), entry.getValue());
-	}
-	
-	@Override
-	public void replaceObjects(ObjectObjectUnaryOperator mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		for(ObjectIterator> iter = getFastIterator(this);iter.hasNext();) {
-			Object2ObjectMap.Entry entry = iter.next();
-			entry.setValue(mappingFunction.apply(entry.getKey(), entry.getValue()));
-		}
-	}
-
-	@Override
-	public V compute(T key, ObjectObjectUnaryOperator mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		V value = getObject(key);
-		V newValue = mappingFunction.apply(key, value);
-		if(Objects.equals(newValue, getDefaultReturnValue())) {
-			if(!Objects.equals(value, getDefaultReturnValue()) || containsKey(key)) {
-				remove(key);
-				return getDefaultReturnValue();
-			}
-			return getDefaultReturnValue();
-		}
-		put(key, newValue);
-		return newValue;
-	}
-	
-	@Override
-	public V computeIfAbsent(T key, UnaryOperator mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		V value;
-		if((value = getObject(key)) == getDefaultReturnValue() || !containsKey(key)) {
-			V newValue = mappingFunction.apply(key);
-			if(!Objects.equals(newValue, getDefaultReturnValue())) {
-				put(key, newValue);
-				return newValue;
-			}
-		}
-		return value;
-	}
-	
-	@Override
-	public V supplyIfAbsent(T key, ObjectSupplier valueProvider) {
-		Objects.requireNonNull(valueProvider);
-		V value;
-		if((value = getObject(key)) == getDefaultReturnValue() || !containsKey(key)) {
-			V newValue = valueProvider.get();
-			if(!Objects.equals(newValue, getDefaultReturnValue())) {
-				put(key, newValue);
-				return newValue;
-			}
-		}
-		return value;
-	}
-	
-	@Override
-	public V computeIfPresent(T key, ObjectObjectUnaryOperator mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		V value;
-		if(!Objects.equals((value = getObject(key)), getDefaultReturnValue()) || containsKey(key)) {
-			V newValue = mappingFunction.apply(key, value);
-			if(!Objects.equals(newValue, getDefaultReturnValue())) {
-				put(key, newValue);
-				return newValue;
-			}
-			remove(key);
-		}
-		return getDefaultReturnValue();
-	}
-
-	@Override
-	public V merge(T key, V value, ObjectObjectUnaryOperator mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		V oldValue = getObject(key);
-		V newValue = Objects.equals(oldValue, getDefaultReturnValue()) ? value : mappingFunction.apply(oldValue, value);
-		if(Objects.equals(newValue, getDefaultReturnValue())) remove(key);
-		else put(key, newValue);
-		return newValue;
-	}
-	
-	@Override
-	public void mergeAll(Object2ObjectMap m, ObjectObjectUnaryOperator mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		for(Object2ObjectMap.Entry entry : getFastIterable(m)) {
-			T key = entry.getKey();
-			V oldValue = getObject(key);
-			V newValue = Objects.equals(oldValue, getDefaultReturnValue()) ? entry.getValue() : mappingFunction.apply(oldValue, entry.getValue());
-			if(Objects.equals(newValue, getDefaultReturnValue())) remove(key);
-			else put(key, newValue);
-		}
-	}
-	
-	@Override
-	public V get(Object key) {
-		return getObject((T)key);
-	}
-	
-	@Override
-	public V getOrDefault(Object key, V defaultValue) {
-		V value = get(key);
-		return !Objects.equals(value, getDefaultReturnValue()) || containsKey(key) ? value : defaultValue;
-	}
-	
-	
-	@Override
-	public V remove(Object key) {
-		return rem((T)key);
-	}
-	
-	@Override
-	public void forEach(ObjectObjectConsumer action) {
-		Objects.requireNonNull(action);
-		for(ObjectIterator> iter = getFastIterator(this);iter.hasNext();) {
-			Object2ObjectMap.Entry entry = iter.next();
-			action.accept(entry.getKey(), entry.getValue());
-		}
-	}
-
-	@Override
-	public ObjectSet keySet() {
-		return new AbstractObjectSet() {
-			@Override
-			public boolean remove(Object o) {
-				if(AbstractObject2ObjectMap.this.containsKey(o)) {
-					AbstractObject2ObjectMap.this.remove(o);
-					return true;
-				}
-				return false;
-			}
-			
-			@Override
-			public boolean add(T o) {
-				throw new UnsupportedOperationException();
-			}
-			
-			@Override
-			public ObjectIterator iterator() {
-				return new ObjectIterator() {
-					ObjectIterator> iter = getFastIterator(AbstractObject2ObjectMap.this);
-					@Override
-					public boolean hasNext() {
-						return iter.hasNext();
-					}
-
-					@Override
-					public T next() {
-						return iter.next().getKey();
-					}
-					
-					@Override
-					public void remove() {
-						iter.remove();
-					}
-				};
-			}
-			
-			@Override
-			public int size() {
-				return AbstractObject2ObjectMap.this.size();
-			}
-			
-			@Override
-			public void clear() {
-				AbstractObject2ObjectMap.this.clear();
-			}
-		};
-	}
-
-	@Override
-	public ObjectCollection values() {
-		return new AbstractObjectCollection() {
-			@Override
-			public boolean add(V o) {
-				throw new UnsupportedOperationException();
-			}
-			
-			@Override
-			public int size() {
-				return AbstractObject2ObjectMap.this.size();
-			}
-			
-			@Override
-			public void clear() {
-				AbstractObject2ObjectMap.this.clear();
-			}
-			
-			@Override
-			public ObjectIterator iterator() {
-				return new ObjectIterator() {
-					ObjectIterator> iter = getFastIterator(AbstractObject2ObjectMap.this);
-					@Override
-					public boolean hasNext() {
-						return iter.hasNext();
-					}
-					
-					@Override
-					public V next() {
-						return iter.next().getValue();
-					}
-					
-					@Override
-					public void remove() {
-						iter.remove();
-					}
-				};
-			}
-		};
-	}
-	
-	@Override
-	@SuppressWarnings("rawtypes")
-	public ObjectSet> entrySet() {
-		return (ObjectSet)object2ObjectEntrySet();
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		if(o == this) return true;
-		if(o instanceof Map) {
-			if(size() != ((Map)o).size()) return false;
-			if(o instanceof Object2ObjectMap) return object2ObjectEntrySet().containsAll(((Object2ObjectMap)o).object2ObjectEntrySet());
-			return object2ObjectEntrySet().containsAll(((Map)o).entrySet());
-		}
-		return false;
-	}
-	
-	@Override
-	public int hashCode() {
-		int hash = 0;
-		ObjectIterator> iter = getFastIterator(this);
-		while(iter.hasNext()) hash += iter.next().hashCode();
-		return hash;
-	}
-	
-	/**
-	 * A Simple Type Specific Entry class to reduce boxing/unboxing
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  the keyType of elements maintained by this Collection
-	 */
-	public static class BasicEntry implements Object2ObjectMap.Entry {
-		protected T key;
-		protected V value;
-		
-		/**
-		 * A basic Empty constructor
-		 */
-		public BasicEntry() {}
-		/**
-		 * A Type Specific Constructor
-		 * @param key the key of a entry
-		 * @param value the value of a entry 
-		 */
-		public BasicEntry(T key, V value) {
-			this.key = key;
-			this.value = value;
-		}
-		
-		/**
-		 * A Helper method for fast replacing values
-		 * @param key the key that should be replaced
-		 * @param value the value that should be replaced
-		 */
-		public void set(T key, V value) {
-			this.key = key;
-			this.value = value;
-		}
-		
-		@Override
-		public T getKey() {
-			return key;
-		}
-
-		@Override
-		public V getValue() {
-			return value;
-		}
-
-		@Override
-		public V setValue(V value) {
-			throw new UnsupportedOperationException();
-		}
-		
-		@Override
-		public boolean equals(Object obj) {
-			if(obj instanceof Map.Entry) {
-				if(obj instanceof Object2ObjectMap.Entry) {
-					Object2ObjectMap.Entry entry = (Object2ObjectMap.Entry)obj;
-					return Objects.equals(key, entry.getKey()) && Objects.equals(value, entry.getValue());
-				}
-				Map.Entry entry = (Map.Entry)obj;
-				Object key = entry.getKey();
-				Object value = entry.getValue();
-				return Objects.equals(this.key, key) && Objects.equals(this.value, value);
-			}
-			return false;
-		}
-		
-		@Override
-		public int hashCode() {
-			return Objects.hashCode(key) ^ Objects.hashCode(value);
-		}
-		
-		@Override
-		public String toString() {
-			return Objects.toString(key) + "=" + Objects.toString(value);
-		}
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/maps/impl/hash/Object2ObjectOpenHashMap.java b/src/main/java/speiger/src/collections/objects/maps/impl/hash/Object2ObjectOpenHashMap.java
deleted file mode 100644
index 721708384..000000000
--- a/src/main/java/speiger/src/collections/objects/maps/impl/hash/Object2ObjectOpenHashMap.java
+++ /dev/null
@@ -1,1258 +0,0 @@
-package speiger.src.collections.objects.maps.impl.hash;
-
-import java.util.Arrays;
-import java.util.ConcurrentModificationException;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.function.Consumer;
-import java.util.function.BiFunction;
-import java.util.function.Predicate;
-
-import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
-import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
-import speiger.src.collections.objects.functions.function.UnaryOperator;
-import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator;
-import speiger.src.collections.objects.maps.abstracts.AbstractObject2ObjectMap;
-import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
-import speiger.src.collections.objects.collections.AbstractObjectCollection;
-import speiger.src.collections.objects.collections.ObjectCollection;
-import speiger.src.collections.objects.functions.ObjectSupplier;
-import speiger.src.collections.objects.collections.ObjectIterator;
-import speiger.src.collections.objects.sets.AbstractObjectSet;
-import speiger.src.collections.objects.sets.ObjectSet;
-import speiger.src.collections.utils.HashUtil;
-import speiger.src.collections.utils.ITrimmable;
-
-/**
- * A Type Specific Custom implementation of the HashMap
- * Instead of using Wrapper Object Arrays for storing keys and values there is dedicated arrays for storing keys and values.
- * Extra to that there is a couple quality of life functions provided
- * @param  the keyType of elements maintained by this Collection
- * @param  the keyType of elements maintained by this Collection
- */
-public class Object2ObjectOpenHashMap extends AbstractObject2ObjectMap implements ITrimmable
-{
-	/** The Backing keys array */
-	protected transient T[] keys;
-	/** The Backing values array */
-	protected transient V[] values;
-	/** If a null value is present */
-	protected transient boolean containsNull;
-	/** Minimum array size the HashMap will be */
-	protected transient int minCapacity;
-	/** Index of the Null Value */
-	protected transient int nullIndex;
-	/** Maximum amount of Values that can be stored before the array gets expanded usually 75% */
-	protected transient int maxFill;
-	/** Max Index that is allowed to be searched through nullIndex - 1 */
-	protected transient int mask;
-	/** EntrySet cache */
-	protected transient FastEntrySet entrySet;
-	/** KeySet cache */
-	protected transient ObjectSet keySet;
-	/** Values cache */
-	protected transient ObjectCollection valuesC;
-
-	/** Amount of Elements stored in the HashMap */
-	protected int size;
-	/** How full the Arrays are allowed to get before resize */
-	protected final float loadFactor;
-
-	/**
-	 * Default Constructor
-	 */
-	public Object2ObjectOpenHashMap() {
-		this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-
-	/**
-	 * Constructor that defines the minimum capacity
-	 * @param minCapacity the minimum capacity the HashMap is allowed to be.
-	 * @throws IllegalStateException if the minimum capacity is negative
-	 */
-	public Object2ObjectOpenHashMap(int minCapacity) {
-		this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-
-	/**
-	 * Constructor that defines the minimum capacity and load factor
-	 * @param minCapacity the minimum capacity the HashMap is allowed to be.
-	 * @param loadFactor the percentage of how full the backing array can be before they resize
-	 * @throws IllegalStateException if the minimum capacity is negative
-	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
-	 */
-	public Object2ObjectOpenHashMap(int minCapacity, float loadFactor) {
-		if(minCapacity < 0)	throw new IllegalStateException("Minimum Capacity is negative. This is not allowed");
-		if(loadFactor <= 0 || loadFactor >= 1F) throw new IllegalStateException("Load Factor is not between 0 and 1");
-		this.loadFactor = loadFactor;
-		this.minCapacity = nullIndex = HashUtil.arraySize(minCapacity, loadFactor);
-		mask = nullIndex - 1;
-		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
-		keys = (T[])new Object[nullIndex + 1];
-		values = (V[])new Object[nullIndex + 1];
-	}
-
-	/**
-	 * Helper constructor that allow to create a map from unboxed values
-	 * @param keys the keys that should be put into the map
-	 * @param values the values that should be put into the map.
-	 * @throws IllegalStateException if the keys and values do not match in lenght
-	 */
-	public Object2ObjectOpenHashMap(T[] keys, V[] values) {
-		this(keys, values, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-
-	/**
-	 * Helper constructor that allow to create a map from unboxed values
-	 * @param keys the keys that should be put into the map
-	 * @param values the values that should be put into the map.
-	 * @param loadFactor the percentage of how full the backing array can be before they resize
-	 * @throws IllegalStateException if the keys and values do not match in lenght
-	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
-	 */
-	public Object2ObjectOpenHashMap(T[] keys, V[] values, float loadFactor) {
-		this(keys.length, loadFactor);
-		if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size");
-		for(int i = 0,m=keys.length;i map) {
-		this(map, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-
-	/**
-	 * A Helper constructor that allows to create a Map with exactly the same values as the provided map.
-	 * @param map the values that should be present in the map
-	 * @param loadFactor the percentage of how full the backing array can be before they resize
-	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
-	 */
-	public Object2ObjectOpenHashMap(Map map, float loadFactor) {
-		this(map.size(), loadFactor);
-		putAll(map);
-	}
-
-	/**
-	 * A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map.
-	 * @param map the values that should be present in the map
- 	 */
-	public Object2ObjectOpenHashMap(Object2ObjectMap map) {
-		this(map, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-
-	/**
-	 * A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map.
-	 * @param map the values that should be present in the map
-	 * @param loadFactor the percentage of how full the backing array can be before they resize
-	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
- 	 */
-	public Object2ObjectOpenHashMap(Object2ObjectMap map, float loadFactor) {
-		this(map.size(), loadFactor);
-		putAll(map);
-	}
-
-	@Override
-	public V put(T key, V value) {
-		int slot = findIndex(key);
-		if(slot < 0) {
-			insert(-slot-1, key, value);
-			return getDefaultReturnValue();
-		}
-		V oldValue = values[slot];
-		values[slot] = value;
-		return oldValue;
-	}
-
-	@Override
-	public V putIfAbsent(T key, V value) {
-		int slot = findIndex(key);
-		if(slot < 0) {
-			insert(-slot-1, key, value);
-			return getDefaultReturnValue();
-		}
-		else if(Objects.equals(values[slot], getDefaultReturnValue())) {
-			V oldValue = values[slot];
-			values[slot] = value;
-			return oldValue;
-		}
-		return values[slot];
-	}
-
-	@Override
-	public boolean containsKey(Object key) {
-		return findIndex(key) >= 0;
-	}
-
-	@Override
-	public boolean containsValue(Object value) {
-		if(containsNull && Objects.equals(values[nullIndex], value)) return true;
-		for(int i = nullIndex-1;i >= 0;i--)
-			if(keys[i] != null && Objects.equals(value, values[i])) return true;
-		return false;
-	}
-
-	@Override
-	public V rem(T key) {
-		int slot = findIndex(key);
-		if(slot < 0) return getDefaultReturnValue();
-		return removeIndex(slot);
-	}
-
-	@Override
-	public V remOrDefault(T key, V defaultValue) {
-		int slot = findIndex(key);
-		if(slot < 0) return defaultValue;
-		return removeIndex(slot);
-	}
-
-	@Override
-	public V remove(Object key) {
-		int slot = findIndex(key);
-		if(slot < 0) return getDefaultReturnValue();
-		return removeIndex(slot);
-	}
-
-	@Override
-	public boolean remove(Object key, Object value) {
-		Objects.requireNonNull(value);
-		if(key == null) {
-			if(containsNull && Objects.equals(value, values[nullIndex])) {
-				removeNullIndex();
-				return true;
-			}
-			return false;
-		}
-		int pos = HashUtil.mix(key.hashCode()) & mask;
-		T current = keys[pos];
-		if(current == null) return false;
-		if(Objects.equals(key, current) && Objects.equals(value, values[pos])) {
-			removeIndex(pos);
-			return true;
-		}
-		while(true) {
-			if((current = keys[pos = (++pos & mask)]) == null) return false;
-			else if(Objects.equals(key, current) && Objects.equals(value, values[pos])){
-				removeIndex(pos);
-				return true;
-			}
-		}
-	}
-
-	@Override
-	public V getObject(T key) {
-		int slot = findIndex(key);
-		return slot < 0 ? getDefaultReturnValue() : values[slot];
-	}
-
-	@Override
-	public V get(Object key) {
-		int slot = findIndex(key);
-		return slot < 0 ? getDefaultReturnValue() : values[slot];
-	}
-
-	@Override
-	public V getOrDefault(Object key, V defaultValue) {
-		int slot = findIndex(key);
-		return slot < 0 ? defaultValue : values[slot];
-	}
-
-	@Override
-	public Object2ObjectOpenHashMap copy() {
-		Object2ObjectOpenHashMap map = new Object2ObjectOpenHashMap<>(0, loadFactor);
-		map.minCapacity = minCapacity;
-		map.mask = mask;
-		map.maxFill = maxFill;
-		map.nullIndex = nullIndex;
-		map.containsNull = containsNull;
-		map.size = size;
-		map.keys = Arrays.copyOf(keys, keys.length);
-		map.values = Arrays.copyOf(values, values.length);
-		return map;
-	}
-
-	@Override
-	public ObjectSet> object2ObjectEntrySet() {
-		if(entrySet == null) entrySet = new MapEntrySet();
-		return entrySet;
-	}
-
-	@Override
-	public ObjectSet keySet() {
-		if(keySet == null) keySet = new KeySet();
-		return keySet;
-	}
-
-	@Override
-	public ObjectCollection values() {
-		if(valuesC == null) valuesC = new Values();
-		return valuesC;
-	}
-
-	@Override
-	public void forEach(ObjectObjectConsumer action) {
-		if(size() <= 0) return;
-		if(containsNull) action.accept(keys[nullIndex], values[nullIndex]);
-		for(int i = nullIndex-1;i>=0;i--) {
-			if(keys[i] != null) action.accept(keys[i], values[i]);
-		}
-	}
-
-	@Override
-	public boolean replace(T key, V oldValue, V newValue) {
-		int index = findIndex(key);
-		if(index < 0 || values[index] != oldValue) return false;
-		values[index] = newValue;
-		return true;
-	}
-
-	@Override
-	public V replace(T key, V value) {
-		int index = findIndex(key);
-		if(index < 0) return getDefaultReturnValue();
-		V oldValue = values[index];
-		values[index] = value;
-		return oldValue;
-	}
-
-	@Override
-	public V compute(T key, ObjectObjectUnaryOperator mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		int index = findIndex(key);
-		if(index < 0) {
-			V newValue = mappingFunction.apply(key, getDefaultReturnValue());
-			if(Objects.equals(newValue, getDefaultReturnValue())) return newValue;
-			insert(-index-1, key, newValue);
-			return newValue;
-		}
-		V newValue = mappingFunction.apply(key, values[index]);
-		if(Objects.equals(newValue, getDefaultReturnValue())) {
-			removeIndex(index);
-			return newValue;
-		}
-		values[index] = newValue;
-		return newValue;
-	}
-
-	@Override
-	public V computeIfAbsent(T key, UnaryOperator mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		int index = findIndex(key);
-		if(index < 0) {
-			V newValue = mappingFunction.apply(key);
-			if(Objects.equals(newValue, getDefaultReturnValue())) return newValue;
-			insert(-index-1, key, newValue);
-			return newValue;
-		}
-		V newValue = values[index];
-		if(Objects.equals(newValue, getDefaultReturnValue())) {
-			newValue = mappingFunction.apply(key);
-			if(Objects.equals(newValue, getDefaultReturnValue())) return newValue;
-			values[index] = newValue;
-		}
-		return newValue;
-	}
-
-	@Override
-	public V supplyIfAbsent(T key, ObjectSupplier valueProvider) {
-		Objects.requireNonNull(valueProvider);
-		int index = findIndex(key);
-		if(index < 0) {
-			V newValue = valueProvider.get();
-			if(Objects.equals(newValue, getDefaultReturnValue())) return newValue;
-			insert(-index-1, key, newValue);
-			return newValue;
-		}
-		V newValue = values[index];
-		if(Objects.equals(newValue, getDefaultReturnValue())) {
-			newValue = valueProvider.get();
-			if(Objects.equals(newValue, getDefaultReturnValue())) return newValue;
-			values[index] = newValue;
-		}
-		return newValue;
-	}
-
-	@Override
-	public V computeIfPresent(T key, ObjectObjectUnaryOperator mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		int index = findIndex(key);
-		if(index < 0 || Objects.equals(values[index], getDefaultReturnValue())) return getDefaultReturnValue();
-		V newValue = mappingFunction.apply(key, values[index]);
-		if(Objects.equals(newValue, getDefaultReturnValue())) {
-			removeIndex(index);
-			return newValue;
-		}
-		values[index] = newValue;
-		return newValue;
-	}
-
-	@Override
-	public V merge(T key, V value, ObjectObjectUnaryOperator mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		Objects.requireNonNull(value);
-		int index = findIndex(key);
-		V newValue = index < 0 || Objects.equals(values[index], getDefaultReturnValue()) ? value : mappingFunction.apply(values[index], value);
-		if(Objects.equals(newValue, getDefaultReturnValue())) {
-			if(index >= 0)
-				removeIndex(index);
-		}
-		else if(index < 0) insert(-index-1, key, newValue);
-		else values[index] = newValue;
-		return newValue;
-	}
-
-	@Override
-	public void mergeAll(Object2ObjectMap m, ObjectObjectUnaryOperator mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		for(Object2ObjectMap.Entry entry : getFastIterable(m)) {
-			T key = entry.getKey();
-			int index = findIndex(key);
-			V newValue = index < 0 || Objects.equals(values[index], getDefaultReturnValue()) ? entry.getValue() : mappingFunction.apply(values[index], entry.getValue());
-			if(Objects.equals(newValue, getDefaultReturnValue())) {
-				if(index >= 0)
-					removeIndex(index);
-			}
-			else if(index < 0) insert(-index-1, key, newValue);
-			else values[index] = newValue;
-		}
-	}
-
-	@Override
-	public int size() { return size; }
-
-	@Override
-	public void clear() {
-		if(size == 0) return;
-		size = 0;
-		containsNull = false;
-		Arrays.fill(keys, null);
-		Arrays.fill(values, null);
-	}
-
-	@Override
-	public boolean trim(int size) {
-		int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor)));
-		if(request >= nullIndex || this.size >= Math.min((int)Math.ceil(request * loadFactor), request - 1)) return false;
-		try {
-			rehash(request);
-		}
-		catch(OutOfMemoryError noMemory) { return false; }
-		return true;
-	}
-
-	@Override
-	public void clearAndTrim(int size) {
-		int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor)));
-		if(request >= nullIndex) {
-			clear();
-			return;
-		}
-		nullIndex = request;
-		mask = request-1;
-		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
-		keys = (T[])new Object[request + 1];
-		values = (V[])new Object[request + 1];
-		this.size = 0;
-		containsNull = false;
-	}
-
-	protected int findIndex(Object key) {
-		if(key == null) return containsNull ? nullIndex : -(nullIndex + 1);
-		int pos = HashUtil.mix(key.hashCode()) & mask;
-		T current = keys[pos];
-		if(current != null) {
-			if(Objects.equals(key, current)) return pos;
-			while((current = keys[pos = (++pos & mask)]) != null)
-				if(Objects.equals(key, current)) return pos;
-		}
-		return -(pos + 1);
-	}
-
-	protected V removeIndex(int pos) {
-		if(pos == nullIndex) return containsNull ? removeNullIndex() : getDefaultReturnValue();
-		V value = values[pos];
-		keys[pos] = null;
-		values[pos] = null;
-		size--;
-		onNodeRemoved(pos);
-		shiftKeys(pos);
-		if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
-		return value;
-	}
-
-	protected V removeNullIndex() {
-		V value = values[nullIndex];
-		containsNull = false;
-		keys[nullIndex] = null;
-		values[nullIndex] = null;
-		size--;
-		onNodeRemoved(nullIndex);
-		if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
-		return value;
-	}
-
-	protected void insert(int slot, T key, V value) {
-		if(slot == nullIndex) containsNull = true;
-		keys[slot] = key;
-		values[slot] = value;
-		onNodeAdded(slot);
-		if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor));
-	}
-
-	protected void rehash(int newSize) {
-		int newMask = newSize - 1;
-		T[] newKeys = (T[])new Object[newSize + 1];
-		V[] newValues = (V[])new Object[newSize + 1];
-		for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) {
-			while(true) {
-				if(--i < 0) throw new ConcurrentModificationException("Map was modified during rehash");
-				if(keys[i] != null) break;
-			}
-			if(newKeys[pos = HashUtil.mix(Objects.hashCode(keys[i])) & newMask] != null)
-				while(newKeys[pos = (++pos & newMask)] != null);
-			newKeys[pos] = keys[i];
-			newValues[pos] = values[i];
-		}
-		newValues[newSize] = values[nullIndex];
-		nullIndex = newSize;
-		mask = newMask;
-		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
-		keys = newKeys;
-		values = newValues;
-	}
-
-	protected void onNodeAdded(int pos) {
-
-	}
-
-	protected void onNodeRemoved(int pos) {
-
-	}
-
-	protected void onNodeMoved(int from, int to) {
-
-	}
-
-	protected void shiftKeys(int startPos) {
-		int slot, last;
-		T current;
-		while(true) {
-			startPos = ((last = startPos) + 1) & mask;
-			while(true){
-				if((current = keys[startPos]) == null) {
-					keys[last] = null;
-					values[last] = null;
-					return;
-				}
-				slot = HashUtil.mix(Objects.hashCode(current)) & mask;
-				if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
-				startPos = ++startPos & mask;
-			}
-			keys[last] = current;
-			values[last] = values[startPos];
-			onNodeMoved(startPos, last);
-		}
-	}
-
-	protected class MapEntry implements Object2ObjectMap.Entry, Map.Entry {
-		public int index = -1;
-
-		public MapEntry() {}
-		public MapEntry(int index) {
-			this.index = index;
-		}
-
-		@Override
-		public T getKey() {
-			return keys[index];
-		}
-
-		@Override
-		public V getValue() {
-			return values[index];
-		}
-
-		@Override
-		public V setValue(V value) {
-			V oldValue = values[index];
-			values[index] = value;
-			return oldValue;
-		}
-
-		@Override
-		public boolean equals(Object obj) {
-			if(obj instanceof Map.Entry) {
-				if(obj instanceof Object2ObjectMap.Entry) {
-					Object2ObjectMap.Entry entry = (Object2ObjectMap.Entry)obj;
-					return Objects.equals(keys[index], entry.getKey()) && Objects.equals(values[index], entry.getValue());
-				}
-				Map.Entry entry = (Map.Entry)obj;
-				Object key = entry.getKey();
-				Object value = entry.getValue();
-				return Objects.equals(keys[index], key) && Objects.equals(values[index], value);
-			}
-			return false;
-		}
-
-		@Override
-		public int hashCode() {
-			return Objects.hashCode(keys[index]) ^ Objects.hashCode(values[index]);
-		}
-
-		@Override
-		public String toString() {
-			return Objects.toString(keys[index]) + "=" + Objects.toString(values[index]);
-		}
-	}
-
-	private final class MapEntrySet extends AbstractObjectSet> implements FastEntrySet {
-		@Override
-		public ObjectIterator> fastIterator() {
-			return new FastEntryIterator();
-		}
-
-		@Override
-		public ObjectIterator> iterator() {
-			return new EntryIterator();
-		}
-
-		@Override
-		public void forEach(Consumer> action) {
-			if(containsNull) action.accept(new BasicEntry<>(keys[nullIndex], values[nullIndex]));
-			for(int i = nullIndex-1;i>=0;i--)
-				if(keys[i] != null) action.accept(new BasicEntry<>(keys[i], values[i]));
-		}
-
-		@Override
-		public void fastForEach(Consumer> action) {
-			BasicEntry entry = new BasicEntry<>();
-			if(containsNull) {
-				entry.set(keys[nullIndex], values[nullIndex]);
-				action.accept(entry);
-			}
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null) {
-					entry.set(keys[i], values[i]);
-					action.accept(entry);
-				}
-			}
-		}
-
-		@Override
-		public void forEachIndexed(IntObjectConsumer> action) {
-			Objects.requireNonNull(action);
-			if(size() <= 0) return;
-			if(containsNull) action.accept(0, new BasicEntry<>(keys[nullIndex], values[nullIndex]));
-			for(int i = nullIndex-1, index = containsNull ? 1 : 0;i>=0;i--) {
-				if(keys[i] != null) action.accept(index++, new BasicEntry<>(keys[i], values[i]));
-			}
-		}
-
-		@Override
-		public  void forEach(E input, ObjectObjectConsumer> action) {
-			Objects.requireNonNull(action);
-			if(size() <= 0) return;
-			if(containsNull) action.accept(input, new BasicEntry<>(keys[nullIndex], values[nullIndex]));
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null) action.accept(input, new BasicEntry<>(keys[i], values[i]));
-			}
-		}
-
-		@Override
-		public boolean matchesAny(Predicate> filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return false;
-			BasicEntry entry = new BasicEntry<>();
-			if(containsNull) {
-				entry.set(keys[nullIndex], values[nullIndex]);
-				if(filter.test(entry)) return true;
-			}
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null) {
-					entry.set(keys[i], values[i]);
-					if(filter.test(entry)) return true;
-				}
-			}
-			return false;
-		}
-
-		@Override
-		public boolean matchesNone(Predicate> filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return true;
-			BasicEntry entry = new BasicEntry<>();
-			if(containsNull) {
-				entry.set(keys[nullIndex], values[nullIndex]);
-				if(filter.test(entry)) return false;
-			}
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null) {
-					entry.set(keys[i], values[i]);
-					if(filter.test(entry)) return false;
-				}
-			}
-			return true;
-		}
-
-		@Override
-		public boolean matchesAll(Predicate> filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return true;
-			BasicEntry entry = new BasicEntry<>();
-			if(containsNull) {
-				entry.set(keys[nullIndex], values[nullIndex]);
-				if(!filter.test(entry)) return false;
-			}
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null) {
-					entry.set(keys[i], values[i]);
-					if(!filter.test(entry)) return false;
-				}
-			}
-			return true;
-		}
-
-		@Override
-		public  E reduce(E identity, BiFunction, E> operator) {
-			Objects.requireNonNull(operator);
-			E state = identity;
-			if(containsNull) state = operator.apply(state, new BasicEntry<>(keys[nullIndex], values[nullIndex]));
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] == null) continue;
-				state = operator.apply(state, new BasicEntry<>(keys[i], values[i]));
-			}
-			return state;
-		}
-
-		@Override
-		public Object2ObjectMap.Entry reduce(ObjectObjectUnaryOperator, Object2ObjectMap.Entry> operator) {
-			Objects.requireNonNull(operator);
-			Object2ObjectMap.Entry state = null;
-			boolean empty = true;
-			if(containsNull) {
-				state = new BasicEntry<>(keys[nullIndex], values[nullIndex]);
-				empty = false;
-			}
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] == null) continue;
-				if(empty) {
-					empty = false;
-					state = new BasicEntry<>(keys[i], values[i]);
-					continue;
-				}
-				state = operator.apply(state, new BasicEntry<>(keys[i], values[i]));
-			}
-			return state;
-		}
-
-		@Override
-		public Object2ObjectMap.Entry findFirst(Predicate> filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return null;
-			BasicEntry entry = new BasicEntry<>();
-			if(containsNull) {
-				entry.set(keys[nullIndex], values[nullIndex]);
-				if(filter.test(entry)) return entry;
-			}
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null) {
-					entry.set(keys[i], values[i]);
-					if(filter.test(entry)) return entry;
-				}
-			}
-			return null;
-		}
-
-		@Override
-		public int count(Predicate> filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return 0;
-			BasicEntry entry = new BasicEntry<>();
-			int result = 0;
-			if(containsNull) {
-				entry.set(keys[nullIndex], values[nullIndex]);
-				if(filter.test(entry)) result++;
-			}
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null) {
-					entry.set(keys[i], values[i]);
-					if(filter.test(entry)) result++;
-				}
-			}
-			return result;
-		}
-
-		@Override
-		public int size() {
-			return Object2ObjectOpenHashMap.this.size();
-		}
-
-		@Override
-		public void clear() {
-			Object2ObjectOpenHashMap.this.clear();
-		}
-
-		@Override
-		public boolean contains(Object o) {
-			if(o instanceof Map.Entry) {
-				if(o instanceof Object2ObjectMap.Entry) {
-					Object2ObjectMap.Entry entry = (Object2ObjectMap.Entry)o;
-					int index = Object2ObjectOpenHashMap.this.findIndex(entry.getKey());
-					if(index >= 0) return Objects.equals(entry.getValue(), Object2ObjectOpenHashMap.this.values[index]);
-				}
-				else {
-					Map.Entry entry = (Map.Entry)o;
-					int index = Object2ObjectOpenHashMap.this.findIndex(entry.getKey());
-					if(index >= 0) return Objects.equals(entry.getValue(), Object2ObjectOpenHashMap.this.values[index]);
-				}
-			}
-			return false;
-		}
-
-		@Override
-		public boolean remove(Object o) {
-			if(o instanceof Map.Entry) {
-				if(o instanceof Object2ObjectMap.Entry) {
-					Object2ObjectMap.Entry entry = (Object2ObjectMap.Entry)o;
-					return Object2ObjectOpenHashMap.this.remove(entry.getKey(), entry.getValue());
-				}
-				Map.Entry entry = (Map.Entry)o;
-				return Object2ObjectOpenHashMap.this.remove(entry.getKey(), entry.getValue());
-			}
-			return false;
-		}
-	}
-
-	private final class KeySet extends AbstractObjectSet {
-		@Override
-		public boolean contains(Object e) {
-			return containsKey(e);
-		}
-
-		@Override
-		public boolean remove(Object o) {
-			int oldSize = size;
-			Object2ObjectOpenHashMap.this.remove(o);
-			return size != oldSize;
-		}
-
-		@Override
-		public boolean add(T o) {
-			throw new UnsupportedOperationException();
-		}
-
-		@Override
-		public ObjectIterator iterator() {
-			return new KeyIterator();
-		}
-
-		@Override
-		public int size() {
-			return Object2ObjectOpenHashMap.this.size();
-		}
-
-		@Override
-		public void clear() {
-			Object2ObjectOpenHashMap.this.clear();
-		}
-
-		@Override
-		public KeySet copy() { throw new UnsupportedOperationException(); }
-
-		@Override
-		public void forEach(Consumer action) {
-			if(containsNull) action.accept(keys[nullIndex]);
-			for(int i = nullIndex-1;i>=0;i--)
-				if(keys[i] != null) action.accept(keys[i]);
-		}
-
-		@Override
-		public void forEachIndexed(IntObjectConsumer action) {
-			Objects.requireNonNull(action);
-			if(size() <= 0) return;
-			if(containsNull) action.accept(0, keys[nullIndex]);
-			for(int i = nullIndex-1, index = containsNull ? 1 : 0;i>=0;i--) {
-				if(keys[i] != null) action.accept(index++, keys[i]);
-			}
-		}
-
-		@Override
-		public  void forEach(E input, ObjectObjectConsumer action) {
-			Objects.requireNonNull(action);
-			if(size() <= 0) return;
-			if(containsNull) action.accept(input, keys[nullIndex]);
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null) action.accept(input, keys[i]);
-			}
-		}
-
-		@Override
-		public boolean matchesAny(Predicate filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return false;
-			if(containsNull && filter.test(keys[nullIndex])) return true;
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null && filter.test(keys[i])) return true;
-			}
-			return false;
-		}
-
-		@Override
-		public boolean matchesNone(Predicate filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return true;
-			if(containsNull && filter.test(keys[nullIndex])) return false;
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null && filter.test(keys[i])) return false;
-			}
-			return true;
-		}
-
-		@Override
-		public boolean matchesAll(Predicate filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return true;
-			if(containsNull && !filter.test(keys[nullIndex])) return false;
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null && !filter.test(keys[i])) return false;
-			}
-			return true;
-		}
-
-		@Override
-		public  E reduce(E identity, BiFunction operator) {
-			Objects.requireNonNull(operator);
-			E state = identity;
-			if(containsNull) state = operator.apply(state, keys[nullIndex]);
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] == null) continue;
-				state = operator.apply(state, keys[i]);
-			}
-			return state;
-		}
-
-		@Override
-		public T reduce(ObjectObjectUnaryOperator operator) {
-			Objects.requireNonNull(operator);
-			T state = null;
-			boolean empty = true;
-			if(containsNull) {
-				state = keys[nullIndex];
-				empty = false;
-			}
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] == null) continue;
-				if(empty) {
-					empty = false;
-					state = keys[i];
-					continue;
-				}
-				state = operator.apply(state, keys[i]);
-			}
-			return state;
-		}
-
-		@Override
-		public T findFirst(Predicate filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return null;
-			if(containsNull && filter.test(keys[nullIndex])) return keys[nullIndex];
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null && filter.test(keys[i])) return keys[i];
-			}
-			return null;
-		}
-
-		@Override
-		public int count(Predicate filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return 0;
-			int result = 0;
-			if(containsNull && filter.test(keys[nullIndex])) result++;
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null && filter.test(keys[i])) result++;
-			}
-			return result;
-		}
-	}
-
-	private class Values extends AbstractObjectCollection {
-		@Override
-		public boolean contains(Object e) {
-			return containsValue(e);
-		}
-
-		@Override
-		public boolean add(V o) {
-			throw new UnsupportedOperationException();
-		}
-
-		@Override
-		public ObjectIterator iterator() {
-			return new ValueIterator();
-		}
-
-		@Override
-		public int size() {
-			return Object2ObjectOpenHashMap.this.size();
-		}
-
-		@Override
-		public void clear() {
-			Object2ObjectOpenHashMap.this.clear();
-		}
-
-		@Override
-		public void forEach(Consumer action) {
-			if(containsNull) action.accept(values[nullIndex]);
-			for(int i = nullIndex-1;i>=0;i--)
-				if(keys[i] != null) action.accept(values[i]);
-		}
-
-		@Override
-		public void forEachIndexed(IntObjectConsumer action) {
-			Objects.requireNonNull(action);
-			if(size() <= 0) return;
-			if(containsNull) action.accept(0, values[nullIndex]);
-			for(int i = nullIndex-1, index = containsNull ? 1 : 0;i>=0;i--) {
-				if(keys[i] != null) action.accept(index++, values[i]);
-			}
-		}
-
-		@Override
-		public  void forEach(E input, ObjectObjectConsumer action) {
-			Objects.requireNonNull(action);
-			if(size() <= 0) return;
-			if(containsNull) action.accept(input, values[nullIndex]);
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null) action.accept(input, values[i]);
-			}
-		}
-
-		@Override
-		public boolean matchesAny(Predicate filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return false;
-			if(containsNull && filter.test(values[nullIndex])) return true;
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null && filter.test(values[i])) return true;
-			}
-			return false;
-		}
-
-		@Override
-		public boolean matchesNone(Predicate filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return true;
-			if(containsNull && filter.test(values[nullIndex])) return false;
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null && filter.test(values[i])) return false;
-			}
-			return true;
-		}
-
-		@Override
-		public boolean matchesAll(Predicate filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return true;
-			if(containsNull && !filter.test(values[nullIndex])) return false;
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null && !filter.test(values[i])) return false;
-			}
-			return true;
-		}
-
-		@Override
-		public  E reduce(E identity, BiFunction operator) {
-			Objects.requireNonNull(operator);
-			E state = identity;
-			if(containsNull) state = operator.apply(state, values[nullIndex]);
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] == null) continue;
-				state = operator.apply(state, values[i]);
-			}
-			return state;
-		}
-
-		@Override
-		public V reduce(ObjectObjectUnaryOperator operator) {
-			Objects.requireNonNull(operator);
-			V state = null;
-			boolean empty = true;
-			if(containsNull) {
-				state = values[nullIndex];
-				empty = false;
-			}
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] == null) continue;
-				if(empty) {
-					empty = false;
-					state = values[i];
-					continue;
-				}
-				state = operator.apply(state, values[i]);
-			}
-			return state;
-		}
-
-		@Override
-		public V findFirst(Predicate filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return null;
-			if(containsNull && filter.test(values[nullIndex])) return values[nullIndex];
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null && filter.test(values[i])) return values[i];
-			}
-			return null;
-		}
-
-		@Override
-		public int count(Predicate filter) {
-			Objects.requireNonNull(filter);
-			if(size() <= 0) return 0;
-			int result = 0;
-			if(containsNull && filter.test(values[nullIndex])) result++;
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null && filter.test(values[i])) result++;
-			}
-			return result;
-		}
-	}
-
-	private class FastEntryIterator extends MapIterator implements ObjectIterator> {
-		MapEntry entry = new MapEntry();
-		@Override
-		public Object2ObjectMap.Entry next() {
-			entry.index = nextEntry();
-			return entry;
-		}
-	}
-
-	private class EntryIterator extends MapIterator implements ObjectIterator> {
-		MapEntry entry;
-		@Override
-		public Object2ObjectMap.Entry next() {
-			return entry = new MapEntry(nextEntry());
-		}
-
-		@Override
-		public void remove() {
-			super.remove();
-			entry.index = -1;
-		}
-	}
-
-	private class KeyIterator extends MapIterator implements ObjectIterator {
-		@Override
-		public T next() {
-			return keys[nextEntry()];
-		}
-	}
-
-	private class ValueIterator extends MapIterator implements ObjectIterator {
-		@Override
-		public V next() {
-			return values[nextEntry()];
-		}
-	}
-
-	private class MapIterator {
-		int pos = nullIndex;
-		int returnedPos = -1;
-		int lastReturned = -1;
-		int nextIndex = Integer.MIN_VALUE;
-		boolean returnNull = containsNull;
-		T[] wrapped = null;
-		int wrappedIndex = 0;
-
-		public boolean hasNext() {
-			if(nextIndex == Integer.MIN_VALUE) {
-				if(returnNull) {
-					returnNull = false;
-					nextIndex = nullIndex;
-				}
-				else
-				{
-					while(true) {
-						if(--pos < 0) {
-							if(wrapped == null || wrappedIndex <= -pos - 1) break;
-							nextIndex = -pos - 1;
-							break;
-						}
-						if(keys[pos] != null){
-							nextIndex = pos;
-							break;
-						}
-					}
-				}
-			}
-			return nextIndex != Integer.MIN_VALUE;
-		}
-
-		public int nextEntry() {
-			if(!hasNext()) throw new NoSuchElementException();
-			returnedPos = pos;
-			if(nextIndex < 0){
-				lastReturned = Integer.MAX_VALUE;
-				int value = findIndex(wrapped[nextIndex]);
-				if(value < 0) throw new IllegalStateException("Entry ["+nextIndex+"] was removed during Iteration");
-				nextIndex = Integer.MIN_VALUE;
-				return value;
-			}
-			int value = (lastReturned = nextIndex);
-			nextIndex = Integer.MIN_VALUE;
-			return value;
-		}
-
-		public void remove() {
-			if(lastReturned == -1) throw new IllegalStateException();
-			if(lastReturned == nullIndex) {
-				containsNull = false;
-				keys[nullIndex] = null;
-				values[nullIndex] = null;
-			}
-			else if(returnedPos >= 0) shiftKeys(returnedPos);
-			else {
-				Object2ObjectOpenHashMap.this.remove(wrapped[-returnedPos - 1]);
-				lastReturned = -1;
-				return;
-			}
-			size--;
-			lastReturned = -1;
-		}
-
-		private void shiftKeys(int startPos) {
-			int slot, last;
-			T current;
-			while(true) {
-				startPos = ((last = startPos) + 1) & mask;
-				while(true){
-					if((current = keys[startPos]) == null) {
-						keys[last] = null;
-						values[last] = null;
-						return;
-					}
-					slot = HashUtil.mix(Objects.hashCode(current)) & mask;
-					if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
-					startPos = ++startPos & mask;
-				}
-				if(startPos < last) addWrapper(keys[startPos]);
-				keys[last] = current;
-				values[last] = values[startPos];
-			}
-		}
-
-		private void addWrapper(T value) {
-			if(wrapped == null) wrapped = (T[])new Object[2];
-			else if(wrappedIndex >= wrapped.length) {
-				T[] newArray = (T[])new Object[wrapped.length * 2];
-				System.arraycopy(wrapped, 0, newArray, 0, wrapped.length);
-				wrapped = newArray;
-			}
-			wrapped[wrappedIndex++] = value;
-		}
-	}
-}
diff --git a/src/main/java/speiger/src/collections/objects/maps/interfaces/Object2ObjectMap.java b/src/main/java/speiger/src/collections/objects/maps/interfaces/Object2ObjectMap.java
deleted file mode 100644
index e904c6ac0..000000000
--- a/src/main/java/speiger/src/collections/objects/maps/interfaces/Object2ObjectMap.java
+++ /dev/null
@@ -1,534 +0,0 @@
-package speiger.src.collections.objects.maps.interfaces;
-
-import java.util.Map;
-import java.util.Objects;
-import java.util.Collection;
-import java.util.Arrays;
-import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-
-
-import speiger.src.collections.objects.collections.ObjectCollection;
-import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
-import speiger.src.collections.objects.functions.function.UnaryOperator;
-import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator;
-
-import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
-
-import speiger.src.collections.objects.collections.ObjectIterable;
-import speiger.src.collections.objects.sets.ObjectSet;
-import speiger.src.collections.objects.functions.ObjectSupplier;
-import speiger.src.collections.objects.collections.ObjectIterator;
-import speiger.src.collections.utils.HashUtil;
-import speiger.src.collections.utils.SanityChecks;
-
-/**
- * A Type Specific Map that reduces memory overhead due to boxing/unboxing of Primitives
- * and some extra helper functions.
- * @param  the keyType of elements maintained by this Collection
- * @param  the keyType of elements maintained by this Collection
- */
-public interface Object2ObjectMap extends Map, UnaryOperator
-{
-	/**
-	 * Helper Class that allows to create Maps without requiring a to type out the entire implementation or know it.
-	 * @return a MapBuilder
-	 */
-	public static MapBuilder builder() {
-		return MapBuilder.INSTANCE;
-	}
-
-	/**
-	 * Method to see what the default return value is.
-	 * @return default return value
-	 */
-	public V getDefaultReturnValue();
-	/**
-	 * Method to define the default return value if a requested key isn't present
-	 * @param v value that should be the default return value
-	 * @return itself
-	 */
-	public Object2ObjectMap setDefaultReturnValue(V v);
-
-	/**
-	 * A Function that does a shallow clone of the Map itself.
-	 * This function is more optimized then a copy constructor since the Map does not have to be unsorted/resorted.
-	 * It can be compared to Cloneable but with less exception risk
-	 * @return a Shallow Copy of the Map
-	 * @note Wrappers and view Maps will not support this feature
-	 */
-	public Object2ObjectMap copy();
-
-	/**
-	 * Type Specific method to reduce boxing/unboxing of values
-	 * @param key the key that should be inserted,
-	 * @param value the value that should be inserted
-	 * @return the last present value or default return value.
-	 * @see Map#put(Object, Object)
-	 */
-	public V put(T key, V value);
-
-	/**
-	 * A Helper method that allows to put int a Object2ObjectMap.Entry into a map.
-	 * @param entry then Entry that should be inserted.
-	 * @return the last present value or default return value.
-	 */
-	public default V put(Entry entry) {
-		return put(entry.getKey(), entry.getValue());
-	}
-
-	/**
-	 * Type Specific array method to bulk add elements into a map without creating a wrapper and increasing performances
-	 * @param keys the keys that should be added
-	 * @param values the values that should be added
-	 * @see Map#putAll(Map)
-	 * @throws IllegalStateException if the arrays are not the same size
-	 */
-	public default void putAll(T[] keys, V[] values) {
-		if(keys.length != values.length) throw new IllegalStateException("Array sizes do not match");
-		putAll(keys, values, 0, keys.length);
-	}
-
-	/**
-	 * Type Specific array method to bulk add elements into a map without creating a wrapper and increasing performances
-	 * @param keys the keys that should be added
-	 * @param values the values that should be added
-	 * @param offset where the to start in the array
-	 * @param size how many elements should be added
-	 * @see Map#putAll(Map)
-	 * @throws IllegalStateException if the arrays are not within the range
-	 */
-	public void putAll(T[] keys, V[] values, int offset, int size);
-
-	/**
-	 * Type Specific method to reduce boxing/unboxing of values
-	 * @param key the key that should be inserted,
-	 * @param value the value that should be inserted
-	 * @return the last present value or default return value.
-	 * @see Map#putIfAbsent(Object, Object)
-	 */
-	public V putIfAbsent(T key, V value);
-
-	/**
-	 * Type-Specific bulk put method put elements into the map if not present.
-	 * @param m elements that should be added if not present.
-	 */
-	public void putAllIfAbsent(Object2ObjectMap m);
-
-	/**
-	 * Type Specific function for the bull putting of values
-	 * @param m the elements that should be inserted
-	 */
-	public void putAll(Object2ObjectMap m);
-
-	/**
-	 * Type Specific remove function to reduce boxing/unboxing
-	 * @param key the element that should be removed
-	 * @return the value that was removed or default return value
-	 */
-	public V rem(T key);
-
-	/**
-	 * @see Map#remove(Object)
-	 * @param key the element that should be removed
-	 * @return the value that was removed or default return value
-	 * @note in some implementations key does not have to be T but just have to support equals with T.
-	 */
-	@Override
-	public default V remove(Object key) {
-		return rem((T)key);
-	}
-
-	/**
-	 * Type-Specific Remove function with a default return value if wanted.
-	 * @see Map#remove(Object, Object)
- 	 * @param key the element that should be removed
- 	 * @param defaultValue the value that should be returned if the entry doesn't exist
-	 * @return the value that was removed or default value
-	 */
-	public V remOrDefault(T key, V defaultValue);
-	/**
-	 * A Type Specific replace method to replace an existing value
-	 * @param key the element that should be searched for
-	 * @param oldValue the expected value to be replaced
-	 * @param newValue the value to replace the oldValue with.
-	 * @return true if the value got replaced
-	 * @note this fails if the value is not present even if it matches the oldValue
-	 */
-	public boolean replace(T key, V oldValue, V newValue);
-	/**
-	 * A Type Specific replace method to reduce boxing/unboxing replace an existing value
-	 * @param key the element that should be searched for
-	 * @param value the value to replace with.
-	 * @return the present value or default return value
-	 * @note this fails if the value is not present
-	 */
-	public V replace(T key, V value);
-
-	/**
-	 * Type-Specific bulk replace method. Could be seen as putAllIfPresent
-	 * @param m elements that should be replaced.
-	 */
-	public void replaceObjects(Object2ObjectMap m);
-	/**
-	 * A Type Specific mass replace method to reduce boxing/unboxing
-	 * @param mappingFunction operation to replace all values
-	 */
-	public void replaceObjects(ObjectObjectUnaryOperator mappingFunction);
-	/**
-	 * A Type Specific compute method to reduce boxing/unboxing
-	 * @param key the key that should be computed
-	 * @param mappingFunction the operator that should generate the value
-	 * @return the result of the computation
-	 */
-	public V compute(T key, ObjectObjectUnaryOperator mappingFunction);
-	/**
-	 * A Type Specific compute method to reduce boxing/unboxing
-	 * @param key the key that should be computed
-	 * @param mappingFunction the operator that should generate the value if not present
-	 * @return the result of the computed value or present value
-	 */
-	public V computeIfAbsent(T key, UnaryOperator mappingFunction);
-
-	/**
-	 * A Supplier based computeIfAbsent function to fill the most used usecase of this function
-	 * @param key the key that should be computed
-	 * @param valueProvider the value if not present
-	 * @return the result of the computed value or present value
-	 */
-	public V supplyIfAbsent(T key, ObjectSupplier valueProvider);
-	/**
-	 * A Type Specific compute method to reduce boxing/unboxing
-	 * @param key the key that should be computed
-	 * @param mappingFunction the operator that should generate the value if present
-	 * @return the result of the default return value or present value
-	 * @note if not present then compute is not executed
-	 */
-	public V computeIfPresent(T key, ObjectObjectUnaryOperator mappingFunction);
-	/**
-	 * A Type Specific merge method to reduce boxing/unboxing
-	 * @param key the key that should be be searched for
-	 * @param value the value that should be merged with
-	 * @param mappingFunction the operator that should generate the new Value
-	 * @return the result of the merge
-	 * @note if the result matches the default return value then the key is removed from the map
-	 */
-	public V merge(T key, V value, ObjectObjectUnaryOperator mappingFunction);
-	/**
-	 * A Bulk method for merging Maps.
-	 * @param m the entries that should be bulk added
-	 * @param mappingFunction the operator that should generate the new Value
-	 * @note if the result matches the default return value then the key is removed from the map
-	 */
-	public void mergeAll(Object2ObjectMap m, ObjectObjectUnaryOperator mappingFunction);
-
-	@Override
-	public default V apply(T key) {
-		return getObject(key);
-	}
-	/**
-	 * A Type Specific get method to reduce boxing/unboxing
-	 * @param key the key that is searched for
-	 * @return the searched value or default return value
-	 */
-	public V getObject(T key);
-
-	@Override
-	public default void replaceAll(BiFunction mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		replaceObjects(mappingFunction instanceof ObjectObjectUnaryOperator ? (ObjectObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(K, V));
-	}
-
-	@Override
-	public default V compute(T key, BiFunction mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		return compute(key, mappingFunction instanceof ObjectObjectUnaryOperator ? (ObjectObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(K, V));
-	}
-
-	@Override
-	public default V computeIfAbsent(T key, Function mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		return computeIfAbsent(key, mappingFunction instanceof UnaryOperator ? (UnaryOperator)mappingFunction : K -> mappingFunction.apply(K));
-	}
-
-	@Override
-	public default V computeIfPresent(T key, BiFunction mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		return computeIfPresent(key, mappingFunction instanceof ObjectObjectUnaryOperator ? (ObjectObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(K, V));
-	}
-
-	@Override
-	public default V merge(T key, V value, BiFunction mappingFunction) {
-		Objects.requireNonNull(mappingFunction);
-		Objects.requireNonNull(value);
-		return merge(key, value, mappingFunction instanceof ObjectObjectUnaryOperator ? (ObjectObjectUnaryOperator)mappingFunction : (K, V) -> mappingFunction.apply(K, V));
-	}
-
-	/**
-	 * Type Specific forEach method to reduce boxing/unboxing
-	 * @param action processor of the values that are iterator over
-	 */
-	public void forEach(ObjectObjectConsumer action);
-
-	@Override
-	public default void forEach(BiConsumer action) {
-		Objects.requireNonNull(action);
-		forEach(action instanceof ObjectObjectConsumer ? (ObjectObjectConsumer)action : (K, V) -> action.accept(K, V));
-	}
-
-	@Override
-	public ObjectSet keySet();
-	@Override
-	public ObjectCollection values();
-	@Override
-	public ObjectSet> entrySet();
-	/**
-	 * Type Sensitive EntrySet to reduce boxing/unboxing and optionally Temp Object Allocation.
-	 * @return a EntrySet of the collection
-	 */
-	public ObjectSet> object2ObjectEntrySet();
-
-	/**
-	 * Fast Entry set that allows for a faster Entry Iterator by recycling the Entry Object and just exchanging 1 internal value
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  the keyType of elements maintained by this Collection
-	 */
-	public interface FastEntrySet extends ObjectSet>
-	{
-		/**
-		 * Fast iterator that recycles the given Entry object to improve speed and reduce object allocation
-		 * @return a Recycling ObjectIterator of the given set
-		 */
-		public ObjectIterator> fastIterator();
-		/**
-		 * Fast for each that recycles the given Entry object to improve speed and reduce object allocation
-		 * @param action the action that should be applied to each given entry
-		 */
-		public default void fastForEach(Consumer> action) {
-			forEach(action);
-		}
-	}
-
-	/**
-	 * Type Specific Map Entry that reduces boxing/unboxing
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  the keyType of elements maintained by this Collection
-	 */
-	public interface Entry extends Map.Entry
-	{
-	}
-
-	/**
-	 * Helper class that reduces the method spam of the Map Class.
-	 */
-	public static final class MapBuilder
-	{
-		static final MapBuilder INSTANCE = new MapBuilder();
-
-		/**
-		 * Starts a Map Builder that allows you to create maps as Constants a lot easier
-		 * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen
-		 * @param  the keyType of elements maintained by this Collection
-		 * @param  the keyType of elements maintained by this Collection
-		 * @return a MapBuilder
-		 */
-		public  BuilderCache start() {
-			return new BuilderCache();
-		}
-
-		/**
-		 * Starts a Map Builder that allows you to create maps as Constants a lot easier
-		 * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen
-		 * @param size the expected minimum size of Elements in the Map, default is 16
-		 * @param  the keyType of elements maintained by this Collection
-		 * @param  the keyType of elements maintained by this Collection
-		 * @return a MapBuilder
-		 */
-		public  BuilderCache start(int size) {
-			return new BuilderCache(size);
-		}
-
-		/**
-		 * Starts a Map builder and puts in the Key and Value into it
-		 * Keys and Values are stored as Array and then inserted using the putAllMethod when the mapType is choosen
-		 * @param key the key that should be added
-		 * @param value the value that should be added
-		 * @param  the keyType of elements maintained by this Collection
-		 * @param  the keyType of elements maintained by this Collection
-		 * @return a MapBuilder with the key and value stored in it.
-		 */
-		public  BuilderCache put(T key, V value) {
-			return new BuilderCache().put(key, value);
-		}
-
-		/**
-		* Helper function to unify code
-		* @param  the keyType of elements maintained by this Collection
-		* @param  the keyType of elements maintained by this Collection
-		* @return a OpenHashMap
-		*/
-		public  Object2ObjectOpenHashMap map() {
-			return new Object2ObjectOpenHashMap<>();
-		}
-
-		/**
-		* Helper function to unify code
-		* @param size the minimum capacity of the Map
-		* @param  the keyType of elements maintained by this Collection
-		* @param  the keyType of elements maintained by this Collection
-		* @return a OpenHashMap with a mimimum capacity
-		*/
-		public  Object2ObjectOpenHashMap map(int size) {
-			return new Object2ObjectOpenHashMap<>(size);
-		}
-
-		/**
-		* Helper function to unify code
-		* @param keys the keys that should be inserted
-		* @param values the values that should be inserted
-		* @param  the keyType of elements maintained by this Collection
-		* @param  the keyType of elements maintained by this Collection
-		* @throws IllegalStateException if the keys and values do not match in length
-		* @return a OpenHashMap thats contains the injected values
-		*/
-		public  Object2ObjectOpenHashMap map(T[] keys, V[] values) {
-			return new Object2ObjectOpenHashMap<>(keys, values);
-		}
-
-		/**
-		* Helper function to unify code
-		* @param map that should be cloned
-		* @param  the keyType of elements maintained by this Collection
-		* @param  the keyType of elements maintained by this Collection
-		* @return a OpenHashMap thats copies the contents of the provided map
-		*/
-		public  Object2ObjectOpenHashMap map(Object2ObjectMap map) {
-			return new Object2ObjectOpenHashMap<>(map);
-		}
-
-		/**
-		* Helper function to unify code
-		* @param map that should be cloned
-		* @param  the keyType of elements maintained by this Collection
-		* @param  the keyType of elements maintained by this Collection
-		* @return a OpenHashMap thats copies the contents of the provided map
-		* @note the map will be unboxed
-		*/
-		public  Object2ObjectOpenHashMap map(Map map) {
-			return new Object2ObjectOpenHashMap<>(map);
-		}
-
-
-	}
-
-	/**
-	 * Builder Cache for allowing to buildMaps
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  the keyType of elements maintained by this Collection
-	 */
-	public static class BuilderCache
-	{
-		T[] keys;
-		V[] values;
-		int size;
-
-		/**
-		 * Default Constructor
-		 */
-		public BuilderCache() {
-			this(HashUtil.DEFAULT_MIN_CAPACITY);
-		}
-
-		/**
-		 * Constructor providing a Minimum Capcity
-		 * @param initialSize the requested start capacity
-		 */
-		public BuilderCache(int initialSize) {
-			if(initialSize < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed");
-			keys = (T[])new Object[initialSize];
-			values = (V[])new Object[initialSize];
-		}
-
-		private void ensureSize(int newSize) {
-			if(keys.length >= newSize) return;
-			newSize = (int)Math.max(Math.min((long)keys.length + (keys.length >> 1), SanityChecks.MAX_ARRAY_SIZE), newSize);
-			keys = Arrays.copyOf(keys, newSize);
-			values = Arrays.copyOf(values, newSize);
-		}
-
-		/**
-		 * Helper function to add a Entry into the Map
-		 * @param key the key that should be added
-		 * @param value the value that should be added
-		 * @return self
-		 */
-		public BuilderCache put(T key, V value) {
-			ensureSize(size+1);
-			keys[size] = key;
-			values[size] = value;
-			size++;
-			return this;
-		}
-
-		/**
-		 * Helper function to add a Entry into the Map
-		 * @param entry the Entry that should be added
-		 * @return self
-		 */
-		public BuilderCache put(Entry entry) {
-			return put(entry.getKey(), entry.getValue());
-		}
-
-		/**
-		 * Helper function to add a Map to the Map
-		 * @param map that should be added
-		 * @return self
-		 */
-		public BuilderCache putAll(Object2ObjectMap map) {
-			return putAll(map.object2ObjectEntrySet());
-		}
-
-		/**
-		 * Helper function to add a Map to the Map
-		 * @param map that should be added
-		 * @return self
-		 */
-		public BuilderCache putAll(Map map) {
-			for(Map.Entry entry : map.entrySet())
-				put(entry.getKey(), entry.getValue());
-			return this;
-		}
-
-		/**
-		 * Helper function to add a Collection of Entries to the Map
-		 * @param c that should be added
-		 * @return self
-		 */
-		public BuilderCache putAll(ObjectIterable> c) {
-			if(c instanceof Collection)
-				ensureSize(size+((Collection>)c).size());
-
-			for(Entry entry : c)
-				put(entry);
-
-			return this;
-		}
-
-		private > E putElements(E e){
-			e.putAll(keys, values, 0, size);
-			return e;
-		}
-
-		/**
-		 * Builds the Keys and Values into a Hash Map
-		 * @return a Object2ObjectOpenHashMap
-		 */
-		public Object2ObjectOpenHashMap map() {
-			return putElements(new Object2ObjectOpenHashMap<>(size));
-		}
-
-	}
-}
diff --git a/src/main/java/speiger/src/collections/objects/sets/AbstractObjectSet.java b/src/main/java/speiger/src/collections/objects/sets/AbstractObjectSet.java
deleted file mode 100644
index e9b6f4e6c..000000000
--- a/src/main/java/speiger/src/collections/objects/sets/AbstractObjectSet.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package speiger.src.collections.objects.sets;
-
-import java.util.Objects;
-import java.util.Set;
-
-import speiger.src.collections.objects.collections.AbstractObjectCollection;
-import speiger.src.collections.objects.collections.ObjectIterator;
-
-/**
- * Abstract Type Specific Set that reduces boxing/unboxing
- * @param  the keyType of elements maintained by this Collection
- */
-public abstract class AbstractObjectSet extends AbstractObjectCollection implements ObjectSet
-{
-	@Override
-	public T addOrGet(T o) { throw new UnsupportedOperationException(); }
-	
-	@Override
-	public abstract ObjectIterator iterator();
-	@Override
-	public AbstractObjectSet copy() { throw new UnsupportedOperationException(); }
-	
-	@Override
-	public int hashCode() {
-		int hashCode = 0;
-		ObjectIterator i = iterator();
-		while(i.hasNext())
-			hashCode += Objects.hashCode(i.next());
-		return hashCode;
-	}
-	
-	@Override
-	public boolean equals(Object o) {
-		if (o == this)
-			return true;
-		if (!(o instanceof Set))
-			return false;
-		Set l = (Set)o;
-		if(l.size() != size()) return false;
-		try {
-			return containsAll(l);
-		} catch (ClassCastException | NullPointerException unused) {
-			return false;
-		}
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/sets/ObjectOpenHashSet.java b/src/main/java/speiger/src/collections/objects/sets/ObjectOpenHashSet.java
deleted file mode 100644
index a2b443ab3..000000000
--- a/src/main/java/speiger/src/collections/objects/sets/ObjectOpenHashSet.java
+++ /dev/null
@@ -1,609 +0,0 @@
-package speiger.src.collections.objects.sets;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.function.Consumer;
-import java.util.function.BiFunction;
-import java.util.function.Predicate;
-
-import speiger.src.collections.objects.collections.ObjectCollection;
-import speiger.src.collections.objects.collections.ObjectIterator;
-import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
-import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
-import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator;
-import speiger.src.collections.utils.HashUtil;
-import speiger.src.collections.utils.ITrimmable;
-import speiger.src.collections.utils.SanityChecks;
-
-/**
- * A Type Specific Custom implementation of the HashSet
- * Instead of using Wrapper Object Arrays for storing keys and values there is dedicated arrays for storing keys.
- * Extra to that there is a couple quality of life functions provided
- * @param  the keyType of elements maintained by this Collection
- */
-public class ObjectOpenHashSet extends AbstractObjectSet implements ITrimmable
-{
-	/** The Backing keys array */
-	protected transient T[] keys;
-	/** If a null value is present */
-	protected transient boolean containsNull;
-	/** Minimum array size the HashSet will be */
-	protected transient int minCapacity;
-	/** Index of the Null Value */
-	protected transient int nullIndex;
-	/** Maximum amount of Values that can be stored before the array gets expanded usually 75% */
-	protected transient int maxFill;
-	/** Max Index that is allowed to be searched through nullIndex - 1 */
-	protected transient int mask;
-	
-	/** Amount of Elements stored in the HashSet */
-	protected int size;
-	/** How full the Array is allowed to get before resize */
-	protected final float loadFactor;
-	
-	/**
-	 * Default Constructor
-	 */
-	public ObjectOpenHashSet() {
-		this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-	
-	/**
-	 * Constructor that defines the minimum capacity
-	 * @param minCapacity the minimum capacity the HashSet is allowed to be.
-	 * @throws IllegalStateException if the minimum capacity is negative
-	 */
-	public ObjectOpenHashSet(int minCapacity) {
-		this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-	
-	/**
-	 * Constructor that defines the minimum capacity and load factor
-	 * @param minCapacity the minimum capacity the HashSet is allowed to be.
-	 * @param loadFactor the percentage of how full the backing array can be before they resize
-	 * @throws IllegalStateException if the minimum capacity is negative
-	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
-	 */
-	public ObjectOpenHashSet(int minCapacity, float loadFactor) {
-		if(minCapacity < 0)	throw new IllegalStateException("Minimum Capacity is negative. This is not allowed");
-		if(loadFactor <= 0 || loadFactor >= 1F) throw new IllegalStateException("Load Factor is not between 0 and 1");
-		this.loadFactor = loadFactor;
-		this.minCapacity = nullIndex = HashUtil.arraySize(minCapacity, loadFactor);
-		mask = nullIndex - 1;
-		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
-		keys = (T[])new Object[nullIndex + 1];
-	}
-	
-	/**
-	 * Helper constructor that allow to create a set from unboxed values
-	 * @param array the elements that should be put into the set
-	 */
-	public ObjectOpenHashSet(T[] array) {
-		this(array, 0, array.length, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-	
-	/**
-	 * Helper constructor that allow to create a set from unboxed values
-	 * @param array the elements that should be put into the set
-	 * @param loadFactor the percentage of how full the backing array can be before they resize
-	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
-	 */
-	public ObjectOpenHashSet(T[] array, float loadFactor) {
-		this(array, 0, array.length, loadFactor);
-	}
-	
-	/**
-	 * Helper constructor that allow to create a set from unboxed values
-	 * @param array the elements that should be put into the set
-	 * @param offset the starting index within the array that should be used
-	 * @param length the amount of elements used from the array
-	 * @throws IllegalStateException if offset and length causes to step outside of the arrays range
-	 */
-	public ObjectOpenHashSet(T[] array, int offset, int length) {
-		this(array, offset, length, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-	
-	/**
-	 * Helper constructor that allow to create a set from unboxed values
-	 * @param array the elements that should be put into the set
-	 * @param offset the starting index within the array that should be used
-	 * @param length the amount of elements used from the array
-	 * @param loadFactor the percentage of how full the backing array can be before they resize
-	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
-	 * @throws IllegalStateException if offset and length causes to step outside of the arrays range
-	 */
-	public ObjectOpenHashSet(T[] array, int offset, int length, float loadFactor) {
-		this(length < 0 ? 0 : length);
-		SanityChecks.checkArrayCapacity(array.length, offset, length);
-		for(int i = 0;i collection) {
-		this(collection, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-	
-	/**
-	 * A Helper constructor that allows to create a Set with exactly the same values as the provided collection.
-	 * @param collection the set the elements should be added to the Set
-	 * @param loadFactor the percentage of how full the backing array can be before they resize
-	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
-	 */
-	public ObjectOpenHashSet(Collection collection, float loadFactor) {
-		this(collection.size(), loadFactor);
-		addAll(collection);
-	}
-	
-	/**
-	 * A Helper constructor that allows to create a Set with exactly the same values as the provided collection.
-	 * @param collection the set the elements should be added to the Set
-	 */
-	public ObjectOpenHashSet(ObjectCollection collection) {
-		this(collection, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-	
-	/**
-	 * A Helper constructor that allows to create a Set with exactly the same values as the provided collection.
-	 * @param collection the set the elements should be added to the Set
-	 * @param loadFactor the percentage of how full the backing array can be before they resize
-	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
-	 */
-	public ObjectOpenHashSet(ObjectCollection collection, float loadFactor) {
-		this(collection.size());
-		addAll(collection);
-	}
-	
-	/**
-	 * A Helper constructor that allows to create a set from a iterator of an unknown size
-	 * @param iterator the elements that should be added to the set
-	 */
-	public ObjectOpenHashSet(Iterator iterator) {
-		this(iterator, HashUtil.DEFAULT_LOAD_FACTOR);
-	}
-	
-	/**
-	 * A Helper constructor that allows to create a set from a iterator of an unknown size
-	 * @param iterator the elements that should be added to the set
-	 * @param loadFactor the percentage of how full the backing array can be before they resize
-	 * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
-	 */
-	public ObjectOpenHashSet(Iterator iterator, float loadFactor) {
-		this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor);
-		while(iterator.hasNext()) add(iterator.next());
-	}
-	
-	@Override
-	public boolean add(T o) {
-		if(o == null) {
-			if(containsNull) return false;
-			containsNull = true;
-			onNodeAdded(nullIndex);
-		}
-		else {
-			int pos = HashUtil.mix(Objects.hashCode(o)) & mask;
-			T current = keys[pos];
-			if(current != null) {
-				if(Objects.equals(current, o)) return false;
-				while((current = keys[pos = (++pos & mask)]) != null)
-					if(Objects.equals(current, o)) return false;
-			}
-			keys[pos] = o;
-			onNodeAdded(pos);
-		}
-		if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor));
-		return true;
-	}
-	
-	@Override
-	public T addOrGet(T o) {
-		if(o == null) {
-			if(containsNull) return null;
-			containsNull = true;
-			onNodeAdded(nullIndex);
-		}
-		else {
-			int pos = HashUtil.mix(Objects.hashCode(o)) & mask;
-			T current = keys[pos];
-			if(current != null) {
-				if(Objects.equals(current, o)) return current;
-				while((current = keys[pos = (++pos & mask)]) != null)
-					if(Objects.equals(current, o)) return current;
-			}
-			keys[pos] = o;
-			onNodeAdded(pos);
-		}
-		if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor));
-		return o;
-	}
-	
-	@Override
-	public boolean addAll(Collection c) {
-		if(loadFactor <= 0.5F) ensureCapacity(c.size());
-		else ensureCapacity(c.size() + size());
-		return super.addAll(c);
-	}
-	
-	@Override
-	public boolean addAll(ObjectCollection c) {
-		if(loadFactor <= 0.5F) ensureCapacity(c.size());
-		else ensureCapacity(c.size() + size());		
-		return super.addAll(c);
-	}
-	
-	@Override
-	public boolean contains(Object o) {
-		if(o == null) return containsNull;
-		int pos = HashUtil.mix(o.hashCode()) & mask;
-		T current = keys[pos];
-		if(current == null) return false;
-		if(Objects.equals(o, current)) return true;
-		while(true) {
-			if((current = keys[pos = (++pos & mask)]) == null) return false;
-			else if(Objects.equals(o, current)) return true;
-		}
-	}
-
-	@Override
-	public boolean remove(Object o) {
-		if(o == null) return (containsNull ? removeNullIndex() : false);
-		int pos = HashUtil.mix(o.hashCode()) & mask;
-		T current = keys[pos];
-		if(current == null) return false;
-		if(Objects.equals(o, current)) return removeIndex(pos);
-		while(true) {
-			if((current = keys[pos = (++pos & mask)]) == null) return false;
-			else if(Objects.equals(o, current)) return removeIndex(pos);
-		}
-	}
-
-	@Override
-	public boolean trim(int size) {
-		int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor)));
-		if(request >= nullIndex || this.size >= Math.min((int)Math.ceil(request * loadFactor), request - 1)) return false;
-		try {
-			rehash(request);
-		}
-		catch(OutOfMemoryError e) { return false; }
-		return true;
-	}
-	
-	@Override
-	public void clearAndTrim(int size) {
-		int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor)));
-		if(request >= nullIndex) {
-			clear();
-			return;
-		}
-		nullIndex = request;
-		mask = request-1;
-		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
-		keys = (T[])new Object[request + 1];
-		this.size = 0;
-		containsNull = false;
-	}
-	
-	@Override
-	public void forEach(Consumer action) {
-		if(size() <= 0) return;
-		if(containsNull) action.accept(keys[nullIndex]);
-		for(int i = nullIndex-1;i>=0;i--) {
-			if(keys[i] != null) action.accept(keys[i]);
-		}
-	}
-	
-	@Override
-	public void forEachIndexed(IntObjectConsumer action) {
-		Objects.requireNonNull(action);
-		if(size() <= 0) return;
-		if(containsNull) action.accept(0, keys[nullIndex]);
-		for(int i = nullIndex-1, index = containsNull ? 1 : 0;i>=0;i--) {
-			if(keys[i] != null) action.accept(index++, keys[i]);
-		}
-	}
-	
-	@Override
-	public  void forEach(E input, ObjectObjectConsumer action) {
-		Objects.requireNonNull(action);
-		if(size() <= 0) return;
-		if(containsNull) action.accept(input, keys[nullIndex]);
-		for(int i = nullIndex-1;i>=0;i--) {
-			if(keys[i] != null) action.accept(input, keys[i]);
-		}
-	}
-	
-	@Override
-	public boolean matchesAny(Predicate filter) {
-		Objects.requireNonNull(filter);
-		if(size() <= 0) return false;
-		if(containsNull && filter.test(keys[nullIndex])) return true;
-		for(int i = nullIndex-1;i>=0;i--) {
-			if(keys[i] != null && filter.test(keys[i])) return true;
-		}
-		return false;
-	}
-	
-	@Override
-	public boolean matchesNone(Predicate filter) {
-		Objects.requireNonNull(filter);
-		if(size() <= 0) return true;
-		if(containsNull && filter.test(keys[nullIndex])) return false;
-		for(int i = nullIndex-1;i>=0;i--) {
-			if(keys[i] != null && filter.test(keys[i])) return false;
-		}
-		return true;
-	}
-	
-	@Override
-	public boolean matchesAll(Predicate filter) {
-		Objects.requireNonNull(filter);
-		if(size() <= 0) return true;
-		if(containsNull && !filter.test(keys[nullIndex])) return false;
-		for(int i = nullIndex-1;i>=0;i--) {
-			if(keys[i] != null && !filter.test(keys[i])) return false;
-		}
-		return true;
-	}
-	
-	@Override
-	public  E reduce(E identity, BiFunction operator) {
-		Objects.requireNonNull(operator);
-		E state = identity;
-		if(containsNull) state = operator.apply(state, keys[nullIndex]);
-		for(int i = nullIndex-1;i>=0;i--) {
-			if(keys[i] == null) continue;
-			state = operator.apply(state, keys[i]);
-		}
-		return state;
-	}
-	
-	@Override
-	public T reduce(ObjectObjectUnaryOperator operator) {
-		Objects.requireNonNull(operator);
-		T state = null;
-		boolean empty = true;
-		if(containsNull) {
-			state = keys[nullIndex];
-			empty = false;
-		}
-		for(int i = nullIndex-1;i>=0;i--) {
-			if(keys[i] == null) continue;
-			if(empty) {
-				empty = false;
-				state = keys[i];
-				continue;
-			}
-			state = operator.apply(state, keys[i]);
-		}
-		return state;
-	}
-	
-	@Override
-	public T findFirst(Predicate filter) {
-		Objects.requireNonNull(filter);
-		if(size() <= 0) return null;
-		if(containsNull && filter.test(keys[nullIndex])) return keys[nullIndex];
-		for(int i = nullIndex-1;i>=0;i--) {
-			if(keys[i] != null && filter.test(keys[i])) return keys[i];
-		}
-		return null;
-	}
-	
-	@Override
-	public int count(Predicate filter) {
-		Objects.requireNonNull(filter);
-		if(size() <= 0) return 0;
-		int result = 0;
-		if(containsNull && filter.test(keys[nullIndex])) result++;
-		for(int i = nullIndex-1;i>=0;i--) {
-			if(keys[i] != null && filter.test(keys[i])) result++;
-		}
-		return result;
-	}
-	
-	private void ensureCapacity(int newCapacity) {
-		int size = HashUtil.arraySize(newCapacity, loadFactor);
-		if(size > nullIndex) rehash(size);
-	}
-	
-	protected boolean removeIndex(int pos) {
-		if(pos == nullIndex) return containsNull ? removeNullIndex() : false;
-		keys[pos] = null;
-		size--;
-		onNodeRemoved(pos);
-		shiftKeys(pos);
-		if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
-		return true;
-	}
-	
-	protected boolean removeNullIndex() {
-		containsNull = false;
-		keys[nullIndex] = null;
-		size--;
-		onNodeRemoved(nullIndex);
-		if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
-		return true;
-	}
-	
-	protected void onNodeAdded(int pos) {
-		
-	}
-	
-	protected void onNodeRemoved(int pos) {
-		
-	}
-	
-	protected void onNodeMoved(int from, int to) {
-		
-	}
-	
-	protected void shiftKeys(int startPos) {
-		int slot, last;
-		T current;
-		while(true) {
-			startPos = ((last = startPos) + 1) & mask;
-			while(true){
-				if((current = keys[startPos]) == null) {
-					keys[last] = null;
-					return;
-				}
-				slot = HashUtil.mix(Objects.hashCode(current)) & mask;
-				if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
-				startPos = ++startPos & mask;
-			}
-			keys[last] = current;
-			onNodeMoved(startPos, last);
-		}
-	}
-	
-	protected void rehash(int newSize) {
-		int newMask = newSize - 1;
-		T[] newKeys = (T[])new Object[newSize + 1];
-		for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) {
-			while(true) {
-				if(--i < 0) throw new ConcurrentModificationException("Set was modified during rehash");
-				if(keys[i] != null) break;
-			}
-			if(newKeys[pos = HashUtil.mix(Objects.hashCode(keys[i])) & newMask] != null)
-				while(newKeys[pos = (++pos & newMask)] != null);
-			newKeys[pos] = keys[i];
-		}
-		nullIndex = newSize;
-		mask = newMask;
-		maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
-		keys = newKeys;
-	}
-	
-	@Override
-	public ObjectIterator iterator() {
-		return new SetIterator();
-	}
-	
-	@Override
-	public ObjectOpenHashSet copy() {
-		ObjectOpenHashSet set = new ObjectOpenHashSet<>(0, loadFactor);
-		set.minCapacity = minCapacity;
-		set.mask = mask;
-		set.maxFill = maxFill;
-		set.nullIndex = nullIndex;
-		set.containsNull = containsNull;
-		set.size = size;
-		set.keys = Arrays.copyOf(keys, keys.length);
-		return set;
-	}
-	
-	@Override
-	public void clear() {
-		if(size == 0) return;
-		size = 0;
-		containsNull = false;
-		Arrays.fill(keys, null);
-	}
-	
-	@Override
-	public int size() {
-		return size;
-	}
-	
-	private class SetIterator implements ObjectIterator {
-		int pos = nullIndex;
-		int returnedPos = -1;
-		int lastReturned = -1;
-		int nextIndex = Integer.MIN_VALUE;
-		boolean returnNull = containsNull;
-		T[] wrapped = null;
-		int wrappedIndex = 0;
-		
-		@Override
-		public boolean hasNext() {
-			if(nextIndex == Integer.MIN_VALUE) {
-				if(returnNull) {
-					returnNull = false;
-					nextIndex = nullIndex;
-				}
-				else
-				{
-					while(true) {
-						if(--pos < 0) {
-							if(wrapped == null || wrappedIndex <= -pos - 1) break;
-							nextIndex = -pos - 1;
-							break;
-						}
-						if(keys[pos] != null){
-							nextIndex = pos;
-							break;
-						}
-					}
-				}
-			}
-			return nextIndex != Integer.MIN_VALUE;
-		}
-		
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			returnedPos = pos;
-			if(nextIndex < 0){
-				lastReturned = Integer.MAX_VALUE;
-				T value = wrapped[nextIndex];
-				nextIndex = Integer.MIN_VALUE;
-				return value;
-			}
-			T value = keys[(lastReturned = nextIndex)];
-			nextIndex = Integer.MIN_VALUE;
-			return value;
-		}
-		
-		@Override
-		public void remove() {
-			if(lastReturned == -1) throw new IllegalStateException();
-			if(lastReturned == nullIndex) {
-				containsNull = false;
-				keys[nullIndex] = null;
-			}
-			else if(returnedPos >= 0) shiftKeys(returnedPos);
-			else {
-				ObjectOpenHashSet.this.remove(wrapped[-returnedPos - 1]);
-				lastReturned = -1;
-				return;
-			}
-			size--;
-			lastReturned = -1;
-		}
-		
-		private void shiftKeys(int startPos) {
-			int slot, last;
-			T current;
-			while(true) {
-				startPos = ((last = startPos) + 1) & mask;
-				while(true){
-					if((current = keys[startPos]) == null) {
-						keys[last] = null;
-						return;
-					}
-					slot = HashUtil.mix(Objects.hashCode(current)) & mask;
-					if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
-					startPos = ++startPos & mask;
-				}
-				if(startPos < last) addWrapper(keys[startPos]);
-				keys[last] = current;
-			}
-		}
-		
-		private void addWrapper(T value) {
-			if(wrapped == null) wrapped = (T[])new Object[2];
-			else if(wrappedIndex >= wrapped.length) {
-				T[] newArray = (T[])new Object[wrapped.length * 2];
-				System.arraycopy(wrapped, 0, newArray, 0, wrapped.length);
-				wrapped = newArray;
-			}
-			wrapped[wrappedIndex++] = value;
-		}
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/sets/ObjectOrderedSet.java b/src/main/java/speiger/src/collections/objects/sets/ObjectOrderedSet.java
deleted file mode 100644
index 428f9538c..000000000
--- a/src/main/java/speiger/src/collections/objects/sets/ObjectOrderedSet.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package speiger.src.collections.objects.sets;
-
-import speiger.src.collections.objects.collections.ObjectBidirectionalIterator;
-import speiger.src.collections.objects.collections.ObjectSplititerator;
-import speiger.src.collections.objects.utils.ObjectSplititerators;
-
-/**
- * A Special Set Interface giving Access to some really usefull functions
- * The Idea behind this interface is to allow access to functions that give control to the Order of elements.
- * Since Linked implementations as examples can be reordered outside of the Insertion Order.
- * This interface provides basic access to such functions while also providing some Sorted/NaivgableSet implementations that still fit into here.
- * 
- * @param  the keyType of elements maintained by this Collection
- */
-public interface ObjectOrderedSet extends ObjectSet
-{
-	/**
-	 * A customized add method that allows you to insert into the first index.
-	 * @param o the element that should be inserted
-	 * @return true if it was added
-	 * @see java.util.Set#add(Object)
-	 */
-	public boolean addAndMoveToFirst(T o);
-	/**
-	 * A customized add method that allows you to insert into the last index.
-	 * @param o the element that should be inserted
-	 * @return true if it was added
-	 * @see java.util.Set#add(Object)
-	 */
-	public boolean addAndMoveToLast(T o);
-	
-	/**
-	 * A specific move method to move a given key to the first index.
-	 * @param o that should be moved to the first index
-	 * @return true if the value was moved.
-	 * @note returns false if the value was not present in the first place
-	 */
-	public boolean moveToFirst(T o);
-	/**
-	 * A specific move method to move a given key to the last index.
-	 * @param o that should be moved to the first last
-	 * @return true if the value was moved.
-	 * @note returns false if the value was not present in the first place
-	 */
-	public boolean moveToLast(T o);
-	
-	@Override
-	public ObjectOrderedSet copy();
-	
-	@Override
-	public ObjectBidirectionalIterator iterator();
-	
-	/**
-	 * A type Specific Iterator starting from a given key
-	 * @param fromElement the element the iterator should start from
-	 * @return a iterator starting from the given element
-	 * @throws java.util.NoSuchElementException if fromElement isn't found
-	 */
-	public ObjectBidirectionalIterator iterator(T fromElement);
-	
-	/**
-	 * A Type Specific Type Splititerator to reduce boxing/unboxing
-	 * @return type specific splititerator
-	 */
-	@Override
-	default ObjectSplititerator spliterator() { return ObjectSplititerators.createSplititerator(this, 0); }
-	
-	/**
-	 * A method to get the first element in the set
-	 * @return first element in the set
-	 */
-	public T first();
-	/**
-	 * A method to get and remove the first element in the set
-	 * @return first element in the set
-	 */
-	public T pollFirst();
-	/**
-	 * A method to get the last element in the set
-	 * @return last element in the set
-	 */
-	public T last();
-	/**
-	 * A method to get and remove the last element in the set
-	 * @return last element in the set
-	 */
-	public T pollLast();
-	
-}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/sets/ObjectSet.java b/src/main/java/speiger/src/collections/objects/sets/ObjectSet.java
deleted file mode 100644
index 31d393d5b..000000000
--- a/src/main/java/speiger/src/collections/objects/sets/ObjectSet.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package speiger.src.collections.objects.sets;
-
-import java.util.Set;
-
-import speiger.src.collections.objects.collections.ObjectCollection;
-import speiger.src.collections.objects.collections.ObjectIterator;
-import speiger.src.collections.objects.collections.ObjectSplititerator;
-import speiger.src.collections.objects.utils.ObjectSplititerators;
-
-
-/**
- * A Type Specific Set class to reduce boxing/unboxing
- * @param  the keyType of elements maintained by this Collection
- */
-public interface ObjectSet extends Set, ObjectCollection
-{	
-	@Override
-	public ObjectIterator iterator();
-	
-	@Override
-	public ObjectSet copy();
-	
-	/**
-	 * A Helper method that allows to add a element or getting the already present implement.
-	 * Allowing to make unique references reuseable.
-	 * @param o the element to add
-	 * @return either the inserted element or the present element.
-	 */
-	public T addOrGet(T o);
-	
-	/**
-	 * A Type Specific Type Splititerator to reduce boxing/unboxing
-	 * @return type specific splititerator
-	 */
-	@Override
-	default ObjectSplititerator spliterator() { return ObjectSplititerators.createSplititerator(this, 0); }
-}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/utils/ObjectArrays.java b/src/main/java/speiger/src/collections/objects/utils/ObjectArrays.java
deleted file mode 100644
index 314148959..000000000
--- a/src/main/java/speiger/src/collections/objects/utils/ObjectArrays.java
+++ /dev/null
@@ -1,1571 +0,0 @@
-package speiger.src.collections.objects.utils;
-
-import java.util.Arrays;
-import java.util.Random;
-import java.util.concurrent.RecursiveAction;
-import java.util.Comparator;
-import java.util.function.IntFunction;
-
-import speiger.src.collections.objects.collections.ObjectIterator;
-import speiger.src.collections.objects.utils.ObjectIterators;
-import speiger.src.collections.objects.utils.ObjectCollections;
-import speiger.src.collections.utils.SanityChecks;
-
-/**
- * A Helper class for Arrays
- */
-public class ObjectArrays
-{
-	/** Default Limit for Insertion/Selection Sort */
-	public static final int BASE_THRESHOLD = 16;
-	/** Default Threshold for Multithreaded Sorting Algorythm options*/
-	public static final int PARALLEL_THRESHOLD = 8192;
-	
-	/** Empty Array Reference used for Uninitialized Collections */
-	public static final Object[] EMPTY_ARRAY = new Object[0];
-	
-	/**
-	 * Function to create a new Array of a given size
-	 * @param clz the class type of array that is requested
-	 * @param length the lenght the array should be.
-	 * @param  the keyType of array that the operation should be applied
-	 * @return a Array with the requested type and length
-	 */
-	public static  T[] newArray(Class clz, int length) {
-		if(clz == Object.class) return (T[])new Object[length];
-		return (T[]) java.lang.reflect.Array.newInstance(clz, length);
-	}
-	
-	/**
-	 * A Helper function that pours all elements of a iterator into a Array
-	 * @param iter the elements that should be gathered.
-	 * @param  the keyType of array that the operation should be applied
-	 * @return array with all elements of the iterator
-	 */
-	public static  T[] pour(ObjectIterator iter) {
-		return pour(iter, Integer.MAX_VALUE);
-	}
-	
-	/**
-	 * A Helper function that pours all elements of a iterator into a Array
-	 * @param iter the elements that should be gathered.
-	 * @param max how many elements should be added
-	 * @param  the keyType of array that the operation should be applied
-	 * @return array with all requested elements of the iterator
-	 */
-	public static  T[] pour(ObjectIterator iter, int max) {
-		ObjectCollections.CollectionWrapper list = ObjectCollections.wrapper();
-		ObjectIterators.pour(iter, list, max);
-		return list.toArray((T[])new Object[list.size()]);
-	}
-	
-	/**
-	 * A Helper function that pours all elements of a iterator into a Array
-	 * @param iter the elements that should be gathered.
-	 * @param  the keyType of array that the operation should be applied
-	 * @param action that is creating the Array to be poured into
-	 * @return array with all elements of the iterator
-	 */
-	public static  E[] pour(ObjectIterator iter, IntFunction action) {
-		return pour(iter, Integer.MAX_VALUE, action);
-	}
-	
-	/**
-	 * A Helper function that pours all elements of a iterator into a Array
-	 * @param iter the elements that should be gathered.
-	 * @param max how many elements should be added
-	 * @param action that is creating the Array to be poured into
-	 * @param  the keyType of array that the operation should be applied
-	 * @return array with all requested elements of the iterator
-	 */
-	public static  E[] pour(ObjectIterator iter, int max, IntFunction action) {
-		ObjectCollections.CollectionWrapper list = ObjectCollections.wrapper();
-		ObjectIterators.pour(iter, list, max);
-		return list.toArray(action.apply(list.size()));
-	}
-	
-	
-	/**
-	 * Method to validate if the current value is the lowest value in the heap
-	 * @param data the current heap.
-	 * @param size the size of the heap
-	 * @param index the index that should be validated
-	 * @param comp the comparator to sort the heap. Can be null
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the index the element was shifted to
-	 */
-	public static  int shiftDown(T[] data, int size, int index, Comparator comp) {
-		int half = size >>> 1;
-		T value = data[index];
-		if(comp != null) {
-			while(index < half) {
-				int child = (index << 1) + 1;
-				T childValue = data[child];
-				int right = child+1;
-				if(right < size && comp.compare(data[right], childValue) < 0) childValue = data[child = right];
-				if(comp.compare(value, childValue) <= 0) break;
-				data[index] = childValue;
-				index = child;
-			}
-		}
-		else {
-			while(index < half) {
-				int child = (index << 1) + 1;
-				T childValue = data[child];
-				int right = child+1;
-				if(right < size && ((Comparable)data[right]).compareTo((T)childValue) < 0) childValue = data[child = right];
-				if(((Comparable)value).compareTo((T)childValue) <= 0) break;
-				data[index] = childValue;
-				index = child;
-			}
-		}
-		data[index] = value;
-		return index;
-	}
-	
-	/**
-	 * Method to sort a specific value into the heap.
-	 * @param data the heap itself.
-	 * @param index that should be heapified.
-	 * @param comp the comparator to sort the heap. Can be null
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the index the element was shifted to
-	 */
-	public static  int shiftUp(T[] data, int index, Comparator comp) {
-		T value = data[index];
-		if(comp != null) {
-			while(index > 0) {
-				int parent = (index - 1) >>> 1;
-				T parentValue = data[parent];
-				if(comp.compare(value, parentValue) >= 0) break;
-				data[index] = parentValue;
-				index = parent;
-			}
-		}
-		else {
-			while(index > 0) {
-				int parent = (index - 1) >>> 1;
-				T parentValue = data[parent];
-				if(((Comparable)value).compareTo((T)parentValue) >= 0) break;
-				data[index] = parentValue;
-				index = parent;
-			}
-		}
-		data[index] = value;
-		return index;
-	}
-	
-	/**
-	 * Helper function to create a Heap out of an array.
-	 * @param data the array to heapify
-	 * @param size the current size of elements within the array.
-	 * @param comp the Comparator to sort the array. Can be null
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the input array
-	 */
-	public static  T[] heapify(T[] data, int size, Comparator comp) {
-		for(int i = (size >>> 1) - 1;i>=0;shiftDown(data, size, i--, comp));
-		return data;
-	}
-	
-	/**
-	 * Simple Shuffle method for Arrays.
-	 * @param array the elements that should be shuffled
-	 * @param  the keyType of array that the operation should be applied
-	 * @note This uses the SanityChecks#getRandom
-	 * @return the provided sorted array
-	 */
-	public static  T[] shuffle(T[] array) {
-		return shuffle(array, SanityChecks.getRandom());
-	}
-	
-	/**
-	 * Simple Shuffle method for Arrays.
-	 * @param array the elements that should be shuffled
-	 * @param length the length of the array
-	 * @param  the keyType of array that the operation should be applied
-	 * @note This uses the SanityChecks#getRandom
-	 * @return the provided sorted array
-	 */
-	public static  T[] shuffle(T[] array, int length) {
-		return shuffle(array, 0, length, SanityChecks.getRandom());
-	}
-	
-	/**
-	 * Simple Shuffle method for Arrays.
-	 * @param array the elements that should be shuffled
-	 * @param offset the start array
-	 * @param length the length of the array
-	 * @param  the keyType of array that the operation should be applied
-	 * @note This uses the SanityChecks#getRandom
-	 * @return the provided sorted array
-	 */
-	public static  T[] shuffle(T[] array, int offset, int length) {
-		return shuffle(array, offset, length, SanityChecks.getRandom());
-	}
-	
-	/**
-	 * Simple Shuffle method for Arrays.
-	 * @param array the elements that should be shuffled
-	 * @param random the Random Number Generator that should be used for the shuffling
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the provided sorted array
-	 */
-	public static  T[] shuffle(T[] array, Random random) {
-		for(int i = array.length-1; i>=0;i--) {
-			int p = random.nextInt(i + 1);
-			T t = array[i];
-			array[i] = array[p];
-			array[p] = t;
-		}
-		return array;
-	}
-	
-	/**
-	 * Simple Shuffle method for Arrays.
-	 * @param array the elements that should be shuffled
-	 * @param length the length of the array
-	 * @param random the Random Number Generator that should be used for the shuffling
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the provided sorted array
-	 */
-	public static  T[] shuffle(T[] array, int length, Random random) {
-		return shuffle(array, 0, length, random);
-	}
-	
-	/**
-	 * Simple Shuffle method for Arrays.
-	 * @param array the elements that should be shuffled
-	 * @param offset the start array
-	 * @param length the length of the array
-	 * @param random the Random Number Generator that should be used for the shuffling
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the provided sorted array
-	 */
-	public static  T[] shuffle(T[] array, int offset, int length, Random random) {
-		for(int i = length-1; i>=0;i--) {
-			int p = offset + random.nextInt(i + 1);
-			T t = array[offset+i];
-			array[offset+i] = array[p];
-			array[p] = t;
-		}
-		return array;
-	}
-	
-	/**
-	 * Simple Array Reversal method
-	 * @param array the Array that should flip
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the provided array
-	 */
-	public static  T[] reverse(T[] array) {
-		return reverse(array, 0, array.length);
-	}
-	
-	/**
-	 * Simple Array Reversal method
-	 * @param array the Array that should flip
-	 * @param length the length of the array
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the provided array
-	 */
-	public static  T[] reverse(T[] array, int length) {
-		return reverse(array, 0, length);
-	}
-	
-	/**
-	 * Simple Array Reversal method
-	 * @param array the Array that should flip
-	 * @param length the length of the array
-	 * @param offset the start of the array
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the provided array
-	 */
-	public static  T[] reverse(T[] array, int offset, int length) {
-		  for (int i = offset, mid = offset + length >> 1, j = offset + length - 1; i < mid; i++, j--) {
-			  T temp = array[i];
-			  array[i] = array[j];
-			  array[j] = temp;
-		  }
-		  return array;
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator,
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Stable sort referres to Mergesort or Insertionsort
-	 * @param array the array that needs to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 * @param comp the Comparator that decides the sorting order
-	 * @return input array.
-	 */
-	public static  T[] stableSort(T[] array, Comparator comp) {
-		stableSort(array, 0, array.length, comp);
-		return array;
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator,
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Stable sort referres to Mergesort or Insertionsort
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void stableSort(T[] array, int length, Comparator comp) {
-		stableSort(array, 0, length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator,
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Stable sort referres to Mergesort or Insertionsort
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void stableSort(T[] array, int from, int to, Comparator comp) {
-		mergeSort(array, null, from, to, comp);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order, 
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Stable sort referres to Mergesort or Insertionsort
-	 * @param array the array that needs to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] stableSort(T[] array) {
-		stableSort(array, 0, array.length);
-		return array;
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order, 
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Stable sort referres to Mergesort or Insertionsort
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void stableSort(T[] array, int length) {
-		stableSort(array, 0, length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order, 
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Stable sort referres to Mergesort or Insertionsort
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void stableSort(T[] array, int from, int to) {
-		mergeSort(array, null, from, to);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator,
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Unstable sort referres to QuickSort or SelectionSort
-	 * @param array the array that needs to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] unstableSort(T[] array, Comparator comp) {
-		unstableSort(array, 0, array.length, comp);
-		return array;
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator,
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Unstable sort referres to QuickSort or SelectionSort
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void unstableSort(T[] array, int length, Comparator comp) {
-		unstableSort(array, 0, length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator,
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Unstable sort referres to QuickSort or SelectionSort
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void unstableSort(T[] array, int from, int to, Comparator comp) {
-		quickSort(array, from, to, comp);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order, 
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Unstable sort referres to QuickSort or SelectionSort
-	 * @param array the array that needs to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] unstableSort(T[] array) {
-		unstableSort(array, 0, array.length);
-		return array;
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order, 
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Unstable sort referres to QuickSort or SelectionSort
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void unstableSort(T[] array, int length) {
-		unstableSort(array, 0, length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order, 
-	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
-	 * Unstable sort referres to QuickSort or SelectionSort
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void unstableSort(T[] array, int from, int to) {
-		quickSort(array, from, to);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort,
-	 * @param array the array that needs to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] insertionSort(T[] array, Comparator comp) {
-		insertionSort(array, 0, array.length, comp);
-		return array;
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort,
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void insertionSort(T[] array, int length, Comparator comp) {
-		insertionSort(array, 0, length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Insertion Sort,
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void insertionSort(T[] array, int from, int to, Comparator comp) {
-		for (int i = from+1;i= from && comp.compare(current, array[j]) < 0) {
-				array[j+1] = array[j--];
-			}
-			array[j+1] = current;
-		}
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using InsertionSort, 
-	 * @param array the array that needs to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] insertionSort(T[] array) {
-		insertionSort(array, 0, array.length);
-		return array;
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using InsertionSort,
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void insertionSort(T[] array, int length) {
-		insertionSort(array, 0, length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using InsertionSort,
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void insertionSort(T[] array, int from, int to) {
-		for (int i = from+1;i= from && ((Comparable)current).compareTo((T)array[j]) < 0) {
-				array[j+1] = array[j--];
-			}
-			array[j+1] = current;
-		}
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort,
-	 * @param array the array that needs to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] selectionSort(T[] array, Comparator comp) {
-		selectionSort(array, 0, array.length, comp);
-		return array;
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort,
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void selectionSort(T[] array, int length, Comparator comp) {
-		selectionSort(array, 0, length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Selection Sort,
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void selectionSort(T[] array, int from, int to, Comparator comp) {
-		for (int i = from; i < to; i++) {
-			T min = array[i];
-			int minId = i;
-			for(int j = i+1; j < to; j++) {
-				if(comp.compare(array[j], min) < 0) {
-					min = array[j];
-					minId = j;
-				}
-			}
-			T temp = array[i];
-			array[i] = min;
-			array[minId] = temp;
-		}
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Selection Sort, 
-	 * @param array the array that needs to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] selectionSort(T[] array) {
-		selectionSort(array, 0, array.length);
-		return array;
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Selection Sort,
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void selectionSort(T[] array, int length) {
-		selectionSort(array, 0, length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Selection Sort,
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void selectionSort(T[] array, int from, int to) {
-		for (int i = from; i < to; i++) {
-			T min = array[i];
-			int minId = i;
-			for(int j = i+1; j < to; j++) {
-				if(((Comparable)array[j]).compareTo((T)min) < 0) {
-					min = array[j];
-					minId = j;
-				}
-			}
-			T temp = array[i];
-			array[i] = min;
-			array[minId] = temp;
-		}
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort,
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] mergeSort(T[] array, Comparator comp) {
-		mergeSort(array, null, 0, array.length, comp);
-		return array;
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort,
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void mergeSort(T[] array, int length, Comparator comp) {
-		mergeSort(array, null, 0, length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Merge Sort,
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @param supp the auxillary array that is used to simplify the sorting
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void mergeSort(T[] array, T[] supp, int from, int to, Comparator comp) {
-		if(to - from < BASE_THRESHOLD) {
-			insertionSort(array, from, to, comp);
-			return;
-		}
-		if(supp == null) supp = Arrays.copyOf(array, to);
-		int mid = (from + to) >>> 1;
-		mergeSort(supp, array, from, mid, comp);
-		mergeSort(supp, array, mid, to, comp);
-		if(comp.compare(supp[mid - 1], supp[mid]) <= 0)
-		{
-			System.arraycopy(supp, from, array, from, to - from);
-			return;
-		}
-		for(int p = from, q = mid;from < to;from++) {
-			if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++];
-			else array[from] = supp[q++];
-		}
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Merge Sort, 
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] mergeSort(T[] array) {
-		mergeSort(array, null, 0, array.length);
-		return array;
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Merge Sort,
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void mergeSort(T[] array, int length) {
-		mergeSort(array, null, 0, length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Merge Sort,
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @param supp the auxillary array that is used to simplify the sorting
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void mergeSort(T[] array, T[] supp, int from, int to) {
-		if(to - from < BASE_THRESHOLD) {
-			insertionSort(array, from, to);
-			return;
-		}
-		if(supp == null) supp = Arrays.copyOf(array, to);
-		int mid = (from + to) >>> 1;
-		mergeSort(supp, array, from, mid);
-		mergeSort(supp, array, mid, to);
-		if(((Comparable)supp[mid - 1]).compareTo((T)supp[mid]) <= 0)
-		{
-			System.arraycopy(supp, from, array, from, to - from);
-			return;
-		}
-		for(int p = from, q = mid;from < to;from++) {
-			if(q >= to || p < mid && ((Comparable)supp[p]).compareTo((T)supp[q]) < 0) array[from] = supp[p++];
-			else array[from] = supp[q++];
-		}
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using a Parallel Merge Sort,
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMergeSort(T[] array, Comparator comp) {
-		parallelMergeSort(array, null, 0, array.length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort,
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMergeSort(T[] array, int length, Comparator comp) {
-		parallelMergeSort(array, null, 0, length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Merge Sort,
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @param supp the auxillary array that is used to simplify the sorting
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param comp the Comparator that decides the sorting order
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMergeSort(T[] array, T[] supp, int from, int to, Comparator comp) {
-		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
-			SanityChecks.invokeTask(new MergeSortActionComp<>(array, supp, from, to, comp));
-			return;
-		}
-		mergeSort(array, supp, from, to, comp);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Parallel Merge Sort, 
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMergeSort(T[] array) {
-		parallelMergeSort(array, null, 0, array.length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Parallel Merge Sort,
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMergeSort(T[] array, int length) {
-		parallelMergeSort(array, null, 0, length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Parallel Merge Sort,
-	 * This implementation was copied from FastUtil with a couple custom optimizations
-	 * @param array the array that needs to be sorted
-	 * @param supp the auxillary array that is used to simplify the sorting
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMergeSort(T[] array, T[] supp, int from, int to) {
-		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
-			SanityChecks.invokeTask(new MergeSortAction<>(array, supp, from, to));
-			return;
-		}
-		mergeSort(array, supp, from, to);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort,
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast.
-	 * @param array the array that needs to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void memFreeMergeSort(T[] array, Comparator comp) {
-		memFreeMergeSort(array, 0, array.length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort,
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast.
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void memFreeMergeSort(T[] array, int length, Comparator comp) {
-		memFreeMergeSort(array, 0, length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Memory Free Merge Sort,
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast.
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void memFreeMergeSort(T[] array, int from, int to, Comparator comp) {
-		if(to - from < BASE_THRESHOLD) {
-			insertionSort(array, from, to, comp);
-			return;
-		}
-		int mid = (from + to) >>> 1;
-		memFreeMergeSort(array, from, mid, comp);
-		memFreeMergeSort(array, mid, to, comp);
-		if(comp.compare(array[mid - 1], array[mid]) <= 0)
-			return;
-		for(int i = from, j = mid, compare;i < j && j < to;) {
-			if((compare = comp.compare(array[i], array[j])) < 0)
-				i++;
-			else if(compare == 0) swap(array, ++i, j);
-			else {
-				int k = j;
-				for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++);
-				if(j == k) {
-					swap(array, i++, j);
-					continue;
-				}
-				else if(j + 1 == k) {
-					T value = array[j];
-					System.arraycopy(array, i, array, i+1, j - i);
-					array[i] = value;
-					i++;
-					j++;
-					continue;
-				}
-				T[] data = (T[])new Object[k - j];
-				System.arraycopy(array, j, data, 0, data.length);
-				System.arraycopy(array, i, array, i+data.length, j - i);
-				System.arraycopy(data, 0, array, i, data.length);
-				i+=data.length;
-				j+=data.length;
-			}
-		}
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Memory Free Merge Sort, 
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
-	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
-	 * It does stack allocate tiny amounts of data for shifting around elements.
-	 * @author Speiger
-	 * @param array the array that needs to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] memFreeMergeSort(T[] array) {
-		memFreeMergeSort(array, 0, array.length);
-		return array;
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Memory Free Merge Sort, 
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
-	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
-	 * It does stack allocate tiny amounts of data for shifting around elements.
-	 * @author Speiger
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void memFreeMergeSort(T[] array, int length) {
-		memFreeMergeSort(array, 0, length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Memory Free Merge Sort, 
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
-	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
-	 * It does stack allocate tiny amounts of data for shifting around elements.
-	 * @author Speiger
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void memFreeMergeSort(T[] array, int from, int to) {
-		if(to - from < BASE_THRESHOLD) {
-			insertionSort(array, from, to);
-			return;
-		}
-		int mid = (from + to) >>> 1;
-		memFreeMergeSort(array, from, mid);
-		memFreeMergeSort(array, mid, to);
-		if(((Comparable)array[mid - 1]).compareTo((T)array[mid]) <= 0)
-			return;
-		for(int i = from, j = mid, comp;i < j && j < to;) {
-			if((comp = ((Comparable)array[i]).compareTo((T)array[j])) < 0)
-				i++;
-			else if(comp == 0) swap(array, ++i, j);
-			else {
-				int k = j;
-				for(;k < to - 1 && ((Comparable)array[i]).compareTo((T)array[k + 1]) > 0;k++);
-				if(j == k) {
-					swap(array, i++, j);
-					continue;
-				}
-				else if(j + 1 == k) {
-					T value = array[j];
-					System.arraycopy(array, i, array, i+1, j - i);
-					array[i] = value;
-					i++;
-					j++;
-					continue;
-				}
-				T[] data = (T[])new Object[k - j];
-				System.arraycopy(array, j, data, 0, data.length);
-				System.arraycopy(array, i, array, i+data.length, j - i);
-				System.arraycopy(data, 0, array, i, data.length);
-				i+=data.length;
-				j+=data.length;
-			}
-		}
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort,
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
-	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
-	 * It does stack allocate tiny amounts of data for shifting around elements.
-	 * @author Speiger
-	 * @param array the array that needs to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMemFreeMergeSort(T[] array, Comparator comp) {
-		parallelMemFreeMergeSort(array, 0, array.length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort,
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
-	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
-	 * It does stack allocate tiny amounts of data for shifting around elements.
-	 * @author Speiger
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMemFreeMergeSort(T[] array, int length, Comparator comp) {
-		parallelMemFreeMergeSort(array, 0, length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort,
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
-	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
-	 * It does stack allocate tiny amounts of data for shifting around elements.
-	 * @author Speiger
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param comp the Comparator that decides the sorting order
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMemFreeMergeSort(T[] array, int from, int to, Comparator comp) {
-		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
-			SanityChecks.invokeTask(new MemFreeMergeSortActionComp<>(array, from, to, comp));
-			return;
-		}
-		memFreeMergeSort(array, from, to, comp);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, 
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
-	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
-	 * It does stack allocate tiny amounts of data for shifting around elements.
-	 * @author Speiger
-	 * @param array the array that needs to be sorted
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMemFreeMergeSort(T[] array) {
-		parallelMemFreeMergeSort(array, 0, array.length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort,
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
-	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
-	 * It does stack allocate tiny amounts of data for shifting around elements.
-	 * @author Speiger
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMemFreeMergeSort(T[] array, int length) {
-		parallelMemFreeMergeSort(array, 0, length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort,
-	 * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array.
-	 * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario.
-	 * It does stack allocate tiny amounts of data for shifting around elements.
-	 * @author Speiger
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void parallelMemFreeMergeSort(T[] array, int from, int to) {
-		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
-			SanityChecks.invokeTask(new MemFreeMergeSortAction<>(array, from, to));
-			return;
-		}
-		memFreeMergeSort(array, from, to);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort,
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] quickSort(T[] array, Comparator comp) {
-		quickSort(array, 0, array.length, comp);
-		return array;
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort,
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void quickSort(T[] array, int length, Comparator comp) {
-		quickSort(array, 0, length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Quick Sort,
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void quickSort(T[] array, int from, int to, Comparator comp) {
-		int length = to - from;
-		if(length <= 0) return;
-		if(length < BASE_THRESHOLD) {
-			selectionSort(array, from, to, comp);
-			return;			
-		}
-		T pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)];
-		int a = from, b = a, c = to - 1, d = c;
-		for(int compare;;swap(array, b++, c--)) {
-			for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) {
-				if(compare == 0) swap(array, a++, b);
-			}
-			for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) {
-				if(compare == 0) swap(array, c, d--);
-			}
-			if(b>c) break;
-		}
-		swap(array, from, b, Math.min(a - from, b - a)); 
-		swap(array, b, to, Math.min(d - c, to - d - 1));
-		if((length = b - a) > 1) quickSort(array, from, from + length, comp);
-		if((length = d - c) > 1) quickSort(array, to - length, to, comp);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Quick Sort, 
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 * @return input array
-	 */
-	public static  T[] quickSort(T[] array) {
-		quickSort(array, 0, array.length);
-		return array;
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Quick Sort,
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void quickSort(T[] array, int length) {
-		quickSort(array, 0, length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Quick Sort,
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param  the keyType of array that the operation should be applied
-	 */
-	public static  void quickSort(T[] array, int from, int to) {
-		int length = to - from;
-		if(length <= 0) return;
-		if(length < BASE_THRESHOLD) {
-			selectionSort(array, from, to);
-			return;			
-		}
-		T pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)];
-		int a = from, b = a, c = to - 1, d = c;
-		for(int comp = 0;;swap(array, b++, c--)) {
-			for(;b<=c && (comp = ((Comparable)array[b]).compareTo((T)pivot)) <= 0;b++) {
-				if(comp == 0) swap(array, a++, b);
-			}
-			for(;c>=b && (comp = ((Comparable)array[c]).compareTo((T)pivot)) >= 0;c--) {
-				if(comp == 0) swap(array, c, d--);
-			}
-			if(b>c) break;
-		}
-		swap(array, from, b, Math.min(a - from, b - a)); 
-		swap(array, b, to, Math.min(d - c, to - d - 1));
-		if((length = b - a) > 1) quickSort(array, from, from + length);
-		if((length = d - c) > 1) quickSort(array, to - length, to);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort,
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 */
-	public static  void parallelQuickSort(T[] array, Comparator comp) {
-		parallelQuickSort(array, 0, array.length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort,
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 */
-	public static  void parallelQuickSort(T[] array, int length, Comparator comp) {
-		parallelQuickSort(array, 0, length, comp);
-	}
-	
-	/**
-	 * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Quick Sort,
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param comp the Comparator that decides the sorting order
-	 * @param  the keyType of array that the operation should be applied
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 */
-	public static  void parallelQuickSort(T[] array, int from, int to, Comparator comp) {
-		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
-			SanityChecks.invokeTask(new QuickSortActionComp<>(array, from, to, comp));
-			return;
-		}
-		quickSort(array, from, to, comp);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Parallel Quick Sort, 
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 */
-	public static  void parallelQuickSort(T[] array) {
-		parallelQuickSort(array, 0, array.length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Parallel Quick Sort,
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param length the maxmium size of the array to be sorted
-	 * @param  the keyType of array that the operation should be applied
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 */
-	public static  void parallelQuickSort(T[] array, int length) {
-		parallelQuickSort(array, 0, length);
-	}
-	
-	/**
-	 * Sorts an array according to the natural ascending order using Parallel Quick Sort,
-	 * This implementation is a custom of FastUtil quicksort but with a different code structure,
-	 * and that sorting Algorithm is based on the tuned quicksort adapted from Jon L. Bentley and M. DouglasMcIlroy, "Engineering a Sort Function", Software: Practice and Experience, 23(11), pages1249−1265, 1993. 
-	 * @param array the array that needs to be sorted
-	 * @param from where the array should be sorted from
-	 * @param to where the array should be sorted to
-	 * @param  the keyType of array that the operation should be applied
-	 * @note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed
-	 */
-	public static  void parallelQuickSort(T[] array, int from, int to) {
-		if(SanityChecks.canParallelTask() && to - from >= PARALLEL_THRESHOLD) {
-			SanityChecks.invokeTask(new QuickSortAction<>(array, from, to));
-			return;
-		}
-		quickSort(array, from, to);
-	}
-	
-	static  void swap(T[] a, int from, int to) {
-		T t = a[from];
-		a[from] = a[to];
-		a[to] = t;
-	}
-	
-	static  void swap(T[] a, int from, int to, int length) {
-		to -= length;
-		for(int i = 0;i int subMedium(T[] data, int a, int b, int c, int length, Comparator comp) {
-		return medium(data, medium(data, a, a + length, a + (length * 2), comp), medium(data, b - length, b, b + length, comp), medium(data, c - (length * 2), c - length, c, comp), comp);
-	}
-	
-	static  int medium(T[] data, int a, int b, int c, Comparator comp) {
-		return comp.compare(data[a], data[b]) < 0 ? (comp.compare(data[b], data[c]) < 0 ? b : comp.compare(data[a], data[c]) < 0 ? c : a) : (comp.compare(data[b], data[c]) > 0 ? b : comp.compare(data[a], data[c]) > 0 ? c : a);
-	}
-	
-	static  int subMedium(T[] data, int a, int b, int c, int length) {
-		return medium(data, medium(data, a, a + length, a + (length * 2)), medium(data, b - length, b, b + length), medium(data, c - (length * 2), c - length, c));
-	}
-	
-	static  int medium(T[] data, int a, int b, int c) {
-		return ((Comparable)data[a]).compareTo((T)data[b]) < 0 ? (((Comparable)data[b]).compareTo((T)data[c]) < 0 ? b : ((Comparable)data[a]).compareTo((T)data[c]) < 0 ? c : a) : (((Comparable)data[b]).compareTo((T)data[c]) > 0 ? b : ((Comparable)data[a]).compareTo((T)data[c]) > 0 ? c : a);
-	}
-	
-	static class QuickSortAction extends RecursiveAction {
-		private static final long serialVersionUID = 0L;
-		T[] array;
-		int from;
-		int to;
-		
-		QuickSortAction(T[] array, int from, int to)
-		{
-			this.array = array;
-			this.from = from;
-			this.to = to;
-		}
-		
-		@Override
-		protected void compute()
-		{
-			int length = to - from;
-			if(length <= 0) return;
-			if(length < BASE_THRESHOLD) {
-				selectionSort(array, from, to);
-				return;			
-			}
-			T pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8) : medium(array, from, from + (length / 2), to - 1)];
-			int a = from, b = a, c = to - 1, d = c;
-			for(int comp = 0;;swap(array, b++, c--)) {
-				for(;b<=c && (comp = ((Comparable)array[b]).compareTo((T)pivot)) <= 0;b++) {
-					if(comp == 0) swap(array, a++, b);
-				}
-				for(;c>=b && (comp = ((Comparable)array[c]).compareTo((T)pivot)) >= 0;c--) {
-					if(comp == 0) swap(array, c, d--);
-				}
-				if(b>c) break;
-			}
-			swap(array, from, b, Math.min(a - from, b - a)); 
-			swap(array, b, to, Math.min(d - c, to - d - 1));
-			if(b - a > 1 && d - c > 1) invokeAll(new QuickSortAction<>(array, from, from + (b - a)), new QuickSortAction<>(array, to - (d - c), to));
-			else if(b - a > 1) new QuickSortAction<>(array, from, from + (b - a)).invoke();
-			else if(d - c > 1) new QuickSortAction<>(array, to - (d - c), to).invoke();
-		}
-	}
-	
-	static class QuickSortActionComp extends RecursiveAction {
-		private static final long serialVersionUID = 0L;
-		T[] array;
-		int from;
-		int to;
-		Comparator comp;
-		
-		QuickSortActionComp(T[] array, int from, int to, Comparator comp)
-		{
-			this.array = array;
-			this.from = from;
-			this.to = to;
-			this.comp = comp;
-		}
-		
-		@Override
-		protected void compute()
-		{
-			int length = to - from;
-			if(length <= 0) return;
-			if(length < BASE_THRESHOLD) {
-				selectionSort(array, from, to, comp);
-				return;			
-			}
-			T pivot = array[length > 128 ? subMedium(array, from, from + (length / 2), to - 1, length / 8, comp) : medium(array, from, from + (length / 2), to - 1, comp)];
-			int a = from, b = a, c = to - 1, d = c;
-			for(int compare;;swap(array, b++, c--)) {
-				for(;b<=c && (compare = comp.compare(array[b], pivot)) <= 0;b++) {
-					if(compare == 0) swap(array, a++, b);
-				}
-				for(;c>=b && (compare = comp.compare(array[c], pivot)) >= 0;c--) {
-					if(compare == 0) swap(array, c, d--);
-				}
-				if(b>c) break;
-			}
-			swap(array, from, b, Math.min(a - from, b - a)); 
-			swap(array, b, to, Math.min(d - c, to - d - 1));
-			if(b - a > 1 && d - c > 1) invokeAll(new QuickSortActionComp<>(array, from, from + (b - a), comp), new QuickSortActionComp<>(array, to - (d - c), to, comp));
-			else if(b - a > 1) new QuickSortActionComp<>(array, from, from + (b - a), comp).invoke();
-			else if(d - c > 1) new QuickSortActionComp<>(array, to - (d - c), to, comp).invoke();
-		}
-	}
-	
-	static class MergeSortAction extends RecursiveAction {
-		private static final long serialVersionUID = 0L;
-		T[] array;
-		T[] supp;
-		int from;
-		int to;
-		
-		MergeSortAction(T[] array, T[] supp, int from, int to)
-		{
-			this.array = array;
-			this.supp = supp;
-			this.from = from;
-			this.to = to;
-		}
-		
-		@Override
-		protected void compute()
-		{
-			if(to - from < BASE_THRESHOLD) {
-				insertionSort(array, from, to);
-				return;
-			}
-			if(supp == null) supp = Arrays.copyOf(array, to);
-			int mid = (from + to) >>> 1;
-			invokeAll(new MergeSortAction<>(supp, array, from, mid), new MergeSortAction<>(supp, array, mid, to));
-			if(((Comparable)supp[mid - 1]).compareTo((T)supp[mid]) <= 0)
-			{
-				System.arraycopy(supp, from, array, from, to - from);
-				return;
-			}
-			for(int p = from, q = mid;from < to;from++) {
-				if(q >= to || p < mid && ((Comparable)supp[p]).compareTo((T)supp[q]) < 0) array[from] = supp[p++];
-				else array[from] = supp[q++];
-			}
-		}
-	}
-	
-	static class MergeSortActionComp extends RecursiveAction {
-		private static final long serialVersionUID = 0L;
-		T[] array;
-		T[] supp;
-		int from;
-		int to;
-		Comparator comp;
-		
-		MergeSortActionComp(T[] array, T[] supp, int from, int to, Comparator comp)
-		{
-			this.array = array;
-			this.supp = supp;
-			this.from = from;
-			this.to = to;
-			this.comp = comp;
-		}
-		
-		@Override
-		protected void compute()
-		{
-			if(to - from < BASE_THRESHOLD) {
-				insertionSort(array, from, to, comp);
-				return;
-			}
-			if(supp == null) supp = Arrays.copyOf(array, to);
-			int mid = (from + to) >>> 1;
-			invokeAll(new MergeSortActionComp<>(supp, array, from, mid, comp), new MergeSortActionComp<>(supp, array, mid, to, comp));
-			if(comp.compare(supp[mid - 1], supp[mid]) <= 0)
-			{
-				System.arraycopy(supp, from, array, from, to - from);
-				return;
-			}
-			for(int p = from, q = mid;from < to;from++) {
-				if(q >= to || p < mid && comp.compare(supp[p], supp[q]) < 0) array[from] = supp[p++];
-				else array[from] = supp[q++];
-			}
-		}
-	}
-	
-	static class MemFreeMergeSortAction extends RecursiveAction {
-		private static final long serialVersionUID = 0L;
-		T[] array;
-		int from;
-		int to;
-		
-		MemFreeMergeSortAction(T[] array, int from, int to)
-		{
-			this.array = array;
-			this.from = from;
-			this.to = to;
-		}
-		
-		@Override
-		protected void compute()
-		{
-			if(to - from < BASE_THRESHOLD) {
-				insertionSort(array, from, to);
-				return;
-			}
-			int mid = (from + to) >>> 1;
-			invokeAll(new MemFreeMergeSortAction<>(array, from, mid), new MemFreeMergeSortAction<>(array, mid, to));
-			if(((Comparable)array[mid - 1]).compareTo((T)array[mid]) <= 0)
-				return;
-			for(int i = from, j = mid, comp;i < j && j < to;) {
-				if((comp = ((Comparable)array[i]).compareTo((T)array[j])) < 0)
-					i++;
-				else if(comp == 0) swap(array, ++i, j);
-				else {
-					int k = j;
-					for(;k < to - 1 && ((Comparable)array[i]).compareTo((T)array[k + 1]) > 0;k++);
-					if(j == k) {
-						swap(array, i++, j);
-						continue;
-					}
-					else if(j + 1 == k) {
-						T value = array[j];
-						System.arraycopy(array, i, array, i+1, j - i);
-						array[i] = value;
-						i++;
-						j++;
-						continue;
-					}
-					T[] data = (T[])new Object[k - j];
-					System.arraycopy(array, j, data, 0, data.length);
-					System.arraycopy(array, i, array, i+data.length, j - i);
-					System.arraycopy(data, 0, array, i, data.length);
-					i+=data.length;
-					j+=data.length;
-				}
-			}
-		}
-	}
-	
-	static class MemFreeMergeSortActionComp extends RecursiveAction {
-		private static final long serialVersionUID = 0L;
-		T[] array;
-		int from;
-		int to;
-		Comparator comp;
-		
-		MemFreeMergeSortActionComp(T[] array, int from, int to, Comparator comp)
-		{
-			this.array = array;
-			this.from = from;
-			this.to = to;
-			this.comp = comp;
-		}
-		
-		@Override
-		protected void compute()
-		{
-			if(to - from < BASE_THRESHOLD) {
-				insertionSort(array, from, to, comp);
-				return;
-			}
-			int mid = (from + to) >>> 1;
-			invokeAll(new MemFreeMergeSortActionComp<>(array, from, mid, comp), new MemFreeMergeSortActionComp<>(array, mid, to, comp));
-
-			if(comp.compare(array[mid - 1], array[mid]) <= 0)
-				return;
-			for(int i = from, j = mid, compare;i < j && j < to;) {
-				if((compare = comp.compare(array[i], array[j])) < 0)
-					i++;
-				else if(compare == 0) swap(array, ++i, j);
-				else {
-					int k = j;
-					for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++);
-					if(j == k) {
-						swap(array, i++, j);
-						continue;
-					}
-					else if(j + 1 == k) {
-						T value = array[j];
-						System.arraycopy(array, i, array, i+1, j - i);
-						array[i] = value;
-						i++;
-						j++;
-						continue;
-					}
-					T[] data = (T[])new Object[k - j];
-					System.arraycopy(array, j, data, 0, data.length);
-					System.arraycopy(array, i, array, i+data.length, j - i);
-					System.arraycopy(data, 0, array, i, data.length);
-					i+=data.length;
-					j+=data.length;
-				}
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/utils/ObjectCollections.java b/src/main/java/speiger/src/collections/objects/utils/ObjectCollections.java
deleted file mode 100644
index 77df1ee3e..000000000
--- a/src/main/java/speiger/src/collections/objects/utils/ObjectCollections.java
+++ /dev/null
@@ -1,802 +0,0 @@
-package speiger.src.collections.objects.utils;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.Comparator;
-import java.util.function.BiFunction;
-import java.util.function.Predicate;
-import java.util.function.Consumer;
-
-import speiger.src.collections.objects.collections.AbstractObjectCollection;
-import speiger.src.collections.objects.collections.ObjectCollection;
-import speiger.src.collections.objects.collections.ObjectIterator;
-import speiger.src.collections.objects.utils.ObjectArrays;
-import speiger.src.collections.objects.functions.function.ObjectObjectUnaryOperator;
-import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
-import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
-import speiger.src.collections.utils.HashUtil;
-import speiger.src.collections.utils.ITrimmable;
-import speiger.src.collections.utils.SanityChecks;
-
-/**
- * A Helper class for Collections
- */
-public class ObjectCollections
-{
-	/**
-	 * Empty Collection Reference
-	 */
-	public static final ObjectCollection EMPTY = new EmptyCollection<>();
-	
-	/**
-	 * Returns a Immutable EmptyCollection instance that is automatically casted.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return an empty collection
-	 */
-	public static  ObjectCollection empty() {
-		return (ObjectCollection)EMPTY;
-	}
-	
-	/**
-	 * Returns a Immutable Collection instance based on the instance given.
-	 * @param c that should be made immutable/unmodifiable
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a unmodifiable collection wrapper. If the Collection already a unmodifiable wrapper then it just returns itself.
-	 */
-	public static  ObjectCollection unmodifiable(ObjectCollection c) {
-		return c instanceof UnmodifiableCollection ? c : new UnmodifiableCollection<>(c);
-	}
-	
-	/**
-	 * Returns a synchronized Collection instance based on the instance given.
-	 * @param c that should be synchronized
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself.
-	 */
-	public static  ObjectCollection synchronize(ObjectCollection c) {
-		return c instanceof SynchronizedCollection ? c : new SynchronizedCollection<>(c);
-	}
-	
-	/**
-	 * Returns a synchronized Collection instance based on the instance given.
-	 * @param c that should be synchronized
-	 * @param mutex is the controller of the synchronization block.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a synchronized collection wrapper. If the Collection already a synchronized wrapper then it just returns itself.
-	 */
-	public static  ObjectCollection synchronize(ObjectCollection c, Object mutex) {
-		return c instanceof SynchronizedCollection ? c : new SynchronizedCollection<>(c, mutex);
-	}
-	
-	/**
-	 * Creates a Singleton Collection of a given element
-	 * @param element the element that should be converted into a singleton collection
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a singletoncollection of the given element
-	 */
-	public static  ObjectCollection singleton(T element) {
-		return new SingletonCollection<>(element);
-	}
-	
-	protected static  CollectionWrapper wrapper() {
-		return new CollectionWrapper<>();
-	}
-	
-	protected static  CollectionWrapper wrapper(int size) {
-		return new CollectionWrapper<>(size);
-	}
-	
-	protected static  DistinctCollectionWrapper distinctWrapper() {
-		return new DistinctCollectionWrapper<>();
-	}
-	
-	protected static  DistinctCollectionWrapper distinctWrapper(int size) {
-		return new DistinctCollectionWrapper<>(size);
-	}
-	
-	protected static class CollectionWrapper extends AbstractObjectCollection implements ITrimmable {
-		T[] elements;
-		int size = 0;
-		
-		public CollectionWrapper() {
-			this(10);
-		}
-		
-		public CollectionWrapper(int size) {
-			if(size < 0) throw new IllegalStateException("Size has to be 0 or greater");
-			elements = (T[])new Object[size];
-		}
-		
-		@Override
-		public boolean add(T o) {
-			if(size >= elements.length) elements = Arrays.copyOf(elements, (int)Math.min((long)elements.length + (elements.length >> 1), SanityChecks.MAX_ARRAY_SIZE));
-			elements[size++] = o;
-			return true;
-		}
-		
-		public T get(int index) {
-			if(index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
-			return elements[index];
-		}
-		
-		@Override
-		public boolean remove(Object e) {
-			for(int i = 0;i= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
-			size--;
-			if(index != size) System.arraycopy(elements, index+1, elements, index, size - index);
-		}
-		
-		@Override
-		public ObjectIterator iterator() {
-			return new ObjectIterator() {
-				int index = 0;
-				int lastReturned = -1;
-				
-				@Override
-				public boolean hasNext() {
-					return index < size;
-				}
-				
-				@Override
-				public T next() {
-					int i = index++;
-					return elements[(lastReturned = i)];
-				}
-				
-				@Override
-				public void remove() {
-					if(lastReturned == -1) throw new IllegalStateException();
-					removeIndex(lastReturned);
-					index = lastReturned;
-					lastReturned = -1;
-				}
-			};
-		}
-		
-		@Override
-		public int size() {
-			return size;
-		}
-		
-		@Override
-		public void clear() {
-			for(int i = 0;i c) {
-			if(c != null) ObjectArrays.stableSort(elements, size, c);
-			else ObjectArrays.stableSort(elements, size);
-		}
-
-		public void unstableSort(Comparator c) {
-			if(c != null) ObjectArrays.unstableSort(elements, size, c);
-			else ObjectArrays.unstableSort(elements, size);
-		}
-		
-		@Override
-		public void forEach(Consumer action) {
-			Objects.requireNonNull(action);
-			for(int i = 0;i void forEach(E input, ObjectObjectConsumer action) {
-			Objects.requireNonNull(action);
-			for(int i = 0;i size() || size() == elements.length) return false;
-			int value = Math.max(size, size());
-			elements = value == 0 ? (T[])ObjectArrays.EMPTY_ARRAY : Arrays.copyOf(elements, value);
-			return true;
-		}
-		
-		@Override
-		public void clearAndTrim(int size) {
-			if(elements.length <= size) {
-				clear();
-				return;
-			}
-			elements = size == 0 ? (T[])ObjectArrays.EMPTY_ARRAY : (T[])new Object[size];
-			this.size = size;
-		}
-		
-		@Override
-		public Object[] toArray() {
-			Object[] obj = new Object[size];
-			for(int i = 0;i E[] toArray(E[] a) {
-			if(a == null) a = (E[])new Object[size];
-			else if(a.length < size) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), size);
-	        System.arraycopy(elements, 0, a, 0, size);
-			if (a.length > size) a[size] = null;
-			return a;
-		}
-		
-	}
-	
-	protected static class DistinctCollectionWrapper extends AbstractObjectCollection {
-		T[] keys;
-		boolean containsNull;
-		int minCapacity;
-		int nullIndex;
-		int maxFill;
-		int mask;
-		int size;
-		
-		public DistinctCollectionWrapper() {
-			this(HashUtil.DEFAULT_MIN_CAPACITY);
-		}
-		
-		public DistinctCollectionWrapper(int size) {
-			if(minCapacity < 0)	throw new IllegalStateException("Minimum Capacity is negative. This is not allowed");
-			minCapacity = nullIndex = HashUtil.arraySize(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR);
-			mask = nullIndex - 1;
-			maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1);
-			keys = (T[])new Object[nullIndex + 1];
-		}
-
-		@Override
-		public boolean add(T o) {
-			if(o == null) {
-				if(containsNull) return false;
-				containsNull = true;
-			}
-			else {
-				int pos = HashUtil.mix(Objects.hashCode(o)) & mask;
-				T current = keys[pos];
-				if(current != null) {
-					if(Objects.equals(current, o)) return false;
-					while((current = keys[pos = (++pos & mask)]) != null)
-						if(Objects.equals(current, o)) return false;
-				}
-				keys[pos] = o;
-			}
-			if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, HashUtil.DEFAULT_LOAD_FACTOR));
-			return true;
-		}
-		
-		@Override
-		public boolean contains(Object o) {
-			if(o == null) return containsNull;
-			int pos = HashUtil.mix(o.hashCode()) & mask;
-			T current = keys[pos];
-			if(current == null) return false;
-			if(Objects.equals(o, current)) return true;
-			while(true) {
-				if((current = keys[pos = (++pos & mask)]) == null) return false;
-				else if(Objects.equals(o, current)) return true;
-			}
-		}
-
-		@Override
-		public boolean remove(Object o) {
-			if(o == null) return (containsNull ? removeNullIndex() : false);
-			int pos = HashUtil.mix(o.hashCode()) & mask;
-			T current = keys[pos];
-			if(current == null) return false;
-			if(Objects.equals(o, current)) return removeIndex(pos);
-			while(true) {
-				if((current = keys[pos = (++pos & mask)]) == null) return false;
-				else if(Objects.equals(o, current)) return removeIndex(pos);
-			}
-		}
-
-		protected boolean removeIndex(int pos) {
-			if(pos == nullIndex) return containsNull ? removeNullIndex() : false;
-			keys[pos] = null;
-			size--;
-			shiftKeys(pos);
-			if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
-			return true;
-		}
-		
-		protected boolean removeNullIndex() {
-			containsNull = false;
-			keys[nullIndex] = null;
-			size--;
-			if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
-			return true;
-		}
-		
-		@Override
-		public ObjectIterator iterator() {
-			return new SetIterator();
-		}
-		
-		@Override
-		public void forEach(Consumer action) {
-			if(size() <= 0) return;
-			if(containsNull) action.accept(keys[nullIndex]);
-			for(int i = nullIndex-1;i>=0;i--) {
-				if(keys[i] != null) action.accept(keys[i]);
-			}
-		}
-		
-		@Override
-		public DistinctCollectionWrapper copy() {
-			DistinctCollectionWrapper set = new DistinctCollectionWrapper<>(0);
-			set.minCapacity = minCapacity;
-			set.mask = mask;
-			set.maxFill = maxFill;
-			set.nullIndex = nullIndex;
-			set.containsNull = containsNull;
-			set.size = size;
-			set.keys = Arrays.copyOf(keys, keys.length);
-			return set;
-		}
-		
-		protected void shiftKeys(int startPos) {
-			int slot, last;
-			T current;
-			while(true) {
-				startPos = ((last = startPos) + 1) & mask;
-				while(true){
-					if((current = keys[startPos]) == null) {
-						keys[last] = null;
-						return;
-					}
-					slot = HashUtil.mix(Objects.hashCode(current)) & mask;
-					if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
-					startPos = ++startPos & mask;
-				}
-				keys[last] = current;
-			}
-		}
-		
-		protected void rehash(int newSize) {
-			int newMask = newSize - 1;
-			T[] newKeys = (T[])new Object[newSize + 1];
-			for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) {
-				while(true) {
-					if(--i < 0) throw new ConcurrentModificationException("Set was modified during rehash");
-					if(keys[i] != null) break;
-				}
-				if(newKeys[pos = HashUtil.mix(Objects.hashCode(keys[i])) & newMask] != null)
-					while(newKeys[pos = (++pos & newMask)] != null);
-				newKeys[pos] = keys[i];
-			}
-			nullIndex = newSize;
-			mask = newMask;
-			maxFill = Math.min((int)Math.ceil(nullIndex * HashUtil.DEFAULT_LOAD_FACTOR), nullIndex - 1);
-			keys = newKeys;
-		}
-		
-		@Override
-		public void clear() {
-			if(size == 0) return;
-			size = 0;
-			containsNull = false;
-			Arrays.fill(keys, null);
-		}
-		
-		@Override
-		public int size() {
-			return size;
-		}
-		
-		private class SetIterator implements ObjectIterator {
-			int pos = nullIndex;
-			int returnedPos = -1;
-			int lastReturned = -1;
-			int nextIndex = Integer.MIN_VALUE;
-			boolean returnNull = containsNull;
-			T[] wrapped = null;
-			int wrappedIndex = 0;
-			
-			@Override
-			public boolean hasNext() {
-				if(nextIndex == Integer.MIN_VALUE) {
-					if(returnNull) {
-						returnNull = false;
-						nextIndex = nullIndex;
-					}
-					else
-					{
-						while(true) {
-							if(--pos < 0) {
-								if(wrapped == null || wrappedIndex <= -pos - 1) break;
-								nextIndex = -pos - 1;
-								break;
-							}
-							if(keys[pos] != null){
-								nextIndex = pos;
-								break;
-							}
-						}
-					}
-				}
-				return nextIndex != Integer.MIN_VALUE;
-			}
-			
-			@Override
-			public T next() {
-				if(!hasNext()) throw new NoSuchElementException();
-				returnedPos = pos;
-				if(nextIndex < 0){
-					lastReturned = Integer.MAX_VALUE;
-					T value = wrapped[nextIndex];
-					nextIndex = Integer.MIN_VALUE;
-					return value;
-				}
-				T value = keys[(lastReturned = nextIndex)];
-				nextIndex = Integer.MIN_VALUE;
-				return value;
-			}
-			
-			@Override
-			public void remove() {
-				if(lastReturned == -1) throw new IllegalStateException();
-				if(lastReturned == nullIndex) {
-					containsNull = false;
-					keys[nullIndex] = null;
-				}
-				else if(returnedPos >= 0) shiftKeys(returnedPos);
-				else {
-					DistinctCollectionWrapper.this.remove(wrapped[-returnedPos - 1]);
-					lastReturned = -1;
-					return;
-				}
-				size--;
-				lastReturned = -1;
-			}
-			
-			private void shiftKeys(int startPos) {
-				int slot, last;
-				T current;
-				while(true) {
-					startPos = ((last = startPos) + 1) & mask;
-					while(true){
-						if((current = keys[startPos]) == null) {
-							keys[last] = null;
-							return;
-						}
-						slot = HashUtil.mix(Objects.hashCode(current)) & mask;
-						if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
-						startPos = ++startPos & mask;
-					}
-					if(startPos < last) addWrapper(keys[startPos]);
-					keys[last] = current;
-				}
-			}
-			
-			private void addWrapper(T value) {
-				if(wrapped == null) wrapped = (T[])new Object[2];
-				else if(wrappedIndex >= wrapped.length) {
-					T[] newArray = (T[])new Object[wrapped.length * 2];
-					System.arraycopy(wrapped, 0, newArray, 0, wrapped.length);
-					wrapped = newArray;
-				}
-				wrapped[wrappedIndex++] = value;
-			}
-		}
-	}
-	
-	private static class SingletonCollection extends AbstractObjectCollection
-	{
-		T element;
-		
-		SingletonCollection(T element) {
-			this.element = element;
-		}
-		
-		@Override
-		public boolean add(T o) { throw new UnsupportedOperationException(); }
-		@Override
-		public ObjectIterator iterator()
-		{
-			return new ObjectIterator() {
-				boolean next = true;
-				@Override
-				public boolean hasNext() { return next; }
-				@Override
-				public T next() {
-					if(!hasNext()) throw new NoSuchElementException();
-					next = false;
-					return element;
-				}
-			};
-		}
-		
-		@Override
-		public boolean equals(Object o) {
-			if (o == this)
-				return true;
-			if (!(o instanceof Collection))
-				return false;
-			Collection l = (Collection)o;
-			if(l.size() != size()) return false;
-			Iterator iter = l.iterator();
-			if (iter.hasNext() && !Objects.equals(element, iter.next())) {
-				return false;
-			}
-			return !iter.hasNext();
-		}
-		
-		@Override
-		public int hashCode() {
-			return Objects.hashCode(element);
-		}
-		
-		@Override
-		public int size() { return 1; }
-		
-		@Override
-		public SingletonCollection copy() { return new SingletonCollection<>(element); }
-	}
-	
-	/**
-	 * Synchronized Collection Wrapper for the synchronizedCollection function
-	 * @param  the keyType of elements maintained by this Collection
-	 */
-	public static class SynchronizedCollection implements ObjectCollection {
-		ObjectCollection c;
-		protected Object mutex;
-		
-		SynchronizedCollection(ObjectCollection c) {
-			this.c = c;
-			mutex = this;
-		}
-		
-		SynchronizedCollection(ObjectCollection c, Object mutex) {
-			this.c = c;
-			this.mutex = mutex;
-		}
-		
-		@Override
-		public boolean add(T o) { synchronized(mutex) { return c.add(o); } }
-		@Override
-		public boolean addAll(Collection c) { synchronized(mutex) { return this.c.addAll(c); } }
-		@Override
-		public boolean addAll(ObjectCollection c) { synchronized(mutex) { return this.c.addAll(c); } }
-		@Override
-		public boolean addAll(T[] e, int offset, int length) { synchronized(mutex) { return c.addAll(e, offset, length); } }
-		@Override
-		public boolean contains(Object o) { synchronized(mutex) { return c.contains(o); } }
-		@Override
-		public boolean containsAll(Collection c) { synchronized(mutex) { return this.c.containsAll(c); } }
-		
-		@Override
-		public boolean containsAny(Collection c) { synchronized(mutex) { return this.c.containsAny(c); } }
-		
-		@Override
-		public boolean containsAll(ObjectCollection c) { synchronized(mutex) { return this.c.containsAll(c); } }
-		
-		@Override
-		public boolean containsAny(ObjectCollection c) { synchronized(mutex) { return this.c.containsAny(c); } }
-		
-		@Override
-		public int size() { synchronized(mutex) { return c.size(); } }
-		
-		@Override
-		public boolean isEmpty() { synchronized(mutex) { return c.isEmpty(); } }
-		
-		@Override
-		public ObjectIterator iterator() {
-			return c.iterator();
-		}
-		
-		@Override
-		public ObjectCollection copy() { synchronized(mutex) { return c.copy(); } }
-		
-		@Override
-		public boolean remove(Object o) { synchronized(mutex) { return c.remove(o); } }
-		@Override
-		public boolean removeAll(Collection c) { synchronized(mutex) { return this.c.removeAll(c); } }
-		@Override
-		public boolean retainAll(Collection c) { synchronized(mutex) { return this.c.retainAll(c); } }
-		@Override
-		public boolean removeAll(ObjectCollection c) { synchronized(mutex) { return this.c.removeAll(c); } }
-		@Override
-		public boolean removeAll(ObjectCollection c, Consumer r) { synchronized(mutex) { return this.c.removeAll(c, r); } }
-		@Override
-		public boolean retainAll(ObjectCollection c) { synchronized(mutex) { return this.c.retainAll(c); } }
-		@Override
-		public boolean retainAll(ObjectCollection c, Consumer r) { synchronized(mutex) { return this.c.retainAll(c, r); } }
-		@Override
-		public void clear() { synchronized(mutex) { c.clear(); } }
-		@Override
-		public Object[] toArray() { synchronized(mutex) { return c.toArray(); } }
-		@Override
-		public  E[] toArray(E[] a) { synchronized(mutex) { return c.toArray(a); } }
-		@Override
-		public void forEach(Consumer action) { synchronized(mutex) { c.forEach(action); } }
-		@Override
-		public void forEachIndexed(IntObjectConsumer action) { synchronized(mutex) { c.forEachIndexed(action); } }
-		@Override
-		public int hashCode() { synchronized(mutex) { return c.hashCode(); } }
-		@Override
-		public boolean equals(Object obj) {
-			if(obj == this) return true;
-			synchronized(mutex) { return c.equals(obj); } 
-		}
-		@Override
-		public String toString() { synchronized(mutex) { return c.toString(); } }
-		@Override
-		public  void forEach(E input, ObjectObjectConsumer action) { synchronized(mutex) { c.forEach(input, action); } }
-		@Override
-		public boolean matchesAny(Predicate filter) { synchronized(mutex) { return c.matchesAny(filter); } }
-		@Override
-		public boolean matchesNone(Predicate filter) { synchronized(mutex) { return c.matchesNone(filter); } }
-		@Override
-		public boolean matchesAll(Predicate filter) { synchronized(mutex) { return c.matchesAll(filter); } }
-		public  E reduce(E identity, BiFunction operator) { synchronized(mutex) { return c.reduce(identity, operator); } }
-		@Override
-		public T reduce(ObjectObjectUnaryOperator operator) { synchronized(mutex) { return c.reduce(operator); } }
-		@Override
-		public T findFirst(Predicate filter) { synchronized(mutex) { return c.findFirst(filter); } }
-		@Override
-		public int count(Predicate filter) { synchronized(mutex) { return c.count(filter); } }
-	}
-	
-	/**
-	 * Unmodifyable Collection Wrapper for the unmodifyableCollection method
-	 * @param  the keyType of elements maintained by this Collection
-	 */
-	public static class UnmodifiableCollection implements ObjectCollection {
-		ObjectCollection c;
-		
-		UnmodifiableCollection(ObjectCollection c) {
-			this.c = c;
-		}
-		
-		@Override
-		public boolean add(T o) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean addAll(Collection c) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean addAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean addAll(T[] e, int offset, int length) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean contains(Object o) { return c.contains(o); }
-		@Override
-		public boolean containsAll(ObjectCollection c) { return this.c.containsAll(c); }
-		@Override
-		public boolean containsAny(ObjectCollection c) { return this.c.containsAny(c); }
-		@Override
-		public boolean containsAny(Collection c) { return this.c.containsAny(c); }
-		@Override
-		public boolean containsAll(Collection c) { return this.c.containsAll(c); }
-		@Override
-		public int size() { return c.size(); }
-		@Override
-		public boolean isEmpty() { return c.isEmpty(); }
-		@Override
-		public ObjectIterator iterator() { return ObjectIterators.unmodifiable(c.iterator()); }
-		@Override
-		public ObjectCollection copy() { return c.copy(); }
-		@Override
-		@Deprecated
-		public boolean remove(Object o) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean removeAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean removeAll(ObjectCollection c, Consumer r) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean retainAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean retainAll(ObjectCollection c, Consumer r) { throw new UnsupportedOperationException(); }
-		@Override
-		public void clear() { throw new UnsupportedOperationException(); }
-		@Override
-		public Object[] toArray() { return c.toArray(); }
-		@Override
-		public  E[] toArray(E[] a) { return c.toArray(a); }
-		@Override
-		public void forEach(Consumer action) { c.forEach(action); }
-		@Override
-		public void forEachIndexed(IntObjectConsumer action) { c.forEachIndexed(action); }
-		@Override
-		public int hashCode() { return c.hashCode(); }
-		@Override
-		public boolean equals(Object obj) { return obj == this || c.equals(obj); }
-		@Override
-		public String toString() { return c.toString(); }
-		@Override
-		public  void forEach(E input, ObjectObjectConsumer action) { c.forEach(input, action); }
-		@Override
-		public boolean matchesAny(Predicate filter) { return c.matchesAny(filter); }
-		@Override
-		public boolean matchesNone(Predicate filter) { return c.matchesNone(filter); }
-		@Override
-		public boolean matchesAll(Predicate filter) { return c.matchesAll(filter); }
-		public  E reduce(E identity, BiFunction operator) { return c.reduce(identity, operator); }
-		@Override
-		public T reduce(ObjectObjectUnaryOperator operator) { return c.reduce(operator); }
-		@Override
-		public T findFirst(Predicate filter) { return c.findFirst(filter); }
-		@Override
-		public int count(Predicate filter) { return c.count(filter); }
-	}
-	
-	/**
-	 * Empty Collection implementation for the empty collection function
-	 * @param  the keyType of elements maintained by this Collection
-	 */
-	public static class EmptyCollection extends AbstractObjectCollection {
-		@Override
-		public boolean add(T o) { throw new UnsupportedOperationException(); }
-		
-		@Override
-		public boolean addAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean addAll(T[] e, int offset, int length) { throw new UnsupportedOperationException(); }
-		
-		@Override
-		public boolean contains(Object o) { return false; }
-		@Override
-		public boolean containsAny(Collection c) { return false; }
-		@Override
-		public boolean containsAll(Collection c) { return c.isEmpty(); }
-		@Override
-		public int hashCode() { return 0; }
-		
-		@Override
-		public boolean equals(Object o) {
-			if(o == this) return true;
-		  	if(!(o instanceof Collection)) return false;
-		  	return ((Collection)o).isEmpty();
-		}
-		
-		@Override
-		@Deprecated
-		public boolean remove(Object o) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean removeIf(Predicate filter) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean removeAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
-		@Override
-		public boolean retainAll(ObjectCollection c) { throw new UnsupportedOperationException(); }
-		@Override
-		public Object[] toArray() { return ObjectArrays.EMPTY_ARRAY; }
-		@Override
-		public  E[] toArray(E[] a) {
-			if(a != null && a.length > 0)
-				a[0] = null;
-			return a;
-		}
-		@Override
-		public ObjectIterator iterator() { return ObjectIterators.empty(); }
-		@Override
-		public void clear() {}
-		@Override
-		public int size() { return 0; }
-		@Override
-		public EmptyCollection copy() { return this; }
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/utils/ObjectIterables.java b/src/main/java/speiger/src/collections/objects/utils/ObjectIterables.java
deleted file mode 100644
index 374376ec7..000000000
--- a/src/main/java/speiger/src/collections/objects/utils/ObjectIterables.java
+++ /dev/null
@@ -1,496 +0,0 @@
-package speiger.src.collections.objects.utils;
-
-import java.util.Objects;
-import java.util.Comparator;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
-
-import speiger.src.collections.objects.collections.ObjectIterable;
-import speiger.src.collections.objects.collections.ObjectCollection;
-import speiger.src.collections.objects.collections.ObjectIterator;
-import speiger.src.collections.objects.functions.function.UnaryOperator;
-import speiger.src.collections.utils.ISizeProvider;
-
-/**
- * A Helper class for Iterables
- */
-public class ObjectIterables
-{
-	/**
-	 * A Helper function that maps a Java-Iterable into a new Type.
-	 * @param iterable the iterable that should be mapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type.
-	 * @return a iterable that is mapped to a new result
-	 */
-	public static  ObjectIterable map(Iterable iterable, UnaryOperator mapper) {
-		return new MappedIterable<>(wrap(iterable), mapper);
-	}
-	
-	/**
-	 * A Helper function that maps a Iterable into a new Type.
-	 * @param iterable the iterable that should be mapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type.
-	 * @return a iterable that is mapped to a new result
-	 */
-	public static  ObjectIterable map(ObjectIterable iterable, UnaryOperator mapper) {
-		return new MappedIterable<>(iterable, mapper);
-	}
-	
-	/**
-	 * A Helper function that flatMaps a Java-Iterable into a new Type.
-	 * @param iterable the iterable that should be flatMapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type supplier.
-	 * @param  The return type.
-	 * @return a iterable that is flatMapped to a new result
-	 */
-	public static > ObjectIterable flatMap(Iterable iterable, UnaryOperator mapper) {
-		return new FlatMappedIterable<>(wrap(iterable), mapper);
-	}
-	
-	/**
-	 * A Helper function that flatMaps a Iterable into a new Type.
-	 * @param iterable the iterable that should be flatMapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type supplier.
-	 * @param  The return type.
-	 * @return a iterable that is flatMapped to a new result
-	 */
-	public static > ObjectIterable flatMap(ObjectIterable iterable, UnaryOperator mapper) {
-		return new FlatMappedIterable<>(iterable, mapper);
-	}
-	
-	/**
-	 * A Helper function that flatMaps a Java-Iterable into a new Type.
-	 * @param iterable the iterable that should be flatMapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type.
-	 * @return a iterable that is flatMapped to a new result
-	 */
-	public static  ObjectIterable arrayFlatMap(Iterable iterable, UnaryOperator mapper) {
-		return new FlatMappedArrayIterable<>(wrap(iterable), mapper);
-	}
-	
-	/**
-	 * A Helper function that flatMaps a Iterable into a new Type.
-	 * @param iterable the iterable that should be flatMapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type.
-	 * @return a iterable that is flatMapped to a new result
-	 */
-	public static  ObjectIterable arrayFlatMap(ObjectIterable iterable, UnaryOperator mapper) {
-		return new FlatMappedArrayIterable<>(iterable, mapper);
-	}
-	
-	/**
-	 * A Helper function that filters out all desired elements from a Java-Iterable
-	 * @param iterable that should be filtered.
-	 * @param filter the filter that decides that should be let through
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a filtered iterable
-	 */
-	public static  ObjectIterable filter(Iterable iterable, Predicate filter) {
-		return new FilteredIterable<>(wrap(iterable), filter);
-	}
-	
-	/**
-	 * A Helper function that filters out all desired elements
-	 * @param iterable that should be filtered.
-	 * @param filter the filter that decides that should be let through
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a filtered iterable
-	 */
-	public static  ObjectIterable filter(ObjectIterable iterable, Predicate filter) {
-		return new FilteredIterable<>(iterable, filter);
-	}
-	
-	/**
-	 * A Helper function that filters out all duplicated elements.
-	 * @param iterable that should be distinct
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a distinct iterable
-	 */
-	public static  ObjectIterable distinct(ObjectIterable iterable) {
-		return new DistinctIterable<>(iterable);
-	}
-	
-	/**
-	 * A Helper function that filters out all duplicated elements from a Java Iterable.
-	 * @param iterable that should be distinct
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a distinct iterable
-	 */
-	public static  ObjectIterable distinct(Iterable iterable) {
-		return new DistinctIterable<>(wrap(iterable));
-	}
-	
-	/**
-	 * A Helper function that repeats the Iterable a specific amount of times
-	 * @param iterable that should be repeated
-	 * @param repeats the amount of times the iterable should be repeated
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a repeating iterable
-	 */
-	public static  ObjectIterable repeat(ObjectIterable iterable, int repeats) {
-		return new RepeatingIterable<>(iterable, repeats);
-	}
-	
-	/**
-	 * A Helper function that repeats the Iterable a specific amount of times from a Java Iterable
-	 * @param iterable that should be repeated
-	 * @param repeats the amount of times the iterable should be repeated
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a repeating iterable
-	 */
-	public static  ObjectIterable repeat(Iterable iterable, int repeats) {
-		return new RepeatingIterable<>(wrap(iterable), repeats);
-	}
-	
-	/**
-	 * A Helper function that hard limits the Iterable to a specific size
-	 * @param iterable that should be limited
-	 * @param limit the amount of elements it should be limited to
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a limited iterable
-	 */
-	public static  ObjectIterable limit(ObjectIterable iterable, long limit) {
-		return new LimitedIterable<>(iterable, limit);
-	}
-	
-	/**
-	 * A Helper function that hard limits the Iterable to a specific size from a Java Iterable
-	 * @param iterable that should be limited
-	 * @param limit the amount of elements it should be limited to
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a limited iterable
-	 */
-	public static  ObjectIterable limit(Iterable iterable, long limit) {
-		return new LimitedIterable<>(wrap(iterable), limit);
-	}
-	
-	/**
-	 * A Helper function that sorts the Iterable.
-	 * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it.
-	 * @param iterable that should be sorted
-	 * @param sorter that sorts the iterable. Can be null.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a sorted iterable.
-	 */
-	public static  ObjectIterable sorted(ObjectIterable iterable, Comparator sorter) {
-		return new SortedIterable<>(iterable, sorter);
-	}
-	
-	/**
-	 * A Helper function that sorts the Iterable from a Java Iterable
-	 * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it.
-	 * @param iterable that should be sorted
-	 * @param sorter that sorts the iterable. Can be null.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a sorted iterable.
-	 */
-	public static  ObjectIterable sorted(Iterable iterable, Comparator sorter) {
-		return new SortedIterable<>(wrap(iterable), sorter);
-	}
-	
-	/**
-	 * A Helper function that allows to preview the result of a Iterable.
-	 * @param iterable that should be peeked at
-	 * @param action callback that receives the value before the iterable returns it
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a peeked iterable
-	 */
-	public static  ObjectIterable peek(ObjectIterable iterable, Consumer action) {
-		return new PeekIterable<>(iterable, action);
-	}
-	
-	/**
-	 * A Helper function that allows to preview the result of a Iterable from a Java Iterable
-	 * @param iterable that should be peeked at
-	 * @param action callback that receives the value before the iterable returns it
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a peeked iterable
-	 */
-	public static  ObjectIterable peek(Iterable iterable, Consumer action) {
-		return new PeekIterable<>(wrap(iterable), action);
-	}
-	
-	/**
-	 * A Wrapper function that wraps a Java-Iterable into a Type Specific Iterable
-	 * @param iterable that should be wrapped
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a type specific iterable
-	 */
-	public static  ObjectIterable wrap(Iterable iterable) {
-		return new WrappedIterable<>(iterable);
-	}
-	
-	private static class WrappedIterable implements ObjectIterable, ISizeProvider
-	{
-		Iterable iterable;
-		
-		public WrappedIterable(Iterable iterable) {
-			this.iterable = iterable;
-		}
-		
-		public ObjectIterator iterator() {
-			return ObjectIterators.wrap(iterable.iterator());
-		}
-		
-		@Override
-		public int size() {
-			ISizeProvider prov = ISizeProvider.of(iterable);
-			return prov == null ? -1 : prov.size();
-		}
-		
-		public void forEach(Consumer action) {
-			Objects.requireNonNull(action);
-			iterable.forEach(action);
-		}
-	}
-	
-	private static class MappedIterable implements ObjectIterable, ISizeProvider
-	{
-		ObjectIterable iterable;
-		UnaryOperator mapper;
-		
-		MappedIterable(ObjectIterable iterable, UnaryOperator mapper) {
-			this.iterable = iterable;
-			this.mapper = mapper;
-		}
-		
-		public ObjectIterator iterator() {
-			return ObjectIterators.map(iterable.iterator(), mapper);
-		}
-		
-		@Override
-		public int size() {
-			ISizeProvider prov = ISizeProvider.of(this);
-			return prov == null ? -1 : prov.size();
-		}
-		
-		@Override
-		public void forEach(Consumer action) {
-			Objects.requireNonNull(action);
-			iterable.forEach(E -> action.accept(mapper.apply(E)));
-		}
-	}
-	
-	private static class FlatMappedIterable> implements ObjectIterable
-	{
-		ObjectIterable iterable;
-		UnaryOperator mapper;
-		
-		FlatMappedIterable(ObjectIterable iterable, UnaryOperator mapper) {
-			this.iterable = iterable;
-			this.mapper = mapper;
-		}
-		
-		@Override
-		public ObjectIterator iterator() {
-			return ObjectIterators.flatMap(iterable.iterator(), mapper);
-		}
-		
-		@Override
-		public void forEach(Consumer action) {
-			Objects.requireNonNull(action);
-			iterable.forEach(E -> mapper.apply(E).forEach(action));
-		}
-		
-	}
-	
-	private static class FlatMappedArrayIterable implements ObjectIterable
-	{
-		ObjectIterable iterable;
-		UnaryOperator mapper;
-		
-		FlatMappedArrayIterable(ObjectIterable iterable, UnaryOperator mapper) {
-			this.iterable = iterable;
-			this.mapper = mapper;
-		}
-		
-		@Override
-		public ObjectIterator iterator() {
-			return ObjectIterators.arrayFlatMap(iterable.iterator(), mapper);
-		}
-		
-		@Override
-		public void forEach(Consumer action) {
-			Objects.requireNonNull(action);
-			iterable.forEach(E -> {
-				T[] array = mapper.apply(E);
-				for(int i = 0,m=array.length;i implements ObjectIterable, ISizeProvider
-	{
-		ObjectIterable iterable;
-		int repeats;
-		
-		public RepeatingIterable(ObjectIterable iterable, int repeats) {
-			this.iterable = iterable;
-			this.repeats = repeats;
-		}
-		
-		@Override
-		public ObjectIterator iterator() {
-			return ObjectIterators.repeat(iterable.iterator(), repeats);
-		}
-		
-		@Override
-		public int size() {
-			ISizeProvider prov = ISizeProvider.of(iterable);
-			return prov == null ? -1 : prov.size() * (repeats+1);
-		}
-		
-		@Override
-		public void forEach(Consumer action) {
-			Objects.requireNonNull(action);
-			ObjectCollection repeater = ObjectCollections.wrapper();
-			iterable.forEach(T -> {action.accept(T); repeater.add(T);});
-			for(int i = 0;i implements ObjectIterable
-	{
-		ObjectIterable iterable;
-		Predicate filter;
-		
-		public FilteredIterable(ObjectIterable iterable, Predicate filter) {
-			this.iterable = iterable;
-			this.filter = filter;
-		}
-		
-		@Override
-		public ObjectIterator iterator() {
-			return ObjectIterators.filter(iterable.iterator(), filter);
-		}
-		
-		public void forEach(Consumer action) {
-			Objects.requireNonNull(action);
-			iterable.forEach(T -> { if(!filter.test(T)) action.accept(T); } );
-		}
-	}
-	
-	private static class LimitedIterable implements ObjectIterable, ISizeProvider
-	{
-		ObjectIterable iterable;
-		long limit;
-		
-		public LimitedIterable(ObjectIterable iterable, long limit) {
-			this.iterable = iterable;
-			this.limit = limit;
-		}
-		
-		@Override
-		public ObjectIterator iterator() {
-			return ObjectIterators.limit(iterable.iterator(), limit);
-		}
-		
-		@Override
-		public int size() {
-			ISizeProvider prov = ISizeProvider.of(iterable);
-			return prov == null ? -1 : (int)Math.min(prov.size(), limit);
-		}
-		
-		public void forEach(Consumer action) {
-			Objects.requireNonNull(action);
-			AtomicLong counter = new AtomicLong();
-			iterable.forEach(T -> {
-				if(counter.get() >= limit) return;
-				counter.incrementAndGet();
-				action.accept(T);
-			});
-		}
-	}
-	
-	private static class SortedIterable implements ObjectIterable, ISizeProvider
-	{
-		ObjectIterable iterable;
-		Comparator sorter;
-		
-		public SortedIterable(ObjectIterable iterable, Comparator sorter) {
-			this.iterable = iterable;
-			this.sorter = sorter;
-		}
-		
-		@Override
-		public ObjectIterator iterator() {
-			return ObjectIterators.sorted(iterable.iterator(), sorter);
-		}
-		
-		@Override
-		public int size() {
-			ISizeProvider prov = ISizeProvider.of(iterable);
-			return prov == null ? -1 : prov.size();
-		}
-		
-		@Override
-		public void forEach(Consumer action) {
-			Objects.requireNonNull(action);
-			ObjectCollections.CollectionWrapper wrapper = ObjectCollections.wrapper();
-			iterable.forEach(wrapper::add);
-			wrapper.unstableSort(sorter);
-			wrapper.forEach(action);
-		}
-	}
-	
-	private static class DistinctIterable implements ObjectIterable
-	{
-		ObjectIterable iterable;
-		
-		public DistinctIterable(ObjectIterable iterable) {
-			this.iterable = iterable;
-		}
-		
-		@Override
-		public ObjectIterator iterator() {
-			return ObjectIterators.distinct(iterable.iterator());
-		}
-		
-		public void forEach(Consumer action) {
-			Objects.requireNonNull(action);
-			ObjectCollection filtered = ObjectCollections.distinctWrapper();
-			iterable.forEach(T -> { if(filtered.add(T)) action.accept(T); });
-		}
-	}
-	
-	private static class PeekIterable implements ObjectIterable, ISizeProvider
-	{
-		ObjectIterable iterable;
-		Consumer action;
-		
-		public PeekIterable(ObjectIterable iterable, Consumer action) {
-			this.iterable = iterable;
-			this.action = action;
-		}
-		
-		@Override
-		public ObjectIterator iterator() {
-			return ObjectIterators.peek(iterable.iterator(), action);
-		}
-		
-		@Override
-		public int size() {
-			ISizeProvider prov = ISizeProvider.of(iterable);
-			return prov == null ? -1 : prov.size();
-		}
-		
-		public void forEach(Consumer action) {
-			Objects.requireNonNull(action);
-			iterable.forEach(this.action.andThen(action));
-		}
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/utils/ObjectIterators.java b/src/main/java/speiger/src/collections/objects/utils/ObjectIterators.java
deleted file mode 100644
index 4c71ec876..000000000
--- a/src/main/java/speiger/src/collections/objects/utils/ObjectIterators.java
+++ /dev/null
@@ -1,1019 +0,0 @@
-package speiger.src.collections.objects.utils;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Comparator;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
-
-import speiger.src.collections.objects.collections.ObjectIterator;
-import speiger.src.collections.objects.functions.function.UnaryOperator;
-import speiger.src.collections.objects.lists.ObjectList;
-import speiger.src.collections.objects.lists.ObjectArrayList;
-
-import speiger.src.collections.objects.lists.ObjectListIterator;
-import speiger.src.collections.objects.collections.ObjectBidirectionalIterator;
-import speiger.src.collections.objects.collections.ObjectCollection;
-
-/**
- * A Helper class for Iterators
- */
-public class ObjectIterators
-{
-	/**
-	 * Empty Iterator Reference
-	 */
-	private static final EmptyIterator EMPTY = new EmptyIterator<>();
-	
-	/**
-	 * Returns a Immutable EmptyIterator instance that is automatically casted.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return an empty iterator
-	 */
-	public static  EmptyIterator empty() {
-		return (EmptyIterator)EMPTY;
-	}
-	
-	/**
-	 * Inverter function for Bidirectional Iterators
-	 * @param it the iterator that should be inverted
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a Inverted Bidirectional Iterator. If it was inverted then it just gives back the original reference
-	 */
-	public static  ObjectBidirectionalIterator invert(ObjectBidirectionalIterator it) {
-		return it instanceof ReverseBiIterator ? ((ReverseBiIterator)it).it : new ReverseBiIterator<>(it);
-	}
-	
-	/**
-	 * Inverter function for List Iterators
-	 * @param it the iterator that should be inverted
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a Inverted List Iterator. If it was inverted then it just gives back the original reference
-	 */
-	public static  ObjectListIterator invert(ObjectListIterator it) {
-		return it instanceof ReverseListIterator ? ((ReverseListIterator)it).it : new ReverseListIterator<>(it);
-	}
-	
-	/**
-	 * Returns a Immutable Iterator instance based on the instance given.
-	 * @param iterator that should be made immutable/unmodifiable
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself.
-	 */
-	public static  ObjectIterator unmodifiable(ObjectIterator iterator) {
-		return iterator instanceof UnmodifiableIterator ? iterator : new UnmodifiableIterator<>(iterator);
-	}
-	
-	/**
-	 * Returns a Immutable Iterator instance based on the instance given.
-	 * @param iterator that should be made immutable/unmodifiable
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a unmodifiable iterator wrapper. If the Iterator already a unmodifiable wrapper then it just returns itself.
-	 */
-	public static  ObjectBidirectionalIterator unmodifiable(ObjectBidirectionalIterator iterator) {
-		return iterator instanceof UnmodifiableBiIterator ? iterator : new UnmodifiableBiIterator<>(iterator);
-	}
-	
-	/**
-	 * Returns a Immutable ListIterator instance based on the instance given.
-	 * @param iterator that should be made immutable/unmodifiable
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a unmodifiable listiterator wrapper. If the ListIterator already a unmodifiable wrapper then it just returns itself.
-	 */
-	public static  ObjectListIterator unmodifiable(ObjectListIterator iterator) {
-		return iterator instanceof UnmodifiableListIterator ? iterator : new UnmodifiableListIterator<>(iterator);
-	}
-	
-	/**
-	 * A Helper function that maps a Java-Iterator into a new Type.
-	 * @param iterator that should be mapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type.
-	 * @return a iterator that is mapped to a new result
-	 */
-	public static  ObjectIterator map(Iterator iterator, UnaryOperator mapper) {
-		return new MappedIterator<>(wrap(iterator), mapper);
-	}
-	
-	/**
-	 * A Helper function that maps a Iterator into a new Type.
-	 * @param iterator that should be mapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type.
-	 * @return a iterator that is mapped to a new result
-	 */
-	public static  ObjectIterator map(ObjectIterator iterator, UnaryOperator mapper) {
-		return new MappedIterator<>(iterator, mapper);
-	}
-	
-	/**
-	 * A Helper function that flatMaps a Java-Iterator into a new Type.
-	 * @param iterator that should be flatMapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type supplier.
-	 * @param  The return type.
-	 * @return a iterator that is flatMapped to a new result
-	 */
-	public static > ObjectIterator flatMap(Iterator iterator, UnaryOperator mapper) {
-		return new FlatMappedIterator<>(wrap(iterator), mapper);
-	}
-	
-	/**
-	 * A Helper function that flatMaps a Iterator into a new Type.
-	 * @param iterator that should be flatMapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type supplier.
-	 * @param  The return type.
-	 * @return a iterator that is flatMapped to a new result
-	 */
-	public static > ObjectIterator flatMap(ObjectIterator iterator, UnaryOperator mapper) {
-		return new FlatMappedIterator<>(iterator, mapper);
-	}
-	
-	/**
-	 * A Helper function that flatMaps a Java-Iterator into a new Type.
-	 * @param iterator that should be flatMapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type.
-	 * @return a iterator that is flatMapped to a new result
-	 */
-	public static  ObjectIterator arrayFlatMap(Iterator iterator, UnaryOperator mapper) {
-		return new FlatMappedArrayIterator<>(wrap(iterator), mapper);
-	}
-	
-	/**
-	 * A Helper function that flatMaps a Iterator into a new Type.
-	 * @param iterator that should be flatMapped
-	 * @param mapper the function that decides what the result turns into.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @param  The return type.
-	 * @return a iterator that is flatMapped to a new result
-	 */
-	public static  ObjectIterator arrayFlatMap(ObjectIterator iterator, UnaryOperator mapper) {
-		return new FlatMappedArrayIterator<>(iterator, mapper);
-	}
-	
-	/**
-	 * A Helper function that filters out all desired elements from a Java-Iterator
-	 * @param iterator that should be filtered.
-	 * @param filter the filter that decides that should be let through
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a filtered iterator
-	 */
-	public static  ObjectIterator filter(Iterator iterator, Predicate filter) {
-		return new FilteredIterator<>(wrap(iterator), filter);
-	}
-	
-	/**
-	 * A Helper function that filters out all desired elements
-	 * @param iterator that should be filtered.
-	 * @param filter the filter that decides that should be let through
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a filtered iterator
-	 */
-	public static  ObjectIterator filter(ObjectIterator iterator, Predicate filter) {
-		return new FilteredIterator<>(iterator, filter);
-	}
-	
-	/**
-	 * A Helper function that filters out all duplicated elements.
-	 * @param iterator that should be distinct
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a distinct iterator
-	 */
-	public static  ObjectIterator distinct(ObjectIterator iterator) {
-		return new DistinctIterator<>(iterator);
-	}
-	
-	/**
-	 * A Helper function that filters out all duplicated elements from a Java Iterator.
-	 * @param iterator that should be distinct
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a distinct iterator
-	 */
-	public static  ObjectIterator distinct(Iterator iterator) {
-		return new DistinctIterator<>(wrap(iterator));
-	}
-	
-	/**
-	 * A Helper function that repeats the Iterator a specific amount of times
-	 * @param iterator that should be repeated
-	 * @param repeats the amount of times the iterator should be repeated
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a repeating iterator
-	 */
-	public static  ObjectIterator repeat(ObjectIterator iterator, int repeats) {
-		return new RepeatingIterator<>(iterator, repeats);
-	}
-	
-	/**
-	 * A Helper function that repeats the Iterator a specific amount of times from a Java Iterator
-	 * @param iterator that should be repeated
-	 * @param repeats the amount of times the iterator should be repeated
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a repeating iterator
-	 */
-	public static  ObjectIterator repeat(Iterator iterator, int repeats) {
-		return new RepeatingIterator<>(wrap(iterator), repeats);
-	}
-	
-	/**
-	 * A Helper function that hard limits the Iterator to a specific size
-	 * @param iterator that should be limited
-	 * @param limit the amount of elements it should be limited to
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a limited iterator
-	 */
-	public static  ObjectIterator limit(ObjectIterator iterator, long limit) {
-		return new LimitedIterator<>(iterator, limit);
-	}
-	
-	/**
-	 * A Helper function that hard limits the Iterator to a specific size from a Java Iterator
-	 * @param iterator that should be limited
-	 * @param limit the amount of elements it should be limited to
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a limited iterator
-	 */
-	public static  ObjectIterator limit(Iterator iterator, long limit) {
-		return new LimitedIterator<>(wrap(iterator), limit);
-	}
-	
-	/**
-	 * A Helper function that sorts the Iterator beforehand.
-	 * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it.
-	 * @param iterator that should be sorted.
-	 * @param sorter the sorter of the iterator. Can be null.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a new sorted iterator
-	 */
-	public static  ObjectIterator sorted(ObjectIterator iterator, Comparator sorter) {
-		return new SortedIterator<>(iterator, sorter);
-	}
-	
-	/**
-	 * A Helper function that sorts the Iterator beforehand from a Java Iterator.
-	 * This operation is heavily hurting performance because it rebuilds the entire iterator and then sorts it.
-	 * @param iterator that should be sorted.
-	 * @param sorter the sorter of the iterator. Can be null.
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a new sorted iterator
-	 */
-	public static  ObjectIterator sorted(Iterator iterator, Comparator sorter) {
-		return new SortedIterator<>(wrap(iterator), sorter);
-	}
-	
-	/**
-	 * A Helper function that allows to preview the result of a Iterator.
-	 * @param iterator that should be peeked at
-	 * @param action callback that receives the value before the iterator returns it
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a peeked iterator
-	 */
-	public static  ObjectIterator peek(ObjectIterator iterator, Consumer action) {
-		return new PeekIterator<>(iterator, action);
-	}
-	
-	/**
-	 * A Helper function that allows to preview the result of a Iterator  from a Java Iterator
-	 * @param iterator that should be peeked at
-	 * @param action callback that receives the value before the iterator returns it
-	 * @param  the keyType of elements maintained by this Collection
-	 * @return a peeked iterator
-	 */
-	public static  ObjectIterator peek(Iterator iterator, Consumer action) {
-		return new PeekIterator<>(wrap(iterator), action);
-	}
-	
-	/**
-	 * Helper function to convert a Object Iterator into a Primitive Iterator
-	 * @param iterator that should be converted to a unboxing iterator
-	 * @param  the keyType of array that the operation should be applied
-	 * @return a primitive iterator
-	 */
-	public static  ObjectIterator wrap(Iterator iterator) {
-		return iterator instanceof ObjectIterator ? (ObjectIterator)iterator : new IteratorWrapper<>(iterator);
-	}
-	
-	/**
-	 * Returns a Array Wrapping iterator
-	 * @param a the array that should be wrapped
-	 * @param  the keyType of array that the operation should be applied
-	 * @return a Iterator that is wrapping a array.
-	 */
-	public static  ArrayIterator wrap(T... a) {
-		return wrap(a, 0, a.length);
-	}
-	
-	/**
-	 * Returns a Array Wrapping iterator
-	 * @param a the array that should be wrapped.
-	 * @param start the index to be started from.
-	 * @param end the index that should be ended.
-	 * @param  the keyType of array that the operation should be applied
-	 * @return a Iterator that is wrapping a array.
-	 */
-	public static  ArrayIterator wrap(T[] a, int start, int end) {
-		return new ArrayIterator<>(a, start, end);
-	}
-	
-	/**
-	 * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted
-	 * @param a where the elements should be inserted
-	 * @param i the source iterator
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the amount of elements that were inserted into the array.
-	 */
-	public static  int unwrap(T[] a, Iterator i) {
-		return unwrap(a, i, 0, a.length);
-	}
-	
-	/**
-	 * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted
-	 * @param a where the elements should be inserted
-	 * @param i the source iterator
-	 * @param offset the array offset where the start should be
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the amount of elements that were inserted into the array.
-	 */
-	public static  int unwrap(T[] a, Iterator i, int offset) {
-		return unwrap(a, i, offset, a.length - offset);
-	}
-	
-	/**
-	 * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted
-	 * @param a where the elements should be inserted
-	 * @param i the source iterator
-	 * @param offset the array offset where the start should be
-	 * @param max the maximum values that should be extracted from the source
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the amount of elements that were inserted into the array.
-	 * @throws IllegalStateException if max is smaller the 0 or if the maximum index is larger then the array
-	 */
-	public static  int unwrap(T[] a, Iterator i, int offset, int max) {
-		if(max < 0) throw new IllegalStateException("The max size is smaller then 0");
-		if(offset + max > a.length) throw new IllegalStateException("largest array index exceeds array size");
-		int index = 0;
-		for(;index the keyType of array that the operation should be applied
-	 * @return the amount of elements that were inserted into the array.
-	 */
-	public static  int unwrap(T[] a, ObjectIterator i) {
-		return unwrap(a, i, 0, a.length);
-	}
-	
-	/**
-	 * A Primitive iterator variant of the ObjectIterators unwrap function
-	 * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted
-	 * @param a where the elements should be inserted
-	 * @param i the source iterator
-	 * @param offset the array offset where the start should be
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the amount of elements that were inserted into the array.
-	 */
-	public static  int unwrap(T[] a, ObjectIterator i, int offset) {
-		return unwrap(a, i, offset, a.length - offset);
-	}
-	
-	/**
-	 * A Primitive iterator variant of the ObjectIterators unwrap function
-	 * Iterates over a iterator and inserts the values into the array and returns the amount that was inserted
-	 * @param a where the elements should be inserted
-	 * @param i the source iterator
-	 * @param offset the array offset where the start should be
-	 * @param max the maximum values that should be extracted from the source
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the amount of elements that were inserted into the array.
-	 * @throws IllegalStateException if max is smaller the 0 or if the maximum index is larger then the array
-	 */
-	public static  int unwrap(T[] a, ObjectIterator i, int offset, int max) {
-		if(max < 0) throw new IllegalStateException("The max size is smaller then 0");
-		if(offset + max > a.length) throw new IllegalStateException("largest array index exceeds array size");
-		int index = 0;
-		for(;index the keyType of array that the operation should be applied
-	 * @return A list of all elements of the Iterator
-	 */
-	public static  ObjectList pour(ObjectIterator iter) {
-		return pour(iter, Integer.MAX_VALUE);
-	}
-	
-	/**
-	 * A Helper function to pours all elements of a Iterator into a List
-	 * @param iter the elements that should be poured into list.
-	 * @param max the maximum amount of elements that should be collected
-	 * @param  the keyType of array that the operation should be applied
-	 * @return A list of all requested elements of the Iterator
-	 */
-	public static  ObjectList pour(ObjectIterator iter, int max) {
-		ObjectArrayList list = new ObjectArrayList<>();
-		pour(iter, list, max);
-		list.trim();
-		return list;
-	}
-	
-	/**
-	 * A Helper function to pours all elements of a Iterator into a Collection
-	 * @param iter the elements that should be poured into list.
-	 * @param c the collection where the elements should be poured into
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the amount of elements that were added
-	 */
-	public static  int pour(ObjectIterator iter, ObjectCollection c) {
-		return pour(iter, c, Integer.MAX_VALUE);
-	}
-	
-	/**
-	 * A Helper function to pours all elements of a Iterator into a Collection
-	 * @param iter the elements that should be poured into list.
-	 * @param c the collection where the elements should be poured into
-	 * @param max the maximum amount of elements that should be collected
-	 * @param  the keyType of array that the operation should be applied
-	 * @return the amount of elements that were added
-	 */
-	public static  int pour(ObjectIterator iter, ObjectCollection c, int max) {
-		if(max < 0) throw new IllegalStateException("Max is negative");
-		int done = 0;
-		for(;done the keyType of array that the operation should be applied
-	 * @return iterator of the inputted iterators
-	 */
-	public static  ObjectIterator concat(ObjectIterator... array) {
-		return concat(array, 0, array.length);
-	}
-	
-	/**
-	 * Helper Iterator that concats other iterators together
-	 * @param array the Iterators that should be concatenated
-	 * @param offset where to start within the array
-	 * @param length the length of the array
-	 * @param  the keyType of array that the operation should be applied
-	 * @return iterator of the inputted iterators
-	 */
-	public static  ObjectIterator concat(ObjectIterator[] array, int offset, int length) {
-		return new ConcatIterator<>(array, offset, length);
-	}
-	
-	private static class IteratorWrapper implements ObjectIterator
-	{
-		Iterator iter;
-		
-		public IteratorWrapper(Iterator iter) {
-			this.iter = iter;
-		}
-		
-		@Override
-		public boolean hasNext() {
-			return iter.hasNext();
-		}
-		
-		@Override
-		public T next() {
-			return iter.next();
-		}
-		
-	}
-	
-	private static class ConcatIterator implements ObjectIterator
-	{
-		ObjectIterator[] iters;
-		int offset;
-		int lastOffset = -1;
-		int length;
-		
-		public ConcatIterator(ObjectIterator[] iters, int offset, int length) {
-			this.iters = iters;
-			this.offset = offset;
-			this.length = length;
-			find();
-		}
-		
-		private void find() {
-			for(;length != 0 && !iters[offset].hasNext();length--, offset++);
-		}
-		
-		@Override
-		public boolean hasNext() {
-			return length > 0;
-		}
-		
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			T result = iters[lastOffset = offset].next();
-			find();
-			return result;
-		}
-		
-		@Override
-		public void remove() {
-			if(lastOffset == -1) throw new IllegalStateException();
-			iters[lastOffset].remove();
-			lastOffset = -1;
-		}
-	}
-	
-	private static class ReverseBiIterator implements ObjectBidirectionalIterator {
-		ObjectBidirectionalIterator it;
-		
-		ReverseBiIterator(ObjectBidirectionalIterator it) {
-			this.it = it;
-		}
-		
-		@Override
-		public T next() { return it.previous(); }
-		@Override
-		public boolean hasNext() { return it.hasPrevious(); }
-		@Override
-		public boolean hasPrevious() { return it.hasNext(); }
-		@Override
-		public T previous() { return it.next(); }
-		@Override
-		public void remove() { it.remove(); }
-	}
-	
-	private static class ReverseListIterator implements ObjectListIterator {
-		ObjectListIterator it;
-		
-		ReverseListIterator(ObjectListIterator it) {
-			this.it = it;
-		}
-	
-		@Override
-		public T next() { return it.previous(); }
-		@Override
-		public boolean hasNext() { return it.hasPrevious(); }
-		@Override
-		public boolean hasPrevious() { return it.hasNext(); }
-		@Override
-		public T previous() { return it.next(); }
-		@Override
-		public void remove() { it.remove(); }
-		@Override
-		public int nextIndex() { return it.previousIndex(); }
-		@Override
-		public int previousIndex() { return it.nextIndex(); }
-		@Override
-		public void set(T e) { it.set(e); }
-		@Override
-		public void add(T e) { it.add(e); }
-	}
-	
-	private static class UnmodifiableListIterator implements ObjectListIterator
-	{
-		ObjectListIterator iter;
-	
-		UnmodifiableListIterator(ObjectListIterator iter) {
-			this.iter = iter;
-		}
-		
-		@Override
-		public boolean hasNext() {
-			return iter.hasNext();
-		}
-		
-		@Override
-		public boolean hasPrevious() {
-			return iter.hasPrevious();
-		}
-		
-		@Override
-		public int nextIndex() {
-			return iter.nextIndex();
-		}
-		
-		@Override
-		public int previousIndex() {
-			return iter.previousIndex();
-		}
-		
-		@Override
-		public void remove() { throw new UnsupportedOperationException(); }
-		
-		@Override
-		public T previous() {
-			return iter.previous();
-		}
-		
-		@Override
-		public T next() {
-			return iter.next();
-		}
-
-		@Override
-		public void set(T e) { throw new UnsupportedOperationException(); }
-		
-		@Override
-		public void add(T e) { throw new UnsupportedOperationException(); }
-	}
-	
-	private static class UnmodifiableBiIterator implements ObjectBidirectionalIterator
-	{
-		ObjectBidirectionalIterator iter;
-		
-		UnmodifiableBiIterator(ObjectBidirectionalIterator iter) {
-			this.iter = iter;
-		}
-		
-		@Override
-		public T next() {
-			return iter.next();
-		}
-		
-		@Override
-		public boolean hasNext() {
-			return iter.hasNext();
-		}
-		
-		@Override
-		public boolean hasPrevious() {
-			return iter.hasPrevious();
-		}
-		
-		@Override
-		public T previous() {
-			return iter.previous();
-		}
-	}
-	
-	private static class UnmodifiableIterator implements ObjectIterator
-	{
-		ObjectIterator iterator;
-	
-		UnmodifiableIterator(ObjectIterator iterator) {
-			this.iterator = iterator;
-		}
-		
-		@Override
-		public boolean hasNext() {
-			return iterator.hasNext();
-		}
-		
-		@Override
-		public T next() {
-			return iterator.next();
-		}
-	}
-	
-	private static class EmptyIterator implements ObjectListIterator
-	{
-		@Override
-		public boolean hasNext() { return false; }
-		@Override
-		public T next() { throw new NoSuchElementException(); }
-		@Override
-		public boolean hasPrevious() { return false; }
-		@Override
-		public T previous() { throw new NoSuchElementException(); }
-		@Override
-		public int nextIndex() { return 0; }
-		@Override
-		public int previousIndex() { return -1; }
-		@Override
-		public void remove() { throw new UnsupportedOperationException(); }
-		@Override
-		public void set(T e) { throw new UnsupportedOperationException(); }
-		@Override
-		public void add(T e) { throw new UnsupportedOperationException(); }
-	}
-	
-	private static class ArrayIterator implements ObjectIterator
-	{
-		T[] a;
-		int from;
-		int to;
-		
-		ArrayIterator(T[] a, int from, int to) {
-			this.a = a;
-			this.from = from;
-			this.to = to;
-		}
-		
-		@Override
-		public boolean hasNext() {
-			return from < to;
-		}
-		
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			return a[from++];
-		}
-		
-		@Override
-		public int skip(int amount) {
-			if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed");
-			int left = Math.min(amount, to - from);
-			from += left;
-			return amount - left;
-		}
-	}
-	
-	private static class MappedIterator implements ObjectIterator
-	{
-		ObjectIterator iterator;
-		UnaryOperator mapper;
-		
-		MappedIterator(ObjectIterator iterator, UnaryOperator mapper) {
-			this.iterator = iterator;
-			this.mapper = mapper;
-		}
-		
-		@Override
-		public boolean hasNext() {
-			return iterator.hasNext();
-		}
-		
-		@Override
-		public T next() {
-			return mapper.apply(iterator.next());
-		}
-		
-		@Override
-		public int skip(int amount) {
-			return iterator.skip(amount);
-		}
-	}
-	
-	private static class FlatMappedIterator> implements ObjectIterator
-	{
-		ObjectIterator iterator;
-		Iterator last = null;
-		UnaryOperator mapper;
-		boolean foundNext = false;
-		
-		FlatMappedIterator(ObjectIterator iterator, UnaryOperator mapper) {
-			this.iterator = iterator;
-			this.mapper = mapper;
-		}
-		
-		void compute() {
-			if(foundNext) return;
-			foundNext = true;
-			while(iterator.hasNext()) {
-				if(last != null && last.hasNext()) return;
-				last = mapper.apply(iterator.next()).iterator();
-			}
-		}
-		
-		@Override
-		public boolean hasNext() {
-			compute();
-			return last != null && last.hasNext();
-		}
-		
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			T result = last.next();
-			foundNext = false;
-			return result;
-		}
-	}
-	
-	private static class FlatMappedArrayIterator implements ObjectIterator
-	{
-		ObjectIterator iterator;
-		Iterator last = null;
-		UnaryOperator mapper;
-		boolean foundNext = false;
-		
-		FlatMappedArrayIterator(ObjectIterator iterator, UnaryOperator mapper) {
-			this.iterator = iterator;
-			this.mapper = mapper;
-		}
-		
-		void compute() {
-			if(foundNext) return;
-			foundNext = true;
-			while(iterator.hasNext()) {
-				if(last != null && last.hasNext()) return;
-				last = ObjectIterators.wrap(mapper.apply(iterator.next()));
-			}
-		}
-		
-		@Override
-		public boolean hasNext() {
-			compute();
-			return last != null && last.hasNext();
-		}
-		
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			T result = last.next();
-			foundNext = false;
-			return result;
-		}
-	}
-	
-	private static class RepeatingIterator implements ObjectIterator
-	{
-		final int repeats;
-		int index = 0;
-		ObjectIterator iter;
-		ObjectCollection repeater = ObjectCollections.wrapper();
-		
-		public RepeatingIterator(ObjectIterator iter, int repeat) {
-			this.iter = iter;
-			this.repeats = repeat;
-		}
-		
-		@Override
-		public boolean hasNext() {
-			if(iter.hasNext()) return true;
-			if(index < repeats) {
-				index++;
-				iter = repeater.iterator();
-				return iter.hasNext();
-			}
-			return false;
-		}
-
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			T value = iter.next();
-			if(index == 0) repeater.add(value);
-			return value;
-		}
-	}
-	
-	private static class SortedIterator implements ObjectIterator
-	{
-		ObjectIterator iterator;
-		Comparator sorter;
-		ObjectCollections.CollectionWrapper sortedElements = null;
-		int index = 0;
-		
-		public SortedIterator(ObjectIterator iterator, Comparator sorter) {
-			this.iterator = iterator;
-			this.sorter = sorter;
-		}
-		
-		@Override
-		public boolean hasNext() {
-			if(sortedElements == null) {
-				boolean hasNext = iterator.hasNext();
-				if(hasNext) {
-					sortedElements = ObjectCollections.wrapper();
-					pour(iterator, sortedElements);
-				}
-				else sortedElements = ObjectCollections.wrapper();
-				if(hasNext) sortedElements.unstableSort(sorter);
-			}
-			return index < sortedElements.size();
-		}
-		
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			return sortedElements.get(index++);
-		}
-	}
-	
-	private static class DistinctIterator implements ObjectIterator
-	{
-		ObjectIterator iterator;
-		ObjectCollection filtered = ObjectCollections.distinctWrapper();
-		T lastFound;
-		boolean foundNext = false;
-		
-		public DistinctIterator(ObjectIterator iterator) {
-			this.iterator = iterator;
-		}
-		
-		void compute() {
-			if(foundNext) return;
-			while(iterator.hasNext()) {
-				lastFound = iterator.next();
-				if(filtered.add(lastFound)) {
-					foundNext = true;
-					break;
-				}
-			}
-		}
-		
-		@Override
-		public boolean hasNext() {
-			compute();
-			return foundNext;
-		}
-		
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			foundNext = false;
-			return lastFound;
-		}
-	}
-	
-	private static class FilteredIterator implements ObjectIterator
-	{
-		ObjectIterator iterator;
-		Predicate filter;
-		T lastFound;
-		boolean foundNext = false;
-		
-		public FilteredIterator(ObjectIterator iterator, Predicate filter) {
-			this.iterator = iterator;
-			this.filter = filter;
-		}
-		
-		void compute() {
-			if(foundNext) return;
-			while(iterator.hasNext()) {
-				lastFound = iterator.next();
-				if(filter.test(lastFound)) {
-					foundNext = true;
-					break;
-				}
-			}
-		}
-		
-		@Override
-		public boolean hasNext() {
-			compute();
-			return foundNext;
-		}
-		
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			foundNext = false;
-			return lastFound;
-		}
-	}
-	
-	private static class LimitedIterator implements ObjectIterator
-	{
-		ObjectIterator iterator;
-		long limit;
-		
-		public LimitedIterator(ObjectIterator iterator, long limit) {
-			this.iterator = iterator;
-			this.limit = limit;
-		}
-		
-		@Override
-		public boolean hasNext() {
-			return limit > 0 && iterator.hasNext();
-		}
-		
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			limit--;
-			return iterator.next();
-		}
-	}
-	
-	private static class PeekIterator implements ObjectIterator
-	{
-		ObjectIterator iterator;
-		Consumer action;
-		
-		public PeekIterator(ObjectIterator iterator, Consumer action) {
-			this.iterator = iterator;
-			this.action = action;
-		}
-		
-		@Override
-		public boolean hasNext() {
-			return iterator.hasNext();
-		}
-		
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			T result = iterator.next();
-			action.accept(result);
-			return result;
-		}
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/objects/utils/ObjectSplititerators.java b/src/main/java/speiger/src/collections/objects/utils/ObjectSplititerators.java
deleted file mode 100644
index cd12f4940..000000000
--- a/src/main/java/speiger/src/collections/objects/utils/ObjectSplititerators.java
+++ /dev/null
@@ -1,242 +0,0 @@
-package speiger.src.collections.objects.utils;
-
-import java.util.Comparator;
-import java.util.NoSuchElementException;
-import java.util.Spliterator;
-import java.util.function.Consumer;
-
-import speiger.src.collections.objects.collections.ObjectCollection;
-import speiger.src.collections.objects.collections.ObjectIterator;
-import speiger.src.collections.objects.collections.ObjectSplititerator;
-import speiger.src.collections.utils.SanityChecks;
-
-/**
- * Helper class that provides SplitIterators for normal and stream usage
- */
-public class ObjectSplititerators
-{
-	/**
-	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
-	* @param array that should be wrapped into a split iterator
-	* @param characteristics characteristics properties of this spliterator's  source or elements.
-	* @param  the keyType of elements maintained by this Collection
-	* @return a Type Specific SplitIterator
-	*/
-	public static  ObjectSplititerator createArraySplititerator(T[] array, int characteristics) { return createArraySplititerator(array, 0, array.length, characteristics);}
-	/**
-	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
-	* @param array that should be wrapped into a split iterator
-	* @param size the maximum index within the array
-	* @param characteristics characteristics properties of this spliterator's  source or elements.
-	* @param  the keyType of elements maintained by this Collection
-	* @return a Type Specific SplitIterator
-	* @throws IllegalStateException if the size is outside of the array size
-	*/
-	public static  ObjectSplititerator createArraySplititerator(T[] array, int size, int characteristics) { return createArraySplititerator(array, 0, size, characteristics);}
-	/**
-	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
-	* @param array that should be wrapped into a split iterator
-	* @param offset the starting index of the array
-	* @param size the maximum index within the array
-	* @param characteristics characteristics properties of this spliterator's  source or elements.
-	* @param  the keyType of elements maintained by this Collection
-	* @return a Type Specific SplitIterator
-	* @throws IllegalStateException the offset and size are outside of the arrays range
-	*/
-	public static  ObjectSplititerator createArraySplititerator(T[] array, int offset, int size, int characteristics) {
-		SanityChecks.checkArrayCapacity(array.length, offset, size);
-		return new TypeArraySplitIterator<>(array, offset, size, characteristics);
-	}
-	
-	/**
-	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
-	* @param collection the collection that should be wrapped in a split iterator
-	* @param characteristics characteristics properties of this spliterator's  source or elements.
-	* @param  the keyType of elements maintained by this Collection
-	* @return a Type Specific SplitIterator
-	*/
-	public static  ObjectSplititerator createSplititerator(ObjectCollection collection, int characteristics) {
-		return new TypeIteratorSpliterator<>(collection, characteristics);
-	}
-	
-	/**
-	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
-	* @param iterator the Iterator that should be wrapped in a split iterator
-	* @param characteristics characteristics properties of this spliterator's source or elements.
-	* @param  the keyType of elements maintained by this Collection
-	* @return a Type Specific SplitIterator
-	*/
-	public static  ObjectSplititerator createUnknownSplititerator(ObjectIterator iterator, int characteristics) {
-		return new TypeIteratorSpliterator<>(iterator, characteristics);
-	}
-	
-	/**
-	* Creates a Type Specific SplitIterator to reduce boxing/unboxing
-	* @param iterator the collection that should be wrapped in a split iterator
-	* @param size the amount of elements in the iterator
-	* @param characteristics characteristics properties of this spliterator's  source or elements.
-	* @param  the keyType of elements maintained by this Collection
-	* @return a Type Specific SplitIterator
-	*/
-	public static  ObjectSplititerator createSizedSplititerator(ObjectIterator iterator, long size, int characteristics) {
-		return new TypeIteratorSpliterator<>(iterator, size, characteristics);
-	}
-	
-	static class TypeIteratorSpliterator implements ObjectSplititerator {
-		static final int BATCH_UNIT = 1 << 10;
-		static final int MAX_BATCH = 1 << 25;
-		private final ObjectCollection collection;
-		private ObjectIterator it;
-		private final int characteristics;
-		private long est;
-		private int batch;
-	
-		TypeIteratorSpliterator(ObjectCollection collection, int characteristics) {
-			this.collection = collection;
-			it = null;
-			this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
-								? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
-								: characteristics;
-		}
-	
-		TypeIteratorSpliterator(ObjectIterator iterator, long size, int characteristics) {
-			collection = null;
-			it = iterator;
-			est = size;
-			this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
-								? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
-								: characteristics;
-		}
-		
-		TypeIteratorSpliterator(ObjectIterator iterator, int characteristics) {
-			collection = null;
-			it = iterator;
-			est = Long.MAX_VALUE;
-			this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
-		}
-		
-		private ObjectIterator iterator()
-		{
-			if (it == null) {
-				it = collection.iterator();
-				est = collection.size();
-			}
-			return it;
-		}
-		
-		@Override
-		public ObjectSplititerator trySplit() {
-			ObjectIterator i = iterator();
-			if (est > 1 && i.hasNext()) {
-				int n = Math.min(batch + BATCH_UNIT, Math.min((int)est, MAX_BATCH));
-				T[] a = (T[])new Object[n];
-				int j = 0;
-				do { a[j] = i.next(); } while (++j < n && i.hasNext());
-				batch = j;
-				if (est != Long.MAX_VALUE)
-					est -= j;
-				return new TypeArraySplitIterator<>(a, 0, j, characteristics);
-			}
-			return null;
-		}
-		
-		@Override
-		public void forEachRemaining(Consumer action) {
-			if (action == null) throw new NullPointerException();
-			iterator().forEachRemaining(action);
-		}
-		
-		@Override
-		public boolean tryAdvance(Consumer action) {
-			if (action == null) throw new NullPointerException();
-			ObjectIterator iter = iterator();
-			if (iter.hasNext()) {
-				action.accept(iter.next());
-				return true;
-			}
-			return false;
-		}
-		
-		@Override
-		public long estimateSize() {
-			iterator();
-			return est;
-		}
-	
-		@Override
-		public int characteristics() { return characteristics; }
-		
-		@Override
-		public Comparator getComparator() {
-			if (hasCharacteristics(4)) //Sorted
-				return null;
-			throw new IllegalStateException();
-		}
-	
-		@Override
-		public T next() { return iterator().next(); }
-	
-		@Override
-		public boolean hasNext() { return iterator().hasNext(); }
-	}
-	
-	static final class TypeArraySplitIterator implements ObjectSplititerator {
-		private final T[] array;
-		private int index;
-		private final int fence; 
-		private final int characteristics;
-		
-		public TypeArraySplitIterator(T[] array, int origin, int fence, int additionalCharacteristics) {
-			this.array = array;
-			index = origin;
-			this.fence = fence;
-			characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
-		}
-		
-		@Override
-		public ObjectSplititerator trySplit() {
-			int lo = index, mid = (lo + fence) >>> 1;
-			return (lo >= mid) ? null : new TypeArraySplitIterator<>(array, lo, index = mid, characteristics);
-		}
-		
-		@Override
-		public void forEachRemaining(Consumer action) {
-			if (action == null) throw new NullPointerException();
-			T[] a; int i, hi;
-			if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) {
-				do { action.accept(a[i]); } while (++i < hi);
-			}
-		}
-		
-		@Override
-		public boolean tryAdvance(Consumer action) {
-			if (action == null) throw new NullPointerException();
-			if (index >= 0 && index < fence) {
-				action.accept(array[index++]);
-				return true;
-			}
-			return false;
-		}
-		
-		@Override
-		public long estimateSize() { return fence - index; }
-		@Override
-		public int characteristics() { return characteristics; }
-		@Override
-		public Comparator getComparator() {
-			if (hasCharacteristics(4)) //Sorted
-				return null;
-			throw new IllegalStateException();
-		}
-		
-		@Override
-		public T next() {
-			if(!hasNext()) throw new NoSuchElementException();
-			return array[index++];
-		}
-		
-		@Override
-		public boolean hasNext() { return index < fence; }
-	}
-	
-}
\ No newline at end of file
diff --git a/src/main/java/speiger/src/collections/shorts/functions/ShortComparator.java b/src/main/java/speiger/src/collections/shorts/functions/ShortComparator.java
deleted file mode 100644
index dfa237c3f..000000000
--- a/src/main/java/speiger/src/collections/shorts/functions/ShortComparator.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package speiger.src.collections.shorts.functions;
-
-import java.util.Comparator;
-import java.util.Objects;
-
-/**
- * Type-Specific Class for Comparator to reduce (un)boxing
- */
-public interface ShortComparator extends Comparator 
-{
-	/**
-	 * Type-Specific compare function to reduce (un)boxing
-	 * @param o1 the first object to be compared.
-	 * @param o2 the second object to be compared.
-	 * @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
-	 * @see Comparator#compare(Object, Object)
-	 */
-	int compare(short o1, short o2);
-	
-	/** {@inheritDoc}
-	 * 

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default int compare(Short o1, Short o2) { - return compare(o1.shortValue(), o2.shortValue()); - } - - /** - * A Wrapper function to convert a Non-Type-Specific Comparator to a Type-Specific-Comparator - * @param c comparator to convert - * @return the wrapper of the comparator - * @throws NullPointerException if the comparator is null - */ - public static ShortComparator of(Comparator c) { - Objects.requireNonNull(c); - return (K, V) -> c.compare(Short.valueOf(K), Short.valueOf(V)); - } - - @Override - public default ShortComparator reversed() { - return new Reversed(this); - } - - /** - * A Type Specific Reversed Comparator to reduce boxing/unboxing - */ - static class Reversed implements ShortComparator - { - ShortComparator original; - - /** - * default constructor - * @param original that is going to be reversed - */ - public Reversed(ShortComparator original) { - this.original = original; - } - - public int compare(short o1, short o2) { - return original.compare(o2, o1); - } - - @Override - public ShortComparator reversed() { - return original; - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/ShortConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/ShortConsumer.java deleted file mode 100644 index d43229902..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/ShortConsumer.java +++ /dev/null @@ -1,48 +0,0 @@ -package speiger.src.collections.shorts.functions; - -import java.util.Objects; -import java.util.function.Consumer; -/** - * Type-Specific Consumer interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -@FunctionalInterface -public interface ShortConsumer extends Consumer -{ - /** - * Type-Specific function to reduce (un)boxing. - * Performs this operation on the given argument. - * - * @param t the input argument - */ - void accept(short t); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced consumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ShortConsumer andThen(ShortConsumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(T);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Short t) { accept(t.shortValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ShortConsumer andThen(Consumer after) { - Objects.requireNonNull(after); - return T -> {accept(T); after.accept(Short.valueOf(T));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/ShortSupplier.java b/src/main/java/speiger/src/collections/shorts/functions/ShortSupplier.java deleted file mode 100644 index 23dc04d87..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/ShortSupplier.java +++ /dev/null @@ -1,12 +0,0 @@ -package speiger.src.collections.shorts.functions; - -/** - * Type-Specific Supplier interface that reduces (un)boxing and allows to merge other consumer types into this interface - */ -public interface ShortSupplier -{ - /** - * @return the supplied value - */ - public short getAsInt(); -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortBooleanConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortBooleanConsumer.java deleted file mode 100644 index 1fff26b27..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortBooleanConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.shorts.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ShortBooleanConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(short k, boolean v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ShortBooleanConsumer andThen(ShortBooleanConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Short k, Boolean v) { accept(k.shortValue(), v.booleanValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ShortBooleanConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Boolean.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortByteConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortByteConsumer.java deleted file mode 100644 index 692bf44ef..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortByteConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.shorts.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ShortByteConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(short k, byte v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ShortByteConsumer andThen(ShortByteConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Short k, Byte v) { accept(k.shortValue(), v.byteValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ShortByteConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Byte.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortCharConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortCharConsumer.java deleted file mode 100644 index c8b5f5a59..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortCharConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.shorts.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ShortCharConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(short k, char v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ShortCharConsumer andThen(ShortCharConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Short k, Character v) { accept(k.shortValue(), v.charValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ShortCharConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Character.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortDoubleConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortDoubleConsumer.java deleted file mode 100644 index bfde026df..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortDoubleConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.shorts.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ShortDoubleConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(short k, double v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ShortDoubleConsumer andThen(ShortDoubleConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Short k, Double v) { accept(k.shortValue(), v.doubleValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ShortDoubleConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Double.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortFloatConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortFloatConsumer.java deleted file mode 100644 index 5ee2a25ae..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortFloatConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.shorts.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ShortFloatConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(short k, float v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ShortFloatConsumer andThen(ShortFloatConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Short k, Float v) { accept(k.shortValue(), v.floatValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ShortFloatConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Float.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortIntConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortIntConsumer.java deleted file mode 100644 index 60879a58f..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortIntConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.shorts.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ShortIntConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(short k, int v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ShortIntConsumer andThen(ShortIntConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Short k, Integer v) { accept(k.shortValue(), v.intValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ShortIntConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Integer.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortLongConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortLongConsumer.java deleted file mode 100644 index 557d0922b..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortLongConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.shorts.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ShortLongConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(short k, long v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ShortLongConsumer andThen(ShortLongConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Short k, Long v) { accept(k.shortValue(), v.longValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ShortLongConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Long.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortObjectConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortObjectConsumer.java deleted file mode 100644 index a75fa69ac..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortObjectConsumer.java +++ /dev/null @@ -1,50 +0,0 @@ -package speiger.src.collections.shorts.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - * @param the keyType of elements maintained by this Collection - */ -public interface ShortObjectConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(short k, V v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ShortObjectConsumer andThen(ShortObjectConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Short k, V v) { accept(k.shortValue(), v); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ShortObjectConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), V);}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortShortConsumer.java b/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortShortConsumer.java deleted file mode 100644 index a89551445..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/consumer/ShortShortConsumer.java +++ /dev/null @@ -1,49 +0,0 @@ -package speiger.src.collections.shorts.functions.consumer; - -import java.util.Objects; -import java.util.function.BiConsumer; - -/** - * A Type Specific BiConsumer class to reduce boxing/unboxing and that fills the gaps that java has. - */ -public interface ShortShortConsumer extends BiConsumer -{ - /** - * A Type Specific operation method to reduce boxing/unboxing - * Performs this operation on the given arguments. - * - * @param k the first input argument - * @param v the second input argument - */ - void accept(short k, short v); - - /** - * Type Specific sequencing method to reduce boxing/unboxing. - * @param after a operation that should be performed afterwards - * @return a sequenced biconsumer that does 2 operations - * @throws NullPointerException if after is null - */ - public default ShortShortConsumer andThen(ShortShortConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(K, V);}; - } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default void accept(Short k, Short v) { accept(k.shortValue(), v.shortValue()); } - - /** {@inheritDoc} - *

This default implementation delegates to the corresponding type-specific function. - * @deprecated Please use the corresponding type-specific function instead. - */ - @Override - @Deprecated - default ShortShortConsumer andThen(BiConsumer after) { - Objects.requireNonNull(after); - return (K, V) -> {accept(K, V); after.accept(Short.valueOf(K), Short.valueOf(V));}; - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2ByteFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2ByteFunction.java deleted file mode 100644 index d1fc90e0c..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/Short2ByteFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Short2ByteFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public byte applyAsByte(short k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2CharFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2CharFunction.java deleted file mode 100644 index a0a56b4fc..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/Short2CharFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Short2CharFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public char applyAsChar(short k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2DoubleFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2DoubleFunction.java deleted file mode 100644 index 0418c9793..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/Short2DoubleFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Short2DoubleFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public double applyAsDouble(short k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2FloatFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2FloatFunction.java deleted file mode 100644 index c25f58373..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/Short2FloatFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Short2FloatFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public float applyAsFloat(short k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2IntFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2IntFunction.java deleted file mode 100644 index 84826457d..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/Short2IntFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Short2IntFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public int applyAsInt(short k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/Short2LongFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/Short2LongFunction.java deleted file mode 100644 index 47b227a1a..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/Short2LongFunction.java +++ /dev/null @@ -1,17 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface Short2LongFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public long applyAsLong(short k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortBooleanUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortBooleanUnaryOperator.java deleted file mode 100644 index a6c3220ab..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortBooleanUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ShortBooleanUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public boolean applyAsBoolean(short k, boolean v); - - @Override - public default Boolean apply(Short k, Boolean v) { return Boolean.valueOf(applyAsBoolean(k.shortValue(), v.booleanValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortByteUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortByteUnaryOperator.java deleted file mode 100644 index e12c739d9..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortByteUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ShortByteUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public byte applyAsByte(short k, byte v); - - @Override - public default Byte apply(Short k, Byte v) { return Byte.valueOf(applyAsByte(k.shortValue(), v.byteValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortCharUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortCharUnaryOperator.java deleted file mode 100644 index 0a5d1a286..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortCharUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ShortCharUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public char applyAsChar(short k, char v); - - @Override - public default Character apply(Short k, Character v) { return Character.valueOf(applyAsChar(k.shortValue(), v.charValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortDoubleUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortDoubleUnaryOperator.java deleted file mode 100644 index b3419fe04..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortDoubleUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ShortDoubleUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public double applyAsDouble(short k, double v); - - @Override - public default Double apply(Short k, Double v) { return Double.valueOf(applyAsDouble(k.shortValue(), v.doubleValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortFloatUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortFloatUnaryOperator.java deleted file mode 100644 index ef16ee0e0..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortFloatUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ShortFloatUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public float applyAsFloat(short k, float v); - - @Override - public default Float apply(Short k, Float v) { return Float.valueOf(applyAsFloat(k.shortValue(), v.floatValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortFunction.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortFunction.java deleted file mode 100644 index ce0291457..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - * @param the keyType of elements maintained by this Collection - */ -@FunctionalInterface -public interface ShortFunction -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public V apply(short k); - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortIntUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortIntUnaryOperator.java deleted file mode 100644 index 29a3485d4..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortIntUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ShortIntUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public int applyAsInt(short k, int v); - - @Override - public default Integer apply(Short k, Integer v) { return Integer.valueOf(applyAsInt(k.shortValue(), v.intValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortLongUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortLongUnaryOperator.java deleted file mode 100644 index 17fb01764..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortLongUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ShortLongUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public long applyAsLong(short k, long v); - - @Override - public default Long apply(Short k, Long v) { return Long.valueOf(applyAsLong(k.shortValue(), v.longValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortObjectUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortObjectUnaryOperator.java deleted file mode 100644 index a53ec6984..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortObjectUnaryOperator.java +++ /dev/null @@ -1,23 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - * @param the keyType of elements maintained by this Collection - */ -public interface ShortObjectUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public V apply(short k, V v); - - @Override - public default V apply(Short k, V v) { return apply(k.shortValue(), v); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortPredicate.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortPredicate.java deleted file mode 100644 index 26a64eba8..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortPredicate.java +++ /dev/null @@ -1,62 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface ShortPredicate -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public boolean test(short k); - - /** - * Creates a Always true function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static ShortPredicate alwaysTrue() { - return T -> true; - } - - /** - * Creates a Always false function that may be useful if you don't need to process information or just want a default. - * @return a default returning function - */ - public static ShortPredicate alwaysFalse() { - return T -> false; - } - - /** - * A Type specific and-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a and comparason - */ - public default ShortPredicate andType(ShortPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) && other.test(T); - } - - /** - * A type specific inverter function - * @return the same function but inverts the result - */ - public default ShortPredicate negate() { - return T -> !test(T); - } - - /** - * A Type specific or-function helper function that reduces boxing/unboxing - * @param other the other function that should be merged with. - * @return a function that compares values in a or comparason - */ - public default ShortPredicate orType(ShortPredicate other) { - Objects.requireNonNull(other); - return T -> test(T) || other.test(T); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortShortUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortShortUnaryOperator.java deleted file mode 100644 index fc9633fb5..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortShortUnaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - -import java.util.function.BiFunction; - -/** - * A Type Specific Unary Operator to support Compute/Merge functions with type specific methods to reduce boxing/unboxing - */ -public interface ShortShortUnaryOperator extends BiFunction -{ - /** - * A Type Specifc apply method to reduce boxing/unboxing. - * Applies this function to the given arguments. - * - * @param k the first function argument - * @param v the second function argument - * @return the function result - */ - public short applyAsShort(short k, short v); - - @Override - public default Short apply(Short k, Short v) { return Short.valueOf(applyAsShort(k.shortValue(), v.shortValue())); } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/shorts/functions/function/ShortUnaryOperator.java b/src/main/java/speiger/src/collections/shorts/functions/function/ShortUnaryOperator.java deleted file mode 100644 index 6a31fc66b..000000000 --- a/src/main/java/speiger/src/collections/shorts/functions/function/ShortUnaryOperator.java +++ /dev/null @@ -1,54 +0,0 @@ -package speiger.src.collections.shorts.functions.function; - -import java.util.Objects; - -/** - * A Type Specific Function interface that reduces boxing/unboxing and fills the gaps of interfaces that are missing. - */ -@FunctionalInterface -public interface ShortUnaryOperator -{ - /** - * Type Specific get function to reduce boxing/unboxing - * @param k the value that should be processed - * @return the result of the function - */ - public short applyAsShort(short k); - - /** - * Creates a Default function that returns the input provided. - * @return a input returning function - */ - public static ShortUnaryOperator identity() { - return T -> T; - } - - /** - * Returns a composed function that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param before the function that should be used first - * @return a composed function with a different starting function. - */ - public default ShortUnaryOperator compose(ShortUnaryOperator before) { - Objects.requireNonNull(before); - return T -> applyAsShort(before.applyAsShort(T)); - } - - /** - * Returns a composed function that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param after the function that should be used last - * @return a composed function with a different starting function. - */ - public default ShortUnaryOperator andThen(ShortUnaryOperator after) { - Objects.requireNonNull(after); - return T -> after.applyAsShort(applyAsShort(T)); - } - -} \ No newline at end of file diff --git a/src/main/java/speiger/src/collections/utils/HashUtil.java b/src/main/java/speiger/src/collections/utils/HashUtil.java deleted file mode 100644 index c2dd14363..000000000 --- a/src/main/java/speiger/src/collections/utils/HashUtil.java +++ /dev/null @@ -1,96 +0,0 @@ -package speiger.src.collections.utils; - -/** - * Helper class that is used for HashMap functions reduce duplicated code - */ -public class HashUtil -{ - /** Minimum HashMap Capacity */ - public static final int DEFAULT_MIN_CAPACITY = 16; - /** Minimum ConcurrentHashMap Concurrency */ - public static final int DEFAULT_MIN_CONCURRENCY = 4; - /** Default HashMap Load Factor */ - public static final float DEFAULT_LOAD_FACTOR = 0.75F; - /** HashMap Load Factor with reduced hash collisions but more memory usage */ - public static final float FAST_LOAD_FACTOR = 0.5F; - /** HashMap Load Factor with minimal hash collisions but more memory usage */ - public static final float FASTER_LOAD_FACTOR = 0.25F; - - /** 232 · φ, φ = (√5 − 1)/2. */ - private static final int INT_PHI = 0x9E3779B9; - /** The reciprocal of {@link #INT_PHI} modulo 232. */ - private static final int INV_INT_PHI = 0x144cbc89; - - /** Quickly mixes the bits of an integer. - * - *

This method mixes the bits of the argument by multiplying by the golden ratio and - * xorshifting the result. It is borrowed from Koloboke, - * - * @param x an integer. - * @return a hash value obtained by mixing the bits of {@code x}. - * @see #invMix(int) - */ - public static int mix(final int x) { - final int h = x * INT_PHI; - return h ^ (h >>> 16); - } - - /** The inverse of {@link #mix(int)}. This method is mainly useful to create unit tests. - * - * @param x an integer. - * @return a value that passed through {@link #mix(int)} would give {@code x}. - */ - public static int invMix(final int x) { - return (x ^ x >>> 16) * INV_INT_PHI; - } - - /** - * Function that rounds up to the closest power of 2 - * A modified version of https://stackoverflow.com/a/466242 - * @param x that should be converted to the next power of two - * @return the input number rounded up to the next power of two - */ - public static int nextPowerOfTwo(int x) { - return 1 << (32 - Integer.numberOfLeadingZeros(x - 1)); - } - - /** - * Function that rounds up to the closest power of 2 - * A modified version of https://stackoverflow.com/a/466242 - * @param x that should be converted to the next power of two - * @return the input number rounded up to the next power of two - */ - public static long nextPowerOfTwo(long x) { - return 1L << (64 - Long.numberOfLeadingZeros(x - 1)); - } - - /** - * Function that finds out how many bits are required to store the number Provided - * @param value to get the required bits to store. - * @return the required bits to store that number - * @note Really useful for compression. Reducing data that is inserted into a GZIP algorithm. - */ - public static int getRequiredBits(int value) { - return Integer.bitCount(nextPowerOfTwo(value+1)-1); - } - - /** - * Function that finds out how many bits are required to store the number Provided - * @param value to get the required bits to store. - * @return the required bits to store that number - * @note Really useful for compression. Reducing data that is inserted into a GZIP algorithm. - */ - public static int getRequiredBits(long value) { - return Long.bitCount(nextPowerOfTwo(value+1L)-1L); - } - - /** - * Helper function that creates the ideal array size for HashMap - * @param size the original array size - * @param loadFactor the load factor - * @return the new array size - */ - public static int arraySize(int size, float loadFactor) { - return (int)Math.min(1 << 30, Math.max(2, nextPowerOfTwo((long)Math.ceil(size / loadFactor)))); - } -} diff --git a/src/main/java/speiger/src/collections/utils/IArray.java b/src/main/java/speiger/src/collections/utils/IArray.java deleted file mode 100644 index 826e9bafd..000000000 --- a/src/main/java/speiger/src/collections/utils/IArray.java +++ /dev/null @@ -1,20 +0,0 @@ -package speiger.src.collections.utils; - -import java.util.RandomAccess; - -/** - * A Helper interface that allows to detect if the Underlying implementation is - * using a Array. This allows to read methods through synchronization layers. - * Also it implements {@link RandomAccess} and {@link ITrimmable} - */ -public interface IArray extends RandomAccess, ITrimmable -{ - /** - * Increases the capacity of this implementation instance, if necessary, - * to ensure that it can hold at least the number of elements specified by - * the minimum capacity argument. - * - * @param size the desired minimum capacity - */ - public void ensureCapacity(int size); -} diff --git a/src/main/java/speiger/src/collections/utils/ISizeProvider.java b/src/main/java/speiger/src/collections/utils/ISizeProvider.java deleted file mode 100644 index 0833ca3ac..000000000 --- a/src/main/java/speiger/src/collections/utils/ISizeProvider.java +++ /dev/null @@ -1,46 +0,0 @@ -package speiger.src.collections.utils; - -import java.util.Collection; - -/** - * @author Speiger - * - * This Interface is a Helper class to allow transfer the information through Iterators, without forcing a Implementation of a size method through it. - * This is mainly used to optimize the toArray function. - * - */ -public interface ISizeProvider -{ - /** @return the size of the implementing Collection */ - public int size(); - - /** - * Gets a SizeProvider given the Iterable. May return null if it isn't a Collection or a SizeProvider. - * @param iter the Iterable that you want the size of. - * @return a SizeProvider if it is one or if it is a JavaCollection - */ - public static ISizeProvider of(Iterable iter) { - if(iter instanceof ISizeProvider) return (ISizeProvider)iter; - if(iter instanceof Collection) return new CollectionSize((Collection)iter); - return null; - } - - /** - * Collection implementation of the SizeProvider - */ - static class CollectionSize implements ISizeProvider - { - Collection collection; - - public CollectionSize(Collection collection) - { - this.collection = collection; - } - - @Override - public int size() - { - return collection.size(); - } - } -} diff --git a/src/main/java/speiger/src/collections/utils/ITrimmable.java b/src/main/java/speiger/src/collections/utils/ITrimmable.java deleted file mode 100644 index 8026ee1bc..000000000 --- a/src/main/java/speiger/src/collections/utils/ITrimmable.java +++ /dev/null @@ -1,37 +0,0 @@ -package speiger.src.collections.utils; - -/** - * Interface that allows to test for if a collection is trimmable. - * This also allows that synchronization-wrappers are trimmable without extracting the original collection. - */ -public interface ITrimmable -{ - /** - * Trims the original collection down to the size of the current elements - * @return if the internal array has been trimmed. - */ - public default boolean trim() { - return trim(0); - } - - /** - * Trims the original collection down to the size of the current elements or the requested size depending which is bigger - * @param size the requested trim size. - * @return if the internal array has been trimmed. - */ - public boolean trim(int size); - - /** - * Trims the collection down to the original size and clears all present elements with it. - */ - public default void clearAndTrim() { - clearAndTrim(0); - } - - /** - * Trims the collection down to the requested size and clears all elements while doing so - * @param size the amount of elements that should be allowed - * @note this will enforce minimum size of the collection itself - */ - public void clearAndTrim(int size); -} diff --git a/src/main/java/speiger/src/collections/utils/SanityChecks.java b/src/main/java/speiger/src/collections/utils/SanityChecks.java deleted file mode 100644 index b19d48707..000000000 --- a/src/main/java/speiger/src/collections/utils/SanityChecks.java +++ /dev/null @@ -1,178 +0,0 @@ -package speiger.src.collections.utils; - -import java.util.Random; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.ForkJoinTask; - -/** - * Helper class that provides functions that are shared within the library. - * On top of that it provides some helper functions that allow control of some internals of the Library - */ -public class SanityChecks -{ - /** Max Possible ArraySize without the JVM Crashing */ - public static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; - private static ForkJoinPool WORK_POOL = ForkJoinPool.commonPool(); - private static boolean FORCE_IGNORE_PARALLELISM = false; - private static ThreadLocal RANDOM = ThreadLocal.withInitial(Random::new); - private static ThreadLocal FORCE_ASYNC = ThreadLocal.withInitial(() -> false); - private static ThreadLocal FORCE_TASK_POOL = ThreadLocal.withInitial(() -> false); - - /** - * Internal function to cast a Integer to a Byte - * @param value that should be turned into a byte - * @return the value as a byte - * @throws IllegalStateException if the value does not fit within a byte - */ - public static byte castToByte(int value) { - if(value > Byte.MAX_VALUE || value < Byte.MIN_VALUE) throw new IllegalStateException("Value ["+value+"] out of Byte[-128,127] range"); - return (byte)value; - } - - /** - * Internal function to cast a Integer to a Short - * @param value that should be turned into a short - * @return the value as a short - * @throws IllegalStateException if the value does not fit within a short - */ - public static short castToShort(int value) { - if(value > Short.MAX_VALUE || value < Short.MIN_VALUE) throw new IllegalStateException("Value ["+value+"] out of Short[-32768,32767] range"); - return (short)value; - } - - /** - * Internal function to cast a Integer to a Character - * @param value that should be turned into a char - * @return the value as a char - * @throws IllegalStateException if the value does not fit within a char - */ - public static char castToChar(int value) { - if(value > Character.MAX_VALUE || value < Character.MIN_VALUE) throw new IllegalStateException("Value ["+value+"] out of Character[0,65535] range"); - return (char)value; - } - - /** - * Internal function to cast a Double to a Double - * @param value that should be turned into a float - * @return the value as a float - * @throws IllegalStateException if the value does not fit within a float - */ - public static float castToFloat(double value) { - if(Double.isNaN(value)) return Float.NaN; - if(Double.isInfinite(value)) return value > 0 ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY; - if(value < -Float.MAX_VALUE || value > Float.MAX_VALUE) throw new IllegalStateException("Value ["+value+"] out of Float range"); - return (float)value; - } - - /** - * Internal function that checks if the given array-size is big enough for the access. - * @param arraySize the size of the Array - * @param offset the offset of the access - * @param accessSize the length of the access - * @throws IllegalStateException if offset or accessSize is negative or the range goes out of the array-size - */ - public static void checkArrayCapacity(int arraySize, int offset, int accessSize) { - if(offset < 0) throw new IndexOutOfBoundsException("Offset is negative ("+offset+")"); - else if(accessSize < 0) throw new IllegalArgumentException("Size is negative ("+accessSize+")"); - else if(arraySize < offset + accessSize) throw new IndexOutOfBoundsException("Index (" + (offset + accessSize) + ") is not in size (" + arraySize + ")"); - } - - /** - * Returns if the current thread-pool can handle Multi-threading tasks - * @return true if the thread-count is bigger the 1 - */ - public static boolean canParallelTask() { - return getPool().getParallelism() > 1 || FORCE_IGNORE_PARALLELISM; - } - - /** - * Helper method to start a ForkJoinTask. This method will await the finalization of said task - * @param task the Task to invoke - * @param the type of the task - */ - public static void invokeTask(ForkJoinTask task) { - if(FORCE_ASYNC.get().booleanValue()) invokeAsyncTask(task); - else getPool().invoke(task); - } - - /** - * Helper method to start a ForkJoinTask. This method will not await the finalization of said task - * @param task the Task to invoke - * @param the type of the task - */ - public static void invokeAsyncTask(ForkJoinTask task) { - getPool().execute(task); - } - - /** - * A Helper method to start a Async Task. This method will not await the finalization of said task - * @param task the Task to invoke - */ - public static void invokeAsyncTask(Runnable task) { - getPool().execute(task); - } - - /** - * Helper method to control what ForkJoinPool is being used for any given task. - * @note this method is not thread-save. It is only there to provide control over how Library specific Threaded tasks are handled. - * @param pool The ForkJoinPool that should receive the tasks. If null {@link ForkJoinPool#commonPool()} is set instead - */ - public static void setWorkPool(ForkJoinPool pool) { - WORK_POOL = pool == null ? ForkJoinPool.commonPool() : pool; - } - - private static ForkJoinPool getPool() { - if(FORCE_TASK_POOL.get().booleanValue()) { - ForkJoinPool pool = ForkJoinTask.getPool(); - if(pool != null) return pool; - } - return WORK_POOL; - } - - /** - * Helper method to detect if the Current Thread forces not to await task completion. - * @return if the Current Thread has not to await task completion. - */ - public static boolean isForcedAsync() { - return FORCE_ASYNC.get().booleanValue(); - } - - /** - * Helper method to detect if the current thread forces to execute tasks in the current Thread-pool if it is a ForkJoinPool. - * @return if the task checks the current pool to be executed in if it is valid. - */ - public static boolean isForcedTaskPool() { - return FORCE_TASK_POOL.get().booleanValue(); - } - - /** - * Helper method to decide if the current thread should forcefully not wait on tasks to be completed. - * @param value it tasks should not be awaited for - */ - public static void setForcedAsync(boolean value) { - FORCE_ASYNC.set(Boolean.valueOf(value)); - } - - /** - * Helper method to decide if it should be checked for if the current thread is a ThreadPool Worker (ForkJoinPool Worker to be specific) and if tasks should be delegated into it. - * @param value if the current thread should check if it is a ThreadPoolWorker. - */ - public static void setForcedTaskPool(boolean value) { - FORCE_TASK_POOL.set(Boolean.valueOf(value)); - } - - /** - * Helper method to decide if Parallelism should be checked or not. - * @param value if the Parallelism should be ignored - */ - public static void setForceIgnoreParallelism(boolean value) { - FORCE_IGNORE_PARALLELISM = value; - } - - /** - * @return Thread Specific Random needed for internal functions in this library. - */ - public static Random getRandom() { - return RANDOM.get(); - } -} diff --git a/src/main/java/speiger/src/collections/utils/Stack.java b/src/main/java/speiger/src/collections/utils/Stack.java deleted file mode 100644 index fa878c9c6..000000000 --- a/src/main/java/speiger/src/collections/utils/Stack.java +++ /dev/null @@ -1,62 +0,0 @@ -package speiger.src.collections.utils; - - -/** - * The Stack Interface represents the Last-In-First-Out layout (LIFO). - * It provides a simple {@link #push(Object)}, {@link #pop()} function, - * with a fast {@link #clear()} function. - * The {@link #peek(int)} function allows to view the contents of the stack (top to bottom). - * @param the type of elements maintained by this Collection - */ -public interface Stack -{ - /** - * Inserts a given Object on top of the stack - * @param e the Object to insert - */ - public void push(T e); - - /** - * Removes the Object on top of the stack. - * @return the element that is on top of the stack - * @throws ArrayIndexOutOfBoundsException if the stack is empty - */ - public T pop(); - - /** - * Provides the amount of elements currently in the stack - * @return amount of elements in the list - */ - public int size(); - - - /** - * @return if the stack is empty - */ - public default boolean isEmpty() { - return size() == 0; - } - - /** - * Clears the stack - */ - public void clear(); - - /** - * Provides the Object on top of the stack - * @return the element that is on top of the stack - * @throws ArrayIndexOutOfBoundsException if the stack is empty - */ - public default T top() { - return peek(0); - } - - /** - * Provides the Selected Object from the stack. - * Top to bottom - * @param index of the element that should be provided - * @return the element that was requested - * @throws ArrayIndexOutOfBoundsException if the index is out of bounds - */ - public T peek(int index); -} diff --git a/src/main/java/zone/rong/rongasm/api/RongReflector.java b/src/main/java/zone/rong/rongasm/api/RongReflector.java index 896a92f21..8c9aa0bec 100644 --- a/src/main/java/zone/rong/rongasm/api/RongReflector.java +++ b/src/main/java/zone/rong/rongasm/api/RongReflector.java @@ -9,7 +9,9 @@ import java.io.InputStream; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.lang.reflect.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.List; import java.util.Map; import java.util.Optional; diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index bad248d9b..19347c740 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -20,7 +20,7 @@ "id_miner", "daxnitro" ], - "credits": "Based on daxnitro's GLSL Shaders Mod.", + "credits": "Based on daxnitro's GLSL Shaders Mod. Includes backported code from Oculus and Iris", "logoFile": "", "screenshots": [], "parent": "", From 63380658ce0e9b23dabffd1e9d0e40d5192fbbbc Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 7 Oct 2023 14:12:11 -0700 Subject: [PATCH 007/301] First pass at Iris (doesn't yet compile) --- addon.gradle | 8 + dependencies.gradle | 1 + .../angelica/client/HFNoiseTexture.java | 15 +- .../angelica/client/Shaders.java | 11 +- .../gtnewhorizons/angelica/mixins/Mixins.java | 23 +- .../accessors/EntityRendererAccessor.java | 13 + .../early/accessors/MinecraftAccessor.java | 12 + .../accessors/SimpleTextureAccessor.java | 12 + .../accessors/TextureAtlasSpriteAccessor.java | 37 + .../renderer/MixinTextureAtlasSprite.java | 9 +- .../early/shaders/MixinGameSettings.java | 27 + .../early/shaders/MixinGuiMainMenu.java | 18 + .../early/shaders/MixinInitRenderer.java | 20 + .../textures/MixinTextureAtlasSprite.java | 17 + .../de/odysseus/ithaka/digraph/Digraph.java | 150 ++ .../ithaka/digraph/DigraphAdapter.java | 142 ++ .../ithaka/digraph/DigraphFactory.java | 30 + .../ithaka/digraph/DigraphProvider.java | 32 + .../de/odysseus/ithaka/digraph/Digraphs.java | 352 +++++ .../ithaka/digraph/DoubledDigraph.java | 40 + .../ithaka/digraph/DoubledDigraphAdapter.java | 214 +++ .../odysseus/ithaka/digraph/EdgeWeights.java | 43 + .../odysseus/ithaka/digraph/EmptyDigraph.java | 123 ++ .../odysseus/ithaka/digraph/MapDigraph.java | 433 ++++++ .../ithaka/digraph/TrivialDigraph.java | 253 ++++ .../ithaka/digraph/UnmodifiableDigraph.java | 71 + .../ithaka/digraph/io/dot/DotAttribute.java | 82 ++ .../ithaka/digraph/io/dot/DotExporter.java | 224 +++ .../ithaka/digraph/io/dot/DotProvider.java | 34 + .../ithaka/digraph/io/tgf/TgfExporter.java | 74 + .../digraph/io/tgf/TgfLabelProvider.java | 22 + .../fas/AbstractFeedbackArcSetProvider.java | 220 +++ .../digraph/util/fas/FeedbackArcSet.java | 63 + .../util/fas/FeedbackArcSetPolicy.java | 31 + .../util/fas/FeedbackArcSetProvider.java | 33 + .../fas/SimpleFeedbackArcSetProvider.java | 174 +++ .../element/AccessibleExpressionElement.java | 4 + .../kroppeb/stareval/element/Element.java | 4 + .../stareval/element/ExpressionElement.java | 4 + .../element/PriorityOperatorElement.java | 7 + .../element/token/BinaryOperatorToken.java | 16 + .../stareval/element/token/IdToken.java | 20 + .../stareval/element/token/NumberToken.java | 20 + .../kroppeb/stareval/element/token/Token.java | 8 + .../element/token/UnaryOperatorToken.java | 29 + .../element/tree/AccessExpressionElement.java | 26 + .../element/tree/BinaryExpressionElement.java | 33 + .../stareval/element/tree/FunctionCall.java | 28 + .../element/tree/UnaryExpressionElement.java | 27 + .../tree/partial/PartialBinaryExpression.java | 31 + .../tree/partial/PartialExpression.java | 8 + .../partial/UnfinishedArgsExpression.java | 15 + .../exception/MissingTokenException.java | 7 + .../stareval/exception/ParseException.java | 22 + .../UnexpectedCharacterException.java | 19 + .../exception/UnexpectedEndingException.java | 11 + .../exception/UnexpectedTokenException.java | 7 + .../kroppeb/stareval/parser/BinaryOp.java | 20 + .../kroppeb/stareval/parser/OpResolver.java | 157 ++ .../java/kroppeb/stareval/parser/Parser.java | 315 ++++ .../stareval/parser/ParserOptions.java | 119 ++ .../kroppeb/stareval/parser/StringReader.java | 138 ++ .../kroppeb/stareval/parser/Tokenizer.java | 107 ++ .../java/kroppeb/stareval/parser/UnaryOp.java | 14 + .../impl/BatchingDebugMessageHelper.java | 18 + .../impl/BlendingStateHolder.java | 5 + .../impl/BufferBuilderExt.java | 10 + .../impl/BufferSegment.java | 28 + .../impl/BufferSegmentRenderer.java | 30 + .../impl/DrawCallTrackingRenderBuffers.java | 7 + .../impl/FlushableMultiBufferSource.java | 6 + .../impl/FullyBufferedMultiBufferSource.java | 255 ++++ .../impl/Groupable.java | 7 + .../impl/MemoryTrackingBuffer.java | 6 + .../impl/MemoryTrackingRenderBuffers.java | 7 + .../OldFullyBufferedMultiBufferSource.java | 141 ++ .../impl/RenderBuffersExt.java | 6 + .../impl/RenderTypeUtil.java | 9 + .../impl/SegmentedBufferBuilder.java | 94 ++ .../impl/TransparencyType.java | 27 + .../impl/WrappableRenderType.java | 8 + .../GraphTranslucencyRenderOrderManager.java | 139 ++ .../impl/ordering/RenderOrderManager.java | 12 + .../ordering/SimpleRenderOrderManager.java | 38 + .../TranslucencyRenderOrderManager.java | 75 + .../wrappers/TaggingRenderTypeWrapper.java | 66 + src/main/java/net/coderbot/iris/Iris.java | 687 +++++++++ .../java/net/coderbot/iris/IrisLogging.java | 58 + .../net/coderbot/iris/JomlConversions.java | 15 + .../java/net/coderbot/iris/LaunchWarn.java | 43 + .../iris/apiimpl/IrisApiV0ConfigImpl.java | 33 + .../coderbot/iris/apiimpl/IrisApiV0Impl.java | 60 + .../block_rendering/BlockMaterialMapping.java | 136 ++ .../BlockRenderingSettings.java | 130 ++ .../coderbot/iris/compat/mojang/GLHelper.java | 18 + .../net/coderbot/iris/config/IrisConfig.java | 172 +++ .../fantastic/IrisParticleRenderTypes.java | 24 + .../fantastic/ParticleRenderingPhase.java | 7 + .../iris/fantastic/PhasedParticleEngine.java | 5 + .../fantastic/WrappingMultiBufferSource.java | 10 + .../coderbot/iris/features/FeatureFlags.java | 69 + .../matching/InputAvailability.java | 78 + .../matching/ProgramTable.java | 31 + .../matching/RenderCondition.java | 22 + .../matching/SpecialCondition.java | 7 + .../state/RenderTargetStateListener.java | 25 + .../gbuffer_overrides/state/StateTracker.java | 22 + .../java/net/coderbot/iris/gl/GLDebug.java | 262 ++++ .../java/net/coderbot/iris/gl/GlResource.java | 30 + .../java/net/coderbot/iris/gl/GlVersion.java | 8 + .../coderbot/iris/gl/IrisRenderSystem.java | 492 +++++++ .../coderbot/iris/gl/blending/AlphaTest.java | 19 + .../iris/gl/blending/AlphaTestFunction.java | 57 + .../iris/gl/blending/AlphaTestOverride.java | 19 + .../iris/gl/blending/AlphaTestStorage.java | 56 + .../coderbot/iris/gl/blending/BlendMode.java | 31 + .../iris/gl/blending/BlendModeFunction.java | 39 + .../iris/gl/blending/BlendModeOverride.java | 19 + .../iris/gl/blending/BlendModeStorage.java | 76 + .../gl/blending/BufferBlendInformation.java | 19 + .../iris/gl/blending/BufferBlendOverride.java | 15 + .../coderbot/iris/gl/blending/ColorMask.java | 31 + .../iris/gl/blending/DepthColorStorage.java | 55 + .../iris/gl/framebuffer/GlFramebuffer.java | 112 ++ .../coderbot/iris/gl/image/ImageBinding.java | 24 + .../coderbot/iris/gl/image/ImageHolder.java | 10 + .../coderbot/iris/gl/image/ImageLimits.java | 24 + .../iris/gl/program/ComputeProgram.java | 90 ++ .../iris/gl/program/GlUniform1iCall.java | 19 + .../net/coderbot/iris/gl/program/Program.java | 49 + .../iris/gl/program/ProgramBuilder.java | 131 ++ .../iris/gl/program/ProgramImages.java | 98 ++ .../iris/gl/program/ProgramSamplers.java | 295 ++++ .../iris/gl/program/ProgramUniforms.java | 354 +++++ .../iris/gl/sampler/SamplerBinding.java | 30 + .../iris/gl/sampler/SamplerHolder.java | 21 + .../iris/gl/sampler/SamplerLimits.java | 31 + .../net/coderbot/iris/gl/shader/GlShader.java | 64 + .../iris/gl/shader/ProgramCreator.java | 52 + .../coderbot/iris/gl/shader/ShaderType.java | 23 + .../iris/gl/shader/ShaderWorkarounds.java | 50 + .../iris/gl/shader/StandardMacros.java | 265 ++++ .../iris/gl/state/StateUpdateNotifiers.java | 18 + .../iris/gl/state/ValueUpdateNotifier.java | 12 + .../iris/gl/texture/DepthBufferFormat.java | 80 ++ .../iris/gl/texture/DepthCopyStrategy.java | 119 ++ .../gl/texture/InternalTextureFormat.java | 108 ++ .../coderbot/iris/gl/texture/PixelFormat.java | 53 + .../coderbot/iris/gl/texture/PixelType.java | 55 + .../iris/gl/texture/TextureScaleOverride.java | 41 + .../iris/gl/texture/TextureUploadHelper.java | 22 + .../iris/gl/uniform/BooleanUniform.java | 9 + .../DynamicLocationalUniformHolder.java | 56 + .../iris/gl/uniform/DynamicUniformHolder.java | 20 + .../iris/gl/uniform/FloatSupplier.java | 6 + .../iris/gl/uniform/FloatUniform.java | 38 + .../coderbot/iris/gl/uniform/IntUniform.java | 40 + .../gl/uniform/LocationalUniformHolder.java | 119 ++ .../uniform/MatrixFromFloatArrayUniform.java | 35 + .../iris/gl/uniform/MatrixUniform.java | 35 + .../net/coderbot/iris/gl/uniform/Uniform.java | 27 + .../iris/gl/uniform/UniformHolder.java | 46 + .../coderbot/iris/gl/uniform/UniformType.java | 12 + .../gl/uniform/UniformUpdateFrequency.java | 7 + .../gl/uniform/VanillaVector3Uniform.java | 30 + .../gl/uniform/Vector2IntegerJomlUniform.java | 41 + .../iris/gl/uniform/Vector2Uniform.java | 29 + .../iris/gl/uniform/Vector3Uniform.java | 54 + .../gl/uniform/Vector4IntegerJomlUniform.java | 41 + .../iris/gl/uniform/Vector4Uniform.java | 41 + .../iris/gui/FeatureMissingErrorScreen.java | 31 + .../net/coderbot/iris/gui/FileDialogUtil.java | 63 + .../java/net/coderbot/iris/gui/GuiUtil.java | 207 +++ .../iris/gui/NavigationController.java | 66 + .../iris/gui/element/IrisElementRow.java | 225 +++ .../gui/element/IrisObjectSelectionList.java | 23 + .../gui/element/ShaderPackOptionList.java | 365 +++++ .../gui/element/ShaderPackSelectionList.java | 310 ++++ .../screen/ElementWidgetScreenData.java | 15 + .../element/widget/AbstractElementWidget.java | 30 + .../widget/BaseOptionElementWidget.java | 180 +++ .../element/widget/BooleanElementWidget.java | 112 ++ .../widget/CommentedElementWidget.java | 16 + .../gui/element/widget/LinkElementWidget.java | 84 ++ .../element/widget/OptionMenuConstructor.java | 87 ++ .../element/widget/ProfileElementWidget.java | 101 ++ .../element/widget/SliderElementWidget.java | 115 ++ .../element/widget/StringElementWidget.java | 109 ++ .../iris/gui/option/IrisVideoSettings.java | 68 + .../ShaderPackSelectionButtonOption.java | 27 + .../iris/gui/option/ShadowDistanceOption.java | 22 + .../option/ShadowDistanceSliderButton.java | 20 + .../coderbot/iris/gui/screen/HudHideable.java | 9 + .../iris/gui/screen/ShaderPackScreen.java | 574 ++++++++ .../layer/BlockEntityRenderStateShard.java | 41 + .../iris/layer/EntityRenderStateShard.java | 41 + .../coderbot/iris/layer/GbufferPrograms.java | 114 ++ .../layer/IsBlockEntityRenderStateShard.java | 10 + .../iris/layer/IsEntityRenderStateShard.java | 10 + .../iris/layer/IsOutlineRenderStateShard.java | 10 + .../iris/layer/OuterWrappedRenderType.java | 88 ++ .../net/coderbot/iris/pipeline/ClearPass.java | 46 + .../iris/pipeline/ClearPassCreator.java | 128 ++ .../iris/pipeline/ClearPassInformation.java | 38 + .../iris/pipeline/CustomTextureManager.java | 176 +++ .../DeferredWorldRenderingPipeline.java | 1269 +++++++++++++++++ .../FixedFunctionWorldRenderingPipeline.java | 193 +++ .../coderbot/iris/pipeline/HandRenderer.java | 137 ++ .../iris/pipeline/HorizonRenderer.java | 177 +++ .../iris/pipeline/PatchedShaderPrinter.java | 70 + .../iris/pipeline/PipelineManager.java | 102 ++ .../iris/pipeline/ShadowRenderer.java | 656 +++++++++ .../iris/pipeline/SodiumTerrainPipeline.java | 180 +++ .../iris/pipeline/WorldRenderingPhase.java | 45 + .../iris/pipeline/WorldRenderingPipeline.java | 55 + .../transform/AttributeParameters.java | 42 + .../transform/AttributeTransformer.java | 167 +++ .../transform/CompatibilityTransformer.java | 544 +++++++ .../transform/CompositeDepthTransformer.java | 30 + .../transform/CompositeTransformer.java | 30 + .../iris/pipeline/transform/Parameters.java | 37 + .../iris/pipeline/transform/Patch.java | 7 + .../pipeline/transform/PatchShaderType.java | 28 + .../transform/SodiumTerrainTransformer.java | 112 ++ .../pipeline/transform/TransformPatcher.java | 226 +++ .../iris/postprocess/BufferFlipper.java | 40 + .../iris/postprocess/CenterDepthSampler.java | 123 ++ .../iris/postprocess/CompositeRenderer.java | 388 +++++ .../iris/postprocess/FinalPassRenderer.java | 402 ++++++ .../postprocess/FullScreenQuadRenderer.java | 86 ++ .../rendertarget/Blaze3dRenderTargetExt.java | 7 + .../iris/rendertarget/DepthTexture.java | 37 + .../NativeImageBackedCustomTexture.java | 45 + .../NativeImageBackedNoiseTexture.java | 35 + .../NativeImageBackedSingleColorTexture.java | 21 + .../iris/rendertarget/NoiseTexture.java | 75 + .../iris/rendertarget/RenderTarget.java | 170 +++ .../iris/rendertarget/RenderTargets.java | 332 +++++ .../iris/rendertarget/SingleColorTexture.java | 40 + .../coderbot/iris/samplers/IrisImages.java | 53 + .../coderbot/iris/samplers/IrisSamplers.java | 166 +++ .../iris/shaderpack/CloudSetting.java | 8 + .../iris/shaderpack/CommentDirective.java | 38 + .../shaderpack/CommentDirectiveParser.java | 151 ++ .../shaderpack/ComputeDirectiveParser.java | 75 + .../iris/shaderpack/ComputeSource.java | 60 + .../iris/shaderpack/ConstDirectiveParser.java | 178 +++ .../coderbot/iris/shaderpack/DimensionId.java | 7 + .../iris/shaderpack/DirectiveHolder.java | 24 + .../DispatchingDirectiveHolder.java | 323 +++++ .../net/coderbot/iris/shaderpack/IdMap.java | 294 ++++ .../coderbot/iris/shaderpack/IrisLimits.java | 12 + .../coderbot/iris/shaderpack/LanguageMap.java | 75 + .../coderbot/iris/shaderpack/LegacyIdMap.java | 98 ++ .../iris/shaderpack/OptionalBoolean.java | 25 + .../shaderpack/OrderBackedProperties.java | 27 + .../iris/shaderpack/PackDirectives.java | 254 ++++ .../PackRenderTargetDirectives.java | 161 +++ .../iris/shaderpack/PackShadowDirectives.java | 450 ++++++ .../iris/shaderpack/ProgramDirectives.java | 186 +++ .../shaderpack/ProgramFallbackResolver.java | 42 + .../coderbot/iris/shaderpack/ProgramSet.java | 453 ++++++ .../iris/shaderpack/ProgramSource.java | 75 + .../coderbot/iris/shaderpack/ShaderPack.java | 405 ++++++ .../iris/shaderpack/ShaderProperties.java | 623 ++++++++ .../coderbot/iris/shaderpack/StringPair.java | 28 + .../discovery/ShaderpackDirectoryManager.java | 103 ++ .../iris/shaderpack/error/RusticError.java | 55 + .../shaderpack/include/AbsolutePackPath.java | 113 ++ .../iris/shaderpack/include/FileNode.java | 98 ++ .../iris/shaderpack/include/IncludeGraph.java | 260 ++++ .../shaderpack/include/IncludeProcessor.java | 59 + .../include/ShaderPackSourceNames.java | 97 ++ .../shaderpack/loading/ProgramArrayId.java | 29 + .../iris/shaderpack/loading/ProgramGroup.java | 22 + .../iris/shaderpack/loading/ProgramId.java | 90 ++ .../iris/shaderpack/loading/SourceSet.java | 13 + .../shaderpack/materialmap/BlockEntry.java | 113 ++ .../materialmap/BlockRenderType.java | 46 + .../shaderpack/materialmap/NamespacedId.java | 61 + .../iris/shaderpack/option/BaseOption.java | 40 + .../iris/shaderpack/option/BooleanOption.java | 24 + .../option/MergedBooleanOption.java | 50 + .../shaderpack/option/MergedStringOption.java | 50 + .../option/OptionAnnotatedSource.java | 563 ++++++++ .../shaderpack/option/OptionLocation.java | 29 + .../iris/shaderpack/option/OptionSet.java | 113 ++ .../iris/shaderpack/option/OptionTests.java | 68 + .../iris/shaderpack/option/OptionType.java | 5 + .../iris/shaderpack/option/Profile.java | 81 ++ .../iris/shaderpack/option/ProfileSet.java | 130 ++ .../shaderpack/option/ShaderPackOptions.java | 66 + .../iris/shaderpack/option/StringOption.java | 76 + .../menu/OptionMenuBooleanOptionElement.java | 14 + .../option/menu/OptionMenuContainer.java | 89 ++ .../option/menu/OptionMenuElement.java | 45 + .../option/menu/OptionMenuElementScreen.java | 47 + .../option/menu/OptionMenuLinkElement.java | 9 + .../menu/OptionMenuMainElementScreen.java | 13 + .../option/menu/OptionMenuOptionElement.java | 39 + .../option/menu/OptionMenuProfileElement.java | 31 + .../menu/OptionMenuStringOptionElement.java | 14 + .../menu/OptionMenuSubElementScreen.java | 17 + .../option/values/ImmutableOptionValues.java | 55 + .../option/values/MutableOptionValues.java | 134 ++ .../option/values/OptionValues.java | 32 + .../iris/shaderpack/parsing/ParsedString.java | 158 ++ .../preprocessor/GlslCollectingListener.java | 33 + .../preprocessor/JcppProcessor.java | 70 + .../PropertiesCommentListener.java | 19 + .../preprocessor/PropertiesPreprocessor.java | 138 ++ .../PropertyCollectingListener.java | 40 + .../shaderpack/texture/CustomTextureData.java | 161 +++ .../texture/TextureFilteringData.java | 19 + .../iris/shaderpack/texture/TextureStage.java | 47 + .../transform/StringTransformations.java | 128 ++ .../shaderpack/transform/Transformations.java | 17 + .../transform/line/LineTransform.java | 19 + .../coderbot/iris/shadow/ShadowMatrices.java | 215 +++ .../iris/shadows/CullingDataCache.java | 6 + .../coderbot/iris/shadows/Matrix4fAccess.java | 25 + .../iris/shadows/ShadowRenderTargets.java | 276 ++++ .../iris/shadows/ShadowRenderingState.java | 14 + .../iris/shadows/frustum/BoxCuller.java | 48 + .../frustum/CullEverythingFrustum.java | 26 + .../iris/shadows/frustum/FrustumHolder.java | 28 + .../AdvancedShadowCullingFrustum.java | 373 +++++ .../frustum/advanced/BaseClippingPlanes.java | 41 + .../frustum/advanced/NeighboringPlaneSet.java | 45 + .../frustum/fallback/BoxCullingFrustum.java | 39 + .../frustum/fallback/NonCullingFrustum.java | 28 + .../iris/texture/TextureInfoCache.java | 91 ++ .../coderbot/iris/texture/TextureTracker.java | 60 + .../texture/format/LabPBRTextureFormat.java | 71 + .../iris/texture/format/TextureFormat.java | 64 + .../texture/format/TextureFormatLoader.java | 72 + .../texture/format/TextureFormatRegistry.java | 25 + .../mipmap/AbstractMipmapGenerator.java | 32 + .../mipmap/ChannelMipmapGenerator.java | 50 + .../texture/mipmap/CustomMipmapGenerator.java | 13 + .../texture/mipmap/DiscreteBlendFunction.java | 58 + .../texture/mipmap/LinearBlendFunction.java | 10 + .../iris/texture/pbr/PBRAtlasHolder.java | 35 + .../iris/texture/pbr/PBRAtlasTexture.java | 147 ++ .../iris/texture/pbr/PBRSpriteHolder.java | 36 + .../iris/texture/pbr/PBRTextureHolder.java | 12 + .../iris/texture/pbr/PBRTextureManager.java | 199 +++ .../coderbot/iris/texture/pbr/PBRType.java | 56 + .../texture/pbr/TextureAtlasExtension.java | 10 + .../pbr/TextureAtlasSpriteExtension.java | 10 + .../texture/pbr/loader/AtlasPBRLoader.java | 222 +++ .../texture/pbr/loader/PBRTextureLoader.java | 23 + .../pbr/loader/PBRTextureLoaderRegistry.java | 29 + .../texture/pbr/loader/SimplePBRLoader.java | 42 + .../texture/util/ImageManipulationUtil.java | 120 ++ .../iris/texture/util/TextureExporter.java | 37 + .../texture/util/TextureManipulationUtil.java | 51 + .../iris/uniforms/CameraUniforms.java | 110 ++ .../iris/uniforms/CapturedRenderingState.java | 93 ++ .../iris/uniforms/CelestialUniforms.java | 135 ++ .../iris/uniforms/CommonUniforms.java | 262 ++++ .../uniforms/ExternallyManagedUniforms.java | 65 + .../coderbot/iris/uniforms/FogUniforms.java | 40 + .../iris/uniforms/FrameUpdateNotifier.java | 20 + .../uniforms/HardcodedCustomUniforms.java | 224 +++ .../coderbot/iris/uniforms/IdMapUniforms.java | 141 ++ .../iris/uniforms/IrisExclusiveUniforms.java | 148 ++ .../iris/uniforms/MatrixUniforms.java | 110 ++ .../iris/uniforms/SystemTimeUniforms.java | 117 ++ .../iris/uniforms/ViewportUniforms.java | 38 + .../iris/uniforms/WorldTimeUniforms.java | 54 + .../builtin/BuiltinReplacementUniforms.java | 31 + .../uniforms/transforms/SmoothedFloat.java | 141 ++ .../uniforms/transforms/SmoothedVec2f.java | 22 + .../vertices/BlockSensitiveBufferBuilder.java | 7 + .../vertices/BufferBuilderPolygonView.java | 42 + .../iris/vertices/ExtendedDataHelper.java | 20 + .../iris/vertices/ExtendingBufferBuilder.java | 5 + .../iris/vertices/ImmediateState.java | 9 + .../iris/vertices/IrisTextVertexSinkImpl.java | 121 ++ .../iris/vertices/IrisVertexFormats.java | 48 + .../net/coderbot/iris/vertices/NormI8.java | 97 ++ .../coderbot/iris/vertices/NormalHelper.java | 345 +++++ .../coderbot/iris/vertices/PolygonView.java | 13 + .../net/coderbot/iris/vertices/QuadView.java | 7 + .../net/coderbot/iris/vertices/TriView.java | 7 + .../net/irisshaders/iris/api/v0/IrisApi.java | 108 ++ .../iris/api/v0/IrisApiConfig.java | 22 + .../iris/api/v0/IrisTextVertexSink.java | 32 + .../api/v0/item/IrisItemLightProvider.java | 24 + 390 files changed, 34055 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/EntityRendererAccessor.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/MinecraftAccessor.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/SimpleTextureAccessor.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/TextureAtlasSpriteAccessor.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGameSettings.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGuiMainMenu.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinInitRenderer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/Digraph.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/DigraphAdapter.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/DigraphFactory.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/DigraphProvider.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/Digraphs.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/DoubledDigraph.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/DoubledDigraphAdapter.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/EdgeWeights.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/EmptyDigraph.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/MapDigraph.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/TrivialDigraph.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/UnmodifiableDigraph.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/io/dot/DotAttribute.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/io/dot/DotExporter.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/io/dot/DotProvider.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/io/tgf/TgfExporter.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/io/tgf/TgfLabelProvider.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/util/fas/AbstractFeedbackArcSetProvider.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSet.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSetPolicy.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSetProvider.java create mode 100644 src/main/java/de/odysseus/ithaka/digraph/util/fas/SimpleFeedbackArcSetProvider.java create mode 100644 src/main/java/kroppeb/stareval/element/AccessibleExpressionElement.java create mode 100644 src/main/java/kroppeb/stareval/element/Element.java create mode 100644 src/main/java/kroppeb/stareval/element/ExpressionElement.java create mode 100644 src/main/java/kroppeb/stareval/element/PriorityOperatorElement.java create mode 100644 src/main/java/kroppeb/stareval/element/token/BinaryOperatorToken.java create mode 100644 src/main/java/kroppeb/stareval/element/token/IdToken.java create mode 100644 src/main/java/kroppeb/stareval/element/token/NumberToken.java create mode 100644 src/main/java/kroppeb/stareval/element/token/Token.java create mode 100644 src/main/java/kroppeb/stareval/element/token/UnaryOperatorToken.java create mode 100644 src/main/java/kroppeb/stareval/element/tree/AccessExpressionElement.java create mode 100644 src/main/java/kroppeb/stareval/element/tree/BinaryExpressionElement.java create mode 100644 src/main/java/kroppeb/stareval/element/tree/FunctionCall.java create mode 100644 src/main/java/kroppeb/stareval/element/tree/UnaryExpressionElement.java create mode 100644 src/main/java/kroppeb/stareval/element/tree/partial/PartialBinaryExpression.java create mode 100644 src/main/java/kroppeb/stareval/element/tree/partial/PartialExpression.java create mode 100644 src/main/java/kroppeb/stareval/element/tree/partial/UnfinishedArgsExpression.java create mode 100644 src/main/java/kroppeb/stareval/exception/MissingTokenException.java create mode 100644 src/main/java/kroppeb/stareval/exception/ParseException.java create mode 100644 src/main/java/kroppeb/stareval/exception/UnexpectedCharacterException.java create mode 100644 src/main/java/kroppeb/stareval/exception/UnexpectedEndingException.java create mode 100644 src/main/java/kroppeb/stareval/exception/UnexpectedTokenException.java create mode 100644 src/main/java/kroppeb/stareval/parser/BinaryOp.java create mode 100644 src/main/java/kroppeb/stareval/parser/OpResolver.java create mode 100644 src/main/java/kroppeb/stareval/parser/Parser.java create mode 100644 src/main/java/kroppeb/stareval/parser/ParserOptions.java create mode 100644 src/main/java/kroppeb/stareval/parser/StringReader.java create mode 100644 src/main/java/kroppeb/stareval/parser/Tokenizer.java create mode 100644 src/main/java/kroppeb/stareval/parser/UnaryOp.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/BatchingDebugMessageHelper.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/BlendingStateHolder.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/DrawCallTrackingRenderBuffers.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/FlushableMultiBufferSource.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/Groupable.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/MemoryTrackingBuffer.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/MemoryTrackingRenderBuffers.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/RenderBuffersExt.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/TransparencyType.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java create mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java create mode 100644 src/main/java/net/coderbot/iris/Iris.java create mode 100644 src/main/java/net/coderbot/iris/IrisLogging.java create mode 100644 src/main/java/net/coderbot/iris/JomlConversions.java create mode 100644 src/main/java/net/coderbot/iris/LaunchWarn.java create mode 100644 src/main/java/net/coderbot/iris/apiimpl/IrisApiV0ConfigImpl.java create mode 100644 src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java create mode 100644 src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java create mode 100644 src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/GLHelper.java create mode 100644 src/main/java/net/coderbot/iris/config/IrisConfig.java create mode 100644 src/main/java/net/coderbot/iris/fantastic/IrisParticleRenderTypes.java create mode 100644 src/main/java/net/coderbot/iris/fantastic/ParticleRenderingPhase.java create mode 100644 src/main/java/net/coderbot/iris/fantastic/PhasedParticleEngine.java create mode 100644 src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java create mode 100644 src/main/java/net/coderbot/iris/features/FeatureFlags.java create mode 100644 src/main/java/net/coderbot/iris/gbuffer_overrides/matching/InputAvailability.java create mode 100644 src/main/java/net/coderbot/iris/gbuffer_overrides/matching/ProgramTable.java create mode 100644 src/main/java/net/coderbot/iris/gbuffer_overrides/matching/RenderCondition.java create mode 100644 src/main/java/net/coderbot/iris/gbuffer_overrides/matching/SpecialCondition.java create mode 100644 src/main/java/net/coderbot/iris/gbuffer_overrides/state/RenderTargetStateListener.java create mode 100644 src/main/java/net/coderbot/iris/gbuffer_overrides/state/StateTracker.java create mode 100644 src/main/java/net/coderbot/iris/gl/GLDebug.java create mode 100644 src/main/java/net/coderbot/iris/gl/GlResource.java create mode 100644 src/main/java/net/coderbot/iris/gl/GlVersion.java create mode 100644 src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/AlphaTest.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/AlphaTestFunction.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/AlphaTestOverride.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/BlendMode.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/BlendModeFunction.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/BlendModeOverride.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/BlendModeStorage.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/BufferBlendInformation.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/BufferBlendOverride.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/ColorMask.java create mode 100644 src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java create mode 100644 src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java create mode 100644 src/main/java/net/coderbot/iris/gl/image/ImageBinding.java create mode 100644 src/main/java/net/coderbot/iris/gl/image/ImageHolder.java create mode 100644 src/main/java/net/coderbot/iris/gl/image/ImageLimits.java create mode 100644 src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java create mode 100644 src/main/java/net/coderbot/iris/gl/program/GlUniform1iCall.java create mode 100644 src/main/java/net/coderbot/iris/gl/program/Program.java create mode 100644 src/main/java/net/coderbot/iris/gl/program/ProgramBuilder.java create mode 100644 src/main/java/net/coderbot/iris/gl/program/ProgramImages.java create mode 100644 src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java create mode 100644 src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java create mode 100644 src/main/java/net/coderbot/iris/gl/sampler/SamplerBinding.java create mode 100644 src/main/java/net/coderbot/iris/gl/sampler/SamplerHolder.java create mode 100644 src/main/java/net/coderbot/iris/gl/sampler/SamplerLimits.java create mode 100644 src/main/java/net/coderbot/iris/gl/shader/GlShader.java create mode 100644 src/main/java/net/coderbot/iris/gl/shader/ProgramCreator.java create mode 100644 src/main/java/net/coderbot/iris/gl/shader/ShaderType.java create mode 100644 src/main/java/net/coderbot/iris/gl/shader/ShaderWorkarounds.java create mode 100644 src/main/java/net/coderbot/iris/gl/shader/StandardMacros.java create mode 100644 src/main/java/net/coderbot/iris/gl/state/StateUpdateNotifiers.java create mode 100644 src/main/java/net/coderbot/iris/gl/state/ValueUpdateNotifier.java create mode 100644 src/main/java/net/coderbot/iris/gl/texture/DepthBufferFormat.java create mode 100644 src/main/java/net/coderbot/iris/gl/texture/DepthCopyStrategy.java create mode 100644 src/main/java/net/coderbot/iris/gl/texture/InternalTextureFormat.java create mode 100644 src/main/java/net/coderbot/iris/gl/texture/PixelFormat.java create mode 100644 src/main/java/net/coderbot/iris/gl/texture/PixelType.java create mode 100644 src/main/java/net/coderbot/iris/gl/texture/TextureScaleOverride.java create mode 100644 src/main/java/net/coderbot/iris/gl/texture/TextureUploadHelper.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/BooleanUniform.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/DynamicLocationalUniformHolder.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/DynamicUniformHolder.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/FloatSupplier.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/FloatUniform.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/IntUniform.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/LocationalUniformHolder.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/MatrixFromFloatArrayUniform.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/Uniform.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/UniformHolder.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/UniformType.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/UniformUpdateFrequency.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/VanillaVector3Uniform.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/Vector2IntegerJomlUniform.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/Vector2Uniform.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/Vector3Uniform.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/Vector4IntegerJomlUniform.java create mode 100644 src/main/java/net/coderbot/iris/gl/uniform/Vector4Uniform.java create mode 100644 src/main/java/net/coderbot/iris/gui/FeatureMissingErrorScreen.java create mode 100644 src/main/java/net/coderbot/iris/gui/FileDialogUtil.java create mode 100644 src/main/java/net/coderbot/iris/gui/GuiUtil.java create mode 100644 src/main/java/net/coderbot/iris/gui/NavigationController.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/IrisObjectSelectionList.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java create mode 100644 src/main/java/net/coderbot/iris/gui/option/ShaderPackSelectionButtonOption.java create mode 100644 src/main/java/net/coderbot/iris/gui/option/ShadowDistanceOption.java create mode 100644 src/main/java/net/coderbot/iris/gui/option/ShadowDistanceSliderButton.java create mode 100644 src/main/java/net/coderbot/iris/gui/screen/HudHideable.java create mode 100644 src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java create mode 100644 src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java create mode 100644 src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java create mode 100644 src/main/java/net/coderbot/iris/layer/GbufferPrograms.java create mode 100644 src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java create mode 100644 src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java create mode 100644 src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java create mode 100644 src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/ClearPass.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/ClearPassCreator.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/ClearPassInformation.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/HandRenderer.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/PatchedShaderPrinter.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/PipelineManager.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/SodiumTerrainPipeline.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/transform/AttributeParameters.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/transform/AttributeTransformer.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/transform/CompatibilityTransformer.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/transform/CompositeDepthTransformer.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/transform/CompositeTransformer.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/transform/Parameters.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/transform/Patch.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/transform/PatchShaderType.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/transform/SodiumTerrainTransformer.java create mode 100644 src/main/java/net/coderbot/iris/pipeline/transform/TransformPatcher.java create mode 100644 src/main/java/net/coderbot/iris/postprocess/BufferFlipper.java create mode 100644 src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java create mode 100644 src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java create mode 100644 src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java create mode 100644 src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java create mode 100644 src/main/java/net/coderbot/iris/rendertarget/Blaze3dRenderTargetExt.java create mode 100644 src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java create mode 100644 src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java create mode 100644 src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java create mode 100644 src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java create mode 100644 src/main/java/net/coderbot/iris/rendertarget/NoiseTexture.java create mode 100644 src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java create mode 100644 src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java create mode 100644 src/main/java/net/coderbot/iris/rendertarget/SingleColorTexture.java create mode 100644 src/main/java/net/coderbot/iris/samplers/IrisImages.java create mode 100644 src/main/java/net/coderbot/iris/samplers/IrisSamplers.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/CloudSetting.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/CommentDirective.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/CommentDirectiveParser.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/ComputeDirectiveParser.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/ComputeSource.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/ConstDirectiveParser.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/DimensionId.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/DirectiveHolder.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/DispatchingDirectiveHolder.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/IdMap.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/IrisLimits.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/LanguageMap.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/LegacyIdMap.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/OptionalBoolean.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/OrderBackedProperties.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/PackRenderTargetDirectives.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/PackShadowDirectives.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/ProgramDirectives.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/ProgramFallbackResolver.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/ProgramSource.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/ShaderProperties.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/StringPair.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/discovery/ShaderpackDirectoryManager.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/error/RusticError.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/include/AbsolutePackPath.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/include/FileNode.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/include/IncludeGraph.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/include/IncludeProcessor.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/include/ShaderPackSourceNames.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/loading/ProgramArrayId.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/loading/ProgramGroup.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/loading/ProgramId.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/loading/SourceSet.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockEntry.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockRenderType.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/materialmap/NamespacedId.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/BaseOption.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/BooleanOption.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/MergedBooleanOption.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/MergedStringOption.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/OptionAnnotatedSource.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/OptionLocation.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/OptionSet.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/OptionTests.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/OptionType.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/Profile.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/ProfileSet.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/ShaderPackOptions.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/StringOption.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuBooleanOptionElement.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuContainer.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuElement.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuElementScreen.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuLinkElement.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuMainElementScreen.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuOptionElement.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuProfileElement.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuStringOptionElement.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuSubElementScreen.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/values/ImmutableOptionValues.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/values/MutableOptionValues.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/option/values/OptionValues.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/parsing/ParsedString.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/preprocessor/GlslCollectingListener.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/preprocessor/JcppProcessor.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertiesCommentListener.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertiesPreprocessor.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertyCollectingListener.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/texture/CustomTextureData.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/texture/TextureFilteringData.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/texture/TextureStage.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/transform/StringTransformations.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/transform/Transformations.java create mode 100644 src/main/java/net/coderbot/iris/shaderpack/transform/line/LineTransform.java create mode 100644 src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java create mode 100644 src/main/java/net/coderbot/iris/shadows/CullingDataCache.java create mode 100644 src/main/java/net/coderbot/iris/shadows/Matrix4fAccess.java create mode 100644 src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java create mode 100644 src/main/java/net/coderbot/iris/shadows/ShadowRenderingState.java create mode 100644 src/main/java/net/coderbot/iris/shadows/frustum/BoxCuller.java create mode 100644 src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java create mode 100644 src/main/java/net/coderbot/iris/shadows/frustum/FrustumHolder.java create mode 100644 src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java create mode 100644 src/main/java/net/coderbot/iris/shadows/frustum/advanced/BaseClippingPlanes.java create mode 100644 src/main/java/net/coderbot/iris/shadows/frustum/advanced/NeighboringPlaneSet.java create mode 100644 src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java create mode 100644 src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java create mode 100644 src/main/java/net/coderbot/iris/texture/TextureInfoCache.java create mode 100644 src/main/java/net/coderbot/iris/texture/TextureTracker.java create mode 100644 src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java create mode 100644 src/main/java/net/coderbot/iris/texture/format/TextureFormat.java create mode 100644 src/main/java/net/coderbot/iris/texture/format/TextureFormatLoader.java create mode 100644 src/main/java/net/coderbot/iris/texture/format/TextureFormatRegistry.java create mode 100644 src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java create mode 100644 src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java create mode 100644 src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java create mode 100644 src/main/java/net/coderbot/iris/texture/mipmap/DiscreteBlendFunction.java create mode 100644 src/main/java/net/coderbot/iris/texture/mipmap/LinearBlendFunction.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasHolder.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/PBRTextureHolder.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/PBRTextureManager.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/PBRType.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/TextureAtlasExtension.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/TextureAtlasSpriteExtension.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoader.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java create mode 100644 src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java create mode 100644 src/main/java/net/coderbot/iris/texture/util/TextureExporter.java create mode 100644 src/main/java/net/coderbot/iris/texture/util/TextureManipulationUtil.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/ExternallyManagedUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/FogUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/FrameUpdateNotifier.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/IrisExclusiveUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/SystemTimeUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/builtin/BuiltinReplacementUniforms.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/transforms/SmoothedFloat.java create mode 100644 src/main/java/net/coderbot/iris/uniforms/transforms/SmoothedVec2f.java create mode 100644 src/main/java/net/coderbot/iris/vertices/BlockSensitiveBufferBuilder.java create mode 100644 src/main/java/net/coderbot/iris/vertices/BufferBuilderPolygonView.java create mode 100644 src/main/java/net/coderbot/iris/vertices/ExtendedDataHelper.java create mode 100644 src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java create mode 100644 src/main/java/net/coderbot/iris/vertices/ImmediateState.java create mode 100644 src/main/java/net/coderbot/iris/vertices/IrisTextVertexSinkImpl.java create mode 100644 src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java create mode 100644 src/main/java/net/coderbot/iris/vertices/NormI8.java create mode 100644 src/main/java/net/coderbot/iris/vertices/NormalHelper.java create mode 100644 src/main/java/net/coderbot/iris/vertices/PolygonView.java create mode 100644 src/main/java/net/coderbot/iris/vertices/QuadView.java create mode 100644 src/main/java/net/coderbot/iris/vertices/TriView.java create mode 100644 src/main/java/net/irisshaders/iris/api/v0/IrisApi.java create mode 100644 src/main/java/net/irisshaders/iris/api/v0/IrisApiConfig.java create mode 100644 src/main/java/net/irisshaders/iris/api/v0/IrisTextVertexSink.java create mode 100644 src/main/java/net/irisshaders/iris/api/v0/item/IrisItemLightProvider.java diff --git a/addon.gradle b/addon.gradle index 8535d4509..39de83d6e 100644 --- a/addon.gradle +++ b/addon.gradle @@ -9,3 +9,11 @@ sourceSets { compileClasspath += configurations.compileStubs } } + +allprojects { + gradle.projectsEvaluated { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xmaxerrs" << "2000" + } + } +} diff --git a/dependencies.gradle b/dependencies.gradle index 032618a66..f8c6a0efe 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -43,6 +43,7 @@ dependencies { implementation("it.unimi.dsi:fastutil:8.2.1") implementation("org.joml:joml:1.10.5") implementation("org.anarres:jcpp:1.4.14") + implementation("io.github.douira:glsl-transformer:1.0.0") compileOnly "org.apache.ant:ant:1.8.2" diff --git a/src/main/java/com/gtnewhorizons/angelica/client/HFNoiseTexture.java b/src/main/java/com/gtnewhorizons/angelica/client/HFNoiseTexture.java index 7e62f955b..05db4ff04 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/HFNoiseTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/HFNoiseTexture.java @@ -1,10 +1,10 @@ package com.gtnewhorizons.angelica.client; -import java.nio.ByteBuffer; - import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; +import java.nio.ByteBuffer; + /** * * @author Nathanael Lane @@ -25,16 +25,7 @@ public HFNoiseTexture(int width, int height) { // GL13.glActiveTexture(GL13.GL_TEXTURE0 + this.textureUnit); GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID); - GL11.glTexImage2D( - GL11.GL_TEXTURE_2D, - 0, - GL11.GL_RGB, - width, - height, - 0, - GL11.GL_RGB, - GL11.GL_UNSIGNED_BYTE, - data); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, width, height, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, data); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index 245ee9f1a..707c69fd7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -1739,16 +1739,7 @@ private static void setupFrameBuffer() { GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_DEPTH_TEXTURE_MODE, GL11.GL_LUMINANCE); - GL11.glTexImage2D( - GL11.GL_TEXTURE_2D, - 0, - GL11.GL_DEPTH_COMPONENT, - renderWidth, - renderHeight, - 0, - GL11.GL_DEPTH_COMPONENT, - GL11.GL_FLOAT, - (ByteBuffer) null); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_DEPTH_COMPONENT, renderWidth, renderHeight, 0, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (ByteBuffer) null); } glFramebufferTexture2DEXT( diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 6bdebf1fe..fc7e97238 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -1,17 +1,30 @@ package com.gtnewhorizons.angelica.mixins; +import cpw.mods.fml.relauncher.FMLLaunchHandler; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.function.Supplier; -import cpw.mods.fml.relauncher.FMLLaunchHandler; - public enum Mixins { ANGELICA_STARTUP(new Builder("Start Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses("shaders.MixinMinecraft")), + .setPhase(Phase.EARLY).addMixinClasses( + "shaders.MixinMinecraft", + "shaders.MixinGameSettings", + "shaders.MixinGuiMainMenu", + "shaders.MixinInitRenderer") + ), + + ANGELICA_ACCESSORS(new Builder("Angelica Accessors").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).addMixinClasses( + "accessors.MinecraftAccessor", + "accessors.EntityRendererAccessor", + "accessors.SimpleTextureAccessor", + "accessors.TextureAtlasSpriteAccessor" + )), ANGELICA_SHADERS_BUTTON(new Builder("Add Shaders Button").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses("settings.MixinGuiVideoSettings")), @@ -45,6 +58,10 @@ public enum Mixins { "renderer.MixinTextureMap", "renderer.MixinThreadDownloadImageData")), + ANGELICA_TEXTURE(new Builder("Texture").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).addMixinClasses( + + )), COMPAT_PR_ILLUMINATION( new Builder("ProjectRed Illumination compat").addTargetedMod(TargetedMod.PROJECTRED_ILLUMINATION) .setSide(Side.CLIENT).addMixinClasses("compat.MixinRenderHalo")), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/EntityRendererAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/EntityRendererAccessor.java new file mode 100644 index 000000000..11168107b --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/EntityRendererAccessor.java @@ -0,0 +1,13 @@ +package com.gtnewhorizons.angelica.mixins.early.accessors; + +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.entity.player.EntityPlayer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(EntityRenderer.class) +public interface EntityRendererAccessor { + @Invoker + float invokeGetNightVisionBrightness(EntityPlayer entityPlayer, float partialTicks); + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/MinecraftAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/MinecraftAccessor.java new file mode 100644 index 000000000..83729cb93 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/MinecraftAccessor.java @@ -0,0 +1,12 @@ +package com.gtnewhorizons.angelica.mixins.early.accessors; + +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import net.minecraft.util.Timer; + +@Mixin(Minecraft.class) +public interface MinecraftAccessor { + @Accessor("timer") + Timer getTimer(); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/SimpleTextureAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/SimpleTextureAccessor.java new file mode 100644 index 000000000..0a361fed0 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/SimpleTextureAccessor.java @@ -0,0 +1,12 @@ +package com.gtnewhorizons.angelica.mixins.early.accessors; + +import net.minecraft.client.renderer.texture.SimpleTexture; +import net.minecraft.util.ResourceLocation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(SimpleTexture.class) +public interface SimpleTextureAccessor { + @Accessor("textureLocation") + ResourceLocation getLocation(); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/TextureAtlasSpriteAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/TextureAtlasSpriteAccessor.java new file mode 100644 index 000000000..d5a0cdcb5 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/TextureAtlasSpriteAccessor.java @@ -0,0 +1,37 @@ +package com.gtnewhorizons.angelica.mixins.early.accessors; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.data.AnimationMetadataSection; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(TextureAtlasSprite.class) +public interface TextureAtlasSpriteAccessor { + @Accessor("animationMetadata") + AnimationMetadataSection getMetadata(); + +// @Accessor("mainImage") +// NativeImage[] getMainImage(); +// +// @Accessor("x") +// int getX(); +// +// @Accessor("y") +// int getY(); + + @Accessor("frameCounter") + int getFrame(); + + @Accessor("frameCounter") + void setFrame(int frame); + + @Accessor("tickCounter") + int getSubFrame(); + + @Accessor("tickCounter") + void setSubFrame(int subFrame); + +// +// @Invoker("upload") +// void callUpload(int frameIndex); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureAtlasSprite.java index f757bd79f..23f06852c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureAtlasSprite.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureAtlasSprite.java @@ -18,14 +18,7 @@ public class MixinTextureAtlasSprite { method = "updateAnimation()V") private void angelica$uploadTexSub(int[][] p_147955_0_, int p_147955_1_, int p_147955_2_, int p_147955_3_, int p_147955_4_, boolean p_147955_5_, boolean p_147955_6_) { - ShadersTex.uploadTexSub( - p_147955_0_, - p_147955_1_, - p_147955_2_, - p_147955_3_, - p_147955_4_, - p_147955_5_, - p_147955_6_); + ShadersTex.uploadTexSub(p_147955_0_, p_147955_1_, p_147955_2_, p_147955_3_, p_147955_4_, p_147955_5_, p_147955_6_); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGameSettings.java new file mode 100644 index 000000000..24cc82172 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGameSettings.java @@ -0,0 +1,27 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.coderbot.iris.Iris; +import net.minecraft.client.settings.GameSettings; +import org.spongepowered.asm.mixin.Mixin; +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.CallbackInfo; + +@Mixin(GameSettings.class) +public abstract class MixinGameSettings { + @Unique + private static boolean angelica$shadersInitialized; + + @Inject(method="Lnet/minecraft/client/settings/GameSettings;loadOptions()V", at=@At("HEAD")) + private void angelica$InitializeShaders(CallbackInfo ci) { + if (angelica$shadersInitialized) { + return; + } + + angelica$shadersInitialized = true; + // TODO: Should this be static, or a new var? + new Iris().onEarlyInitialize(); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGuiMainMenu.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGuiMainMenu.java new file mode 100644 index 000000000..a0a5a6aa1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGuiMainMenu.java @@ -0,0 +1,18 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.coderbot.iris.Iris; +import net.minecraft.client.gui.GuiMainMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GuiMainMenu.class) +public class MixinGuiMainMenu { + + @Inject(method = "initGui", at = @At("RETURN")) + public void angelica$shadersOnLoadingComplete(CallbackInfo ci) { + Iris.onLoadingComplete(); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinInitRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinInitRenderer.java new file mode 100644 index 000000000..d200b1332 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinInitRenderer.java @@ -0,0 +1,20 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.GLDebug; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.minecraft.client.renderer.OpenGlHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(OpenGlHelper.class) +public class MixinInitRenderer { + @Inject(method = "initializeTextures", at = @At("RETURN")) + private static void angelica$initializeRenderer(CallbackInfo ci) { + GLDebug.initRenderer(); + IrisRenderSystem.initRenderer(); + Iris.onRenderSystemInit(); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java new file mode 100644 index 000000000..f27e555af --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java @@ -0,0 +1,17 @@ +package com.gtnewhorizons.angelica.mixins.early.textures; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.data.AnimationMetadataSection; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(TextureAtlasSprite.class) +public abstract class MixinTextureAtlasSprite { + @Shadow + private AnimationMetadataSection animationMetadata; + + public boolean isAnimation() { + return animationMetadata != null && animationMetadata.getFrameCount() > 1; + } + +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/Digraph.java b/src/main/java/de/odysseus/ithaka/digraph/Digraph.java new file mode 100644 index 000000000..4c3af75ca --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/Digraph.java @@ -0,0 +1,150 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +import java.util.Collection; +import java.util.OptionalInt; +import java.util.Set; + +/** + * Directed graph interface. + * + * @param vertex type + */ +public interface Digraph extends EdgeWeights { + /** + * Get an edge. + * + * @param source source vertex + * @param target target vertex + * @return edge weight (0 if there is no edge from source to target) + */ + OptionalInt get(V source, V target); + + /** + * Edge test. + * + * @param source source vertex + * @param target target vertex + * @return true iff this de.odysseus.ithaka.digraph contains an edge from source to target + */ + boolean contains(V source, V target); + + /** + * Vertex test + * + * @return true iff this de.odysseus.ithaka.digraph contains vertex + */ + boolean contains(V vertex); + + /** + * Add vertex. + * + * @return true iff vertex has been added + */ + boolean add(V vertex); + + /** + * Put an edge. + * Vertices are added automatically if they appear in an edge. + * + * @param source source vertex + * @param target target vertex + * @param weight edge weight + * @return edge weight that has been previously set (0 if there was no edge from source + * to target) + */ + OptionalInt put(V source, V target, int weight); + + /** + * Remove an edge. + * + * @param source source vertex + * @param target target vertex + * @return edge weight that has been previously set (0 if there was no edge from source + * to target) + */ + OptionalInt remove(V source, V target); + + /** + * Remove a vertex. + * + * @param vertex vertex + * @return true iff this de.odysseus.ithaka.digraph contained vertex + */ + boolean remove(V vertex); + + /** + * Remove all vertices. + * + * @param vertices vertices + */ + void removeAll(Collection vertices); + + /** + * Iterate over vertices. + * + * @return vertices + */ + Iterable vertices(); + + /** + * Iterate over edge targets for given source vertex. + * + * @param source source vertex + * @return edge targets of edges starting at source + */ + Iterable targets(V source); + + /** + * @return number of vertices in this de.odysseus.ithaka.digraph + */ + int getVertexCount(); + + /** + * @return sum of edge weights + */ + int totalWeight(); + + /** + * @return number of edges starting at vertex + */ + int getOutDegree(V vertex); + + /** + * @return number of edges in this de.odysseus.ithaka.digraph + */ + int getEdgeCount(); + + /** + * @return true iff this de.odysseus.ithaka.digraph is acyclic (i.e. it is a DAG) + */ + boolean isAcyclic(); + + /** + * Get reverse de.odysseus.ithaka.digraph (same vertices, with edges reversed). + * + * @return reverse de.odysseus.ithaka.digraph + */ + Digraph reverse(); + + /** + * Get induced subgraph (with vertices in this de.odysseus.ithaka.digraph and the given vertex set and edges that appear in this de.odysseus.ithaka.digraph over the given vertex set). + * + * @return subgraph + */ + Digraph subgraph(Set vertices); +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/DigraphAdapter.java b/src/main/java/de/odysseus/ithaka/digraph/DigraphAdapter.java new file mode 100644 index 000000000..120992254 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/DigraphAdapter.java @@ -0,0 +1,142 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +import java.util.Collection; +import java.util.OptionalInt; +import java.util.Set; + +/** + * Abstract Digraph adapter. + * A de.odysseus.ithaka.digraph adapter delegates to a de.odysseus.ithaka.digraph supplied at construction time. + * + * @param vertex type + */ +public abstract class DigraphAdapter implements Digraph { + private final Digraph delegate; + + public DigraphAdapter(Digraph delegate) { + this.delegate = delegate; + } + + @Override + public boolean add(V vertex) { + return delegate.add(vertex); + } + + @Override + public boolean contains(V source, V target) { + return delegate.contains(source, target); + } + + @Override + public boolean contains(V vertex) { + return delegate.contains(vertex); + } + + @Override + public OptionalInt get(V source, V target) { + return delegate.get(source, target); + } + + @Override + public int getOutDegree(V vertex) { + return delegate.getOutDegree(vertex); + } + + @Override + public int getEdgeCount() { + return delegate.getEdgeCount(); + } + + @Override + public int getVertexCount() { + return delegate.getVertexCount(); + } + + @Override + public int totalWeight() { + return delegate.totalWeight(); + } + + @Override + public Iterable vertices() { + return delegate.vertices(); + } + + @Override + public OptionalInt put(V source, V target, int edge) { + return delegate.put(source, target, edge); + } + + @Override + public OptionalInt remove(V source, V target) { + return delegate.remove(source, target); + } + + @Override + public boolean remove(V vertex) { + return delegate.remove(vertex); + } + + @Override + public void removeAll(Collection vertices) { + delegate.removeAll(vertices); + } + + @Override + public Digraph reverse() { + return delegate.reverse(); + } + + @Override + public Digraph subgraph(Set vertices) { + return delegate.subgraph(vertices); + } + + @Override + public boolean isAcyclic() { + return delegate.isAcyclic(); + } + + @Override + public Iterable targets(V source) { + return delegate.targets(source); + } + + @Override + public String toString() { + return delegate.toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + if (this.getClass() != obj.getClass()) { + return false; + } + + return delegate.equals(((DigraphAdapter) obj).delegate); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/DigraphFactory.java b/src/main/java/de/odysseus/ithaka/digraph/DigraphFactory.java new file mode 100644 index 000000000..63aa63afc --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/DigraphFactory.java @@ -0,0 +1,30 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +/** + * Digraph factory interface. + * + * @param de.odysseus.ithaka.digraph type + */ +public interface DigraphFactory> { + /** + * Create a de.odysseus.ithaka.digraph. + * + * @return de.odysseus.ithaka.digraph + */ + G create(); +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/DigraphProvider.java b/src/main/java/de/odysseus/ithaka/digraph/DigraphProvider.java new file mode 100644 index 000000000..021dfe086 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/DigraphProvider.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +/** + * Digraph provider interface. + * + * @param de.odysseus.ithaka.digraph sub-type + * @param de.odysseus.ithaka.digraph type + */ +public interface DigraphProvider> { + /** + * Get a de.odysseus.ithaka.digraph. + * + * @param value value associated with a de.odysseus.ithaka.digraph + * @return de.odysseus.ithaka.digraph + */ + G get(T value); +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/Digraphs.java b/src/main/java/de/odysseus/ithaka/digraph/Digraphs.java new file mode 100644 index 000000000..973d5a3d4 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/Digraphs.java @@ -0,0 +1,352 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.OptionalInt; +import java.util.Set; +import java.util.Stack; + +/** + * This class provides some common de.odysseus.ithaka.digraph utilities. + */ +public class Digraphs { + /** + * Get an unmodifiable empty de.odysseus.ithaka.digraph. + * + * @return empty de.odysseus.ithaka.digraph + */ + public static DoubledDigraph emptyDigraph() { + return new EmptyDigraph<>(); + } + + /** + * Wraps the given de.odysseus.ithaka.digraph to make it unmodifiable. Whenever a method + * is called on the resulting de.odysseus.ithaka.digraph that could modify the underlying + * de.odysseus.ithaka.digraph, an exception is thrown. + * + * @param vertex type + * @return unmodifiable de.odysseus.ithaka.digraph equivalent to the given de.odysseus.ithaka.digraph + */ + public static Digraph unmodifiableDigraph(Digraph digraph) { + return new UnmodifiableDigraph<>(digraph); + } + + /** + * Topologically sort vertices of an acyclic directed graph (DAG). + * This method will produce an ordering of vertices, such that all + * edges go from left right. + * If the input graph is not a DAG, the algorithm will still perform, + * but in the resulting list there will be edges from vertices to + * vertices prior in the list. + * + * @param vertex type + * @param digraph input graph + * @param descending let edges go from right to left if true + * @return list of vertices topologically ordered. + */ + public static List toposort(Digraph digraph, boolean descending) { + List finished = new ArrayList<>(); + Set discovered = new HashSet<>(digraph.getVertexCount()); + for (V vertex : digraph.vertices()) { + if (!discovered.contains(vertex)) { + dfs(digraph, vertex, discovered, finished); + } + } + if (!descending) { + Collections.reverse(finished); + } + return finished; + } + + /** + * Compute the set of vertices reachable from the given source in the given de.odysseus.ithaka.digraph. + * + * @param vertex type + * @param source source vertex + * @return the set of vertices reachable from source + */ + public static Set closure(Digraph digraph, V source) { + Set closure = new HashSet<>(); + dfs(digraph, source, closure, closure); + return closure; + } + + /** + * Returns true if this graph is definitely acyclic from some quick checks, + * but false if properly determining whether the graph is acyclic would + * take more work. + */ + public static boolean isTriviallyAcyclic(Digraph digraph) { + return digraph.getVertexCount() < 2; + } + + /** + * Answer true if the given de.odysseus.ithaka.digraph is acyclic (DAG). + * Per definition, the empty graph and single vertex digraphs are acyclic. + * + * @param vertex type + * @return true iff the given de.odysseus.ithaka.digraph is acyclic + */ + public static boolean isAcyclic(Digraph digraph) { + if (isTriviallyAcyclic(digraph)) { + return true; + } + + int n = digraph.getVertexCount(); + + if (digraph.getEdgeCount() > (n * (n - 1)) / 2) { + return false; + } + + return Digraphs.scc(digraph).size() == n; + } + + /** + * Test if the given digraphs are equivalent. + * This is the case if and the same vertices are connected by an edge. + *

    + *
  1. both digraphs contain the same vertices
  2. + *
  3. the same pairs of vertices are connected by an edge in both digraphs
  4. + *
  5. optionally, this method may require that the corresponding edges are equal.
  6. + *
+ * + * @param vertex type + * @param first first de.odysseus.ithaka.digraph. + * @param second second de.odysseus.ithaka.digraph. + * @param compareEdges if true, compare edges using equals(). + * @return true iff the two digraphs are equivalent according to the above description. + */ + public static boolean isEquivalent(Digraph first, Digraph second, boolean compareEdges) { + if (first == second) { + return true; + } + if (first.getEdgeCount() != second.getEdgeCount() || first.getVertexCount() != second.getVertexCount()) { + return false; + } + for (V source : first.vertices()) { + if (!second.contains(source)) { + return false; + } + for (V target : first.targets(source)) { + OptionalInt secondEdge = second.get(source, target); + + if (!secondEdge.isPresent()) { + return false; + } + + if (compareEdges) { + int edge1 = first.get(source, target).getAsInt(); + int edge2 = secondEdge.getAsInt(); + + if (edge1 != edge2) { + return false; + } + } + } + } + return true; + } + + /** + * Answer true if the given de.odysseus.ithaka.digraph is strongly connected. + * Per definition, the empty graph and single vertex digraphs are strongly connected. + * + * @param vertex type + * @return true iff the given de.odysseus.ithaka.digraph is strongly connected + */ + public static boolean isStronglyConnected(Digraph digraph) { + int n = digraph.getVertexCount(); + if (n < 2) { + return true; + } + return Digraphs.scc(digraph).size() == 1; + } + + /** + * Answer true if there is a path from the given source to the given target + * in the supplied graph. If source is equal to target, answer true. + * + * @param vertex type + * @param source source vertex + * @param target target vertex + * @return true iff there's a path from source to target in de.odysseus.ithaka.digraph + */ + public static boolean isReachable(Digraph digraph, V source, V target) { + return digraph.contains(source, target) || Digraphs.closure(digraph, source).contains(target); + } + + /** + * Perform a depth first search. + * + * @param vertex type + * @param source dfs start vertex + * @param discovered set of vertices already discovered during search + * @param finished collection of vertices visited during search + */ + public static void dfs(Digraph digraph, V source, Set discovered, Collection finished) { + if (discovered.add(source)) { + for (V target : digraph.targets(source)) { + dfs(digraph, target, discovered, finished); + } + finished.add(source); + } + } + + /** + * Perform an undirected depth first search. + * + * @param vertex type + * @param source dfs start vertex + * @param discovered set of vertices already discovered during search + * @param finished collection of vertices visited during search + */ + public static void dfs2(Digraph digraph, V source, Set discovered, Collection finished) { + dfs2(digraph, digraph.reverse(), source, discovered, finished); + } + + private static void dfs2(Digraph forward, Digraph backward, V source, Set discovered, Collection finished) { + if (discovered.add(source)) { + for (V target : forward.targets(source)) { + dfs2(forward, backward, target, discovered, finished); + } + for (V target : backward.targets(source)) { + dfs2(forward, backward, target, discovered, finished); + } + finished.add(source); + } + } + + /** + * Compute strongly connected components. + * + * @return strongly connected components + */ + public static List> scc(Digraph digraph) { + List> components = new ArrayList<>(); + Digraph reverse = digraph.reverse(); + + // dfs on this graph + Stack stack = new Stack<>(); + Set discovered = new HashSet<>(); + for (V vertex : digraph.vertices()) { + dfs(digraph, vertex, discovered, stack); + } + + // dfs on reverse graph + discovered = new HashSet<>(); + while (!stack.isEmpty()) { + V vertex = stack.pop(); + if (!discovered.contains(vertex)) { + Set component = new HashSet<>(); + dfs(reverse, vertex, discovered, component); + components.add(component); + } + } + + return components; + } + + /** + * Compute weakly connected components. + * + * @return weakly connected components + */ + public static List> wcc(Digraph digraph) { + List> components = new ArrayList<>(); + Digraph reverse = digraph.reverse(); + + // dfs on both graphs + Set discovered = new HashSet<>(); + for (V vertex : digraph.vertices()) { + if (!discovered.contains(vertex)) { + Set component = new HashSet<>(); + dfs2(digraph, reverse, vertex, discovered, component); + components.add(component); + } + } + return components; + } + + /** + * Compute the reverse graph. + * + * @param vertex type + * @param result type + * @param digraph input de.odysseus.ithaka.digraph + * @param factory factory used to create result graph + * @return the reverse de.odysseus.ithaka.digraph + */ + public static > G reverse(Digraph digraph, DigraphFactory factory) { + G reverse = factory.create(); + for (V source : digraph.vertices()) { + reverse.add(source); + for (V target : digraph.targets(source)) { + reverse.put(target, source, digraph.get(source, target).getAsInt()); + } + } + return reverse; + } + + /** + * Copy a de.odysseus.ithaka.digraph. + * + * @param digraph graph to copy + * @param factory factory used to create copy + * @return a copy of the given de.odysseus.ithaka.digraph + */ + public static > G copy(Digraph digraph, DigraphFactory factory) { + G result = factory.create(); + for (V source : digraph.vertices()) { + result.add(source); + for (V target : digraph.targets(source)) { + result.put(source, target, digraph.get(source, target).getAsInt()); + } + } + return result; + } + + /** + * Create subgraph induced by the specified vertices. + * + * @param vertex type + * @param subgraph type + * @return subgraph of the supplied de.odysseus.ithaka.digraph containing the specified vertices. + */ + public static > G subgraph( + Digraph digraph, + Set vertices, + DigraphFactory factory) { + G subgraph = factory.create(); + for (V v : vertices) { + if (digraph.contains(v)) { + subgraph.add(v); + for (V w : digraph.targets(v)) { + if (vertices.contains(w)) { + subgraph.put(v, w, digraph.get(v, w).getAsInt()); + } + } + } + } + return subgraph; + } + + // a partition method used to be here but it was removed because it was causing issues +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/DoubledDigraph.java b/src/main/java/de/odysseus/ithaka/digraph/DoubledDigraph.java new file mode 100644 index 000000000..e7a337707 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/DoubledDigraph.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +/** + * Digraph holding its reverse graph and granting access to incoming edges. + */ +public interface DoubledDigraph extends Digraph { + /** + * @return number of edges ending at vertex + */ + int getInDegree(V vertex); + + /** + * Iterate over edge sources for given target vertex. + * + * @param target target vertex + * @return edge sources of edges ending at target + */ + Iterable sources(V target); + + /** + * Restrict result type. + */ + @Override + DoubledDigraph reverse(); +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/DoubledDigraphAdapter.java b/src/main/java/de/odysseus/ithaka/digraph/DoubledDigraphAdapter.java new file mode 100644 index 000000000..f2c1741c5 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/DoubledDigraphAdapter.java @@ -0,0 +1,214 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.OptionalInt; + +/** + * Doubled de.odysseus.ithaka.digraph implementation. + * + * @param vertex type + */ +public class DoubledDigraphAdapter extends DigraphAdapter implements DoubledDigraph { + /** + * Factory creating DoubledDigraph. + * + * @param factory delegate factory + * @return doubled de.odysseus.ithaka.digraph factory + */ + public static DigraphFactory> getAdapterFactory(final DigraphFactory> factory) { + return () -> new DoubledDigraphAdapter<>(factory); + } + + private final DoubledDigraphAdapter reverse; + private final DigraphFactory> factory; + + public DoubledDigraphAdapter() { + this(MapDigraph.getDefaultDigraphFactory()); + } + + public DoubledDigraphAdapter(DigraphFactory> factory) { + super(factory.create()); + this.factory = factory; + this.reverse = createReverse(); + } + + protected DoubledDigraphAdapter(DigraphFactory> factory, DoubledDigraphAdapter reverse) { + super(factory.create()); + this.factory = factory; + this.reverse = reverse; + } + + protected DoubledDigraphAdapter createReverse() { + return new DoubledDigraphAdapter<>(factory, this); + } + + protected DigraphFactory> getDigraphFactory() { + return getAdapterFactory(factory); + } + + protected DigraphFactory> getDelegateFactory() { + return factory; + } + + @Override + public int getInDegree(V vertex) { + return reverse.getOutDegree(vertex); + } + + @Override + public Iterable sources(V target) { + return reverse.targets(target); + } + + @Override + public final boolean add(V vertex) { + reverse.add0(vertex); + return add0(vertex); + } + + protected boolean add0(V vertex) { + return super.add(vertex); + } + + @Override + public final boolean remove(V vertex) { + reverse.remove0(vertex); + return remove0(vertex); + } + + protected boolean remove0(V vertex) { + return super.remove(vertex); + } + + @Override + public void removeAll(Collection vertices) { + reverse.removeAll0(vertices); + removeAll0(vertices); + } + + protected void removeAll0(Collection vertices) { + super.removeAll(vertices); + } + + /** + * Make sure the reverse de.odysseus.ithaka.digraph is kept in sync if Iterator.remove() is called. + */ + @Override + public Iterable vertices() { + final Iterator delegate = super.vertices().iterator(); + if (!delegate.hasNext()) { + return Collections.emptySet(); + } + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + V vertex; + + @Override + public boolean hasNext() { + return delegate.hasNext(); + } + + @Override + public V next() { + return vertex = delegate.next(); + } + + @Override + public void remove() { + delegate.remove(); + reverse.remove0(vertex); + } + }; + } + + @Override + public String toString() { + return DoubledDigraphAdapter.super.vertices().toString(); + } + }; + } + + /** + * Make sure the reverse de.odysseus.ithaka.digraph is kept in sync if Iterator.remove() is called. + */ + @Override + public Iterable targets(final V source) { + final Iterator delegate = super.targets(source).iterator(); + if (!delegate.hasNext()) { + return Collections.emptySet(); + } + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + V target; + + @Override + public boolean hasNext() { + return delegate.hasNext(); + } + + @Override + public V next() { + return target = delegate.next(); + } + + @Override + public void remove() { + delegate.remove(); + reverse.remove0(target, source); + } + }; + } + + @Override + public String toString() { + return DoubledDigraphAdapter.super.targets(source).toString(); + } + }; + } + + @Override + public final OptionalInt put(V source, V target, int edge) { + reverse.put0(target, source, edge); + return put0(source, target, edge); + } + + protected OptionalInt put0(V source, V target, int edge) { + return super.put(source, target, edge); + } + + @Override + public final OptionalInt remove(V source, V target) { + reverse.remove0(target, source); + return remove0(source, target); + } + + protected OptionalInt remove0(V source, V target) { + return super.remove(source, target); + } + + @Override + public final DoubledDigraphAdapter reverse() { + return reverse; + } +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/EdgeWeights.java b/src/main/java/de/odysseus/ithaka/digraph/EdgeWeights.java new file mode 100644 index 000000000..fdfc687f8 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/EdgeWeights.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +import java.util.OptionalInt; + +/** + * Edge weights interface. + * + * @param vertex type + */ +public interface EdgeWeights { + // We're storing this in order to avoid reallocating this optional constantly. + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + OptionalInt UNIT_WEIGHT = OptionalInt.of(1); + + /** + * Unit edge weights. + */ + EdgeWeights UNIT_WEIGHTS = (source, target) -> UNIT_WEIGHT; + + /** + * Get edge weight + * + * @param source source vertex + * @param target target vertex + * @return weight for edge starting at source and ending at target + */ + OptionalInt get(V source, V target); +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/EmptyDigraph.java b/src/main/java/de/odysseus/ithaka/digraph/EmptyDigraph.java new file mode 100644 index 000000000..28bce9269 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/EmptyDigraph.java @@ -0,0 +1,123 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +import java.util.Collection; +import java.util.Collections; +import java.util.OptionalInt; +import java.util.Set; + +/** + * Empty de.odysseus.ithaka.digraph. + * Adding a vertex or edge will throw a UnsupportedOperationException. + * + * @param vertex type + */ +class EmptyDigraph implements DoubledDigraph { + @Override + public boolean add(Object vertex) { + throw new UnsupportedOperationException("Empty de.odysseus.ithaka.digraph cannot have vertices!"); + } + + @Override + public boolean contains(Object source, Object target) { + return false; + } + + @Override + public boolean contains(Object vertex) { + return false; + } + + @Override + public OptionalInt get(Object source, Object target) { + return OptionalInt.empty(); + } + + @Override + public int getInDegree(Object vertex) { + return 0; + } + + @Override + public int getOutDegree(Object vertex) { + return 0; + } + + @Override + public int getEdgeCount() { + return 0; + } + + @Override + public int getVertexCount() { + return 0; + } + + @Override + public int totalWeight() { + return 0; + } + + @Override + public Iterable vertices() { + return Collections.emptyList(); + } + + @Override + public OptionalInt put(V source, V target, int edgeWeight) { + throw new UnsupportedOperationException("Empty de.odysseus.ithaka.digraph cannot have edges!"); + } + + @Override + public OptionalInt remove(V source, V target) { + return OptionalInt.empty(); + } + + @Override + public boolean remove(Object vertex) { + return false; + } + + @Override + public void removeAll(Collection vertices) { + } + + @Override + public DoubledDigraph reverse() { + return this; + } + + @Override + public Digraph subgraph(Set vertices) { + return this; + } + + @Override + public Iterable sources(Object target) { + return Collections.emptyList(); + } + + @Override + public Iterable targets(Object source) { + return Collections.emptyList(); + } + + @Override + public boolean isAcyclic() { + return true; + } +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/MapDigraph.java b/src/main/java/de/odysseus/ithaka/digraph/MapDigraph.java new file mode 100644 index 000000000..4d16f5d09 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/MapDigraph.java @@ -0,0 +1,433 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +import it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap; +import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMaps; + +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.OptionalInt; +import java.util.Set; +import java.util.TreeMap; + +/** + * Map-based directed graph implementation. + * + * @param vertex type + */ +public class MapDigraph implements Digraph { + private static final int INVALID_WEIGHT = Integer.MIN_VALUE; + + /** + * Factory creating default MapDigraph. + * + * @return map de.odysseus.ithaka.digraph factory + */ + public static DigraphFactory> getDefaultDigraphFactory() { + return getMapDigraphFactory(MapDigraph.getDefaultVertexMapFactory(null), MapDigraph.getDefaultEdgeMapFactory(null)); + } + + /** + * Factory creating MapDigraph. + * + * @param vertexMapFactory factory to create vertex --> edge-map maps + * @param edgeMapFactory factory to create edge-target --> edge-value maps + * @return map de.odysseus.ithaka.digraph factory + */ + public static DigraphFactory> getMapDigraphFactory( + final VertexMapFactory vertexMapFactory, + final EdgeMapFactory edgeMapFactory) { + return () -> new MapDigraph<>(vertexMapFactory, edgeMapFactory); + } + + /** + * Vertex map factory (vertex to edge map). + */ + public interface VertexMapFactory { + Map> create(); + } + + /** + * Edge map factory (edge target to edge value). + */ + public interface EdgeMapFactory { + Object2IntMap create(V source); + } + + private static VertexMapFactory getDefaultVertexMapFactory(final Comparator comparator) { + return new VertexMapFactory() { + @Override + public Map> create() { + if (comparator == null) { + return new LinkedHashMap<>(16); + } else { + return new TreeMap<>(comparator); + } + } + }; + } + + private static EdgeMapFactory getDefaultEdgeMapFactory(final Comparator comparator) { + return new EdgeMapFactory() { + @Override + public Object2IntMap create(V ignore) { + Object2IntMap map; + + if (comparator == null) { + map = new Object2IntLinkedOpenHashMap<>(16); + } else { + map = new Object2IntAVLTreeMap<>(comparator); + } + + map.defaultReturnValue(INVALID_WEIGHT); + + return map; + } + }; + } + + private static Object2IntMap createEmptyMap() { + return Object2IntMaps.emptyMap(); + } + + private final VertexMapFactory vertexMapFactory; + private final EdgeMapFactory edgeMapFactory; + private final Map> vertexMap; + + private int edgeCount; + + /** + * Create de.odysseus.ithaka.digraph. + * {@link LinkedHashMap}s will be used as vertex/edge maps. + * Vertices and edge targets will be iterated in no particular order. + */ + public MapDigraph() { + this(null); + } + + /** + * Create de.odysseus.ithaka.digraph. + * If a vertex comparator is given, {@link TreeMap}s will be used as vertex/edge maps. + * Vertices and edge targets will be iterated in the order given by the comparator. + * + * @param comparator vertex comparator (may be null) + */ + public MapDigraph(final Comparator comparator) { + this(comparator, comparator); + } + + /** + * Create de.odysseus.ithaka.digraph. + * If a vertex comparator is given, {@link TreeMap}s will be used as vertex maps + * and vertices will be iterated in the order given by the vertex comparator. + * If an edge comparator is given, {@link TreeMap}s will be used as edge maps + * and edge targets will be iterated in the order given by the edge comparator. + */ + public MapDigraph(final Comparator vertexComparator, final Comparator edgeComparator) { + this(MapDigraph.getDefaultVertexMapFactory(vertexComparator), MapDigraph.getDefaultEdgeMapFactory(edgeComparator)); + } + + /** + * Create de.odysseus.ithaka.digraph. + * + * @param vertexMapFactory factory to create vertex --> edge-map maps + * @param edgeMapFactory factory to create edge-target --> edge-value maps + */ + public MapDigraph(VertexMapFactory vertexMapFactory, EdgeMapFactory edgeMapFactory) { + this.vertexMapFactory = vertexMapFactory; + this.edgeMapFactory = edgeMapFactory; + + vertexMap = vertexMapFactory.create(); + } + + @Override + public boolean add(V vertex) { + if (!vertexMap.containsKey(vertex)) { + vertexMap.put(vertex, createEmptyMap()); + return true; + } + + return false; + } + + @Override + public OptionalInt put(V source, V target, int weight) { + if (weight == INVALID_WEIGHT) { + throw new IllegalArgumentException("Invalid weight " + weight); + } + + Object2IntMap edgeMap = vertexMap.get(source); + + if (edgeMap == null || edgeMap.isEmpty()) { + vertexMap.put(source, edgeMap = edgeMapFactory.create(source)); + } + + int previousInt = edgeMap.put(target, weight); + OptionalInt previous; + + if (previousInt != INVALID_WEIGHT) { + previous = OptionalInt.of(previousInt); + } else { + previous = OptionalInt.empty(); + add(target); + edgeCount++; + } + + return previous; + } + + @Override + public OptionalInt get(V source, V target) { + Object2IntMap edgeMap = vertexMap.get(source); + + if (edgeMap == null || edgeMap.isEmpty()) { + return OptionalInt.empty(); + } + + int result = edgeMap.getInt(target); + + return result == INVALID_WEIGHT ? OptionalInt.empty() : OptionalInt.of(result); + } + + @Override + public OptionalInt remove(V source, V target) { + Object2IntMap edgeMap = vertexMap.get(source); + if (edgeMap == null || !edgeMap.containsKey(target)) { + return OptionalInt.empty(); + } + int result = edgeMap.removeInt(target); + edgeCount--; + if (edgeMap.isEmpty()) { + vertexMap.put(source, createEmptyMap()); + } + return result == INVALID_WEIGHT ? OptionalInt.empty() : OptionalInt.of(result); + } + + @Override + public boolean remove(V vertex) { + Object2IntMap edgeMap = vertexMap.get(vertex); + if (edgeMap == null) { + return false; + } + edgeCount -= edgeMap.size(); + vertexMap.remove(vertex); + for (V source : vertexMap.keySet()) { + remove(source, vertex); + } + return true; + } + + @Override + public void removeAll(Collection vertices) { + for (V vertex : vertices) { + Object2IntMap edgeMap = vertexMap.get(vertex); + if (edgeMap != null) { + edgeCount -= edgeMap.size(); + vertexMap.remove(vertex); + } + } + for (V source : vertexMap.keySet()) { + Object2IntMap edgeMap = vertexMap.get(source); + Iterator iterator = edgeMap.keySet().iterator(); + while (iterator.hasNext()) { + if (vertices.contains(iterator.next())) { + iterator.remove(); + edgeCount--; + } + } + if (edgeMap.isEmpty()) { + vertexMap.put(source, createEmptyMap()); + } + } + } + + @Override + public boolean contains(V source, V target) { + Object2IntMap edgeMap = vertexMap.get(source); + + if (edgeMap == null || edgeMap.isEmpty()) { + return false; + } + + return edgeMap.containsKey(target); + } + + @Override + public boolean contains(V vertex) { + return vertexMap.containsKey(vertex); + } + + @Override + public Iterable vertices() { + if (vertexMap.isEmpty()) { + return Collections.emptySet(); + } + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + private final Iterator delegate = vertexMap.keySet().iterator(); + V vertex = null; + + @Override + public boolean hasNext() { + return delegate.hasNext(); + } + + @Override + public V next() { + return vertex = delegate.next(); + } + + @Override + public void remove() { + Object2IntMap edgeMap = vertexMap.get(vertex); + delegate.remove(); + edgeCount -= edgeMap.size(); + for (V source : vertexMap.keySet()) { + MapDigraph.this.remove(source, vertex); + } + } + }; + } + + @Override + public String toString() { + return vertexMap.keySet().toString(); + } + }; + } + + @Override + public Iterable targets(final V source) { + final Object2IntMap edgeMap = vertexMap.get(source); + if (edgeMap == null || edgeMap.isEmpty()) { + return Collections.emptySet(); + } + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + private final Iterator delegate = edgeMap.keySet().iterator(); + + @Override + public boolean hasNext() { + return delegate.hasNext(); + } + + @Override + public V next() { + return delegate.next(); + } + + @Override + public void remove() { + delegate.remove(); + edgeCount--; + if (edgeMap.isEmpty()) { + vertexMap.put(source, createEmptyMap()); + } + } + }; + } + + @Override + public String toString() { + return edgeMap.keySet().toString(); + } + }; + } + + @Override + public int getVertexCount() { + return vertexMap.size(); + } + + @Override + public int totalWeight() { + int weight = 0; + + for (V source : vertices()) { + for (V target : targets(source)) { + weight += get(source, target).getAsInt(); + } + } + + return weight; + } + + @Override + public int getOutDegree(V vertex) { + Object2IntMap edgeMap = vertexMap.get(vertex); + if (edgeMap == null) { + return 0; + } + return edgeMap.size(); + } + + @Override + public int getEdgeCount() { + return edgeCount; + } + + public DigraphFactory> getDigraphFactory() { + return () -> new MapDigraph<>(vertexMapFactory, edgeMapFactory); + } + + @Override + public MapDigraph reverse() { + return Digraphs.>reverse(this, getDigraphFactory()); + } + + @Override + public MapDigraph subgraph(Set vertices) { + return Digraphs.>subgraph(this, vertices, getDigraphFactory()); + } + + @Override + public boolean isAcyclic() { + return Digraphs.isAcyclic(this); + } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + b.append(getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1)); + b.append("("); + Iterator vertices = vertices().iterator(); + while (vertices.hasNext()) { + V v = vertices.next(); + b.append(v); + b.append(targets(v)); + if (vertices.hasNext()) { + b.append(", "); + if (b.length() > 1000) { + b.append("..."); + break; + } + } + } + b.append(")"); + return b.toString(); + } +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/TrivialDigraph.java b/src/main/java/de/odysseus/ithaka/digraph/TrivialDigraph.java new file mode 100644 index 000000000..a0e7da537 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/TrivialDigraph.java @@ -0,0 +1,253 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.OptionalInt; +import java.util.Set; + +/** + * Convenience class representing a de.odysseus.ithaka.digraph with zero or one vertex and an optional loop edge. + * Vertex as well as edge null is forbidden. + * + * @param vertex type + * @author beck + */ +public class TrivialDigraph implements DoubledDigraph { + private V vertex; + private boolean hasLoop; + private int loopWeight; + + public TrivialDigraph() { + vertex = null; + hasLoop = false; + loopWeight = 0; + } + + /** + * @throws UnsupportedOperationException if adding the vertex would result in having 2 vertices in the graph + * @throws IllegalArgumentException if vertex == null + */ + @Override + public boolean add(V vertex) { + if (vertex == null) { + throw new IllegalArgumentException("Cannot add null vertex!"); + } + + if (this.vertex == null) { + this.vertex = vertex; + return true; + } + + if (this.vertex.equals(vertex)) { + return false; + } + + throw new UnsupportedOperationException("TrivialDigraph must contain at most one vertex!"); + } + + @Override + public boolean contains(Object source, Object target) { + return vertex != null && hasLoop && vertex.equals(source) && vertex.equals(target); + } + + @Override + public boolean contains(Object vertex) { + return this.vertex != null && this.vertex.equals(vertex); + } + + @Override + public OptionalInt get(Object source, Object target) { + return contains(source, target) ? OptionalInt.of(loopWeight) : OptionalInt.empty(); + } + + @Override + public int getInDegree(Object vertex) { + return hasLoop ? 1 : 0; + } + + @Override + public int getOutDegree(Object vertex) { + return hasLoop ? 1 : 0; + } + + @Override + public int getEdgeCount() { + return hasLoop ? 1 : 0; + } + + @Override + public int getVertexCount() { + return vertex == null ? 0 : 1; + } + + @Override + public int totalWeight() { + return hasLoop ? loopWeight : 0; + } + + @Override + public Iterable vertices() { + if (vertex == null) { + return Collections.emptyList(); + } + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + boolean hasNext = true; + + @Override + public boolean hasNext() { + return hasNext; + } + + @Override + public V next() { + if (hasNext) { + hasNext = false; + return vertex; + } + throw new NoSuchElementException("No more vertices"); + } + + @Override + public void remove() { + if (hasNext) { + throw new IllegalStateException(); + } + TrivialDigraph.this.remove(vertex); + } + }; + } + + @Override + public String toString() { + return "[" + vertex + "]"; + } + }; + } + + @Override + public OptionalInt put(V source, V target, int loopWeight) { + if (source != target) { + throw new UnsupportedOperationException("TrivialDigraph must not contain no-loop edges!"); + } + + OptionalInt previousLoopWeight = hasLoop ? OptionalInt.of(this.loopWeight) : OptionalInt.empty(); + add(source); + this.hasLoop = true; + this.loopWeight = loopWeight; + + return previousLoopWeight; + } + + @Override + public OptionalInt remove(V source, V target) { + if (contains(source, target)) { + int loopWeight = this.loopWeight; + this.loopWeight = 0; + this.hasLoop = false; + return OptionalInt.of(loopWeight); + } + + return OptionalInt.empty(); + } + + @Override + public boolean remove(V vertex) { + if (this.vertex != null && this.vertex.equals(vertex)) { + this.vertex = null; + this.loopWeight = 0; + this.hasLoop = false; + return true; + } + + return false; + } + + @Override + public void removeAll(Collection vertices) { + if (vertices.contains(vertex)) { + remove(vertex); + } + } + + @Override + public DoubledDigraph reverse() { + return this; + } + + @Override + public Digraph subgraph(Set vertices) { + return vertex != null && vertices.contains(vertex) ? this : Digraphs.emptyDigraph(); + } + + @Override + public Iterable sources(Object target) { + return targets(target); + } + + @Override + public Iterable targets(Object source) { + if (!hasLoop || vertex == null || !vertex.equals(source)) { + return Collections.emptyList(); + } + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + boolean hasNext = true; + + @Override + public boolean hasNext() { + return hasNext; + } + + @Override + public V next() { + if (hasNext) { + hasNext = false; + return vertex; + } + throw new NoSuchElementException("No more vertices"); + } + + @Override + public void remove() { + if (hasNext) { + throw new IllegalStateException(); + } + TrivialDigraph.this.remove(vertex, vertex); + } + }; + } + + @Override + public String toString() { + return "[" + vertex + "]"; + } + }; + } + + @Override + public boolean isAcyclic() { + return !hasLoop; + } +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/UnmodifiableDigraph.java b/src/main/java/de/odysseus/ithaka/digraph/UnmodifiableDigraph.java new file mode 100644 index 000000000..29b309a32 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/UnmodifiableDigraph.java @@ -0,0 +1,71 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph; + +import java.util.Collection; +import java.util.OptionalInt; + +/** + * Unmodifiable de.odysseus.ithaka.digraph adapter. + * Overrides add, put, remove, removeAll to throw an exception. + * + * @param vertex type + */ +public class UnmodifiableDigraph extends DigraphAdapter { + public UnmodifiableDigraph(Digraph digraph) { + super(digraph); + } + + /** + * @throws UnsupportedOperationException unmodifiable + */ + @Override + public final boolean add(V vertex) { + throw new UnsupportedOperationException("This de.odysseus.ithaka.digraph is readonly!"); + } + + /** + * @throws UnsupportedOperationException unmodifiable + */ + @Override + public final OptionalInt put(V source, V target, int edge) { + throw new UnsupportedOperationException("This de.odysseus.ithaka.digraph is readonly!"); + } + + /** + * @throws UnsupportedOperationException unmodifiable + */ + @Override + public final boolean remove(V vertex) { + throw new UnsupportedOperationException("This de.odysseus.ithaka.digraph is readonly!"); + } + + /** + * @throws UnsupportedOperationException unmodifiable + */ + @Override + public final OptionalInt remove(V source, V target) { + throw new UnsupportedOperationException("This de.odysseus.ithaka.digraph is readonly!"); + } + + /** + * @throws UnsupportedOperationException unmodifiable + */ + @Override + public final void removeAll(Collection vertices) { + throw new UnsupportedOperationException("This de.odysseus.ithaka.digraph is readonly!"); + } +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/io/dot/DotAttribute.java b/src/main/java/de/odysseus/ithaka/digraph/io/dot/DotAttribute.java new file mode 100644 index 000000000..96e05a9bd --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/io/dot/DotAttribute.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph.io.dot; + +import java.awt.Color; +import java.io.IOException; +import java.io.Writer; + +public class DotAttribute { + private static boolean isIdentifier(String value) { + if (!Character.isJavaIdentifierStart(value.charAt(0))) { + return false; + } + for (char c : value.substring(1).toCharArray()) { + if (!Character.isJavaIdentifierPart(c)) { + return false; + } + } + return true; + } + + private final String name; + private final String value; + private final boolean quotes; + + public DotAttribute(String name, String value) { + this.name = name; + this.value = value; + this.quotes = !isIdentifier(value); + } + + public DotAttribute(String name, Number value) { + this.name = name; + this.value = value.toString(); + this.quotes = false; + } + + public DotAttribute(String name, boolean value) { + this.name = name; + this.value = String.valueOf(value); + this.quotes = false; + } + + public DotAttribute(String name, Color value) { + this.name = name; + this.value = String.format("#%6X", value.getRGB() & 0x00FFFFFF); + this.quotes = true; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public void write(Writer writer) throws IOException { + writer.write(name); + writer.write('='); + if (quotes) { + writer.write('"'); + } + writer.write(value); + if (quotes) { + writer.write('"'); + } + } +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/io/dot/DotExporter.java b/src/main/java/de/odysseus/ithaka/digraph/io/dot/DotExporter.java new file mode 100644 index 000000000..83e2cbcc1 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/io/dot/DotExporter.java @@ -0,0 +1,224 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph.io.dot; + +import de.odysseus.ithaka.digraph.Digraph; +import de.odysseus.ithaka.digraph.DigraphProvider; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class DotExporter { + private static class Cluster> { + String id; + G subgraph; + V sample; + DotAttribute tail; + DotAttribute head; + + public Cluster(String id, G subgraph) { + this.id = id; + this.subgraph = subgraph; + this.sample = subgraph.vertices().iterator().next(); + + this.head = new DotAttribute("lhead", id); + this.tail = new DotAttribute("ltail", id); + } + } + + private final String indent; + private final String lineSpeparator; + + public DotExporter() { + this(" ", System.getProperty("line.separator")); + } + + public DotExporter(String indent, String newline) { + this.indent = indent; + this.lineSpeparator = newline; + } + + private void indent(Writer writer, int level) throws IOException { + for (int i = 0; i < level; i++) { + writer.write(indent); + } + } + + private void writeAttributes(Writer writer, Iterator iterator) throws IOException { + if (iterator.hasNext()) { + boolean first = true; + while (iterator.hasNext()) { + if (first) { + writer.write('['); + first = false; + } else { + writer.write(", "); + } + iterator.next().write(writer); + } + writer.write(']'); + } + } + + private void writeDefaultAttributes(Writer writer, int level, String name, Iterable attributes) throws IOException { + if (attributes != null) { + indent(writer, level); + Iterator iterator = attributes.iterator(); + if (iterator.hasNext()) { + writer.write(name); + writeAttributes(writer, iterator); + } + writer.write(";"); + writer.write(lineSpeparator); + } + } + + private void writeNode(Writer writer, int level, V vertex, DotProvider provider) throws IOException { + indent(writer, level); + writer.write(provider.getNodeId(vertex)); + Iterable attributes = provider.getNodeAttributes(vertex); + if (attributes != null) { + writeAttributes(writer, attributes.iterator()); + } + writer.write(";"); + writer.write(lineSpeparator); + } + + private void writeEdge(Writer writer, int level, V source, V target, int edgeWeight, DotProvider provider, + Cluster sourceCluster, Cluster targetCluster) throws IOException { + indent(writer, level); + writer.write(provider.getNodeId(sourceCluster == null ? source : sourceCluster.sample)); + writer.write(" -> "); + writer.write(provider.getNodeId(targetCluster == null ? target : targetCluster.sample)); + Iterable attributes = provider.getEdgeAttributes(source, target, edgeWeight); + if (sourceCluster == null && targetCluster == null) { + if (attributes != null) { + writeAttributes(writer, attributes.iterator()); + } + } else { + List attributeList = new ArrayList<>(); + if (sourceCluster != null) { + attributeList.add(sourceCluster.tail); + } + if (targetCluster != null) { + attributeList.add(targetCluster.head); + } + if (attributes != null) { + for (DotAttribute attribute : attributes) { + attributeList.add(attribute); + } + } + writeAttributes(writer, attributeList.iterator()); + } + writer.write(";"); + writer.write(lineSpeparator); + } + + private > Map> createClusters( + G digraph, + DotProvider provider, + DigraphProvider subgraphs) { + Map> clusters = new HashMap<>(); + if (subgraphs != null) { + for (V vertex : digraph.vertices()) { + G subgraph = subgraphs.get(vertex); + if (subgraph != null && subgraph.getVertexCount() > 0) { + clusters.put(vertex, new Cluster<>("cluster_" + provider.getNodeId(vertex), subgraph)); + } + } + } + return clusters; + } + + public > void export( + DotProvider provider, + G digraph, + DigraphProvider subgraphs, + Writer writer) throws IOException { + + writer.write("de.odysseus.ithaka.digraph G {"); + writer.write(lineSpeparator); + + Map> clusters = createClusters(digraph, provider, subgraphs); + if (!clusters.isEmpty()) { + indent(writer, 1); + writer.write("compound=true;"); + writer.write(lineSpeparator); + } + + writeDefaultAttributes(writer, 1, "graph", provider.getDefaultGraphAttributes(digraph)); + writeDefaultAttributes(writer, 1, "node", provider.getDefaultNodeAttributes(digraph)); + writeDefaultAttributes(writer, 1, "edge", provider.getDefaultEdgeAttributes(digraph)); + + writeNodesAndEdges(writer, 1, provider, digraph, clusters, subgraphs); + + writer.write("}"); + writer.write(lineSpeparator); + + writer.flush(); + } + + private > void writeNodesAndEdges( + Writer writer, + int level, + DotProvider provider, + G digraph, + Map> clusters, + DigraphProvider subgraphs) throws IOException { + for (V vertex : digraph.vertices()) { + if (clusters.containsKey(vertex)) { + writeCluster(writer, level, provider, vertex, clusters.get(vertex), subgraphs); + } else { + writeNode(writer, level, vertex, provider); + } + } + for (V source : digraph.vertices()) { + for (V target : digraph.targets(source)) { + writeEdge(writer, level, source, target, digraph.get(source, target).getAsInt(), provider, + clusters.get(source), clusters.get(target)); + } + } + } + + private > void writeCluster( + Writer writer, + int level, + DotProvider provider, + V subgraphVertex, + Cluster cluster, + DigraphProvider subgraphs) throws IOException { + + indent(writer, level); + writer.write("subgraph "); + writer.write(cluster.id); + writer.write(" {"); + writer.write(lineSpeparator); + + writeDefaultAttributes(writer, level + 1, "graph", provider.getSubgraphAttributes(cluster.subgraph, subgraphVertex)); + + Map> subclusters = createClusters(cluster.subgraph, provider, subgraphs); + writeNodesAndEdges(writer, level + 1, provider, cluster.subgraph, subclusters, subgraphs); + + indent(writer, level); + writer.write("}"); + writer.write(lineSpeparator); + } +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/io/dot/DotProvider.java b/src/main/java/de/odysseus/ithaka/digraph/io/dot/DotProvider.java new file mode 100644 index 000000000..65e85ca47 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/io/dot/DotProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph.io.dot; + +import de.odysseus.ithaka.digraph.Digraph; + +public interface DotProvider> { + Iterable getDefaultGraphAttributes(G digraph); + + Iterable getDefaultNodeAttributes(G digraph); + + Iterable getDefaultEdgeAttributes(G digraph); + + String getNodeId(V vertex); + + Iterable getNodeAttributes(V vertex); + + Iterable getEdgeAttributes(V source, V target, int edgeWeight); + + Iterable getSubgraphAttributes(G subgraph, V vertex); +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/io/tgf/TgfExporter.java b/src/main/java/de/odysseus/ithaka/digraph/io/tgf/TgfExporter.java new file mode 100644 index 000000000..d381f5338 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/io/tgf/TgfExporter.java @@ -0,0 +1,74 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph.io.tgf; + +import de.odysseus.ithaka.digraph.Digraph; + +import java.io.IOException; +import java.io.Writer; +import java.util.HashMap; +import java.util.Map; + +public class TgfExporter { + private final String newline; + + public TgfExporter() { + this(System.getProperty("line.separator")); + } + + public TgfExporter(String newline) { + this.newline = newline; + } + + public void export( + TgfLabelProvider provider, + Digraph digraph, + Writer writer) throws IOException { + Map index = new HashMap<>(); + int n = 0; + + for (V vertex : digraph.vertices()) { + n += 1; + index.put(vertex, n); + writer.write(String.valueOf(n)); + String label = provider.getVertexLabel(vertex); + if (label != null) { + writer.write(' '); + writer.write(label); + } + writer.write(newline); + } + + writer.write('#'); + writer.write(newline); + + for (V source : digraph.vertices()) { + for (V target : digraph.targets(source)) { + writer.write(String.valueOf(index.get(source))); + writer.write(' '); + writer.write(String.valueOf(index.get(target))); + String label = provider.getEdgeLabel(digraph.get(source, target).getAsInt()); + if (label != null) { + writer.write(' '); + writer.write(label); + } + writer.write(newline); + } + } + + writer.flush(); + } +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/io/tgf/TgfLabelProvider.java b/src/main/java/de/odysseus/ithaka/digraph/io/tgf/TgfLabelProvider.java new file mode 100644 index 000000000..539db91c8 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/io/tgf/TgfLabelProvider.java @@ -0,0 +1,22 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph.io.tgf; + +public interface TgfLabelProvider { + String getVertexLabel(V vertex); + + String getEdgeLabel(int edgeWeight); +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/util/fas/AbstractFeedbackArcSetProvider.java b/src/main/java/de/odysseus/ithaka/digraph/util/fas/AbstractFeedbackArcSetProvider.java new file mode 100644 index 000000000..9fc5640e5 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/util/fas/AbstractFeedbackArcSetProvider.java @@ -0,0 +1,220 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph.util.fas; + +import de.odysseus.ithaka.digraph.Digraph; +import de.odysseus.ithaka.digraph.Digraphs; +import de.odysseus.ithaka.digraph.EdgeWeights; +import de.odysseus.ithaka.digraph.MapDigraph; + +import java.util.ArrayList; +import java.util.List; +import java.util.OptionalInt; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + * Abstract feedback arc set provider. + */ +public abstract class AbstractFeedbackArcSetProvider implements FeedbackArcSetProvider { + class FeedbackTask implements Callable> { + final Digraph digraph; + final EdgeWeights weights; + final FeedbackArcSetPolicy policy; + final Set scc; + + FeedbackTask(Digraph digraph, EdgeWeights weights, FeedbackArcSetPolicy policy, Set scc) { + this.digraph = digraph; + this.weights = weights; + this.policy = policy; + this.scc = scc; + } + + @Override + public FeedbackArcSet call() { + return fas(digraph.subgraph(scc), weights, policy); + } + } + + private final ExecutorService executor; + + /** + * Create provider which calculates a feedback arc set on a de.odysseus.ithaka.digraph (in the + * current thread). + * + * The provider decomposes a de.odysseus.ithaka.digraph into strongly connected components and computes + * feedback arc sets on the components and combines the results. + * + * The {@link #mfas(Digraph, EdgeWeights)} and {@link #lfas(Digraph, EdgeWeights)} + * implementation methods do not have to handle arbitrary digraphs for this reason. + */ + protected AbstractFeedbackArcSetProvider() { + this.executor = null; + } + + /** + * Create provider which decomposes a de.odysseus.ithaka.digraph into strongly connected components + * and computes feedback arc sets on the components and combines the results. + * Feedback calculations can be distributed to a given number of threads. + * If numberOfThreads == 0, calculation is done in the current thread. + * + * @param numberOfThreads number + */ + protected AbstractFeedbackArcSetProvider(int numberOfThreads) { + if (numberOfThreads > 0) { + this.executor = Executors.newFixedThreadPool(numberOfThreads); + } else { + this.executor = null; + } + } + + /** + * Compute minimum feedback arc set. + * + * @return feedback arc set or null + */ + protected Digraph mfas(Digraph digraph, EdgeWeights weights) { + return null; + } + + /** + * Compute light feedback arc set. + * + * @param digraph original graph or tangle of it (if decompose == true) + * @return feedback arc set + */ + protected abstract Digraph lfas(Digraph digraph, EdgeWeights weights); + + private FeedbackArcSet fas(Digraph digraph, EdgeWeights weights, FeedbackArcSetPolicy policy) { + EdgeWeights filteredWeights = weights; + if (policy == FeedbackArcSetPolicy.MIN_SIZE) { + /* + * Manipulate graph weights if the feedback arc set has to be of minimum size (i.e., #arcs): + * all weights are increased by an amount (delta) equal to the sum of all weights, + * so that every arc is heavier than any arc subset with the original weights. + * A minimum weight feedback arc set (mwfas) of the resulting graph has a total weight of + * #arcs(mwfas) * delta + origWeight(mwfas). + * Since origWeight(mwfas) < delta, the determined mwfas has a minimum #arcs and + * from all those feedback arc sets of minimum size it has minimum original weight (we could + * have obtained the first result easily by setting all weights to 1, but not the second). + */ + final EdgeWeights origWeights = weights; + final int delta = totalWeight(digraph, origWeights); + filteredWeights = new EdgeWeights() { + @Override + public OptionalInt get(V source, V target) { + OptionalInt original = origWeights.get(source, target); + + if (original.isPresent()) { + return OptionalInt.of(original.getAsInt() + delta); + } else { + return OptionalInt.empty(); + } + } + }; + } + Digraph result = mfas(digraph, filteredWeights); + boolean exact = true; + if (result == null) { + result = lfas(digraph, filteredWeights); + exact = false; + } + return new FeedbackArcSet<>(result, totalWeight(result, weights), policy, exact); + } + + protected int totalWeight(Digraph digraph, EdgeWeights weights) { + int weight = 0; + for (V source : digraph.vertices()) { + for (V target : digraph.targets(source)) { + weight += weights.get(source, target).getAsInt(); + } + } + return weight; + } + + private List> executeAll(List> tasks) { + List> result = new ArrayList<>(); + + if (executor == null) { + for (FeedbackTask task : tasks) { + result.add(task.call()); + } + } else { + try { + for (Future> future : executor.invokeAll(tasks)) { + result.add(future.get()); + } + } catch (ExecutionException | InterruptedException e) { + e.printStackTrace(); + return null; // should not happen + } + } + + return result; + } + + @Override + public FeedbackArcSet getFeedbackArcSet(Digraph digraph, EdgeWeights weights, FeedbackArcSetPolicy policy) { + if (Digraphs.isTriviallyAcyclic(digraph)) { + // known acyclic based on low vertex count + return FeedbackArcSet.empty(policy); + } + + List> components = Digraphs.scc(digraph); + + if (components.size() == digraph.getVertexCount()) { + // known acyclic based on strongly connected components + return FeedbackArcSet.empty(policy); + } + + if (components.size() == 1) { + return fas(digraph, weights, policy); + } + + List> tasks = new ArrayList<>(); + + for (Set component : components) { + if (component.size() > 1) { + tasks.add(new FeedbackTask<>(digraph, weights, policy, component)); + } + } + + List> feedbacks = executeAll(tasks); + if (feedbacks == null) { + return null; + } + + int weight = 0; + boolean exact = true; + + Digraph result = new MapDigraph<>(); + for (FeedbackArcSet feedback : feedbacks) { + for (V source : feedback.vertices()) { + for (V target : feedback.targets(source)) { + result.put(source, target, digraph.get(source, target).getAsInt()); + } + } + exact &= feedback.isExact(); + weight += feedback.getWeight(); + } + + return new FeedbackArcSet<>(result, weight, policy, exact); + } +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSet.java b/src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSet.java new file mode 100644 index 000000000..cdaaa02b4 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSet.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph.util.fas; + +import de.odysseus.ithaka.digraph.Digraph; +import de.odysseus.ithaka.digraph.Digraphs; +import de.odysseus.ithaka.digraph.UnmodifiableDigraph; + +/** + * Feedback arc set. + * + * @param vertex type + */ +public class FeedbackArcSet extends UnmodifiableDigraph { + private final FeedbackArcSetPolicy policy; + private final boolean exact; + private final int weight; + + public FeedbackArcSet(Digraph feedback, int weight, FeedbackArcSetPolicy policy, boolean exact) { + super(feedback); + this.weight = weight; + this.policy = policy; + this.exact = exact; + } + + public static FeedbackArcSet empty(FeedbackArcSetPolicy policy) { + return new FeedbackArcSet<>(Digraphs.emptyDigraph(), 0, policy, true); + } + + /** + * @return true if this FAS is known to be of minimal + */ + public boolean isExact() { + return exact; + } + + /** + * @return total weight + */ + public int getWeight() { + return weight; + } + + /** + * @return minimization policy (weight/#arcs) + */ + public FeedbackArcSetPolicy getPolicy() { + return policy; + } +} diff --git a/src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSetPolicy.java b/src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSetPolicy.java new file mode 100644 index 000000000..51de76d61 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSetPolicy.java @@ -0,0 +1,31 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph.util.fas; + +/** + * Minimization policy + */ +public enum FeedbackArcSetPolicy { + /** + * minimize number of feedback arcs + */ + MIN_SIZE, + + /** + * minimize weight of feedback arcs + */ + MIN_WEIGHT +} \ No newline at end of file diff --git a/src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSetProvider.java b/src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSetProvider.java new file mode 100644 index 000000000..c9b89cfd5 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/util/fas/FeedbackArcSetProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph.util.fas; + +import de.odysseus.ithaka.digraph.Digraph; +import de.odysseus.ithaka.digraph.EdgeWeights; + +/** + * Feedback arc set provider interface. + */ +public interface FeedbackArcSetProvider { + /** + * Calculate feedback arc set. + * + * @return feedback arc set + */ + FeedbackArcSet getFeedbackArcSet(Digraph digraph, + EdgeWeights weights, + FeedbackArcSetPolicy policy); +} \ No newline at end of file diff --git a/src/main/java/de/odysseus/ithaka/digraph/util/fas/SimpleFeedbackArcSetProvider.java b/src/main/java/de/odysseus/ithaka/digraph/util/fas/SimpleFeedbackArcSetProvider.java new file mode 100644 index 000000000..53ccd9268 --- /dev/null +++ b/src/main/java/de/odysseus/ithaka/digraph/util/fas/SimpleFeedbackArcSetProvider.java @@ -0,0 +1,174 @@ +/* + * Copyright 2012 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.odysseus.ithaka.digraph.util.fas; + +import de.odysseus.ithaka.digraph.Digraph; +import de.odysseus.ithaka.digraph.DigraphFactory; +import de.odysseus.ithaka.digraph.Digraphs; +import de.odysseus.ithaka.digraph.EdgeWeights; +import de.odysseus.ithaka.digraph.MapDigraph; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.Set; + +/** + * Simple feedback arc set provider. + */ +public class SimpleFeedbackArcSetProvider extends AbstractFeedbackArcSetProvider { + /** + * Calculate feedback arc in the current thread. + */ + public SimpleFeedbackArcSetProvider() { + super(); + } + + /** + * Calculate feedback arc set using the specified number of threads. + */ + public SimpleFeedbackArcSetProvider(int numberOfThreads) { + super(numberOfThreads); + } + + /** + * create equivalent graphs with different edge orderings. + * + * @param digraph de.odysseus.ithaka.digraph to copy + * @return list of copies + */ + private List> copies(Digraph digraph, int count) { + List> copies = new ArrayList<>(); + copies.add(digraph); + + final List shuffle = new ArrayList<>(); + final Map order = new HashMap<>(); + int index = 0; + for (V source : digraph.vertices()) { + order.put(source, index); + shuffle.add(index++); + } + + Random random = new Random(7); + for (int i = 0; i < count; i++) { + Collections.shuffle(shuffle, random); + List mapping = new ArrayList<>(shuffle); + + copies.add(Digraphs.copy(digraph, new DigraphFactory>() { + @Override + public Digraph create() { + return new MapDigraph<>(new Comparator() { + @Override + public int compare(V v1, V v2) { + int value1 = mapping.get(order.get(v1)); + int value2 = mapping.get(order.get(v2)); + return Integer.compare(value1, value2); + } + }); + } + })); + } + return copies; + } + + /** + * Compute simple feedback arc set by performing |n| DFS traversals (each starting + * with a different vertex) on the tangle, taking non-forward edges as feedback. + * The minimum weight feedback arc set among those |n| results is returned. + * + * @param tangle strongly connected component + * @param weights edge weights + * @return feedback arc set + */ + @Override + protected Digraph lfas(Digraph tangle, EdgeWeights weights) { + /* + * store best results + */ + int minWeight = Integer.MAX_VALUE; + int minSize = Integer.MAX_VALUE; + List minFinished = null; + + /* + * threshold on max. number of iterations (avoid running forever) + */ + int maxIterationsLeft = Math.max(1, 1000000 / (tangle.getVertexCount() + tangle.getEdgeCount())); + + /* + * perform DFS for each node, keep best result + */ + List> copies = copies(tangle, Math.min(10, tangle.getVertexCount())); + List finished = new ArrayList<>(tangle.getVertexCount()); + Set discovered = new HashSet<>(tangle.getVertexCount()); + for (V start : tangle.vertices()) { + for (Digraph copy : copies) { + finished.clear(); + discovered.clear(); + Digraphs.dfs(copy, start, discovered, finished); + assert finished.size() == tangle.getVertexCount(); + + int weight = 0; + int size = 0; + discovered.clear(); + for (V source : finished) { + discovered.add(source); + for (V target : tangle.targets(source)) { + if (!discovered.contains(target)) { // feedback edge + weight += weights.get(source, target).getAsInt(); + size++; + } + } + if (weight > minWeight) { + break; + } + } + if (weight < minWeight || weight == minWeight && size < minSize) { + minFinished = new ArrayList<>(finished); + minWeight = weight; + minSize = size; + } + } + if (--maxIterationsLeft == 0) { + break; + } + } + + // If the input graph has at least a single vertex, we'll get at least one result. + Objects.requireNonNull(minFinished); + + /* + * create feedback graph + */ + Digraph feedback = MapDigraph.getDefaultDigraphFactory().create(); + discovered.clear(); + for (V source : minFinished) { + discovered.add(source); + for (V target : tangle.targets(source)) { + if (!discovered.contains(target)) { // feedback edge + feedback.put(source, target, tangle.get(source, target).getAsInt()); + } + } + } + + return feedback; + } +} diff --git a/src/main/java/kroppeb/stareval/element/AccessibleExpressionElement.java b/src/main/java/kroppeb/stareval/element/AccessibleExpressionElement.java new file mode 100644 index 000000000..52975f669 --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/AccessibleExpressionElement.java @@ -0,0 +1,4 @@ +package kroppeb.stareval.element; + +public interface AccessibleExpressionElement extends ExpressionElement { +} diff --git a/src/main/java/kroppeb/stareval/element/Element.java b/src/main/java/kroppeb/stareval/element/Element.java new file mode 100644 index 000000000..6dafe5c38 --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/Element.java @@ -0,0 +1,4 @@ +package kroppeb.stareval.element; + +public interface Element { +} diff --git a/src/main/java/kroppeb/stareval/element/ExpressionElement.java b/src/main/java/kroppeb/stareval/element/ExpressionElement.java new file mode 100644 index 000000000..6fa53b100 --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/ExpressionElement.java @@ -0,0 +1,4 @@ +package kroppeb.stareval.element; + +public interface ExpressionElement extends Element { +} diff --git a/src/main/java/kroppeb/stareval/element/PriorityOperatorElement.java b/src/main/java/kroppeb/stareval/element/PriorityOperatorElement.java new file mode 100644 index 000000000..e2f323d9f --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/PriorityOperatorElement.java @@ -0,0 +1,7 @@ +package kroppeb.stareval.element; + +public interface PriorityOperatorElement extends Element { + int getPriority(); + + ExpressionElement resolveWith(ExpressionElement right); +} diff --git a/src/main/java/kroppeb/stareval/element/token/BinaryOperatorToken.java b/src/main/java/kroppeb/stareval/element/token/BinaryOperatorToken.java new file mode 100644 index 000000000..1566a4f28 --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/token/BinaryOperatorToken.java @@ -0,0 +1,16 @@ +package kroppeb.stareval.element.token; + +import kroppeb.stareval.parser.BinaryOp; + +public class BinaryOperatorToken extends Token { + public final BinaryOp op; + + public BinaryOperatorToken(BinaryOp op) { + this.op = op; + } + + @Override + public String toString() { + return "BinaryOp{" + this.op + "}"; + } +} diff --git a/src/main/java/kroppeb/stareval/element/token/IdToken.java b/src/main/java/kroppeb/stareval/element/token/IdToken.java new file mode 100644 index 000000000..b85061365 --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/token/IdToken.java @@ -0,0 +1,20 @@ +package kroppeb.stareval.element.token; + +import kroppeb.stareval.element.AccessibleExpressionElement; + +public class IdToken extends Token implements AccessibleExpressionElement { + private final String id; + + public IdToken(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + @Override + public String toString() { + return "Id{" + this.id + "}"; + } +} diff --git a/src/main/java/kroppeb/stareval/element/token/NumberToken.java b/src/main/java/kroppeb/stareval/element/token/NumberToken.java new file mode 100644 index 000000000..1f6cfbef4 --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/token/NumberToken.java @@ -0,0 +1,20 @@ +package kroppeb.stareval.element.token; + +import kroppeb.stareval.element.ExpressionElement; + +public class NumberToken extends Token implements ExpressionElement { + private final String number; + + public NumberToken(String number) { + this.number = number; + } + + public String getNumber() { + return number; + } + + @Override + public String toString() { + return "Number{" + this.number + "}"; + } +} diff --git a/src/main/java/kroppeb/stareval/element/token/Token.java b/src/main/java/kroppeb/stareval/element/token/Token.java new file mode 100644 index 000000000..b302aa73c --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/token/Token.java @@ -0,0 +1,8 @@ +package kroppeb.stareval.element.token; + +import kroppeb.stareval.element.Element; + +public abstract class Token implements Element { + @Override + public abstract String toString(); +} diff --git a/src/main/java/kroppeb/stareval/element/token/UnaryOperatorToken.java b/src/main/java/kroppeb/stareval/element/token/UnaryOperatorToken.java new file mode 100644 index 000000000..da3e84aee --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/token/UnaryOperatorToken.java @@ -0,0 +1,29 @@ +package kroppeb.stareval.element.token; + +import kroppeb.stareval.element.ExpressionElement; +import kroppeb.stareval.element.PriorityOperatorElement; +import kroppeb.stareval.element.tree.UnaryExpressionElement; +import kroppeb.stareval.parser.UnaryOp; + +public class UnaryOperatorToken extends Token implements PriorityOperatorElement { + private final UnaryOp op; + + public UnaryOperatorToken(UnaryOp op) { + this.op = op; + } + + @Override + public String toString() { + return "UnaryOp{" + this.op + "}"; + } + + @Override + public int getPriority() { + return -1; + } + + @Override + public UnaryExpressionElement resolveWith(ExpressionElement right) { + return new UnaryExpressionElement(this.op, right); + } +} diff --git a/src/main/java/kroppeb/stareval/element/tree/AccessExpressionElement.java b/src/main/java/kroppeb/stareval/element/tree/AccessExpressionElement.java new file mode 100644 index 000000000..033303a2a --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/tree/AccessExpressionElement.java @@ -0,0 +1,26 @@ +package kroppeb.stareval.element.tree; + +import kroppeb.stareval.element.AccessibleExpressionElement; + +public class AccessExpressionElement implements AccessibleExpressionElement { + private final AccessibleExpressionElement base; + private final String index; + + public AccessExpressionElement(AccessibleExpressionElement base, String index) { + this.base = base; + this.index = index; + } + + public AccessibleExpressionElement getBase() { + return this.base; + } + + public String getIndex() { + return this.index; + } + + @Override + public String toString() { + return "Access{" + this.base + "[" + this.index + "]}"; + } +} diff --git a/src/main/java/kroppeb/stareval/element/tree/BinaryExpressionElement.java b/src/main/java/kroppeb/stareval/element/tree/BinaryExpressionElement.java new file mode 100644 index 000000000..ded159e6f --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/tree/BinaryExpressionElement.java @@ -0,0 +1,33 @@ +package kroppeb.stareval.element.tree; + +import kroppeb.stareval.element.ExpressionElement; +import kroppeb.stareval.parser.BinaryOp; + +public class BinaryExpressionElement implements ExpressionElement { + private final BinaryOp op; + private final ExpressionElement left; + private final ExpressionElement right; + + public BinaryExpressionElement(BinaryOp op, ExpressionElement left, ExpressionElement right) { + this.op = op; + this.left = left; + this.right = right; + } + + public BinaryOp getOp() { + return this.op; + } + + public ExpressionElement getLeft() { + return this.left; + } + + public ExpressionElement getRight() { + return this.right; + } + + @Override + public String toString() { + return "BinaryExpr{ {" + this.left + "} " + this.op + " {" + this.right + "} }"; + } +} diff --git a/src/main/java/kroppeb/stareval/element/tree/FunctionCall.java b/src/main/java/kroppeb/stareval/element/tree/FunctionCall.java new file mode 100644 index 000000000..12bb8ab07 --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/tree/FunctionCall.java @@ -0,0 +1,28 @@ +package kroppeb.stareval.element.tree; + +import kroppeb.stareval.element.ExpressionElement; + +import java.util.List; + +public class FunctionCall implements ExpressionElement { + private final String id; + private final List args; + + public FunctionCall(String id, List args) { + this.id = id; + this.args = args; + } + + public String getId() { + return this.id; + } + + public List getArgs() { + return this.args; + } + + @Override + public String toString() { + return "FunctionCall{" + this.id + " {" + this.args + "} }"; + } +} diff --git a/src/main/java/kroppeb/stareval/element/tree/UnaryExpressionElement.java b/src/main/java/kroppeb/stareval/element/tree/UnaryExpressionElement.java new file mode 100644 index 000000000..4126b549a --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/tree/UnaryExpressionElement.java @@ -0,0 +1,27 @@ +package kroppeb.stareval.element.tree; + +import kroppeb.stareval.element.ExpressionElement; +import kroppeb.stareval.parser.UnaryOp; + +public class UnaryExpressionElement implements ExpressionElement { + private final UnaryOp op; + private final ExpressionElement inner; + + public UnaryExpressionElement(UnaryOp op, ExpressionElement inner) { + this.op = op; + this.inner = inner; + } + + public UnaryOp getOp() { + return op; + } + + public ExpressionElement getInner() { + return inner; + } + + @Override + public String toString() { + return "UnaryExpr{" + this.op + " {" + this.inner + "} }"; + } +} diff --git a/src/main/java/kroppeb/stareval/element/tree/partial/PartialBinaryExpression.java b/src/main/java/kroppeb/stareval/element/tree/partial/PartialBinaryExpression.java new file mode 100644 index 000000000..ae6041c37 --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/tree/partial/PartialBinaryExpression.java @@ -0,0 +1,31 @@ +package kroppeb.stareval.element.tree.partial; + +import kroppeb.stareval.element.ExpressionElement; +import kroppeb.stareval.element.PriorityOperatorElement; +import kroppeb.stareval.element.tree.BinaryExpressionElement; +import kroppeb.stareval.parser.BinaryOp; + +public class PartialBinaryExpression extends PartialExpression implements PriorityOperatorElement { + private final ExpressionElement left; + private final BinaryOp op; + + public PartialBinaryExpression(ExpressionElement left, BinaryOp op) { + this.left = left; + this.op = op; + } + + @Override + public String toString() { + return "PartialBinaryExpression{ {" + this.left + "} " + this.op + "}"; + } + + @Override + public int getPriority() { + return this.op.getPriority(); + } + + @Override + public BinaryExpressionElement resolveWith(ExpressionElement right) { + return new BinaryExpressionElement(this.op, this.left, right); + } +} diff --git a/src/main/java/kroppeb/stareval/element/tree/partial/PartialExpression.java b/src/main/java/kroppeb/stareval/element/tree/partial/PartialExpression.java new file mode 100644 index 000000000..83512faad --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/tree/partial/PartialExpression.java @@ -0,0 +1,8 @@ +package kroppeb.stareval.element.tree.partial; + +import kroppeb.stareval.element.Element; + +public abstract class PartialExpression implements Element { + @Override + public abstract String toString(); +} diff --git a/src/main/java/kroppeb/stareval/element/tree/partial/UnfinishedArgsExpression.java b/src/main/java/kroppeb/stareval/element/tree/partial/UnfinishedArgsExpression.java new file mode 100644 index 000000000..b0b5d3691 --- /dev/null +++ b/src/main/java/kroppeb/stareval/element/tree/partial/UnfinishedArgsExpression.java @@ -0,0 +1,15 @@ +package kroppeb.stareval.element.tree.partial; + +import kroppeb.stareval.element.ExpressionElement; + +import java.util.ArrayList; +import java.util.List; + +public class UnfinishedArgsExpression extends PartialExpression { + public final List tokens = new ArrayList<>(); + + @Override + public String toString() { + return "UnfinishedArgs{" + this.tokens + "}"; + } +} diff --git a/src/main/java/kroppeb/stareval/exception/MissingTokenException.java b/src/main/java/kroppeb/stareval/exception/MissingTokenException.java new file mode 100644 index 000000000..ade5fbf04 --- /dev/null +++ b/src/main/java/kroppeb/stareval/exception/MissingTokenException.java @@ -0,0 +1,7 @@ +package kroppeb.stareval.exception; + +public class MissingTokenException extends ParseException { + public MissingTokenException(String message, int index) { + super(message + " at index " + index); + } +} diff --git a/src/main/java/kroppeb/stareval/exception/ParseException.java b/src/main/java/kroppeb/stareval/exception/ParseException.java new file mode 100644 index 000000000..3a4f56106 --- /dev/null +++ b/src/main/java/kroppeb/stareval/exception/ParseException.java @@ -0,0 +1,22 @@ +package kroppeb.stareval.exception; + +public abstract class ParseException extends Exception{ + public ParseException() { + } + + public ParseException(String message) { + super(message); + } + + public ParseException(String message, Throwable cause) { + super(message, cause); + } + + public ParseException(Throwable cause) { + super(cause); + } + + public ParseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/kroppeb/stareval/exception/UnexpectedCharacterException.java b/src/main/java/kroppeb/stareval/exception/UnexpectedCharacterException.java new file mode 100644 index 000000000..9de12af20 --- /dev/null +++ b/src/main/java/kroppeb/stareval/exception/UnexpectedCharacterException.java @@ -0,0 +1,19 @@ +package kroppeb.stareval.exception; + +public class UnexpectedCharacterException extends ParseException { + public UnexpectedCharacterException(char expected, char actual, int index) { + this("Expected to read '" + expected + "' but got '" + actual + "' at index " + index); + } + + public UnexpectedCharacterException(char actual, int index) { + this("Read an unexpected character '" + actual + "' at index " + index); + } + + public UnexpectedCharacterException(String expected, char actual, int index) { + this("Expected to read " + expected + " but got '" + actual + "' at index " + index); + } + + private UnexpectedCharacterException(String message) { + super(message); + } +} diff --git a/src/main/java/kroppeb/stareval/exception/UnexpectedEndingException.java b/src/main/java/kroppeb/stareval/exception/UnexpectedEndingException.java new file mode 100644 index 000000000..1b2135bbd --- /dev/null +++ b/src/main/java/kroppeb/stareval/exception/UnexpectedEndingException.java @@ -0,0 +1,11 @@ +package kroppeb.stareval.exception; + +public class UnexpectedEndingException extends ParseException { + public UnexpectedEndingException() { + this("Expected to read more text, but the string has ended"); + } + + public UnexpectedEndingException(String message) { + super(message); + } +} diff --git a/src/main/java/kroppeb/stareval/exception/UnexpectedTokenException.java b/src/main/java/kroppeb/stareval/exception/UnexpectedTokenException.java new file mode 100644 index 000000000..d395cc498 --- /dev/null +++ b/src/main/java/kroppeb/stareval/exception/UnexpectedTokenException.java @@ -0,0 +1,7 @@ +package kroppeb.stareval.exception; + +public class UnexpectedTokenException extends ParseException { + public UnexpectedTokenException(String message, int index) { + super(message + " at index " + index); + } +} diff --git a/src/main/java/kroppeb/stareval/parser/BinaryOp.java b/src/main/java/kroppeb/stareval/parser/BinaryOp.java new file mode 100644 index 000000000..41bf081a7 --- /dev/null +++ b/src/main/java/kroppeb/stareval/parser/BinaryOp.java @@ -0,0 +1,20 @@ +package kroppeb.stareval.parser; + +public class BinaryOp { + private final String name; + private final int priority; + + public BinaryOp(String name, int priority) { + this.name = name; + this.priority = priority; + } + + @Override + public String toString() { + return this.name + "{" + this.priority + "}"; + } + + public int getPriority() { + return this.priority; + } +} diff --git a/src/main/java/kroppeb/stareval/parser/OpResolver.java b/src/main/java/kroppeb/stareval/parser/OpResolver.java new file mode 100644 index 000000000..e9ada48bd --- /dev/null +++ b/src/main/java/kroppeb/stareval/parser/OpResolver.java @@ -0,0 +1,157 @@ +package kroppeb.stareval.parser; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import kroppeb.stareval.exception.ParseException; + +import java.util.Map; + +/** + * OpResolver maps the trailing characters identifying an operator to an actual operator. + * @param + */ +abstract class OpResolver { + abstract T resolve(StringReader input) throws ParseException; + + static class Builder { + private final Map map; + + public Builder() { + map = new Object2ObjectOpenHashMap<>(); + } + + public void singleChar(T op) { + multiChar("", op); + } + + /** + * Adds a new multi-character operator. Calling this with an empty string is equivalent to calling singleChar. + * + * @param trailing every character after the first character of the operator. + * @param op the operator + */ + public void multiChar(String trailing, T op) { + T previous = map.put(trailing, op); + + if (previous != null) { + throw new RuntimeException("Tried to add multiple operators that map to the same string."); + } + } + + public OpResolver build() { + if (map.size() > 2) { + throw new RuntimeException("unimplemented: Cannot currently build an optimized operator resolver " + + "tree when more than two operators start with the same character"); + } + + T singleChar = map.get(""); + + if (singleChar != null) { + if (map.size() == 1) { + return new SingleChar<>(singleChar); + } else { + for (Map.Entry subEntry : map.entrySet()) { + if ("".equals(subEntry.getKey())) { + // We already checked this key + continue; + } + + if (subEntry.getKey().length() != 1) { + throw new RuntimeException("unimplemented: Optimized operator resolver trees can " + + "currently only be built of operators that contain one or two characters."); + } + + // We can assume that this is the only other entry in the map due to the size check above + return new SingleDualChar<>( + singleChar, + subEntry.getValue(), + subEntry.getKey().charAt(0) + ); + } + } + } else { + if (map.size() > 1) { + throw new RuntimeException("unimplemented: Optimized operator resolver trees can currently only " + + "handle two operators starting with the same character if one operator is a single character"); + } + + for (Map.Entry subEntry : map.entrySet()) { + if (subEntry.getKey().length() != 1) { + throw new RuntimeException("unimplemented: Optimized operator resolver trees can " + + "currently only be built of operators that contain one or two characters."); + } + + // We can assume that this is the only entry in the map due to the size check above. + return new DualChar<>( + subEntry.getValue(), + subEntry.getKey().charAt(0) + ); + } + } + + if (map.isEmpty()) { + throw new RuntimeException("Tried to build an operator resolver tree that contains no operators."); + } else { + throw new RuntimeException("This shouldn't be reachable"); + } + } + } + + /** + * Matches a single-character operator. + */ + static class SingleChar extends OpResolver { + private final T op; + + SingleChar(T op) { + this.op = op; + } + + @Override + T resolve(StringReader input) { + return this.op; + } + } + + /** + * Matches a two-character operator. + */ + static class DualChar extends OpResolver { + private final T op; + private final char secondChar; + + DualChar(T op, char secondChar) { + this.op = op; + this.secondChar = secondChar; + } + + @Override + T resolve(StringReader input) throws ParseException { + input.read(this.secondChar); + return this.op; + } + } + + /** + * Matches either a dual character operator or a single character operator. + */ + static class SingleDualChar extends OpResolver { + private final T singleCharOperator; + private final T doubleCharOperator; + private final char secondChar; + + SingleDualChar(T singleCharOperator, T doubleCharOperator, char secondChar) { + this.singleCharOperator = singleCharOperator; + this.doubleCharOperator = doubleCharOperator; + this.secondChar = secondChar; + } + + @Override + T resolve(StringReader input) { + if (input.tryRead(this.secondChar)) { + return this.doubleCharOperator; + } else { + return this.singleCharOperator; + } + } + } +} diff --git a/src/main/java/kroppeb/stareval/parser/Parser.java b/src/main/java/kroppeb/stareval/parser/Parser.java new file mode 100644 index 000000000..4824c6f48 --- /dev/null +++ b/src/main/java/kroppeb/stareval/parser/Parser.java @@ -0,0 +1,315 @@ +package kroppeb.stareval.parser; + +import kroppeb.stareval.element.AccessibleExpressionElement; +import kroppeb.stareval.element.Element; +import kroppeb.stareval.element.ExpressionElement; +import kroppeb.stareval.element.PriorityOperatorElement; +import kroppeb.stareval.element.token.BinaryOperatorToken; +import kroppeb.stareval.element.token.IdToken; +import kroppeb.stareval.element.token.NumberToken; +import kroppeb.stareval.element.token.UnaryOperatorToken; +import kroppeb.stareval.element.tree.AccessExpressionElement; +import kroppeb.stareval.element.tree.BinaryExpressionElement; +import kroppeb.stareval.element.tree.FunctionCall; +import kroppeb.stareval.element.tree.UnaryExpressionElement; +import kroppeb.stareval.element.tree.partial.PartialBinaryExpression; +import kroppeb.stareval.element.tree.partial.UnfinishedArgsExpression; +import kroppeb.stareval.exception.MissingTokenException; +import kroppeb.stareval.exception.ParseException; +import kroppeb.stareval.exception.UnexpectedTokenException; + +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * A parser for parsing expressions with operator precedences. + *

+ * I can't actually find a parser type on wikipedia that matches this type of parser + *

+ * The following parser is a bottom-up parser, meaning that the input tokens get combined into elements + * which then get merged with other elements and tokens until a valid expression is formed, or an expression + * is thrown. + *

+ * The uniqueness of this parser lies in how it handles operator precedence without using any lookahead, instead any + * binary operators trigger a simplification on the left-hand side of the operator until the left-hand side has a + * precedence that is strictly higher than the new operator (assuming any expression that is not operator-based is the + * highest possible precedence, eg: function calls, numbers and brackets). Note that making this relationship require + * higher or equal, would make the operator right associative instead of left associative, in case that is ever needed. + *

+ * Once the left-hand side of a binary operator has been sufficiently combined, the operator is combined with the + * expression and is converted into a "partial binary expression" which acts like a unary operator with the precedence + * level. The comments inside {@link #visitBinaryOperator} show a few cases on what this reduction does with a given + * stack. + *

+ * The parsing of brackets is a bit strange, and due to the fact this documentation has been written 5 months after I + * made the design decision and 3 months after my latest code change, I can't fully explain why I put mutable state + * inside one of the elements of the parser, as it does not provide any significant speedup that I could think of. + *

+ * When an opening parenthesis is encountered, an "unfinished argument list" is pushed to the stack. Any comma will + * fully combine the expression on the left of the comma and push it to that list. When a closing parenthesis is + * encountered, a similar reduction is performed if the top of the stack is an expression. Then the parser checks if + * the top of the stack is a Identifier, if so, this is a call expression, otherwise it is simply a bracketed expression + *

+ * + * @author Kroppeb + */ +public class Parser { + private final List stack = new ArrayList<>(); + + Parser() { + } + + private Element peek() { + if (!this.stack.isEmpty()) { + return this.stack.get(this.stack.size() - 1); + } + + return null; + } + + private Element pop() { + if (this.stack.isEmpty()) { + throw new IllegalStateException("Internal token stack is empty"); + } + + return this.stack.remove(this.stack.size() - 1); + } + + private void push(Element element) { + this.stack.add(element); + } + + /** + * @throws ClassCastException if the top is not an expression + * @see #expressionReducePop(int) + */ + private ExpressionElement expressionReducePop() { + return this.expressionReducePop(Integer.MAX_VALUE); + } + + /** + * Pops an expression after trying to reduce the stack. + * Executes following reduce steps: + *
    + *
  • {@link PriorityOperatorElement}, {@link ExpressionElement} => {@link ExpressionElement} + * as long as the {@code priority} of the {@link PriorityOperatorElement} is stricter than the given priority
  • + *
+ * + * @throws ClassCastException if the top is not an expression + */ + private ExpressionElement expressionReducePop(int priority) { + ExpressionElement token = (ExpressionElement) this.pop(); + + while (!this.stack.isEmpty()) { + Element x = this.peek(); + + if (x instanceof PriorityOperatorElement && ((PriorityOperatorElement) x).getPriority() <= priority) { + this.pop(); + token = ((PriorityOperatorElement) x).resolveWith(token); + } else { + break; + } + } + + return token; + } + + /** + * Executes following reduce step: + *
    + *
  • {@link UnfinishedArgsExpression}, {@link #expressionReducePop} => {@link UnfinishedArgsExpression}
  • + *
+ * + * @param index the current reader index, for exception throwing. + * @throws ClassCastException if the top is not an expression + */ + private void commaReduce(int index) throws ParseException { + // ( expr, + // UnfinishedArgs Expression (commaReduce) + // => UnfinishedArgs + + ExpressionElement expr = this.expressionReducePop(); + Element args = this.peek(); + + if (args == null) { + throw new MissingTokenException( + "Expected an opening bracket '(' before seeing a comma ',' or closing bracket ')'", + index + ); + } + + if (args instanceof UnfinishedArgsExpression) { + ((UnfinishedArgsExpression) args).tokens.add(expr); + } else { + throw new UnexpectedTokenException( + "Expected to see an opening bracket '(' or a comma ',' right before an expression followed by a " + + "closing bracket ')' or a comma ','", index); + } + } + + // visitor methods + + void visitId(String id) { + this.push(new IdToken(id)); + } + + boolean canReadAccess() { + return this.peek() instanceof AccessibleExpressionElement; + } + + /** + * Assumes `canReadAccess` has returned true + */ + void visitAccess(String access) { + AccessibleExpressionElement pop = (AccessibleExpressionElement) this.pop(); + this.push(new AccessExpressionElement(pop, access)); + } + + void visitNumber(String numberString) { + this.push(new NumberToken(numberString)); + } + + void visitOpeningParenthesis() { + this.push(new UnfinishedArgsExpression()); + } + + void visitComma(int index) throws ParseException { + if (this.peek() instanceof ExpressionElement) { + this.commaReduce(index); + } else { + throw new UnexpectedTokenException("Expected an expression before a comma ','", index); + } + } + + /** + * Allows for trailing comma. + * Executes following reduce steps: + *
    + *
  • {@link IdToken} {@link UnfinishedArgsExpression}, {@link #expressionReducePop} => {@link FunctionCall}
  • + *
  • {@link IdToken} {@link UnfinishedArgsExpression} => {@link FunctionCall}
  • + *
  • {@link UnfinishedArgsExpression}, {@link #expressionReducePop} => {@link ExpressionElement}
  • + *
+ * + * @param index the current reader index, for exception throwing. + */ + void visitClosingParenthesis(int index) throws ParseException { + // + // ( ... ) + // UnfinishedArgsExpression Expression? (callReduce) + + boolean expressionOnTop = this.peek() instanceof ExpressionElement; + if (expressionOnTop) { + this.commaReduce(index); + } + + UnfinishedArgsExpression args; + { + if (this.stack.isEmpty()) { + throw new MissingTokenException("A closing bracket ')' can't be the first character of an expression", index); + } + + Element pop = this.pop(); + + if (!(pop instanceof UnfinishedArgsExpression)) { + throw new UnexpectedTokenException( + "Expected to see an opening bracket '(' or a comma ',' right before an expression followed by a " + + "closing bracket ')' or a comma ','", index); + } + args = (UnfinishedArgsExpression) pop; + } + + Element top = this.peek(); + + if (top instanceof IdToken) { + this.pop(); + this.push(new FunctionCall(((IdToken) top).getId(), args.tokens)); + } else { + if (args.tokens.isEmpty()) { + throw new MissingTokenException("Encountered empty brackets that aren't a call", index); + } else if (args.tokens.size() > 1) { + throw new UnexpectedTokenException("Encountered too many expressions in brackets that aren't a call", index); + } else if (!expressionOnTop) { + throw new UnexpectedTokenException("Encountered a trailing comma in brackets that aren't a call", index); + } else { + this.push(args.tokens.get(0)); + } + } + } + + boolean canReadBinaryOp() { + return this.peek() instanceof ExpressionElement; + } + + /** + * Executes following reduce steps: + *
    + *
  • {@link ExpressionElement} | {@link BinaryOperatorToken} => {@link PartialBinaryExpression}
  • + *
  • {@link UnaryOperatorToken}, {@link ExpressionElement} | {@link BinaryOperatorToken} => {@link UnaryExpressionElement} | {@link BinaryOperatorToken}
  • + *
  • + * {@link PartialBinaryExpression}, {@link ExpressionElement} | {@link BinaryOperatorToken}
    + * where the operator on the stack has a higher or equal priority to the one being added, the 3 items on the + * stack get popped, merged to a {@link BinaryExpressionElement} and placed on the stack. + * The new token is then pushed again. + *
  • + *
+ */ + void visitBinaryOperator(BinaryOp binaryOp) { + // reduce the expressions to the needed priority level + ExpressionElement left = this.expressionReducePop(binaryOp.getPriority()); + // stack[ {'a', '*'}, 'b'], token = '+' -> stack[], left = {'a', '*', 'b'} + // -> stack[{{'a', '*', 'b'}, '+'}] + // stack[ {'a', '+'}, 'b'], token = '+' -> stack[], left = {'a', '+', 'b'} + // -> stack[{{'a', '+', 'b'}, '+'}] + // stack[ { '-'}, 'b'], token = '+' -> stack[], left = {'-', 'b'} + // -> stack[{{ '-', 'b'}, '+'}] + + // stack[ {'a', '+'}, 'b'], token = '*' -> stack[{'a', '+'}], left = {'b'} + // -> stack[{'a', '+'}, {'b', '*'}] + + this.stack.add(new PartialBinaryExpression(left, binaryOp)); + } + + void visitUnaryOperator(UnaryOp unaryOp) { + this.push(new UnaryOperatorToken(unaryOp)); + } + + ExpressionElement getFinal(int endIndex) throws ParseException { + if (!this.stack.isEmpty()) { + if (this.peek() instanceof ExpressionElement) { + ExpressionElement result = this.expressionReducePop(); + + if (this.stack.isEmpty()) { + return result; + } + + if (this.peek() instanceof UnfinishedArgsExpression) { + throw new MissingTokenException("Expected a closing bracket", endIndex); + } else { + throw new UnexpectedTokenException( + "The stack of tokens isn't empty at the end of the expression: " + this.stack + + " top: " + result, endIndex); + } + } else { + Element top = this.peek(); + if (top instanceof UnfinishedArgsExpression) { + throw new MissingTokenException("Expected a closing bracket", endIndex); + } else if (top instanceof PriorityOperatorElement) { + throw new MissingTokenException( + "Expected a identifier, constant or subexpression on the right side of the operator", + endIndex); + } else { + throw new UnexpectedTokenException( + "The stack of tokens contains an unexpected token at the top: " + this.stack, + endIndex); + } + } + } else { + throw new MissingTokenException("The input seems to be empty", endIndex); + } + } + + public static ExpressionElement parse(String input, ParserOptions options) throws ParseException { + return Tokenizer.parse(input, options); + } +} diff --git a/src/main/java/kroppeb/stareval/parser/ParserOptions.java b/src/main/java/kroppeb/stareval/parser/ParserOptions.java new file mode 100644 index 000000000..2c3ee04ed --- /dev/null +++ b/src/main/java/kroppeb/stareval/parser/ParserOptions.java @@ -0,0 +1,119 @@ +package kroppeb.stareval.parser; + +import it.unimi.dsi.fastutil.chars.Char2ObjectMap; +import it.unimi.dsi.fastutil.chars.Char2ObjectOpenHashMap; + +public final class ParserOptions { + private final Char2ObjectMap> unaryOpResolvers; + private final Char2ObjectMap> binaryOpResolvers; + private final TokenRules tokenRules; + + private ParserOptions( + Char2ObjectMap> unaryOpResolvers, + Char2ObjectMap> binaryOpResolvers, + TokenRules tokenRules) { + this.unaryOpResolvers = unaryOpResolvers; + this.binaryOpResolvers = binaryOpResolvers; + this.tokenRules = tokenRules; + } + + TokenRules getTokenRules() { + return this.tokenRules; + } + + OpResolver getUnaryOpResolver(char c) { + return this.unaryOpResolvers.get(c); + } + + OpResolver getBinaryOpResolver(char c) { + return this.binaryOpResolvers.get(c); + } + + public static class Builder { + private final Char2ObjectMap> unaryOpResolvers = new Char2ObjectOpenHashMap<>(); + private final Char2ObjectMap> binaryOpResolvers = new Char2ObjectOpenHashMap<>(); + private TokenRules tokenRules = TokenRules.DEFAULT; + + public void addUnaryOp(String s, UnaryOp op) { + char first = s.charAt(0); + String trailing = s.substring(1); + + this.unaryOpResolvers.computeIfAbsent(first, (c) -> new OpResolver.Builder<>()).multiChar(trailing, op); + } + + public void addBinaryOp(String s, BinaryOp op) { + char first = s.charAt(0); + String trailing = s.substring(1); + + this.binaryOpResolvers.computeIfAbsent(first, (c) -> new OpResolver.Builder<>()).multiChar(trailing, op); + } + + public void setTokenRules(TokenRules tokenRules) { + this.tokenRules = tokenRules; + } + + private static Char2ObjectMap> buildOpResolvers( + Char2ObjectMap> ops) { + Char2ObjectMap> result = new Char2ObjectOpenHashMap<>(); + + ops.char2ObjectEntrySet().forEach( + entry -> result.put(entry.getCharKey(), entry.getValue().build())); + + return result; + } + + public ParserOptions build() { + return new ParserOptions( + buildOpResolvers(this.unaryOpResolvers), + buildOpResolvers(this.binaryOpResolvers), + this.tokenRules); + } + } + + /** + * Defines a set of rules that allows the tokenizer to identify tokens within a string. + */ + public interface TokenRules { + TokenRules DEFAULT = new TokenRules() {}; + + static boolean isNumber(final char c) { + return c >= '0' && c <= '9'; + } + + static boolean isLowerCaseLetter(final char c) { + return c >= 'a' && c <= 'z'; + } + + static boolean isUpperCaseLetter(final char c) { + return c >= 'A' && c <= 'Z'; + } + + static boolean isLetter(final char c) { + return isLowerCaseLetter(c) || isUpperCaseLetter(c); + } + + default boolean isIdStart(final char c) { + return isLetter(c) || c == '_'; + } + + default boolean isIdPart(final char c) { + return this.isIdStart(c) || isNumber(c); + } + + default boolean isNumberStart(final char c) { + return isNumber(c) || c == '.'; + } + + default boolean isNumberPart(final char c) { + return this.isNumberStart(c) || isLetter(c); + } + + default boolean isAccessStart(final char c) { + return this.isIdStart(c) || isNumber(c); + } + + default boolean isAccessPart(final char c) { + return this.isAccessStart(c); + } + } +} diff --git a/src/main/java/kroppeb/stareval/parser/StringReader.java b/src/main/java/kroppeb/stareval/parser/StringReader.java new file mode 100644 index 000000000..9c2c6a0e2 --- /dev/null +++ b/src/main/java/kroppeb/stareval/parser/StringReader.java @@ -0,0 +1,138 @@ +package kroppeb.stareval.parser; + +import kroppeb.stareval.exception.UnexpectedCharacterException; + +/** + * A class to facilitate the reading of strings. + */ +public class StringReader { + /** + * The string we are reading + */ + private final String string; + /** + * The next index to read at + */ + private int nextIndex = -1; + /** + * The last index read + */ + private int lastIndex; + /** + * The start of {@link #substring()} + */ + private int mark; + + + public StringReader(String string) { + this.string = string; + this.advanceOneCharacter(); + this.skipWhitespace(); + + // Initializing these variables to the actual start of the string. + this.lastIndex = this.nextIndex; + this.mark(); + } + + /** + * moves the indexes, nextIndex will skip all spaces. + */ + private void advanceOneCharacter() { + this.lastIndex = this.nextIndex; + + if (this.nextIndex >= this.string.length()) { + return; + } + + this.nextIndex++; + } + + /** + * Skips all whitespace characters until a non-whitespace character is encountered. + */ + public void skipWhitespace() { + while (this.nextIndex < this.string.length() && Character.isWhitespace(this.string.charAt(this.nextIndex))) { + this.nextIndex++; + } + } + + /** + * @return The character that would be returned by the next call to {@link #read} + */ + public char peek() { + return this.string.charAt(this.nextIndex); + } + + /** + * Skips the current character + */ + public void skipOneCharacter() { + this.advanceOneCharacter(); + } + + /** + * Read a character + */ + public char read() { + char current = this.peek(); + this.skipOneCharacter(); + return current; + } + + /** + * Read a character and verify it's the expected character. + */ + public void read(char c) throws UnexpectedCharacterException { + char read = this.read(); + + if (read != c) { + throw new UnexpectedCharacterException(c, read, this.getCurrentIndex()); + } + } + + /** + * Try to read a character. + * + * @param c the character to read + * @return whether it could read the character. + */ + public boolean tryRead(char c) { + if (!this.canRead()) { + return false; + } + + char read = this.peek(); + + if (read != c) { + return false; + } + + this.skipOneCharacter(); + return true; + } + + /** + * Place a mark at the character that just got read. Used for {@link #substring()} + */ + public void mark() { + this.mark = this.lastIndex; + } + + /** + * @return a string, starting at the last call to {@link #mark()}, up to and including the last read character + */ + public String substring() { + return this.string.substring(this.mark, this.lastIndex + 1); + } + + /** + * @return whether there is more text to read. + */ + public boolean canRead() { + return this.nextIndex < this.string.length(); + } + + public int getCurrentIndex() { + return this.lastIndex; + } +} diff --git a/src/main/java/kroppeb/stareval/parser/Tokenizer.java b/src/main/java/kroppeb/stareval/parser/Tokenizer.java new file mode 100644 index 000000000..7d1535022 --- /dev/null +++ b/src/main/java/kroppeb/stareval/parser/Tokenizer.java @@ -0,0 +1,107 @@ +package kroppeb.stareval.parser; + +import kroppeb.stareval.element.ExpressionElement; +import kroppeb.stareval.exception.ParseException; +import kroppeb.stareval.exception.UnexpectedCharacterException; +import kroppeb.stareval.exception.UnexpectedEndingException; + +class Tokenizer { + private Tokenizer() { + } + + static ExpressionElement parse(String input, ParserOptions options) throws ParseException { + return parseInternal(new StringReader(input), options); + } + + static ExpressionElement parseInternal(StringReader input, ParserOptions options) throws ParseException { + // parser stack + final Parser stack = new Parser(); + ParserOptions.TokenRules tokenRules = options.getTokenRules(); + + while (input.canRead()) { + input.skipWhitespace(); + + if (!input.canRead()) { + break; + } + + char c = input.read(); + + if (tokenRules.isIdStart(c)) { + final String id = readWhile(input, tokenRules::isIdPart); + stack.visitId(id); + } else if (c == '.' && stack.canReadAccess()) { + input.skipWhitespace(); + + if (input.canRead()) { + char start = input.read(); + + if (!tokenRules.isAccessStart(start)) { + throw new UnexpectedCharacterException("a valid accessor", start, input.getCurrentIndex()); + } + + final String access = readWhile(input, tokenRules::isAccessPart); + stack.visitAccess(access); + } else { + throw new UnexpectedEndingException("An expression can't end with '.'"); + } + } else if (tokenRules.isNumberStart(c)) { + // start parsing a number + final String numberString = readWhile(input, tokenRules::isNumberPart); + stack.visitNumber(numberString); + } else if (c == '(') { + stack.visitOpeningParenthesis(); + } else if (c == ',') { + stack.visitComma(input.getCurrentIndex()); + } else if (c == ')') { + stack.visitClosingParenthesis(input.getCurrentIndex()); + } else { + if (stack.canReadBinaryOp()) { + // maybe binary operator + OpResolver resolver = options.getBinaryOpResolver(c); + + if (resolver != null) { + stack.visitBinaryOperator(resolver.resolve(input)); + continue; + } + } else { + // maybe unary operator + OpResolver resolver = options.getUnaryOpResolver(c); + + if (resolver != null) { + stack.visitUnaryOperator(resolver.resolve(input)); + continue; + } + } + + throw new UnexpectedCharacterException(c, input.getCurrentIndex()); + } + } + + return stack.getFinal(input.getCurrentIndex()); + } + + /** + * The returned value includes the last value btw; + */ + private static String readWhile(StringReader input, CharPredicate predicate) { + input.mark(); + + while (input.canRead()) { + if (!predicate.test(input.peek())) { + break; + } + + // NB: Do not skip whitespace here implicitly. + input.skipOneCharacter(); + } + + return input.substring(); + } + + private interface CharPredicate { + boolean test(char c); + } +} + + diff --git a/src/main/java/kroppeb/stareval/parser/UnaryOp.java b/src/main/java/kroppeb/stareval/parser/UnaryOp.java new file mode 100644 index 000000000..150110288 --- /dev/null +++ b/src/main/java/kroppeb/stareval/parser/UnaryOp.java @@ -0,0 +1,14 @@ +package kroppeb.stareval.parser; + +public class UnaryOp { + private final String name; + + public UnaryOp(String name) { + this.name = name; + } + + @Override + public String toString() { + return this.name; + } +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BatchingDebugMessageHelper.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BatchingDebugMessageHelper.java new file mode 100644 index 000000000..4f13c5200 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BatchingDebugMessageHelper.java @@ -0,0 +1,18 @@ +package net.coderbot.batchedentityrendering.impl; + +public class BatchingDebugMessageHelper { + public static String getDebugMessage(DrawCallTrackingRenderBuffers drawTracker) { + int drawCalls = drawTracker.getDrawCalls(); + int renderTypes = drawTracker.getRenderTypes(); + + if (drawCalls > 0) { + int effectivenessTimes10 = renderTypes * 1000 / drawCalls; + float effectiveness = effectivenessTimes10 / 10.0F; + + return drawCalls + " draw calls / " + renderTypes + " render types = " + + effectiveness + "% effective"; + } else { + return "(no draw calls)"; + } + } +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BlendingStateHolder.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BlendingStateHolder.java new file mode 100644 index 000000000..74905dd37 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BlendingStateHolder.java @@ -0,0 +1,5 @@ +package net.coderbot.batchedentityrendering.impl; + +public interface BlendingStateHolder { + TransparencyType getTransparencyType(); +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java new file mode 100644 index 000000000..0fb15f232 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java @@ -0,0 +1,10 @@ +package net.coderbot.batchedentityrendering.impl; + + +import java.nio.ByteBuffer; + +public interface BufferBuilderExt { + void setupBufferSlice(ByteBuffer buffer, BufferBuilder.DrawState drawState); + void teardownBufferSlice(); + void splitStrip(); +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java new file mode 100644 index 000000000..5b93e6ad6 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java @@ -0,0 +1,28 @@ +package net.coderbot.batchedentityrendering.impl; + + +import java.nio.ByteBuffer; + +public class BufferSegment { + private final ByteBuffer slice; + private final BufferBuilder.DrawState drawState; + private final RenderType type; + + public BufferSegment(ByteBuffer slice, BufferBuilder.DrawState drawState, RenderType type) { + this.slice = slice; + this.drawState = drawState; + this.type = type; + } + + public ByteBuffer getSlice() { + return slice; + } + + public BufferBuilder.DrawState getDrawState() { + return drawState; + } + + public RenderType getRenderType() { + return type; + } +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java new file mode 100644 index 000000000..fed318a90 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java @@ -0,0 +1,30 @@ +package net.coderbot.batchedentityrendering.impl; + + +public class BufferSegmentRenderer { + private final BufferBuilder fakeBufferBuilder; + private final BufferBuilderExt fakeBufferBuilderExt; + + public BufferSegmentRenderer() { + this.fakeBufferBuilder = new BufferBuilder(0); + this.fakeBufferBuilderExt = (BufferBuilderExt) this.fakeBufferBuilder; + } + + /** + * Sets up the render type, draws the buffer, and then tears down the render type. + */ + public void draw(BufferSegment segment) { + segment.getRenderType().setupRenderState(); + drawInner(segment); + segment.getRenderType().clearRenderState(); + } + + /** + * Like draw(), but it doesn't setup / tear down the render type. + */ + public void drawInner(BufferSegment segment) { + fakeBufferBuilderExt.setupBufferSlice(segment.getSlice(), segment.getDrawState()); + BufferUploader.end(fakeBufferBuilder); + fakeBufferBuilderExt.teardownBufferSlice(); + } +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/DrawCallTrackingRenderBuffers.java b/src/main/java/net/coderbot/batchedentityrendering/impl/DrawCallTrackingRenderBuffers.java new file mode 100644 index 000000000..d527db5c8 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/DrawCallTrackingRenderBuffers.java @@ -0,0 +1,7 @@ +package net.coderbot.batchedentityrendering.impl; + +public interface DrawCallTrackingRenderBuffers { + int getDrawCalls(); + int getRenderTypes(); + void resetDrawCounts(); +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/FlushableMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/FlushableMultiBufferSource.java new file mode 100644 index 000000000..3d77c02e6 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/FlushableMultiBufferSource.java @@ -0,0 +1,6 @@ +package net.coderbot.batchedentityrendering.impl; + +public interface FlushableMultiBufferSource { + void flushNonTranslucentContent(); + void flushTranslucentContent(); +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java new file mode 100644 index 000000000..3d7318266 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java @@ -0,0 +1,255 @@ +package net.coderbot.batchedentityrendering.impl; + +import net.coderbot.batchedentityrendering.impl.ordering.GraphTranslucencyRenderOrderManager; +import net.coderbot.batchedentityrendering.impl.ordering.RenderOrderManager; +import net.coderbot.iris.fantastic.WrappingMultiBufferSource; +import net.minecraft.client.Minecraft; +import net.minecraft.profiler.Profiler; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public class FullyBufferedMultiBufferSource extends MultiBufferSource.BufferSource implements MemoryTrackingBuffer, Groupable, WrappingMultiBufferSource { + private static final int NUM_BUFFERS = 32; + + private final RenderOrderManager renderOrderManager; + private final SegmentedBufferBuilder[] builders; + /** + * An LRU cache mapping RenderType objects to a relevant buffer. + */ + private final LinkedHashMap affinities; + private int drawCalls; + private int renderTypes; + + private final BufferSegmentRenderer segmentRenderer; + private final UnflushableWrapper unflushableWrapper; + private final List> wrappingFunctionStack; + private Function wrappingFunction = null; + + public FullyBufferedMultiBufferSource() { + super(new BufferBuilder(0), Collections.emptyMap()); + + this.renderOrderManager = new GraphTranslucencyRenderOrderManager(); + this.builders = new SegmentedBufferBuilder[NUM_BUFFERS]; + + for (int i = 0; i < this.builders.length; i++) { + this.builders[i] = new SegmentedBufferBuilder(); + } + + // use accessOrder=true so our LinkedHashMap works as an LRU cache. + this.affinities = new LinkedHashMap<>(32, 0.75F, true); + + this.drawCalls = 0; + this.segmentRenderer = new BufferSegmentRenderer(); + this.unflushableWrapper = new UnflushableWrapper(this); + this.wrappingFunctionStack = new ArrayList<>(); + } + + @Override + public VertexConsumer getBuffer(RenderType renderType) { + if (wrappingFunction != null) { + renderType = wrappingFunction.apply(renderType); + } + + renderOrderManager.begin(renderType); + Integer affinity = affinities.get(renderType); + + if (affinity == null) { + if (affinities.size() < builders.length) { + affinity = affinities.size(); + } else { + // We remove the element from the map that is used least-frequently. + // With how we've configured our LinkedHashMap, that is the first element. + Iterator> iterator = affinities.entrySet().iterator(); + Map.Entry evicted = iterator.next(); + iterator.remove(); + + // The previous type is no longer associated with this buffer ... + affinities.remove(evicted.getKey()); + + // ... since our new type is now associated with it. + affinity = evicted.getValue(); + } + + affinities.put(renderType, affinity); + } + + return builders[affinity].getBuffer(renderType); + } + + @Override + public void endBatch() { + Profiler profiler = Minecraft.getMinecraft().mcProfiler; + + profiler.startSection("collect"); + + Map> typeToSegment = new HashMap<>(); + + for (SegmentedBufferBuilder builder : builders) { + List segments = builder.getSegments(); + + for (BufferSegment segment : segments) { + typeToSegment.computeIfAbsent(segment.getRenderType(), (type) -> new ArrayList<>()).add(segment); + } + } + + profiler.endStartSection("resolve ordering"); + + Iterable renderOrder = renderOrderManager.getRenderOrder(); + + profiler.endStartSection("draw buffers"); + + for (RenderType type : renderOrder) { + type.setupRenderState(); + + renderTypes += 1; + + for (BufferSegment segment : typeToSegment.getOrDefault(type, Collections.emptyList())) { + segmentRenderer.drawInner(segment); + drawCalls += 1; + } + + type.clearRenderState(); + } + + profiler.endStartSection("reset"); + + renderOrderManager.reset(); + affinities.clear(); + + profiler.endSection(); + } + + public int getDrawCalls() { + return drawCalls; + } + + public int getRenderTypes() { + return renderTypes; + } + + public void resetDrawCalls() { + drawCalls = 0; + renderTypes = 0; + } + + @Override + public void endBatch(RenderType type) { + // Disable explicit flushing + } + + public MultiBufferSource.BufferSource getUnflushableWrapper() { + return unflushableWrapper; + } + + @Override + public int getAllocatedSize() { + int size = 0; + + for (SegmentedBufferBuilder builder : builders) { + size += builder.getAllocatedSize(); + } + + return size; + } + + @Override + public int getUsedSize() { + int size = 0; + + for (SegmentedBufferBuilder builder : builders) { + size += builder.getUsedSize(); + } + + return size; + } + + @Override + public void startGroup() { + renderOrderManager.startGroup(); + } + + @Override + public boolean maybeStartGroup() { + return renderOrderManager.maybeStartGroup(); + } + + @Override + public void endGroup() { + renderOrderManager.endGroup(); + } + + @Override + public void pushWrappingFunction(Function wrappingFunction) { + if (this.wrappingFunction != null) { + this.wrappingFunctionStack.add(this.wrappingFunction); + } + + this.wrappingFunction = wrappingFunction; + } + + @Override + public void popWrappingFunction() { + if (this.wrappingFunctionStack.isEmpty()) { + this.wrappingFunction = null; + } else { + this.wrappingFunction = this.wrappingFunctionStack.remove(this.wrappingFunctionStack.size() - 1); + } + } + + @Override + public void assertWrapStackEmpty() { + if (!this.wrappingFunctionStack.isEmpty() || this.wrappingFunction != null) { + throw new IllegalStateException("Wrapping function stack not empty!"); + } + } + + /** + * A wrapper that prevents callers from explicitly flushing anything. + */ + private static class UnflushableWrapper extends MultiBufferSource.BufferSource implements Groupable { + private final FullyBufferedMultiBufferSource wrapped; + + UnflushableWrapper(FullyBufferedMultiBufferSource wrapped) { + super(new BufferBuilder(0), Collections.emptyMap()); + + this.wrapped = wrapped; + } + + @Override + public VertexConsumer getBuffer(RenderType renderType) { + return wrapped.getBuffer(renderType); + } + + @Override + public void endBatch() { + // Disable explicit flushing + } + + @Override + public void endBatch(RenderType type) { + // Disable explicit flushing + } + + @Override + public void startGroup() { + wrapped.startGroup(); + } + + @Override + public boolean maybeStartGroup() { + return wrapped.maybeStartGroup(); + } + + @Override + public void endGroup() { + wrapped.endGroup(); + } + } +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/Groupable.java b/src/main/java/net/coderbot/batchedentityrendering/impl/Groupable.java new file mode 100644 index 000000000..343d094d7 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/Groupable.java @@ -0,0 +1,7 @@ +package net.coderbot.batchedentityrendering.impl; + +public interface Groupable { + void startGroup(); + boolean maybeStartGroup(); + void endGroup(); +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/MemoryTrackingBuffer.java b/src/main/java/net/coderbot/batchedentityrendering/impl/MemoryTrackingBuffer.java new file mode 100644 index 000000000..7937c4fe8 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/MemoryTrackingBuffer.java @@ -0,0 +1,6 @@ +package net.coderbot.batchedentityrendering.impl; + +public interface MemoryTrackingBuffer { + int getAllocatedSize(); + int getUsedSize(); +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/MemoryTrackingRenderBuffers.java b/src/main/java/net/coderbot/batchedentityrendering/impl/MemoryTrackingRenderBuffers.java new file mode 100644 index 000000000..c6ea1641e --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/MemoryTrackingRenderBuffers.java @@ -0,0 +1,7 @@ +package net.coderbot.batchedentityrendering.impl; + +public interface MemoryTrackingRenderBuffers { + int getEntityBufferAllocatedSize(); + int getMiscBufferAllocatedSize(); + int getMaxBegins(); +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java new file mode 100644 index 000000000..908a16e2a --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java @@ -0,0 +1,141 @@ +package net.coderbot.batchedentityrendering.impl; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class OldFullyBufferedMultiBufferSource extends MultiBufferSource.BufferSource { + private final Map bufferBuilders; + private final Object2IntMap unused; + private final Set activeBuffers; + private boolean flushed; + + private final Set typesThisFrame; + private final List typesInOrder; + + public OldFullyBufferedMultiBufferSource() { + super(new BufferBuilder(0), Collections.emptyMap()); + + this.bufferBuilders = new HashMap<>(); + this.unused = new Object2IntOpenHashMap<>(); + this.activeBuffers = new HashSet<>(); + this.flushed = false; + + this.typesThisFrame = new HashSet<>(); + this.typesInOrder = new ArrayList<>(); + } + + private TransparencyType getTransparencyType(RenderType type) { + while (type instanceof WrappableRenderType) { + type = ((WrappableRenderType) type).unwrap(); + } + + if (type instanceof BlendingStateHolder) { + return ((BlendingStateHolder) type).getTransparencyType(); + } + + // Default to "generally transparent" if we can't figure it out. + return TransparencyType.GENERAL_TRANSPARENT; + } + + @Override + public VertexConsumer getBuffer(RenderType renderType) { + flushed = false; + + BufferBuilder buffer = bufferBuilders.computeIfAbsent(renderType, type -> new BufferBuilder(type.bufferSize())); + + if (activeBuffers.add(buffer)) { + buffer.begin(renderType.mode(), renderType.format()); + } + + if (this.typesThisFrame.add(renderType)) { + // If we haven't seen this type yet, add it to the list of types to render. + // + // We keep track of the order that types were added, in order to ensure that if layers are not + // sorted relative each other due to translucency, that they are sorted in the order that they were + // drawn in. + // + // This is important for things like villager rendering, where the clothes and skin of villagers overlap + // each other, so if the clothes are drawn before the skin, they appear to be poorly-clothed. + this.typesInOrder.add(renderType); + } + + // If this buffer is scheduled to be removed, unschedule it since it's now being used. + unused.removeInt(renderType); + + return buffer; + } + + @Override + public void endBatch() { + if (flushed) { + return; + } + + List removedTypes = new ArrayList<>(); + + unused.forEach((unusedType, unusedCount) -> { + if (unusedCount < 10) { + // Removed after 10 frames of not being used + return; + } + + BufferBuilder buffer = bufferBuilders.remove(unusedType); + removedTypes.add(unusedType); + + if (activeBuffers.contains(buffer)) { + throw new IllegalStateException( + "A buffer was simultaneously marked as inactive and as active, something is very wrong..."); + } + }); + + for (RenderType removed : removedTypes) { + unused.removeInt(removed); + } + + // Make sure translucent types are rendered after non-translucent ones. + typesInOrder.sort(Comparator.comparing(this::getTransparencyType)); + + for (RenderType type : typesInOrder) { + drawInternal(type); + } + + typesInOrder.clear(); + typesThisFrame.clear(); + + flushed = true; + } + + @Override + public void endBatch(RenderType type) { + // Disable explicit flushing + } + + private void drawInternal(RenderType type) { + BufferBuilder buffer = bufferBuilders.get(type); + + if (buffer == null) { + return; + } + + if (activeBuffers.remove(buffer)) { + type.end(buffer, 0, 0, 0); + buffer.clear(); + } else { + // Schedule the buffer for removal next frame if it isn't used this frame. + int unusedCount = unused.getOrDefault(type, 0); + + unusedCount += 1; + + unused.put(type, unusedCount); + } + } +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderBuffersExt.java b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderBuffersExt.java new file mode 100644 index 000000000..0226be468 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderBuffersExt.java @@ -0,0 +1,6 @@ +package net.coderbot.batchedentityrendering.impl; + +public interface RenderBuffersExt { + void beginLevelRendering(); + void endLevelRendering(); +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java new file mode 100644 index 000000000..9b29a0959 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java @@ -0,0 +1,9 @@ +package net.coderbot.batchedentityrendering.impl; + +import org.lwjgl.opengl.GL11; + +public class RenderTypeUtil { + public static boolean isTriangleStripDrawMode(RenderType renderType) { + return renderType.mode() == GL11.GL_TRIANGLE_STRIP; + } +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java b/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java new file mode 100644 index 000000000..fa355375e --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java @@ -0,0 +1,94 @@ +package net.coderbot.batchedentityrendering.impl; + + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class SegmentedBufferBuilder implements MultiBufferSource, MemoryTrackingBuffer { + private final BufferBuilder buffer; + private final List usedTypes; + private RenderType currentType; + + public SegmentedBufferBuilder() { + // 2 MB initial allocation + this.buffer = new BufferBuilder(512 * 1024); + this.usedTypes = new ArrayList<>(256); + + this.currentType = null; + } + + @Override + public VertexConsumer getBuffer(RenderType renderType) { + if (!Objects.equals(currentType, renderType)) { + if (currentType != null) { + if (shouldSortOnUpload(currentType)) { + buffer.sortQuads(0, 0, 0); + } + + buffer.end(); + usedTypes.add(currentType); + } + + buffer.begin(renderType.mode(), renderType.format()); + + currentType = renderType; + } + + // Use duplicate vertices to break up triangle strips + // https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/Art/degenerate_triangle_strip_2x.png + // This works by generating zero-area triangles that don't end up getting rendered. + // TODO: How do we handle DEBUG_LINE_STRIP? + if (RenderTypeUtil.isTriangleStripDrawMode(currentType)) { + ((BufferBuilderExt) buffer).splitStrip(); + } + + return buffer; + } + + public List getSegments() { + if (currentType == null) { + return Collections.emptyList(); + } + + usedTypes.add(currentType); + + if (shouldSortOnUpload(currentType)) { + buffer.sortQuads(0, 0, 0); + } + + buffer.end(); + currentType = null; + + List segments = new ArrayList<>(usedTypes.size()); + + for (RenderType type : usedTypes) { + Pair pair = buffer.popNextBuffer(); + + BufferBuilder.DrawState drawState = pair.getFirst(); + ByteBuffer slice = pair.getSecond(); + + segments.add(new BufferSegment(slice, drawState, type)); + } + + usedTypes.clear(); + + return segments; + } + + private static boolean shouldSortOnUpload(RenderType type) { + return ((RenderTypeAccessor) type).shouldSortOnUpload(); + } + + @Override + public int getAllocatedSize() { + return ((MemoryTrackingBuffer) buffer).getAllocatedSize(); + } + + @Override + public int getUsedSize() { + return ((MemoryTrackingBuffer) buffer).getUsedSize(); + } +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/TransparencyType.java b/src/main/java/net/coderbot/batchedentityrendering/impl/TransparencyType.java new file mode 100644 index 000000000..6bd124265 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/TransparencyType.java @@ -0,0 +1,27 @@ +package net.coderbot.batchedentityrendering.impl; + +public enum TransparencyType { + /** + * Opaque, non transparent content. + */ + OPAQUE, + /** + * Generally transparent / translucent content. + */ + GENERAL_TRANSPARENT, + /** + * Enchantment glint and crumbling blocks + * These *must* be rendered after their corresponding opaque / transparent parts. + */ + DECAL, + /** + * Water mask, should be drawn after pretty much everything except for translucent terrain and lines. + * Prevents water from appearing inside of boats. + */ + WATER_MASK, + /** + * Block outlines and other debug things that are overlaid on to the world. + * Should be drawn last to avoid weirdness with entity shadows / banners. + */ + LINES +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java b/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java new file mode 100644 index 000000000..0392ef8b3 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java @@ -0,0 +1,8 @@ +package net.coderbot.batchedentityrendering.impl; + +public interface WrappableRenderType { + /** + * Returns the underlying wrapped RenderType. Might return itself if this RenderType doesn't wrap anything. + */ + RenderType unwrap(); +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java new file mode 100644 index 000000000..b8172b770 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java @@ -0,0 +1,139 @@ +package net.coderbot.batchedentityrendering.impl.ordering; + +import de.odysseus.ithaka.digraph.Digraph; +import de.odysseus.ithaka.digraph.Digraphs; +import de.odysseus.ithaka.digraph.MapDigraph; +import de.odysseus.ithaka.digraph.util.fas.FeedbackArcSet; +import de.odysseus.ithaka.digraph.util.fas.FeedbackArcSetPolicy; +import de.odysseus.ithaka.digraph.util.fas.FeedbackArcSetProvider; +import de.odysseus.ithaka.digraph.util.fas.SimpleFeedbackArcSetProvider; +import net.coderbot.batchedentityrendering.impl.BlendingStateHolder; +import net.coderbot.batchedentityrendering.impl.TransparencyType; +import net.coderbot.batchedentityrendering.impl.WrappableRenderType; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; + +public class GraphTranslucencyRenderOrderManager implements RenderOrderManager { + private final FeedbackArcSetProvider feedbackArcSetProvider; + private final EnumMap> types; + + private boolean inGroup = false; + private final EnumMap currentTypes; + + public GraphTranslucencyRenderOrderManager() { + feedbackArcSetProvider = new SimpleFeedbackArcSetProvider(); + types = new EnumMap<>(TransparencyType.class); + currentTypes = new EnumMap<>(TransparencyType.class); + + for (TransparencyType type : TransparencyType.values()) { + types.put(type, new MapDigraph<>()); + } + } + + private static TransparencyType getTransparencyType(RenderType type) { + while (type instanceof WrappableRenderType) { + type = ((WrappableRenderType) type).unwrap(); + } + + if (type instanceof BlendingStateHolder) { + return ((BlendingStateHolder) type).getTransparencyType(); + } + + // Default to "generally transparent" if we can't figure it out. + return TransparencyType.GENERAL_TRANSPARENT; + } + + public void begin(RenderType renderType) { + TransparencyType transparencyType = getTransparencyType(renderType); + Digraph graph = types.get(transparencyType); + graph.add(renderType); + + if (inGroup) { + RenderType previous = currentTypes.put(transparencyType, renderType); + + if (previous == null) { + return; + } + + int weight = graph.get(previous, renderType).orElse(0); + weight += 1; + graph.put(previous, renderType, weight); + } + } + + public void startGroup() { + if (inGroup) { + throw new IllegalStateException("Already in a group"); + } + + currentTypes.clear(); + inGroup = true; + } + + public boolean maybeStartGroup() { + if (inGroup) { + return false; + } + + currentTypes.clear(); + inGroup = true; + return true; + } + + public void endGroup() { + if (!inGroup) { + throw new IllegalStateException("Not in a group"); + } + + currentTypes.clear(); + inGroup = false; + } + + @Override + public void reset() { + // TODO: Is reallocation efficient? + types.clear(); + + for (TransparencyType type : TransparencyType.values()) { + types.put(type, new MapDigraph<>()); + } + } + + public Iterable getRenderOrder() { + int layerCount = 0; + + for (Digraph graph : types.values()) { + layerCount += graph.getVertexCount(); + } + + List allLayers = new ArrayList<>(layerCount); + + for (Digraph graph : types.values()) { + // TODO: Make sure that FAS can't become a bottleneck! + // Running NP-hard algorithms in a real time rendering loop might not be an amazing idea. + // This shouldn't be necessary in sane scenes, though, and if there aren't cycles, + // then this *should* be relatively inexpensive, since it'll bail out and return an empty set. + FeedbackArcSet arcSet = + feedbackArcSetProvider.getFeedbackArcSet(graph, graph, FeedbackArcSetPolicy.MIN_WEIGHT); + + if (arcSet.getEdgeCount() > 0) { + // This means that our dependency graph had cycles!!! + // This is very weird and isn't expected - but we try to handle it gracefully anyways. + + // Our feedback arc set algorithm finds some dependency links that can be removed hopefully + // without disrupting the overall order too much. Hopefully it isn't too slow! + for (RenderType source : arcSet.vertices()) { + for (RenderType target : arcSet.targets(source)) { + graph.remove(source, target); + } + } + } + + allLayers.addAll(Digraphs.toposort(graph, false)); + } + + return allLayers; + } +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java new file mode 100644 index 000000000..6e6c6407d --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java @@ -0,0 +1,12 @@ +package net.coderbot.batchedentityrendering.impl.ordering; + +import net.minecraft.client.renderer.RenderType; + +public interface RenderOrderManager { + void begin(RenderType type); + void startGroup(); + boolean maybeStartGroup(); + void endGroup(); + void reset(); + Iterable getRenderOrder(); +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java new file mode 100644 index 000000000..43d36888b --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java @@ -0,0 +1,38 @@ +package net.coderbot.batchedentityrendering.impl.ordering; + + +import java.util.LinkedHashSet; + +public class SimpleRenderOrderManager implements RenderOrderManager { + private final LinkedHashSet renderTypes; + + public SimpleRenderOrderManager() { + renderTypes = new LinkedHashSet<>(); + } + + public void begin(RenderType type) { + renderTypes.add(type); + } + + public void startGroup() { + // no-op + } + + public boolean maybeStartGroup() { + // no-op + return false; + } + + public void endGroup() { + // no-op + } + + @Override + public void reset() { + renderTypes.clear(); + } + + public Iterable getRenderOrder() { + return renderTypes; + } +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java new file mode 100644 index 000000000..18def0b43 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java @@ -0,0 +1,75 @@ +package net.coderbot.batchedentityrendering.impl.ordering; + +import net.coderbot.batchedentityrendering.impl.BlendingStateHolder; +import net.coderbot.batchedentityrendering.impl.TransparencyType; +import net.coderbot.batchedentityrendering.impl.WrappableRenderType; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.LinkedHashSet; +import java.util.List; + +public class TranslucencyRenderOrderManager implements RenderOrderManager { + private final EnumMap> renderTypes; + + public TranslucencyRenderOrderManager() { + renderTypes = new EnumMap<>(TransparencyType.class); + + for (TransparencyType type : TransparencyType.values()) { + renderTypes.put(type, new LinkedHashSet<>()); + } + } + + private static TransparencyType getTransparencyType(RenderType type) { + while (type instanceof WrappableRenderType) { + type = ((WrappableRenderType) type).unwrap(); + } + + if (type instanceof BlendingStateHolder) { + return ((BlendingStateHolder) type).getTransparencyType(); + } + + // Default to "generally transparent" if we can't figure it out. + return TransparencyType.GENERAL_TRANSPARENT; + } + + public void begin(RenderType type) { + renderTypes.get(getTransparencyType(type)).add(type); + } + + public void startGroup() { + // no-op + } + + public boolean maybeStartGroup() { + // no-op + return false; + } + + public void endGroup() { + // no-op + } + + @Override + public void reset() { + renderTypes.forEach((type, set) -> { + set.clear(); + }); + } + + public Iterable getRenderOrder() { + int layerCount = 0; + + for (LinkedHashSet set : renderTypes.values()) { + layerCount += set.size(); + } + + List allRenderTypes = new ArrayList<>(layerCount); + + for (LinkedHashSet set : renderTypes.values()) { + allRenderTypes.addAll(set); + } + + return allRenderTypes; + } +} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java new file mode 100644 index 000000000..05e3253a4 --- /dev/null +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java @@ -0,0 +1,66 @@ +package net.coderbot.batchedentityrendering.impl.wrappers; + +import net.coderbot.batchedentityrendering.impl.WrappableRenderType; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.Optional; + +public class TaggingRenderTypeWrapper extends RenderType implements WrappableRenderType { + private final int tag; + private final RenderType wrapped; + + public TaggingRenderTypeWrapper(String name, RenderType wrapped, int tag) { + super(name, wrapped.format(), wrapped.mode(), wrapped.bufferSize(), + wrapped.affectsCrumbling(), shouldSortOnUpload(wrapped), wrapped::setupRenderState, wrapped::clearRenderState); + + this.tag = tag; + this.wrapped = wrapped; + } + + @Override + public RenderType unwrap() { + return this.wrapped; + } + + @Override + public Optional outline() { + return this.wrapped.outline(); + } + + @Override + public boolean isOutline() { + return this.wrapped.isOutline(); + } + + @Override + public boolean equals(@Nullable Object object) { + if (object == null) { + return false; + } + + if (object.getClass() != this.getClass()) { + return false; + } + + TaggingRenderTypeWrapper other = (TaggingRenderTypeWrapper) object; + + return this.tag == other.tag && Objects.equals(this.wrapped, other.wrapped); + } + + @Override + public int hashCode() { + // Add one so that we don't have the exact same hash as the wrapped object. + // This means that we won't have a guaranteed collision if we're inserted to a map alongside the unwrapped object. + return this.wrapped.hashCode() + 1; + } + + @Override + public String toString() { + return "tagged(" +tag+ "):" + this.wrapped.toString(); + } + + private static boolean shouldSortOnUpload(RenderType type) { + return ((RenderTypeAccessor) type).shouldSortOnUpload(); + } +} diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java new file mode 100644 index 000000000..c48d7fcb5 --- /dev/null +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -0,0 +1,687 @@ +package net.coderbot.iris; + +import com.mojang.realmsclient.gui.ChatFormatting; +import net.coderbot.iris.config.IrisConfig; +import net.coderbot.iris.gl.GLDebug; +import net.coderbot.iris.gl.shader.StandardMacros; +import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline; +import net.coderbot.iris.pipeline.FixedFunctionWorldRenderingPipeline; +import net.coderbot.iris.pipeline.PipelineManager; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.coderbot.iris.shaderpack.DimensionId; +import net.coderbot.iris.shaderpack.OptionalBoolean; +import net.coderbot.iris.shaderpack.ProgramSet; +import net.coderbot.iris.shaderpack.ShaderPack; +import net.coderbot.iris.shaderpack.discovery.ShaderpackDirectoryManager; +import net.coderbot.iris.shaderpack.option.OptionSet; +import net.coderbot.iris.shaderpack.option.Profile; +import net.coderbot.iris.shaderpack.option.values.MutableOptionValues; +import net.coderbot.iris.shaderpack.option.values.OptionValues; +import net.coderbot.iris.texture.pbr.PBRTextureManager; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.resources.I18n; +import net.minecraft.launchwrapper.Launch; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.opengl.ContextCapabilities; +import org.lwjgl.opengl.GLContext; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.stream.Stream; +import java.util.zip.ZipError; +import java.util.zip.ZipException; + +public class Iris { + final boolean isDevelopmentEnvironment; + public static ContextCapabilities capabilities; + + public static final String MODID = "angelica"; + + /** + * The user-facing name of the mod. Moved into a constant to facilitate easy branding changes (for forks). You'll still need to change this separately in + * mixin plugin classes & the language files. + */ + public static final String MODNAME = "Angelica"; + + public static final IrisLogging logger = new IrisLogging(MODNAME); + + private static Path shaderpacksDirectory; + private static ShaderpackDirectoryManager shaderpacksDirectoryManager; + + private static ShaderPack currentPack; + private static String currentPackName; + // TODO: Iris Backport - Tie this to archaicfix + private static final boolean sodiumInstalled = true; // FMLLoader.getLoadingModList().getModFileById("rubidium") != null; + private static boolean initialized; + + private static PipelineManager pipelineManager; + private static IrisConfig irisConfig; + private static FileSystem zipFileSystem; + // TODO: Iris Backport + // private static KeyMapping reloadKeybind; + // private static KeyMapping toggleShadersKeybind; + // private static KeyMapping shaderpackScreenKeybind; + + private static final Map shaderPackOptionQueue = new HashMap<>(); + // Flag variable used when reloading + // Used in favor of queueDefaultShaderPackOptionValues() for resetting as the + // behavior is more concrete and therefore is more likely to repair a user's issues + private static boolean resetShaderPackOptions = false; + + private static String IRIS_VERSION; + private static boolean fallback; + + // Wrapped in try-catch due to early initializing class + public Iris() { + isDevelopmentEnvironment = (boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment"); + // TODO: Iris Backport + // try { + // FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onInitializeClient); + // MinecraftForge.EVENT_BUS.addListener(this::onKeyInput); + // + // ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); + // }catch(Exception ignored) {} + } + + /** + * Called very early on in Minecraft initialization. At this point we *cannot* safely access OpenGL, but we can do some very basic setup, config loading, + * and environment checks. + * + *

This is roughly equivalent to Fabric Loader's ClientModInitializer#onInitializeClient entrypoint, except + * it's entirely cross platform & we get to decide its exact semantics.

+ * + *

This is called right before options are loaded, so we can add key bindings here.

+ */ + public void onEarlyInitialize() { + try { + if (!Files.exists(getShaderpacksDirectory())) { + Files.createDirectories(getShaderpacksDirectory()); + } + } catch (IOException e) { + logger.warn("Failed to create the shaderpacks directory!"); + logger.warn("", e); + } + + // Minecraft.getMinecraft().mcDataDir.toPath().resolve("shaderpacks") + // Minecraft.getMinecraft().mcDataDir.toPath().resolve("config") + irisConfig = new IrisConfig(Minecraft.getMinecraft().mcDataDir.toPath().resolve("config").resolve("shaders.properties")); + + try { + irisConfig.initialize(); + } catch (IOException e) { + logger.error("Failed to initialize Oculus configuration, default values will be used instead"); + logger.error("", e); + } + + // TODO: Iris Backport + // reloadKeybind = new KeyMapping("iris.keybind.reload", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_R, "iris.keybinds"); + // toggleShadersKeybind = new KeyMapping("iris.keybind.toggleShaders", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_K, "iris.keybinds"); + // shaderpackScreenKeybind = new KeyMapping("iris.keybind.shaderPackSelection", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_O, "iris.keybinds"); + + initialized = true; + } + + // TODO: Iris Backport + // public void onInitializeClient(final FMLClientSetupEvent event) { + // IRIS_VERSION = ModList.get().getModContainerById(MODID).get().getModInfo().getVersion().toString(); + // ClientRegistry.registerKeyBinding(reloadKeybind); + // ClientRegistry.registerKeyBinding(toggleShadersKeybind); + // ClientRegistry.registerKeyBinding(shaderpackScreenKeybind); + // } + + // TODO: Iris Backport + // public void onKeyInput(InputEvent.KeyInputEvent event) { + // handleKeybinds(Minecraft.getMinecraft()); + // } + + /** + * Called once RenderSystem#initRenderer has completed. This means that we can safely access OpenGL. + */ + public static void onRenderSystemInit() { + if (!initialized) { + Iris.logger.warn("Iris::onRenderSystemInit was called, but Iris::onEarlyInitialize was not called." + + " Trying to avoid a crash but this is an odd state."); + return; + } + capabilities = GLContext.getCapabilities(); + + setDebug(irisConfig.areDebugOptionsEnabled()); + + PBRTextureManager.INSTANCE.init(); + + // Only load the shader pack when we can access OpenGL + loadShaderpack(); + } + + /** + * Called when the title screen is initialized for the first time. + */ + public static void onLoadingComplete() { + if (!initialized) { + Iris.logger.warn("Iris::onLoadingComplete was called, but Iris::onEarlyInitialize was not called." + + " Trying to avoid a crash but this is an odd state."); + return; + } + + // Initialize the pipeline now so that we don't increase world loading time. Just going to guess that + // the player is in the overworld. + // See: https://github.com/IrisShaders/Iris/issues/323 + lastDimension = DimensionId.OVERWORLD; + Iris.getPipelineManager().preparePipeline(DimensionId.OVERWORLD); + } + + // TODO: Iris Backport + // public static void handleKeybinds(Minecraft minecraft) { + // if (reloadKeybind.consumeClick()) { + // try { + // reload(); + // + // if (minecraft.thePlayer != null) { + // minecraft.thePlayer.sendChatMessage(I18n.format("iris.shaders.reloaded"), false); + // } + // + // } catch (Exception e) { + // logger.error("Error while reloading Shaders for " + MODNAME + "!", e); + // + // if (minecraft.thePlayer != null) { + // minecraft.thePlayer.sendChatMessage(I18n.format("iris.shaders.reloaded.failure", Throwables.getRootCause(e).getMessage()).withStyle( + // ChatFormatting.RED), false); + // } + // } + // } else if (toggleShadersKeybind.consumeClick()) { + // try { + // toggleShaders(minecraft, !irisConfig.areShadersEnabled()); + // } catch (Exception e) { + // logger.error("Error while toggling shaders!", e); + // + // if (minecraft.thePlayer != null) { + // minecraft.thePlayer.sendChatMessage(I18n.format("iris.shaders.toggled.failure", Throwables.getRootCause(e).getMessage()).withStyle(ChatFormatting.RED), false); + // } + // setShadersDisabled(); + // fallback = true; + // } + // } else if (shaderpackScreenKeybind.consumeClick()) { + // minecraft.setScreen(new ShaderPackScreen(null)); + // } + // } + + public static void toggleShaders(Minecraft minecraft, boolean enabled) throws IOException { + irisConfig.setShadersEnabled(enabled); + irisConfig.save(); + + reload(); + if (minecraft.thePlayer != null) { + minecraft.thePlayer.sendChatMessage(enabled ? I18n.format("iris.shaders.toggled", currentPackName) : I18n.format("iris.shaders.disabled")); + } + } + + public static void loadShaderpack() { + if (irisConfig == null) { + if (!initialized) { + throw new IllegalStateException("Iris::loadShaderpack was called, but Iris::onInitializeClient wasn't" + " called yet. How did this happen?"); + } else { + throw new NullPointerException("Iris.irisConfig was null unexpectedly"); + } + } + + if (!irisConfig.areShadersEnabled()) { + logger.info("Shaders are disabled because enableShaders is set to false in oculus.properties"); + + setShadersDisabled(); + + return; + } + + // Attempt to load an external shaderpack if it is available + Optional externalName = irisConfig.getShaderPackName(); + + if (!externalName.isPresent()) { + logger.info("Shaders are disabled because no valid shaderpack is selected"); + + setShadersDisabled(); + + return; + } + + if (!loadExternalShaderpack(externalName.get())) { + logger.warn("Falling back to normal rendering without shaders because the shaderpack could not be loaded"); + setShadersDisabled(); + fallback = true; + } + } + + private static boolean loadExternalShaderpack(String name) { + Path shaderPackRoot; + Path shaderPackConfigTxt; + + try { + shaderPackRoot = getShaderpacksDirectory().resolve(name); + shaderPackConfigTxt = getShaderpacksDirectory().resolve(name + ".txt"); + } catch (InvalidPathException e) { + logger.error("Failed to load the shaderpack \"{}\" because it contains invalid characters in its path", name); + + return false; + } + + Path shaderPackPath; + + if (shaderPackRoot.toString().endsWith(".zip")) { + Optional optionalPath; + + try { + optionalPath = loadExternalZipShaderpack(shaderPackRoot); + } catch (FileSystemNotFoundException | NoSuchFileException e) { + logger.error("Failed to load the shaderpack \"{}\" because it does not exist in your shaderpacks folder!", name); + + return false; + } catch (ZipException e) { + logger.error("The shaderpack \"{}\" appears to be corrupted, please try downloading it again!", name); + + return false; + } catch (IOException e) { + logger.error("Failed to load the shaderpack \"{}\"!", name); + logger.error("", e); + + return false; + } + + if (optionalPath.isPresent()) { + shaderPackPath = optionalPath.get(); + } else { + logger.error("Could not load the shaderpack \"{}\" because it appears to lack a \"shaders\" directory", name); + return false; + } + } else { + if (!Files.exists(shaderPackRoot)) { + logger.error("Failed to load the shaderpack \"{}\" because it does not exist!", name); + return false; + } + + // If it's a folder-based shaderpack, just use the shaders subdirectory + shaderPackPath = shaderPackRoot.resolve("shaders"); + } + + if (!Files.exists(shaderPackPath)) { + logger.error("Could not load the shaderpack \"{}\" because it appears to lack a \"shaders\" directory", name); + return false; + } + + Map changedConfigs = tryReadConfigProperties(shaderPackConfigTxt).map(properties -> (Map) (Map) properties) + .orElse(new HashMap<>()); + + changedConfigs.putAll(shaderPackOptionQueue); + clearShaderPackOptionQueue(); + + if (resetShaderPackOptions) { + changedConfigs.clear(); + } + resetShaderPackOptions = false; + + try { + currentPack = new ShaderPack(shaderPackPath, changedConfigs, StandardMacros.createStandardEnvironmentDefines()); + + MutableOptionValues changedConfigsValues = currentPack.getShaderPackOptions().getOptionValues().mutableCopy(); + + // Store changed values from those currently in use by the shader pack + Properties configsToSave = new Properties(); + changedConfigsValues.getBooleanValues().forEach((k, v) -> configsToSave.setProperty(k, Boolean.toString(v))); + changedConfigsValues.getStringValues().forEach(configsToSave::setProperty); + + tryUpdateConfigPropertiesFile(shaderPackConfigTxt, configsToSave); + } catch (Exception e) { + logger.error("Failed to load the shaderpack \"{}\"!", name); + logger.error("", e); + + return false; + } + + fallback = false; + currentPackName = name; + + logger.info("Using shaderpack: " + name); + + return true; + } + + private static Optional loadExternalZipShaderpack(Path shaderpackPath) throws IOException { + FileSystem zipSystem = FileSystems.newFileSystem(shaderpackPath, Iris.class.getClassLoader()); + zipFileSystem = zipSystem; + + // Should only be one root directory for a zip shaderpack + Path root = zipSystem.getRootDirectories().iterator().next(); + + Path potentialShaderDir = zipSystem.getPath("shaders"); + + // If the shaders dir was immediately found return it + // Otherwise, manually search through each directory path until it ends with "shaders" + if (Files.exists(potentialShaderDir)) { + return Optional.of(potentialShaderDir); + } + + // Sometimes shaderpacks have their shaders directory within another folder in the shaderpack + // For example Sildurs-Vibrant-Shaders.zip/shaders + // While other packs have Trippy-Shaderpack-master.zip/Trippy-Shaderpack-master/shaders + // This makes it hard to determine what is the actual shaders dir + try (Stream stream = Files.walk(root)) { + return stream.filter(Files::isDirectory).filter(path -> path.endsWith("shaders")).findFirst(); + } + } + + private static void setShadersDisabled() { + currentPack = null; + fallback = false; + currentPackName = "(off)"; + + logger.info("Shaders are disabled"); + } + + private static void setDebug(boolean enable) { + int success; + if (enable) { + success = GLDebug.setupDebugMessageCallback(); + } else { + success = GLDebug.disableDebugMessages(); + } + logger.info("Debug functionality is " + (enable ? "enabled, logging will be more verbose!" : "disabled.")); + if (Minecraft.getMinecraft().thePlayer != null) { + Minecraft.getMinecraft().thePlayer.sendChatMessage(I18n.format(success != 0 ? (enable + ? "iris.shaders.debug.enabled" + : "iris.shaders.debug.disabled") : "iris.shaders.debug.failure")); + if (success == 2) { + Minecraft.getMinecraft().thePlayer.sendChatMessage(I18n.format("iris.shaders.debug.restart")); + } + } + + try { + irisConfig.setDebugEnabled(enable); + irisConfig.save(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static Optional tryReadConfigProperties(Path path) { + Properties properties = new Properties(); + + if (Files.exists(path)) { + try (InputStream is = Files.newInputStream(path)) { + // NB: config properties are specified to be encoded with ISO-8859-1 by OptiFine, + // so we don't need to do the UTF-8 workaround here. + properties.load(is); + } catch (IOException e) { + // TODO: Better error handling + return Optional.empty(); + } + } + + return Optional.of(properties); + } + + private static void tryUpdateConfigPropertiesFile(Path path, Properties properties) { + try { + if (properties.isEmpty()) { + // Delete the file or don't create it if there are no changed configs + if (Files.exists(path)) { + Files.delete(path); + } + + return; + } + + try (OutputStream out = Files.newOutputStream(path)) { + properties.store(out, null); + } + } catch (IOException e) { + // TODO: Better error handling + } + } + + public static boolean isValidShaderpack(Path pack) { + if (Files.isDirectory(pack)) { + // Sometimes the shaderpack directory itself can be + // identified as a shader pack due to it containing + // folders which contain "shaders" folders, this is + // necessary to check against that + if (pack.equals(getShaderpacksDirectory())) { + return false; + } + try (Stream stream = Files.walk(pack)) { + return stream.filter(Files::isDirectory) + // Prevent a pack simply named "shaders" from being + // identified as a valid pack + .filter(path -> !path.equals(pack)).anyMatch(path -> path.endsWith("shaders")); + } catch (IOException ignored) { + // ignored, not a valid shader pack. + } + } + + if (pack.toString().endsWith(".zip")) { + try (FileSystem zipSystem = FileSystems.newFileSystem(pack, Iris.class.getClassLoader())) { + Path root = zipSystem.getRootDirectories().iterator().next(); + try (Stream stream = Files.walk(root)) { + return stream.filter(Files::isDirectory).anyMatch(path -> path.endsWith("shaders")); + } + } catch (ZipError zipError) { + // Java 8 seems to throw a ZipError instead of a subclass of IOException + Iris.logger.warn("The ZIP at " + pack + " is corrupt"); + } catch (IOException ignored) { + // ignored, not a valid shader pack. + } + } + + return false; + } + + public static Map getShaderPackOptionQueue() { + return shaderPackOptionQueue; + } + + public static void queueShaderPackOptionsFromProfile(Profile profile) { + getShaderPackOptionQueue().putAll(profile.optionValues); + } + + public static void queueShaderPackOptionsFromProperties(Properties properties) { + queueDefaultShaderPackOptionValues(); + + properties.stringPropertyNames().forEach(key -> getShaderPackOptionQueue().put(key, properties.getProperty(key))); + } + + // Used in favor of resetShaderPackOptions as the aforementioned requires the pack to be reloaded + public static void queueDefaultShaderPackOptionValues() { + clearShaderPackOptionQueue(); + + getCurrentPack().ifPresent(pack -> { + OptionSet options = pack.getShaderPackOptions().getOptionSet(); + OptionValues values = pack.getShaderPackOptions().getOptionValues(); + + options.getStringOptions().forEach((key, mOpt) -> { + if (values.getStringValue(key).isPresent()) { + getShaderPackOptionQueue().put(key, mOpt.getOption().getDefaultValue()); + } + }); + options.getBooleanOptions().forEach((key, mOpt) -> { + if (values.getBooleanValue(key) != OptionalBoolean.DEFAULT) { + getShaderPackOptionQueue().put(key, Boolean.toString(mOpt.getOption().getDefaultValue())); + } + }); + }); + } + + public static void clearShaderPackOptionQueue() { + getShaderPackOptionQueue().clear(); + } + + public static void resetShaderPackOptionsOnNextReload() { + resetShaderPackOptions = true; + } + + public static boolean shouldResetShaderPackOptionsOnNextReload() { + return resetShaderPackOptions; + } + + public static void reload() throws IOException { + // allows shaderpacks to be changed at runtime + irisConfig.initialize(); + + // Destroy all allocated resources + destroyEverything(); + + // Load the new shaderpack + loadShaderpack(); + + // Very important - we need to re-create the pipeline straight away. + // https://github.com/IrisShaders/Iris/issues/1330 + if (Minecraft.getMinecraft().theWorld != null) { + Iris.getPipelineManager().preparePipeline(Iris.getCurrentDimension()); + } + } + + /** + * Destroys and deallocates all created OpenGL resources. Useful as part of a reload. + */ + private static void destroyEverything() { + currentPack = null; + + getPipelineManager().destroyPipeline(); + + // Close the zip filesystem that the shaderpack was loaded from + // + // This prevents a FileSystemAlreadyExistsException when reloading shaderpacks. + if (zipFileSystem != null) { + try { + zipFileSystem.close(); + } catch (NoSuchFileException e) { + logger.warn("Failed to close the shaderpack zip when reloading because it was deleted, proceeding anyways."); + } catch (IOException e) { + logger.error("Failed to close zip file system?", e); + } + } + } + + public static DimensionId lastDimension = null; + + public static DimensionId getCurrentDimension() { + WorldClient level = Minecraft.getMinecraft().theWorld; + + if (level != null) { + if (level.provider == null) return DimensionId.OVERWORLD; + + if ((level.provider.isHellWorld || level.provider.hasNoSky) || level.provider.dimensionId == -1) { + return DimensionId.NETHER; + } else if (level.provider.dimensionId == 1) { + return DimensionId.END; + } else { + return DimensionId.OVERWORLD; + } + } else { + // This prevents us from reloading the shaderpack unless we need to. Otherwise, if the player is in the + // nether and quits the game, we might end up reloading the shaders on exit and on entry to the level + // because the code thinks that the dimension changed. + return lastDimension; + } + } + + private static WorldRenderingPipeline createPipeline(DimensionId dimensionId) { + if (currentPack == null) { + // Completely disables shader-based rendering + return new FixedFunctionWorldRenderingPipeline(); + } + + ProgramSet programs = currentPack.getProgramSet(dimensionId); + + try { + return new DeferredWorldRenderingPipeline(programs); + } catch (Exception e) { + logger.error("Failed to create shader rendering pipeline, disabling shaders!", e); + // TODO: This should be reverted if a dimension change causes shaders to compile again + fallback = true; + + return new FixedFunctionWorldRenderingPipeline(); + } + } + + @NotNull + public static PipelineManager getPipelineManager() { + if (pipelineManager == null) { + pipelineManager = new PipelineManager(Iris::createPipeline); + } + + return pipelineManager; + } + + @NotNull + public static Optional getCurrentPack() { + return Optional.ofNullable(currentPack); + } + + public static String getCurrentPackName() { + return currentPackName; + } + + public static IrisConfig getIrisConfig() { + return irisConfig; + } + + public static boolean isFallback() { + return fallback; + } + + public static String getVersion() { + if (IRIS_VERSION == null) { + return "Version info unknown!"; + } + + return IRIS_VERSION; + } + + public static String getFormattedVersion() { + ChatFormatting color; + String version = getVersion(); + + if (version.endsWith("-development-environment")) { + color = ChatFormatting.GOLD; + version = version.replace("-development-environment", " (Development Environment)"); + } else if (version.endsWith("-dirty") || version.contains("unknown") || version.endsWith("-nogit")) { + color = ChatFormatting.RED; + } else if (version.contains("+rev.")) { + color = ChatFormatting.LIGHT_PURPLE; + } else { + color = ChatFormatting.GREEN; + } + + return color + version; + } + + public static boolean isSodiumInstalled() { + return sodiumInstalled; + } + + public static Path getShaderpacksDirectory() { + if (shaderpacksDirectory == null) { + shaderpacksDirectory = Minecraft.getMinecraft().mcDataDir.toPath().resolve("shaderpacks"); + } + + return shaderpacksDirectory; + } + + public static ShaderpackDirectoryManager getShaderpacksDirectoryManager() { + if (shaderpacksDirectoryManager == null) { + shaderpacksDirectoryManager = new ShaderpackDirectoryManager(getShaderpacksDirectory()); + } + + return shaderpacksDirectoryManager; + } +} diff --git a/src/main/java/net/coderbot/iris/IrisLogging.java b/src/main/java/net/coderbot/iris/IrisLogging.java new file mode 100644 index 000000000..a14de21ea --- /dev/null +++ b/src/main/java/net/coderbot/iris/IrisLogging.java @@ -0,0 +1,58 @@ +package net.coderbot.iris; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class IrisLogging { + public static boolean ENABLE_SPAM = false; // FabricLoader.getInstance().isDevelopmentEnvironment(); + + private final Logger logger; + + public IrisLogging(String loggerName) { + this.logger = LogManager.getLogger(loggerName); + } + + public void fatal(String fatal) { + this.logger.fatal(fatal); + } + + public void error(String error) { + this.logger.error(error); + } + + public void error(String error, Object... o) { + this.logger.error(error, o); + } + + public void error(String error, Throwable t) { + this.logger.error(error, t); + } + + public void warn(String warning) { + this.logger.warn(warning); + } + + public void warn(String warning, Throwable t) { + this.logger.warn(warning, t); + } + + public void warn(Object... o) { + this.logger.warn(o); + } + + public void info(String info) { + this.logger.info(info); + } + + public void info(String info, Object... o) { + this.logger.info(info, o); + } + + public void debug(String debug) { + this.logger.debug(debug); + } + + public void debug(String debug, Throwable t) { + this.logger.debug(debug, t); + } +} diff --git a/src/main/java/net/coderbot/iris/JomlConversions.java b/src/main/java/net/coderbot/iris/JomlConversions.java new file mode 100644 index 000000000..aee46ff56 --- /dev/null +++ b/src/main/java/net/coderbot/iris/JomlConversions.java @@ -0,0 +1,15 @@ +package net.coderbot.iris; + +import net.minecraft.util.Vec3; +import org.joml.Vector3d; +import org.joml.Vector4f; + +public class JomlConversions { + public static Vector3d fromVec3(Vec3 vec) { + return new Vector3d(vec.xCoord, vec.yCoord, vec.zCoord); + } + + public static Vector4f toJoml(Vector4f v) { + return new Vector4f(v.x(), v.y(), v.z(), v.w()); + } +} diff --git a/src/main/java/net/coderbot/iris/LaunchWarn.java b/src/main/java/net/coderbot/iris/LaunchWarn.java new file mode 100644 index 000000000..8a282d358 --- /dev/null +++ b/src/main/java/net/coderbot/iris/LaunchWarn.java @@ -0,0 +1,43 @@ +package net.coderbot.iris; + +import javax.swing.JOptionPane; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import java.awt.Desktop; +import java.awt.GraphicsEnvironment; +import java.io.IOException; +import java.net.URI; + +public class LaunchWarn { + public static void main(String[] args) { + // TODO: make this translatable + String message = "This file is the Fabric version of Iris, meant to be installed as a mod. Would you like to get the Iris Installer instead?"; + String fallback = "This file is the Fabric version of Iris, meant to be installed as a mod. Please download the Iris Installer from https://irisshaders.net."; + if (GraphicsEnvironment.isHeadless()) { + System.err.println(fallback); + } else { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ReflectiveOperationException | UnsupportedLookAndFeelException ignored) { + // Ignored + } + + if (Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { + int option = JOptionPane.showOptionDialog(null, message, "Iris Installer", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE, null, null, null); + + if (option == JOptionPane.YES_OPTION) { + try { + Desktop.getDesktop().browse(URI.create("https://irisshaders.net")); + } catch (IOException e) { + e.printStackTrace(); + } + } + } else { + // Fallback for Linux, etc users with no "default" browser + JOptionPane.showMessageDialog(null, fallback); + } + } + + System.exit(0); + } +} diff --git a/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0ConfigImpl.java b/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0ConfigImpl.java new file mode 100644 index 000000000..952bc5183 --- /dev/null +++ b/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0ConfigImpl.java @@ -0,0 +1,33 @@ +package net.coderbot.iris.apiimpl; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.config.IrisConfig; +import net.irisshaders.iris.api.v0.IrisApiConfig; + +import java.io.IOException; + +public class IrisApiV0ConfigImpl implements IrisApiConfig { + @Override + public boolean areShadersEnabled() { + return Iris.getIrisConfig().areShadersEnabled(); + } + + @Override + public void setShadersEnabledAndApply(boolean enabled) { + IrisConfig config = Iris.getIrisConfig(); + + config.setShadersEnabled(enabled); + + try { + config.save(); + } catch (IOException e) { + Iris.logger.error("Error saving configuration file!", e); + } + + try { + Iris.reload(); + } catch (IOException e) { + Iris.logger.error("Error reloading shader pack while applying changes!", e); + } + } +} diff --git a/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java b/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java new file mode 100644 index 000000000..b716db439 --- /dev/null +++ b/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java @@ -0,0 +1,60 @@ +package net.coderbot.iris.apiimpl; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.pipeline.FixedFunctionWorldRenderingPipeline; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.coderbot.iris.shadows.ShadowRenderingState; +import net.coderbot.iris.vertices.IrisTextVertexSinkImpl; +import net.irisshaders.iris.api.v0.IrisApi; +import net.irisshaders.iris.api.v0.IrisApiConfig; +import net.irisshaders.iris.api.v0.IrisTextVertexSink; + +import java.nio.ByteBuffer; +import java.util.function.IntFunction; + +public class IrisApiV0Impl implements IrisApi { + public static final IrisApiV0Impl INSTANCE = new IrisApiV0Impl(); + private static final IrisApiV0ConfigImpl CONFIG = new IrisApiV0ConfigImpl(); + + @Override + public int getMinorApiRevision() { + return 1; + } + + @Override + public boolean isShaderPackInUse() { + WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); + + if (pipeline == null) { + return false; + } + + return !(pipeline instanceof FixedFunctionWorldRenderingPipeline); + } + + @Override + public boolean isRenderingShadowPass() { + return ShadowRenderingState.areShadowsCurrentlyBeingRendered(); + } + + @Override + public Object openMainIrisScreenObj(Object parent) { + return new ShaderPackScreen((Screen) parent); + } + + @Override + public String getMainScreenLanguageKey() { + return "options.iris.shaderPackSelection"; + } + + @Override + public IrisApiConfig getConfig() { + return CONFIG; + } + + @Override + public IrisTextVertexSink createTextVertexSink(int maxQuadCount, IntFunction bufferProvider) { + return new IrisTextVertexSinkImpl(maxQuadCount, bufferProvider); + } +} diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java new file mode 100644 index 000000000..018a134aa --- /dev/null +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java @@ -0,0 +1,136 @@ +package net.coderbot.iris.block_rendering; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.materialmap.BlockEntry; +import net.coderbot.iris.shaderpack.materialmap.BlockRenderType; +import net.coderbot.iris.shaderpack.materialmap.NamespacedId; +import net.minecraft.block.Block; +import net.minecraft.util.ResourceLocation; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class BlockMaterialMapping { + public static Object2IntMap createBlockStateIdMap(Int2ObjectMap> blockPropertiesMap) { + Object2IntMap blockStateIds = new Object2IntOpenHashMap<>(); + + blockPropertiesMap.forEach((intId, entries) -> { + for (BlockEntry entry : entries) { + addBlockStates(entry, blockStateIds, intId); + } + }); + + return blockStateIds; + } + + public static Map createBlockTypeMap(Map blockPropertiesMap) { + Map blockTypeIds = new Reference2ReferenceOpenHashMap<>(); + + blockPropertiesMap.forEach((id, blockType) -> { + ResourceLocation resourceLocation = new ResourceLocation(id.getNamespace(), id.getName()); + + Block block = Registry.BLOCK.get(resourceLocation); + + blockTypeIds.put(block, convertBlockToRenderType(blockType)); + }); + + return blockTypeIds; + } + + private static RenderType convertBlockToRenderType(BlockRenderType type) { + if (type == null) { + return null; + } + + switch (type) { + case SOLID: return RenderType.solid(); + case CUTOUT: return RenderType.cutout(); + case CUTOUT_MIPPED: return RenderType.cutoutMipped(); + case TRANSLUCENT: return RenderType.translucent(); + default: return null; + } + } + + private static void addBlockStates(BlockEntry entry, Object2IntMap idMap, int intId) { + NamespacedId id = entry.getId(); + ResourceLocation resourceLocation = new ResourceLocation(id.getNamespace(), id.getName()); + + Block block = Registry.BLOCK.get(resourceLocation); + + // If the block doesn't exist, by default the registry will return AIR. That probably isn't what we want. + // TODO: Assuming that Registry.BLOCK.getDefaultId() == "minecraft:air" here + if (block == Blocks.AIR) { + return; + } + + Map propertyPredicates = entry.getPropertyPredicates(); + + if (propertyPredicates.isEmpty()) { + // Just add all the states if there aren't any predicates + for (BlockState state : block.getStateDefinition().getPossibleStates()) { + // NB: Using putIfAbsent means that the first successful mapping takes precedence + // Needed for OptiFine parity: + // https://github.com/IrisShaders/Iris/issues/1327 + idMap.putIfAbsent(state, intId); + } + + return; + } + + // As a result, we first collect each key=value pair in order to determine what properties we need to filter on. + // We already get this from BlockEntry, but we convert the keys to `Property`s to ensure they exist and to avoid + // string comparisons later. + Map, String> properties = new HashMap<>(); + StateDefinition stateManager = block.getStateDefinition(); + + propertyPredicates.forEach((key, value) -> { + Property property = stateManager.getProperty(key); + + if (property == null) { + Iris.logger.warn("Error while parsing the block ID map entry for \"" + "block." + intId + "\":"); + Iris.logger.warn("- The block " + resourceLocation + " has no property with the name " + key + ", ignoring!"); + + return; + } + + properties.put(property, value); + }); + + // Once we have a list of properties and their expected values, we iterate over every possible state of this + // block and check for ones that match the filters. This isn't particularly efficient, but it works! + for (BlockState state : stateManager.getPossibleStates()) { + if (checkState(state, properties)) { + // NB: Using putIfAbsent means that the first successful mapping takes precedence + // Needed for OptiFine parity: + // https://github.com/IrisShaders/Iris/issues/1327 + idMap.putIfAbsent(state, intId); + } + } + } + + // We ignore generics here, the actual types don't matter because we just convert + // them to strings anyways, and the compiler checks just get in the way. + // + // If you're able to rewrite this function without SuppressWarnings, feel free. + // But otherwise it works fine. + @SuppressWarnings({"rawtypes", "unchecked"}) + private static boolean checkState(BlockState state, Map, String> expectedValues) { + for (Map.Entry, String> condition : expectedValues.entrySet()) { + Property property = condition.getKey(); + String expectedValue = condition.getValue(); + + String actualValue = property.getName(state.getValue(property)); + + if (!expectedValue.equals(actualValue)) { + return false; + } + } + + return true; + } +} diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java new file mode 100644 index 000000000..eb70fa299 --- /dev/null +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java @@ -0,0 +1,130 @@ +package net.coderbot.iris.block_rendering; + +import it.unimi.dsi.fastutil.objects.Object2IntFunction; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.coderbot.iris.shaderpack.materialmap.NamespacedId; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +public class BlockRenderingSettings { + public static final BlockRenderingSettings INSTANCE = new BlockRenderingSettings(); + + private boolean reloadRequired; + private Object2IntMap blockStateIds; + private Map blockTypeIds; + private Object2IntFunction entityIds; + private float ambientOcclusionLevel; + private boolean disableDirectionalShading; + private boolean useSeparateAo; + private boolean useExtendedVertexFormat; + + public BlockRenderingSettings() { + reloadRequired = false; + blockStateIds = null; + blockTypeIds = null; + ambientOcclusionLevel = 1.0F; + disableDirectionalShading = false; + useSeparateAo = false; + useExtendedVertexFormat = false; + } + + public boolean isReloadRequired() { + return reloadRequired; + } + + public void clearReloadRequired() { + reloadRequired = false; + } + + @Nullable + public Object2IntMap getBlockStateIds() { + return blockStateIds; + } + + @Nullable + public Map getBlockTypeIds() { + return blockTypeIds; + } + + // TODO (coderbot): This doesn't belong here. But I couldn't think of a nicer place to put it. + @Nullable + public Object2IntFunction getEntityIds() { + return entityIds; + } + + public void setBlockStateIds(Object2IntMap blockStateIds) { + if (this.blockStateIds != null && this.blockStateIds.equals(blockStateIds)) { + return; + } + + this.reloadRequired = true; + this.blockStateIds = blockStateIds; + } + + public void setBlockTypeIds(Map blockTypeIds) { + if (this.blockTypeIds != null && this.blockTypeIds.equals(blockTypeIds)) { + return; + } + + this.reloadRequired = true; + this.blockTypeIds = blockTypeIds; + } + + public void setEntityIds(Object2IntFunction entityIds) { + // note: no reload needed, entities are rebuilt every frame. + this.entityIds = entityIds; + } + + public float getAmbientOcclusionLevel() { + return ambientOcclusionLevel; + } + + public void setAmbientOcclusionLevel(float ambientOcclusionLevel) { + if (ambientOcclusionLevel == this.ambientOcclusionLevel) { + return; + } + + this.reloadRequired = true; + this.ambientOcclusionLevel = ambientOcclusionLevel; + } + + public boolean shouldDisableDirectionalShading() { + return disableDirectionalShading; + } + + public void setDisableDirectionalShading(boolean disableDirectionalShading) { + if (disableDirectionalShading == this.disableDirectionalShading) { + return; + } + + this.reloadRequired = true; + this.disableDirectionalShading = disableDirectionalShading; + } + + public boolean shouldUseSeparateAo() { + return useSeparateAo; + } + + public void setUseSeparateAo(boolean useSeparateAo) { + if (useSeparateAo == this.useSeparateAo) { + return; + } + + this.reloadRequired = true; + this.useSeparateAo = useSeparateAo; + } + + public boolean shouldUseExtendedVertexFormat() { + return useExtendedVertexFormat; + } + + public void setUseExtendedVertexFormat(boolean useExtendedVertexFormat) { + if (useExtendedVertexFormat == this.useExtendedVertexFormat) { + return; + } + + this.reloadRequired = true; + this.useExtendedVertexFormat = useExtendedVertexFormat; + } +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/GLHelper.java b/src/main/java/net/coderbot/iris/compat/mojang/GLHelper.java new file mode 100644 index 000000000..ac8a130b0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/GLHelper.java @@ -0,0 +1,18 @@ +package net.coderbot.iris.compat.mojang; + +import net.minecraft.client.renderer.OpenGlHelper; + +public class GLHelper { + + public static void glDeleteFramebuffers(int framebuffer) { + OpenGlHelper.func_153174_h(framebuffer); + } + + public static int glCheckFramebufferStatus(int target) { + return OpenGlHelper.func_153167_i(target); + } + + public static int glGenFramebuffers() { + return OpenGlHelper.func_153165_e/*glGenFramebuffers*/(); + } +} diff --git a/src/main/java/net/coderbot/iris/config/IrisConfig.java b/src/main/java/net/coderbot/iris/config/IrisConfig.java new file mode 100644 index 000000000..a9fad4fa2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/config/IrisConfig.java @@ -0,0 +1,172 @@ +package net.coderbot.iris.config; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.option.IrisVideoSettings; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; +import java.util.Properties; + +/** + * A class dedicated to storing the config values of shaderpacks. Right now it only stores the path to the current shaderpack + */ +public class IrisConfig { + private static final String COMMENT = + "This file stores configuration options for " + Iris.MODNAME + ", such as the currently active shaderpack"; + + /** + * The path to the current shaderpack. Null if the internal shaderpack is being used. + */ + private String shaderPackName; + + /** + * Whether or not shaders are used for rendering. False to disable all shader-based rendering, true to enable it. + */ + private boolean enableShaders; + + /** + * If debug features should be enabled. Gives much more detailed OpenGL error outputs at the cost of performance. + */ + private boolean enableDebugOptions; + + /** + * If the update notification should be disabled or not. + */ + private boolean disableUpdateMessage; + + private final Path propertiesPath; + + public IrisConfig(Path propertiesPath) { + shaderPackName = null; + enableShaders = true; + enableDebugOptions = false; + disableUpdateMessage = false; + this.propertiesPath = propertiesPath; + } + + /** + * Initializes the configuration, loading it if it is present and creating a default config otherwise. + * + * @throws IOException file exceptions + */ + public void initialize() throws IOException { + load(); + if (!Files.exists(propertiesPath)) { + save(); + } + } + + /** + * returns whether or not the current shaderpack is internal + * + * @return if the shaderpack is internal + */ + public boolean isInternal() { + return false; + } + + /** + * Returns the name of the current shaderpack + * + * @return Returns the current shaderpack name - if internal shaders are being used it returns "(internal)" + */ + public Optional getShaderPackName() { + return Optional.ofNullable(shaderPackName); + } + + /** + * Sets the name of the current shaderpack + */ + public void setShaderPackName(String name) { + if (name == null || name.equals("(internal)") || name.isEmpty()) { + this.shaderPackName = null; + } else { + this.shaderPackName = name; + } + } + + /** + * Determines whether or not shaders are used for rendering. + * + * @return False to disable all shader-based rendering, true to enable shader-based rendering. + */ + public boolean areShadersEnabled() { + return enableShaders; + } + + public boolean areDebugOptionsEnabled() { + return enableDebugOptions; + } + + public boolean shouldDisableUpdateMessage() { + return disableUpdateMessage; + } + + public void setDebugEnabled(boolean enabled) { + enableDebugOptions = enabled; + } + + /** + * Sets whether shaders should be used for rendering. + */ + public void setShadersEnabled(boolean enabled) { + this.enableShaders = enabled; + } + + /** + * loads the config file and then populates the string, int, and boolean entries with the parsed entries + * + * @throws IOException if the file cannot be loaded + */ + + public void load() throws IOException { + if (!Files.exists(propertiesPath)) { + return; + } + + Properties properties = new Properties(); + // NB: This uses ISO-8859-1 with unicode escapes as the encoding + try (InputStream is = Files.newInputStream(propertiesPath)) { + properties.load(is); + } + shaderPackName = properties.getProperty("shaderPack"); + enableShaders = !"false".equals(properties.getProperty("enableShaders")); + enableDebugOptions = "true".equals(properties.getProperty("enableDebugOptions")); + disableUpdateMessage = "true".equals(properties.getProperty("disableUpdateMessage")); + try { + IrisVideoSettings.shadowDistance = Integer.parseInt(properties.getProperty("maxShadowRenderDistance", "32")); + } catch (NumberFormatException e) { + Iris.logger.error("Shadow distance setting reset; value is invalid."); + IrisVideoSettings.shadowDistance = 32; + save(); + } + + if (shaderPackName != null) { + if (shaderPackName.equals("(internal)") || shaderPackName.isEmpty()) { + shaderPackName = null; + } + } + } + + /** + * Serializes the config into a file. Should be called whenever any config values are modified. + * + * @throws IOException file exceptions + */ + public void save() throws IOException { + Properties properties = new Properties(); + properties.setProperty("shaderPack", getShaderPackName().orElse("")); + properties.setProperty("enableShaders", enableShaders ? "true" : "false"); + properties.setProperty("enableDebugOptions", enableDebugOptions ? "true" : "false"); + properties.setProperty("disableUpdateMessage", disableUpdateMessage ? "true" : "false"); + properties.setProperty("maxShadowRenderDistance", String.valueOf(IrisVideoSettings.shadowDistance)); + // NB: This uses ISO-8859-1 with unicode escapes as the encoding + try (OutputStream os = Files.newOutputStream(propertiesPath)) { + properties.store(os, COMMENT); + } + } +} diff --git a/src/main/java/net/coderbot/iris/fantastic/IrisParticleRenderTypes.java b/src/main/java/net/coderbot/iris/fantastic/IrisParticleRenderTypes.java new file mode 100644 index 000000000..42c4502fc --- /dev/null +++ b/src/main/java/net/coderbot/iris/fantastic/IrisParticleRenderTypes.java @@ -0,0 +1,24 @@ +package net.coderbot.iris.fantastic; + +import net.minecraft.client.renderer.texture.TextureManager; +import org.lwjgl.opengl.GL11; + +public class IrisParticleRenderTypes { + public static final ParticleRenderType OPAQUE_TERRAIN = new ParticleRenderType() { + public void begin(BufferBuilder bufferBuilder, TextureManager textureManager) { + GL11.glDisable(GL11.GL_BLEND); + GL11.glDepthMask(true); + GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F); + textureManager.bind(TextureAtlas.LOCATION_BLOCKS); + bufferBuilder.begin(7, DefaultVertexFormat.PARTICLE); + } + + public void end(Tesselator tesselator) { + tesselator.end(); + } + + public String toString() { + return "OPAQUE_TERRAIN_SHEET"; + } + }; +} diff --git a/src/main/java/net/coderbot/iris/fantastic/ParticleRenderingPhase.java b/src/main/java/net/coderbot/iris/fantastic/ParticleRenderingPhase.java new file mode 100644 index 000000000..ee5d4980a --- /dev/null +++ b/src/main/java/net/coderbot/iris/fantastic/ParticleRenderingPhase.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.fantastic; + +public enum ParticleRenderingPhase { + EVERYTHING, + OPAQUE, + TRANSLUCENT +} diff --git a/src/main/java/net/coderbot/iris/fantastic/PhasedParticleEngine.java b/src/main/java/net/coderbot/iris/fantastic/PhasedParticleEngine.java new file mode 100644 index 000000000..fee55dce7 --- /dev/null +++ b/src/main/java/net/coderbot/iris/fantastic/PhasedParticleEngine.java @@ -0,0 +1,5 @@ +package net.coderbot.iris.fantastic; + +public interface PhasedParticleEngine { + void setParticleRenderingPhase(ParticleRenderingPhase phase); +} diff --git a/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java b/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java new file mode 100644 index 000000000..34c99a14a --- /dev/null +++ b/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java @@ -0,0 +1,10 @@ +package net.coderbot.iris.fantastic; + + +import java.util.function.Function; + +public interface WrappingMultiBufferSource { + void pushWrappingFunction(Function wrappingFunction); + void popWrappingFunction(); + void assertWrapStackEmpty(); +} diff --git a/src/main/java/net/coderbot/iris/features/FeatureFlags.java b/src/main/java/net/coderbot/iris/features/FeatureFlags.java new file mode 100644 index 000000000..a1619e3b9 --- /dev/null +++ b/src/main/java/net/coderbot/iris/features/FeatureFlags.java @@ -0,0 +1,69 @@ +package net.coderbot.iris.features; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.minecraft.client.resources.I18n; +import org.apache.commons.lang3.text.WordUtils; + +import java.util.List; +import java.util.function.BooleanSupplier; + +public enum FeatureFlags { + SEPARATE_HARDWARE_SAMPLERS(() -> true, () -> true), + PER_BUFFER_BLENDING(() -> true, IrisRenderSystem::supportsBufferBlending), + COMPUTE_SHADERS(() -> true, IrisRenderSystem::supportsCompute), + ENTITY_TRANSLUCENT(() -> true, () -> true), + UNKNOWN(() -> false, () -> false); + + private final BooleanSupplier irisRequirement; + private final BooleanSupplier hardwareRequirement; + + FeatureFlags(BooleanSupplier irisRequirement, BooleanSupplier hardwareRequirement) { + this.irisRequirement = irisRequirement; + this.hardwareRequirement = hardwareRequirement; + } + + public static String getInvalidStatus(List invalidFeatureFlags) { + boolean unsupportedHardware = false, unsupportedIris = false; + FeatureFlags[] flags = invalidFeatureFlags.toArray(new FeatureFlags[0]); + for (FeatureFlags flag : flags) { + unsupportedIris |= !flag.irisRequirement.getAsBoolean(); + unsupportedHardware |= !flag.hardwareRequirement.getAsBoolean(); + } + + if (unsupportedIris) { + if (unsupportedHardware) { + return I18n.format("iris.unsupported.irisorpc"); + } + + return I18n.format("iris.unsupported.iris"); + } else if (unsupportedHardware) { + return I18n.format("iris.unsupported.pc"); + } else { + return null; + } + } + + public String getHumanReadableName() { + return WordUtils.capitalize(name().replace("_", " ").toLowerCase()); + } + + public boolean isUsable() { + return irisRequirement.getAsBoolean() && hardwareRequirement.getAsBoolean(); + } + + public static boolean isInvalid(String name) { + try { + return !FeatureFlags.valueOf(name).isUsable(); + } catch (IllegalArgumentException e) { + return true; + } + } + + public static FeatureFlags getValue(String value) { + try { + return FeatureFlags.valueOf(value); + } catch (IllegalArgumentException e) { + return FeatureFlags.UNKNOWN; + } + } +} diff --git a/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/InputAvailability.java b/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/InputAvailability.java new file mode 100644 index 000000000..cf0899196 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/InputAvailability.java @@ -0,0 +1,78 @@ +package net.coderbot.iris.gbuffer_overrides.matching; + +public class InputAvailability { + public static final int NUM_VALUES = 8; + + public final boolean texture; + public final boolean lightmap; + public final boolean overlay; + + public InputAvailability(boolean texture, boolean lightmap, boolean overlay) { + this.texture = texture; + this.lightmap = lightmap; + this.overlay = overlay; + } + + public InputAvailability withoutOverlay() { + return new InputAvailability(texture, lightmap, false); + } + + public static InputAvailability unpack(int packed) { + return new InputAvailability((packed & 1) == 1, (packed & 2) == 2, (packed & 4) == 4); + } + + public int pack() { + int packed = 0; + + if (overlay) { + packed |= 4; + } + + if (lightmap) { + packed |= 2; + } + + if (texture) { + packed |= 1; + } + + return packed; + } + + @Override + public String toString() { + return "InputAvailability{" + + "texture=" + texture + + ", lightmap=" + lightmap + + ", overlay=" + overlay + + '}'; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (lightmap ? 1231 : 1237); + result = prime * result + (overlay ? 1231 : 1237); + result = prime * result + (texture ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + InputAvailability other = (InputAvailability) obj; + if (lightmap != other.lightmap) + return false; + if (overlay != other.overlay) + return false; + if (texture != other.texture) + return false; + return true; + } +} diff --git a/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/ProgramTable.java b/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/ProgramTable.java new file mode 100644 index 000000000..e581a4830 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/ProgramTable.java @@ -0,0 +1,31 @@ +package net.coderbot.iris.gbuffer_overrides.matching; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Consumer; + +public class ProgramTable { + private final List table = new ArrayList<>(); + + public ProgramTable(BiFunction constructor) { + for (RenderCondition condition : RenderCondition.values()) { + for (int packedAvailability = 0; packedAvailability < InputAvailability.NUM_VALUES; packedAvailability++) { + InputAvailability availability = InputAvailability.unpack(packedAvailability); + + table.add(constructor.apply(condition, availability)); + } + } + } + + // TODO: Remove InputAvailability allocations? + public T match(RenderCondition condition, InputAvailability availability) { + int index = (condition.ordinal() * InputAvailability.NUM_VALUES) + availability.pack(); + + return table.get(index); + } + + public void forEach(Consumer consumer) { + table.forEach(consumer); + } +} diff --git a/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/RenderCondition.java b/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/RenderCondition.java new file mode 100644 index 000000000..258336274 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/RenderCondition.java @@ -0,0 +1,22 @@ +package net.coderbot.iris.gbuffer_overrides.matching; + +public enum RenderCondition { + DEFAULT, + SKY, + TERRAIN_OPAQUE, + TERRAIN_TRANSLUCENT, + CLOUDS, + DESTROY, + BLOCK_ENTITIES, + BEACON_BEAM, + ENTITIES, + ENTITIES_TRANSLUCENT, + GLINT, + ENTITY_EYES, + HAND_OPAQUE, + HAND_TRANSLUCENT, + RAIN_SNOW, + WORLD_BORDER, + // NB: Must be last due to implementation details of DeferredWorldRenderingPipeline + SHADOW +} diff --git a/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/SpecialCondition.java b/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/SpecialCondition.java new file mode 100644 index 000000000..deeb20933 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gbuffer_overrides/matching/SpecialCondition.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.gbuffer_overrides.matching; + +public enum SpecialCondition { + ENTITY_EYES, + BEACON_BEAM, + GLINT +} diff --git a/src/main/java/net/coderbot/iris/gbuffer_overrides/state/RenderTargetStateListener.java b/src/main/java/net/coderbot/iris/gbuffer_overrides/state/RenderTargetStateListener.java new file mode 100644 index 000000000..a3a7a9212 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gbuffer_overrides/state/RenderTargetStateListener.java @@ -0,0 +1,25 @@ +package net.coderbot.iris.gbuffer_overrides.state; + +public interface RenderTargetStateListener { + RenderTargetStateListener NOP = new RenderTargetStateListener() { + @Override + public void beginPostChain() { + + } + + @Override + public void endPostChain() { + + } + + @Override + public void setIsMainBound(boolean bound) { + + } + }; + + void beginPostChain(); + void endPostChain(); + + void setIsMainBound(boolean bound); +} diff --git a/src/main/java/net/coderbot/iris/gbuffer_overrides/state/StateTracker.java b/src/main/java/net/coderbot/iris/gbuffer_overrides/state/StateTracker.java new file mode 100644 index 000000000..bf6c6e982 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gbuffer_overrides/state/StateTracker.java @@ -0,0 +1,22 @@ +package net.coderbot.iris.gbuffer_overrides.state; + +import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; + +public class StateTracker { + public static final StateTracker INSTANCE = new StateTracker(); + + // All textures are disabled by default + + // TextureStateShard / TextureUnit.TERRAIN + public boolean albedoSampler; + // LightmapStateShard / TextureUnit.LIGHTMAP + public boolean lightmapSampler; + // OverlayStateShard / TextureUnit.OVERLAY + public boolean overlaySampler; + + public InputAvailability getInputs() { + return new InputAvailability(albedoSampler, + lightmapSampler, + overlaySampler); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/GLDebug.java b/src/main/java/net/coderbot/iris/gl/GLDebug.java new file mode 100644 index 000000000..d55220c9d --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/GLDebug.java @@ -0,0 +1,262 @@ +/* + * Copyright LWJGL. All rights reserved. Modified by IMS for use in Iris (net.coderbot.iris.gl). + * License terms: https://www.lwjgl.org/license + */ + +package net.coderbot.iris.gl; + +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import net.coderbot.iris.Iris; +import org.lwjgl.opengl.AMDDebugOutput; +import org.lwjgl.opengl.AMDDebugOutputCallback; +import org.lwjgl.opengl.ARBDebugOutput; +import org.lwjgl.opengl.ARBDebugOutputCallback; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GL43; +import org.lwjgl.opengl.KHRDebug; +import org.lwjgl.opengl.KHRDebugCallback; + +import java.io.PrintStream; +import java.util.function.Consumer; + +import static org.lwjgl.opengl.ARBDebugOutput.glDebugMessageCallbackARB; + +public final class GLDebug { + + private static void trace(Consumer output) { + /* + * We can not just use a fixed stacktrace element offset, because some methods + * are intercepted and some are not. So, check the package name. + */ + StackTraceElement[] elems = filterStackTrace(new Throwable(), 4).getStackTrace(); + for (StackTraceElement ste : elems) { + output.accept(ste.toString()); + } + } + + public static Throwable filterStackTrace(Throwable throwable, int offset) { + StackTraceElement[] elems = throwable.getStackTrace(); + StackTraceElement[] filtered = new StackTraceElement[elems.length]; + int j = 0; + for (int i = offset; i < elems.length; i++) { + String className = elems[i].getClassName(); + if (className == null) { + className = ""; + } + filtered[j++] = elems[i]; + } + StackTraceElement[] newElems = new StackTraceElement[j]; + System.arraycopy(filtered, 0, newElems, 0, j); + throwable.setStackTrace(newElems); + return throwable; + } + + private static void printTrace(PrintStream stream) { + trace(new Consumer() { + boolean first = true; + + public void accept(String str) { + if (first) { + printDetail(stream, "Stacktrace", str); + first = false; + } else { + printDetailLine(stream, "Stacktrace", str); + } + } + }); + } + + /** + * Sets up debug callbacks + * @return 0 for failure, 1 for success, 2 for restart required. + */ + public static int setupDebugMessageCallback() { + if (Iris.capabilities.OpenGL43 || Iris.capabilities.GL_KHR_debug) { + AngelicaTweaker.LOGGER.info("[GL] Using KHR_debug for error logging."); + KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); + KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); + KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_LOW, null, false); + KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, null, false); + KHRDebug.glDebugMessageCallback(new KHRDebugCallback()); + + if (Iris.capabilities.OpenGL30 && (GL11.glGetInteger(GL30.GL_CONTEXT_FLAGS) & 2) == 0) { + AngelicaTweaker.LOGGER.warn("[GL] Warning: A non-debug context may not produce any debug output."); + GL11.glDisable(GL43.GL_DEBUG_OUTPUT); + return 2; + } + return 1; + } else if (Iris.capabilities.GL_ARB_debug_output) { + AngelicaTweaker.LOGGER.info("[GL] Using ARB_debug_output for error logging."); + + ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); + ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); + ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_LOW, null, false); + ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, null, false); + glDebugMessageCallbackARB(new ARBDebugOutputCallback()); + return 1; + } else if (Iris.capabilities.GL_AMD_debug_output) { + AngelicaTweaker.LOGGER.info("[GL] Using AMD_debug_output for error logging."); + + AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); + AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); + AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_LOW, null, false); + AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, null, false); + AMDDebugOutput.glDebugMessageCallbackAMD(new AMDDebugOutputCallback()); + return 1; + } else { + AngelicaTweaker.LOGGER.info("[GL] No debug output implementation is available, cannot return debug info."); + return 0; + } + } + + public static int disableDebugMessages() { + if (Iris.capabilities.OpenGL43) { + GL43.glDebugMessageCallback(null); + return 1; + } else if (Iris.capabilities.GL_KHR_debug) { + KHRDebug.glDebugMessageCallback(null); + if (Iris.capabilities.OpenGL30 && (GL11.glGetInteger(GL30.GL_CONTEXT_FLAGS) & 2) == 0) { + GL11.glDisable(GL43.GL_DEBUG_OUTPUT); + } + return 1; + } else if (Iris.capabilities.GL_ARB_debug_output) { + glDebugMessageCallbackARB(null); + return 1; + } else if (Iris.capabilities.GL_AMD_debug_output) { + AMDDebugOutput.glDebugMessageCallbackAMD(null); + return 1; + } else { + AngelicaTweaker.LOGGER.info("[GL] No debug output implementation is available, cannot disable debug info."); + return 0; + } + } + + private static void printDetail(PrintStream stream, String type, String message) { + stream.printf("\t%s: %s\n", type, message); + } + + private static void printDetailLine(PrintStream stream, String type, String message) { + stream.append(" "); + for (int i = 0; i < type.length(); i++) { + stream.append(" "); + } + stream.append(message).append("\n"); + } + + private static String getDebugSource(int source) { + return switch (source) { + case GL43.GL_DEBUG_SOURCE_API -> "API"; + case GL43.GL_DEBUG_SOURCE_WINDOW_SYSTEM -> "WINDOW SYSTEM"; + case GL43.GL_DEBUG_SOURCE_SHADER_COMPILER -> "SHADER COMPILER"; + case GL43.GL_DEBUG_SOURCE_THIRD_PARTY -> "THIRD PARTY"; + case GL43.GL_DEBUG_SOURCE_APPLICATION -> "APPLICATION"; + case GL43.GL_DEBUG_SOURCE_OTHER -> "OTHER"; + default -> String.format("Unknown [0x%X]", source); + }; + } + + private static String getDebugType(int type) { + return switch (type) { + case GL43.GL_DEBUG_TYPE_ERROR -> "ERROR"; + case GL43.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR -> "DEPRECATED BEHAVIOR"; + case GL43.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR -> "UNDEFINED BEHAVIOR"; + case GL43.GL_DEBUG_TYPE_PORTABILITY -> "PORTABILITY"; + case GL43.GL_DEBUG_TYPE_PERFORMANCE -> "PERFORMANCE"; + case GL43.GL_DEBUG_TYPE_OTHER -> "OTHER"; + case GL43.GL_DEBUG_TYPE_MARKER -> "MARKER"; + default -> String.format("Unknown [0x%X]", type); + }; + } + + private static String getDebugSeverity(int severity) { + return switch (severity) { + case GL43.GL_DEBUG_SEVERITY_NOTIFICATION -> "NOTIFICATION"; + case GL43.GL_DEBUG_SEVERITY_HIGH -> "HIGH"; + case GL43.GL_DEBUG_SEVERITY_MEDIUM -> "MEDIUM"; + case GL43.GL_DEBUG_SEVERITY_LOW -> "LOW"; + default -> String.format("Unknown [0x%X]", severity); + }; + } + + + private static String getCategoryAMD(int category) { + return switch (category) { + case AMDDebugOutput.GL_DEBUG_CATEGORY_API_ERROR_AMD -> "API ERROR"; + case AMDDebugOutput.GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD -> "WINDOW SYSTEM"; + case AMDDebugOutput.GL_DEBUG_CATEGORY_DEPRECATION_AMD -> "DEPRECATION"; + case AMDDebugOutput.GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD -> "UNDEFINED BEHAVIOR"; + case AMDDebugOutput.GL_DEBUG_CATEGORY_PERFORMANCE_AMD -> "PERFORMANCE"; + case AMDDebugOutput.GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD -> "SHADER COMPILER"; + case AMDDebugOutput.GL_DEBUG_CATEGORY_APPLICATION_AMD -> "APPLICATION"; + case AMDDebugOutput.GL_DEBUG_CATEGORY_OTHER_AMD -> "OTHER"; + default -> String.format("Unknown [0x%X]", category); + }; + } + + private static String getSeverityAMD(int severity) { + return switch (severity) { + case AMDDebugOutput.GL_DEBUG_SEVERITY_HIGH_AMD -> "HIGH"; + case AMDDebugOutput.GL_DEBUG_SEVERITY_MEDIUM_AMD -> "MEDIUM"; + case AMDDebugOutput.GL_DEBUG_SEVERITY_LOW_AMD -> "LOW"; + default -> String.format("Unknown [0x%X]", severity); + }; + } + + private static DebugState debugState; + + private static interface DebugState { + void nameObject(int id, int object, String name); + void pushGroup(int id, String name); + void popGroup(); + } + + private static class KHRDebugState implements DebugState { + private boolean hasGroup; + + @Override + public void nameObject(int id, int object, String name) { + KHRDebug.glObjectLabel(id, object, name); + } + + @Override + public void pushGroup(int id, String name) { + KHRDebug.glPushDebugGroup(KHRDebug.GL_DEBUG_SOURCE_APPLICATION, id, name); + hasGroup = true; + } + + @Override + public void popGroup() { + if (hasGroup) { + KHRDebug.glPopDebugGroup(); + hasGroup = false; + } + } + } + + private static class UnsupportedDebugState implements DebugState { + @Override + public void nameObject(int id, int object, String name) { + } + + @Override + public void pushGroup(int id, String name) { + } + + @Override + public void popGroup() { + } + } + + public static void initRenderer() { + if (Iris.capabilities.GL_KHR_debug || Iris.capabilities.OpenGL43) { + debugState = new KHRDebugState(); + } else { + debugState = new UnsupportedDebugState(); + } + } + + public static void nameObject(int id, int object, String name) { + debugState.nameObject(id, object, name); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/GlResource.java b/src/main/java/net/coderbot/iris/gl/GlResource.java new file mode 100644 index 000000000..7cf0a4fff --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/GlResource.java @@ -0,0 +1,30 @@ +package net.coderbot.iris.gl; + +public abstract class GlResource { + private final int id; + private boolean isValid; + + protected GlResource(int id) { + this.id = id; + isValid = true; + } + + public final void destroy() { + destroyInternal(); + isValid = false; + } + + protected abstract void destroyInternal(); + + protected void assertValid() { + if (!isValid) { + throw new IllegalStateException("Tried to use a destroyed GlResource"); + } + } + + protected int getGlId() { + assertValid(); + + return id; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/GlVersion.java b/src/main/java/net/coderbot/iris/gl/GlVersion.java new file mode 100644 index 000000000..7a72e007a --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/GlVersion.java @@ -0,0 +1,8 @@ +package net.coderbot.iris.gl; + +public enum GlVersion { + GL_11, + GL_12, + GL_30, + GL_31 +} diff --git a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java new file mode 100644 index 000000000..f1c9f2fd6 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java @@ -0,0 +1,492 @@ +package net.coderbot.iris.gl; + +import net.coderbot.iris.Iris; +import net.minecraft.client.renderer.OpenGlHelper; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3i; +import org.lwjgl.opengl.ARBDirectStateAccess; +import org.lwjgl.opengl.EXTShaderImageLoadStore; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GL40; +import org.lwjgl.opengl.GL42; +import org.lwjgl.opengl.GL43; +import org.lwjgl.opengl.GL45; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + +/** + * This class is responsible for abstracting calls to OpenGL and asserting that calls are run on the render thread. + */ +public class IrisRenderSystem { + private static DSAAccess dsaState; + private static boolean hasMultibind; + private static boolean supportsCompute; + + public static void initRenderer() { + if (Iris.capabilities.OpenGL45) { + dsaState = new DSACore(); + Iris.logger.info("OpenGL 4.5 detected, enabling DSA."); + } else if (Iris.capabilities.GL_ARB_direct_state_access) { + dsaState = new DSAARB(); + Iris.logger.info("ARB_direct_state_access detected, enabling DSA."); + } else { + dsaState = new DSAUnsupported(); + Iris.logger.info("DSA support not detected."); + } + + if (Iris.capabilities.OpenGL45 || Iris.capabilities.GL_ARB_multi_bind) { + hasMultibind = true; + } else { + hasMultibind = false; + } + + supportsCompute = supportsCompute(); + } + + public static void getIntegerv(int pname, int[] params) { + // TODO: Iris Shaders - IntBuffer + GL11.glGetInteger(pname, IntBuffer.wrap(params)); + } + + public static void getFloatv(int pname, float[] params) { + // TODO: Iris Shaders - FloatBuffer + GL11.glGetFloat(pname, FloatBuffer.wrap(params)); + } + + public static void generateMipmaps(int texture, int mipmapTarget) { + dsaState.generateMipmaps(texture, mipmapTarget); + } + + public static void bindAttributeLocation(int program, int index, CharSequence name) { + GL20.glBindAttribLocation(program, index, name); + } + + public static void texImage2D(int texture, int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable ByteBuffer pixels) { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + } + + public static void uniformMatrix4fv(int location, boolean transpose, FloatBuffer matrix) { + GL20.glUniformMatrix4(location, transpose, matrix); + } + + public static void copyTexImage2D(int target, int level, int internalFormat, int x, int y, int width, int height, int border) { + GL11.glCopyTexImage2D(target, level, internalFormat, x, y, width, height, border); + } + + public static void uniform1f(int location, float v0) { + GL20.glUniform1f(location, v0); + } + + public static void uniform1i(int location, int v0) { + GL20.glUniform1i(location, v0); + } + + public static void uniform2f(int location, float v0, float v1) { + GL20.glUniform2f(location, v0, v1); + } + + public static void uniform2i(int location, int v0, int v1) { + GL20.glUniform2i(location, v0, v1); + } + + public static void uniform3f(int location, float v0, float v1, float v2) { + GL20.glUniform3f(location, v0, v1, v2); + } + + public static void uniform4f(int location, float v0, float v1, float v2, float v3) { + GL20.glUniform4f(location, v0, v1, v2, v3); + } + + public static void uniform4i(int location, int v0, int v1, int v2, int v3) { + GL20.glUniform4i(location, v0, v1, v2, v3); + } + + public static int getAttribLocation(int programId, String name) { + return GL20.glGetAttribLocation(programId, name); + } + + public static int getUniformLocation(int programId, String name) { + return GL20.glGetUniformLocation(programId, name); + } + + public static void texParameteriv(int texture, int target, int pname, int[] params) { + dsaState.texParameteriv(texture, target, pname, params); + } + + public static void copyTexSubImage2D(int destTexture, int target, int i, int i1, int i2, int i3, int i4, int width, int height) { + dsaState.copyTexSubImage2D(destTexture, target, i, i1, i2, i3, i4, width, height); + } + + public static void texParameteri(int texture, int target, int pname, int param) { + dsaState.texParameteri(texture, target, pname, param); + } + + public static void texParameterf(int texture, int target, int pname, float param) { + dsaState.texParameterf(texture, target, pname, param); + } + + public static String getProgramInfoLog(int program) { + return GL20.glGetProgramInfoLog(program, GL20.glGetProgrami(program, GL20.GL_INFO_LOG_LENGTH)); + } + + public static String getShaderInfoLog(int shader) { + return GL20.glGetShaderInfoLog(shader, GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH)); + } + + public static void drawBuffers(int framebuffer, int[] buffers) { + dsaState.drawBuffers(framebuffer, buffers); + } + + public static void readBuffer(int framebuffer, int buffer) { + dsaState.readBuffer(framebuffer, buffer); + } + + public static String getActiveUniform(int program, int index, int maxLength, IntBuffer sizeType) { + return GL20.glGetActiveUniform(program, index, maxLength, sizeType); + } + + public static void readPixels(int x, int y, int width, int height, int format, int type, float[] pixels) { + GL11.glReadPixels(x, y, width, height, format, type, FloatBuffer.wrap(pixels)); + } + + public static void bufferData(int target, float[] data, int usage) { + GL15.glBufferData(target, FloatBuffer.wrap(data), usage); + } + + public static int bufferStorage(int target, float[] data, int usage) { + return dsaState.bufferStorage(target, data, usage); + } + + public static void vertexAttrib4f(int index, float v0, float v1, float v2, float v3) { + GL20.glVertexAttrib4f(index, v0, v1, v2, v3); + } + + public static void detachShader(int program, int shader) { + GL20.glDetachShader(program, shader); + } + + public static void framebufferTexture2D(int fb, int fbtarget, int attachment, int target, int texture, int levels) { + dsaState.framebufferTexture2D(fb, fbtarget, attachment, target, texture, levels); + } + + public static int getTexParameteri(int texture, int target, int pname) { + return dsaState.getTexParameteri(texture, target, pname); + } + + public static void bindImageTexture(int unit, int texture, int level, boolean layered, int layer, int access, int format) { + if (Iris.capabilities.OpenGL42) { + GL42.glBindImageTexture(unit, texture, level, layered, layer, access, format); + } else { + EXTShaderImageLoadStore.glBindImageTextureEXT(unit, texture, level, layered, layer, access, format); + } + } + + public static int getMaxImageUnits() { + if (Iris.capabilities.OpenGL42) { + return GL11.glGetInteger(GL42.GL_MAX_IMAGE_UNITS); + } else if (Iris.capabilities.GL_EXT_shader_image_load_store) { + return GL11.glGetInteger(EXTShaderImageLoadStore.GL_MAX_IMAGE_UNITS_EXT); + } else { + return 0; + } + } + + public static void getProgramiv(int program, int value, int[] storage) { + GL20.glGetProgram(program, value, IntBuffer.wrap(storage)); + } + + public static void dispatchCompute(int workX, int workY, int workZ) { + GL43.glDispatchCompute(workX, workY, workZ); + } + + public static void dispatchCompute(Vector3i workGroups) { + GL43.glDispatchCompute(workGroups.x, workGroups.y, workGroups.z); + } + + public static void memoryBarrier(int barriers) { + if (supportsCompute) { + GL42.glMemoryBarrier(barriers); + } + } + + public static boolean supportsBufferBlending() { + return Iris.capabilities.GL_ARB_draw_buffers_blend || Iris.capabilities.OpenGL40; + } + + public static void disableBufferBlend(int buffer) { + GL30.glDisablei(GL11.GL_BLEND, buffer); + } + + public static void enableBufferBlend(int buffer) { + GL30.glEnablei(GL11.GL_BLEND, buffer); + } + + public static void blendFuncSeparatei(int buffer, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) { + GL40.glBlendFuncSeparatei(buffer, srcRGB, dstRGB, srcAlpha, dstAlpha); + } + + public static void bindTextureToUnit(int unit, int texture) { + dsaState.bindTextureToUnit(unit, texture); + } + + public static void setupProjectionMatrix(float[] matrix) { + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glPushMatrix(); + GL11.glLoadMatrix(FloatBuffer.wrap(matrix)); + GL11.glMatrixMode(GL11.GL_MODELVIEW); + } + + public static void restoreProjectionMatrix() { + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glPopMatrix(); + GL11.glMatrixMode(GL11.GL_MODELVIEW); + } + + public static void blitFramebuffer(int source, int dest, int offsetX, int offsetY, int width, int height, int offsetX2, int offsetY2, int width2, int height2, int bufferChoice, int filter) { + dsaState.blitFramebuffer(source, dest, offsetX, offsetY, width, height, offsetX2, offsetY2, width2, height2, bufferChoice, filter); + } + + public static int createFramebuffer() { + return dsaState.createFramebuffer(); + } + + public static int createTexture(int target) { + return dsaState.createTexture(target); + } + + public interface DSAAccess { + void generateMipmaps(int texture, int target); + + void texParameteri(int texture, int target, int pname, int param); + void texParameterf(int texture, int target, int pname, float param); + void texParameteriv(int texture, int target, int pname, int[] params); + + void readBuffer(int framebuffer, int buffer); + + void drawBuffers(int framebuffer, int[] buffers); + + int getTexParameteri(int texture, int target, int pname); + + void copyTexSubImage2D(int destTexture, int target, int i, int i1, int i2, int i3, int i4, int width, int height); + + void bindTextureToUnit(int unit, int texture); + + int bufferStorage(int target, float[] data, int usage); + + void blitFramebuffer(int source, int dest, int offsetX, int offsetY, int width, int height, int offsetX2, int offsetY2, int width2, int height2, int bufferChoice, int filter); + + void framebufferTexture2D(int fb, int fbtarget, int attachment, int target, int texture, int levels); + + int createFramebuffer(); + int createTexture(int target); + } + + public static class DSACore extends DSAARB { + + } + + public static class DSAARB extends DSAUnsupported { + + @Override + public void generateMipmaps(int texture, int target) { + ARBDirectStateAccess.glGenerateTextureMipmap(texture); + } + + @Override + public void texParameteri(int texture, int target, int pname, int param) { + ARBDirectStateAccess.glTextureParameteri(texture, pname, param); + } + + @Override + public void texParameterf(int texture, int target, int pname, float param) { + ARBDirectStateAccess.glTextureParameterf(texture, pname, param); + } + + @Override + public void texParameteriv(int texture, int target, int pname, int[] params) { + ARBDirectStateAccess.glTextureParameter(texture, pname, IntBuffer.wrap(params)); + } + + @Override + public void readBuffer(int framebuffer, int buffer) { + ARBDirectStateAccess.glNamedFramebufferReadBuffer(framebuffer, buffer); + } + + @Override + public void drawBuffers(int framebuffer, int[] buffers) { + ARBDirectStateAccess.glNamedFramebufferDrawBuffers(framebuffer, IntBuffer.wrap(buffers)); + } + + @Override + public int getTexParameteri(int texture, int target, int pname) { + return ARBDirectStateAccess.glGetTextureParameteri(texture, pname); + } + + @Override + public void copyTexSubImage2D(int destTexture, int target, int i, int i1, int i2, int i3, int i4, int width, int height) { + ARBDirectStateAccess.glCopyTextureSubImage2D(destTexture, i, i1, i2, i3, i4, width, height); + } + + @Override + public void bindTextureToUnit(int unit, int texture) { + if (texture == 0) { + super.bindTextureToUnit(unit, texture); + } else { + ARBDirectStateAccess.glBindTextureUnit(unit, texture); + } + } + + @Override + public int bufferStorage(int target, float[] data, int usage) { + int buffer = GL45.glCreateBuffers(); + GL45.glNamedBufferData(buffer, FloatBuffer.wrap(data), usage); + return buffer; + } + + @Override + public void blitFramebuffer(int source, int dest, int offsetX, int offsetY, int width, int height, int offsetX2, int offsetY2, int width2, int height2, int bufferChoice, int filter) { + ARBDirectStateAccess.glBlitNamedFramebuffer(source, dest, offsetX, offsetY, width, height, offsetX2, offsetY2, width2, height2, bufferChoice, filter); + } + + @Override + public void framebufferTexture2D(int fb, int fbtarget, int attachment, int target, int texture, int levels) { + ARBDirectStateAccess.glNamedFramebufferTexture(fb, attachment, texture, levels); + } + + @Override + public int createFramebuffer() { + return ARBDirectStateAccess.glCreateFramebuffers(); + } + + @Override + public int createTexture(int target) { + return ARBDirectStateAccess.glCreateTextures(target); + } + } + + public static class DSAUnsupported implements DSAAccess { + @Override + public void generateMipmaps(int texture, int target) { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GL30.glGenerateMipmap(target); + } + + @Override + public void texParameteri(int texture, int target, int pname, int param) { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GL11.glTexParameteri(target, pname, param); + } + + @Override + public void texParameterf(int texture, int target, int pname, float param) { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GL11.glTexParameterf(target, pname, param); + } + + @Override + public void texParameteriv(int texture, int target, int pname, int[] params) { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GL11.glTexParameter(target, pname, IntBuffer.wrap(params)); + } + + @Override + public void readBuffer(int framebuffer, int buffer) { + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, framebuffer); + GL11.glReadBuffer(buffer); + } + + @Override + public void drawBuffers(int framebuffer, int[] buffers) { + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, framebuffer); + GL20.glDrawBuffers(IntBuffer.wrap(buffers)); + } + + @Override + public int getTexParameteri(int texture, int target, int pname) { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + return GL11.glGetTexParameteri(target, pname); + } + + @Override + public void copyTexSubImage2D(int destTexture, int target, int i, int i1, int i2, int i3, int i4, int width, int height) { + int previous = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, destTexture); + GL11.glCopyTexSubImage2D(target, i, i1, i2, i3, i4, width, height); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, previous); + } + + @Override + public void bindTextureToUnit(int unit, int texture) { + GL13.glActiveTexture(GL13.GL_TEXTURE0 + unit); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + } + + @Override + public int bufferStorage(int target, float[] data, int usage) { + int buffer = GL15.glGenBuffers(); + GL15.glBindBuffer(target, buffer); + bufferData(target, data, usage); + GL15.glBindBuffer(target, 0); + + return buffer; + } + + @Override + public void blitFramebuffer(int source, int dest, int offsetX, int offsetY, int width, int height, int offsetX2, int offsetY2, int width2, int height2, int bufferChoice, int filter) { + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_READ_FRAMEBUFFER, source); + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_DRAW_FRAMEBUFFER, dest); + GL30.glBlitFramebuffer(offsetX, offsetY, width, height, offsetX2, offsetY2, width2, height2, bufferChoice, filter); + } + + @Override + public void framebufferTexture2D(int fb, int fbtarget, int attachment, int target, int texture, int levels) { + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(fbtarget, fb); + GL30.glFramebufferTexture2D(fbtarget, attachment, target, texture, levels); + } + + @Override + public int createFramebuffer() { + int framebuffer = OpenGlHelper.func_153165_e/*glGenFramebuffers*/(); + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, framebuffer); + return framebuffer; + } + + @Override + public int createTexture(int target) { + int texture = GL11.glGenTextures(); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + return texture; + } + } + + /* + public static void bindTextures(int startingTexture, int[] bindings) { + if (hasMultibind) { + ARBMultiBind.glBindTextures(startingTexture, bindings); + } else if (dsaState != DSAState.NONE) { + for (int binding : bindings) { + ARBDirectStateAccess.glBindTextureUnit(startingTexture, binding); + startingTexture++; + } + } else { + for (int binding : bindings) { + GL13.glActiveTexture(startingTexture); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, binding); + startingTexture++; + } + } + } + */ + + // TODO: Proper notification of compute support + public static boolean supportsCompute() { + return Iris.capabilities.GL_ARB_compute_shader; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/AlphaTest.java b/src/main/java/net/coderbot/iris/gl/blending/AlphaTest.java new file mode 100644 index 000000000..93d8ede42 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/AlphaTest.java @@ -0,0 +1,19 @@ +package net.coderbot.iris.gl.blending; + +public class AlphaTest { + private final AlphaTestFunction function; + private final float reference; + + public AlphaTest(AlphaTestFunction function, float reference) { + this.function = function; + this.reference = reference; + } + + public AlphaTestFunction getFunction() { + return function; + } + + public float getReference() { + return reference; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/AlphaTestFunction.java b/src/main/java/net/coderbot/iris/gl/blending/AlphaTestFunction.java new file mode 100644 index 000000000..6a15e3d61 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/AlphaTestFunction.java @@ -0,0 +1,57 @@ +package net.coderbot.iris.gl.blending; + +import org.lwjgl.opengl.GL11; + +import java.util.Optional; + +public enum AlphaTestFunction { + NEVER(GL11.GL_NEVER), + LESS(GL11.GL_LESS), + EQUAL(GL11.GL_EQUAL), + LEQUAL(GL11.GL_LEQUAL), + GREATER(GL11.GL_GREATER), + NOTEQUAL(GL11.GL_NOTEQUAL), + GEQUAL(GL11.GL_GEQUAL), + ALWAYS(GL11.GL_ALWAYS); + + private final int glId; + + AlphaTestFunction(int glFormat) { + this.glId = glFormat; + } + + public static Optional fromGlId(int glId) { + return switch (glId) { + case GL11.GL_NEVER -> Optional.of(NEVER); + case GL11.GL_LESS -> Optional.of(LESS); + case GL11.GL_EQUAL -> Optional.of(EQUAL); + case GL11.GL_LEQUAL -> Optional.of(LEQUAL); + case GL11.GL_GREATER -> Optional.of(GREATER); + case GL11.GL_NOTEQUAL -> Optional.of(NOTEQUAL); + case GL11.GL_GEQUAL -> Optional.of(GEQUAL); + case GL11.GL_ALWAYS -> Optional.of(ALWAYS); + default -> Optional.empty(); + }; + } + + public static Optional fromString(String name) { + if ("GL_ALWAYS".equals(name)) { + // shaders.properties states that GL_ALWAYS is the name to use, but I haven't verified that this actually + // matches the implementation... All of the other names do not have the GL_ prefix. + // + // We'll support it here just to be safe, even though just a plain ALWAYS seems more likely to be what it + // parses. + return Optional.of(AlphaTestFunction.ALWAYS); + } + + try { + return Optional.of(AlphaTestFunction.valueOf(name)); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } + + public int getGlId() { + return glId; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/AlphaTestOverride.java b/src/main/java/net/coderbot/iris/gl/blending/AlphaTestOverride.java new file mode 100644 index 000000000..3df5d5907 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/AlphaTestOverride.java @@ -0,0 +1,19 @@ +package net.coderbot.iris.gl.blending; + +public class AlphaTestOverride { + public static final AlphaTestOverride OFF = new AlphaTestOverride(null); + + private final AlphaTest alphaTest; + + public AlphaTestOverride(AlphaTest alphaTest) { + this.alphaTest = alphaTest; + } + + public void apply() { + AlphaTestStorage.overrideAlphaTest(this.alphaTest); + } + + public static void restore() { + AlphaTestStorage.restoreAlphaTest(); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java b/src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java new file mode 100644 index 000000000..6772de5e1 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java @@ -0,0 +1,56 @@ +package net.coderbot.iris.gl.blending; + +import org.lwjgl.opengl.GL11; + +public class AlphaTestStorage { + private static boolean originalAlphaTestEnable; + private static AlphaTest originalAlphaTest; + private static boolean alphaTestLocked; + + public static boolean isAlphaTestLocked() { + return alphaTestLocked; + } + + public static void overrideAlphaTest(AlphaTest override) { + if (!alphaTestLocked) { + // Only save the previous state if the alpha test wasn't already locked + originalAlphaTestEnable = GL11.glGetBoolean(GL11.GL_ALPHA_TEST); + originalAlphaTest = new AlphaTest(AlphaTestFunction.fromGlId(GL11.glGetInteger(GL11.GL_ALPHA_TEST_FUNC)).orElse(AlphaTestFunction.ALWAYS), GL11.glGetInteger(GL11.GL_ALPHA_TEST_REF)); + } + + alphaTestLocked = false; + + if (override == null) { + GL11.glDisable(GL11.GL_ALPHA_TEST); + } else { + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glAlphaFunc(override.getFunction().getGlId(), override.getReference()); + } + + alphaTestLocked = true; + } + + public static void deferAlphaTestToggle(boolean enabled) { + originalAlphaTestEnable = enabled; + } + + public static void deferAlphaFunc(int function, float reference) { + originalAlphaTest = new AlphaTest(AlphaTestFunction.fromGlId(function).get(), reference); + } + + public static void restoreAlphaTest() { + if (!alphaTestLocked) { + return; + } + + alphaTestLocked = false; + + if (originalAlphaTestEnable) { + GL11.glEnable(GL11.GL_ALPHA_TEST); + } else { + GL11.glDisable(GL11.GL_ALPHA_TEST); + } + + GL11.glAlphaFunc(originalAlphaTest.getFunction().getGlId(), originalAlphaTest.getReference()); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/BlendMode.java b/src/main/java/net/coderbot/iris/gl/blending/BlendMode.java new file mode 100644 index 000000000..659cec779 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/BlendMode.java @@ -0,0 +1,31 @@ +package net.coderbot.iris.gl.blending; + +public class BlendMode { + private final int srcRgb; + private final int dstRgb; + private final int srcAlpha; + private final int dstAlpha; + + public BlendMode(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { + this.srcRgb = srcRgb; + this.dstRgb = dstRgb; + this.srcAlpha = srcAlpha; + this.dstAlpha = dstAlpha; + } + + public int getSrcRgb() { + return srcRgb; + } + + public int getDstRgb() { + return dstRgb; + } + + public int getSrcAlpha() { + return srcAlpha; + } + + public int getDstAlpha() { + return dstAlpha; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/BlendModeFunction.java b/src/main/java/net/coderbot/iris/gl/blending/BlendModeFunction.java new file mode 100644 index 000000000..44ab9b141 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/BlendModeFunction.java @@ -0,0 +1,39 @@ +package net.coderbot.iris.gl.blending; + +import net.coderbot.iris.Iris; +import org.lwjgl.opengl.GL11; + +import java.util.Optional; + +public enum BlendModeFunction { + ZERO(GL11.GL_ZERO), + ONE(GL11.GL_ONE), + SRC_COLOR(GL11.GL_SRC_COLOR), + ONE_MINUS_SRC_COLOR(GL11.GL_ONE_MINUS_SRC_COLOR), + DST_COLOR(GL11.GL_DST_COLOR), + ONE_MINUS_DST_COLOR(GL11.GL_ONE_MINUS_DST_COLOR), + SRC_ALPHA(GL11.GL_SRC_ALPHA), + ONE_MINUS_SRC_ALPHA(GL11.GL_ONE_MINUS_SRC_ALPHA), + DST_ALPHA(GL11.GL_DST_ALPHA), + ONE_MINUS_DST_ALPHA(GL11.GL_ONE_MINUS_DST_ALPHA), + SRC_ALPHA_SATURATE(GL11.GL_SRC_ALPHA_SATURATE); + + private final int glId; + + BlendModeFunction(int glFormat) { + this.glId = glFormat; + } + + public static Optional fromString(String name) { + try { + return Optional.of(BlendModeFunction.valueOf(name)); + } catch (IllegalArgumentException e) { + Iris.logger.warn("Invalid blend mode! " + name); + return Optional.empty(); + } + } + + public int getGlId() { + return glId; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/BlendModeOverride.java b/src/main/java/net/coderbot/iris/gl/blending/BlendModeOverride.java new file mode 100644 index 000000000..ab8de89a1 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/BlendModeOverride.java @@ -0,0 +1,19 @@ +package net.coderbot.iris.gl.blending; + +public class BlendModeOverride { + public static final BlendModeOverride OFF = new BlendModeOverride(null); + + private final BlendMode blendMode; + + public BlendModeOverride(BlendMode blendMode) { + this.blendMode = blendMode; + } + + public void apply() { + BlendModeStorage.overrideBlend(this.blendMode); + } + + public static void restore() { + BlendModeStorage.restoreBlend(); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/BlendModeStorage.java b/src/main/java/net/coderbot/iris/gl/blending/BlendModeStorage.java new file mode 100644 index 000000000..67682a206 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/BlendModeStorage.java @@ -0,0 +1,76 @@ +package net.coderbot.iris.gl.blending; + +import net.coderbot.iris.gl.IrisRenderSystem; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; + +public class BlendModeStorage { + private static boolean originalBlendEnable; + private static BlendMode originalBlend; + private static boolean blendLocked; + + public static boolean isBlendLocked() { + return blendLocked; + } + + public static void overrideBlend(BlendMode override) { + if (!blendLocked) { + // Only save the previous state if the blend mode wasn't already locked + originalBlendEnable = GL11.glGetBoolean(GL11.GL_BLEND); + originalBlend = new BlendMode(GL11.glGetInteger(GL14.GL_BLEND_SRC_RGB), GL11.glGetInteger(GL14.GL_BLEND_DST_RGB), GL11.glGetInteger(GL14.GL_BLEND_SRC_ALPHA), GL11.glGetInteger(GL14.GL_BLEND_DST_ALPHA)); + } + + blendLocked = false; + + if (override == null) { + GL11.glDisable(GL11.GL_BLEND); + } else { + GL11.glEnable(GL11.GL_BLEND); + + GL14.glBlendFuncSeparate(override.getSrcRgb(), override.getDstRgb(), override.getSrcAlpha(), override.getDstAlpha()); + } + + blendLocked = true; + } + + public static void overrideBufferBlend(int index, BlendMode override) { + if (!blendLocked) { + // Only save the previous state if the blend mode wasn't already locked + originalBlendEnable = GL11.glGetBoolean(GL11.GL_BLEND); + originalBlend = new BlendMode(GL11.glGetInteger(GL14.GL_BLEND_SRC_RGB), GL11.glGetInteger(GL14.GL_BLEND_DST_RGB), GL11.glGetInteger(GL14.GL_BLEND_SRC_ALPHA), GL11.glGetInteger(GL14.GL_BLEND_DST_ALPHA)); + } + + if (override == null) { + IrisRenderSystem.disableBufferBlend(index); + } else { + IrisRenderSystem.enableBufferBlend(index); + IrisRenderSystem.blendFuncSeparatei(index, override.getSrcRgb(), override.getDstRgb(), override.getSrcAlpha(), override.getDstAlpha()); + } + + blendLocked = true; + } + + public static void deferBlendModeToggle(boolean enabled) { + originalBlendEnable = enabled; + } + + public static void deferBlendFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { + originalBlend = new BlendMode(srcRgb, dstRgb, srcAlpha, dstAlpha); + } + + public static void restoreBlend() { + if (!blendLocked) { + return; + } + + blendLocked = false; + + if (originalBlendEnable) { + GL11.glEnable(GL11.GL_BLEND); + } else { + GL11.glDisable(GL11.GL_BLEND); + } + + GL14.glBlendFuncSeparate(originalBlend.getSrcRgb(), originalBlend.getDstRgb(), originalBlend.getSrcAlpha(), originalBlend.getDstAlpha()); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/BufferBlendInformation.java b/src/main/java/net/coderbot/iris/gl/blending/BufferBlendInformation.java new file mode 100644 index 000000000..bbd688a27 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/BufferBlendInformation.java @@ -0,0 +1,19 @@ +package net.coderbot.iris.gl.blending; + +public class BufferBlendInformation { + private final int index; + private final BlendMode blendMode; + + public BufferBlendInformation(int index, BlendMode blendMode) { + this.index = index; + this.blendMode = blendMode; + } + + public BlendMode getBlendMode() { + return blendMode; + } + + public int getIndex() { + return index; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/BufferBlendOverride.java b/src/main/java/net/coderbot/iris/gl/blending/BufferBlendOverride.java new file mode 100644 index 000000000..ca3fbb801 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/BufferBlendOverride.java @@ -0,0 +1,15 @@ +package net.coderbot.iris.gl.blending; + +public class BufferBlendOverride { + private final int drawBuffer; + private final BlendMode blendMode; + + public BufferBlendOverride(int drawBuffer, BlendMode blendMode) { + this.drawBuffer = drawBuffer; + this.blendMode = blendMode; + } + + public void apply() { + BlendModeStorage.overrideBufferBlend(this.drawBuffer, this.blendMode); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/ColorMask.java b/src/main/java/net/coderbot/iris/gl/blending/ColorMask.java new file mode 100644 index 000000000..73e6a174b --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/ColorMask.java @@ -0,0 +1,31 @@ +package net.coderbot.iris.gl.blending; + +public class ColorMask { + private final boolean red; + private final boolean green; + private final boolean blue; + private final boolean alpha; + + public ColorMask(boolean red, boolean green, boolean blue, boolean alpha) { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; + } + + public boolean isRedMasked() { + return red; + } + + public boolean isGreenMasked() { + return green; + } + + public boolean isBlueMasked() { + return blue; + } + + public boolean isAlphaMasked() { + return alpha; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java b/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java new file mode 100644 index 000000000..973a6ff7d --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java @@ -0,0 +1,55 @@ +package net.coderbot.iris.gl.blending; + +import org.lwjgl.opengl.GL11; + +public class DepthColorStorage { + private static boolean originalDepthEnable; + private static ColorMask originalColor; + private static boolean depthColorLocked; + + public static boolean isDepthColorLocked() { + return depthColorLocked; + } + + public static void disableDepthColor() { + if (!depthColorLocked) { + // Only save the previous state if the depth and color mask wasn't already locked + GlStateManager.ColorMask colorMask = GlStateManagerAccessor.getCOLOR_MASK(); + GlStateManager.DepthState depthState = GlStateManagerAccessor.getDEPTH(); + + originalDepthEnable = depthState.mask; + originalColor = new ColorMask(colorMask.red, colorMask.green, colorMask.blue, colorMask.alpha); + } + + depthColorLocked = false; + + GL11.glDepthMask(false); + GL11.glColorMask(false, false, false, false); + + depthColorLocked = true; + } + + public static void deferDepthEnable(boolean enabled) { + originalDepthEnable = enabled; + } + + public static void deferColorMask(boolean red, boolean green, boolean blue, boolean alpha) { + originalColor = new ColorMask(red, green, blue, alpha); + } + + public static void unlockDepthColor() { + if (!depthColorLocked) { + return; + } + + depthColorLocked = false; + + if (originalDepthEnable) { + GL11.glDepthMask(true); + } else { + GL11.glDepthMask(false); + } + + GL11.glColorMask(originalColor.isRedMasked(), originalColor.isGreenMasked(), originalColor.isBlueMasked(), originalColor.isAlphaMasked()); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java new file mode 100644 index 000000000..9725e30b8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java @@ -0,0 +1,112 @@ +package net.coderbot.iris.gl.framebuffer; + +import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import net.coderbot.iris.gl.GlResource; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.texture.DepthBufferFormat; +import net.coderbot.iris.texture.TextureInfoCache; +import net.minecraft.client.renderer.OpenGlHelper; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL30; + +public class GlFramebuffer extends GlResource { + private final Int2IntMap attachments; + private final int maxDrawBuffers; + private final int maxColorAttachments; + private boolean hasDepthAttachment; + + public GlFramebuffer() { + super(IrisRenderSystem.createFramebuffer()); + + this.attachments = new Int2IntArrayMap(); + this.maxDrawBuffers = GL11.glGetInteger(GL20.GL_MAX_DRAW_BUFFERS); + this.maxColorAttachments = GL11.glGetInteger(GL30.GL_MAX_COLOR_ATTACHMENTS); + this.hasDepthAttachment = false; + } + + public void addDepthAttachment(int texture) { + int internalFormat = TextureInfoCache.INSTANCE.getInfo(texture).getInternalFormat(); + DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); + + int fb = getGlId(); + + if (depthBufferFormat.isCombinedStencil()) { + IrisRenderSystem.framebufferTexture2D(fb, GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_STENCIL_ATTACHMENT, GL11.GL_TEXTURE_2D, texture, 0); + } else { + IrisRenderSystem.framebufferTexture2D(fb, GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, texture, 0); + } + + this.hasDepthAttachment = true; + } + + public void addColorAttachment(int index, int texture) { + int fb = getGlId(); + + IrisRenderSystem.framebufferTexture2D(fb, GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0 + index, GL11.GL_TEXTURE_2D, texture, 0); + attachments.put(index, texture); + } + + public void noDrawBuffers() { + IrisRenderSystem.drawBuffers(getGlId(), new int[] { GL11.GL_NONE }); + } + + public void drawBuffers(int[] buffers) { + int[] glBuffers = new int[buffers.length]; + int index = 0; + + if (buffers.length > maxDrawBuffers) { + throw new IllegalArgumentException("Cannot write to more than " + maxDrawBuffers + " draw buffers on this GPU"); + } + + for (int buffer : buffers) { + if (buffer >= maxColorAttachments) { + throw new IllegalArgumentException("Only " + maxColorAttachments + " color attachments are supported on this GPU, but an attempt was made to write to a color attachment with index " + buffer); + } + + glBuffers[index++] = GL30.GL_COLOR_ATTACHMENT0 + buffer; + } + + IrisRenderSystem.drawBuffers(getGlId(), glBuffers); + } + + public void readBuffer(int buffer) { + IrisRenderSystem.readBuffer(getGlId(), GL30.GL_COLOR_ATTACHMENT0 + buffer); + } + + public int getColorAttachment(int index) { + return attachments.get(index); + } + + public boolean hasDepthAttachment() { + return hasDepthAttachment; + } + + public void bind() { + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, getGlId()); + } + + public void bindAsReadBuffer() { + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_READ_FRAMEBUFFER, getGlId()); + } + + public void bindAsDrawBuffer() { + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30C.GL_DRAW_FRAMEBUFFER, getGlId()); + } + + protected void destroyInternal() { + GlStateManager._glDeleteFramebuffers(getGlId()); + } + + public boolean isComplete() { + bind(); + int status = GlStateManager.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER); + + return status == GL30.GL_FRAMEBUFFER_COMPLETE; + } + + public int getId() { + return getGlId(); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/image/ImageBinding.java b/src/main/java/net/coderbot/iris/gl/image/ImageBinding.java new file mode 100644 index 000000000..6d66099bd --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/image/ImageBinding.java @@ -0,0 +1,24 @@ +package net.coderbot.iris.gl.image; + +import net.coderbot.iris.gl.IrisRenderSystem; +import org.lwjgl.opengl.GL15; + +import java.util.function.IntSupplier; + +public class ImageBinding { + private final int imageUnit; + private final int internalFormat; + private final IntSupplier textureID; + + public ImageBinding(int imageUnit, int internalFormat, IntSupplier textureID) { + this.textureID = textureID; + this.imageUnit = imageUnit; + this.internalFormat = internalFormat; + } + + public void update() { + // We can assume that image bindings are supported here as either the EXT extension or 4.2 core, as otherwise ImageLimits + // would report that zero image units are supported. + IrisRenderSystem.bindImageTexture(imageUnit, textureID.getAsInt(), 0, false, 0, GL15.GL_READ_WRITE, internalFormat); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/image/ImageHolder.java b/src/main/java/net/coderbot/iris/gl/image/ImageHolder.java new file mode 100644 index 000000000..9b9f66d8a --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/image/ImageHolder.java @@ -0,0 +1,10 @@ +package net.coderbot.iris.gl.image; + +import net.coderbot.iris.gl.texture.InternalTextureFormat; + +import java.util.function.IntSupplier; + +public interface ImageHolder { + boolean hasImage(String name); + void addTextureImage(IntSupplier textureID, InternalTextureFormat internalFormat, String name); +} diff --git a/src/main/java/net/coderbot/iris/gl/image/ImageLimits.java b/src/main/java/net/coderbot/iris/gl/image/ImageLimits.java new file mode 100644 index 000000000..64e784c57 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/image/ImageLimits.java @@ -0,0 +1,24 @@ +package net.coderbot.iris.gl.image; + +import net.coderbot.iris.gl.IrisRenderSystem; + +public class ImageLimits { + private final int maxImageUnits; + private static ImageLimits instance; + + private ImageLimits() { + this.maxImageUnits = IrisRenderSystem.getMaxImageUnits(); + } + + public int getMaxImageUnits() { + return maxImageUnits; + } + + public static ImageLimits get() { + if (instance == null) { + instance = new ImageLimits(); + } + + return instance; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java b/src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java new file mode 100644 index 000000000..d543b4484 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java @@ -0,0 +1,90 @@ +package net.coderbot.iris.gl.program; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.GlResource; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import org.joml.Vector2f; +import org.joml.Vector3i; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL43; + +public final class ComputeProgram extends GlResource { + private final ProgramUniforms uniforms; + private final ProgramSamplers samplers; + private final ProgramImages images; + private Vector3i absoluteWorkGroups; + private Vector2f relativeWorkGroups; + private int[] localSize; + private float cachedWidth; + private float cachedHeight; + private Vector3i cachedWorkGroups; + + ComputeProgram(int program, ProgramUniforms uniforms, ProgramSamplers samplers, ProgramImages images) { + super(program); + + localSize = new int[3]; + IrisRenderSystem.getProgramiv(program, GL43.GL_COMPUTE_WORK_GROUP_SIZE, localSize); + this.uniforms = uniforms; + this.samplers = samplers; + this.images = images; + } + + public void setWorkGroupInfo(Vector2f relativeWorkGroups, Vector3i absoluteWorkGroups) { + this.relativeWorkGroups = relativeWorkGroups; + this.absoluteWorkGroups = absoluteWorkGroups; + } + + public Vector3i getWorkGroups(float width, float height) { + if (cachedWidth != width || cachedHeight != height || cachedWorkGroups == null) { + this.cachedWidth = width; + this.cachedHeight = height; + if (this.absoluteWorkGroups != null) { + this.cachedWorkGroups = this.absoluteWorkGroups; + } else if (relativeWorkGroups != null) { + // TODO: This is my best guess at what Optifine does. Can this be confirmed? + // Do not use actual localSize here, apparently that's not what we want. + this.cachedWorkGroups = new Vector3i((int) Math.ceil(Math.ceil((width * relativeWorkGroups.x)) / localSize[0]), (int) Math.ceil(Math.ceil((height * relativeWorkGroups.y)) / localSize[1]), 1); + } else { + this.cachedWorkGroups = new Vector3i((int) Math.ceil(width / localSize[0]), (int) Math.ceil(height / localSize[1]), 1); + } + } + + return cachedWorkGroups; + } + + public void dispatch(float width, float height) { + GL20.glUseProgram(getGlId()); + uniforms.update(); + samplers.update(); + images.update(); + + if (!Iris.getPipelineManager().getPipeline().map(WorldRenderingPipeline::allowConcurrentCompute).orElse(false)) { + IrisRenderSystem.memoryBarrier(40); + } + + IrisRenderSystem.dispatchCompute(getWorkGroups(width, height)); + } + + public static void unbind() { + ProgramUniforms.clearActiveUniforms(); + GL20.glUseProgram(0); + } + + public void destroyInternal() { + GL20.glDeleteProgram(getGlId()); + } + + /** + * @return the OpenGL ID of this program. + * @deprecated this should be encapsulated eventually + */ + @Deprecated + public int getProgramId() { + return getGlId(); + } + + public int getActiveImages() { + return images.getActiveImages(); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/program/GlUniform1iCall.java b/src/main/java/net/coderbot/iris/gl/program/GlUniform1iCall.java new file mode 100644 index 000000000..004fc87b3 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/program/GlUniform1iCall.java @@ -0,0 +1,19 @@ +package net.coderbot.iris.gl.program; + +public class GlUniform1iCall { + private final int location; + private final int value; + + public GlUniform1iCall(int location, int value) { + this.location = location; + this.value = value; + } + + public int getLocation() { + return location; + } + + public int getValue() { + return value; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/program/Program.java b/src/main/java/net/coderbot/iris/gl/program/Program.java new file mode 100644 index 000000000..6aa5d6284 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/program/Program.java @@ -0,0 +1,49 @@ +package net.coderbot.iris.gl.program; + +import net.coderbot.iris.gl.GlResource; +import org.lwjgl.opengl.GL20; + +public final class Program extends GlResource { + private final ProgramUniforms uniforms; + private final ProgramSamplers samplers; + private final ProgramImages images; + + Program(int program, ProgramUniforms uniforms, ProgramSamplers samplers, ProgramImages images) { + super(program); + + this.uniforms = uniforms; + this.samplers = samplers; + this.images = images; + } + + public void use() { + GL20.glUseProgram(getGlId()); + + uniforms.update(); + samplers.update(); + images.update(); + } + + public static void unbind() { + ProgramUniforms.clearActiveUniforms(); + ProgramSamplers.clearActiveSamplers(); + GL20.glUseProgram(0); + } + + public void destroyInternal() { + GL20.glDeleteProgram(getGlId()); + } + + /** + * @return the OpenGL ID of this program. + * @deprecated this should be encapsulated eventually + */ + @Deprecated + public int getProgramId() { + return getGlId(); + } + + public int getActiveImages() { + return images.getActiveImages(); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/program/ProgramBuilder.java b/src/main/java/net/coderbot/iris/gl/program/ProgramBuilder.java new file mode 100644 index 000000000..a57483656 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/program/ProgramBuilder.java @@ -0,0 +1,131 @@ +package net.coderbot.iris.gl.program; + +import com.google.common.collect.ImmutableSet; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.image.ImageHolder; +import net.coderbot.iris.gl.sampler.SamplerHolder; +import net.coderbot.iris.gl.shader.GlShader; +import net.coderbot.iris.gl.shader.ProgramCreator; +import net.coderbot.iris.gl.shader.ShaderType; +import net.coderbot.iris.gl.state.ValueUpdateNotifier; +import net.coderbot.iris.gl.texture.InternalTextureFormat; +import org.jetbrains.annotations.Nullable; + +import java.util.function.IntSupplier; + +public class ProgramBuilder extends ProgramUniforms.Builder implements SamplerHolder, ImageHolder { + private final int program; + private final ProgramSamplers.Builder samplers; + private final ProgramImages.Builder images; + + private ProgramBuilder(String name, int program, ImmutableSet reservedTextureUnits) { + super(name, program); + + this.program = program; + this.samplers = ProgramSamplers.builder(program, reservedTextureUnits); + this.images = ProgramImages.builder(program); + } + + public void bindAttributeLocation(int index, String name) { + IrisRenderSystem.bindAttributeLocation(program, index, name); + } + + public static ProgramBuilder begin(String name, @Nullable String vertexSource, @Nullable String geometrySource, + @Nullable String fragmentSource, ImmutableSet reservedTextureUnits) { + GlShader vertex; + GlShader geometry; + GlShader fragment; + + vertex = buildShader(ShaderType.VERTEX, name + ".vsh", vertexSource); + + if (geometrySource != null) { + geometry = buildShader(ShaderType.GEOMETRY, name + ".gsh", geometrySource); + } else { + geometry = null; + } + + fragment = buildShader(ShaderType.FRAGMENT, name + ".fsh", fragmentSource); + + int programId; + + if (geometry != null) { + programId = ProgramCreator.create(name, vertex, geometry, fragment); + } else { + programId = ProgramCreator.create(name, vertex, fragment); + } + + vertex.destroy(); + + if (geometry != null) { + geometry.destroy(); + } + + fragment.destroy(); + + return new ProgramBuilder(name, programId, reservedTextureUnits); + } + + public static ProgramBuilder beginCompute(String name, @Nullable String source, ImmutableSet reservedTextureUnits) { + if (!IrisRenderSystem.supportsCompute()) { + throw new IllegalStateException("This PC does not support compute shaders, but it's attempting to be used???"); + } + + GlShader compute = buildShader(ShaderType.COMPUTE, name + ".csh", source); + + int programId = ProgramCreator.create(name, compute); + + compute.destroy(); + + return new ProgramBuilder(name, programId, reservedTextureUnits); + } + + public Program build() { + return new Program(program, super.buildUniforms(), this.samplers.build(), this.images.build()); + } + + public ComputeProgram buildCompute() { + return new ComputeProgram(program, super.buildUniforms(), this.samplers.build(), this.images.build()); + } + + private static GlShader buildShader(ShaderType shaderType, String name, @Nullable String source) { + try { + return new GlShader(shaderType, name, source); + } catch (RuntimeException e) { + throw new RuntimeException("Failed to compile " + shaderType + " shader for program " + name, e); + } + } + + @Override + public void addExternalSampler(int textureUnit, String... names) { + samplers.addExternalSampler(textureUnit, names); + } + + @Override + public boolean hasSampler(String name) { + return samplers.hasSampler(name); + } + + @Override + public boolean addDefaultSampler(IntSupplier sampler, String... names) { + return samplers.addDefaultSampler(sampler, names); + } + + @Override + public boolean addDynamicSampler(IntSupplier sampler, String... names) { + return samplers.addDynamicSampler(sampler, names); + } + + public boolean addDynamicSampler(IntSupplier sampler, ValueUpdateNotifier notifier, String... names) { + return samplers.addDynamicSampler(sampler, notifier, names); + } + + @Override + public boolean hasImage(String name) { + return images.hasImage(name); + } + + @Override + public void addTextureImage(IntSupplier textureID, InternalTextureFormat internalFormat, String name) { + images.addTextureImage(textureID, internalFormat, name); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/program/ProgramImages.java b/src/main/java/net/coderbot/iris/gl/program/ProgramImages.java new file mode 100644 index 000000000..23710a596 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/program/ProgramImages.java @@ -0,0 +1,98 @@ +package net.coderbot.iris.gl.program; + +import com.google.common.collect.ImmutableList; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.image.ImageBinding; +import net.coderbot.iris.gl.image.ImageHolder; +import net.coderbot.iris.gl.image.ImageLimits; +import net.coderbot.iris.gl.texture.InternalTextureFormat; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.IntSupplier; + +public class ProgramImages { + private final ImmutableList imageBindings; + private List initializer; + + private ProgramImages(ImmutableList imageBindings, List initializer) { + this.imageBindings = imageBindings; + this.initializer = initializer; + } + + public void update() { + if (initializer != null) { + for (GlUniform1iCall call : initializer) { + IrisRenderSystem.uniform1i(call.getLocation(), call.getValue()); + } + + initializer = null; + } + + for (ImageBinding imageBinding : imageBindings) { + imageBinding.update(); + } + } + + public int getActiveImages() { + return imageBindings.size(); + } + + public static Builder builder(int program) { + return new Builder(program); + } + + public static final class Builder implements ImageHolder { + private final int program; + private final ImmutableList.Builder images; + private final List calls; + private int nextImageUnit; + private final int maxImageUnits; + + private Builder(int program) { + this.program = program; + this.images = ImmutableList.builder(); + this.calls = new ArrayList<>(); + this.nextImageUnit = 0; + this.maxImageUnits = ImageLimits.get().getMaxImageUnits(); + } + + @Override + public boolean hasImage(String name) { + return GlStateManager._glGetUniformLocation(program, name) != -1; + } + + @Override + public void addTextureImage(IntSupplier textureID, InternalTextureFormat internalFormat, String name) { + int location = GlStateManager._glGetUniformLocation(program, name); + + if (location == -1) { + return; + } + + if (nextImageUnit >= maxImageUnits) { + if (maxImageUnits == 0) { + throw new IllegalStateException("Image units are not supported on this platform, but a shader" + + " program attempted to reference " + name + "."); + } else { + throw new IllegalStateException("No more available texture units while activating image " + name + "." + + " Only " + maxImageUnits + " image units are available."); + } + } + + if (internalFormat == InternalTextureFormat.RGBA) { + // Internal detail of Optifine: Set RGBA8 if RGBA is selected, as RGBA is not valid for images. + internalFormat = InternalTextureFormat.RGBA8; + } + + images.add(new ImageBinding(nextImageUnit, internalFormat.getGlFormat(), textureID)); + calls.add(new GlUniform1iCall(location, nextImageUnit)); + + nextImageUnit += 1; + } + + public ProgramImages build() { + return new ProgramImages(images.build(), calls); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java b/src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java new file mode 100644 index 000000000..c55ab046d --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java @@ -0,0 +1,295 @@ +package net.coderbot.iris.gl.program; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.sampler.SamplerBinding; +import net.coderbot.iris.gl.sampler.SamplerHolder; +import net.coderbot.iris.gl.sampler.SamplerLimits; +import net.coderbot.iris.gl.state.ValueUpdateNotifier; +import net.coderbot.iris.shaderpack.PackRenderTargetDirectives; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.function.IntSupplier; + +public class ProgramSamplers { + private static ProgramSamplers active; + private final ImmutableList samplerBindings; + private final ImmutableList notifiersToReset; + private List initializer; + + private ProgramSamplers(ImmutableList samplerBindings, ImmutableList notifiersToReset, List initializer) { + this.samplerBindings = samplerBindings; + this.notifiersToReset = notifiersToReset; + this.initializer = initializer; + } + + public void update() { + if (active != null) { + active.removeListeners(); + } + + active = this; + + if (initializer != null) { + for (GlUniform1iCall call : initializer) { + IrisRenderSystem.uniform1i(call.getLocation(), call.getValue()); + } + + initializer = null; + } + + // We need to keep the active texture intact, since if we mess it up + // in the middle of RenderType setup, bad things will happen. + int activeTexture = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + + for (SamplerBinding samplerBinding : samplerBindings) { + samplerBinding.update(); + } + + GL13.glActiveTexture(GL13.GL_TEXTURE0 + activeTexture); + } + + public void removeListeners() { + active = null; + + for (ValueUpdateNotifier notifier : notifiersToReset) { + notifier.setListener(null); + } + } + + public static void clearActiveSamplers() { + if (active != null) { + active.removeListeners(); + } + } + + public static Builder builder(int program, Set reservedTextureUnits) { + return new Builder(program, reservedTextureUnits); + } + + public static CustomTextureSamplerInterceptor customTextureSamplerInterceptor(SamplerHolder samplerHolder, Object2ObjectMap customTextureIds) { + return customTextureSamplerInterceptor(samplerHolder, customTextureIds, ImmutableSet.of()); + } + + public static CustomTextureSamplerInterceptor customTextureSamplerInterceptor(SamplerHolder samplerHolder, Object2ObjectMap customTextureIds, ImmutableSet flippedAtLeastOnceSnapshot) { + return new CustomTextureSamplerInterceptor(samplerHolder, customTextureIds, flippedAtLeastOnceSnapshot); + } + + public static final class Builder implements SamplerHolder { + private final int program; + private final ImmutableSet reservedTextureUnits; + private final ImmutableList.Builder samplers; + private final ImmutableList.Builder notifiersToReset; + private final List calls; + private int remainingUnits; + private int nextUnit; + + private Builder(int program, Set reservedTextureUnits) { + this.program = program; + this.reservedTextureUnits = ImmutableSet.copyOf(reservedTextureUnits); + this.samplers = ImmutableList.builder(); + this.notifiersToReset = ImmutableList.builder(); + this.calls = new ArrayList<>(); + + int maxTextureUnits = SamplerLimits.get().getMaxTextureUnits(); + + for (int unit : reservedTextureUnits) { + if (unit >= maxTextureUnits) { + throw new IllegalStateException("Cannot mark texture unit " + unit + " as reserved because that " + + "texture unit isn't available on this system! Only " + maxTextureUnits + + " texture units are available."); + } + } + + this.remainingUnits = maxTextureUnits - reservedTextureUnits.size(); + this.nextUnit = 0; + + while (reservedTextureUnits.contains(nextUnit)) { + nextUnit += 1; + } + + //System.out.println("Begin building samplers. Reserved texture units are " + reservedTextureUnits + + // ", next texture unit is " + nextUnit + ", there are " + remainingUnits + " units remaining."); + } + + @Override + public void addExternalSampler(int textureUnit, String... names) { + if (!reservedTextureUnits.contains(textureUnit)) { + throw new IllegalArgumentException("Cannot add an externally-managed sampler for texture unit " + + textureUnit + " since it isn't in the set of reserved texture units."); + } + + for (String name : names) { + int location = IrisRenderSystem.getUniformLocation(program, name); + + if (location == -1) { + // There's no active sampler with this particular name in the program. + continue; + } + + // Set up this sampler uniform to use this particular texture unit. + //System.out.println("Binding external sampler " + name + " to texture unit " + textureUnit); + calls.add(new GlUniform1iCall(location, textureUnit)); + } + } + + @Override + public boolean hasSampler(String name) { + return IrisRenderSystem.getUniformLocation(program, name) != -1; + } + + @Override + public boolean addDefaultSampler(IntSupplier sampler, String... names) { + if (nextUnit != 0) { + // TODO: Relax this restriction! + throw new IllegalStateException("Texture unit 0 is already used."); + } + + return addDynamicSampler(sampler, true, null, names); + } + + /** + * Adds a sampler + * @return false if this sampler is not active, true if at least one of the names referred to an active sampler + */ + @Override + public boolean addDynamicSampler(IntSupplier sampler, String... names) { + return addDynamicSampler(sampler, false, null, names); + } + + /** + * Adds a sampler + * @return false if this sampler is not active, true if at least one of the names referred to an active sampler + */ + @Override + public boolean addDynamicSampler(IntSupplier sampler, ValueUpdateNotifier notifier, String... names) { + notifiersToReset.add(notifier); + return addDynamicSampler(sampler, false, notifier, names); + } + + private boolean addDynamicSampler(IntSupplier sampler, boolean used, ValueUpdateNotifier notifier, String... names) { + for (String name : names) { + int location = IrisRenderSystem.getUniformLocation(program, name); + + if (location == -1) { + // There's no active sampler with this particular name in the program. + continue; + } + + // Make sure that we aren't out of texture units. + if (remainingUnits <= 0) { + throw new IllegalStateException("No more available texture units while activating sampler " + name); + } + + //System.out.println("Binding dynamic sampler " + name + " to texture unit " + nextUnit); + + // Set up this sampler uniform to use this particular texture unit. + calls.add(new GlUniform1iCall(location, nextUnit)); + + // And mark this texture unit as used. + used = true; + } + + if (!used) { + return false; + } + + samplers.add(new SamplerBinding(nextUnit, sampler, notifier)); + + remainingUnits -= 1; + nextUnit += 1; + + while (remainingUnits > 0 && reservedTextureUnits.contains(nextUnit)) { + nextUnit += 1; + } + + //System.out.println("The next unit is " + nextUnit + ", there are " + remainingUnits + " units remaining."); + + return true; + } + + public ProgramSamplers build() { + return new ProgramSamplers(samplers.build(), notifiersToReset.build(), calls); + } + } + + public static final class CustomTextureSamplerInterceptor implements SamplerHolder { + private final SamplerHolder samplerHolder; + private final Object2ObjectMap customTextureIds; + private final ImmutableSet deactivatedOverrides; + + private CustomTextureSamplerInterceptor(SamplerHolder samplerHolder, Object2ObjectMap customTextureIds, ImmutableSet flippedAtLeastOnceSnapshot) { + this.samplerHolder = samplerHolder; + this.customTextureIds = customTextureIds; + + ImmutableSet.Builder deactivatedOverrides = new ImmutableSet.Builder<>(); + + for (int deactivatedOverride : flippedAtLeastOnceSnapshot) { + deactivatedOverrides.add("colortex" + deactivatedOverride); + + if (deactivatedOverride < PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.size()) { + deactivatedOverrides.add(PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.get(deactivatedOverride)); + } + } + + this.deactivatedOverrides = deactivatedOverrides.build(); + } + + private IntSupplier getOverride(IntSupplier existing, String... names) { + for (String name : names) { + if (customTextureIds.containsKey(name) && !deactivatedOverrides.contains(name)) { + return customTextureIds.get(name); + } + } + + return existing; + } + + @Override + public void addExternalSampler(int textureUnit, String... names) { + IntSupplier override = getOverride(null, names); + + if (override != null) { + if (textureUnit == 0) { + samplerHolder.addDefaultSampler(override, names); + } else { + samplerHolder.addDynamicSampler(override, names); + } + } else { + samplerHolder.addExternalSampler(textureUnit, names); + } + } + + @Override + public boolean hasSampler(String name) { + return samplerHolder.hasSampler(name); + } + + @Override + public boolean addDefaultSampler(IntSupplier sampler, String... names) { + sampler = getOverride(sampler, names); + + return samplerHolder.addDefaultSampler(sampler, names); + } + + @Override + public boolean addDynamicSampler(IntSupplier sampler, String... names) { + sampler = getOverride(sampler, names); + + return samplerHolder.addDynamicSampler(sampler, names); + } + + @Override + public boolean addDynamicSampler(IntSupplier sampler, ValueUpdateNotifier notifier, String... names) { + sampler = getOverride(sampler, names); + + return samplerHolder.addDynamicSampler(sampler, notifier, names); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java b/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java new file mode 100644 index 000000000..c066959fc --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java @@ -0,0 +1,354 @@ +package net.coderbot.iris.gl.program; + +import com.google.common.collect.ImmutableList; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.state.ValueUpdateNotifier; +import net.coderbot.iris.gl.uniform.DynamicLocationalUniformHolder; +import net.coderbot.iris.gl.uniform.Uniform; +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.coderbot.iris.gl.uniform.UniformType; +import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; +import net.coderbot.iris.uniforms.SystemTimeUniforms; +import net.minecraft.client.Minecraft; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.ARBShaderImageLoadStore; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL30; + +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; + +public class ProgramUniforms { + private static ProgramUniforms active; + private final ImmutableList perTick; + private final ImmutableList perFrame; + private final ImmutableList dynamic; + private final ImmutableList notifiersToReset; + + private ImmutableList once; + long lastTick = -1; + int lastFrame = -1; + + public ProgramUniforms(ImmutableList once, ImmutableList perTick, ImmutableList perFrame, + ImmutableList dynamic, ImmutableList notifiersToReset) { + this.once = once; + this.perTick = perTick; + this.perFrame = perFrame; + this.dynamic = dynamic; + this.notifiersToReset = notifiersToReset; + } + + private void updateStage(ImmutableList uniforms) { + for (Uniform uniform : uniforms) { + uniform.update(); + } + } + + private static long getCurrentTick() { + return Objects.requireNonNull(Minecraft.getMinecraft().theWorld).getWorldTime(); + } + + public void update() { + if (active != null) { + active.removeListeners(); + } + + active = this; + + updateStage(dynamic); + + if (once != null) { + updateStage(once); + updateStage(perTick); + updateStage(perFrame); + lastTick = getCurrentTick(); + + once = null; + return; + } + + long currentTick = getCurrentTick(); + + if (lastTick != currentTick) { + lastTick = currentTick; + + updateStage(perTick); + } + + // TODO: Move the frame counter to a different place? + int currentFrame = SystemTimeUniforms.COUNTER.getAsInt(); + + if (lastFrame != currentFrame) { + lastFrame = currentFrame; + + updateStage(perFrame); + } + } + + public void removeListeners() { + active = null; + + for (ValueUpdateNotifier notifier : notifiersToReset) { + notifier.setListener(null); + } + } + + public static void clearActiveUniforms() { + if (active != null) { + active.removeListeners(); + } + } + + public static Builder builder(String name, int program) { + return new Builder(name, program); + } + + public static class Builder implements DynamicLocationalUniformHolder { + private final String name; + private final int program; + + private final Map locations; + private final Map once; + private final Map perTick; + private final Map perFrame; + private final Map dynamic; + private final Map uniformNames; + private final Map externalUniformNames; + private final List notifiersToReset; + + protected Builder(String name, int program) { + this.name = name; + this.program = program; + + locations = new HashMap<>(); + once = new HashMap<>(); + perTick = new HashMap<>(); + perFrame = new HashMap<>(); + dynamic = new HashMap<>(); + uniformNames = new HashMap<>(); + externalUniformNames = new HashMap<>(); + notifiersToReset = new ArrayList<>(); + } + + @Override + public Builder addUniform(UniformUpdateFrequency updateFrequency, Uniform uniform) { + Objects.requireNonNull(uniform); + + switch (updateFrequency) { + case ONCE: + once.put(locations.get(uniform.getLocation()), uniform); + break; + case PER_TICK: + perTick.put(locations.get(uniform.getLocation()), uniform); + break; + case PER_FRAME: + perFrame.put(locations.get(uniform.getLocation()), uniform); + break; + } + + return this; + } + + @Override + public OptionalInt location(String name, UniformType type) { + int id = IrisRenderSystem.getUniformLocation(program, name); + + if (id == -1) { + return OptionalInt.empty(); + } + + // TODO: Temporary hack until custom uniforms are merged. + if ((!locations.containsKey(id) && !uniformNames.containsKey(name)) || name.equals("framemod8")) { + locations.put(id, name); + uniformNames.put(name, type); + } else { + Iris.logger.warn("[" + this.name + "] Duplicate uniform: " + type.toString().toLowerCase() + " " + name); + + return OptionalInt.empty(); + } + + return OptionalInt.of(id); + } + + public ProgramUniforms buildUniforms() { + // Check for any unsupported uniforms and warn about them so that we can easily figure out what uniforms we need to add. + final int activeUniforms = GL20.glGetProgrami(program, GL20.GL_ACTIVE_UNIFORMS); + IntBuffer sizeType = BufferUtils.createIntBuffer(2); + + for (int index = 0; index < activeUniforms; index++) { + final String name = IrisRenderSystem.getActiveUniform(program, index, 128, sizeType); + + if (name.isEmpty()) { + // No further information available. + continue; + } + + int size = sizeType.get(0); + int type = sizeType.get(1); + + UniformType provided = uniformNames.get(name); + UniformType expected = getExpectedType(type); + + if (provided == null && !name.startsWith("gl_")) { + 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; + } + + UniformType externalProvided = externalUniformNames.get(name); + + if (externalProvided != null) { + if (externalProvided != expected) { + String expectedName; + + 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 + "."); + } + + 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; + } + + // TODO: This is an absolutely horrific hack, but is needed until custom uniforms work. + if ("framemod8".equals(name) && expected == UniformType.FLOAT && provided == UniformType.INT) { + SystemTimeUniforms.addFloatFrameMod8Uniform(this); + provided = UniformType.FLOAT; + } + + if (provided != null && provided != expected) { + String expectedName; + + if (expected != null) { + expectedName = expected.toString(); + } else { + expectedName = "(unsupported type: " + getTypeName(type) + ")"; + } + + Iris.logger.error("[" + this.name + "] Wrong uniform type for " + name + ": Iris is providing " + provided + " but the program expects " + expectedName + ". Disabling that uniform."); + + once.remove(name); + perTick.remove(name); + perFrame.remove(name); + dynamic.remove(name); + } + } + + return new ProgramUniforms(ImmutableList.copyOf(once.values()), ImmutableList.copyOf(perTick.values()), ImmutableList.copyOf(perFrame.values()), + ImmutableList.copyOf(dynamic.values()), ImmutableList.copyOf(notifiersToReset)); + } + + @Override + public Builder addDynamicUniform(Uniform uniform, ValueUpdateNotifier notifier) { + Objects.requireNonNull(uniform); + Objects.requireNonNull(notifier); + + dynamic.put(locations.get(uniform.getLocation()), uniform); + notifiersToReset.add(notifier); + + return this; + } + + @Override + public UniformHolder externallyManagedUniform(String name, UniformType type) { + externalUniformNames.put(name, type); + + return this; + } + } + + private static String getTypeName(int type) { + return switch(type) { + case GL11.GL_FLOAT -> "float"; + case GL11.GL_INT -> "int"; + case GL20.GL_FLOAT_MAT4 -> "mat4"; + case GL20.GL_FLOAT_VEC4 -> "vec4"; + case GL20.GL_FLOAT_MAT3 -> "mat3"; + case GL20.GL_FLOAT_VEC3 -> "vec3"; + case GL20.GL_FLOAT_MAT2 -> "mat2"; + case GL20.GL_FLOAT_VEC2 -> "vec2"; + case GL20.GL_INT_VEC2 -> "ivec2"; + case GL20.GL_INT_VEC4 -> "ivec4"; + case GL20.GL_SAMPLER_3D -> "sampler3D"; + case GL20.GL_SAMPLER_2D -> "sampler2D"; + case GL30.GL_UNSIGNED_INT_SAMPLER_2D -> "usampler2D"; + case GL30.GL_UNSIGNED_INT_SAMPLER_3D -> "usampler3D"; + case GL20.GL_SAMPLER_1D -> "sampler1D"; + case GL20.GL_SAMPLER_2D_SHADOW -> "sampler2DShadow"; + case GL20.GL_SAMPLER_1D_SHADOW -> "sampler1DShadow"; + case ARBShaderImageLoadStore.GL_IMAGE_2D -> "image2D"; + case ARBShaderImageLoadStore.GL_IMAGE_3D -> "image3D"; + default -> "(unknown:" + type + ")"; + }; + } + + private static UniformType getExpectedType(int type) { + return switch (type) { + case GL11.GL_FLOAT -> UniformType.FLOAT; + case GL11.GL_INT -> 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_MAT2 -> null; + case GL20.GL_FLOAT_VEC2 -> UniformType.VEC2; + case GL20.GL_INT_VEC2 -> UniformType.VEC2I; + case GL20.GL_SAMPLER_3D -> UniformType.INT; + case GL20.GL_SAMPLER_2D -> UniformType.INT; + case GL30.GL_UNSIGNED_INT_SAMPLER_2D -> UniformType.INT; + case GL30.GL_UNSIGNED_INT_SAMPLER_3D -> UniformType.INT; + case GL20.GL_SAMPLER_1D -> UniformType.INT; + case GL20.GL_SAMPLER_2D_SHADOW -> UniformType.INT; + case GL20.GL_SAMPLER_1D_SHADOW -> UniformType.INT; + default -> null; + }; + } + + private static boolean isSampler(int type) { + return type == GL20.GL_SAMPLER_1D + || type == GL20.GL_SAMPLER_2D + || type == GL30.GL_UNSIGNED_INT_SAMPLER_2D + || type == GL30.GL_UNSIGNED_INT_SAMPLER_3D + || type == GL20.GL_SAMPLER_3D + || type == GL20.GL_SAMPLER_1D_SHADOW + || type == GL20.GL_SAMPLER_2D_SHADOW; + } + + private static boolean isImage(int type) { + return type == ARBShaderImageLoadStore.GL_IMAGE_1D + || type == ARBShaderImageLoadStore.GL_IMAGE_2D + || type == ARBShaderImageLoadStore.GL_UNSIGNED_INT_IMAGE_1D + || type == ARBShaderImageLoadStore.GL_UNSIGNED_INT_IMAGE_2D + || type == ARBShaderImageLoadStore.GL_UNSIGNED_INT_IMAGE_3D + || type == ARBShaderImageLoadStore.GL_INT_IMAGE_1D + || type == ARBShaderImageLoadStore.GL_INT_IMAGE_2D + || type == ARBShaderImageLoadStore.GL_INT_IMAGE_3D + || type == ARBShaderImageLoadStore.GL_IMAGE_3D + || type == ARBShaderImageLoadStore.GL_IMAGE_1D_ARRAY + || type == ARBShaderImageLoadStore.GL_IMAGE_2D_ARRAY; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/sampler/SamplerBinding.java b/src/main/java/net/coderbot/iris/gl/sampler/SamplerBinding.java new file mode 100644 index 000000000..22aef74b2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/sampler/SamplerBinding.java @@ -0,0 +1,30 @@ +package net.coderbot.iris.gl.sampler; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.state.ValueUpdateNotifier; + +import java.util.function.IntSupplier; + +public class SamplerBinding { + private final int textureUnit; + private final IntSupplier texture; + private final ValueUpdateNotifier notifier; + + public SamplerBinding(int textureUnit, IntSupplier texture, ValueUpdateNotifier notifier) { + this.textureUnit = textureUnit; + this.texture = texture; + this.notifier = notifier; + } + + public void update() { + updateSampler(); + + if (notifier != null) { + notifier.setListener(this::updateSampler); + } + } + + private void updateSampler() { + IrisRenderSystem.bindTextureToUnit(textureUnit, texture.getAsInt()); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/sampler/SamplerHolder.java b/src/main/java/net/coderbot/iris/gl/sampler/SamplerHolder.java new file mode 100644 index 000000000..c44aeb3d1 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/sampler/SamplerHolder.java @@ -0,0 +1,21 @@ +package net.coderbot.iris.gl.sampler; + +import net.coderbot.iris.gl.state.ValueUpdateNotifier; + +import java.util.function.IntSupplier; + +public interface SamplerHolder { + void addExternalSampler(int textureUnit, String... names); + boolean hasSampler(String name); + + /** + * Like addDynamicSampler, but also ensures that any unrecognized / unbound samplers sample from this + * sampler. + * + * Throws an exception if texture unit 0 is already allocated or reserved in some way. Do not call this + * function after calls to addDynamicSampler, it must be called before any calls to addDynamicSampler. + */ + boolean addDefaultSampler(IntSupplier sampler, String... names); + boolean addDynamicSampler(IntSupplier sampler, String... names); + boolean addDynamicSampler(IntSupplier sampler, ValueUpdateNotifier notifier, String... names); +} diff --git a/src/main/java/net/coderbot/iris/gl/sampler/SamplerLimits.java b/src/main/java/net/coderbot/iris/gl/sampler/SamplerLimits.java new file mode 100644 index 000000000..4338f93f1 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/sampler/SamplerLimits.java @@ -0,0 +1,31 @@ +package net.coderbot.iris.gl.sampler; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; + +public class SamplerLimits { + private final int maxTextureUnits; + private final int maxDrawBuffers; + private static SamplerLimits instance; + + private SamplerLimits() { + this.maxTextureUnits = GL11.glGetInteger(GL20.GL_MAX_TEXTURE_IMAGE_UNITS); + this.maxDrawBuffers = GL11.glGetInteger(GL20.GL_MAX_DRAW_BUFFERS); + } + + public int getMaxTextureUnits() { + return maxTextureUnits; + } + + public int getMaxDrawBuffers() { + return maxDrawBuffers; + } + + public static SamplerLimits get() { + if (instance == null) { + instance = new SamplerLimits(); + } + + return instance; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/shader/GlShader.java b/src/main/java/net/coderbot/iris/gl/shader/GlShader.java new file mode 100644 index 000000000..c1e9126ef --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/shader/GlShader.java @@ -0,0 +1,64 @@ +// This file is based on code from Sodium by JellySquid, licensed under the LGPLv3 license. + +package net.coderbot.iris.gl.shader; + +import net.coderbot.iris.gl.GLDebug; +import net.coderbot.iris.gl.GlResource; +import net.coderbot.iris.gl.IrisRenderSystem; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.KHRDebug; + +import java.util.Locale; + +/** + * A compiled OpenGL shader object. + */ +public class GlShader extends GlResource { + private static final Logger LOGGER = LogManager.getLogger(GlShader.class); + + private final String name; + + public GlShader(ShaderType type, String name, String src) { + super(createShader(type, name, src)); + + this.name = name; + } + + private static int createShader(ShaderType type, String name, String src) { + int handle = GL20.glCreateShader(type.id); + ShaderWorkarounds.safeShaderSource(handle, src); + GL20.glCompileShader(handle); + + GLDebug.nameObject(KHRDebug.GL_SHADER, handle, name + "(" + type.name().toLowerCase(Locale.ROOT) + ")"); + + String log = IrisRenderSystem.getShaderInfoLog(handle); + + if (!log.isEmpty()) { + LOGGER.warn("Shader compilation log for " + name + ": " + log); + } + + int result = GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS); + + if (result != GL11.GL_TRUE) { + throw new RuntimeException("Shader compilation failed, see log for details"); + } + + return handle; + } + + public String getName() { + return this.name; + } + + public int getHandle() { + return this.getGlId(); + } + + @Override + protected void destroyInternal() { + GL20.glDeleteShader(this.getGlId()); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/shader/ProgramCreator.java b/src/main/java/net/coderbot/iris/gl/shader/ProgramCreator.java new file mode 100644 index 000000000..26c47dbe6 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/shader/ProgramCreator.java @@ -0,0 +1,52 @@ +// This file is based on code from Sodium by JellySquid, licensed under the LGPLv3 license. + +package net.coderbot.iris.gl.shader; + +import net.coderbot.iris.gl.GLDebug; +import net.coderbot.iris.gl.IrisRenderSystem; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.KHRDebug; + +public class ProgramCreator { + private static final Logger LOGGER = LogManager.getLogger(ProgramCreator.class); + + 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 + IrisRenderSystem.bindAttributeLocation(program, 11, "mc_Entity"); + IrisRenderSystem.bindAttributeLocation(program, 12, "mc_midTexCoord"); + IrisRenderSystem.bindAttributeLocation(program, 13, "at_tangent"); + IrisRenderSystem.bindAttributeLocation(program, 14, "at_midBlock"); + + for (GlShader shader : shaders) { + GL20.glAttachShader(program, shader.getHandle()); + } + + GL20.glLinkProgram(program); + + GLDebug.nameObject(KHRDebug.GL_PROGRAM, program, name); + + //Always detach shaders according to https://www.khronos.org/opengl/wiki/Shader_Compilation#Cleanup + for (GlShader shader : shaders) { + IrisRenderSystem.detachShader(program, shader.getHandle()); + } + + String log = IrisRenderSystem.getProgramInfoLog(program); + + if (!log.isEmpty()) { + LOGGER.warn("Program link log for " + name + ": " + log); + } + + int result = GL20.glGetProgrami(program, GL20.GL_LINK_STATUS); + + if (result != GL11.GL_TRUE) { + throw new RuntimeException("Shader program linking failed, see log for details"); + } + + return program; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/shader/ShaderType.java b/src/main/java/net/coderbot/iris/gl/shader/ShaderType.java new file mode 100644 index 000000000..49d621f11 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/shader/ShaderType.java @@ -0,0 +1,23 @@ +// This file is based on code from Sodium by JellySquid, licensed under the LGPLv3 license. + +package net.coderbot.iris.gl.shader; + +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL32; +import org.lwjgl.opengl.GL43; + +/** + * An enumeration over the supported OpenGL shader types. + */ +public enum ShaderType { + VERTEX(GL20.GL_VERTEX_SHADER), + GEOMETRY(GL32.GL_GEOMETRY_SHADER), + FRAGMENT(GL20.GL_FRAGMENT_SHADER), + COMPUTE(GL43.GL_COMPUTE_SHADER); + + public final int id; + + ShaderType(int id) { + this.id = id; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/shader/ShaderWorkarounds.java b/src/main/java/net/coderbot/iris/gl/shader/ShaderWorkarounds.java new file mode 100644 index 000000000..cb4f4d76f --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/shader/ShaderWorkarounds.java @@ -0,0 +1,50 @@ +// Copyright 2020 Grondag +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package net.coderbot.iris.gl.shader; + +import org.lwjgl.PointerBuffer; + +import java.nio.ByteBuffer; + +/** + * Contains a workaround for a crash in nglShaderSource on some AMD drivers. Copied from the following Canvas commit: + * https://github.com/grondag/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96 + */ +public class ShaderWorkarounds { + /** + * Identical in function to {@link GL20C#glShaderSource(int, CharSequence)} but + * passes a null pointer for string length to force the driver to rely on the null + * terminator for string length. This is a workaround for an apparent flaw with some + * AMD drivers that don't receive or interpret the length correctly, resulting in + * an access violation when the driver tries to read past the string memory. + * + *

Hat tip to fewizz for the find and the fix. + */ + public static void safeShaderSource(int glId, CharSequence source) { + final MemoryStack stack = MemoryStack.stackGet(); + final int stackPointer = stack.getPointer(); + + try { + final ByteBuffer sourceBuffer = MemoryUtil.memUTF8(source, true); + final PointerBuffer pointers = stack.mallocPointer(1); + pointers.put(sourceBuffer); + + GL20C.nglShaderSource(glId, 1, pointers.address0(), 0); + org.lwjgl.system.APIUtil.apiArrayFree(pointers.address0(), 1); + } finally { + stack.setPointer(stackPointer); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/shader/StandardMacros.java b/src/main/java/net/coderbot/iris/gl/shader/StandardMacros.java new file mode 100644 index 000000000..e84a5c776 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/shader/StandardMacros.java @@ -0,0 +1,265 @@ +package net.coderbot.iris.gl.shader; + +import com.google.common.collect.ImmutableList; +import cpw.mods.fml.common.Loader; +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 org.lwjgl.LWJGLUtil; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; + +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.Objects; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class StandardMacros { + private static final Pattern SEMVER_PATTERN = Pattern.compile("(?\\d+)\\.(?\\d+)\\.*(?\\d*)(.*)"); + + private static void define(List defines, String key) { + defines.add(new StringPair(key, "")); + } + + private static void define(List defines, String key, String value) { + defines.add(new StringPair(key, value)); + } + + public static Iterable createStandardEnvironmentDefines() { + ArrayList standardDefines = new ArrayList<>(); + + define(standardDefines, "MC_VERSION", getMcVersion()); + define(standardDefines, "MC_GL_VERSION", getGlVersion(GL11.GL_VERSION)); + define(standardDefines, "MC_GLSL_VERSION", getGlVersion(GL20.GL_SHADING_LANGUAGE_VERSION)); + define(standardDefines, getOsString()); + define(standardDefines, getVendor()); + define(standardDefines, getRenderer()); + + for (String glExtension : getGlExtensions()) { + define(standardDefines, glExtension); + } + + define(standardDefines, "MC_NORMAL_MAP"); + define(standardDefines, "MC_SPECULAR_MAP"); + define(standardDefines, "MC_RENDER_QUALITY", "1.0"); + define(standardDefines, "MC_SHADOW_QUALITY", "1.0"); + define(standardDefines, "MC_HAND_DEPTH", Float.toString(HandRenderer.DEPTH)); + + TextureFormat textureFormat = TextureFormatLoader.getFormat(); + if (textureFormat != null) { + for (String define : textureFormat.getDefines()) { + define(standardDefines, define); + } + } + + getRenderStages().forEach((stage, index) -> define(standardDefines, stage, index)); + + for (String irisDefine : getIrisDefines()) { + define(standardDefines, irisDefine); + } + + return ImmutableList.copyOf(standardDefines); + } + + /** + * Gets the current mc version String in a 5 digit format + * + * @return mc version string + * @see Optifine Doc + */ + public static String getMcVersion() { + final String version = Loader.MC_VERSION;; + + String[] splitVersion = version.split("\\."); + + if (splitVersion.length < 2) { + throw new IllegalStateException("Could not parse game version \"" + version + "\""); + } + + String major = splitVersion[0]; + String minor = splitVersion[1]; + String bugfix; + + if (splitVersion.length < 3) { + bugfix = "00"; + } else { + bugfix = splitVersion[2]; + } + + if (minor.length() == 1) { + minor = 0 + minor; + } + if (bugfix.length() == 1) { + bugfix = 0 + bugfix; + } + + return major + minor + bugfix; + } + + /** + * Returns the current GL Version using regex + * + * @param name the name of the gl attribute to parse + * @return current gl version stripped of semantic versioning + * @see Optifine Doc for GL Version + * @see Optifine Doc for GLSL Version + */ + public static String getGlVersion(int name) { + final String info = GL11.glGetString(name); + + Matcher matcher = SEMVER_PATTERN.matcher(Objects.requireNonNull(info)); + + if (!matcher.matches()) { + throw new IllegalStateException("Could not parse GL version from \"" + info + "\""); + } + + String major = group(matcher, "major"); + String minor = group(matcher, "minor"); + String bugfix = group(matcher, "bugfix"); + + if (bugfix == null) { + // if bugfix is not there, it is 0 + bugfix = "0"; + } + + if (major == null || minor == null) { + throw new IllegalStateException("Could not parse GL version from \"" + info + "\""); + } + + return major + minor + bugfix; + } + + /** + * Expanded version of {@link Matcher#group(String)} that does not throw an exception. + * If the argument is incorrect (normally resulting in an exception), it returns null + * + * @param matcher matcher to check the group by + * @param name name of the group + * @return the section of the matcher that is a group, or null, if that matcher does not contain said group + */ + public static String group(Matcher matcher, String name) { + try { + return matcher.group(name); + } catch (IllegalArgumentException | IllegalStateException exception) { + return null; + } + } + + /** + * Returns the current OS String + * + * @return the string based on the current OS + * @see Optifine Doc + */ + public static String getOsString() { + return switch (LWJGLUtil.getPlatform()) { + case LWJGLUtil.PLATFORM_MACOSX -> "MC_OS_MAC"; + case LWJGLUtil.PLATFORM_LINUX -> "MC_OS_LINUX"; + case LWJGLUtil.PLATFORM_WINDOWS -> "MC_OS_WINDOWS"; + default -> "MC_OS_UNKNOWN"; + }; + } + + /** + * Returns a string indicating the graphics card being used + * + * @return the graphics card prefixed with "MC_GL_VENDOR_" + * @see Optifine Doc + */ + public static String getVendor() { + String vendor = Objects.requireNonNull(GL11.glGetString(GL11.GL_VENDOR)).toLowerCase(Locale.ROOT); + if (vendor.startsWith("ati")) { + return "MC_GL_VENDOR_ATI"; + } else if (vendor.startsWith("intel")) { + return "MC_GL_VENDOR_INTEL"; + } else if (vendor.startsWith("nvidia")) { + return "MC_GL_VENDOR_NVIDIA"; + } else if (vendor.startsWith("amd")) { + return "MC_GL_VENDOR_AMD"; + } else if (vendor.startsWith("x.org")) { + return "MC_GL_VENDOR_XORG"; + } + return "MC_GL_VENDOR_OTHER"; + } + + /** + * Returns the graphics driver being used + * + * @return graphics driver prefixed with "MC_GL_RENDERER_" + * @see Optifine Doc + */ + public static String getRenderer() { + String renderer = Objects.requireNonNull(GL11.glGetString(GL11.GL_RENDERER)).toLowerCase(Locale.ROOT); + if (renderer.startsWith("amd")) { + return "MC_GL_RENDERER_RADEON"; + } else if (renderer.startsWith("ati")) { + return "MC_GL_RENDERER_RADEON"; + } else if (renderer.startsWith("radeon")) { + return "MC_GL_RENDERER_RADEON"; + } else if (renderer.startsWith("gallium")) { + return "MC_GL_RENDERER_GALLIUM"; + } else if (renderer.startsWith("intel")) { + return "MC_GL_RENDERER_INTEL"; + } else if (renderer.startsWith("geforce")) { + return "MC_GL_RENDERER_GEFORCE"; + } else if (renderer.startsWith("nvidia")) { + return "MC_GL_RENDERER_GEFORCE"; + } else if (renderer.startsWith("quadro")) { + return "MC_GL_RENDERER_QUADRO"; + } else if (renderer.startsWith("nvs")) { + return "MC_GL_RENDERER_QUADRO"; + } else if (renderer.startsWith("mesa")) { + return "MC_GL_RENDERER_MESA"; + } + return "MC_GL_RENDERER_OTHER"; + } + + /** + * Returns the list of currently enabled GL extensions + * This is done by calling {@link GL11#glGetString} with the arg {@link GL11#GL_EXTENSIONS} + * + * @return list of activated extensions prefixed with "MC_" + * @see Optifine Doc + */ + public static Set getGlExtensions() { + String[] extensions = Objects.requireNonNull(GL11.glGetString(GL11.GL_EXTENSIONS)).split("\\s+"); + + // TODO note that we do not add extensions based on if the shader uses them and if they are supported + // see https://github.com/sp614x/optifine/blob/master/OptiFineDoc/doc/shaders.txt#L738 + + // NB: Use Collectors.toSet(). In some cases, there are duplicate extensions in the extension list. + // RenderDoc is one example - it causes the GL_KHR_debug extension to appear twice: + + return Arrays.stream(extensions).map(s -> "MC_" + s).collect(Collectors.toSet()); + } + + public static Map getRenderStages() { + Map stages = new HashMap<>(); + for (WorldRenderingPhase phase : WorldRenderingPhase.values()) { + stages.put("MC_RENDER_STAGE_" + phase.name(), String.valueOf(phase.ordinal())); + } + return stages; + } + + /** + * Returns the list of Iris-exclusive uniforms supported in the current version of Iris. + * + * @return List of definitions corresponding to the uniform names prefixed with "MC_" + */ + public static List getIrisDefines() { + List defines = new ArrayList<>(); + // All Iris-exclusive uniforms should have a corresponding definition here. Example: + // defines.add("MC_UNIFORM_DRAGON_DEATH_PROGRESS"); + + return defines; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/state/StateUpdateNotifiers.java b/src/main/java/net/coderbot/iris/gl/state/StateUpdateNotifiers.java new file mode 100644 index 000000000..7c1f535f3 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/state/StateUpdateNotifiers.java @@ -0,0 +1,18 @@ +package net.coderbot.iris.gl.state; + +/** + * Holds some standard update notifiers for various elements of GL state. Currently, this class has a few listeners for + * fog-related values. + */ +public class StateUpdateNotifiers { + public static ValueUpdateNotifier fogToggleNotifier; + public static ValueUpdateNotifier fogModeNotifier; + public static ValueUpdateNotifier fogStartNotifier; + public static ValueUpdateNotifier fogEndNotifier; + public static ValueUpdateNotifier fogDensityNotifier; + public static ValueUpdateNotifier blendFuncNotifier; + public static ValueUpdateNotifier bindTextureNotifier; + public static ValueUpdateNotifier normalTextureChangeNotifier; + public static ValueUpdateNotifier specularTextureChangeNotifier; + public static ValueUpdateNotifier phaseChangeNotifier; +} diff --git a/src/main/java/net/coderbot/iris/gl/state/ValueUpdateNotifier.java b/src/main/java/net/coderbot/iris/gl/state/ValueUpdateNotifier.java new file mode 100644 index 000000000..81774db5a --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/state/ValueUpdateNotifier.java @@ -0,0 +1,12 @@ +package net.coderbot.iris.gl.state; + +/** + * A + */ +public interface ValueUpdateNotifier { + /** + * Sets up a listener with this notifier. Whenever the underlying value of + * @param listener + */ + void setListener(Runnable listener); +} diff --git a/src/main/java/net/coderbot/iris/gl/texture/DepthBufferFormat.java b/src/main/java/net/coderbot/iris/gl/texture/DepthBufferFormat.java new file mode 100644 index 000000000..d0e9316d4 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/texture/DepthBufferFormat.java @@ -0,0 +1,80 @@ +package net.coderbot.iris.gl.texture; + +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; +import org.lwjgl.opengl.GL30; + +public enum DepthBufferFormat { + DEPTH(false), + DEPTH16(false), + DEPTH24(false), + DEPTH32(false), + DEPTH32F(false), + DEPTH_STENCIL(true), + DEPTH24_STENCIL8(true), + DEPTH32F_STENCIL8(true); + + private final boolean combinedStencil; + + DepthBufferFormat(boolean combinedStencil) { + this.combinedStencil = combinedStencil; + } + + @Nullable + public static DepthBufferFormat fromGlEnum(int glenum) { + switch (glenum) { + case GL11.GL_DEPTH_COMPONENT: return DepthBufferFormat.DEPTH; + case GL14.GL_DEPTH_COMPONENT16: return DepthBufferFormat.DEPTH16; + case GL14.GL_DEPTH_COMPONENT24: return DepthBufferFormat.DEPTH24; + case GL14.GL_DEPTH_COMPONENT32: return DepthBufferFormat.DEPTH32; + case GL30.GL_DEPTH_COMPONENT32F: return DepthBufferFormat.DEPTH32F; + case GL30.GL_DEPTH_STENCIL: return DepthBufferFormat.DEPTH_STENCIL; + case GL30.GL_DEPTH24_STENCIL8: return DepthBufferFormat.DEPTH24_STENCIL8; + case GL30.GL_DEPTH32F_STENCIL8: return DepthBufferFormat.DEPTH32F_STENCIL8; + default: return null; + } + } + + public static DepthBufferFormat fromGlEnumOrDefault(int glenum) { + DepthBufferFormat format = fromGlEnum(glenum); + if (format == null) { + // yolo, just assume it's GL_DEPTH_COMPONENT + return DepthBufferFormat.DEPTH; + } + return format; + } + + public int getGlInternalFormat() { + return switch (this) { + case DEPTH -> GL11.GL_DEPTH_COMPONENT; + case DEPTH16 -> GL14.GL_DEPTH_COMPONENT16; + case DEPTH24 -> GL14.GL_DEPTH_COMPONENT24; + case DEPTH32 -> GL14.GL_DEPTH_COMPONENT32; + case DEPTH32F -> GL30.GL_DEPTH_COMPONENT32F; + case DEPTH_STENCIL -> GL30.GL_DEPTH_STENCIL; + case DEPTH24_STENCIL8 -> GL30.GL_DEPTH24_STENCIL8; + case DEPTH32F_STENCIL8 -> GL30.GL_DEPTH32F_STENCIL8; + }; + + } + + public int getGlType() { + return isCombinedStencil() ? GL30.GL_DEPTH_STENCIL : GL11.GL_DEPTH_COMPONENT; + } + + public int getGlFormat() { + return switch (this) { + case DEPTH, DEPTH16 -> GL11.GL_UNSIGNED_SHORT; + case DEPTH24, DEPTH32 -> GL11.GL_UNSIGNED_INT; + case DEPTH32F -> GL11.GL_FLOAT; + case DEPTH_STENCIL, DEPTH24_STENCIL8 -> GL30.GL_UNSIGNED_INT_24_8; + case DEPTH32F_STENCIL8 -> GL30.GL_FLOAT_32_UNSIGNED_INT_24_8_REV; + }; + + } + + public boolean isCombinedStencil() { + return combinedStencil; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/texture/DepthCopyStrategy.java b/src/main/java/net/coderbot/iris/gl/texture/DepthCopyStrategy.java new file mode 100644 index 000000000..169e177d5 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/texture/DepthCopyStrategy.java @@ -0,0 +1,119 @@ +package net.coderbot.iris.gl.texture; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.framebuffer.GlFramebuffer; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL43; + +public interface DepthCopyStrategy { + // FB -> T + class Gl20CopyTexture implements DepthCopyStrategy { + private Gl20CopyTexture() { + // private + } + + @Override + public boolean needsDestFramebuffer() { + return false; + } + + @Override + public void copy(GlFramebuffer sourceFb, int sourceTexture, GlFramebuffer destFb, int destTexture, int width, int height) { + sourceFb.bindAsReadBuffer(); + + IrisRenderSystem.copyTexSubImage2D( + destTexture, + // target + GL11.GL_TEXTURE_2D, + // level + 0, + // xoffset, yoffset + 0, 0, + // x, y + 0, 0, + // width + width, + // height + height); + } + } + + // FB -> FB + class Gl30BlitFbCombinedDepthStencil implements DepthCopyStrategy { + private Gl30BlitFbCombinedDepthStencil() { + // private + } + + @Override + public boolean needsDestFramebuffer() { + return true; + } + + @Override + public void copy(GlFramebuffer sourceFb, int sourceTexture, GlFramebuffer destFb, int destTexture, int width, int height) { + IrisRenderSystem.blitFramebuffer(sourceFb.getId(), destFb.getId(), 0, 0, width, height, + 0, 0, width, height, + GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT, + GL11.GL_NEAREST); + } + } + + // T -> T + // Fastest + class Gl43CopyImage implements DepthCopyStrategy { + private Gl43CopyImage() { + // private + } + + @Override + public boolean needsDestFramebuffer() { + return false; + } + + @Override + public void copy(GlFramebuffer sourceFb, int sourceTexture, GlFramebuffer destFb, int destTexture, int width, int height) { + GL43.glCopyImageSubData( + sourceTexture, + GL11.GL_TEXTURE_2D, + 0, + 0, + 0, + 0, + destTexture, + GL11.GL_TEXTURE_2D, + 0, + 0, + 0, + 0, + width, + height, + 1 + ); + } + } + + static DepthCopyStrategy fastest(boolean combinedStencilRequired) { + if (Iris.capabilities.GL_ARB_copy_image) { + return new Gl43CopyImage(); + } + + if (combinedStencilRequired) { + return new Gl30BlitFbCombinedDepthStencil(); + } else { + return new Gl20CopyTexture(); + } + } + + boolean needsDestFramebuffer(); + + /** + * Executes the copy. May or may not clobber GL_READ_FRAMEBUFFER and GL_DRAW_FRAMEBUFFER bindings - the caller is + * responsible for ensuring that they are restored to sensible values, or that the previous values are not relied + * on. The callee is responsible for ensuring that texture bindings are not modified. + * + * @param destFb The destination framebuffer. If {@link #needsDestFramebuffer()} returns false, then this param + * will not be used, and it can be null. + */ + void copy(GlFramebuffer sourceFb, int sourceTexture, GlFramebuffer destFb, int destTexture, int width, int height); +} diff --git a/src/main/java/net/coderbot/iris/gl/texture/InternalTextureFormat.java b/src/main/java/net/coderbot/iris/gl/texture/InternalTextureFormat.java new file mode 100644 index 000000000..5989fd543 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/texture/InternalTextureFormat.java @@ -0,0 +1,108 @@ +package net.coderbot.iris.gl.texture; + +import net.coderbot.iris.gl.GlVersion; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GL31; + +import java.util.Optional; + +public enum InternalTextureFormat { + // Default + // TODO: This technically shouldn't be exposed to shaders since it's not in the specification, it's the default anyways + RGBA(GL11.GL_RGBA, GlVersion.GL_11, PixelFormat.RGBA), + // 8-bit normalized + R8(GL30.GL_R8, GlVersion.GL_30, PixelFormat.RED), + RG8(GL30.GL_RG8, GlVersion.GL_30, PixelFormat.RG), + RGB8(GL11.GL_RGB8, GlVersion.GL_11, PixelFormat.RGB), + RGBA8(GL11.GL_RGBA8, GlVersion.GL_11, PixelFormat.RGBA), + // 8-bit signed normalized + R8_SNORM(GL31.GL_R8_SNORM, GlVersion.GL_31, PixelFormat.RED), + RG8_SNORM(GL31.GL_RG8_SNORM, GlVersion.GL_31, PixelFormat.RG), + RGB8_SNORM(GL31.GL_RGB8_SNORM, GlVersion.GL_31, PixelFormat.RGB), + RGBA8_SNORM(GL31.GL_RGBA8_SNORM, GlVersion.GL_31, PixelFormat.RGBA), + // 16-bit normalized + R16(GL30.GL_R16, GlVersion.GL_30, PixelFormat.RED), + RG16(GL30.GL_RG16, GlVersion.GL_30, PixelFormat.RG), + RGB16(GL11.GL_RGB16, GlVersion.GL_11, PixelFormat.RGB), + RGBA16(GL11.GL_RGBA16, GlVersion.GL_11, PixelFormat.RGBA), + // 16-bit signed normalized + R16_SNORM(GL31.GL_R16_SNORM, GlVersion.GL_31, PixelFormat.RED), + RG16_SNORM(GL31.GL_RG16_SNORM, GlVersion.GL_31, PixelFormat.RG), + RGB16_SNORM(GL31.GL_RGB16_SNORM, GlVersion.GL_31, PixelFormat.RGB), + RGBA16_SNORM(GL31.GL_RGBA16_SNORM, GlVersion.GL_31, PixelFormat.RGBA), + // 16-bit float + R16F(GL30.GL_R16F, GlVersion.GL_30, PixelFormat.RED), + RG16F(GL30.GL_RG16F, GlVersion.GL_30, PixelFormat.RG), + RGB16F(GL30.GL_RGB16F, GlVersion.GL_30, PixelFormat.RGB), + RGBA16F(GL30.GL_RGBA16F, GlVersion.GL_30, PixelFormat.RGBA), + // 32-bit float + R32F(GL30.GL_R32F, GlVersion.GL_30, PixelFormat.RED), + RG32F(GL30.GL_RG32F, GlVersion.GL_30, PixelFormat.RG), + RGB32F(GL30.GL_RGB32F, GlVersion.GL_30, PixelFormat.RGB), + RGBA32F(GL30.GL_RGBA32F, GlVersion.GL_30, PixelFormat.RGBA), + // 8-bit integer + R8I(GL30.GL_R8I, GlVersion.GL_30, PixelFormat.RED_INTEGER), + RG8I(GL30.GL_RG8I, GlVersion.GL_30, PixelFormat.RG_INTEGER), + RGB8I(GL30.GL_RGB8I, GlVersion.GL_30, PixelFormat.RGB_INTEGER), + RGBA8I(GL30.GL_RGBA8I, GlVersion.GL_30, PixelFormat.RGBA_INTEGER), + // 8-bit unsigned integer + R8UI(GL30.GL_R8UI, GlVersion.GL_30, PixelFormat.RED_INTEGER), + RG8UI(GL30.GL_RG8UI, GlVersion.GL_30, PixelFormat.RG_INTEGER), + RGB8UI(GL30.GL_RGB8UI, GlVersion.GL_30, PixelFormat.RGB_INTEGER), + RGBA8UI(GL30.GL_RGBA8UI, GlVersion.GL_30, PixelFormat.RGBA_INTEGER), + // 16-bit integer + R16I(GL30.GL_R16I, GlVersion.GL_30, PixelFormat.RED_INTEGER), + RG16I(GL30.GL_RG16I, GlVersion.GL_30, PixelFormat.RG_INTEGER), + RGB16I(GL30.GL_RGB16I, GlVersion.GL_30, PixelFormat.RGB_INTEGER), + RGBA16I(GL30.GL_RGBA16I, GlVersion.GL_30, PixelFormat.RGBA_INTEGER), + // 16-bit unsigned integer + R16UI(GL30.GL_R16UI, GlVersion.GL_30, PixelFormat.RED_INTEGER), + RG16UI(GL30.GL_RG16UI, GlVersion.GL_30, PixelFormat.RG_INTEGER), + RGB16UI(GL30.GL_RGB16UI, GlVersion.GL_30, PixelFormat.RGB_INTEGER), + RGBA16UI(GL30.GL_RGBA16UI, GlVersion.GL_30, PixelFormat.RGBA_INTEGER), + // 32-bit integer + R32I(GL30.GL_R32I, GlVersion.GL_30, PixelFormat.RED_INTEGER), + RG32I(GL30.GL_RG32I, GlVersion.GL_30, PixelFormat.RG_INTEGER), + RGB32I(GL30.GL_RGB32I, GlVersion.GL_30, PixelFormat.RGB_INTEGER), + RGBA32I(GL30.GL_RGBA32I, GlVersion.GL_30, PixelFormat.RGBA_INTEGER), + // 32-bit unsigned integer + R32UI(GL30.GL_R32UI, GlVersion.GL_30, PixelFormat.RED_INTEGER), + RG32UI(GL30.GL_RG32UI, GlVersion.GL_30, PixelFormat.RG_INTEGER), + RGB32UI(GL30.GL_RGB32UI, GlVersion.GL_30, PixelFormat.RGB_INTEGER), + RGBA32UI(GL30.GL_RGBA32UI, GlVersion.GL_30, PixelFormat.RGBA_INTEGER), + // Mixed + R3_G3_B2(GL11.GL_R3_G3_B2, GlVersion.GL_11, PixelFormat.RGB), + RGB5_A1(GL11.GL_RGB5_A1, GlVersion.GL_11, PixelFormat.RGBA), + RGB10_A2(GL11.GL_RGB10_A2, GlVersion.GL_11, PixelFormat.RGBA), + R11F_G11F_B10F(GL30.GL_R11F_G11F_B10F, GlVersion.GL_30, PixelFormat.RGB), + RGB9_E5(GL30.GL_RGB9_E5, GlVersion.GL_30, PixelFormat.RGB); + + private final int glFormat; + private final GlVersion minimumGlVersion; + private final PixelFormat expectedPixelFormat; + + InternalTextureFormat(int glFormat, GlVersion minimumGlVersion, PixelFormat expectedPixelFormat) { + this.glFormat = glFormat; + this.minimumGlVersion = minimumGlVersion; + this.expectedPixelFormat = expectedPixelFormat; + } + + public static Optional fromString(String name) { + try { + return Optional.of(InternalTextureFormat.valueOf(name)); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } + + public int getGlFormat() { + return glFormat; + } + + public PixelFormat getPixelFormat() { return expectedPixelFormat; } + + public GlVersion getMinimumGlVersion() { + return minimumGlVersion; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/texture/PixelFormat.java b/src/main/java/net/coderbot/iris/gl/texture/PixelFormat.java new file mode 100644 index 000000000..338dd3f7c --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/texture/PixelFormat.java @@ -0,0 +1,53 @@ +package net.coderbot.iris.gl.texture; + +import net.coderbot.iris.gl.GlVersion; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; +import org.lwjgl.opengl.GL30; + +import java.util.Optional; + +public enum PixelFormat { + RED(GL11.GL_RED, GlVersion.GL_11, false), + RG(GL30.GL_RG, GlVersion.GL_30, false), + RGB(GL11.GL_RGB, GlVersion.GL_11, false), + BGR(GL12.GL_BGR, GlVersion.GL_12, false), + RGBA(GL11.GL_RGBA, GlVersion.GL_11, false), + BGRA(GL12.GL_BGRA, GlVersion.GL_12, false), + RED_INTEGER(GL30.GL_RED_INTEGER, GlVersion.GL_30, true), + RG_INTEGER(GL30.GL_RG_INTEGER, GlVersion.GL_30, true), + RGB_INTEGER(GL30.GL_RGB_INTEGER, GlVersion.GL_30, true), + BGR_INTEGER(GL30.GL_BGR_INTEGER, GlVersion.GL_30, true), + RGBA_INTEGER(GL30.GL_RGBA_INTEGER, GlVersion.GL_30, true), + BGRA_INTEGER(GL30.GL_BGRA_INTEGER, GlVersion.GL_30, true); + + private final int glFormat; + private final GlVersion minimumGlVersion; + private final boolean isInteger; + + PixelFormat(int glFormat, GlVersion minimumGlVersion, boolean isInteger) { + this.glFormat = glFormat; + this.minimumGlVersion = minimumGlVersion; + this.isInteger = isInteger; + } + + public static Optional fromString(String name) { + try { + return Optional.of(PixelFormat.valueOf(name)); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } + + public int getGlFormat() { + return glFormat; + } + + public GlVersion getMinimumGlVersion() { + return minimumGlVersion; + } + + public boolean isInteger() { + return isInteger; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/texture/PixelType.java b/src/main/java/net/coderbot/iris/gl/texture/PixelType.java new file mode 100644 index 000000000..7457b2faf --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/texture/PixelType.java @@ -0,0 +1,55 @@ +package net.coderbot.iris.gl.texture; + +import net.coderbot.iris.gl.GlVersion; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; +import org.lwjgl.opengl.GL30; + +import java.util.Optional; + +public enum PixelType { + BYTE(GL11.GL_BYTE, GlVersion.GL_11), + SHORT(GL11.GL_SHORT, GlVersion.GL_11), + INT(GL11.GL_INT, GlVersion.GL_11), + HALF_FLOAT(GL30.GL_HALF_FLOAT, GlVersion.GL_30), + FLOAT(GL11.GL_FLOAT, GlVersion.GL_11), + UNSIGNED_BYTE(GL11.GL_UNSIGNED_BYTE, GlVersion.GL_11), + UNSIGNED_BYTE_3_3_2(GL12.GL_UNSIGNED_BYTE_3_3_2, GlVersion.GL_12), + UNSIGNED_BYTE_2_3_3_REV(GL12.GL_UNSIGNED_BYTE_2_3_3_REV, GlVersion.GL_12), + UNSIGNED_SHORT(GL11.GL_UNSIGNED_SHORT, GlVersion.GL_11), + UNSIGNED_SHORT_5_6_5(GL12.GL_UNSIGNED_SHORT_5_6_5, GlVersion.GL_12), + UNSIGNED_SHORT_5_6_5_REV(GL12.GL_UNSIGNED_SHORT_5_6_5_REV, GlVersion.GL_12), + UNSIGNED_SHORT_4_4_4_4(GL12.GL_UNSIGNED_SHORT_4_4_4_4, GlVersion.GL_12), + UNSIGNED_SHORT_4_4_4_4_REV(GL12.GL_UNSIGNED_SHORT_4_4_4_4_REV, GlVersion.GL_12), + UNSIGNED_SHORT_5_5_5_1(GL12.GL_UNSIGNED_SHORT_5_5_5_1, GlVersion.GL_12), + UNSIGNED_SHORT_1_5_5_5_REV(GL12.GL_UNSIGNED_SHORT_1_5_5_5_REV, GlVersion.GL_12), + UNSIGNED_INT(GL11.GL_UNSIGNED_BYTE, GlVersion.GL_11), + UNSIGNED_INT_8_8_8_8(GL12.GL_UNSIGNED_INT_8_8_8_8, GlVersion.GL_12), + UNSIGNED_INT_8_8_8_8_REV(GL12.GL_UNSIGNED_INT_8_8_8_8_REV, GlVersion.GL_12), + UNSIGNED_INT_10_10_10_2(GL12.GL_UNSIGNED_INT_10_10_10_2, GlVersion.GL_12), + UNSIGNED_INT_2_10_10_10_REV(GL12.GL_UNSIGNED_INT_2_10_10_10_REV, GlVersion.GL_12); + + private final int glFormat; + private final GlVersion minimumGlVersion; + + PixelType(int glFormat, GlVersion minimumGlVersion) { + this.glFormat = glFormat; + this.minimumGlVersion = minimumGlVersion; + } + + public static Optional fromString(String name) { + try { + return Optional.of(PixelType.valueOf(name)); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } + + public int getGlFormat() { + return glFormat; + } + + public GlVersion getMinimumGlVersion() { + return minimumGlVersion; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/texture/TextureScaleOverride.java b/src/main/java/net/coderbot/iris/gl/texture/TextureScaleOverride.java new file mode 100644 index 000000000..e978ba1b5 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/texture/TextureScaleOverride.java @@ -0,0 +1,41 @@ +package net.coderbot.iris.gl.texture; + +public class TextureScaleOverride { + public float relativeX, relativeY; + public int sizeX, sizeY; + public final boolean isXRelative, isYRelative; + + public TextureScaleOverride(String xValue, String yValue) { + if (xValue.contains(".")) { + this.relativeX = Float.parseFloat(xValue); + this.isXRelative = true; + } else { + this.sizeX = Integer.parseInt(xValue); + this.isXRelative = false; + } + + if (yValue.contains(".")) { + this.relativeY = Float.parseFloat(yValue); + this.isYRelative = true; + } else { + this.sizeY = Integer.parseInt(yValue); + this.isYRelative = false; + } + } + + public int getX(int originalX) { + if (isXRelative) { + return (int) (originalX * relativeX); + } else { + return sizeX; + } + } + + public int getY(int originalY) { + if (isYRelative) { + return (int) (originalY * relativeY); + } else { + return sizeY; + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/texture/TextureUploadHelper.java b/src/main/java/net/coderbot/iris/gl/texture/TextureUploadHelper.java new file mode 100644 index 000000000..cfc97f19d --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/texture/TextureUploadHelper.java @@ -0,0 +1,22 @@ +package net.coderbot.iris.gl.texture; + +import org.lwjgl.opengl.GL11; + +public class TextureUploadHelper { + private TextureUploadHelper() { + // no construction + } + + public static void resetTextureUploadState() { + // Ensure that the pixel storage mode is in a sane state, otherwise the uploaded texture data will be quite + // incorrect. + // + // It is likely that this also avoids the crashes on AMD that I previously experienced with texture creation. + // + // This code is from Canvas: https://github.com/grondag/canvas/commit/f0ab652d7a8b7cc9febf0209bee15cffce9eac83 + GL11.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, 0); + GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_ROWS, 0); + GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_PIXELS, 0); + GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/BooleanUniform.java b/src/main/java/net/coderbot/iris/gl/uniform/BooleanUniform.java new file mode 100644 index 000000000..340575a69 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/BooleanUniform.java @@ -0,0 +1,9 @@ +package net.coderbot.iris.gl.uniform; + +import java.util.function.BooleanSupplier; + +public class BooleanUniform extends IntUniform { + BooleanUniform(int location, BooleanSupplier value) { + super(location, () -> value.getAsBoolean() ? 1 : 0); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/DynamicLocationalUniformHolder.java b/src/main/java/net/coderbot/iris/gl/uniform/DynamicLocationalUniformHolder.java new file mode 100644 index 000000000..12c678b0d --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/DynamicLocationalUniformHolder.java @@ -0,0 +1,56 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.state.ValueUpdateNotifier; +import org.joml.Vector2i; +import org.joml.Vector4f; +import org.joml.Vector4i; + +import java.util.function.DoubleSupplier; +import java.util.function.IntSupplier; +import java.util.function.Supplier; + +public interface DynamicLocationalUniformHolder extends LocationalUniformHolder, DynamicUniformHolder { + DynamicLocationalUniformHolder addDynamicUniform(Uniform uniform, ValueUpdateNotifier notifier); + + default DynamicLocationalUniformHolder uniform1f(String name, FloatSupplier value, ValueUpdateNotifier notifier) { + location(name, UniformType.FLOAT).ifPresent(id -> addDynamicUniform(new FloatUniform(id, value, notifier), notifier)); + + return this; + } + + default DynamicLocationalUniformHolder uniform1f(String name, IntSupplier value, ValueUpdateNotifier notifier) { + location(name, UniformType.FLOAT).ifPresent(id -> addDynamicUniform(new FloatUniform(id, () -> (float) value.getAsInt(), notifier), notifier)); + + return this; + } + + default DynamicLocationalUniformHolder uniform1f(String name, DoubleSupplier value, ValueUpdateNotifier notifier) { + location(name, UniformType.FLOAT).ifPresent(id -> addDynamicUniform(new FloatUniform(id, () -> (float) value.getAsDouble(), notifier), notifier)); + + return this; + } + + default DynamicLocationalUniformHolder uniform1i(String name, IntSupplier value, ValueUpdateNotifier notifier) { + location(name, UniformType.INT).ifPresent(id -> addDynamicUniform(new IntUniform(id, value, notifier), notifier)); + + return this; + } + + default DynamicLocationalUniformHolder uniform2i(String name, Supplier value, ValueUpdateNotifier notifier) { + location(name, UniformType.VEC2I).ifPresent(id -> addDynamicUniform(new Vector2IntegerJomlUniform(id, value, notifier), notifier)); + + return this; + } + + default DynamicUniformHolder uniform4f(String name, Supplier value, ValueUpdateNotifier notifier) { + location(name, UniformType.VEC4).ifPresent(id -> addDynamicUniform(new Vector4Uniform(id, value, notifier), notifier)); + + return this; + } + + default DynamicUniformHolder uniform4i(String name, Supplier value, ValueUpdateNotifier notifier) { + location(name, UniformType.VEC4I).ifPresent(id -> addDynamicUniform(new Vector4IntegerJomlUniform(id, value, notifier), notifier)); + + return this; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/DynamicUniformHolder.java b/src/main/java/net/coderbot/iris/gl/uniform/DynamicUniformHolder.java new file mode 100644 index 000000000..c921ef6b2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/DynamicUniformHolder.java @@ -0,0 +1,20 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.state.ValueUpdateNotifier; +import org.joml.Vector2i; +import org.joml.Vector4f; +import org.joml.Vector4i; + +import java.util.function.DoubleSupplier; +import java.util.function.IntSupplier; +import java.util.function.Supplier; + +public interface DynamicUniformHolder extends UniformHolder { + DynamicUniformHolder uniform1f(String name, FloatSupplier value, ValueUpdateNotifier notifier); + DynamicUniformHolder uniform1f(String name, IntSupplier value, ValueUpdateNotifier notifier); + DynamicUniformHolder uniform1f(String name, DoubleSupplier value, ValueUpdateNotifier notifier); + DynamicUniformHolder uniform1i(String name, IntSupplier value, ValueUpdateNotifier notifier); + DynamicUniformHolder uniform2i(String name, Supplier value, ValueUpdateNotifier notifier); + DynamicUniformHolder uniform4f(String name, Supplier value, ValueUpdateNotifier notifier); + DynamicUniformHolder uniform4i(String name, Supplier value, ValueUpdateNotifier notifier); +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/FloatSupplier.java b/src/main/java/net/coderbot/iris/gl/uniform/FloatSupplier.java new file mode 100644 index 000000000..9a8ccd4f8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/FloatSupplier.java @@ -0,0 +1,6 @@ +package net.coderbot.iris.gl.uniform; + +@FunctionalInterface +public interface FloatSupplier { + float getAsFloat(); +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/FloatUniform.java b/src/main/java/net/coderbot/iris/gl/uniform/FloatUniform.java new file mode 100644 index 000000000..4de68e710 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/FloatUniform.java @@ -0,0 +1,38 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.state.ValueUpdateNotifier; + +public class FloatUniform extends Uniform { + private float cachedValue; + private final FloatSupplier value; + + FloatUniform(int location, FloatSupplier value) { + this(location, value, null); + } + + FloatUniform(int location, FloatSupplier value, ValueUpdateNotifier notifier) { + super(location, notifier); + + this.cachedValue = 0; + this.value = value; + } + + @Override + public void update() { + updateValue(); + + if (notifier != null) { + notifier.setListener(this::updateValue); + } + } + + private void updateValue() { + float newValue = value.getAsFloat(); + + if (cachedValue != newValue) { + cachedValue = newValue; + IrisRenderSystem.uniform1f(location, newValue); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/IntUniform.java b/src/main/java/net/coderbot/iris/gl/uniform/IntUniform.java new file mode 100644 index 000000000..2d519efcf --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/IntUniform.java @@ -0,0 +1,40 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.state.ValueUpdateNotifier; + +import java.util.function.IntSupplier; + +public class IntUniform extends Uniform { + private int cachedValue; + private final IntSupplier value; + + IntUniform(int location, IntSupplier value) { + this(location, value, null); + } + + IntUniform(int location, IntSupplier value, ValueUpdateNotifier notifier) { + super(location, notifier); + + this.cachedValue = 0; + this.value = value; + } + + @Override + public void update() { + updateValue(); + + if (notifier != null) { + notifier.setListener(this::updateValue); + } + } + + private void updateValue() { + int newValue = value.getAsInt(); + + if (cachedValue != newValue) { + cachedValue = newValue; + IrisRenderSystem.uniform1i(location, newValue); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/LocationalUniformHolder.java b/src/main/java/net/coderbot/iris/gl/uniform/LocationalUniformHolder.java new file mode 100644 index 000000000..a0afb3f50 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/LocationalUniformHolder.java @@ -0,0 +1,119 @@ +package net.coderbot.iris.gl.uniform; + +import net.minecraft.util.Vec3; +import org.joml.Matrix4f; +import org.joml.Vector2f; +import org.joml.Vector2i; +import org.joml.Vector3d; +import org.joml.Vector3f; +import org.joml.Vector4f; + +import java.util.OptionalInt; +import java.util.function.BooleanSupplier; +import java.util.function.DoubleSupplier; +import java.util.function.IntSupplier; +import java.util.function.Supplier; + +public interface LocationalUniformHolder extends UniformHolder { + LocationalUniformHolder addUniform(UniformUpdateFrequency updateFrequency, Uniform uniform); + + OptionalInt location(String name, UniformType type); + + @Override + default LocationalUniformHolder uniform1f(UniformUpdateFrequency updateFrequency, String name, FloatSupplier value) { + location(name, UniformType.FLOAT).ifPresent(id -> addUniform(updateFrequency, new FloatUniform(id, value))); + + return this; + } + + @Override + default LocationalUniformHolder uniform1f(UniformUpdateFrequency updateFrequency, String name, IntSupplier value) { + location(name, UniformType.FLOAT).ifPresent(id -> addUniform(updateFrequency, new FloatUniform(id, () -> (float) value.getAsInt()))); + + return this; + } + + @Override + default LocationalUniformHolder uniform1f(UniformUpdateFrequency updateFrequency, String name, DoubleSupplier value) { + location(name, UniformType.FLOAT).ifPresent(id -> addUniform(updateFrequency, new FloatUniform(id, () -> (float) value.getAsDouble()))); + + return this; + } + + @Override + default LocationalUniformHolder uniform1i(UniformUpdateFrequency updateFrequency, String name, IntSupplier value) { + location(name, UniformType.INT).ifPresent(id -> addUniform(updateFrequency, new IntUniform(id, value))); + + return this; + } + + @Override + default LocationalUniformHolder uniform1b(UniformUpdateFrequency updateFrequency, String name, BooleanSupplier value) { + location(name, UniformType.INT).ifPresent(id -> addUniform(updateFrequency, new BooleanUniform(id, value))); + + return this; + } + + @Override + default LocationalUniformHolder uniform2f(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + location(name, UniformType.VEC2).ifPresent(id -> addUniform(updateFrequency, new Vector2Uniform(id, value))); + + return this; + } + + @Override + default LocationalUniformHolder uniform2i(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + location(name, UniformType.VEC2I).ifPresent(id -> addUniform(updateFrequency, new Vector2IntegerJomlUniform(id, value))); + + return this; + } + + @Override + default LocationalUniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + location(name, UniformType.VEC3).ifPresent(id -> addUniform(updateFrequency, new Vector3Uniform(id, value))); + + return this; + } + + @Override + default LocationalUniformHolder uniformVanilla3f(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + location(name, UniformType.VEC3).ifPresent(id -> addUniform(updateFrequency, new VanillaVector3Uniform(id, value))); + + return this; + } + + @Override + default LocationalUniformHolder uniformTruncated3f(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + location(name, UniformType.VEC3).ifPresent(id -> addUniform(updateFrequency, Vector3Uniform.truncated(id, value))); + + return this; + } + + @Override + default LocationalUniformHolder uniform3d(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + location(name, UniformType.VEC3).ifPresent(id -> addUniform(updateFrequency, Vector3Uniform.converted(id, value))); + + return this; + } + + @Override + default LocationalUniformHolder uniform4f(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + location(name, UniformType.VEC4).ifPresent(id -> addUniform(updateFrequency, new Vector4Uniform(id, value))); + + return this; + } + + @Override + default LocationalUniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + location(name, UniformType.MAT4).ifPresent(id -> addUniform(updateFrequency, new MatrixUniform(id, value))); + + return this; + } + + @Override + default LocationalUniformHolder uniformMatrixFromArray(UniformUpdateFrequency updateFrequency, String name, Supplier value) { + location(name, UniformType.MAT4).ifPresent(id -> addUniform(updateFrequency, new MatrixFromFloatArrayUniform(id, value))); + + return this; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/MatrixFromFloatArrayUniform.java b/src/main/java/net/coderbot/iris/gl/uniform/MatrixFromFloatArrayUniform.java new file mode 100644 index 000000000..b4a895270 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/MatrixFromFloatArrayUniform.java @@ -0,0 +1,35 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.IrisRenderSystem; +import org.lwjgl.BufferUtils; + +import java.nio.FloatBuffer; +import java.util.Arrays; +import java.util.function.Supplier; + +public class MatrixFromFloatArrayUniform extends Uniform { + private final FloatBuffer buffer = BufferUtils.createFloatBuffer(16); + private float[] cachedValue; + private final Supplier value; + + MatrixFromFloatArrayUniform(int location, Supplier value) { + super(location); + + this.cachedValue = null; + this.value = value; + } + + @Override + public void update() { + float[] newValue = value.get(); + + if (!Arrays.equals(newValue, cachedValue)) { + cachedValue = Arrays.copyOf(newValue, 16); + + buffer.put(cachedValue); + buffer.rewind(); + + IrisRenderSystem.uniformMatrix4fv(location, false, buffer); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java b/src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java new file mode 100644 index 000000000..6c3928ebd --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java @@ -0,0 +1,35 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.IrisRenderSystem; +import org.joml.Matrix4f; +import org.lwjgl.BufferUtils; + +import java.nio.FloatBuffer; +import java.util.function.Supplier; + +public class MatrixUniform extends Uniform { + private final FloatBuffer buffer = BufferUtils.createFloatBuffer(16); + private Matrix4f cachedValue; + private final Supplier value; + + MatrixUniform(int location, Supplier value) { + super(location); + + this.cachedValue = null; + this.value = value; + } + + @Override + public void update() { + final Matrix4f newValue = value.get(); + + if (!newValue.equals(cachedValue)) { + cachedValue = new Matrix4f(newValue); + + cachedValue.get(buffer); + buffer.rewind(); + + IrisRenderSystem.uniformMatrix4fv(location, false, buffer); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/Uniform.java b/src/main/java/net/coderbot/iris/gl/uniform/Uniform.java new file mode 100644 index 000000000..520b27890 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/Uniform.java @@ -0,0 +1,27 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.state.ValueUpdateNotifier; + +public abstract class Uniform { + protected final int location; + protected final ValueUpdateNotifier notifier; + + Uniform(int location) { + this(location, null); + } + + Uniform(int location, ValueUpdateNotifier notifier) { + this.location = location; + this.notifier = notifier; + } + + public abstract void update(); + + public final int getLocation() { + return location; + } + + public final ValueUpdateNotifier getNotifier() { + return notifier; + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/UniformHolder.java b/src/main/java/net/coderbot/iris/gl/uniform/UniformHolder.java new file mode 100644 index 000000000..05f339a09 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/UniformHolder.java @@ -0,0 +1,46 @@ +package net.coderbot.iris.gl.uniform; + +import net.minecraft.util.Vec3; +import org.joml.Matrix4f; +import org.joml.Vector2f; +import org.joml.Vector2i; +import org.joml.Vector3d; +import org.joml.Vector3f; +import org.joml.Vector4f; + +import java.util.function.BooleanSupplier; +import java.util.function.DoubleSupplier; +import java.util.function.IntSupplier; +import java.util.function.Supplier; + +public interface UniformHolder { + UniformHolder uniform1f(UniformUpdateFrequency updateFrequency, String name, FloatSupplier value); + + UniformHolder uniform1f(UniformUpdateFrequency updateFrequency, String name, IntSupplier value); + + UniformHolder uniform1f(UniformUpdateFrequency updateFrequency, String name, DoubleSupplier value); + + UniformHolder uniform1i(UniformUpdateFrequency updateFrequency, String name, IntSupplier value); + + UniformHolder uniform1b(UniformUpdateFrequency updateFrequency, String name, BooleanSupplier value); + + UniformHolder uniform2f(UniformUpdateFrequency updateFrequency, String name, Supplier value); + + UniformHolder uniform2i(UniformUpdateFrequency updateFrequency, String name, Supplier value); + + UniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier value); + + UniformHolder uniformVanilla3f(UniformUpdateFrequency updateFrequency, String name, Supplier value); + + UniformHolder uniformTruncated3f(UniformUpdateFrequency updateFrequency, String name, Supplier value); + + UniformHolder uniform3d(UniformUpdateFrequency updateFrequency, String name, Supplier value); + + UniformHolder uniform4f(UniformUpdateFrequency updateFrequency, String name, Supplier value); + + UniformHolder uniformMatrix(UniformUpdateFrequency updateFrequency, String name, Supplier value); + + UniformHolder uniformMatrixFromArray(UniformUpdateFrequency updateFrequency, String name, Supplier value); + + UniformHolder externallyManagedUniform(String name, UniformType type); +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/UniformType.java b/src/main/java/net/coderbot/iris/gl/uniform/UniformType.java new file mode 100644 index 000000000..0bc4f20fd --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/UniformType.java @@ -0,0 +1,12 @@ +package net.coderbot.iris.gl.uniform; + +public enum UniformType { + INT, + FLOAT, + MAT4, + VEC2, + VEC2I, + VEC3, + VEC4, + VEC4I +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/UniformUpdateFrequency.java b/src/main/java/net/coderbot/iris/gl/uniform/UniformUpdateFrequency.java new file mode 100644 index 000000000..e6b76acce --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/UniformUpdateFrequency.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.gl.uniform; + +public enum UniformUpdateFrequency { + ONCE, + PER_TICK, + PER_FRAME +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/VanillaVector3Uniform.java b/src/main/java/net/coderbot/iris/gl/uniform/VanillaVector3Uniform.java new file mode 100644 index 000000000..172e6bdda --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/VanillaVector3Uniform.java @@ -0,0 +1,30 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.minecraft.util.Vec3; + +import java.util.function.Supplier; + +public class VanillaVector3Uniform extends Uniform { + private final Vec3 cachedValue; + private final Supplier value; + + VanillaVector3Uniform(int location, Supplier value) { + super(location); + + this.cachedValue = Vec3.createVectorHelper(0, 0, 0); + this.value = value; + } + + @Override + public void update() { + Vec3 newValue = value.get(); + + if (!newValue.equals(cachedValue)) { + cachedValue.xCoord = newValue.xCoord; + cachedValue.yCoord = newValue.yCoord; + cachedValue.zCoord = newValue.zCoord; + IrisRenderSystem.uniform3f(location, (float)cachedValue.xCoord, (float)cachedValue.yCoord, (float)cachedValue.zCoord); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/Vector2IntegerJomlUniform.java b/src/main/java/net/coderbot/iris/gl/uniform/Vector2IntegerJomlUniform.java new file mode 100644 index 000000000..785ef87d4 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/Vector2IntegerJomlUniform.java @@ -0,0 +1,41 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.state.ValueUpdateNotifier; +import org.joml.Vector2i; + +import java.util.function.Supplier; + +public class Vector2IntegerJomlUniform extends Uniform { + private Vector2i cachedValue; + private final Supplier value; + + Vector2IntegerJomlUniform(int location, Supplier value) { + this(location, value, null); + } + + Vector2IntegerJomlUniform(int location, Supplier value, ValueUpdateNotifier notifier) { + super(location, notifier); + + this.cachedValue = null; + this.value = value; + } + + @Override + public void update() { + updateValue(); + + if (notifier != null) { + notifier.setListener(this::updateValue); + } + } + + private void updateValue() { + Vector2i newValue = value.get(); + + if (cachedValue == null || !newValue.equals(cachedValue)) { + cachedValue = newValue; + IrisRenderSystem.uniform2i(this.location, newValue.x, newValue.y); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/Vector2Uniform.java b/src/main/java/net/coderbot/iris/gl/uniform/Vector2Uniform.java new file mode 100644 index 000000000..379b33512 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/Vector2Uniform.java @@ -0,0 +1,29 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.IrisRenderSystem; +import org.joml.Vector2f; + +import java.util.function.Supplier; + +public class Vector2Uniform extends Uniform { + private Vector2f cachedValue; + private final Supplier value; + + Vector2Uniform(int location, Supplier value) { + super(location); + + this.cachedValue = null; + this.value = value; + + } + + @Override + public void update() { + Vector2f newValue = value.get(); + + if (cachedValue == null || !newValue.equals(cachedValue)) { + cachedValue = newValue; + IrisRenderSystem.uniform2f(this.location, newValue.x, newValue.y); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/Vector3Uniform.java b/src/main/java/net/coderbot/iris/gl/uniform/Vector3Uniform.java new file mode 100644 index 000000000..3475b0785 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/Vector3Uniform.java @@ -0,0 +1,54 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.IrisRenderSystem; +import org.joml.Vector3d; +import org.joml.Vector3f; +import org.joml.Vector4f; + +import java.util.function.Supplier; + +public class Vector3Uniform extends Uniform { + private final Vector3f cachedValue; + private final Supplier value; + + Vector3Uniform(int location, Supplier value) { + super(location); + + this.cachedValue = new Vector3f(); + this.value = value; + } + + static Vector3Uniform converted(int location, Supplier value) { + Vector3f held = new Vector3f(); + + return new Vector3Uniform(location, () -> { + Vector3d updated = value.get(); + + held.set((float) updated.x, (float) updated.y, (float) updated.z); + + return held; + }); + } + + static Vector3Uniform truncated(int location, Supplier value) { + Vector3f held = new Vector3f(); + + return new Vector3Uniform(location, () -> { + Vector4f updated = value.get(); + + held.set(updated.x(), updated.y(), updated.z()); + + return held; + }); + } + + @Override + public void update() { + Vector3f newValue = value.get(); + + if (!newValue.equals(cachedValue)) { + cachedValue.set(newValue.x(), newValue.y(), newValue.z()); + IrisRenderSystem.uniform3f(location, cachedValue.x(), cachedValue.y(), cachedValue.z()); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/Vector4IntegerJomlUniform.java b/src/main/java/net/coderbot/iris/gl/uniform/Vector4IntegerJomlUniform.java new file mode 100644 index 000000000..b373fa766 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/Vector4IntegerJomlUniform.java @@ -0,0 +1,41 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.state.ValueUpdateNotifier; +import org.joml.Vector4i; + +import java.util.function.Supplier; + +public class Vector4IntegerJomlUniform extends Uniform { + private Vector4i cachedValue; + private final Supplier value; + + Vector4IntegerJomlUniform(int location, Supplier value) { + this(location, value, null); + } + + Vector4IntegerJomlUniform(int location, Supplier value, ValueUpdateNotifier notifier) { + super(location, notifier); + + this.cachedValue = null; + this.value = value; + } + + @Override + public void update() { + updateValue(); + + if (notifier != null) { + notifier.setListener(this::updateValue); + } + } + + private void updateValue() { + Vector4i newValue = value.get(); + + if (cachedValue == null || !newValue.equals(cachedValue)) { + cachedValue = newValue; + IrisRenderSystem.uniform4i(this.location, newValue.x, newValue.y, newValue.z, newValue.w); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gl/uniform/Vector4Uniform.java b/src/main/java/net/coderbot/iris/gl/uniform/Vector4Uniform.java new file mode 100644 index 000000000..41a9d61f3 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/uniform/Vector4Uniform.java @@ -0,0 +1,41 @@ +package net.coderbot.iris.gl.uniform; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.state.ValueUpdateNotifier; +import org.joml.Vector4f; + +import java.util.function.Supplier; + +public class Vector4Uniform extends Uniform { + private final Vector4f cachedValue; + private final Supplier value; + + Vector4Uniform(int location, Supplier value) { + this(location, value, null); + } + + Vector4Uniform(int location, Supplier value, ValueUpdateNotifier notifier) { + super(location, notifier); + + this.cachedValue = new Vector4f(); + this.value = value; + } + + @Override + public void update() { + updateValue(); + + if (notifier != null) { + notifier.setListener(this::updateValue); + } + } + + private void updateValue() { + Vector4f newValue = value.get(); + + if (!newValue.equals(cachedValue)) { + cachedValue.set(newValue.x(), newValue.y(), newValue.z(), newValue.w()); + IrisRenderSystem.uniform4f(location, cachedValue.x(), cachedValue.y(), cachedValue.z(), cachedValue.w()); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gui/FeatureMissingErrorScreen.java b/src/main/java/net/coderbot/iris/gui/FeatureMissingErrorScreen.java new file mode 100644 index 000000000..be4c7ef15 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/FeatureMissingErrorScreen.java @@ -0,0 +1,31 @@ +package net.coderbot.iris.gui; + + +import net.minecraft.client.gui.GuiScreen; + +public class FeatureMissingErrorScreen extends GuiScreen { + private final GuiScreen parent; + private MultiLineLabel message; + private final FormattedText messageTemp; + + public FeatureMissingErrorScreen(GuiScreen parent, Component title, Component message) { + super(title); + this.parent = parent; + this.messageTemp = message; + } + + @Override + protected void init() { + super.init(); + this.message = MultiLineLabel.create(this.font, messageTemp, this.width - 50); + this.addButton(new Button(this.width / 2 - 100, 140, 200, 20, CommonComponents.GUI_BACK, arg -> this.minecraft.setScreen(parent))); + } + + @Override + public void render(PoseStack poseStack, int mouseX, int mouseY, float delta) { + this.renderBackground(poseStack); + ErrorScreen.drawCenteredString(poseStack, this.font, this.title, this.width / 2, 90, 0xFFFFFF); + message.renderCentered(poseStack, this.width / 2, 110, 9, 0xFFFFFF); + super.render(poseStack, mouseX, mouseY, delta); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/FileDialogUtil.java b/src/main/java/net/coderbot/iris/gui/FileDialogUtil.java new file mode 100644 index 000000000..5249346ce --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/FileDialogUtil.java @@ -0,0 +1,63 @@ +package net.coderbot.iris.gui; + +import org.jetbrains.annotations.Nullable; +import org.lwjgl.PointerBuffer; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Class used to make interfacing with {@link TinyFileDialogs} easier and asynchronous. + */ +public final class FileDialogUtil { + private static final ExecutorService FILE_DIALOG_EXECUTOR = Executors.newSingleThreadExecutor(); + + private FileDialogUtil() {} + + /** + * Opens an asynchronous file select dialog window. + * + * @param dialog Whether to open a "save" dialog or an "open" dialog + * @param title The title of the dialog window + * @param origin The path that the window should start at + * @param filterLabel A label used to describe what file extensions are allowed and their purpose + * @param filters The file extension filters used by the dialog, each formatted as {@code "*.extension"} + * @return a {@link CompletableFuture} which is completed once a file is selected or the dialog is cancelled. + */ + public static CompletableFuture> fileSelectDialog(DialogType dialog, String title, @Nullable Path origin, @Nullable String filterLabel, String ... filters) { + CompletableFuture> future = new CompletableFuture<>(); + + FILE_DIALOG_EXECUTOR.submit(() -> { + String result = null; + + try (MemoryStack stack = MemoryStack.stackPush()) { + PointerBuffer filterBuffer = stack.mallocPointer(filters.length); + + for (String filter : filters) { + filterBuffer.put(stack.UTF8(filter)); + } + filterBuffer.flip(); + + String path = origin != null ? origin.toAbsolutePath().toString() : null; + + if (dialog == DialogType.SAVE) { + result = TinyFileDialogs.tinyfd_saveFileDialog(title, path, filterBuffer, filterLabel); + } else if (dialog == DialogType.OPEN) { + result = TinyFileDialogs.tinyfd_openFileDialog(title, path, filterBuffer, filterLabel, false); + } + } + + future.complete(Optional.ofNullable(result).map(Paths::get)); + }); + + return future; + } + + public enum DialogType { + SAVE, OPEN + } +} diff --git a/src/main/java/net/coderbot/iris/gui/GuiUtil.java b/src/main/java/net/coderbot/iris/gui/GuiUtil.java new file mode 100644 index 000000000..32bf36a19 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/GuiUtil.java @@ -0,0 +1,207 @@ +package net.coderbot.iris.gui; + + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.ResourceLocation; + +/** + * Class serving as abstraction and + * centralization for common GUI + * rendering/other code calls. + * + * Helps allow for easier portability + * to Minecraft 1.17 by abstracting + * some code that will be changed. + */ +public final class GuiUtil { + public static final ResourceLocation IRIS_WIDGETS_TEX = new ResourceLocation("iris", "textures/gui/widgets.png"); + private static final Component ELLIPSIS = new TextComponent("..."); + + private GuiUtil() {} + + private static Minecraft client() { + return Minecraft.getMinecraft(); + } + + /** + * Binds Iris's widgets texture to be + * used for succeeding draw calls. + */ + public static void bindIrisWidgetsTexture() { + client().getTextureManager().bind(IRIS_WIDGETS_TEX); + } + + /** + * Draws a button. Button textures must be mapped with the + * same coordinates as those on the vanilla widgets texture. + * + * @param x X position of the left of the button + * @param y Y position of the top of the button + * @param width Width of the button, maximum 398 + * @param height Height of the button, maximum 20 + * @param hovered Whether the button is being hovered over with the mouse + * @param disabled Whether the button should use the "disabled" texture + */ + public static void drawButton(PoseStack poseStack, int x, int y, int width, int height, boolean hovered, boolean disabled) { + // Create variables for half of the width and height. + // Will not be exact when width and height are odd, but + // that case is handled within the draw calls. + int halfWidth = width / 2; + int halfHeight = height / 2; + + // V offset for which button texture to use + int vOffset = disabled ? 46 : hovered ? 86 : 66; + + // Sets RenderSystem to use solid white as the tint color for blend mode, and enables blend mode + RenderSystem.blendColor(1.0f, 1.0f, 1.0f, 1.0f); + RenderSystem.enableBlend(); + + // Sets RenderSystem to be able to use textures when drawing + RenderSystem.enableTexture(); + + // Top left section + GuiComponent.blit(poseStack, x, y, 0, vOffset, halfWidth, halfHeight, 256, 256); + // Top right section + GuiComponent.blit(poseStack, x + halfWidth, y, 200 - (width - halfWidth), vOffset, width - halfWidth, halfHeight, 256, 256); + // Bottom left section + GuiComponent.blit(poseStack, x, y + halfHeight, 0, vOffset + (20 - (height - halfHeight)), halfWidth, height - halfHeight, 256, 256); + // Bottom right section + GuiComponent.blit(poseStack, x + halfWidth, y + halfHeight, 200 - (width - halfWidth), vOffset + (20 - (height - halfHeight)), width - halfWidth, height - halfHeight, 256, 256); + } + + /** + * Draws a translucent black panel + * with a light border. + * + * @param x The x position of the panel + * @param y The y position of the panel + * @param width The width of the panel + * @param height The height of the panel + */ + public static void drawPanel(PoseStack poseStack, int x, int y, int width, int height) { + int borderColor = 0xDEDEDEDE; + int innerColor = 0xDE000000; + + // Top border section + GuiComponent.fill(poseStack, x, y, x + width, y + 1, borderColor); + // Bottom border section + GuiComponent.fill(poseStack, x, (y + height) - 1, x + width, y + height, borderColor); + // Left border section + GuiComponent.fill(poseStack, x, y + 1, x + 1, (y + height) - 1, borderColor); + // Right border section + GuiComponent.fill(poseStack, (x + width) - 1, y + 1, x + width, (y + height) - 1, borderColor); + // Inner section + GuiComponent.fill(poseStack, x + 1, y + 1, (x + width) - 1, (y + height) - 1, innerColor); + } + + /** + * Draws a text with a panel behind it. + * + * @param text The text component to draw + * @param x The x position of the panel + * @param y The y position of the panel + */ + public static void drawTextPanel(Font font, PoseStack poseStack, Component text, int x, int y) { + drawPanel(poseStack, x, y, font.width(text) + 8, 16); + font.drawShadow(poseStack, text, x + 4, y + 4, 0xFFFFFF); + } + + /** + * Shorten a text to a specific length, adding an ellipsis (...) + * to the end if shortened. + * + * Text may lose formatting. + * + * @param font Font to use for determining the width of text + * @param text Text to shorten + * @param width Width to shorten text to + * @return a shortened text + */ + public static MutableComponent shortenText(Font font, MutableComponent text, int width) { + if (font.width(text) > width) { + return new TextComponent(font.plainSubstrByWidth(text.getString(), width - font.width(ELLIPSIS))).append(ELLIPSIS).setStyle(text.getStyle()); + } + return text; + } + + /** + * Creates a new translated text, if a translation + * is present. If not, will return the default text + * component passed. + * + * @param defaultText Default text to use if no translation is found + * @param translationDesc Translation key to try and use + * @param format Formatting arguments for the translated text, if created + * @return the translated text if found, otherwise the default provided + */ + public static MutableComponent translateOrDefault(MutableComponent defaultText, String translationDesc, Object ... format) { + if (I18n.exists(translationDesc)) { + return I18n.format(translationDesc, format); + } + return defaultText; + } + + /** + * Plays the {@code UI_BUTTON_CLICK} sound event as a + * master sound effect. + * + * Used in non-{@code ButtonWidget} UI elements upon click + * or other action. + */ + public static void playButtonClickSound() { + client().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1)); + } + + /** + * A class representing a section of a + * texture, to be easily drawn in GUIs. + */ + public static class Icon { + public static final Icon SEARCH = new Icon(0, 0, 7, 8); + public static final Icon CLOSE = new Icon(7, 0, 5, 6); + public static final Icon REFRESH = new Icon(12, 0, 10, 10); + public static final Icon EXPORT = new Icon(22, 0, 7, 8); + public static final Icon EXPORT_COLORED = new Icon(29, 0, 7, 8); + public static final Icon IMPORT = new Icon(22, 8, 7, 8); + public static final Icon IMPORT_COLORED = new Icon(29, 8, 7, 8); + + private final int u; + private final int v; + private final int width; + private final int height; + + public Icon(int u, int v, int width, int height) { + this.u = u; + this.v = v; + this.width = width; + this.height = height; + } + + /** + * Draws this icon to the screen at the specified coordinates. + * + * @param x The x position to draw the icon at (left) + * @param y The y position to draw the icon at (top) + */ + public void draw(PoseStack poseStack, int x, int y) { + // Sets RenderSystem to use solid white as the tint color for blend mode, and enables blend mode + RenderSystem.blendColor(1.0f, 1.0f, 1.0f, 1.0f); + RenderSystem.enableBlend(); + + // Sets RenderSystem to be able to use textures when drawing + RenderSystem.enableTexture(); + + // Draw the texture to the screen + GuiComponent.blit(poseStack, x, y, u, v, width, height, 256, 256); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + } +} diff --git a/src/main/java/net/coderbot/iris/gui/NavigationController.java b/src/main/java/net/coderbot/iris/gui/NavigationController.java new file mode 100644 index 000000000..0c7aa8481 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/NavigationController.java @@ -0,0 +1,66 @@ +package net.coderbot.iris.gui; + +import net.coderbot.iris.gui.element.ShaderPackOptionList; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; + +import java.util.ArrayDeque; +import java.util.Deque; + +public class NavigationController { + private final OptionMenuContainer container; + private ShaderPackOptionList optionList; + + private String currentScreen = null; + private final Deque history = new ArrayDeque<>(); + + public NavigationController(OptionMenuContainer container) { + this.container = container; + } + + public void back() { + if (history.size() > 0) { + history.removeLast(); + + if (history.size() > 0) { + currentScreen = history.getLast(); + } else { + currentScreen = null; + } + } else { + currentScreen = null; + } + + this.rebuild(); + } + + public void open(String screen) { + currentScreen = screen; + history.addLast(screen); + + this.rebuild(); + } + + public void rebuild() { + if (optionList != null) { + optionList.rebuild(); + } + } + + public void refresh() { + if (optionList != null) { + optionList.refresh(); + } + } + + public boolean hasHistory() { + return this.history.size() > 0; + } + + public void setActiveOptionList(ShaderPackOptionList optionList) { + this.optionList = optionList; + } + + public String getCurrentScreen() { + return currentScreen; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java b/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java new file mode 100644 index 000000000..25c8ceaf4 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java @@ -0,0 +1,225 @@ +package net.coderbot.iris.gui.element; + +import net.coderbot.iris.gui.GuiUtil; + +import net.minecraft.client.Minecraft; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +/** + * Intended to make very simple rows of buttons easier to make + */ +public class IrisElementRow { + private final Map elements = new HashMap<>(); + private final List orderedElements = new ArrayList<>(); + private final int spacing; + private int x; + private int y; + private int width; + private int height; + + public IrisElementRow(int spacing) { + this.spacing = spacing; + } + + public IrisElementRow() { + this(1); + } + + /** + * Adds an element to the right of this row. + * + * @param element The element to add + * @param width The width of the element in this row + * @return {@code this}, to be used for chaining statements + */ + public IrisElementRow add(Element element, int width) { + if (!this.orderedElements.contains(element)) { + this.orderedElements.add(element); + } + this.elements.put(element, width); + + this.width += width + this.spacing; + + return this; + } + + /** + * Modifies the width of an element. + * + * @param element The element whose width to modify + * @param width The width to be assigned to the specified element + */ + public void setWidth(Element element, int width) { + if (!this.elements.containsKey(element)) { + return; + } + + this.width -= this.elements.get(element) + 2; + + add(element, width); + } + + /** + * Renders the row, with the anchor point being the top left. + */ + public void render(PoseStack poseStack, int x, int y, int height, int mouseX, int mouseY, float tickDelta, boolean rowHovered) { + this.x = x; + this.y = y; + this.height = height; + + int currentX = x; + + for (Element element : this.orderedElements) { + int currentWidth = this.elements.get(element); + + element.render(poseStack, currentX, y, currentWidth, height, mouseX, mouseY, tickDelta, + rowHovered && sectionHovered(currentX, currentWidth, mouseX, mouseY)); + + currentX += currentWidth + this.spacing; + } + } + + /** + * Renders the row, with the anchor point being the top right. + */ + public void renderRightAligned(PoseStack poseStack, int x, int y, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + render(poseStack, x - this.width, y, height, mouseX, mouseY, tickDelta, hovered); + } + + private boolean sectionHovered(int sectionX, int sectionWidth, double mx, double my) { + return mx > sectionX && mx < sectionX + sectionWidth && + my > this.y && my < this.y + this.height; + } + + private Optional getHovered(double mx, double my) { + int currentX = this.x; + + for (Element element : this.orderedElements) { + int currentWidth = this.elements.get(element); + + if (sectionHovered(currentX, currentWidth, mx, my)) { + return Optional.of(element); + } + + currentX += currentWidth + this.spacing; + } + + return Optional.empty(); + } + + public boolean mouseClicked(double mx, double my, int button) { + return getHovered(mx, my).map(element -> element.mouseClicked(mx, my, button)).orElse(false); + } + + public boolean mouseReleased(double mx, double my, int button) { + return getHovered(mx, my).map(element -> element.mouseReleased(mx, my, button)).orElse(false); + } + + public static abstract class Element { + public boolean disabled = false; + private boolean hovered = false; + + public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + GuiUtil.bindIrisWidgetsTexture(); + GuiUtil.drawButton(poseStack, x, y, width, height, hovered, this.disabled); + + this.hovered = hovered; + this.renderLabel(poseStack, x, y, width, height, mouseX, mouseY, tickDelta, hovered); + } + + public abstract void renderLabel(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered); + + public boolean mouseClicked(double mx, double my, int button) { + return false; + } + + public boolean mouseReleased(double mx, double my, int button) { + return false; + } + + public boolean isHovered() { + return hovered; + } + } + + public static abstract class ButtonElement> extends Element { + private final Function onClick; + + protected ButtonElement(Function onClick) { + this.onClick = onClick; + } + + @Override + public boolean mouseClicked(double mx, double my, int button) { + if (this.disabled) { + return false; + } + + if (button == GLFW.GLFW_MOUSE_BUTTON_1) { + return this.onClick.apply((T) this); + } + + return super.mouseClicked(mx, my, button); + } + } + + /** + * A clickable button element that uses a {@link GuiUtil.Icon} as its label. + */ + public static class IconButtonElement extends ButtonElement { + public GuiUtil.Icon icon; + public GuiUtil.Icon hoveredIcon; + + public IconButtonElement(GuiUtil.Icon icon, GuiUtil.Icon hoveredIcon, Function onClick) { + super(onClick); + this.icon = icon; + this.hoveredIcon = hoveredIcon; + } + + public IconButtonElement(GuiUtil.Icon icon, Function onClick) { + this(icon, icon, onClick); + } + + @Override + public void renderLabel(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + int iconX = x + (int)((width - this.icon.getWidth()) * 0.5); + int iconY = y + (int)((height - this.icon.getHeight()) * 0.5); + + GuiUtil.bindIrisWidgetsTexture(); + if (!this.disabled && hovered) { + this.hoveredIcon.draw(poseStack, iconX, iconY); + } else { + this.icon.draw(poseStack, iconX, iconY); + } + } + } + + /** + * A clickable button element that uses a text component as its label. + */ + public static class TextButtonElement extends ButtonElement { + protected final Font font; + public Component text; + + public TextButtonElement(Component text, Function onClick) { + super(onClick); + + this.font = Minecraft.getMinecraft().font; + this.text = text; + } + + @Override + public void renderLabel(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + int textX = x + (int)((width - this.font.width(this.text)) * 0.5); + int textY = y + (int)((height - 8) * 0.5); + + this.font.drawShadow(poseStack, this.text, textX, textY, 0xFFFFFF); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisObjectSelectionList.java b/src/main/java/net/coderbot/iris/gui/element/IrisObjectSelectionList.java new file mode 100644 index 000000000..100478dc6 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/IrisObjectSelectionList.java @@ -0,0 +1,23 @@ +package net.coderbot.iris.gui.element; + +import net.minecraft.client.Minecraft; + +public class IrisObjectSelectionList> extends ObjectSelectionList { + public IrisObjectSelectionList(Minecraft client, int width, int height, int top, int bottom, int left, int right, int itemHeight) { + super(client, width, height, top, bottom, itemHeight); + + this.x0 = left; + this.x1 = right; + } + + @Override + protected int getScrollbarPosition() { + // Position the scrollbar at the rightmost edge of the screen. + // By default, the scrollbar is positioned moderately offset from the center. + return width - 6; + } + + public void select(int entry) { + setSelected(this.getEntry(entry)); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java new file mode 100644 index 000000000..92fe7dcdf --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java @@ -0,0 +1,365 @@ +package net.coderbot.iris.gui.element; + +import com.mojang.realmsclient.gui.ChatFormatting; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.FileDialogUtil; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.element.widget.AbstractElementWidget; +import net.coderbot.iris.gui.element.widget.OptionMenuConstructor; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.ShaderPack; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +public class ShaderPackOptionList extends IrisObjectSelectionList { + private final List> elementWidgets = new ArrayList<>(); + private final ShaderPackScreen screen; + private final NavigationController navigation; + private OptionMenuContainer container; + + public ShaderPackOptionList(ShaderPackScreen screen, NavigationController navigation, ShaderPack pack, Minecraft client, int width, int height, int top, int bottom, int left, int right) { + super(client, width, height, top, bottom, left, right, 24); + this.navigation = navigation; + this.screen = screen; + + applyShaderPack(pack); + } + + public void applyShaderPack(ShaderPack pack) { + this.container = pack.getMenuContainer(); + } + + public void rebuild() { + this.clearEntries(); + this.setScrollAmount(0); + OptionMenuConstructor.constructAndApplyToScreen(this.container, this.screen, this, navigation); + } + + public void refresh() { + this.elementWidgets.forEach(widget -> widget.init(this.screen, this.navigation)); + } + + @Override + public int getRowWidth() { + return Math.min(400, width - 12); + } + + public void addHeader(Component text, boolean backButton) { + this.addEntry(new HeaderEntry(this.screen, this.navigation, text, backButton)); + } + + public void addWidgets(int columns, List> elements) { + this.elementWidgets.addAll(elements); + + List> row = new ArrayList<>(); + for (AbstractElementWidget element : elements) { + row.add(element); + + if (row.size() >= columns) { + this.addEntry(new ElementRowEntry(screen, this.navigation, row)); + row = new ArrayList<>(); // Clearing the list would affect the row entry created above + } + } + + if (row.size() > 0) { + while (row.size() < columns) { + row.add(AbstractElementWidget.EMPTY); + } + + this.addEntry(new ElementRowEntry(screen, this.navigation, row)); + } + } + + public NavigationController getNavigation() { + return navigation; + } + + public abstract static class BaseEntry extends ObjectSelectionList.Entry { + protected final NavigationController navigation; + + protected BaseEntry(NavigationController navigation) { + this.navigation = navigation; + } + } + + public static class HeaderEntry extends BaseEntry { + public static final Component BACK_BUTTON_TEXT = new TextComponent("< ").append(I18n.format("options.iris.back").withStyle(ChatFormatting.ITALIC)); + public static final MutableComponent RESET_BUTTON_TEXT_INACTIVE = I18n.format("options.iris.reset").withStyle(ChatFormatting.GRAY); + public static final MutableComponent RESET_BUTTON_TEXT_ACTIVE = I18n.format("options.iris.reset").withStyle(ChatFormatting.YELLOW); + + public static final MutableComponent RESET_HOLD_SHIFT_TOOLTIP = I18n.format("options.iris.reset.tooltip.holdShift").withStyle(ChatFormatting.GOLD); + public static final MutableComponent RESET_TOOLTIP = I18n.format("options.iris.reset.tooltip").withStyle(ChatFormatting.RED); + public static final MutableComponent IMPORT_TOOLTIP = I18n.format("options.iris.importSettings.tooltip") + .withStyle(style -> style.withColor(TextColor.fromRgb(0x4da6ff))); + public static final MutableComponent EXPORT_TOOLTIP = I18n.format("options.iris.exportSettings.tooltip") + .withStyle(style -> style.withColor(TextColor.fromRgb(0xfc7d3d))); + + private static final int MIN_SIDE_BUTTON_WIDTH = 42; + private static final int BUTTON_HEIGHT = 16; + + private final ShaderPackScreen screen; + private final @Nullable IrisElementRow backButton; + private final IrisElementRow utilityButtons = new IrisElementRow(); + private final IrisElementRow.TextButtonElement resetButton; + private final IrisElementRow.IconButtonElement importButton; + private final IrisElementRow.IconButtonElement exportButton; + private final Component text; + + public HeaderEntry(ShaderPackScreen screen, NavigationController navigation, Component text, boolean hasBackButton) { + super(navigation); + + if (hasBackButton) { + this.backButton = new IrisElementRow().add( + new IrisElementRow.TextButtonElement(BACK_BUTTON_TEXT, this::backButtonClicked), + Math.max(MIN_SIDE_BUTTON_WIDTH, Minecraft.getMinecraft().font.width(BACK_BUTTON_TEXT) + 8) + ); + } else { + this.backButton = null; + } + + this.resetButton = new IrisElementRow.TextButtonElement( + RESET_BUTTON_TEXT_INACTIVE, this::resetButtonClicked); + this.importButton = new IrisElementRow.IconButtonElement( + GuiUtil.Icon.IMPORT, GuiUtil.Icon.IMPORT_COLORED, this::importSettingsButtonClicked); + this.exportButton = new IrisElementRow.IconButtonElement( + GuiUtil.Icon.EXPORT, GuiUtil.Icon.EXPORT_COLORED, this::exportSettingsButtonClicked); + + this.utilityButtons + .add(this.importButton, 15) + .add(this.exportButton, 15) + .add(this.resetButton, Math.max(MIN_SIDE_BUTTON_WIDTH, Minecraft.getMinecraft().font.width(RESET_BUTTON_TEXT_INACTIVE) + 8)); + + this.screen = screen; + this.text = text; + } + + @Override + public void render(PoseStack poseStack, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + // Draw dividing line + fill(poseStack, x - 3, (y + entryHeight) - 2, x + entryWidth, (y + entryHeight) - 1, 0x66BEBEBE); + + Font font = Minecraft.getMinecraft().font; + + // Draw header text + drawCenteredString(poseStack, font, text, x + (int)(entryWidth * 0.5), y + 5, 0xFFFFFF); + + GuiUtil.bindIrisWidgetsTexture(); + + // Draw back button if present + if (this.backButton != null) { + backButton.render(poseStack, x, y, BUTTON_HEIGHT, mouseX, mouseY, tickDelta, hovered); + } + + boolean shiftDown = Screen.hasShiftDown(); + + // Set the appearance of the reset button + this.resetButton.disabled = !shiftDown; + this.resetButton.text = shiftDown ? RESET_BUTTON_TEXT_ACTIVE : RESET_BUTTON_TEXT_INACTIVE; + + // Draw the utility buttons + this.utilityButtons.renderRightAligned(poseStack, (x + entryWidth) - 3, y, BUTTON_HEIGHT, mouseX, mouseY, tickDelta, hovered); + + // Draw the reset button's tooltip + if (this.resetButton.isHovered()) { + Component tooltip = shiftDown ? RESET_TOOLTIP : RESET_HOLD_SHIFT_TOOLTIP; + queueBottomRightAnchoredTooltip(poseStack, mouseX, mouseY, font, tooltip); + } + // Draw the import/export button tooltips + if (this.importButton.isHovered()) { + queueBottomRightAnchoredTooltip(poseStack, mouseX, mouseY, font, IMPORT_TOOLTIP); + } + if (this.exportButton.isHovered()) { + queueBottomRightAnchoredTooltip(poseStack, mouseX, mouseY, font, EXPORT_TOOLTIP); + } + } + + private void queueBottomRightAnchoredTooltip(PoseStack poseStack, int x, int y, Font font, Component text) { + ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel( + font, poseStack, text, + x - (font.width(text) + 10), y - 16 + )); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + boolean backButtonResult = backButton != null && backButton.mouseClicked(mouseX, mouseY, button); + boolean utilButtonResult = utilityButtons.mouseClicked(mouseX, mouseY, button); + + return backButtonResult || utilButtonResult; + } + + private boolean backButtonClicked(IrisElementRow.TextButtonElement button) { + this.navigation.back(); + GuiUtil.playButtonClickSound(); + + return true; + } + + private boolean resetButtonClicked(IrisElementRow.TextButtonElement button) { + if (Screen.hasShiftDown()) { + Iris.resetShaderPackOptionsOnNextReload(); + this.screen.applyChanges(); + GuiUtil.playButtonClickSound(); + + return true; + } + + return false; + } + + private boolean importSettingsButtonClicked(IrisElementRow.IconButtonElement button) { + GuiUtil.playButtonClickSound(); + + // Invalid state to be in + if (!Iris.getCurrentPack().isPresent()) { + return false; + } + + // Displaying a dialog when the game is full-screened can cause severe issues + // https://github.com/IrisShaders/Iris/issues/1258 + if (Minecraft.getMinecraft().getWindow().isFullscreen()) { + this.screen.displayNotification( + I18n.format("options.iris.mustDisableFullscreen") + .withStyle(ChatFormatting.RED).withStyle(ChatFormatting.BOLD)); + return false; + } + + final ShaderPackScreen originalScreen = this.screen; // Also used to prevent invalid state + + FileDialogUtil.fileSelectDialog( + FileDialogUtil.DialogType.OPEN, "Import Shader Settings from File", + Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"), + "Shader Pack Settings (.txt)", "*.txt") + .whenComplete((path, err) -> { + if (err != null) { + Iris.logger.error("Error selecting shader settings from file", err); + + return; + } + + if (Minecraft.getMinecraft().screen == originalScreen) { + path.ifPresent(originalScreen::importPackOptions); + } + }); + + return true; + } + + private boolean exportSettingsButtonClicked(IrisElementRow.IconButtonElement button) { + GuiUtil.playButtonClickSound(); + + // Invalid state to be in + if (!Iris.getCurrentPack().isPresent()) { + return false; + } + + // Displaying a dialog when the game is full-screened can cause severe issues + // https://github.com/IrisShaders/Iris/issues/1258 + if (Minecraft.getMinecraft().getWindow().isFullscreen()) { + this.screen.displayNotification( + I18n.format("options.iris.mustDisableFullscreen") + .withStyle(ChatFormatting.RED).withStyle(ChatFormatting.BOLD)); + return false; + } + + FileDialogUtil.fileSelectDialog( + FileDialogUtil.DialogType.SAVE, "Export Shader Settings to File", + Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"), + "Shader Pack Settings (.txt)", "*.txt") + .whenComplete((path, err) -> { + if (err != null) { + Iris.logger.error("Error selecting file to export shader settings", err); + + return; + } + + path.ifPresent(p -> { + Properties toSave = new Properties(); + + // Dirty way of getting the currently applied settings as a Properties, directly + // opens and copies out of the saved settings file if it is present + Path sourceTxtPath = Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"); + if (Files.exists(sourceTxtPath)) { + try (InputStream in = Files.newInputStream(sourceTxtPath)) { + toSave.load(in); + } catch (IOException ignored) {} + } + + // Save properties to user determined file + try (OutputStream out = Files.newOutputStream(p)) { + toSave.store(out, null); + } catch (IOException e) { + Iris.logger.error("Error saving properties to \"" + p + "\"", e); + } + }); + }); + + return true; + } + } + + public static class ElementRowEntry extends BaseEntry { + private final List> widgets; + private final ShaderPackScreen screen; + + private int cachedWidth; + private int cachedPosX; + + public ElementRowEntry(ShaderPackScreen screen, NavigationController navigation, List> widgets) { + super(navigation); + + this.screen = screen; + this.widgets = widgets; + } + + @Override + public void render(PoseStack poseStack, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + this.cachedWidth = entryWidth; + this.cachedPosX = x; + + // The amount of space widgets will occupy, excluding margins. Will be divided up between widgets. + int totalWidthWithoutMargins = entryWidth - (2 * (widgets.size() - 1)); + + totalWidthWithoutMargins -= 3; // Centers it for some reason + + // Width of a single widget + float singleWidgetWidth = (float) totalWidthWithoutMargins / widgets.size(); + + for (int i = 0; i < widgets.size(); i++) { + AbstractElementWidget widget = widgets.get(i); + boolean widgetHovered = hovered && (getHoveredWidget(mouseX) == i); + widget.render(poseStack, x + (int)((singleWidgetWidth + 2) * i), y, (int) singleWidgetWidth, entryHeight + 2, mouseX, mouseY, tickDelta, widgetHovered); + + screen.setElementHoveredStatus(widget, widgetHovered); + } + } + + public int getHoveredWidget(int mouseX) { + float positionAcrossWidget = ((float) Mth.clamp(mouseX - cachedPosX, 0, cachedWidth)) / cachedWidth; + + return Mth.clamp((int) Math.floor(widgets.size() * positionAcrossWidget), 0, widgets.size() - 1); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return this.widgets.get(getHoveredWidget((int) mouseX)).mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + return this.widgets.get(getHoveredWidget((int) mouseX)).mouseReleased(mouseX, mouseY, button); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java new file mode 100644 index 000000000..57c57c198 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java @@ -0,0 +1,310 @@ +package net.coderbot.iris.gui.element; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.screen.ShaderPackScreen; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; + +import java.util.Collection; +import java.util.function.Function; + +public class ShaderPackSelectionList extends IrisObjectSelectionList { + private static final Component PACK_LIST_LABEL = I18n.format("pack.iris.list.label").withStyle(ChatFormatting.ITALIC, ChatFormatting.GRAY); + + private final ShaderPackScreen screen; + private final TopButtonRowEntry topButtonRow; + private ShaderPackEntry applied = null; + + public ShaderPackSelectionList(ShaderPackScreen screen, Minecraft client, int width, int height, int top, int bottom, int left, int right) { + super(client, width, height, top, bottom, left, right, 20); + + this.screen = screen; + this.topButtonRow = new TopButtonRowEntry(this, Iris.getIrisConfig().areShadersEnabled()); + + refresh(); + } + + @Override + public int getRowWidth() { + return Math.min(308, width - 50); + } + + @Override + protected int getRowTop(int index) { + return super.getRowTop(index) + 2; + } + + public void refresh() { + this.clearEntries(); + + Collection names; + + try { + names = Iris.getShaderpacksDirectoryManager().enumerate(); + } catch (Throwable e) { + Iris.logger.error("Error reading files while constructing selection UI", e); + + // Not translating this since it's going to be seen very rarely, + // We're just trying to get more information on a seemingly untraceable bug: + // - https://github.com/IrisShaders/Iris/issues/785 + this.addLabelEntries( + TextComponent.EMPTY, + new TextComponent("There was an error reading your shaderpacks directory") + .withStyle(ChatFormatting.RED, ChatFormatting.BOLD), + TextComponent.EMPTY, + new TextComponent("Check your logs for more information."), + new TextComponent("Please file an issue report including a log file."), + new TextComponent("If you are able to identify the file causing this, " + + "please include it in your report as well."), + new TextComponent("Note that this might be an issue with folder " + + "permissions; ensure those are correct first.") + ); + + return; + } + + this.addEntry(topButtonRow); + + // Only allow the enable/disable shaders button if the user has + // added a shader pack. Otherwise, the button will be disabled. + topButtonRow.allowEnableShadersButton = names.size() > 0; + + int index = 0; + + for (String name : names) { + index++; + addPackEntry(index, name); + } + + this.addLabelEntries(PACK_LIST_LABEL); + } + + public void addPackEntry(int index, String name) { + ShaderPackEntry entry = new ShaderPackEntry(index, this, name); + + Iris.getIrisConfig().getShaderPackName().ifPresent(currentPackName -> { + if (name.equals(currentPackName)) { + setSelected(entry); + setApplied(entry); + } + }); + + this.addEntry(entry); + } + + public void addLabelEntries(Component ... lines) { + for (Component text : lines) { + this.addEntry(new LabelEntry(text)); + } + } + + public void select(String name) { + for (int i = 0; i < getItemCount(); i++) { + BaseEntry entry = getEntry(i); + + if (entry instanceof ShaderPackEntry && ((ShaderPackEntry)entry).packName.equals(name)) { + setSelected(entry); + + return; + } + } + } + + public void setApplied(ShaderPackEntry entry) { + this.applied = entry; + } + + public ShaderPackEntry getApplied() { + return this.applied; + } + + public TopButtonRowEntry getTopButtonRow() { + return topButtonRow; + } + + public static abstract class BaseEntry extends ObjectSelectionList.Entry { + protected BaseEntry() {} + } + + public static class ShaderPackEntry extends BaseEntry { + private final String packName; + private final ShaderPackSelectionList list; + private final int index; + + public ShaderPackEntry(int index, ShaderPackSelectionList list, String packName) { + this.packName = packName; + this.list = list; + this.index = index; + } + + public boolean isApplied() { + return list.getApplied() == this; + } + + public boolean isSelected() { + return list.getSelected() == this; + } + + public String getPackName() { + return packName; + } + + @Override + public void render(PoseStack poseStack, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + Font font = Minecraft.getMinecraft().font; + int color = 0xFFFFFF; + String name = packName; + + boolean shadersEnabled = list.getTopButtonRow().shadersEnabled; + + if (font.width(new TextComponent(name).withStyle(ChatFormatting.BOLD)) > this.list.getRowWidth() - 3) { + name = font.plainSubstrByWidth(name, this.list.getRowWidth() - 8) + "..."; + } + + MutableComponent text = new TextComponent(name); + + if (this.isMouseOver(mouseX, mouseY)) { + text = text.withStyle(ChatFormatting.BOLD); + } + + if (shadersEnabled && this.isApplied()) { + color = 0xFFF263; + } + + if (!shadersEnabled && !this.isMouseOver(mouseX, mouseY)) { + color = 0xA2A2A2; + } + + drawCenteredString(poseStack, font, text, (x + entryWidth / 2) - 2, y + (entryHeight - 11) / 2, color); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + // Only do anything on left-click + if (button != 0) { + return false; + } + + boolean didAnything = false; + + // UX: If shaders are disabled, then clicking a shader in the list will also + // enable shaders on apply. Previously, it was not possible to select + // a pack when shaders were disabled, but this was a source of confusion + // - people did not realize that they needed to enable shaders before + // selecting a shader pack. + if (!list.getTopButtonRow().shadersEnabled) { + list.getTopButtonRow().setShadersEnabled(true); + didAnything = true; + } + + if (!this.isSelected()) { + this.list.select(this.index); + didAnything = true; + } + + return didAnything; + } + } + + public static class LabelEntry extends BaseEntry { + private final Component label; + + public LabelEntry(Component label) { + this.label = label; + } + + @Override + public void render(PoseStack poseStack, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + drawCenteredString(poseStack, Minecraft.getMinecraft().font, label, (x + entryWidth / 2) - 2, y + (entryHeight - 11) / 2, 0xC2C2C2); + } + } + + public static class TopButtonRowEntry extends BaseEntry { + private static final Component REFRESH_SHADER_PACKS_LABEL = I18n.format("options.iris.refreshShaderPacks").withStyle(style -> style.withColor(TextColor.fromRgb(0x99ceff))); + private static final Component NONE_PRESENT_LABEL = I18n.format("options.iris.shaders.nonePresent").withStyle(ChatFormatting.GRAY); + private static final Component SHADERS_DISABLED_LABEL = I18n.format("options.iris.shaders.disabled"); + private static final Component SHADERS_ENABLED_LABEL = I18n.format("options.iris.shaders.enabled"); + private static final int REFRESH_BUTTON_WIDTH = 18; + + private final ShaderPackSelectionList list; + private final IrisElementRow buttons = new IrisElementRow(); + private final EnableShadersButtonElement enableDisableButton; + private final IrisElementRow.Element refreshPacksButton; + + public boolean allowEnableShadersButton = true; + public boolean shadersEnabled; + + public TopButtonRowEntry(ShaderPackSelectionList list, boolean shadersEnabled) { + this.list = list; + this.shadersEnabled = shadersEnabled; + this.enableDisableButton = new EnableShadersButtonElement( + getEnableDisableLabel(), + button -> { + if (this.allowEnableShadersButton) { + setShadersEnabled(!this.shadersEnabled); + GuiUtil.playButtonClickSound(); + return true; + } + + return false; + }); + this.refreshPacksButton = new IrisElementRow.IconButtonElement( + GuiUtil.Icon.REFRESH, + button -> { + this.list.refresh(); + + GuiUtil.playButtonClickSound(); + return true; + }); + this.buttons.add(this.enableDisableButton, 0).add(this.refreshPacksButton, REFRESH_BUTTON_WIDTH); + } + + public void setShadersEnabled(boolean shadersEnabled) { + this.shadersEnabled = shadersEnabled; + this.enableDisableButton.text = getEnableDisableLabel(); + this.list.screen.refreshScreenSwitchButton(); + } + + @Override + public void render(PoseStack poseStack, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + this.buttons.setWidth(this.enableDisableButton, (entryWidth - 1) - REFRESH_BUTTON_WIDTH); + this.enableDisableButton.centerX = x + (int)(entryWidth * 0.5); + + this.buttons.render(poseStack, x - 2, y - 3, 18, mouseX, mouseY, tickDelta, hovered); + + if (this.refreshPacksButton.isHovered()) { + ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> + GuiUtil.drawTextPanel(Minecraft.getMinecraft().font, poseStack, REFRESH_SHADER_PACKS_LABEL, + (mouseX - 8) - Minecraft.getMinecraft().font.width(REFRESH_SHADER_PACKS_LABEL), mouseY - 16)); + } + } + + private Component getEnableDisableLabel() { + return this.allowEnableShadersButton ? this.shadersEnabled ? SHADERS_ENABLED_LABEL : SHADERS_DISABLED_LABEL : NONE_PRESENT_LABEL; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return this.buttons.mouseClicked(mouseX, mouseY, button); + } + + // Renders the label at an offset as to not look misaligned with the rest of the menu + public static class EnableShadersButtonElement extends IrisElementRow.TextButtonElement { + private int centerX; + + public EnableShadersButtonElement(Component text, Function onClick) { + super(text, onClick); + } + + @Override + public void renderLabel(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + int textX = this.centerX - (int)(this.font.width(this.text) * 0.5); + int textY = y + (int)((height - 8) * 0.5); + + this.font.drawShadow(poseStack, this.text, textX, textY, 0xFFFFFF); + } + } + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java b/src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java new file mode 100644 index 000000000..78eb212a0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java @@ -0,0 +1,15 @@ +package net.coderbot.iris.gui.element.screen; + + + +public class ElementWidgetScreenData { + public static final ElementWidgetScreenData EMPTY = new ElementWidgetScreenData(TextComponent.EMPTY, true); + + public final Component heading; + public final boolean backButton; + + public ElementWidgetScreenData(Component heading, boolean backButton) { + this.heading = heading; + this.backButton = backButton; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java new file mode 100644 index 000000000..8b780878c --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java @@ -0,0 +1,30 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; + +public abstract class AbstractElementWidget { + protected final T element; + + public static final AbstractElementWidget EMPTY = new AbstractElementWidget(null) { + @Override + public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) {} + }; + + public AbstractElementWidget(T element) { + this.element = element; + } + + public void init(ShaderPackScreen screen, NavigationController navigation) {} + + public abstract void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered); + + public boolean mouseClicked(double mx, double my, int button) { + return false; + } + + public boolean mouseReleased(double mx, double my, int button) { + return false; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java new file mode 100644 index 000000000..6512f95cf --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java @@ -0,0 +1,180 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public abstract class BaseOptionElementWidget extends CommentedElementWidget { + protected static final Component SET_TO_DEFAULT = I18n.format("options.iris.setToDefault").withStyle(ChatFormatting.GREEN); + protected static final Component DIVIDER = new TextComponent(": "); + + protected MutableComponent unmodifiedLabel; + protected ShaderPackScreen screen; + protected NavigationController navigation; + private MutableComponent label; + + protected Component trimmedLabel; + protected Component valueLabel; + + private boolean isLabelTrimmed; + private int maxLabelWidth; + private int valueSectionWidth; + + public BaseOptionElementWidget(T element) { + super(element); + } + + @Override + public void init(ShaderPackScreen screen, NavigationController navigation) { + this.screen = screen; + this.navigation = navigation; + this.valueLabel = null; + this.trimmedLabel = null; + } + + protected final void setLabel(MutableComponent label) { + this.label = label.copy().append(DIVIDER); + this.unmodifiedLabel = label; + } + + protected final void updateRenderParams(int width, int minValueSectionWidth) { + // Lazy init of value label + if (this.valueLabel == null) { + this.valueLabel = createValueLabel(); + } + + // Determine the width of the value box + Font font = Minecraft.getMinecraft().font; + this.valueSectionWidth = Math.max(minValueSectionWidth, font.width(this.valueLabel) + 8); + + // Determine maximum width of trimmed label + this.maxLabelWidth = (width - 8) - this.valueSectionWidth; + + // Lazy init of trimmed label, and make sure it is only trimmed when necessary + if (this.trimmedLabel == null || font.width(this.label) > this.maxLabelWidth != isLabelTrimmed) { + updateLabels(); + } + + // Set whether the label has been trimmed (used when updating label and determining whether to render tooltips) + this.isLabelTrimmed = font.width(this.label) > this.maxLabelWidth; + } + + protected final void renderOptionWithValue(PoseStack poseStack, int x, int y, int width, int height, boolean hovered, float sliderPosition, int sliderWidth) { + GuiUtil.bindIrisWidgetsTexture(); + + // Draw button background + GuiUtil.drawButton(poseStack, x, y, width, height, hovered, false); + + // Draw the value box + GuiUtil.drawButton(poseStack, (x + width) - (this.valueSectionWidth + 2), y + 2, this.valueSectionWidth, height - 4, false, true); + + // Draw the preview slider + if (sliderPosition >= 0) { + // Range of x values the slider can occupy + int sliderSpace = (this.valueSectionWidth - 4) - sliderWidth; + + // Position of slider + int sliderPos = ((x + width) - this.valueSectionWidth) + (int)(sliderPosition * sliderSpace); + + GuiUtil.drawButton(poseStack, sliderPos, y + 4, sliderWidth, height - 8, false, false); + } + + Font font = Minecraft.getMinecraft().font; + + // Draw the label + font.drawShadow(poseStack, this.trimmedLabel, x + 6, y + 7, 0xFFFFFF); + // Draw the value label + font.drawShadow(poseStack, this.valueLabel, (x + (width - 2)) - (int)(this.valueSectionWidth * 0.5) - (int)(font.width(this.valueLabel) * 0.5), y + 7, 0xFFFFFF); + } + + protected final void renderOptionWithValue(PoseStack poseStack, int x, int y, int width, int height, boolean hovered) { + this.renderOptionWithValue(poseStack, x, y, width, height, hovered, -1, 0); + } + + protected final void tryRenderTooltip(PoseStack poseStack, int mouseX, int mouseY, boolean hovered) { + if (Screen.hasShiftDown()) { + renderTooltip(poseStack, SET_TO_DEFAULT, mouseX, mouseY, hovered); + } else if (this.isLabelTrimmed && !this.screen.isDisplayingComment()) { + renderTooltip(poseStack, this.unmodifiedLabel, mouseX, mouseY, hovered); + } + } + + protected final void renderTooltip(PoseStack poseStack, Component text, int mouseX, int mouseY, boolean hovered) { + if (hovered) { + ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel(Minecraft.getMinecraft().font, poseStack, text, mouseX + 2, mouseY - 16)); + } + } + + protected final void updateLabels() { + this.trimmedLabel = createTrimmedLabel(); + this.valueLabel = createValueLabel(); + } + + protected final Component createTrimmedLabel() { + MutableComponent label = GuiUtil.shortenText( + Minecraft.getMinecraft().font, + this.label.copy(), + this.maxLabelWidth); + + if (this.isValueModified()) { + label = label.withStyle(style -> style.withColor(TextColor.fromRgb(0xffc94a))); + } + + return label; + } + + protected abstract Component createValueLabel(); + + public abstract boolean applyNextValue(); + + public abstract boolean applyPreviousValue(); + + public abstract boolean applyOriginalValue(); + + public abstract boolean isValueModified(); + + public abstract @Nullable String getCommentKey(); + + @Override + public Optional getCommentTitle() { + return Optional.of(this.unmodifiedLabel); + } + + @Override + public Optional getCommentBody() { + return Optional.ofNullable(getCommentKey()).map(key -> I18n.exists(key) ? I18n.format(key) : null); + } + + @Override + public boolean mouseClicked(double mx, double my, int button) { + if (button == GLFW.GLFW_MOUSE_BUTTON_1 || button == GLFW.GLFW_MOUSE_BUTTON_2) { + boolean refresh = false; + + if (Screen.hasShiftDown()) { + refresh = applyOriginalValue(); + } + if (!refresh) { + if (button == GLFW.GLFW_MOUSE_BUTTON_1) { + refresh = applyNextValue(); + } else { + refresh = applyPreviousValue(); + } + } + + if (refresh) { + this.navigation.refresh(); + } + + GuiUtil.playButtonClickSound(); + + return true; + } + return super.mouseClicked(mx, my, button); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java new file mode 100644 index 000000000..40ca5b3f0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java @@ -0,0 +1,112 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.BooleanOption; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuBooleanOptionElement; + +import net.minecraft.client.resources.I18n; + +public class BooleanElementWidget extends BaseOptionElementWidget { + private static final Component TEXT_TRUE = I18n.format("label.iris.true").withStyle(ChatFormatting.GREEN); + private static final Component TEXT_FALSE = I18n.format("label.iris.false").withStyle(ChatFormatting.RED); + private static final Component TEXT_TRUE_DEFAULT = I18n.format("label.iris.true"); + private static final Component TEXT_FALSE_DEFAULT = I18n.format("label.iris.false"); + + private final BooleanOption option; + + private boolean appliedValue; + private boolean value; + private boolean defaultValue; + + public BooleanElementWidget(OptionMenuBooleanOptionElement element) { + super(element); + + this.option = element.option; + } + + @Override + public void init(ShaderPackScreen screen, NavigationController navigation) { + super.init(screen, navigation); + + // The value currently in use by the shader pack + this.appliedValue = this.element.getAppliedOptionValues().getBooleanValueOrDefault(this.option.getName()); + + // The yet-to-be-applied value that has been queued (if that is the case) + // Might be equal to the applied value + this.value = this.element.getPendingOptionValues().getBooleanValueOrDefault(this.option.getName()); + + this.defaultValue = this.element.getAppliedOptionValues().getOptionSet().getBooleanOptions() + .get(this.option.getName()).getOption().getDefaultValue(); + + this.setLabel(GuiUtil.translateOrDefault(new TextComponent(this.option.getName()), "option." + this.option.getName())); + } + + @Override + public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + this.updateRenderParams(width, 28); + + this.renderOptionWithValue(poseStack, x, y, width, height, hovered); + this.tryRenderTooltip(poseStack, mouseX, mouseY, hovered); + } + + @Override + protected Component createValueLabel() { + // UX: Do not use color if the value is set to default. + // + // This is because the red color for "Off" and green color of "On" + // was causing people to want to change options to On when that was + // unnecessary due to red having a bad association. + // + // This was changed on request of Emin, since people kept on changing + // Compatibility Mode to "On" when not needed. Now we use white for + // default to avoid giving a positive or negative connotation to a + // default value. + if (this.value == this.defaultValue) { + return this.value ? TEXT_TRUE_DEFAULT : TEXT_FALSE_DEFAULT; + } + + return this.value ? TEXT_TRUE : TEXT_FALSE; + } + + @Override + public String getCommentKey() { + return "option." + this.option.getName() + ".comment"; + } + + public String getValue() { + return Boolean.toString(this.value); + } + + private void queue() { + Iris.getShaderPackOptionQueue().put(this.option.getName(), this.getValue()); + } + + @Override + public boolean applyNextValue() { + this.value = !this.value; + this.queue(); + + return true; + } + + @Override + public boolean applyPreviousValue() { + return this.applyNextValue(); + } + + @Override + public boolean applyOriginalValue() { + this.value = this.option.getDefaultValue(); + this.queue(); + + return true; + } + + @Override + public boolean isValueModified() { + return this.value != this.appliedValue; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java new file mode 100644 index 000000000..603f2b971 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java @@ -0,0 +1,16 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; + + +import java.util.Optional; + +public abstract class CommentedElementWidget extends AbstractElementWidget { + public CommentedElementWidget(T element) { + super(element); + } + + public abstract Optional getCommentTitle(); + + public abstract Optional getCommentBody(); +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java new file mode 100644 index 000000000..0a76dbb88 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java @@ -0,0 +1,84 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuLinkElement; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; + +import java.util.Optional; + +public class LinkElementWidget extends CommentedElementWidget { + private static final Component ARROW = new TextComponent(">"); + + private final String targetScreenId; + private final MutableComponent label; + + private NavigationController navigation; + private MutableComponent trimmedLabel = null; + private boolean isLabelTrimmed = false; + + public LinkElementWidget(OptionMenuLinkElement element) { + super(element); + + this.targetScreenId = element.targetScreenId; + this.label = GuiUtil.translateOrDefault(new TextComponent(element.targetScreenId), "screen." + element.targetScreenId); + } + + @Override + public void init(ShaderPackScreen screen, NavigationController navigation) { + this.navigation = navigation; + } + + @Override + public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + GuiUtil.bindIrisWidgetsTexture(); + GuiUtil.drawButton(poseStack, x, y, width, height, hovered, false); + + Font font = Minecraft.getMinecraft().font; + + int maxLabelWidth = width - 9; + + if (font.width(this.label) > maxLabelWidth) { + this.isLabelTrimmed = true; + } + + if (this.trimmedLabel == null) { + this.trimmedLabel = GuiUtil.shortenText(font, this.label, maxLabelWidth); + } + + int labelWidth = font.width(this.trimmedLabel); + + font.drawShadow(poseStack, this.trimmedLabel, x + (int)(width * 0.5) - (int)(labelWidth * 0.5) - (int)(0.5 * Math.max(labelWidth - (width - 18), 0)), y + 7, 0xFFFFFF); + font.draw(poseStack, ARROW, (x + width) - 9, y + 7, 0xFFFFFF); + + if (hovered && this.isLabelTrimmed) { + // To prevent other elements from being drawn on top of the tooltip + ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel(font, poseStack, this.label, mouseX + 2, mouseY - 16)); + } + } + + @Override + public boolean mouseClicked(double mx, double my, int button) { + if (button == GLFW.GLFW_MOUSE_BUTTON_1) { + this.navigation.open(targetScreenId); + GuiUtil.playButtonClickSound(); + + return true; + } + return super.mouseClicked(mx, my, button); + } + + @Override + public Optional getCommentTitle() { + return Optional.of(this.label); + } + + @Override + public Optional getCommentBody() { + String translation = "screen." + this.targetScreenId + ".comment"; + return Optional.ofNullable(I18n.exists(translation) ? I18n.format(translation) : null); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java b/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java new file mode 100644 index 000000000..5003ee4b2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java @@ -0,0 +1,87 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.element.ShaderPackOptionList; +import net.coderbot.iris.gui.element.screen.ElementWidgetScreenData; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuBooleanOptionElement; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuElementScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuLinkElement; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuMainElementScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuProfileElement; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuStringOptionElement; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuSubElementScreen; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public final class OptionMenuConstructor { + private static final Map, WidgetProvider> WIDGET_CREATORS = new HashMap<>(); + private static final Map, ScreenDataProvider> SCREEN_DATA_CREATORS = new HashMap<>(); + + private OptionMenuConstructor() {} + + @SuppressWarnings("unchecked") + public static void registerWidget(Class element, WidgetProvider widget) { + WIDGET_CREATORS.put(element, (WidgetProvider) widget); + } + + @SuppressWarnings("unchecked") + public static void registerScreen(Class screen, ScreenDataProvider data) { + SCREEN_DATA_CREATORS.put(screen, (ScreenDataProvider) data); + } + + public static AbstractElementWidget createWidget(OptionMenuElement element) { + return WIDGET_CREATORS.getOrDefault(element.getClass(), e -> AbstractElementWidget.EMPTY).create(element); + } + + public static ElementWidgetScreenData createScreenData(OptionMenuElementScreen screen) { + return SCREEN_DATA_CREATORS.getOrDefault(screen.getClass(), s -> ElementWidgetScreenData.EMPTY).create(screen); + } + + @SuppressWarnings("unchecked") + public static void constructAndApplyToScreen(OptionMenuContainer container, ShaderPackScreen packScreen, ShaderPackOptionList optionList, NavigationController navigation) { + OptionMenuElementScreen screen = container.mainScreen; + + if (navigation.getCurrentScreen() != null && container.subScreens.containsKey(navigation.getCurrentScreen())) { + screen = container.subScreens.get(navigation.getCurrentScreen()); + } + + ElementWidgetScreenData data = createScreenData(screen); + + optionList.addHeader(data.heading, data.backButton); + optionList.addWidgets(screen.getColumnCount(), screen.elements.stream().map(element -> { + AbstractElementWidget widget = (AbstractElementWidget) createWidget(element); + widget.init(packScreen, navigation); + return widget; + }).collect(Collectors.toList())); + } + + static { + registerScreen(OptionMenuMainElementScreen.class, screen -> + new ElementWidgetScreenData(new TextComponent(Iris.getCurrentPackName()).append(Iris.isFallback() ? " (fallback)" : "").withStyle(ChatFormatting.BOLD), false)); + + registerScreen(OptionMenuSubElementScreen.class, screen -> + new ElementWidgetScreenData(GuiUtil.translateOrDefault(new TextComponent(screen.screenId), "screen." + screen.screenId), true)); + + registerWidget(OptionMenuBooleanOptionElement.class, BooleanElementWidget::new); + registerWidget(OptionMenuProfileElement.class, ProfileElementWidget::new); + registerWidget(OptionMenuLinkElement.class, LinkElementWidget::new); + + registerWidget(OptionMenuStringOptionElement.class, element -> + element.slider ? new SliderElementWidget(element) : new StringElementWidget(element)); + } + + public interface WidgetProvider { + AbstractElementWidget create(T element); + } + + public interface ScreenDataProvider { + ElementWidgetScreenData create(T screen); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java new file mode 100644 index 000000000..c839d63db --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java @@ -0,0 +1,101 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.OptionSet; +import net.coderbot.iris.shaderpack.option.Profile; +import net.coderbot.iris.shaderpack.option.ProfileSet; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuProfileElement; +import net.coderbot.iris.shaderpack.option.values.OptionValues; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; + +import java.util.Optional; + +public class ProfileElementWidget extends BaseOptionElementWidget { + private static final MutableComponent PROFILE_LABEL = I18n.format("options.iris.profile"); + private static final MutableComponent PROFILE_CUSTOM = I18n.format("options.iris.profile.custom").withStyle(ChatFormatting.YELLOW); + + private Profile next; + private Profile previous; + private Component profileLabel; + + public ProfileElementWidget(OptionMenuProfileElement element) { + super(element); + } + + @Override + public void init(ShaderPackScreen screen, NavigationController navigation) { + super.init(screen, navigation); + this.setLabel(PROFILE_LABEL); + + ProfileSet profiles = this.element.profiles; + OptionSet options = this.element.options; + OptionValues pendingValues = this.element.getPendingOptionValues(); + + ProfileSet.ProfileResult result = profiles.scan(options, pendingValues); + + this.next = result.next; + this.previous = result.previous; + Optional profileName = result.current.map(p -> p.name); + + this.profileLabel = profileName.map(name -> GuiUtil.translateOrDefault(new TextComponent(name), "profile." + name)).orElse(PROFILE_CUSTOM); + } + + @Override + public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + this.updateRenderParams(width, width - (Minecraft.getMinecraft().font.width(PROFILE_LABEL) + 16)); + + this.renderOptionWithValue(poseStack, x, y, width, height, hovered); + } + + @Override + protected Component createValueLabel() { + return this.profileLabel; + } + + @Override + public Optional getCommentTitle() { + return Optional.of(PROFILE_LABEL); + } + + @Override + public String getCommentKey() { + return "profile.comment"; + } + + @Override + public boolean applyNextValue() { + if (this.next == null) { + return false; + } + + Iris.queueShaderPackOptionsFromProfile(this.next); + + return true; + } + + @Override + public boolean applyPreviousValue() { + if (this.previous == null) { + return false; + } + + Iris.queueShaderPackOptionsFromProfile(this.previous); + + return true; + } + + @Override + public boolean applyOriginalValue() { + return false; // Resetting options is the way to return to the "default profile" + } + + @Override + public boolean isValueModified() { + return false; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java new file mode 100644 index 000000000..c6e347108 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java @@ -0,0 +1,115 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuStringOptionElement; +import net.minecraft.client.Minecraft; + +public class SliderElementWidget extends StringElementWidget { + private static final int PREVIEW_SLIDER_WIDTH = 4; + private static final int ACTIVE_SLIDER_WIDTH = 6; + + private boolean mouseDown = false; + + public SliderElementWidget(OptionMenuStringOptionElement element) { + super(element); + } + + @Override + public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + this.updateRenderParams(width, 35); + + if (!hovered) { + this.renderOptionWithValue(poseStack, x, y, width, height, false, (float)valueIndex / (valueCount - 1), PREVIEW_SLIDER_WIDTH); + } else { + this.renderSlider(poseStack, x, y, width, height, mouseX, mouseY, tickDelta); + } + + if (Screen.hasShiftDown()) { + renderTooltip(poseStack, SET_TO_DEFAULT, mouseX, mouseY, hovered); + } else if (!this.screen.isDisplayingComment()) { + renderTooltip(poseStack, this.unmodifiedLabel, mouseX, mouseY, hovered); + } + + if (this.mouseDown) { + // Release if the mouse went off the slider + if (!hovered) { + this.onReleased(); + } + + whileDragging(x, width, mouseX); + } + } + + private void renderSlider(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta) { + GuiUtil.bindIrisWidgetsTexture(); + + // Draw background button + GuiUtil.drawButton(poseStack, x, y, width, height, false, false); + // Draw slider area + GuiUtil.drawButton(poseStack, x + 2, y + 2, width - 4, height - 4, false, true); + + // Range of x values the slider can occupy + int sliderSpace = (width - 8) - ACTIVE_SLIDER_WIDTH; + // Position of slider + int sliderPos = (x + 4) + (int)(((float)valueIndex / (valueCount - 1)) * sliderSpace); + // Draw slider + GuiUtil.drawButton(poseStack, sliderPos, y + 4, ACTIVE_SLIDER_WIDTH, height - 8, this.mouseDown, false); + + // Draw value label + Font font = Minecraft.getMinecraft().font; + font.drawShadow(poseStack, this.valueLabel, (int)(x + (width * 0.5)) - (int)(font.width(this.valueLabel) * 0.5), y + 7, 0xFFFFFF); + } + + private void whileDragging(int x, int width, int mouseX) { + float mousePositionAcrossWidget = Mth.clamp((float)(mouseX - (x + 4)) / (width - 8), 0, 1); + + int newValueIndex = Math.min(valueCount - 1, (int)(mousePositionAcrossWidget * valueCount)); + + if (valueIndex != newValueIndex) { + this.valueIndex = newValueIndex; + + this.updateLabels(); + } + } + + private void onReleased() { + mouseDown = false; + + this.queue(); + this.navigation.refresh(); + + GuiUtil.playButtonClickSound(); + } + + @Override + public boolean mouseClicked(double mx, double my, int button) { + if (button == GLFW.GLFW_MOUSE_BUTTON_1) { + if (Screen.hasShiftDown()) { + if (this.applyOriginalValue()) { + this.navigation.refresh(); + } + GuiUtil.playButtonClickSound(); + + return true; + } + + mouseDown = true; + GuiUtil.playButtonClickSound(); + + return true; + } + + // Do not use base widget's button click behavior + return false; + } + + @Override + public boolean mouseReleased(double mx, double my, int button) { + if (button == GLFW.GLFW_MOUSE_BUTTON_1) { + this.onReleased(); + + return true; + } + return super.mouseReleased(mx, my, button); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java new file mode 100644 index 000000000..efcd0aabd --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java @@ -0,0 +1,109 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.StringOption; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuStringOptionElement; + +import java.util.List; + +public class StringElementWidget extends BaseOptionElementWidget { + protected final StringOption option; + + protected String appliedValue; + protected int valueCount; + protected int valueIndex; + + public StringElementWidget(OptionMenuStringOptionElement element) { + super(element); + + this.option = element.option; + } + + @Override + public void init(ShaderPackScreen screen, NavigationController navigation) { + super.init(screen, navigation); + + // The yet-to-be-applied value that has been queued (if that is the case) + // Might be equal to the applied value + String actualPendingValue = this.element.getPendingOptionValues().getStringValueOrDefault(this.option.getName()); + + // The value currently in use by the shader pack + this.appliedValue = this.element.getAppliedOptionValues().getStringValueOrDefault(this.option.getName()); + + this.setLabel(GuiUtil.translateOrDefault(new TextComponent(this.option.getName()), "option." + this.option.getName())); + + List values = this.option.getAllowedValues(); + + this.valueCount = values.size(); + this.valueIndex = values.indexOf(actualPendingValue); + } + + @Override + public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + this.updateRenderParams(width, 0); + + this.renderOptionWithValue(poseStack, x, y, width, height, hovered); + this.tryRenderTooltip(poseStack, mouseX, mouseY, hovered); + } + + private void increment(int amount) { + this.valueIndex = Math.max(this.valueIndex, 0); + + this.valueIndex = Math.floorMod(this.valueIndex + amount, this.valueCount); + } + + @Override + protected Component createValueLabel() { + return GuiUtil.translateOrDefault( + new TextComponent(getValue()).withStyle(style -> style.withColor(TextColor.fromRgb(0x6688ff))), + "value." + this.option.getName() + "." + getValue()); + } + + @Override + public String getCommentKey() { + return "option." + this.option.getName() + ".comment"; + } + + public String getValue() { + if (this.valueIndex < 0) { + return this.appliedValue; + } + return this.option.getAllowedValues().get(this.valueIndex); + } + + protected void queue() { + Iris.getShaderPackOptionQueue().put(this.option.getName(), this.getValue()); + } + + @Override + public boolean applyNextValue() { + this.increment(1); + this.queue(); + + return true; + } + + @Override + public boolean applyPreviousValue() { + this.increment(-1); + this.queue(); + + return true; + } + + @Override + public boolean applyOriginalValue() { + this.valueIndex = this.option.getAllowedValues().indexOf(this.option.getDefaultValue()); + this.queue(); + + return true; + } + + @Override + public boolean isValueModified() { + return !this.appliedValue.equals(this.getValue()); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java b/src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java new file mode 100644 index 000000000..59e601eef --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java @@ -0,0 +1,68 @@ +package net.coderbot.iris.gui.option; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; + +import java.io.IOException; + +public class IrisVideoSettings { + public static int shadowDistance = 32; + + // TODO: Tell the user to check in the shader options once that's supported. + private static final Component DISABLED_TOOLTIP = I18n.format("options.iris.shadowDistance.disabled"); + private static final Component ENABLED_TOOLTIP = I18n.format("options.iris.shadowDistance.enabled"); + + public static int getOverriddenShadowDistance(int base) { + return Iris.getPipelineManager().getPipeline() + .map(pipeline -> pipeline.getForcedShadowRenderDistanceChunksForDisplay().orElse(base)) + .orElse(base); + } + + public static boolean isShadowDistanceSliderEnabled() { + return Iris.getPipelineManager().getPipeline() + .map(pipeline -> !pipeline.getForcedShadowRenderDistanceChunksForDisplay().isPresent()) + .orElse(true); + } + + public static final ProgressOption RENDER_DISTANCE = new ShadowDistanceOption("options.iris.shadowDistance", 0.0D, 32.0D, 1.0F, (gameOptions) -> { + return (double) getOverriddenShadowDistance(shadowDistance); + }, (gameOptions, viewDistance) -> { + double outputShadowDistance = viewDistance; + shadowDistance = (int) outputShadowDistance; + try { + Iris.getIrisConfig().save(); + } catch (IOException e) { + e.printStackTrace(); + } + }, (gameOptions, option) -> { + int d = (int) option.get(gameOptions); + + WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); + + Component tooltip; + + if (pipeline != null) { + d = pipeline.getForcedShadowRenderDistanceChunksForDisplay().orElse(d); + + if (pipeline.getForcedShadowRenderDistanceChunksForDisplay().isPresent()) { + tooltip = DISABLED_TOOLTIP; + } else { + tooltip = ENABLED_TOOLTIP; + } + } else { + tooltip = ENABLED_TOOLTIP; + } + + option.setTooltip(Minecraft.getMinecraft().font.split(tooltip, 200)); + + if (d <= 0.0) { + return I18n.format("options.generic_value", I18n.format("options.iris.shadowDistance"), "0 (disabled)"); + } else { + return I18n.format("options.generic_value", + I18n.format("options.iris.shadowDistance"), + I18n.format("options.chunks", d)); + } + }); +} diff --git a/src/main/java/net/coderbot/iris/gui/option/ShaderPackSelectionButtonOption.java b/src/main/java/net/coderbot/iris/gui/option/ShaderPackSelectionButtonOption.java new file mode 100644 index 000000000..26f2c56c3 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/option/ShaderPackSelectionButtonOption.java @@ -0,0 +1,27 @@ +package net.coderbot.iris.gui.option; + +import codechicken.nei.config.OptionButton; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; + +public class ShaderPackSelectionButtonOption extends Option { + private final Screen parent; + private final Minecraft client; + + public ShaderPackSelectionButtonOption(Screen parent, Minecraft client) { + super("options.iris.shaderPackSelection"); + this.parent = parent; + this.client = client; + } + + @Override + public AbstractWidget createButton(Options options, int x, int y, int width) { + return new OptionButton( + x, y, width, 20, + this, + I18n.format("options.iris.shaderPackSelection"), + button -> client.setScreen(new ShaderPackScreen(parent)) + ); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceOption.java b/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceOption.java new file mode 100644 index 000000000..b90e68746 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceOption.java @@ -0,0 +1,22 @@ +package net.coderbot.iris.gui.option; + + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class ShadowDistanceOption extends ProgressOption { + + public ShadowDistanceOption(String string, double d, double e, float f, Function function, BiConsumer biConsumer, BiFunction biFunction) { + super(string, d, e, f, function, biConsumer, biFunction); + } + + @Override + public AbstractWidget createButton(Options options, int x, int y, int width) { + AbstractWidget widget = new ShadowDistanceSliderButton(options, x, y, width, 20, this); + + widget.active = IrisVideoSettings.isShadowDistanceSliderEnabled(); + + return widget; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceSliderButton.java b/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceSliderButton.java new file mode 100644 index 000000000..706168651 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceSliderButton.java @@ -0,0 +1,20 @@ +package net.coderbot.iris.gui.option; + + +public class ShadowDistanceSliderButton extends SliderButton { + public ShadowDistanceSliderButton(Options gameOptions, int x, int y, int width, int height, ProgressOption option) { + super(gameOptions, x, y, width, height, option); + } + + public boolean isMouseOver(double mouseX, double mouseY) { + boolean actuallyActive = this.active; + this.active = true; + + // Temporarily set active to true so that isMouseOver doesn't immediately bail out. + // We don't just copy the code here in case some other mod wants to change how it works. + boolean mouseOver = super.isMouseOver(mouseX, mouseY); + + this.active = actuallyActive; + return mouseOver; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/screen/HudHideable.java b/src/main/java/net/coderbot/iris/gui/screen/HudHideable.java new file mode 100644 index 000000000..71a88e4e2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/screen/HudHideable.java @@ -0,0 +1,9 @@ +package net.coderbot.iris.gui.screen; + +/** + * Screens implementing this will hide the player hand and HUD + * + * Only used for instanceof checks + */ +public interface HudHideable { +} diff --git a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java new file mode 100644 index 000000000..48735a195 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java @@ -0,0 +1,574 @@ +package net.coderbot.iris.gui.screen; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.element.ShaderPackOptionList; +import net.coderbot.iris.gui.element.ShaderPackSelectionList; +import net.coderbot.iris.gui.element.widget.AbstractElementWidget; +import net.coderbot.iris.gui.element.widget.CommentedElementWidget; +import net.coderbot.iris.shaderpack.ShaderPack; +import net.irisshaders.iris.api.v0.IrisApi; + +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.ChatComponentText; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; + +public class ShaderPackScreen extends GuiScreen implements HudHideable { + /** + * Queue rendering to happen on top of all elements. Useful for tooltips or dialogs. + */ + public static final Set TOP_LAYER_RENDER_QUEUE = new HashSet<>(); + + private static final Component SELECT_TITLE = I18n.format("pack.iris.select.title").withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC); + private static final Component CONFIGURE_TITLE = I18n.format("pack.iris.configure.title").withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC); + private static final int COMMENT_PANEL_WIDTH = 314; + + private final GuiScreen parent; + private final MutableComponent irisTextComponent; + + private ShaderPackSelectionList shaderPackList; + + private @Nullable ShaderPackOptionList shaderOptionList = null; + private @Nullable NavigationController navigation = null; + private GuiButton screenSwitchButton; + + private Component notificationDialog = null; + private int notificationDialogTimer = 0; + + private @Nullable AbstractElementWidget hoveredElement = null; + private Optional hoveredElementCommentTitle = Optional.empty(); + private List hoveredElementCommentBody = new ArrayList<>(); + private int hoveredElementCommentTimer = 0; + + private boolean optionMenuOpen = false; + + private boolean dropChanges = false; + private static String development = "Development Environment"; + private MutableComponent developmentComponent; + private MutableComponent updateComponent; + + private boolean guiHidden = false; + private float guiButtonHoverTimer = 0.0f; + + public ShaderPackScreen(GuiScreen parent) { + super(I18n.format("options.iris.shaderPackSelection.title")); + + this.parent = parent; + + String irisName = Iris.MODNAME + " " + Iris.getVersion(); + + if (irisName.contains("-development-environment")) { + this.developmentComponent = new ChatComponentText("Development Environment").withStyle(ChatFormatting.GOLD); + irisName = irisName.replace("-development-environment", ""); + } + + this.irisTextComponent = new TextComponent(irisName).withStyle(ChatFormatting.GRAY); + + refreshForChangedPack(); + } + + @Override + public void render(PoseStack poseStack, int mouseX, int mouseY, float delta) { + if (this.minecraft.level == null) { + this.renderBackground(poseStack); + } else if (!this.guiHidden) { + this.fillGradient(poseStack, 0, 0, width, height, 0x4F232323, 0x4F232323); + } + + if (!this.guiHidden) { + if (optionMenuOpen && this.shaderOptionList != null) { + this.shaderOptionList.render(poseStack, mouseX, mouseY, delta); + } else { + this.shaderPackList.render(poseStack, mouseX, mouseY, delta); + } + } + + float previousHoverTimer = this.guiButtonHoverTimer; + super.render(poseStack, mouseX, mouseY, delta); + if (previousHoverTimer == this.guiButtonHoverTimer) { + this.guiButtonHoverTimer = 0.0f; + } + + if (!this.guiHidden) { + drawCenteredString(poseStack, this.font, this.title, (int) (this.width * 0.5), 8, 0xFFFFFF); + + if (notificationDialog != null && notificationDialogTimer > 0) { + drawCenteredString(poseStack, this.font, notificationDialog, (int) (this.width * 0.5), 21, 0xFFFFFF); + } else { + if (optionMenuOpen) { + drawCenteredString(poseStack, this.font, CONFIGURE_TITLE, (int) (this.width * 0.5), 21, 0xFFFFFF); + } else { + drawCenteredString(poseStack, this.font, SELECT_TITLE, (int) (this.width * 0.5), 21, 0xFFFFFF); + } + } + + // Draw the comment panel + if (this.isDisplayingComment()) { + // Determine panel height and position + int panelHeight = Math.max(50, 18 + (this.hoveredElementCommentBody.size() * 10)); + int x = (int) (0.5 * this.width) - 157; + int y = this.height - (panelHeight + 4); + // Draw panel + GuiUtil.drawPanel(poseStack, x, y, COMMENT_PANEL_WIDTH, panelHeight); + // Draw text + this.font.drawShadow(poseStack, this.hoveredElementCommentTitle.orElse(TextComponent.EMPTY), x + 4, y + 4, 0xFFFFFF); + for (int i = 0; i < this.hoveredElementCommentBody.size(); i++) { + this.font.drawShadow(poseStack, this.hoveredElementCommentBody.get(i), x + 4, (y + 16) + (i * 10), 0xFFFFFF); + } + } + } + + // Render everything queued to render last + for (Runnable render : TOP_LAYER_RENDER_QUEUE) { + render.run(); + } + TOP_LAYER_RENDER_QUEUE.clear(); + + if (this.developmentComponent != null) { + this.font.drawShadow(poseStack, developmentComponent, 2, this.height - 10, 0xFFFFFF); + this.font.drawShadow(poseStack, irisTextComponent, 2, this.height - 20, 0xFFFFFF); + } else if (this.updateComponent != null) { + this.font.drawShadow(poseStack, updateComponent, 2, this.height - 10, 0xFFFFFF); + this.font.drawShadow(poseStack, irisTextComponent, 2, this.height - 20, 0xFFFFFF); + } else { + this.font.drawShadow(poseStack, irisTextComponent, 2, this.height - 10, 0xFFFFFF); + } + } + + @Override + protected void init() { + super.init(); + int bottomCenter = this.width / 2 - 50; + int topCenter = this.width / 2 - 76; + boolean inWorld = this.minecraft.level != null; + + this.children.remove(this.shaderPackList); + this.children.remove(this.shaderOptionList); + + this.shaderPackList = new ShaderPackSelectionList(this, this.minecraft, this.width, this.height, 32, this.height - 58, 0, this.width); + + if (Iris.getCurrentPack().isPresent() && this.navigation != null) { + ShaderPack currentPack = Iris.getCurrentPack().get(); + + this.shaderOptionList = new ShaderPackOptionList(this, this.navigation, currentPack, this.minecraft, this.width, this.height, 32, this.height - 58, 0, this.width); + this.navigation.setActiveOptionList(this.shaderOptionList); + + this.shaderOptionList.rebuild(); + } else { + optionMenuOpen = false; + this.shaderOptionList = null; + } + + if (inWorld) { + this.shaderPackList.setRenderBackground(false); + if (shaderOptionList != null) { + this.shaderOptionList.setRenderBackground(false); + } + } + + this.buttons.clear(); + this.children.clear(); + + if (!this.guiHidden) { + if (optionMenuOpen && shaderOptionList != null) { + this.children.add(shaderOptionList); + } else { + this.children.add(shaderPackList); + } + + this.addButton(new Button(bottomCenter + 104, this.height - 27, 100, 20, + CommonComponents.GUI_DONE, button -> onClose())); + + this.addButton(new Button(bottomCenter, this.height - 27, 100, 20, + I18n.format("options.iris.apply"), button -> this.applyChanges())); + + this.addButton(new Button(bottomCenter - 104, this.height - 27, 100, 20, + CommonComponents.GUI_CANCEL, button -> this.dropChangesAndClose())); + + this.addButton(new Button(topCenter - 78, this.height - 51, 152, 20, + I18n.format("options.iris.openShaderPackFolder"), button -> openShaderPackFolder())); + + this.screenSwitchButton = this.addButton(new Button(topCenter + 78, this.height - 51, 152, 20, + I18n.format("options.iris.shaderPackList"), button -> { + this.optionMenuOpen = !this.optionMenuOpen; + + // UX: Apply changes before switching screens to avoid unintuitive behavior + // + // Not doing this leads to unintuitive behavior, since selecting a pack in the + // list (but not applying) would open the settings for the previous pack, rather + // than opening the settings for the selected (but not applied) pack. + this.applyChanges(); + + this.init(); + } + )); + + refreshScreenSwitchButton(); + } + + if (inWorld) { + Component showOrHide = this.guiHidden + ? I18n.format("options.iris.gui.show") + : I18n.format("options.iris.gui.hide"); + + float endOfLastButton = this.width / 2.0f + 154.0f; + float freeSpace = this.width - endOfLastButton; + int x; + if (freeSpace > 100.0f) { + x = this.width - 50; + } else if (freeSpace < 20.0f) { + x = this.width - 20; + } else { + x = (int) (endOfLastButton + (freeSpace / 2.0f)) - 10; + } + + this.addButton(new ImageButton( + x, this.height - 39, + 20, 20, + this.guiHidden ? 20 : 0, 146, 20, + GuiUtil.IRIS_WIDGETS_TEX, + 256, 256, + button -> { + this.guiHidden = !this.guiHidden; + this.init(); + }, + (button, poseStack, i, j) -> { + this.guiButtonHoverTimer += this.minecraft.getDeltaFrameTime(); + if (this.guiButtonHoverTimer >= 10.0f) { + TOP_LAYER_RENDER_QUEUE.add(() -> this.renderTooltip(poseStack, showOrHide, i, j)); + } + }, + showOrHide + )); + } + + // NB: Don't let comment remain when exiting options screen + // https://github.com/IrisShaders/Iris/issues/1494 + this.hoveredElement = null; + this.hoveredElementCommentTimer = 0; + } + + public void refreshForChangedPack() { + if (Iris.getCurrentPack().isPresent()) { + ShaderPack currentPack = Iris.getCurrentPack().get(); + + this.navigation = new NavigationController(currentPack.getMenuContainer()); + + if (this.shaderOptionList != null) { + this.shaderOptionList.applyShaderPack(currentPack); + this.shaderOptionList.rebuild(); + } + } else { + this.navigation = null; + } + + refreshScreenSwitchButton(); + } + + public void refreshScreenSwitchButton() { + if (this.screenSwitchButton != null) { + this.screenSwitchButton.setMessage( + optionMenuOpen ? + I18n.format("options.iris.shaderPackList") + : I18n.format("options.iris.shaderPackSettings") + ); + this.screenSwitchButton.active = optionMenuOpen || shaderPackList.getTopButtonRow().shadersEnabled; + } + } + + @Override + public void tick() { + super.tick(); + + if (this.notificationDialogTimer > 0) { + this.notificationDialogTimer--; + } + + if (this.hoveredElement != null) { + this.hoveredElementCommentTimer++; + } else { + this.hoveredElementCommentTimer = 0; + } + } + + @Override + public boolean keyPressed(int key, int j, int k) { + if (key == GLFW.GLFW_KEY_ESCAPE) { + if (this.guiHidden) { + this.guiHidden = false; + this.init(); + + return true; + } else if (this.navigation != null && this.navigation.hasHistory()) { + this.navigation.back(); + + return true; + } else if (this.optionMenuOpen) { + this.optionMenuOpen = false; + this.init(); + + return true; + } + } + + return this.guiHidden || super.keyPressed(key, j, k); + } + + @Override + public void onFilesDrop(List paths) { + if (this.optionMenuOpen) { + onOptionMenuFilesDrop(paths); + } else { + onPackListFilesDrop(paths); + } + } + + public void onPackListFilesDrop(List paths) { + List packs = paths.stream().filter(Iris::isValidShaderpack).collect(Collectors.toList()); + + for (Path pack : packs) { + String fileName = pack.getFileName().toString(); + + try { + Iris.getShaderpacksDirectoryManager().copyPackIntoDirectory(fileName, pack); + } catch (FileAlreadyExistsException e) { + this.notificationDialog = I18n.format( + "options.iris.shaderPackSelection.copyErrorAlreadyExists", + fileName + ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); + + this.notificationDialogTimer = 100; + this.shaderPackList.refresh(); + + return; + } catch (IOException e) { + Iris.logger.warn("Error copying dragged shader pack", e); + + this.notificationDialog = I18n.format( + "options.iris.shaderPackSelection.copyError", + fileName + ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); + + this.notificationDialogTimer = 100; + this.shaderPackList.refresh(); + + return; + } + } + + // After copying the relevant files over to the folder, make sure to refresh the shader pack list. + this.shaderPackList.refresh(); + + if (packs.size() == 0) { + // If zero packs were added, then notify the user that the files that they added weren't actually shader + // packs. + + if (paths.size() == 1) { + // If a single pack could not be added, provide a message with that pack in the file name + String fileName = paths.get(0).getFileName().toString(); + + this.notificationDialog = I18n.format( + "options.iris.shaderPackSelection.failedAddSingle", + fileName + ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); + } else { + // Otherwise, show a generic message. + + this.notificationDialog = I18n.format( + "options.iris.shaderPackSelection.failedAdd" + ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); + } + + } else if (packs.size() == 1) { + // In most cases, users will drag a single pack into the selection menu. So, let's special case it. + String packName = packs.get(0).getFileName().toString(); + + this.notificationDialog = I18n.format( + "options.iris.shaderPackSelection.addedPack", + packName + ).withStyle(ChatFormatting.ITALIC, ChatFormatting.YELLOW); + + // Select the pack that the user just added, since if a user just dragged a pack in, they'll probably want + // to actually use that pack afterwards. + this.shaderPackList.select(packName); + } else { + // We also support multiple packs being dragged and dropped at a time. Just show a generic success message + // in that case. + this.notificationDialog = I18n.format( + "options.iris.shaderPackSelection.addedPacks", + packs.size() + ).withStyle(ChatFormatting.ITALIC, ChatFormatting.YELLOW); + } + + // Show the relevant message for 5 seconds (100 ticks) + this.notificationDialogTimer = 100; + } + + public void displayNotification(Component component) { + this.notificationDialog = component; + this.notificationDialogTimer = 100; + } + + public void onOptionMenuFilesDrop(List paths) { + // If more than one option file has been dragged, display an error + // as only one option file should be imported at a time + if (paths.size() != 1) { + this.notificationDialog = I18n.format( + "options.iris.shaderPackOptions.tooManyFiles" + ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); + this.notificationDialogTimer = 100; // 5 seconds (100 ticks) + + return; + } + + this.importPackOptions(paths.get(0)); + } + + public void importPackOptions(Path settingFile) { + try (InputStream in = Files.newInputStream(settingFile)) { + Properties properties = new Properties(); + properties.load(in); + + Iris.queueShaderPackOptionsFromProperties(properties); + + this.notificationDialog = I18n.format( + "options.iris.shaderPackOptions.importedSettings", + settingFile.getFileName().toString() + ).withStyle(ChatFormatting.ITALIC, ChatFormatting.YELLOW); + this.notificationDialogTimer = 100; // 5 seconds (100 ticks) + + if (this.navigation != null) { + this.navigation.refresh(); + } + } catch (Exception e) { + // If the file could not be properly parsed or loaded, + // log the error and display a message to the user + Iris.logger.error("Error importing shader settings file \""+ settingFile.toString() +"\"", e); + + this.notificationDialog = I18n.format( + "options.iris.shaderPackOptions.failedImport", + settingFile.getFileName().toString() + ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); + this.notificationDialogTimer = 100; // 5 seconds (100 ticks) + } + } + + @Override + public void onClose() { + if (!dropChanges) { + applyChanges(); + } else { + discardChanges(); + } + + this.minecraft.setScreen(parent); + } + + private void dropChangesAndClose() { + dropChanges = true; + onClose(); + } + + public void applyChanges() { + ShaderPackSelectionList.BaseEntry base = this.shaderPackList.getSelected(); + + if (!(base instanceof ShaderPackSelectionList.ShaderPackEntry)) { + return; + } + + ShaderPackSelectionList.ShaderPackEntry entry = (ShaderPackSelectionList.ShaderPackEntry)base; + this.shaderPackList.setApplied(entry); + + String name = entry.getPackName(); + + // If the pack is being changed, clear pending options from the previous pack to + // avoid possible undefined behavior from applying one pack's options to another pack + if (!name.equals(Iris.getCurrentPackName())) { + Iris.clearShaderPackOptionQueue(); + } + + boolean enabled = this.shaderPackList.getTopButtonRow().shadersEnabled; + + String previousPackName = Iris.getIrisConfig().getShaderPackName().orElse(null); + boolean previousShadersEnabled = Iris.getIrisConfig().areShadersEnabled(); + + // Only reload if the pack would be different from before, or shaders were toggled, or options were changed, or if we're about to reset options. + if (!name.equals(previousPackName) || enabled != previousShadersEnabled || !Iris.getShaderPackOptionQueue().isEmpty() || Iris.shouldResetShaderPackOptionsOnNextReload()) { + Iris.getIrisConfig().setShaderPackName(name); + IrisApi.getInstance().getConfig().setShadersEnabledAndApply(enabled); + } + + refreshForChangedPack(); + } + + private void discardChanges() { + Iris.clearShaderPackOptionQueue(); + } + + private void openShaderPackFolder() { + Util.getPlatform().openUri(Iris.getShaderpacksDirectoryManager().getDirectoryUri()); + } + + // Let the screen know if an element is hovered or not, allowing for accurately updating which element is hovered + public void setElementHoveredStatus(AbstractElementWidget widget, boolean hovered) { + if (hovered && widget != this.hoveredElement) { + this.hoveredElement = widget; + + if (widget instanceof CommentedElementWidget) { + this.hoveredElementCommentTitle = ((CommentedElementWidget) widget).getCommentTitle(); + + Optional commentBody = ((CommentedElementWidget) widget).getCommentBody(); + if (!commentBody.isPresent()) { + this.hoveredElementCommentBody.clear(); + } else { + String rawCommentBody = commentBody.get().getString(); + + // Strip any trailing "."s + if (rawCommentBody.endsWith(".")) { + rawCommentBody = rawCommentBody.substring(0, rawCommentBody.length() - 1); + } + // Split comment body into lines by separator ". " + List splitByPeriods = Arrays.stream(rawCommentBody.split("\\. [ ]*")).map(TextComponent::new).collect(Collectors.toList()); + // Line wrap + this.hoveredElementCommentBody = new ArrayList<>(); + for (MutableComponent text : splitByPeriods) { + this.hoveredElementCommentBody.addAll(this.font.split(text, COMMENT_PANEL_WIDTH - 8)); + } + } + } else { + this.hoveredElementCommentTitle = Optional.empty(); + this.hoveredElementCommentBody.clear(); + } + + this.hoveredElementCommentTimer = 0; + } else if (!hovered && widget == this.hoveredElement) { + this.hoveredElement = null; + this.hoveredElementCommentTitle = Optional.empty(); + this.hoveredElementCommentBody.clear(); + this.hoveredElementCommentTimer = 0; + } + } + + public boolean isDisplayingComment() { + return this.hoveredElementCommentTimer > 20 && + this.hoveredElementCommentTitle.isPresent() && + !this.hoveredElementCommentBody.isEmpty(); + } +} diff --git a/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java new file mode 100644 index 000000000..bdbde7db8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java @@ -0,0 +1,41 @@ +package net.coderbot.iris.layer; + +import net.coderbot.iris.uniforms.CapturedRenderingState; + +public final class BlockEntityRenderStateShard extends RenderStateShard { + private static final BlockEntityRenderStateShard UNIDENTIFIED = new BlockEntityRenderStateShard(-1); + + private final int entityId; + + private BlockEntityRenderStateShard(int entityId) { + super("iris:is_block_entity", () -> { + CapturedRenderingState.INSTANCE.setCurrentBlockEntity(entityId); + GbufferPrograms.beginBlockEntities(); + }, () -> { + CapturedRenderingState.INSTANCE.setCurrentBlockEntity(-1); + GbufferPrograms.endBlockEntities(); + }); + + this.entityId = entityId; + } + + public static BlockEntityRenderStateShard forId(int entityId) { + if (entityId == -1) { + return UNIDENTIFIED; + } else { + // TODO: Cache all created render phases to avoid allocations? + return new BlockEntityRenderStateShard(entityId); + } + } + + @Override + public boolean equals(Object object) { + if (object == null || object.getClass() != this.getClass()) { + return false; + } + + BlockEntityRenderStateShard other = (BlockEntityRenderStateShard) object; + + return this.entityId == other.entityId; + } +} diff --git a/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java new file mode 100644 index 000000000..c4e648b76 --- /dev/null +++ b/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java @@ -0,0 +1,41 @@ +package net.coderbot.iris.layer; + +import net.coderbot.iris.uniforms.CapturedRenderingState; + +public final class EntityRenderStateShard extends RenderStateShard { + private static final EntityRenderStateShard UNIDENTIFIED = new EntityRenderStateShard(-1); + + private final int entityId; + + private EntityRenderStateShard(int entityId) { + super("iris:is_entity", () -> { + CapturedRenderingState.INSTANCE.setCurrentEntity(entityId); + GbufferPrograms.beginEntities(); + }, () -> { + CapturedRenderingState.INSTANCE.setCurrentEntity(-1); + GbufferPrograms.endEntities(); + }); + + this.entityId = entityId; + } + + public static EntityRenderStateShard forId(int entityId) { + if (entityId == -1) { + return UNIDENTIFIED; + } else { + // TODO: Cache all created render phases to avoid allocations? + return new EntityRenderStateShard(entityId); + } + } + + @Override + public boolean equals(Object object) { + if (object == null || object.getClass() != this.getClass()) { + return false; + } + + EntityRenderStateShard other = (EntityRenderStateShard) object; + + return this.entityId == other.entityId; + } +} diff --git a/src/main/java/net/coderbot/iris/layer/GbufferPrograms.java b/src/main/java/net/coderbot/iris/layer/GbufferPrograms.java new file mode 100644 index 000000000..42f048099 --- /dev/null +++ b/src/main/java/net/coderbot/iris/layer/GbufferPrograms.java @@ -0,0 +1,114 @@ +package net.coderbot.iris.layer; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; +import net.coderbot.iris.gl.state.StateUpdateNotifiers; +import net.coderbot.iris.pipeline.WorldRenderingPhase; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; + +public class GbufferPrograms { + private static boolean entities; + private static boolean blockEntities; + private static boolean outline; + private static Runnable phaseChangeListener; + + private static void checkReentrancy() { + if (entities || blockEntities || outline) { + throw new IllegalStateException("GbufferPrograms in weird state, tried to call begin function when entities = " + + entities + ", blockEntities = " + blockEntities + ", outline = " + outline); + } + } + + public static void beginEntities() { + checkReentrancy(); + setPhase(WorldRenderingPhase.ENTITIES); + entities = true; + } + + public static void endEntities() { + if (!entities) { + throw new IllegalStateException("GbufferPrograms in weird state, tried to call endEntities when entities = false"); + } + + setPhase(WorldRenderingPhase.NONE); + entities = false; + } + + public static void beginOutline() { + checkReentrancy(); + setPhase(WorldRenderingPhase.OUTLINE); + outline = true; + } + + public static void endOutline() { + if (!outline) { + throw new IllegalStateException("GbufferPrograms in weird state, tried to call endOutline when outline = false"); + } + + setPhase(WorldRenderingPhase.NONE); + outline = false; + } + + public static void beginBlockEntities() { + checkReentrancy(); + setPhase(WorldRenderingPhase.BLOCK_ENTITIES); + blockEntities = true; + } + + public static void endBlockEntities() { + if (!blockEntities) { + throw new IllegalStateException("GbufferPrograms in weird state, tried to call endBlockEntities when blockEntities = false"); + } + + setPhase(WorldRenderingPhase.NONE); + blockEntities = false; + } + + public static WorldRenderingPhase getCurrentPhase() { + WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); + + if (pipeline != null) { + return pipeline.getPhase(); + } else { + return WorldRenderingPhase.NONE; + } + } + + private static void setPhase(WorldRenderingPhase phase) { + WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); + + if (pipeline != null) { + pipeline.setPhase(phase); + } + } + + public static void setOverridePhase(WorldRenderingPhase phase) { + WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); + + if (pipeline != null) { + pipeline.setOverridePhase(phase); + } + } + + public static void runPhaseChangeNotifier() { + if (phaseChangeListener != null) { + phaseChangeListener.run(); + } + } + + public static void setupSpecialRenderCondition(SpecialCondition override) { + Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setSpecialCondition(override)); + } + + public static void teardownSpecialRenderCondition(SpecialCondition override) { + Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setSpecialCondition(null)); + } + + static { + StateUpdateNotifiers.phaseChangeNotifier = listener -> phaseChangeListener = listener; + } + + public static void init() { + // Empty initializer to run static + } +} diff --git a/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java new file mode 100644 index 000000000..9650bcfe5 --- /dev/null +++ b/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java @@ -0,0 +1,10 @@ +package net.coderbot.iris.layer; + + +public class IsBlockEntityRenderStateShard extends RenderStateShard { + public static final IsBlockEntityRenderStateShard INSTANCE = new IsBlockEntityRenderStateShard(); + + private IsBlockEntityRenderStateShard() { + super("iris:is_block_entity", GbufferPrograms::beginBlockEntities, GbufferPrograms::endBlockEntities); + } +} diff --git a/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java new file mode 100644 index 000000000..a0b262786 --- /dev/null +++ b/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java @@ -0,0 +1,10 @@ +package net.coderbot.iris.layer; + + +public class IsEntityRenderStateShard extends RenderStateShard { + public static final IsEntityRenderStateShard INSTANCE = new IsEntityRenderStateShard(); + + private IsEntityRenderStateShard() { + super("iris:is_entity", GbufferPrograms::beginEntities, GbufferPrograms::endEntities); + } +} diff --git a/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java new file mode 100644 index 000000000..21db48abe --- /dev/null +++ b/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java @@ -0,0 +1,10 @@ +package net.coderbot.iris.layer; + + +public class IsOutlineRenderStateShard extends RenderStateShard { + public static final IsOutlineRenderStateShard INSTANCE = new IsOutlineRenderStateShard(); + + private IsOutlineRenderStateShard() { + super("iris:is_outline", GbufferPrograms::beginOutline, GbufferPrograms::endOutline); + } +} diff --git a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java new file mode 100644 index 000000000..7a2d07c28 --- /dev/null +++ b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java @@ -0,0 +1,88 @@ +package net.coderbot.iris.layer; + +import net.coderbot.batchedentityrendering.impl.WrappableRenderType; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.Optional; + +public class OuterWrappedRenderType extends RenderType implements WrappableRenderType { + private final RenderStateShard extra; + private final RenderType wrapped; + + private OuterWrappedRenderType(String name, RenderType wrapped, RenderStateShard extra) { + super(name, wrapped.format(), wrapped.mode(), wrapped.bufferSize(), + wrapped.affectsCrumbling(), shouldSortOnUpload(wrapped), wrapped::setupRenderState, wrapped::clearRenderState); + + this.extra = extra; + this.wrapped = wrapped; + } + + public static OuterWrappedRenderType wrapExactlyOnce(String name, RenderType wrapped, RenderStateShard extra) { + if (wrapped instanceof OuterWrappedRenderType) { + wrapped = ((OuterWrappedRenderType) wrapped).unwrap(); + } + + return new OuterWrappedRenderType(name, wrapped, extra); + } + + @Override + public void setupRenderState() { + extra.setupRenderState(); + + super.setupRenderState(); + } + + @Override + public void clearRenderState() { + super.clearRenderState(); + + extra.clearRenderState(); + } + + @Override + public RenderType unwrap() { + return this.wrapped; + } + + @Override + public Optional outline() { + return this.wrapped.outline(); + } + + @Override + public boolean isOutline() { + return this.wrapped.isOutline(); + } + + @Override + public boolean equals(@Nullable Object object) { + if (object == null) { + return false; + } + + if (object.getClass() != this.getClass()) { + return false; + } + + OuterWrappedRenderType other = (OuterWrappedRenderType) object; + + return Objects.equals(this.wrapped, other.wrapped) && Objects.equals(this.extra, other.extra); + } + + @Override + public int hashCode() { + // Add one so that we don't have the exact same hash as the wrapped object. + // This means that we won't have a guaranteed collision if we're inserted to a map alongside the unwrapped object. + return this.wrapped.hashCode() + 1; + } + + @Override + public String toString() { + return "iris_wrapped:" + this.wrapped.toString(); + } + + private static boolean shouldSortOnUpload(RenderType type) { + return ((RenderTypeAccessor) type).shouldSortOnUpload(); + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/ClearPass.java b/src/main/java/net/coderbot/iris/pipeline/ClearPass.java new file mode 100644 index 000000000..0d2558715 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/ClearPass.java @@ -0,0 +1,46 @@ +package net.coderbot.iris.pipeline; + +import net.coderbot.iris.gl.framebuffer.GlFramebuffer; +import net.minecraft.client.Minecraft; +import org.joml.Vector4f; +import org.lwjgl.opengl.GL11; + +import java.util.Objects; +import java.util.function.IntSupplier; + +public class ClearPass { + private final Vector4f color; + private final IntSupplier viewportX; + private final IntSupplier viewportY; + private final GlFramebuffer framebuffer; + private final int clearFlags; + + public ClearPass(Vector4f color, IntSupplier viewportX, IntSupplier viewportY, GlFramebuffer framebuffer, int clearFlags) { + this.color = color; + this.viewportX = viewportX; + this.viewportY = viewportY; + this.framebuffer = framebuffer; + this.clearFlags = clearFlags; + } + + public void execute(Vector4f defaultClearColor) { + GL11.glViewport(0, 0, viewportX.getAsInt(), viewportY.getAsInt()); + framebuffer.bind(); + + Vector4f color = Objects.requireNonNull(defaultClearColor); + + if (this.color != null) { + color = this.color; + } + + GL11.glClearColor(color.x, color.y, color.z, color.w); + GL11.glClear(clearFlags); + if (Minecraft.isRunningOnMac) { + GL11.glGetError(); + } + } + + public GlFramebuffer getFramebuffer() { + return framebuffer; + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/ClearPassCreator.java b/src/main/java/net/coderbot/iris/pipeline/ClearPassCreator.java new file mode 100644 index 000000000..ef97bf4ed --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/ClearPassCreator.java @@ -0,0 +1,128 @@ +package net.coderbot.iris.pipeline; + +import com.google.common.collect.ImmutableList; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import net.coderbot.iris.rendertarget.RenderTarget; +import net.coderbot.iris.rendertarget.RenderTargets; +import net.coderbot.iris.shaderpack.PackRenderTargetDirectives; +import net.coderbot.iris.shaderpack.PackShadowDirectives; +import net.coderbot.iris.shadows.ShadowRenderTargets; +import org.joml.Vector2i; +import org.joml.Vector4f; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ClearPassCreator { + public static ImmutableList createClearPasses(RenderTargets renderTargets, boolean fullClear, + PackRenderTargetDirectives renderTargetDirectives) { + final int maxDrawBuffers = GL11.glGetInteger(GL20.GL_MAX_DRAW_BUFFERS); + + // Sort buffers by their clear color so we can group up glClear calls. + Map> clearByColor = new HashMap<>(); + + renderTargetDirectives.getRenderTargetSettings().forEach((bufferI, settings) -> { + // unboxed + final int buffer = bufferI; + + if (fullClear || settings.shouldClear()) { + Vector4f defaultClearColor; + + if (buffer == 0) { + // colortex0 is cleared to the fog color (with 1.0 alpha) by default. + defaultClearColor = null; + } else if (buffer == 1) { + // colortex1 is cleared to solid white (with 1.0 alpha) by default. + defaultClearColor = new Vector4f(1.0f, 1.0f, 1.0f, 1.0f); + } else { + // all other buffers are cleared to solid black (with 0.0 alpha) by default. + defaultClearColor = new Vector4f(0.0f, 0.0f, 0.0f, 0.0f); + } + + RenderTarget target = renderTargets.get(buffer); + Vector4f clearColor = settings.getClearColor().orElse(defaultClearColor); + clearByColor.computeIfAbsent(new Vector2i(target.getWidth(), target.getHeight()), size -> new HashMap<>()).computeIfAbsent(new ClearPassInformation(clearColor, target.getWidth(), target.getHeight()), color -> new IntArrayList()).add(buffer); + } + }); + + List clearPasses = new ArrayList<>(); + + clearByColor.forEach((passSize, vector4fIntListMap) -> { + vector4fIntListMap.forEach((clearInfo, buffers) -> { + int startIndex = 0; + + while (startIndex < buffers.size()) { + // clear up to the maximum number of draw buffers per each clear pass. + // This allows us to handle having more than 8 buffers with the same clear color on systems with + // a max draw buffers of 8 (ie, most systems). + int[] clearBuffers = new int[Math.min(buffers.size() - startIndex, maxDrawBuffers)]; + + for (int i = 0; i < clearBuffers.length; i++) { + clearBuffers[i] = buffers.getInt(startIndex); + startIndex++; + } + + // No need to clear the depth buffer, since we're using Minecraft's depth buffer. + clearPasses.add(new ClearPass(clearInfo.getColor(), clearInfo::getWidth, clearInfo::getHeight, + renderTargets.createClearFramebuffer(true, clearBuffers), GL11.GL_COLOR_BUFFER_BIT)); + + clearPasses.add(new ClearPass(clearInfo.getColor(), clearInfo::getWidth, clearInfo::getHeight, + renderTargets.createClearFramebuffer(false, clearBuffers), GL11.GL_COLOR_BUFFER_BIT)); + } + }); + }); + + return ImmutableList.copyOf(clearPasses); + } + + public static ImmutableList createShadowClearPasses(ShadowRenderTargets renderTargets, boolean fullClear, + PackShadowDirectives renderTargetDirectives) { + final int maxDrawBuffers = GL11.glGetInteger(GL20.GL_MAX_DRAW_BUFFERS); + + // Sort buffers by their clear color so we can group up glClear calls. + Map clearByColor = new HashMap<>(); + + for (int i = 0; i < renderTargetDirectives.getColorSamplingSettings().size(); i++) { + // unboxed + PackShadowDirectives.SamplingSettings settings = renderTargetDirectives.getColorSamplingSettings().get(i); + + if (fullClear || settings.getClear()) { + Vector4f clearColor = settings.getClearColor(); + clearByColor.computeIfAbsent(clearColor, color -> new IntArrayList()).add(i); + } + } + + List clearPasses = new ArrayList<>(); + + + clearByColor.forEach((clearColor, buffers) -> { + int startIndex = 0; + + while (startIndex < buffers.size()) { + // clear up to the maximum number of draw buffers per each clear pass. + // This allows us to handle having more than 8 buffers with the same clear color on systems with + // a max draw buffers of 8 (ie, most systems). + int[] clearBuffers = new int[Math.min(buffers.size() - startIndex, maxDrawBuffers)]; + + for (int i = 0; i < clearBuffers.length; i++) { + clearBuffers[i] = buffers.getInt(startIndex); + startIndex++; + } + + // No need to clear the depth buffer, since we're using Minecraft's depth buffer. + clearPasses.add(new ClearPass(clearColor, renderTargets::getResolution, renderTargets::getResolution, + renderTargets.createFramebufferWritingToAlt(clearBuffers), GL11.GL_COLOR_BUFFER_BIT)); + + clearPasses.add(new ClearPass(clearColor, renderTargets::getResolution, renderTargets::getResolution, + renderTargets.createFramebufferWritingToMain(clearBuffers), GL11.GL_COLOR_BUFFER_BIT)); + } + }); + + return ImmutableList.copyOf(clearPasses); + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/ClearPassInformation.java b/src/main/java/net/coderbot/iris/pipeline/ClearPassInformation.java new file mode 100644 index 000000000..42197a5dc --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/ClearPassInformation.java @@ -0,0 +1,38 @@ +package net.coderbot.iris.pipeline; + +import org.joml.Vector4f; + +public class ClearPassInformation { + private final Vector4f color; + private final int width; + private final int height; + + public ClearPassInformation(Vector4f vector4f, int width, int height) { + this.color = vector4f; + this.width = width; + this.height = height; + } + + public Vector4f getColor() { + return color; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ClearPassInformation)) { + return false; + } + + ClearPassInformation information = (ClearPassInformation) obj; + + return information.color.equals(this.color) && information.height == this.height && information.width == this.width; + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java b/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java new file mode 100644 index 000000000..bf8b49f1b --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java @@ -0,0 +1,176 @@ +package net.coderbot.iris.pipeline; + +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.coderbot.iris.Iris; +import net.coderbot.iris.rendertarget.NativeImageBackedCustomTexture; +import net.coderbot.iris.rendertarget.NativeImageBackedNoiseTexture; +import net.coderbot.iris.shaderpack.PackDirectives; +import net.coderbot.iris.shaderpack.texture.CustomTextureData; +import net.coderbot.iris.shaderpack.texture.TextureStage; +import net.coderbot.iris.texture.format.TextureFormat; +import net.coderbot.iris.texture.format.TextureFormatLoader; +import net.coderbot.iris.texture.pbr.PBRTextureHolder; +import net.coderbot.iris.texture.pbr.PBRTextureManager; +import net.coderbot.iris.texture.pbr.PBRType; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.util.ResourceLocation; +import org.apache.commons.io.FilenameUtils; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Optional; +import java.util.function.IntSupplier; + +public class CustomTextureManager { + private final EnumMap> customTextureIdMap = new EnumMap<>(TextureStage.class); + private final IntSupplier noise; + + /** + * List of all OpenGL texture objects owned by this CustomTextureManager that need to be deleted in order to avoid + * leaks. + * Make sure any textures added to this list call releaseId from the close method. + */ + private final List ownedTextures = new ArrayList<>(); + + public CustomTextureManager(PackDirectives packDirectives, + EnumMap> customTextureDataMap, + Optional customNoiseTextureData) { + customTextureDataMap.forEach((textureStage, customTextureStageDataMap) -> { + Object2ObjectMap customTextureIds = new Object2ObjectOpenHashMap<>(); + + customTextureStageDataMap.forEach((samplerName, textureData) -> { + try { + customTextureIds.put(samplerName, createCustomTexture(textureData)); + } catch (IOException e) { + Iris.logger.error("Unable to parse the image data for the custom texture on stage " + + textureStage + ", sampler " + samplerName, e); + } + }); + + customTextureIdMap.put(textureStage, customTextureIds); + }); + + noise = customNoiseTextureData.flatMap(textureData -> { + try { + return Optional.of(createCustomTexture(textureData)); + } catch (IOException e) { + Iris.logger.error("Unable to parse the image data for the custom noise texture", e); + + return Optional.empty(); + } + }).orElseGet(() -> { + final int noiseTextureResolution = packDirectives.getNoiseTextureResolution(); + + AbstractTexture texture = new NativeImageBackedNoiseTexture(noiseTextureResolution); + ownedTextures.add(texture); + + return texture::getGlTextureId; + }); + } + + private IntSupplier createCustomTexture(CustomTextureData textureData) throws IOException { + if (textureData instanceof CustomTextureData.PngData) { + AbstractTexture texture = new NativeImageBackedCustomTexture((CustomTextureData.PngData) textureData); + ownedTextures.add(texture); + + return texture::getGlTextureId; + } else if (textureData instanceof CustomTextureData.LightmapMarker) { + // Special code path for the light texture. While shader packs hardcode the primary light texture, it's + // possible that a mod will create a different light texture, so this code path is robust to that. + return () -> + ((LightTextureAccessor) Minecraft.getMinecraft().gameRenderer.lightTexture()) + .getLightTexture().getId(); + } else if (textureData instanceof CustomTextureData.ResourceData) { + CustomTextureData.ResourceData resourceData = (CustomTextureData.ResourceData) textureData; + String namespace = resourceData.getNamespace(); + String location = resourceData.getLocation(); + + String withoutExtension; + int extensionIndex = FilenameUtils.indexOfExtension(location); + if (extensionIndex != -1) { + withoutExtension = location.substring(0, extensionIndex); + } else { + withoutExtension = location; + } + PBRType pbrType = PBRType.fromFileLocation(withoutExtension); + + TextureManager textureManager = Minecraft.getMinecraft().getTextureManager(); + + if (pbrType == null) { + ResourceLocation textureLocation = new ResourceLocation(namespace, location); + + // NB: We have to re-query the TextureManager for the texture object every time. This is because the + // AbstractTexture object could be removed / deleted from the TextureManager on resource reloads, + // and we could end up holding on to a deleted texture unless we added special code to handle resource + // reloads. Re-fetching the texture from the TextureManager every time is the most robust approach for + // now. + return () -> { + AbstractTexture texture = textureManager.getTexture(textureLocation); + + // TODO: Should we give something else if the texture isn't there? This will need some thought + return texture != null ? texture.getId() : MissingTextureAtlasSprite.getTexture().getId(); + }; + } else { + location = location.substring(0, extensionIndex - pbrType.getSuffix().length()) + location.substring(extensionIndex); + ResourceLocation textureLocation = new ResourceLocation(namespace, location); + + return () -> { + AbstractTexture texture = textureManager.getTexture(textureLocation); + + if (texture != null) { + int id = texture.getGlTextureId(); + PBRTextureHolder pbrHolder = PBRTextureManager.INSTANCE.getOrLoadHolder(id); + AbstractTexture pbrTexture; + switch (pbrType) { + case NORMAL: + pbrTexture = pbrHolder.getNormalTexture(); + break; + case SPECULAR: + pbrTexture = pbrHolder.getSpecularTexture(); + break; + default: + throw new Error("Unknown PBRType '" + pbrType + "'"); + } + + TextureFormat textureFormat = TextureFormatLoader.getFormat(); + if (textureFormat != null) { + int previousBinding = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, pbrTexture.getGlTextureId()); + textureFormat.setupTextureParameters(pbrType, pbrTexture); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, previousBinding); + } + + return pbrTexture.getGlTextureId(); + } + + return MissingTextureAtlasSprite.getTexture().getId(); + }; + } + } else { + throw new IllegalArgumentException("Unable to handle custom texture data " + textureData); + } + } + + public EnumMap> getCustomTextureIdMap() { + return customTextureIdMap; + } + + public Object2ObjectMap getCustomTextureIdMap(TextureStage stage) { + return customTextureIdMap.getOrDefault(stage, Object2ObjectMaps.emptyMap()); + } + + public IntSupplier getNoiseTexture() { + return noise; + } + + public void destroy() { + ownedTextures.forEach(AbstractTexture::close); + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java new file mode 100644 index 000000000..f72068a71 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -0,0 +1,1269 @@ +package net.coderbot.iris.pipeline; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.primitives.Ints; +import net.coderbot.iris.Iris; +import net.coderbot.iris.block_rendering.BlockMaterialMapping; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; +import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; +import net.coderbot.iris.gbuffer_overrides.matching.ProgramTable; +import net.coderbot.iris.gbuffer_overrides.matching.RenderCondition; +import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; +import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; +import net.coderbot.iris.gl.blending.AlphaTestOverride; +import net.coderbot.iris.gl.blending.BlendModeOverride; +import net.coderbot.iris.gl.blending.BufferBlendOverride; +import net.coderbot.iris.gl.framebuffer.GlFramebuffer; +import net.coderbot.iris.gl.program.ComputeProgram; +import net.coderbot.iris.gl.program.Program; +import net.coderbot.iris.gl.program.ProgramBuilder; +import net.coderbot.iris.gl.program.ProgramImages; +import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.texture.DepthBufferFormat; +import net.coderbot.iris.layer.GbufferPrograms; +import net.coderbot.iris.pipeline.transform.PatchShaderType; +import net.coderbot.iris.pipeline.transform.TransformPatcher; +import net.coderbot.iris.postprocess.BufferFlipper; +import net.coderbot.iris.postprocess.CenterDepthSampler; +import net.coderbot.iris.postprocess.CompositeRenderer; +import net.coderbot.iris.postprocess.FinalPassRenderer; +import net.coderbot.iris.rendertarget.Blaze3dRenderTargetExt; +import net.coderbot.iris.rendertarget.NativeImageBackedSingleColorTexture; +import net.coderbot.iris.rendertarget.RenderTarget; +import net.coderbot.iris.rendertarget.RenderTargets; +import net.coderbot.iris.samplers.IrisImages; +import net.coderbot.iris.samplers.IrisSamplers; +import net.coderbot.iris.shaderpack.CloudSetting; +import net.coderbot.iris.shaderpack.ComputeSource; +import net.coderbot.iris.shaderpack.IdMap; +import net.coderbot.iris.shaderpack.OptionalBoolean; +import net.coderbot.iris.shaderpack.PackDirectives; +import net.coderbot.iris.shaderpack.PackShadowDirectives; +import net.coderbot.iris.shaderpack.ProgramDirectives; +import net.coderbot.iris.shaderpack.ProgramFallbackResolver; +import net.coderbot.iris.shaderpack.ProgramSet; +import net.coderbot.iris.shaderpack.ProgramSource; +import net.coderbot.iris.shaderpack.loading.ProgramId; +import net.coderbot.iris.shaderpack.texture.TextureStage; +import net.coderbot.iris.shadows.ShadowRenderTargets; +import net.coderbot.iris.texture.TextureInfoCache; +import net.coderbot.iris.texture.format.TextureFormat; +import net.coderbot.iris.texture.format.TextureFormatLoader; +import net.coderbot.iris.texture.pbr.PBRTextureHolder; +import net.coderbot.iris.texture.pbr.PBRTextureManager; +import net.coderbot.iris.texture.pbr.PBRType; +import net.coderbot.iris.uniforms.CapturedRenderingState; +import net.coderbot.iris.uniforms.CommonUniforms; +import net.coderbot.iris.uniforms.FrameUpdateNotifier; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.texture.AbstractTexture; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3d; +import org.joml.Vector4f; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL30; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.Set; +import java.util.function.IntFunction; +import java.util.function.Supplier; + +/** + * Encapsulates the compiled shader program objects for the currently loaded shaderpack. + */ +public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, RenderTargetStateListener { + private final RenderTargets renderTargets; + + @Nullable + private ShadowRenderTargets shadowRenderTargets; + @Nullable + private ComputeProgram[] shadowComputes; + private final Supplier shadowTargetsSupplier; + + private final ProgramTable table; + + private ImmutableList clearPassesFull; + private ImmutableList clearPasses; + private ImmutableList shadowClearPasses; + private ImmutableList shadowClearPassesFull; + + private final CompositeRenderer prepareRenderer; + + @Nullable + private final ShadowRenderer shadowRenderer; + + private final int shadowMapResolution; + private final CompositeRenderer deferredRenderer; + private final CompositeRenderer compositeRenderer; + private final FinalPassRenderer finalPassRenderer; + private final CustomTextureManager customTextureManager; + private final AbstractTexture whitePixel; + private final FrameUpdateNotifier updateNotifier; + private final CenterDepthSampler centerDepthSampler; + + private final ImmutableSet flippedBeforeShadow; + private final ImmutableSet flippedAfterPrepare; + private final ImmutableSet flippedAfterTranslucent; + + private final SodiumTerrainPipeline sodiumTerrainPipeline; + + private final HorizonRenderer horizonRenderer = new HorizonRenderer(); + + private final float sunPathRotation; + private final CloudSetting cloudSetting; + private final boolean shouldRenderUnderwaterOverlay; + private final boolean shouldRenderVignette; + private final boolean shouldRenderSun; + private final boolean shouldRenderMoon; + private final boolean shouldWriteRainAndSnowToDepthBuffer; + private final boolean shouldRenderParticlesBeforeDeferred; + private final boolean shouldRenderPrepareBeforeShadow; + private final boolean oldLighting; + private final boolean allowConcurrentCompute; + private final OptionalInt forcedShadowRenderDistanceChunks; + + private Pass current = null; + + private WorldRenderingPhase overridePhase = null; + private WorldRenderingPhase phase = WorldRenderingPhase.NONE; + private boolean isBeforeTranslucent; + private boolean isRenderingShadow = false; + private InputAvailability inputs = new InputAvailability(false, false, false); + private SpecialCondition special = null; + + private boolean shouldBindPBR; + private int currentNormalTexture; + private int currentSpecularTexture; + private PackDirectives packDirectives; + + public DeferredWorldRenderingPipeline(ProgramSet programs) { + Objects.requireNonNull(programs); + + this.cloudSetting = programs.getPackDirectives().getCloudSetting(); + this.shouldRenderUnderwaterOverlay = programs.getPackDirectives().underwaterOverlay(); + this.shouldRenderVignette = programs.getPackDirectives().vignette(); + this.shouldRenderSun = programs.getPackDirectives().shouldRenderSun(); + this.shouldRenderMoon = programs.getPackDirectives().shouldRenderMoon(); + this.shouldWriteRainAndSnowToDepthBuffer = programs.getPackDirectives().rainDepth(); + this.shouldRenderParticlesBeforeDeferred = programs.getPackDirectives().areParticlesBeforeDeferred(); + this.allowConcurrentCompute = programs.getPackDirectives().getConcurrentCompute(); + this.shouldRenderPrepareBeforeShadow = programs.getPackDirectives().isPrepareBeforeShadow(); + this.oldLighting = programs.getPackDirectives().isOldLighting(); + this.updateNotifier = new FrameUpdateNotifier(); + + this.packDirectives = programs.getPackDirectives(); + + RenderTarget mainTarget = Minecraft.getMinecraft().getMainRenderTarget(); + + int depthTextureId = mainTarget.getDepthTextureId(); + int internalFormat = TextureInfoCache.INSTANCE.getInfo(depthTextureId).getInternalFormat(); + DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); + + this.renderTargets = new RenderTargets(mainTarget.width, mainTarget.height, depthTextureId, + ((Blaze3dRenderTargetExt) mainTarget).iris$getDepthBufferVersion(), + depthBufferFormat, programs.getPackDirectives().getRenderTargetDirectives().getRenderTargetSettings(), programs.getPackDirectives()); + + this.sunPathRotation = programs.getPackDirectives().getSunPathRotation(); + + PackShadowDirectives shadowDirectives = programs.getPackDirectives().getShadowDirectives(); + + if (shadowDirectives.isDistanceRenderMulExplicit()) { + if (shadowDirectives.getDistanceRenderMul() >= 0.0) { + // add 15 and then divide by 16 to ensure we're rounding up + forcedShadowRenderDistanceChunks = + OptionalInt.of(((int) (shadowDirectives.getDistance() * shadowDirectives.getDistanceRenderMul()) + 15) / 16); + } else { + forcedShadowRenderDistanceChunks = OptionalInt.of(-1); + } + } else { + forcedShadowRenderDistanceChunks = OptionalInt.empty(); + } + + BlockRenderingSettings.INSTANCE.setBlockStateIds( + BlockMaterialMapping.createBlockStateIdMap(programs.getPack().getIdMap().getBlockProperties())); + BlockRenderingSettings.INSTANCE.setBlockTypeIds(BlockMaterialMapping.createBlockTypeMap(programs.getPack().getIdMap().getBlockRenderTypeMap())); + + BlockRenderingSettings.INSTANCE.setEntityIds(programs.getPack().getIdMap().getEntityIdMap()); + BlockRenderingSettings.INSTANCE.setAmbientOcclusionLevel(programs.getPackDirectives().getAmbientOcclusionLevel()); + BlockRenderingSettings.INSTANCE.setDisableDirectionalShading(shouldDisableDirectionalShading()); + BlockRenderingSettings.INSTANCE.setUseSeparateAo(programs.getPackDirectives().shouldUseSeparateAo()); + BlockRenderingSettings.INSTANCE.setUseExtendedVertexFormat(true); + + // Don't clobber anything in texture unit 0. It probably won't cause issues, but we're just being cautious here. + GL13.glActiveTexture(GL13.GL_TEXTURE2); + + customTextureManager = new CustomTextureManager(programs.getPackDirectives(), programs.getPack().getCustomTextureDataMap(), programs.getPack().getCustomNoiseTexture()); + + whitePixel = new NativeImageBackedSingleColorTexture(255, 255, 255, 255); + + GL13.glActiveTexture(GL13.GL_TEXTURE0); + + this.flippedBeforeShadow = ImmutableSet.of(); + + BufferFlipper flipper = new BufferFlipper(); + + this.centerDepthSampler = new CenterDepthSampler(() -> getRenderTargets().getDepthTexture(), programs.getPackDirectives().getCenterDepthHalfLife()); + + this.shadowMapResolution = programs.getPackDirectives().getShadowDirectives().getResolution(); + + this.shadowTargetsSupplier = () -> { + if (shadowRenderTargets == null) { + this.shadowRenderTargets = new ShadowRenderTargets(shadowMapResolution, shadowDirectives); + } + + return shadowRenderTargets; + }; + + PatchedShaderPrinter.resetPrintState(); + + this.prepareRenderer = new CompositeRenderer(programs.getPackDirectives(), programs.getPrepare(), programs.getPrepareCompute(), renderTargets, + customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, flipper, shadowTargetsSupplier, + customTextureManager.getCustomTextureIdMap(TextureStage.PREPARE), + programs.getPackDirectives().getExplicitFlips("prepare_pre")); + + flippedAfterPrepare = flipper.snapshot(); + + this.deferredRenderer = new CompositeRenderer(programs.getPackDirectives(), programs.getDeferred(), programs.getDeferredCompute(), renderTargets, + customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, flipper, shadowTargetsSupplier, + customTextureManager.getCustomTextureIdMap(TextureStage.DEFERRED), + programs.getPackDirectives().getExplicitFlips("deferred_pre")); + + flippedAfterTranslucent = flipper.snapshot(); + + this.compositeRenderer = new CompositeRenderer(programs.getPackDirectives(), programs.getComposite(), programs.getCompositeCompute(), renderTargets, + customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, flipper, shadowTargetsSupplier, + customTextureManager.getCustomTextureIdMap(TextureStage.COMPOSITE_AND_FINAL), + programs.getPackDirectives().getExplicitFlips("composite_pre")); + this.finalPassRenderer = new FinalPassRenderer(programs, renderTargets, customTextureManager.getNoiseTexture(), updateNotifier, flipper.snapshot(), + centerDepthSampler, shadowTargetsSupplier, + customTextureManager.getCustomTextureIdMap(TextureStage.COMPOSITE_AND_FINAL), + this.compositeRenderer.getFlippedAtLeastOnceFinal()); + + // [(textured=false,lightmap=false), (textured=true,lightmap=false), (textured=true,lightmap=true)] + ProgramId[] ids = new ProgramId[] { + ProgramId.Basic, ProgramId.Textured, ProgramId.TexturedLit, + ProgramId.SkyBasic, ProgramId.SkyTextured, ProgramId.SkyTextured, + null, null, ProgramId.Terrain, + null, null, ProgramId.Water, + null, ProgramId.Clouds, ProgramId.Clouds, + null, ProgramId.DamagedBlock, ProgramId.DamagedBlock, + ProgramId.Block, ProgramId.Block, ProgramId.Block, + ProgramId.BeaconBeam, ProgramId.BeaconBeam, ProgramId.BeaconBeam, + ProgramId.Entities, ProgramId.Entities, ProgramId.Entities, + ProgramId.EntitiesTrans, ProgramId.EntitiesTrans, ProgramId.EntitiesTrans, + null, ProgramId.ArmorGlint, ProgramId.ArmorGlint, + null, ProgramId.SpiderEyes, ProgramId.SpiderEyes, + ProgramId.Hand, ProgramId.Hand, ProgramId.Hand, + ProgramId.HandWater, ProgramId.HandWater, ProgramId.HandWater, + null, null, ProgramId.Weather, + // world border uses textured_lit even though it has no lightmap :/ + null, ProgramId.TexturedLit, ProgramId.TexturedLit, + ProgramId.Shadow, ProgramId.Shadow, ProgramId.Shadow + }; + + if (ids.length != RenderCondition.values().length * 3) { + throw new IllegalStateException("Program ID table length mismatch"); + } + + ProgramFallbackResolver resolver = new ProgramFallbackResolver(programs); + + Map, Pass> cachedPasses = new HashMap<>(); + + this.shadowComputes = createShadowComputes(programs.getShadowCompute(), programs); + + this.table = new ProgramTable<>((condition, availability) -> { + int idx; + + if (availability.texture && availability.lightmap) { + idx = 2; + } else if (availability.texture) { + idx = 1; + } else { + idx = 0; + } + + ProgramId id = ids[condition.ordinal() * 3 + idx]; + + if (id == null) { + id = ids[idx]; + } + + ProgramId finalId = id; + + return cachedPasses.computeIfAbsent(Pair.of(id, availability), p -> { + ProgramSource source = resolver.resolveNullable(p.getLeft()); + + if (condition == RenderCondition.SHADOW) { + if (!shadowDirectives.isShadowEnabled().orElse(shadowRenderTargets != null)) { + // shadow is not used + return null; + } else if (source == null) { + // still need the custom framebuffer, viewport, and blend mode behavior + GlFramebuffer shadowFb = + shadowTargetsSupplier.get().createShadowFramebuffer(shadowRenderTargets.snapshot(), new int[] {0}); + return new Pass(null, shadowFb, shadowFb, null, + BlendModeOverride.OFF, Collections.emptyList(), true); + } + } + + if (source == null) { + return createDefaultPass(); + } + + try { + return createPass(source, availability, condition == RenderCondition.SHADOW, finalId); + } catch (Exception e) { + throw new RuntimeException("Failed to create pass for " + source.getName() + " for rendering condition " + + condition + " specialized to input availability " + availability, e); + } + }); + }); + + if (shadowRenderTargets == null && shadowDirectives.isShadowEnabled() == OptionalBoolean.TRUE) { + shadowRenderTargets = new ShadowRenderTargets(shadowMapResolution, shadowDirectives); + } + + if (shadowRenderTargets != null) { + this.shadowClearPasses = ClearPassCreator.createShadowClearPasses(shadowRenderTargets, false, shadowDirectives); + this.shadowClearPassesFull = ClearPassCreator.createShadowClearPasses(shadowRenderTargets, true, shadowDirectives); + + if (programs.getPackDirectives().getShadowDirectives().isShadowEnabled().orElse(true)) { + this.shadowRenderer = new ShadowRenderer(programs.getShadow().orElse(null), + programs.getPackDirectives(), shadowRenderTargets); + Program shadowProgram = table.match(RenderCondition.SHADOW, new InputAvailability(true, true, true)).getProgram(); + shadowRenderer.setUsesImages(shadowProgram != null && shadowProgram.getActiveImages() > 0); + } else { + shadowRenderer = null; + } + } else { + this.shadowClearPasses = ImmutableList.of(); + this.shadowClearPassesFull = ImmutableList.of(); + this.shadowRenderer = null; + } + + this.clearPassesFull = ClearPassCreator.createClearPasses(renderTargets, true, + programs.getPackDirectives().getRenderTargetDirectives()); + this.clearPasses = ClearPassCreator.createClearPasses(renderTargets, false, + programs.getPackDirectives().getRenderTargetDirectives()); + + // SodiumTerrainPipeline setup follows. + + Supplier> flipped = + () -> isBeforeTranslucent ? flippedAfterPrepare : flippedAfterTranslucent; + + IntFunction createTerrainSamplers = (programId) -> { + ProgramSamplers.Builder builder = ProgramSamplers.builder(programId, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS); + ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureManager.getCustomTextureIdMap(TextureStage.GBUFFERS_AND_SHADOW)); + + IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false); + IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true, false)); + IrisSamplers.addWorldDepthSamplers(customTextureSamplerInterceptor, renderTargets); + IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture()); + + if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { + IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, Objects.requireNonNull(shadowRenderTargets)); + } + + return builder.build(); + }; + + IntFunction createTerrainImages = (programId) -> { + ProgramImages.Builder builder = ProgramImages.builder(programId); + + IrisImages.addRenderTargetImages(builder, flipped, renderTargets); + + if (IrisImages.hasShadowImages(builder)) { + IrisImages.addShadowColorImages(builder, Objects.requireNonNull(shadowRenderTargets)); + } + + return builder.build(); + }; + + IntFunction createShadowTerrainSamplers = (programId) -> { + ProgramSamplers.Builder builder = ProgramSamplers.builder(programId, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS); + ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureManager.getCustomTextureIdMap(TextureStage.GBUFFERS_AND_SHADOW)); + + IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flippedAfterPrepare, renderTargets, false); + IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true, false)); + IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture()); + + // Only initialize these samplers if the shadow map renderer exists. + // Otherwise, this program shouldn't be used at all? + if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { + IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, Objects.requireNonNull(shadowRenderTargets)); + } + + return builder.build(); + }; + + IntFunction createShadowTerrainImages = (programId) -> { + ProgramImages.Builder builder = ProgramImages.builder(programId); + + IrisImages.addRenderTargetImages(builder, () -> flippedAfterPrepare, renderTargets); + + if (IrisImages.hasShadowImages(builder)) { + IrisImages.addShadowColorImages(builder, Objects.requireNonNull(shadowRenderTargets)); + } + + return builder.build(); + }; + + this.sodiumTerrainPipeline = new SodiumTerrainPipeline(this, programs, createTerrainSamplers, + shadowRenderer == null ? null : createShadowTerrainSamplers, createTerrainImages, + shadowRenderer == null ? null : createShadowTerrainImages); + } + + private RenderTargets getRenderTargets() { + return renderTargets; + } + + private void checkWorld() { + // If we're not in a world, then obviously we cannot possibly be rendering a world. + if (Minecraft.getMinecraft().theWorld == null) { + isRenderingWorld = false; + current = null; + } + } + + @Override + public boolean shouldDisableVanillaEntityShadows() { + // OptiFine seems to disable vanilla shadows when the shaderpack uses shadow mapping? + return shadowRenderer != null; + } + + @Override + public boolean shouldDisableDirectionalShading() { + return !oldLighting; + } + + @Override + public CloudSetting getCloudSetting() { + return cloudSetting; + } + + @Override + public boolean shouldRenderUnderwaterOverlay() { + return shouldRenderUnderwaterOverlay; + } + + @Override + public boolean shouldRenderVignette() { + return shouldRenderVignette; + } + + @Override + public boolean shouldRenderSun() { + return shouldRenderSun; + } + + @Override + public boolean shouldRenderMoon() { + return shouldRenderMoon; + } + + @Override + public boolean shouldWriteRainAndSnowToDepthBuffer() { + return shouldWriteRainAndSnowToDepthBuffer; + } + + @Override + public boolean shouldRenderParticlesBeforeDeferred() { + return shouldRenderParticlesBeforeDeferred; + } + + @Override + public boolean allowConcurrentCompute() { + return allowConcurrentCompute; + } + + @Override + public float getSunPathRotation() { + return sunPathRotation; + } + + private RenderCondition getCondition(WorldRenderingPhase phase) { + if (isRenderingShadow) { + return RenderCondition.SHADOW; + } + + if (special != null) { + if (special == SpecialCondition.BEACON_BEAM) { + return RenderCondition.BEACON_BEAM; + } else if (special == SpecialCondition.ENTITY_EYES) { + return RenderCondition.ENTITY_EYES; + } else if (special == SpecialCondition.GLINT) { + return RenderCondition.GLINT; + } + } + + switch (phase) { + case NONE: + case OUTLINE: + case DEBUG: + case PARTICLES: + return RenderCondition.DEFAULT; + case SKY: + case SUNSET: + case CUSTOM_SKY: + case SUN: + case MOON: + case STARS: + case VOID: + return RenderCondition.SKY; + case TERRAIN_SOLID: + case TERRAIN_CUTOUT: + case TERRAIN_CUTOUT_MIPPED: + return RenderCondition.TERRAIN_OPAQUE; + case ENTITIES: + if (GlStateManagerAccessor.getBLEND().srcRgb == GlStateManager.SourceFactor.SRC_ALPHA.value && GlStateManagerAccessor.getBLEND().dstRgb == GlStateManager.SourceFactor.ONE_MINUS_SRC_ALPHA.value && GlStateManagerAccessor.getBLEND().srcAlpha == GlStateManager.SourceFactor.ONE.value && GlStateManagerAccessor.getBLEND().dstAlpha == GlStateManager.SourceFactor.ONE_MINUS_SRC_ALPHA.value) { + return RenderCondition.ENTITIES_TRANSLUCENT; + } else { + return RenderCondition.ENTITIES; + } + case BLOCK_ENTITIES: + return RenderCondition.BLOCK_ENTITIES; + case DESTROY: + return RenderCondition.DESTROY; + case HAND_SOLID: + return RenderCondition.HAND_OPAQUE; + case TERRAIN_TRANSLUCENT: + case TRIPWIRE: + return RenderCondition.TERRAIN_TRANSLUCENT; + case CLOUDS: + return RenderCondition.CLOUDS; + case RAIN_SNOW: + return RenderCondition.RAIN_SNOW; + case HAND_TRANSLUCENT: + return RenderCondition.HAND_TRANSLUCENT; + case WORLD_BORDER: + return RenderCondition.WORLD_BORDER; + default: + throw new IllegalStateException("Unknown render phase " + phase); + } + } + + private void matchPass() { + if (!isRenderingWorld || isRenderingFullScreenPass || isPostChain || !isMainBound) { + return; + } + + if (sodiumTerrainRendering) { + beginPass(table.match(getCondition(getPhase()), new InputAvailability(true, true, false))); + return; + } + + beginPass(table.match(getCondition(getPhase()), inputs)); + } + + public void beginPass(Pass pass) { + if (current == pass) { + return; + } + + if (current != null) { + current.stopUsing(); + } + + current = pass; + + if (pass != null) { + pass.use(); + } else { + Program.unbind(); + } + } + + private Pass createDefaultPass() { + GlFramebuffer framebufferBeforeTranslucents; + GlFramebuffer framebufferAfterTranslucents; + + framebufferBeforeTranslucents = + renderTargets.createGbufferFramebuffer(flippedAfterPrepare, new int[] {0}); + framebufferAfterTranslucents = + renderTargets.createGbufferFramebuffer(flippedAfterTranslucent, new int[] {0}); + + return new Pass(null, framebufferBeforeTranslucents, framebufferAfterTranslucents, null, + null, Collections.emptyList(), false); + } + + private Pass createPass(ProgramSource source, InputAvailability availability, boolean shadow, ProgramId id) { + // TODO: Properly handle empty shaders? + Map transformed = TransformPatcher.patchAttributes( + source.getVertexSource().orElseThrow(NullPointerException::new), + source.getGeometrySource().orElse(null), + source.getFragmentSource().orElseThrow(NullPointerException::new), + availability); + String vertex = transformed.get(PatchShaderType.VERTEX); + String geometry = transformed.get(PatchShaderType.GEOMETRY); + String fragment = transformed.get(PatchShaderType.FRAGMENT); + + PatchedShaderPrinter.debugPatchedShaders(source.getName(), vertex, geometry, fragment); + + ProgramBuilder builder = ProgramBuilder.begin(source.getName(), vertex, geometry, fragment, + IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS); + + return createPassInner(builder, source.getParent().getPack().getIdMap(), source.getDirectives(), source.getParent().getPackDirectives(), availability, shadow, id); + } + + private Pass createPassInner(ProgramBuilder builder, IdMap map, ProgramDirectives programDirectives, + PackDirectives packDirectives, InputAvailability availability, boolean shadow, ProgramId id) { + + CommonUniforms.addCommonUniforms(builder, map, packDirectives, updateNotifier); + + Supplier> flipped; + + if (shadow) { + flipped = () -> (shouldRenderPrepareBeforeShadow ? flippedAfterPrepare : flippedBeforeShadow); + } else { + flipped = () -> isBeforeTranslucent ? flippedAfterPrepare : flippedAfterTranslucent; + } + + TextureStage textureStage = TextureStage.GBUFFERS_AND_SHADOW; + + ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = + ProgramSamplers.customTextureSamplerInterceptor(builder, + customTextureManager.getCustomTextureIdMap(textureStage)); + + IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false); + IrisImages.addRenderTargetImages(builder, flipped, renderTargets); + + if (!shouldBindPBR) { + shouldBindPBR = IrisSamplers.hasPBRSamplers(customTextureSamplerInterceptor); + } + + IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, availability); + + if (!shadow) { + IrisSamplers.addWorldDepthSamplers(customTextureSamplerInterceptor, renderTargets); + } + + IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture()); + + if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { + if (!shadow) { + shadowTargetsSupplier.get(); + } + + if (shadowRenderTargets != null) { + IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowRenderTargets); + IrisImages.addShadowColorImages(builder, shadowRenderTargets); + } + } + + GlFramebuffer framebufferBeforeTranslucents; + GlFramebuffer framebufferAfterTranslucents; + + if (shadow) { + // Always add both draw buffers on the shadow pass. + framebufferBeforeTranslucents = + shadowTargetsSupplier.get().createShadowFramebuffer(shadowRenderTargets.snapshot(), new int[] { 0, 1 }); + framebufferAfterTranslucents = framebufferBeforeTranslucents; + } else { + framebufferBeforeTranslucents = + renderTargets.createGbufferFramebuffer(flippedAfterPrepare, programDirectives.getDrawBuffers()); + framebufferAfterTranslucents = + renderTargets.createGbufferFramebuffer(flippedAfterTranslucent, programDirectives.getDrawBuffers()); + } + + builder.bindAttributeLocation(11, "mc_Entity"); + builder.bindAttributeLocation(12, "mc_midTexCoord"); + builder.bindAttributeLocation(13, "at_tangent"); + builder.bindAttributeLocation(14, "at_midBlock"); + + AlphaTestOverride alphaTestOverride = programDirectives.getAlphaTestOverride().orElse(null); + + List bufferOverrides = new ArrayList<>(); + + programDirectives.getBufferBlendOverrides().forEach(information -> { + int index = Ints.indexOf(programDirectives.getDrawBuffers(), information.getIndex()); + if (index > -1) { + bufferOverrides.add(new BufferBlendOverride(index, information.getBlendMode())); + } + }); + + return new Pass(builder.build(), framebufferBeforeTranslucents, framebufferAfterTranslucents, alphaTestOverride, + programDirectives.getBlendModeOverride().orElse(id.getBlendModeOverride()), bufferOverrides, shadow); + } + + private boolean isPostChain; + private boolean isMainBound = true; + + @Override + public void beginPostChain() { + isPostChain = true; + + beginPass(null); + } + + @Override + public void endPostChain() { + isPostChain = false; + } + + @Override + public void setIsMainBound(boolean bound) { + isMainBound = bound; + + if (!isRenderingWorld || isRenderingFullScreenPass || isPostChain) { + return; + } + + if (bound) { + // force refresh + current = null; + } else { + beginPass(null); + } + } + + private final class Pass { + @Nullable + private final Program program; + private final GlFramebuffer framebufferBeforeTranslucents; + private final GlFramebuffer framebufferAfterTranslucents; + @Nullable + private final AlphaTestOverride alphaTestOverride; + @Nullable + private final BlendModeOverride blendModeOverride; + @Nullable + private final List bufferBlendOverrides; + private final boolean shadowViewport; + + private Pass(@Nullable Program program, GlFramebuffer framebufferBeforeTranslucents, GlFramebuffer framebufferAfterTranslucents, + @Nullable AlphaTestOverride alphaTestOverride, @Nullable BlendModeOverride blendModeOverride, @Nullable List bufferBlendOverrides, boolean shadowViewport) { + this.program = program; + this.framebufferBeforeTranslucents = framebufferBeforeTranslucents; + this.framebufferAfterTranslucents = framebufferAfterTranslucents; + this.alphaTestOverride = alphaTestOverride; + this.blendModeOverride = blendModeOverride; + this.bufferBlendOverrides = bufferBlendOverrides; + this.shadowViewport = shadowViewport; + } + + public void use() { + if (isBeforeTranslucent) { + framebufferBeforeTranslucents.bind(); + } else { + framebufferAfterTranslucents.bind(); + } + + if (shadowViewport) { + GL11.glViewport(0, 0, shadowMapResolution, shadowMapResolution); + } else { + RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); + GL11.glViewport(0, 0, main.width, main.height); + } + + if (program != null && !sodiumTerrainRendering) { + program.use(); + } + + if (alphaTestOverride != null) { + alphaTestOverride.apply(); + } else { + // Previous program on the stack might have applied an override + AlphaTestOverride.restore(); + } + + if (blendModeOverride != null) { + blendModeOverride.apply(); + } else { + // Previous program on the stack might have applied an override + BlendModeOverride.restore(); + } + + if (bufferBlendOverrides != null && !bufferBlendOverrides.isEmpty()) { + bufferBlendOverrides.forEach(BufferBlendOverride::apply); + } + } + + public void stopUsing() { + if (alphaTestOverride != null) { + AlphaTestOverride.restore(); + } + + if (blendModeOverride != null || (bufferBlendOverrides != null && !bufferBlendOverrides.isEmpty())) { + BlendModeOverride.restore(); + } + } + + @Nullable + public Program getProgram() { + return program; + } + + public void destroy() { + if (this.program != null) { + this.program.destroy(); + } + } + } + + @Override + public void destroy() { + BlendModeOverride.restore(); + AlphaTestOverride.restore(); + + destroyPasses(table); + + // Destroy the composite rendering pipeline + // + // This destroys all the loaded composite programs as well. + compositeRenderer.destroy(); + deferredRenderer.destroy(); + finalPassRenderer.destroy(); + centerDepthSampler.destroy(); + + horizonRenderer.destroy(); + + // Make sure that any custom framebuffers are not bound before destroying render targets + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_READ_FRAMEBUFFER, 0); + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_DRAW_FRAMEBUFFER, 0); + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, 0); + + Minecraft.getMinecraft().getMainRenderTarget().bindWrite(false); + + // Destroy our render targets + // + // While it's possible to just clear them instead and reuse them, we'd need to investigate whether or not this + // would help performance. + renderTargets.destroy(); + + // destroy the shadow render targets + if (shadowRenderTargets != null) { + shadowRenderTargets.destroy(); + } + + // Destroy custom textures and the static samplers (normals, specular, and noise) + customTextureManager.destroy(); + whitePixel.releaseId(); + } + + private static void destroyPasses(ProgramTable table) { + Set destroyed = new HashSet<>(); + + table.forEach(pass -> { + if (pass == null) { + return; + } + + if (destroyed.contains(pass)) { + return; + } + + pass.destroy(); + destroyed.add(pass); + }); + } + + private void prepareRenderTargets() { + // Make sure we're using texture unit 0 for this. + GL13.glActiveTexture(GL13.GL_TEXTURE0); + Vector4f emptyClearColor = new Vector4f(1.0F); + + if (shadowRenderTargets != null) { + if (packDirectives.getShadowDirectives().isShadowEnabled() == OptionalBoolean.FALSE) { + if (shadowRenderTargets.isFullClearRequired()) { + shadowRenderTargets.onFullClear(); + for (ClearPass clearPass : shadowClearPassesFull) { + clearPass.execute(emptyClearColor); + } + } + } else { + // Clear depth first, regardless of any color clearing. + shadowRenderTargets.getDepthSourceFb().bind(); + GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT); + if (Minecraft.isRunningOnMac) { + GL11.glGetError(); + } + + + ImmutableList passes; + + for (ComputeProgram computeProgram : shadowComputes) { + if (computeProgram != null) { + computeProgram.dispatch(shadowMapResolution, shadowMapResolution); + } + } + + if (shadowRenderTargets.isFullClearRequired()) { + passes = shadowClearPassesFull; + shadowRenderTargets.onFullClear(); + } else { + passes = shadowClearPasses; + } + + for (ClearPass clearPass : passes) { + clearPass.execute(emptyClearColor); + } + } + } + + RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); + Blaze3dRenderTargetExt mainExt = (Blaze3dRenderTargetExt) main; + + int depthTextureId = main.getDepthTextureId(); + int internalFormat = TextureInfoCache.INSTANCE.getInfo(depthTextureId).getInternalFormat(); + DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); + + boolean changed = renderTargets.resizeIfNeeded(mainExt.iris$getDepthBufferVersion(), depthTextureId, main.width, + main.height, depthBufferFormat, packDirectives); + + if (changed) { + prepareRenderer.recalculateSizes(); + deferredRenderer.recalculateSizes(); + compositeRenderer.recalculateSizes(); + finalPassRenderer.recalculateSwapPassSize(); + + this.clearPassesFull.forEach(clearPass -> renderTargets.destroyFramebuffer(clearPass.getFramebuffer())); + this.clearPasses.forEach(clearPass -> renderTargets.destroyFramebuffer(clearPass.getFramebuffer())); + + this.clearPassesFull = ClearPassCreator.createClearPasses(renderTargets, true, + packDirectives.getRenderTargetDirectives()); + this.clearPasses = ClearPassCreator.createClearPasses(renderTargets, false, + packDirectives.getRenderTargetDirectives()); + } + + final ImmutableList passes; + + if (renderTargets.isFullClearRequired()) { + renderTargets.onFullClear(); + passes = clearPassesFull; + } else { + passes = clearPasses; + } + + Vector3d fogColor3 = CapturedRenderingState.INSTANCE.getFogColor(); + + // NB: The alpha value must be 1.0 here, or else you will get a bunch of bugs. Sildur's Vibrant Shaders + // will give you pink reflections and other weirdness if this is zero. + Vector4f fogColor = new Vector4f((float) fogColor3.x, (float) fogColor3.y, (float) fogColor3.z, 1.0F); + + for (ClearPass clearPass : passes) { + clearPass.execute(fogColor); + } + + // Reset framebuffer and viewport + Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); + } + + private ComputeProgram[] createShadowComputes(ComputeSource[] compute, ProgramSet programSet) { + ComputeProgram[] programs = new ComputeProgram[compute.length]; + for (int i = 0; i < programs.length; i++) { + ComputeSource source = compute[i]; + if (source == null || !source.getSource().isPresent()) { + continue; + } else { + ProgramBuilder builder; + + try { + builder = ProgramBuilder.beginCompute(source.getName(), source.getSource().orElse(null), IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS); + } catch (RuntimeException e) { + // TODO: Better error handling + throw new RuntimeException("Shader compilation failed!", e); + } + + CommonUniforms.addCommonUniforms(builder, programSet.getPack().getIdMap(), programSet.getPackDirectives(), updateNotifier); + + Supplier> flipped; + + flipped = () -> flippedBeforeShadow; + + TextureStage textureStage = TextureStage.GBUFFERS_AND_SHADOW; + + ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = + ProgramSamplers.customTextureSamplerInterceptor(builder, + customTextureManager.getCustomTextureIdMap(textureStage)); + + IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false); + IrisImages.addRenderTargetImages(builder, flipped, renderTargets); + + IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true, false)); + + IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture()); + + if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { + if (shadowRenderTargets != null) { + IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowRenderTargets); + IrisImages.addShadowColorImages(builder, shadowRenderTargets); + } + } + + programs[i] = builder.buildCompute(); + + programs[i].setWorkGroupInfo(source.getWorkGroupRelative(), source.getWorkGroups()); + } + } + + + return programs; + } + + @Override + public void beginHand() { + // We need to copy the current depth texture so that depthtex2 can contain the depth values for + // all non-translucent content without the hand, as required. + renderTargets.copyPreHandDepth(); + } + + @Override + public void beginTranslucents() { + isBeforeTranslucent = false; + + // We need to copy the current depth texture so that depthtex1 can contain the depth values for + // all non-translucent content, as required. + renderTargets.copyPreTranslucentDepth(); + + + // needed to remove blend mode overrides and similar + beginPass(null); + + isRenderingFullScreenPass = true; + + deferredRenderer.renderAll(); + + RenderSystem.enableBlend(); + RenderSystem.enableAlphaTest(); + + // note: we are careful not to touch the lightmap texture unit or overlay color texture unit here, + // so we don't need to do anything to restore them if needed. + // + // Previous versions of the code tried to "restore" things by enabling the lightmap & overlay color + // but that actually broke rendering of clouds and rain by making them appear red in the case of + // a pack not overriding those shader programs. + // + // Not good! + + isRenderingFullScreenPass = false; + } + + @Override + public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCamera) { + if (shouldRenderPrepareBeforeShadow) { + isRenderingFullScreenPass = true; + + prepareRenderer.renderAll(); + + isRenderingFullScreenPass = false; + } + + if (shadowRenderer != null) { + isRenderingShadow = true; + + shadowRenderer.renderShadows(levelRenderer, playerCamera); + + // needed to remove blend mode overrides and similar + beginPass(null); + isRenderingShadow = false; + } + + if (!shouldRenderPrepareBeforeShadow) { + isRenderingFullScreenPass = true; + + prepareRenderer.renderAll(); + + isRenderingFullScreenPass = false; + } + } + + @Override + public void addDebugText(List messages) { + messages.add(""); + + if (shadowRenderer != null) { + shadowRenderer.addDebugText(messages); + } else { + messages.add("[Iris] Shadow Maps: not used by shader pack"); + } + } + + @Override + public OptionalInt getForcedShadowRenderDistanceChunksForDisplay() { + return forcedShadowRenderDistanceChunks; + } + + // TODO: better way to avoid this global state? + private boolean isRenderingWorld = false; + private boolean isRenderingFullScreenPass = false; + + @Override + public void beginLevelRendering() { + isRenderingFullScreenPass = false; + isRenderingWorld = true; + isBeforeTranslucent = true; + isMainBound = true; + isPostChain = false; + phase = WorldRenderingPhase.NONE; + overridePhase = null; + HandRenderer.INSTANCE.getBufferSource().resetDrawCalls(); + + checkWorld(); + + if (!isRenderingWorld) { + Iris.logger.warn("beginWorldRender was called but we are not currently rendering a world?"); + return; + } + + if (current != null) { + throw new IllegalStateException("Called beginLevelRendering but level rendering appears to still be in progress?"); + } + + updateNotifier.onNewFrame(); + + // Get ready for world rendering + prepareRenderTargets(); + + setPhase(WorldRenderingPhase.SKY); + + // Render our horizon box before actual sky rendering to avoid being broken by mods that do weird things + // while rendering the sky. + // + // A lot of dimension mods touch sky rendering, FabricSkyboxes injects at HEAD and cancels, etc. + DimensionSpecialEffects.SkyType skyType = Minecraft.getMinecraft().theWorld.effects().skyType(); + + if (skyType == DimensionSpecialEffects.SkyType.NORMAL) { + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glDepthMask(false); + + Vector3d fogColor = CapturedRenderingState.INSTANCE.getFogColor(); + GL11.glColor4f((float) fogColor.x, (float) fogColor.y, (float) fogColor.z, 1.0F); + + horizonRenderer.renderHorizon(CapturedRenderingState.INSTANCE.getGbufferModelView()); + + GL11.glDepthMask(true); + GL11.glEnable(GL11.GL_TEXTURE_2D); + } + } + + @Override + public void finalizeLevelRendering() { + checkWorld(); + + if (!isRenderingWorld) { + Iris.logger.warn("finalizeWorldRendering was called but we are not currently rendering a world?"); + return; + } + + beginPass(null); + + isRenderingWorld = false; + phase = WorldRenderingPhase.NONE; + overridePhase = null; + + isRenderingFullScreenPass = true; + + centerDepthSampler.sampleCenterDepth(); + + compositeRenderer.renderAll(); + finalPassRenderer.renderFinalPass(); + + isRenderingFullScreenPass = false; + } + + @Override + public SodiumTerrainPipeline getSodiumTerrainPipeline() { + return sodiumTerrainPipeline; + } + + @Override + public FrameUpdateNotifier getFrameUpdateNotifier() { + return updateNotifier; + } + + @Override + public WorldRenderingPhase getPhase() { + if (overridePhase != null) { + return overridePhase; + } + + return phase; + } + + boolean sodiumTerrainRendering = false; + + @Override + public void syncProgram() { + matchPass(); + } + + @Override + public void beginSodiumTerrainRendering() { + sodiumTerrainRendering = true; + syncProgram(); + + } + + @Override + public void endSodiumTerrainRendering() { + sodiumTerrainRendering = false; + current = null; + syncProgram(); + } + + @Override + public void setOverridePhase(WorldRenderingPhase phase) { + this.overridePhase = phase; + + GbufferPrograms.runPhaseChangeNotifier(); + } + + @Override + public void setPhase(WorldRenderingPhase phase) { + this.phase = phase; + + GbufferPrograms.runPhaseChangeNotifier(); + } + + @Override + public void setInputs(InputAvailability availability) { + this.inputs = availability; + } + + @Override + public void setSpecialCondition(SpecialCondition special) { + this.special = special; + } + + @Override + public RenderTargetStateListener getRenderTargetStateListener() { + return this; + } + + @Override + public int getCurrentNormalTexture() { + return currentNormalTexture; + } + + @Override + public int getCurrentSpecularTexture() { + return currentSpecularTexture; + } + + @Override + public void onBindTexture(int id) { + if (shouldBindPBR && isRenderingWorld) { + PBRTextureHolder pbrHolder = PBRTextureManager.INSTANCE.getOrLoadHolder(id); + currentNormalTexture = pbrHolder.getNormalTexture().getId(); + currentSpecularTexture = pbrHolder.getSpecularTexture().getId(); + + TextureFormat textureFormat = TextureFormatLoader.getFormat(); + if (textureFormat != null) { + textureFormat.setupTextureParameters(PBRType.NORMAL, pbrHolder.getNormalTexture()); + textureFormat.setupTextureParameters(PBRType.SPECULAR, pbrHolder.getSpecularTexture()); + } + + PBRTextureManager.notifyPBRTexturesChanged(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java new file mode 100644 index 000000000..d8b7103c7 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java @@ -0,0 +1,193 @@ +package net.coderbot.iris.pipeline; + +import net.coderbot.iris.block_rendering.BlockRenderingSettings; +import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; +import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; +import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; +import net.coderbot.iris.shaderpack.CloudSetting; +import net.coderbot.iris.uniforms.FrameUpdateNotifier; +import net.minecraft.client.Minecraft; +import org.lwjgl.opengl.GL20; + +import java.util.List; +import java.util.OptionalInt; + +public class FixedFunctionWorldRenderingPipeline implements WorldRenderingPipeline { + public FixedFunctionWorldRenderingPipeline() { + BlockRenderingSettings.INSTANCE.setDisableDirectionalShading(shouldDisableDirectionalShading()); + BlockRenderingSettings.INSTANCE.setUseSeparateAo(false); + BlockRenderingSettings.INSTANCE.setAmbientOcclusionLevel(1.0f); + BlockRenderingSettings.INSTANCE.setUseExtendedVertexFormat(false); + BlockRenderingSettings.INSTANCE.setBlockTypeIds(null); + } + + @Override + public void beginLevelRendering() { + // Use the default Minecraft framebuffer and ensure that no programs are in use + Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); + GL20.glUseProgram(0); + } + + @Override + public void renderShadows(LevelRendererAccessor levelRenderer, Camera camera) { + // stub: nothing to do here + } + + @Override + public void addDebugText(List messages) { + // stub: nothing to do here + } + + @Override + public OptionalInt getForcedShadowRenderDistanceChunksForDisplay() { + return OptionalInt.empty(); + } + + @Override + public WorldRenderingPhase getPhase() { + return WorldRenderingPhase.NONE; + } + + @Override + public void beginSodiumTerrainRendering() { + + } + + @Override + public void endSodiumTerrainRendering() { + + } + + @Override + public void setOverridePhase(WorldRenderingPhase phase) { + + } + + @Override + public void setPhase(WorldRenderingPhase phase) { + + } + + @Override + public void setInputs(InputAvailability availability) { + + } + + @Override + public void setSpecialCondition(SpecialCondition special) { + + } + + @Override + public void syncProgram() { + + } + + @Override + public RenderTargetStateListener getRenderTargetStateListener() { + return RenderTargetStateListener.NOP; + } + + @Override + public int getCurrentNormalTexture() { + return 0; + } + + @Override + public int getCurrentSpecularTexture() { + return 0; + } + + @Override + public void onBindTexture(int id) { + + } + + @Override + public void beginHand() { + // stub: nothing to do here + } + + @Override + public void beginTranslucents() { + // stub: nothing to do here + } + + @Override + public void finalizeLevelRendering() { + // stub: nothing to do here + } + + @Override + public void destroy() { + // stub: nothing to do here + } + + @Override + public SodiumTerrainPipeline getSodiumTerrainPipeline() { + // no shaders to override + return null; + } + + @Override + public FrameUpdateNotifier getFrameUpdateNotifier() { + // return a dummy notifier + return new FrameUpdateNotifier(); + } + + @Override + public boolean shouldDisableVanillaEntityShadows() { + return false; + } + + @Override + public boolean shouldDisableDirectionalShading() { + return false; + } + + @Override + public CloudSetting getCloudSetting() { + return CloudSetting.DEFAULT; + } + + @Override + public boolean shouldRenderUnderwaterOverlay() { + return true; + } + + @Override + public boolean shouldRenderVignette() { + return true; + } + + @Override + public boolean shouldRenderSun() { + return true; + } + + @Override + public boolean shouldRenderMoon() { + return true; + } + + @Override + public boolean shouldWriteRainAndSnowToDepthBuffer() { + return false; + } + + @Override + public boolean shouldRenderParticlesBeforeDeferred() { + return false; + } + + @Override + public boolean allowConcurrentCompute() { + return false; + } + + @Override + public float getSunPathRotation() { + // No sun tilt + return 0; + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java new file mode 100644 index 000000000..ac463eb06 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java @@ -0,0 +1,137 @@ +package net.coderbot.iris.pipeline; + +import net.coderbot.batchedentityrendering.impl.FullyBufferedMultiBufferSource; +import net.coderbot.iris.uniforms.CapturedRenderingState; +import net.irisshaders.iris.api.v0.IrisApi; +import net.minecraft.client.Minecraft; +import net.minecraft.item.Item; +import net.minecraft.item.ItemBlock; +import org.joml.Matrix4f; + +public class HandRenderer { + public static final HandRenderer INSTANCE = new HandRenderer(); + + private boolean ACTIVE; + private boolean renderingSolid; + private final FullyBufferedMultiBufferSource bufferSource = new FullyBufferedMultiBufferSource(); + + public static final float DEPTH = 0.125F; + + private void setupGlState(GameRenderer gameRenderer, Camera camera, PoseStack poseStack, float tickDelta) { + final PoseStack.Pose pose = poseStack.last(); + + // We need to scale the matrix by 0.125 so the hand doesn't clip through blocks. + Matrix4f scaleMatrix = Matrix4f.createScaleMatrix(1F, 1F, DEPTH); + scaleMatrix.multiply(gameRenderer.getProjectionMatrix(camera, tickDelta, false)); + gameRenderer.resetProjectionMatrix(scaleMatrix); + + pose.pose().setIdentity(); + pose.normal().setIdentity(); + + ((GameRendererAccessor) gameRenderer).invokeBobHurt(poseStack, tickDelta); + + if (Minecraft.getMinecraft().gameSettings.bobView) { + ((GameRendererAccessor) gameRenderer).invokeBobView(poseStack, tickDelta); + } + } + + private boolean canRender(Camera camera, GameRenderer gameRenderer) { + return !(!((GameRendererAccessor) gameRenderer).getRenderHand() + || camera.isDetached() + || !(camera.getEntity() instanceof Player) + || ((GameRendererAccessor)gameRenderer).getPanoramicMode() + || Minecraft.getMinecraft().gameSettings.hideGui + || (camera.getEntity() instanceof LivingEntity && ((LivingEntity)camera.getEntity()).isSleeping()) + || Minecraft.getMinecraft().gameMode.getPlayerMode() == GameType.SPECTATOR); + } + + public boolean isHandTranslucent(InteractionHand hand) { + Item item = Minecraft.getMinecraft().thePlayer.getItemBySlot(hand == InteractionHand.OFF_HAND ? EquipmentSlot.OFFHAND : EquipmentSlot.MAINHAND).getItem(); + + if (item instanceof ItemBlock itemBlock) { + return ItemBlockRenderTypes.getChunkRenderType(itemBlock.getBlock().defaultBlockState()) == RenderType.translucent(); + } + + return false; + } + + public boolean isAnyHandTranslucent() { + return isHandTranslucent(InteractionHand.MAIN_HAND) || isHandTranslucent(InteractionHand.OFF_HAND); + } + + public void renderSolid(PoseStack poseStack, float tickDelta, Camera camera, GameRenderer gameRenderer, WorldRenderingPipeline pipeline) { + if (!canRender(camera, gameRenderer) || !IrisApi.getInstance().isShaderPackInUse()) { + return; + } + + ACTIVE = true; + + pipeline.setPhase(WorldRenderingPhase.HAND_SOLID); + + poseStack.pushPose(); + + Minecraft.getMinecraft().mcProfiler.push("iris_hand"); + + setupGlState(gameRenderer, camera, poseStack, tickDelta); + + renderingSolid = true; + + Minecraft.getMinecraft().getItemInHandRenderer().renderHandsWithItems(tickDelta, poseStack, bufferSource, Minecraft.getMinecraft().thePlayer, Minecraft.getMinecraft().getEntityRenderDispatcher().getPackedLightCoords(camera.getEntity(), tickDelta)); + + Minecraft.getMinecraft().mcProfiler.endSection(); + + gameRenderer.resetProjectionMatrix(CapturedRenderingState.INSTANCE.getGbufferProjection()); + + poseStack.popPose(); + + bufferSource.endBatch(); + + renderingSolid = false; + + pipeline.setPhase(WorldRenderingPhase.NONE); + + ACTIVE = false; + } + + public void renderTranslucent(PoseStack poseStack, float tickDelta, Camera camera, GameRenderer gameRenderer, WorldRenderingPipeline pipeline) { + if (!canRender(camera, gameRenderer) || !isAnyHandTranslucent() || !IrisApi.getInstance().isShaderPackInUse()) { + return; + } + + ACTIVE = true; + + pipeline.setPhase(WorldRenderingPhase.HAND_TRANSLUCENT); + + poseStack.pushPose(); + + Minecraft.getMinecraft().mcProfiler.startSection("iris_hand_translucent"); + + setupGlState(gameRenderer, camera, poseStack, tickDelta); + + Minecraft.getMinecraft().getItemInHandRenderer().renderHandsWithItems(tickDelta, poseStack, bufferSource, Minecraft.getMinecraft().thePlayer, Minecraft.getMinecraft().getEntityRenderDispatcher().getPackedLightCoords(camera.getEntity(), tickDelta)); + + poseStack.popPose(); + + Minecraft.getMinecraft().mcProfiler.endSection(); + + gameRenderer.resetProjectionMatrix(CapturedRenderingState.INSTANCE.getGbufferProjection()); + + bufferSource.endBatch(); + + pipeline.setPhase(WorldRenderingPhase.NONE); + + ACTIVE = false; + } + + public boolean isActive() { + return ACTIVE; + } + + public boolean isRenderingSolid() { + return renderingSolid; + } + + public FullyBufferedMultiBufferSource getBufferSource() { + return bufferSource; + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java new file mode 100644 index 000000000..a2a88b219 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java @@ -0,0 +1,177 @@ +package net.coderbot.iris.pipeline; + +import net.minecraft.client.Minecraft; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11; + +/** + * Renders the sky horizon. Vanilla Minecraft simply uses the "clear color" for its horizon, and then draws a plane + * above the player. This class extends the sky rendering so that an octagonal prism is drawn around the player instead, + * allowing shaders to perform more advanced sky rendering. + *

+ * However, the horizon rendering is designed so that when sky shaders are not being used, it looks almost exactly the + * same as vanilla sky rendering, except a few almost entirely imperceptible differences where the walls + * of the octagonal prism intersect the top plane. + */ +public class HorizonRenderer { + /** + * The Y coordinate of the top skybox plane. Acts as the upper bound for the horizon prism, since the prism lies + * between the bottom and top skybox planes. + */ + private static final float TOP = 16.0F; + + /** + * The Y coordinate of the bottom skybox plane. Acts as the lower bound for the horizon prism, since the prism lies + * between the bottom and top skybox planes. + */ + private static final float BOTTOM = -16.0F; + + /** + * Cosine of 22.5 degrees. + */ + private static final double COS_22_5 = Math.cos(Math.toRadians(22.5)); + + /** + * Sine of 22.5 degrees. + */ + private static final double SIN_22_5 = Math.sin(Math.toRadians(22.5)); + private VertexBuffer buffer; + private int currentRenderDistance; + + public HorizonRenderer() { + currentRenderDistance = Minecraft.getMinecraft().gameSettings.renderDistanceChunks; + + rebuildBuffer(); + } + + private void rebuildBuffer() { + if (this.buffer != null) { + this.buffer.close(); + } + + BufferBuilder buffer = Tesselator.getInstance().getBuilder(); + + // Build the horizon quads into a buffer + buffer.begin(GL11.GL_QUADS, DefaultVertexFormat.POSITION); + buildHorizon(currentRenderDistance * 16, buffer); + buffer.end(); + + this.buffer = new VertexBuffer(DefaultVertexFormat.POSITION); + this.buffer.bind(); + this.buffer.upload(buffer); + VertexBuffer.unbind(); + } + + private void buildQuad(VertexConsumer consumer, double x1, double z1, double x2, double z2) { + consumer.vertex(x1, BOTTOM, z1); + consumer.endVertex(); + consumer.vertex(x1, TOP, z1); + consumer.endVertex(); + consumer.vertex(x2, TOP, z2); + consumer.endVertex(); + consumer.vertex(x2, BOTTOM, z2); + consumer.endVertex(); + } + + private void buildHalf(VertexConsumer consumer, double adjacent, double opposite, boolean invert) { + if (invert) { + adjacent = -adjacent; + opposite = -opposite; + } + + // NB: Make sure that these vertices are being specified in counterclockwise order! + // Otherwise back face culling will remove your quads, and you'll be wondering why there's a hole in your horizon. + // Don't poke holes in the horizon. Specify vertices in counterclockwise order. + + // +X,-Z face + buildQuad(consumer, adjacent, -opposite, opposite, -adjacent); + // +X face + buildQuad(consumer, adjacent, opposite, adjacent, -opposite); + // +X,+Z face + buildQuad(consumer, opposite, adjacent, adjacent, opposite); + // +Z face + buildQuad(consumer, -opposite, adjacent, opposite, adjacent); + } + + /** + * @param adjacent the adjacent side length of the a triangle with a hypotenuse extending from the center of the + * octagon to a given vertex on the perimeter. + * @param opposite the opposite side length of the a triangle with a hypotenuse extending from the center of the + * octagon to a given vertex on the perimeter. + */ + private void buildOctagonalPrism(VertexConsumer consumer, double adjacent, double opposite) { + buildHalf(consumer, adjacent, opposite, false); + buildHalf(consumer, adjacent, opposite, true); + } + + private void buildRegularOctagonalPrism(VertexConsumer consumer, double radius) { + buildOctagonalPrism(consumer, radius * COS_22_5, radius * SIN_22_5); + } + + private void buildBottomPlane(VertexConsumer consumer, int radius) { + for (int x = -radius; x <= radius; x += 64) { + for (int z = -radius; z <= radius; z += 64) { + consumer.vertex(x + 64, BOTTOM, z); + consumer.endVertex(); + consumer.vertex(x, BOTTOM, z); + consumer.endVertex(); + consumer.vertex(x, BOTTOM, z + 64); + consumer.endVertex(); + consumer.vertex(x + 64, BOTTOM, z + 64); + consumer.endVertex(); + } + } + } + + private void buildTopPlane(VertexConsumer consumer, int radius) { + // You might be tempted to try to combine this with buildBottomPlane to avoid code duplication, + // but that won't work since the winding order has to be reversed or else one of the planes will be + // discarded by back face culling. + for (int x = -radius; x <= radius; x += 64) { + for (int z = -radius; z <= radius; z += 64) { + consumer.vertex(x + 64, TOP, z); + consumer.endVertex(); + consumer.vertex(x + 64, TOP, z + 64); + consumer.endVertex(); + consumer.vertex(x, TOP, z + 64); + consumer.endVertex(); + consumer.vertex(x, TOP, z); + consumer.endVertex(); + } + } + } + + private void buildHorizon(int radius, VertexConsumer consumer) { + if (radius > 256) { + // Prevent the prism from getting too large, this causes issues on some shader packs that modify the vanilla + // sky if we don't do this. + radius = 256; + } + + buildRegularOctagonalPrism(consumer, radius); + + // Replicate the vanilla top plane since we can't assume that it'll be rendered. + // TODO: Remove vanilla top plane + buildTopPlane(consumer, 384); + + // Always make the bottom plane have a radius of 384, to match the top plane. + buildBottomPlane(consumer, 384); + } + + public void renderHorizon(Matrix4f matrix) { + if (currentRenderDistance != Minecraft.getMinecraft().gameSettings.renderDistanceChunks) { + currentRenderDistance = Minecraft.getMinecraft().gameSettings.renderDistanceChunks; + rebuildBuffer(); + } + + buffer.bind(); + DefaultVertexFormat.POSITION.setupBufferState(0L); + buffer.draw(matrix, GL11.GL_QUADS); + DefaultVertexFormat.POSITION.clearBufferState(); + VertexBuffer.unbind(); + } + + public void destroy() { + buffer.close(); + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/PatchedShaderPrinter.java b/src/main/java/net/coderbot/iris/pipeline/PatchedShaderPrinter.java new file mode 100644 index 000000000..ee8a4ff89 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/PatchedShaderPrinter.java @@ -0,0 +1,70 @@ +package net.coderbot.iris.pipeline; + +import net.coderbot.iris.Iris; +import net.minecraft.client.Minecraft; +import net.minecraft.launchwrapper.Launch; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; + +/** + * Static class that deals with printing the patched_shader folder. + */ +public class PatchedShaderPrinter { + private static boolean outputLocationCleared = false; + private static int programCounter = 0; + + // Is this too early? We'll find out! + public static final boolean prettyPrintShaders = (boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment") + || System.getProperty("iris.prettyPrintShaders", "false").equals("true"); + + public static void resetPrintState() { + outputLocationCleared = false; + programCounter = 0; + } + + public static void debugPatchedShaders(String name, String vertex, String geometry, String fragment) { + if (prettyPrintShaders) { + final Path debugOutDir = Minecraft.getMinecraft().mcDataDir.toPath().resolve("patched_shaders"); + if (!outputLocationCleared) { + try { + if (Files.exists(debugOutDir)) { + try (Stream stream = Files.list(debugOutDir)) { + stream.forEach(path -> { + try { + Files.delete(path); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + } + + Files.createDirectories(debugOutDir); + } catch (IOException e) { + Iris.logger.warn("Failed to initialize debug patched shader source location", e); + } + outputLocationCleared = true; + } + + try { + programCounter++; + String prefix = String.format("%03d_", programCounter); + if (vertex != null) { + Files.write(debugOutDir.resolve(prefix + name + ".vsh"), vertex.getBytes(StandardCharsets.UTF_8)); + } + if (geometry != null) { + Files.write(debugOutDir.resolve(prefix + name + ".gsh"), geometry.getBytes(StandardCharsets.UTF_8)); + } + if (fragment != null) { + Files.write(debugOutDir.resolve(prefix + name + ".fsh"), fragment.getBytes(StandardCharsets.UTF_8)); + } + } catch (IOException e) { + Iris.logger.warn("Failed to write debug patched shader source", e); + } + } + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java b/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java new file mode 100644 index 000000000..5dd9c8eeb --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java @@ -0,0 +1,102 @@ +package net.coderbot.iris.pipeline; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; +import net.coderbot.iris.shaderpack.DimensionId; +import net.coderbot.iris.uniforms.SystemTimeUniforms; +import net.minecraft.client.Minecraft; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public class PipelineManager { + private static PipelineManager instance; + private final Function pipelineFactory; + private final Map pipelinesPerDimension = new HashMap<>(); + private WorldRenderingPipeline pipeline = new FixedFunctionWorldRenderingPipeline(); + private int versionCounterForSodiumShaderReload = 0; + + public PipelineManager(Function pipelineFactory) { + this.pipelineFactory = pipelineFactory; + } + + public WorldRenderingPipeline preparePipeline(DimensionId currentDimension) { + if (!pipelinesPerDimension.containsKey(currentDimension)) { + SystemTimeUniforms.COUNTER.reset(); + SystemTimeUniforms.TIMER.reset(); + + Iris.logger.info("Creating pipeline for dimension {}", currentDimension); + pipeline = pipelineFactory.apply(currentDimension); + pipelinesPerDimension.put(currentDimension, pipeline); + + if (BlockRenderingSettings.INSTANCE.isReloadRequired()) { + if (Minecraft.getMinecraft().renderGlobal != null) { + Minecraft.getMinecraft().renderGlobal.allChanged(); + } + + BlockRenderingSettings.INSTANCE.clearReloadRequired(); + } + } else { + pipeline = pipelinesPerDimension.get(currentDimension); + } + + return pipeline; + } + + @Nullable + public WorldRenderingPipeline getPipelineNullable() { + return pipeline; + } + + public Optional getPipeline() { + return Optional.ofNullable(pipeline); + } + + + /** + * Destroys all the current pipelines. + * + *

This method is EXTREMELY DANGEROUS! It is a huge potential source of hard-to-trace inconsistencies + * in program state. You must make sure that you immediately re-prepare the pipeline after destroying + * it to prevent the program from falling into an inconsistent state.

+ * + *

In particular,

+ * + * @see this GitHub issue + */ + public void destroyPipeline() { + pipelinesPerDimension.forEach((dimensionId, pipeline) -> { + Iris.logger.info("Destroying pipeline {}", dimensionId); + resetTextureState(); + pipeline.destroy(); + }); + + pipelinesPerDimension.clear(); + pipeline = null; + versionCounterForSodiumShaderReload++; + } + + private void resetTextureState() { + // Unbind all textures + // + // This is necessary because we don't want destroyed render target textures to remain bound to certain texture + // units. Vanilla appears to properly rebind all textures as needed, and we do so too, so this does not cause + // issues elsewhere. + // + // Without this code, there will be weird issues when reloading certain shaderpacks. + for (int i = 0; i < 16; i++) { + GL13.glActiveTexture(GL13.GL_TEXTURE0 + i); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + } + + // Set the active texture unit to unit 0 + // + // This seems to be what most code expects. It's a sane default in any case. + GL13.glActiveTexture(GL13.GL_TEXTURE0); + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java new file mode 100644 index 000000000..ad54f7fef --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -0,0 +1,656 @@ +package net.coderbot.iris.pipeline; + +import com.google.common.collect.ImmutableList; +import net.coderbot.batchedentityrendering.impl.BatchingDebugMessageHelper; +import net.coderbot.batchedentityrendering.impl.DrawCallTrackingRenderBuffers; +import net.coderbot.batchedentityrendering.impl.RenderBuffersExt; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gui.option.IrisVideoSettings; +import net.coderbot.iris.shaderpack.OptionalBoolean; +import net.coderbot.iris.shaderpack.PackDirectives; +import net.coderbot.iris.shaderpack.PackShadowDirectives; +import net.coderbot.iris.shaderpack.ProgramSource; +import net.coderbot.iris.shadow.ShadowMatrices; +import net.coderbot.iris.shadows.CullingDataCache; +import net.coderbot.iris.shadows.Matrix4fAccess; +import net.coderbot.iris.shadows.ShadowRenderTargets; +import net.coderbot.iris.shadows.frustum.BoxCuller; +import net.coderbot.iris.shadows.frustum.CullEverythingFrustum; +import net.coderbot.iris.shadows.frustum.FrustumHolder; +import net.coderbot.iris.shadows.frustum.advanced.AdvancedShadowCullingFrustum; +import net.coderbot.iris.shadows.frustum.fallback.BoxCullingFrustum; +import net.coderbot.iris.shadows.frustum.fallback.NonCullingFrustum; +import net.coderbot.iris.uniforms.CameraUniforms; +import net.coderbot.iris.uniforms.CapturedRenderingState; +import net.coderbot.iris.uniforms.CelestialUniforms; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.entity.Entity; +import net.minecraft.profiler.Profiler; +import net.minecraft.tileentity.TileEntity; +import org.joml.Matrix4f; +import org.joml.Vector3d; +import org.joml.Vector3f; +import org.joml.Vector4f; +import org.lwjgl.opengl.ARBTextureSwizzle; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL14; +import org.lwjgl.opengl.GL30; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; + +public class ShadowRenderer { + public static Matrix4f MODELVIEW; + public static Matrix4f PROJECTION; + public static List visibleTileEntities; + public static boolean ACTIVE = false; + private final float halfPlaneLength; + private final float renderDistanceMultiplier; + private final float entityShadowDistanceMultiplier; + private final int resolution; + private final float intervalSize; + private final Float fov; + private final ShadowRenderTargets targets; + private final OptionalBoolean packCullingState; + private boolean packHasVoxelization; + private final boolean shouldRenderTerrain; + private final boolean shouldRenderTranslucent; + private final boolean shouldRenderEntities; + private final boolean shouldRenderPlayer; + private final boolean shouldRenderBlockEntities; + private final float sunPathRotation; + private final RenderBuffers buffers; + private final RenderBuffersExt renderBuffersExt; + private final List mipmapPasses = new ArrayList<>(); + private final String debugStringOverall; + private FrustumHolder terrainFrustumHolder; + private FrustumHolder entityFrustumHolder; + private String debugStringTerrain = "(unavailable)"; + private int renderedShadowEntities = 0; + private int renderedShadowBlockEntities = 0; + private Profiler profiler; + + public ShadowRenderer(ProgramSource shadow, PackDirectives directives, ShadowRenderTargets shadowRenderTargets) { + + this.profiler = Minecraft.getMinecraft().mcProfiler; + + final PackShadowDirectives shadowDirectives = directives.getShadowDirectives(); + + this.halfPlaneLength = shadowDirectives.getDistance(); + this.renderDistanceMultiplier = shadowDirectives.getDistanceRenderMul(); + this.entityShadowDistanceMultiplier = shadowDirectives.getEntityShadowDistanceMul(); + this.resolution = shadowDirectives.getResolution(); + this.intervalSize = shadowDirectives.getIntervalSize(); + this.shouldRenderTerrain = shadowDirectives.shouldRenderTerrain(); + this.shouldRenderTranslucent = shadowDirectives.shouldRenderTranslucent(); + this.shouldRenderEntities = shadowDirectives.shouldRenderEntities(); + this.shouldRenderPlayer = shadowDirectives.shouldRenderPlayer(); + this.shouldRenderBlockEntities = shadowDirectives.shouldRenderBlockEntities(); + + debugStringOverall = "half plane = " + halfPlaneLength + " meters @ " + resolution + "x" + resolution; + + this.terrainFrustumHolder = new FrustumHolder(); + this.entityFrustumHolder = new FrustumHolder(); + + this.fov = shadowDirectives.getFov(); + this.targets = shadowRenderTargets; + + if (shadow != null) { + // Assume that the shader pack is doing voxelization if a geometry shader is detected. + // Also assume voxelization if image load / store is detected. + this.packHasVoxelization = shadow.getGeometrySource().isPresent(); + this.packCullingState = shadowDirectives.getCullingState(); + } else { + this.packHasVoxelization = false; + this.packCullingState = OptionalBoolean.DEFAULT; + } + + this.sunPathRotation = directives.getSunPathRotation(); + + this.buffers = new RenderBuffers(); + + if (this.buffers instanceof RenderBuffersExt) { + this.renderBuffersExt = (RenderBuffersExt) buffers; + } else { + this.renderBuffersExt = null; + } + + configureSamplingSettings(shadowDirectives); + } + + public void setUsesImages(boolean usesImages) { + this.packHasVoxelization = packHasVoxelization || usesImages; + } + + public static PoseStack createShadowModelView(float sunPathRotation, float intervalSize) { + // Determine the camera position + Vector3d cameraPos = CameraUniforms.getUnshiftedCameraPosition(); + + double cameraX = cameraPos.x; + double cameraY = cameraPos.y; + double cameraZ = cameraPos.z; + + // Set up our modelview matrix stack + PoseStack modelView = new PoseStack(); + ShadowMatrices.createModelViewMatrix(modelView, getShadowAngle(), intervalSize, sunPathRotation, cameraX, cameraY, cameraZ); + + return modelView; + } + + private static WorldClient getLevel() { + return Objects.requireNonNull(Minecraft.getMinecraft().theWorld); + } + + private static float getSkyAngle() { + return getLevel().getTimeOfDay(CapturedRenderingState.INSTANCE.getTickDelta()); + } + + private static float getSunAngle() { + float skyAngle = getSkyAngle(); + + if (skyAngle < 0.75F) { + return skyAngle + 0.25F; + } else { + return skyAngle - 0.75F; + } + } + + private static float getShadowAngle() { + float shadowAngle = getSunAngle(); + + if (!CelestialUniforms.isDay()) { + shadowAngle -= 0.5F; + } + + return shadowAngle; + } + + private void configureSamplingSettings(PackShadowDirectives shadowDirectives) { + final ImmutableList depthSamplingSettings = + shadowDirectives.getDepthSamplingSettings(); + + final ImmutableList colorSamplingSettings = + shadowDirectives.getColorSamplingSettings(); + + GL13.glActiveTexture(GL13.GL_TEXTURE4); + + configureDepthSampler(targets.getDepthTexture().getTextureId(), depthSamplingSettings.get(0)); + + configureDepthSampler(targets.getDepthTextureNoTranslucents().getTextureId(), depthSamplingSettings.get(1)); + + for (int i = 0; i < colorSamplingSettings.size(); i++) { + int glTextureId = targets.get(i).getMainTexture(); + + configureSampler(glTextureId, colorSamplingSettings.get(i)); + } + + GL13.glActiveTexture(GL13.GL_TEXTURE0); + } + + private void configureDepthSampler(int glTextureId, PackShadowDirectives.DepthSamplingSettings settings) { + if (settings.getHardwareFiltering()) { + // We have to do this or else shadow hardware filtering breaks entirely! + IrisRenderSystem.texParameteri(glTextureId, GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_COMPARE_MODE, GL30.GL_COMPARE_REF_TO_TEXTURE); + } + + // Workaround for issues with old shader packs like Chocapic v4. + // They expected the driver to put the depth value in z, but it's supposed to only + // be available in r. So we set up the swizzle to fix that. + IrisRenderSystem.texParameteriv(glTextureId, GL11.GL_TEXTURE_2D, ARBTextureSwizzle.GL_TEXTURE_SWIZZLE_RGBA, + new int[] { GL11.GL_RED, GL11.GL_RED, GL11.GL_RED, GL11.GL_ONE }); + + configureSampler(glTextureId, settings); + } + + private void configureSampler(int glTextureId, PackShadowDirectives.SamplingSettings settings) { + if (settings.getMipmap()) { + int filteringMode = settings.getNearest() ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR; + mipmapPasses.add(new MipmapPass(glTextureId, filteringMode)); + } + + if (!settings.getNearest()) { + // Make sure that things are smoothed + IrisRenderSystem.texParameteri(glTextureId, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + IrisRenderSystem.texParameteri(glTextureId, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + } else { + IrisRenderSystem.texParameteri(glTextureId, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + IrisRenderSystem.texParameteri(glTextureId, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + } + } + + private void generateMipmaps() { + GL13.glActiveTexture(GL13.GL_TEXTURE4); + + for (MipmapPass mipmapPass : mipmapPasses) { + setupMipmappingForTexture(mipmapPass.getTexture(), mipmapPass.getTargetFilteringMode()); + } + + GL13.glActiveTexture(GL13.GL_TEXTURE0); + } + + private void setupMipmappingForTexture(int texture, int filteringMode) { + IrisRenderSystem.generateMipmaps(texture, GL11.GL_TEXTURE_2D); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filteringMode); + } + + private FrustumHolder createShadowFrustum(float renderMultiplier, FrustumHolder holder) { + // TODO: Cull entities / block entities with Advanced Frustum Culling even if voxelization is detected. + String distanceInfo; + String cullingInfo; + if ((packCullingState == OptionalBoolean.FALSE || packHasVoxelization) && packCullingState != OptionalBoolean.TRUE) { + double distance = halfPlaneLength * renderMultiplier; + + String reason; + + if (packCullingState == OptionalBoolean.FALSE) { + reason = "(set by shader pack)"; + } else /*if (packHasVoxelization)*/ { + reason = "(voxelization detected)"; + } + + if (distance <= 0 || distance > Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16) { + distanceInfo = Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16 + + " blocks (capped by normal render distance)"; + cullingInfo = "disabled " + reason; + return holder.setInfo(new NonCullingFrustum(), distanceInfo, cullingInfo); + } else { + distanceInfo = distance + " blocks (set by shader pack)"; + cullingInfo = "distance only " + reason; + BoxCuller boxCuller = new BoxCuller(distance); + holder.setInfo(new BoxCullingFrustum(boxCuller), distanceInfo, cullingInfo); + } + } else { + BoxCuller boxCuller; + + double distance = halfPlaneLength * renderMultiplier; + String setter = "(set by shader pack)"; + + if (renderMultiplier < 0) { + distance = IrisVideoSettings.shadowDistance * 16; + setter = "(set by user)"; + } + + if (distance >= Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16) { + distanceInfo = Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16 + + " blocks (capped by normal render distance)"; + boxCuller = null; + } else { + distanceInfo = distance + " blocks " + setter; + + if (distance == 0.0) { + cullingInfo = "no shadows rendered"; + holder.setInfo(new CullEverythingFrustum(), distanceInfo, cullingInfo); + } + + boxCuller = new BoxCuller(distance); + } + + cullingInfo = "Advanced Frustum Culling enabled"; + + Vector4f shadowLightPosition = new CelestialUniforms(sunPathRotation).getShadowLightPositionInWorldSpace(); + + Vector3f shadowLightVectorFromOrigin = + new Vector3f(shadowLightPosition.x(), shadowLightPosition.y(), shadowLightPosition.z()); + + shadowLightVectorFromOrigin.normalize(); + + return holder.setInfo(new AdvancedShadowCullingFrustum(((Matrix4fAccess) (Object) CapturedRenderingState.INSTANCE.getGbufferModelView()).convertToJOML(), + ((Matrix4fAccess) (Object) CapturedRenderingState.INSTANCE.getGbufferProjection()).convertToJOML(), shadowLightVectorFromOrigin, boxCuller), distanceInfo, cullingInfo); + + } + + return holder; + } + + private void setupGlState(float[] projMatrix) { + // Set up our projection matrix and load it into the legacy matrix stack + IrisRenderSystem.setupProjectionMatrix(projMatrix); + + // Disable backface culling + // This partially works around an issue where if the front face of a mountain isn't visible, it casts no + // shadow. + // + // However, it only partially resolves issues of light leaking into caves. + // + // TODO: Better way of preventing light from leaking into places where it shouldn't + GL11.glDisable(GL11.GL_CULL_FACE); + } + + private void restoreGlState() { + // Restore backface culling + GL11.glEnable(GL11.GL_CULL_FACE); + + // Make sure to unload the projection matrix + IrisRenderSystem.restoreProjectionMatrix(); + } + + private void copyPreTranslucentDepth() { + profiler.endStartSection("translucent depth copy"); + + targets.copyPreTranslucentDepth(); + } + + private void renderEntities(LevelRendererAccessor levelRenderer, Frustum frustum, MultiBufferSource.BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { + EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); + + int shadowEntities = 0; + + profiler.startSection("cull"); + + List renderedEntities = new ArrayList<>(32); + + // TODO: I'm sure that this can be improved / optimized. + for (Entity entity : getLevel().entitiesForRendering()) { + if (!dispatcher.shouldRender(entity, frustum, cameraX, cameraY, cameraZ) || entity.isSpectator()) { + continue; + } + + renderedEntities.add(entity); + } + + profiler.endStartSection("sort"); + + // Sort the entities by type first in order to allow vanilla's entity batching system to work better. + renderedEntities.sort(Comparator.comparingInt(entity -> entity.getType().hashCode())); + + profiler.endStartSection("build geometry"); + + for (Entity entity : renderedEntities) { + levelRenderer.invokeRenderEntity(entity, cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); + shadowEntities++; + } + + renderedShadowEntities = shadowEntities; + + profiler.endSection(); + } + + private void renderPlayerEntity(LevelRendererAccessor levelRenderer, Frustum frustum, MultiBufferSource.BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { + EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); + + profiler.startSection("cull"); + + Entity player = Minecraft.getMinecraft().thePlayer; + + if (!dispatcher.shouldRender(player, frustum, cameraX, cameraY, cameraZ) || player.isSpectator()) { + return; + } + + profiler.endStartSection("build geometry"); + + int shadowEntities = 0; + + if (!player.getPassengers().isEmpty()) { + for (int i = 0; i < player.getPassengers().size(); i++) { + levelRenderer.invokeRenderEntity(player.getPassengers().get(i), cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); + shadowEntities++; + } + } + + if (player.getVehicle() != null) { + levelRenderer.invokeRenderEntity(player.getVehicle(), cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); + shadowEntities++; + } + + levelRenderer.invokeRenderEntity(player, cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); + + shadowEntities++; + + renderedShadowEntities = shadowEntities; + + profiler.endSection(); + } + + private void renderBlockEntities(MultiBufferSource.BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta, boolean hasEntityFrustum) { + profiler.startSection("build blockentities"); + + int shadowBlockEntities = 0; + BoxCuller culler = null; + if (hasEntityFrustum) { + culler = new BoxCuller(halfPlaneLength * (renderDistanceMultiplier * entityShadowDistanceMultiplier)); + culler.setPosition(cameraX, cameraY, cameraZ); + } + + for (TileEntity entity : visibleTileEntities) { + if (hasEntityFrustum) { + if (culler.isCulled(entity.xCoord - 1, entity.yCoord - 1, entity.zCoord - 1, entity.xCoord + 1, entity.yCoord + 1, entity.zCoord + 1)) { + continue; + } + } + modelView.pushPose(); + modelView.translate(entity.xCoord - cameraX, entity.yCoord - cameraY, entity.zCoord - cameraZ); + BlockEntityRenderDispatcher.instance.render(entity, tickDelta, modelView, bufferSource); + modelView.popPose(); + + shadowBlockEntities++; + } + + renderedShadowBlockEntities = shadowBlockEntities; + + profiler.endSection(); + } + + public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCamera) { + // We have to re-query this each frame since this changes based on whether the profiler is active + // If the profiler is inactive, it will return InactiveProfiler.INSTANCE + this.profiler = Minecraft.getMinecraft().mcProfiler; + + Minecraft client = Minecraft.getMinecraft(); + + profiler.endStartSection("shadows"); + ACTIVE = true; + + // NB: We store the previous player buffers in order to be able to allow mods rendering entities in the shadow pass (Flywheel) to use the shadow buffers instead. + RenderBuffers playerBuffers = levelRenderer.getRenderBuffers(); + levelRenderer.setRenderBuffers(buffers); + + visibleTileEntities = new ArrayList<>(); + + // Create our camera + PoseStack modelView = createShadowModelView(this.sunPathRotation, this.intervalSize); + MODELVIEW = modelView.last().pose().copy(); + float[] projMatrix; + if (this.fov != null) { + // If FOV is not null, the pack wants a perspective based projection matrix. (This is to support legacy packs) + projMatrix = ShadowMatrices.createPerspectiveMatrix(this.fov); + } else { + projMatrix = ShadowMatrices.createOrthoMatrix(halfPlaneLength); + } + + PROJECTION = new Matrix4f(); + ((Matrix4fAccess) (Object) PROJECTION).copyFromArray(projMatrix); + + profiler.push("terrain_setup"); + + if (levelRenderer instanceof CullingDataCache) { + ((CullingDataCache) levelRenderer).saveState(); + } + + profiler.push("initialize frustum"); + + terrainFrustumHolder = createShadowFrustum(renderDistanceMultiplier, terrainFrustumHolder); + + // Determine the player camera position + Vector3d cameraPos = CameraUniforms.getUnshiftedCameraPosition(); + + double cameraX = cameraPos.x(); + double cameraY = cameraPos.y(); + double cameraZ = cameraPos.z(); + + // Center the frustum on the player camera position + terrainFrustumHolder.getFrustum().prepare(cameraX, cameraY, cameraZ); + + profiler.endSection(); + + // Disable chunk occlusion culling - it's a bit complex to get this properly working with shadow rendering + // as-is, however in the future it will be good to work on restoring it for a nice performance boost. + // + // TODO: Get chunk occlusion working with shadows + boolean wasChunkCullingEnabled = client.smartCull; + client.smartCull = false; + + // Always schedule a terrain update + // TODO: Only schedule a terrain update if the sun / moon is moving, or the shadow map camera moved. + // We have to ensure that we don't regenerate clouds every frame, since that's what needsUpdate ends up doing. + // This took up to 10% of the frame time before we applied this fix! That's really bad! + boolean regenerateClouds = levelRenderer.shouldRegenerateClouds(); + ((LevelRenderer) levelRenderer).needsUpdate(); + levelRenderer.setShouldRegenerateClouds(regenerateClouds); + + // Execute the vanilla terrain setup / culling routines using our shadow frustum. + levelRenderer.invokeSetupRender(playerCamera, terrainFrustumHolder.getFrustum(), false, levelRenderer.getFrameId(), false); + + // Don't forget to increment the frame counter! This variable is arbitrary and only used in terrain setup, + // and if it's not incremented, the vanilla culling code will get confused and think that it's already seen + // chunks during traversal, and break rendering in concerning ways. + levelRenderer.setFrameId(levelRenderer.getFrameId() + 1); + + client.smartCull = wasChunkCullingEnabled; + + profiler.endStartSection("terrain"); + + setupGlState(projMatrix); + + // Render all opaque terrain unless pack requests not to + if (shouldRenderTerrain) { + levelRenderer.invokeRenderChunkLayer(RenderType.solid(), modelView, cameraX, cameraY, cameraZ); + levelRenderer.invokeRenderChunkLayer(RenderType.cutout(), modelView, cameraX, cameraY, cameraZ); + levelRenderer.invokeRenderChunkLayer(RenderType.cutoutMipped(), modelView, cameraX, cameraY, cameraZ); + } + + profiler.endStartSection("entities"); + + // Get the current tick delta. Normally this is the same as client.getTickDelta(), but when the game is paused, + // it is set to a fixed value. + final float tickDelta = CapturedRenderingState.INSTANCE.getTickDelta(); + + // Create a constrained shadow frustum for entities to avoid rendering faraway entities in the shadow pass, + // if the shader pack has requested it. Otherwise, use the same frustum as for terrain. + boolean hasEntityFrustum = false; + + if (entityShadowDistanceMultiplier == 1.0F || entityShadowDistanceMultiplier < 0.0F) { + entityFrustumHolder.setInfo(terrainFrustumHolder.getFrustum(), terrainFrustumHolder.getDistanceInfo(), terrainFrustumHolder.getCullingInfo()); + } else { + hasEntityFrustum = true; + entityFrustumHolder = createShadowFrustum(renderDistanceMultiplier * entityShadowDistanceMultiplier, entityFrustumHolder); + } + + Frustum entityShadowFrustum = entityFrustumHolder.getFrustum(); + entityShadowFrustum.prepare(cameraX, cameraY, cameraZ); + + // Render nearby entities + // + // Note: We must use a separate BuilderBufferStorage object here, or else very weird things will happen during + // rendering. + if (renderBuffersExt != null) { + renderBuffersExt.beginLevelRendering(); + } + + if (buffers instanceof DrawCallTrackingRenderBuffers) { + ((DrawCallTrackingRenderBuffers) buffers).resetDrawCounts(); + } + + MultiBufferSource.BufferSource bufferSource = buffers.bufferSource(); + + if (shouldRenderEntities) { + renderEntities(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); + } else if (shouldRenderPlayer) { + renderPlayerEntity(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); + } + + if (shouldRenderBlockEntities) { + renderBlockEntities(bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta, hasEntityFrustum); + } + + profiler.endStartSection("draw entities"); + + // NB: Don't try to draw the translucent parts of entities afterwards. It'll cause problems since some + // shader packs assume that everything drawn afterwards is actually translucent and should cast a colored + // shadow... + bufferSource.endBatch(); + + copyPreTranslucentDepth(); + + profiler.endStartSection("translucent terrain"); + + // TODO: Prevent these calls from scheduling translucent sorting... + // It doesn't matter a ton, since this just means that they won't be sorted in the normal rendering pass. + // Just something to watch out for, however... + if (shouldRenderTranslucent) { + levelRenderer.invokeRenderChunkLayer(RenderType.translucent(), modelView, cameraX, cameraY, cameraZ); + } + + // Note: Apparently tripwire isn't rendered in the shadow pass. + // worldRenderer.invokeRenderType(RenderType.getTripwire(), modelView, cameraX, cameraY, cameraZ); + + if (renderBuffersExt != null) { + renderBuffersExt.endLevelRendering(); + } + + debugStringTerrain = ((LevelRenderer) levelRenderer).getChunkStatistics(); + + profiler.endStartSection("generate mipmaps"); + + generateMipmaps(); + + profiler.endStartSection("restore gl state"); + + restoreGlState(); + + if (levelRenderer instanceof CullingDataCache) { + ((CullingDataCache) levelRenderer).restoreState(); + } + + levelRenderer.setRenderBuffers(playerBuffers); + + ACTIVE = false; + profiler.endSection(); + profiler.endStartSection("updatechunks"); + } + + public void addDebugText(List messages) { + messages.add("[" + Iris.MODNAME + "] Shadow Maps: " + debugStringOverall); + messages.add("[" + Iris.MODNAME + "] Shadow Distance Terrain: " + terrainFrustumHolder.getDistanceInfo() + " Entity: " + entityFrustumHolder.getDistanceInfo()); + messages.add("[" + Iris.MODNAME + "] Shadow Culling Terrain: " + terrainFrustumHolder.getCullingInfo() + " Entity: " + entityFrustumHolder.getCullingInfo()); + messages.add("[" + Iris.MODNAME + "] Shadow Terrain: " + debugStringTerrain + + (shouldRenderTerrain ? "" : " (no terrain) ") + (shouldRenderTranslucent ? "" : "(no translucent)")); + messages.add("[" + Iris.MODNAME + "] Shadow Entities: " + getEntitiesDebugString()); + messages.add("[" + Iris.MODNAME + "] Shadow Block Entities: " + getTileEntitiesDebugString()); + + if (buffers instanceof DrawCallTrackingRenderBuffers && (shouldRenderEntities || shouldRenderPlayer)) { + DrawCallTrackingRenderBuffers drawCallTracker = (DrawCallTrackingRenderBuffers) buffers; + messages.add("[" + Iris.MODNAME + "] Shadow Entity Batching: " + BatchingDebugMessageHelper.getDebugMessage(drawCallTracker)); + } + } + + private String getEntitiesDebugString() { + return (shouldRenderEntities || shouldRenderPlayer) ? (renderedShadowEntities + "/" + Minecraft.getMinecraft().theWorld.loadedEntityList.size()) : "disabled by pack"; + } + + private String getTileEntitiesDebugString() { + return shouldRenderBlockEntities ? (renderedShadowBlockEntities + "/" + Minecraft.getMinecraft().theWorld.loadedTileEntityList.size()) : "disabled by pack"; + } + + private static class MipmapPass { + private final int texture; + private final int targetFilteringMode; + + public MipmapPass(int texture, int targetFilteringMode) { + this.texture = texture; + this.targetFilteringMode = targetFilteringMode; + } + + public int getTexture() { + return texture; + } + + public int getTargetFilteringMode() { + return targetFilteringMode; + } + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/SodiumTerrainPipeline.java b/src/main/java/net/coderbot/iris/pipeline/SodiumTerrainPipeline.java new file mode 100644 index 000000000..946bf78ab --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/SodiumTerrainPipeline.java @@ -0,0 +1,180 @@ +package net.coderbot.iris.pipeline; + +import net.coderbot.iris.gl.program.ProgramImages; +import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.program.ProgramUniforms; +import net.coderbot.iris.pipeline.transform.PatchShaderType; +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.builtin.BuiltinReplacementUniforms; + +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.IntFunction; + +public class SodiumTerrainPipeline { + Optional terrainVertex = Optional.empty(); + Optional terrainGeometry = Optional.empty(); + Optional terrainFragment = Optional.empty(); + Optional translucentVertex = Optional.empty(); + Optional translucentGeometry = Optional.empty(); + Optional translucentFragment = Optional.empty(); + Optional shadowVertex = Optional.empty(); + Optional shadowGeometry = Optional.empty(); + Optional shadowFragment = Optional.empty(); + //GlFramebuffer framebuffer; + ProgramSet programSet; + + private final WorldRenderingPipeline parent; + + private final IntFunction createTerrainSamplers; + private final IntFunction createShadowSamplers; + + private final IntFunction createTerrainImages; + private final IntFunction createShadowImages; + + public SodiumTerrainPipeline(WorldRenderingPipeline parent, + ProgramSet programSet, IntFunction createTerrainSamplers, + IntFunction createShadowSamplers, + IntFunction createTerrainImages, + IntFunction createShadowImages) { + this.parent = Objects.requireNonNull(parent); + + Optional terrainSource = first(programSet.getGbuffersTerrain(), programSet.getGbuffersTexturedLit(), programSet.getGbuffersTextured(), programSet.getGbuffersBasic()); + Optional translucentSource = first(programSet.getGbuffersWater(), terrainSource); + Optional shadowSource = programSet.getShadow(); + + this.programSet = programSet; + + terrainSource.ifPresent(sources -> { + Map result = TransformPatcher.patchSodiumTerrain( + sources.getVertexSource().orElse(null), + sources.getGeometrySource().orElse(null), + sources.getFragmentSource().orElse(null)); + terrainVertex = Optional.ofNullable(result.get(PatchShaderType.VERTEX)); + terrainGeometry = Optional.ofNullable(result.get(PatchShaderType.GEOMETRY)); + terrainFragment = Optional.ofNullable(result.get(PatchShaderType.FRAGMENT)); + + PatchedShaderPrinter.debugPatchedShaders(sources.getName() + "_sodium", + terrainVertex.orElse(null), terrainGeometry.orElse(null), terrainFragment.orElse(null)); + }); + + translucentSource.ifPresent(sources -> { + Map result = TransformPatcher.patchSodiumTerrain( + sources.getVertexSource().orElse(null), + sources.getGeometrySource().orElse(null), + sources.getFragmentSource().orElse(null)); + translucentVertex = Optional.ofNullable(result.get(PatchShaderType.VERTEX)); + translucentGeometry = Optional.ofNullable(result.get(PatchShaderType.GEOMETRY)); + translucentFragment = Optional.ofNullable(result.get(PatchShaderType.FRAGMENT)); + + PatchedShaderPrinter.debugPatchedShaders(sources.getName() + "_sodium", + translucentVertex.orElse(null), translucentGeometry.orElse(null), translucentFragment.orElse(null)); + }); + + shadowSource.ifPresent(sources -> { + Map result = TransformPatcher.patchSodiumTerrain( + sources.getVertexSource().orElse(null), + sources.getGeometrySource().orElse(null), + sources.getFragmentSource().orElse(null)); + shadowVertex = Optional.ofNullable(result.get(PatchShaderType.VERTEX)); + shadowGeometry = Optional.ofNullable(result.get(PatchShaderType.GEOMETRY)); + shadowFragment = Optional.ofNullable(result.get(PatchShaderType.FRAGMENT)); + + PatchedShaderPrinter.debugPatchedShaders(sources.getName() + "_sodium", + shadowVertex.orElse(null), shadowGeometry.orElse(null), shadowFragment.orElse(null)); + }); + + this.createTerrainSamplers = createTerrainSamplers; + this.createShadowSamplers = createShadowSamplers; + this.createTerrainImages = createTerrainImages; + this.createShadowImages = createShadowImages; + } + + public Optional getTerrainVertexShaderSource() { + return terrainVertex; + } + + public Optional getTerrainGeometryShaderSource() { + return terrainGeometry; + } + + public Optional getTerrainFragmentShaderSource() { + return terrainFragment; + } + + public Optional getTranslucentVertexShaderSource() { + return translucentVertex; + } + + public Optional getTranslucentGeometryShaderSource() { + return translucentGeometry; + } + + public Optional getTranslucentFragmentShaderSource() { + return translucentFragment; + } + + public Optional getShadowVertexShaderSource() { + return shadowVertex; + } + + public Optional getShadowGeometryShaderSource() { + return shadowGeometry; + } + + public Optional getShadowFragmentShaderSource() { + return shadowFragment; + } + + public ProgramUniforms initUniforms(int programId) { + ProgramUniforms.Builder uniforms = ProgramUniforms.builder("", programId); + + CommonUniforms.addCommonUniforms(uniforms, programSet.getPack().getIdMap(), programSet.getPackDirectives(), parent.getFrameUpdateNotifier()); + BuiltinReplacementUniforms.addBuiltinReplacementUniforms(uniforms); + + return uniforms.buildUniforms(); + } + + public boolean hasShadowPass() { + return createShadowSamplers != null; + } + + public ProgramSamplers initTerrainSamplers(int programId) { + return createTerrainSamplers.apply(programId); + } + + public ProgramSamplers initShadowSamplers(int programId) { + return createShadowSamplers.apply(programId); + } + + public ProgramImages initTerrainImages(int programId) { + return createTerrainImages.apply(programId); + } + + public ProgramImages initShadowImages(int programId) { + return createShadowImages.apply(programId); + } + + /*public void bindFramebuffer() { + this.framebuffer.bind(); + } + + public void unbindFramebuffer() { + GlStateManager.bindFramebuffer(GL30.GL_FRAMEBUFFER, 0); + }*/ + + @SafeVarargs + private static Optional first(Optional... candidates) { + for (Optional candidate : candidates) { + if (candidate.isPresent()) { + return candidate; + } + } + + return Optional.empty(); + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java new file mode 100644 index 000000000..71230de51 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java @@ -0,0 +1,45 @@ +package net.coderbot.iris.pipeline; + + +public enum WorldRenderingPhase { + NONE, + SKY, + SUNSET, + CUSTOM_SKY, // Unused, just here to match OptiFine ordinals + SUN, + MOON, + STARS, + VOID, + TERRAIN_SOLID, + TERRAIN_CUTOUT_MIPPED, + TERRAIN_CUTOUT, + ENTITIES, + BLOCK_ENTITIES, + DESTROY, + OUTLINE, + DEBUG, + HAND_SOLID, + TERRAIN_TRANSLUCENT, + TRIPWIRE, + PARTICLES, + CLOUDS, + RAIN_SNOW, + WORLD_BORDER, + HAND_TRANSLUCENT; + + public static WorldRenderingPhase fromTerrainRenderType(RenderType renderType) { + if (renderType == RenderType.solid()) { + return WorldRenderingPhase.TERRAIN_SOLID; + } else if (renderType == RenderType.cutout()) { + return WorldRenderingPhase.TERRAIN_CUTOUT; + } else if (renderType == RenderType.cutoutMipped()) { + return WorldRenderingPhase.TERRAIN_CUTOUT_MIPPED; + } else if (renderType == RenderType.translucent()) { + return WorldRenderingPhase.TERRAIN_TRANSLUCENT; + } else if (renderType == RenderType.tripwire()) { + return WorldRenderingPhase.TRIPWIRE; + } else { + throw new IllegalStateException("Illegal render type!"); + } + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java new file mode 100644 index 000000000..6a735c065 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java @@ -0,0 +1,55 @@ +package net.coderbot.iris.pipeline; + +import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; +import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; +import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; +import net.coderbot.iris.shaderpack.CloudSetting; +import net.coderbot.iris.uniforms.FrameUpdateNotifier; + +import java.util.List; +import java.util.OptionalInt; + +public interface WorldRenderingPipeline { + void beginLevelRendering(); + void renderShadows(LevelRendererAccessor levelRenderer, Camera camera); + void addDebugText(List messages); + OptionalInt getForcedShadowRenderDistanceChunksForDisplay(); + + WorldRenderingPhase getPhase(); + + void beginSodiumTerrainRendering(); + void endSodiumTerrainRendering(); + void setOverridePhase(WorldRenderingPhase phase); + void setPhase(WorldRenderingPhase phase); + void setInputs(InputAvailability availability); + void setSpecialCondition(SpecialCondition special); + void syncProgram(); + RenderTargetStateListener getRenderTargetStateListener(); + + int getCurrentNormalTexture(); + int getCurrentSpecularTexture(); + + void onBindTexture(int id); + + void beginHand(); + + void beginTranslucents(); + void finalizeLevelRendering(); + void destroy(); + + SodiumTerrainPipeline getSodiumTerrainPipeline(); + FrameUpdateNotifier getFrameUpdateNotifier(); + + boolean shouldDisableVanillaEntityShadows(); + boolean shouldDisableDirectionalShading(); + CloudSetting getCloudSetting(); + boolean shouldRenderUnderwaterOverlay(); + boolean shouldRenderVignette(); + boolean shouldRenderSun(); + boolean shouldRenderMoon(); + boolean shouldWriteRainAndSnowToDepthBuffer(); + boolean shouldRenderParticlesBeforeDeferred(); + boolean allowConcurrentCompute(); + + float getSunPathRotation(); +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/AttributeParameters.java b/src/main/java/net/coderbot/iris/pipeline/transform/AttributeParameters.java new file mode 100644 index 000000000..11d85b53f --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/AttributeParameters.java @@ -0,0 +1,42 @@ +package net.coderbot.iris.pipeline.transform; + +import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; + +class AttributeParameters extends Parameters { + public final boolean hasGeometry; + public final InputAvailability inputs; + + public AttributeParameters(Patch patch, boolean hasGeometry, InputAvailability inputs) { + super(patch); + this.hasGeometry = hasGeometry; + this.inputs = inputs; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (hasGeometry ? 1231 : 1237); + result = prime * result + ((inputs == null) ? 0 : inputs.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + AttributeParameters other = (AttributeParameters) obj; + if (hasGeometry != other.hasGeometry) + return false; + if (inputs == null) { + if (other.inputs != null) + return false; + } else if (!inputs.equals(other.inputs)) + return false; + return true; + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/AttributeTransformer.java b/src/main/java/net/coderbot/iris/pipeline/transform/AttributeTransformer.java new file mode 100644 index 000000000..bf0c333cd --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/AttributeTransformer.java @@ -0,0 +1,167 @@ +package net.coderbot.iris.pipeline.transform; + +import io.github.douira.glsl_transformer.ast.node.Identifier; +import io.github.douira.glsl_transformer.ast.node.Profile; +import io.github.douira.glsl_transformer.ast.node.TranslationUnit; +import io.github.douira.glsl_transformer.ast.node.basic.ASTNode; +import io.github.douira.glsl_transformer.ast.node.external_declaration.ExternalDeclaration; +import io.github.douira.glsl_transformer.ast.query.Root; +import io.github.douira.glsl_transformer.ast.query.match.AutoHintedMatcher; +import io.github.douira.glsl_transformer.ast.query.match.Matcher; +import io.github.douira.glsl_transformer.ast.transform.ASTInjectionPoint; +import io.github.douira.glsl_transformer.ast.transform.ASTParser; +import net.coderbot.iris.gl.shader.ShaderType; + +import java.util.stream.Stream; + +/** + * Implements AttributeShaderTransformer using glsl-transformer AST + * transformation methods. + */ +class AttributeTransformer { + public static void transform( + ASTParser t, + TranslationUnit tree, + Root root, + AttributeParameters parameters) { + boolean isCore = (tree.getVersionStatement().profile == Profile.CORE || (tree.getVersionStatement().profile == null && tree.getVersionStatement().version.number > 140)); + if (isCore) { + if (parameters.type == PatchShaderType.VERTEX) { + throw new IllegalStateException("Vertex shaders must be in the compatibility profile to run properly!"); + } + return; + } + + // gl_MultiTexCoord1 and gl_MultiTexCoord2 are both ways to refer to the + // lightmap texture coordinate. + // See https://github.com/IrisShaders/Iris/issues/1149 + if (parameters.inputs.lightmap) { + root.rename("gl_MultiTexCoord1", "gl_MultiTexCoord2"); + } + + Stream stream = Stream.empty(); + boolean hasItems = false; + if (!parameters.inputs.lightmap) { + stream = Stream.concat(stream, + root.identifierIndex.getStream("gl_MultiTexCoord1")); + stream = Stream.concat(stream, + root.identifierIndex.getStream("gl_MultiTexCoord2")); + hasItems = true; + } + if (!parameters.inputs.texture) { + stream = Stream.concat(stream, + root.identifierIndex.getStream("gl_MultiTexCoord0")); + hasItems = true; + } + if (hasItems) { + root.replaceReferenceExpressions(t, stream, "vec4(240.0, 240.0, 0.0, 1.0)"); + } + + patchTextureMatrices(t, tree, root, parameters.inputs.lightmap); + + if (parameters.inputs.overlay) { + patchOverlayColor(t, tree, root, parameters); + } + + if (parameters.type.glShaderType == ShaderType.VERTEX + && root.identifierIndex.has("gl_MultiTexCoord3") + && !root.identifierIndex.has("mc_midTexCoord")) { + // TODO: proper type conversion + // gl_MultiTexCoord3 is a super legacy alias of mc_midTexCoord. We don't do this + // replacement if we think mc_midTexCoord could be defined just we can't handle + // an existing declaration robustly. But basically the proper way to do this is + // to define mc_midTexCoord only if it's not defined, and if it is defined, + // figure out its type, then replace all occurrences of gl_MultiTexCoord3 with + // the correct conversion from mc_midTexCoord's declared type to vec4. + root.rename("gl_MultiTexCoord3", "mc_midTexCoord"); + tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_FUNCTIONS, + "attribute vec4 mc_midTexCoord;"); + } + } + + private static void patchTextureMatrices( + ASTParser t, + TranslationUnit tree, + Root root, + boolean hasLightmap) { + root.rename("gl_TextureMatrix", "iris_TextureMatrix"); + + tree.parseAndInjectNodes(t, ASTInjectionPoint.BEFORE_FUNCTIONS, + "const float iris_ONE_OVER_256 = 0.00390625;", + "const float iris_ONE_OVER_32 = iris_ONE_OVER_256 * 8;"); + if (hasLightmap) { + tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_FUNCTIONS, + "mat4 iris_LightmapTextureMatrix = gl_TextureMatrix[2];"); + } else { + tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_FUNCTIONS, "mat4 iris_LightmapTextureMatrix =" + + "mat4(iris_ONE_OVER_256, 0.0, 0.0, 0.0," + + " 0.0, iris_ONE_OVER_256, 0.0, 0.0," + + " 0.0, 0.0, iris_ONE_OVER_256, 0.0," + + " iris_ONE_OVER_32, iris_ONE_OVER_32, iris_ONE_OVER_32, iris_ONE_OVER_256);"); + } + + // column major + tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_FUNCTIONS, "mat4 iris_TextureMatrix[8] = mat4[8](" + + "gl_TextureMatrix[0]," + + "iris_LightmapTextureMatrix," + + "mat4(1.0)," + + "mat4(1.0)," + + "mat4(1.0)," + + "mat4(1.0)," + + "mat4(1.0)," + + "mat4(1.0)" + + ");"); + } + + private static final AutoHintedMatcher uniformVec4EntityColor = new AutoHintedMatcher<>( + "uniform vec4 entityColor;", Matcher.externalDeclarationPattern); + + // Add entity color -> overlay color attribute support. + private static void patchOverlayColor( + ASTParser t, + TranslationUnit tree, + Root root, + AttributeParameters parameters) { + // delete original declaration + root.processMatches(t, uniformVec4EntityColor, ASTNode::detachAndDelete); + + if (parameters.type.glShaderType == ShaderType.VERTEX) { + // add our own declarations + // TODO: We're exposing entityColor to this stage even if it isn't declared in + // this stage. But this is needed for the pass-through behavior. + tree.parseAndInjectNodes(t, ASTInjectionPoint.BEFORE_FUNCTIONS, + "uniform sampler2D iris_overlay;", + "varying vec4 entityColor;"); + + // this is so we can pass through the overlay color at the end to the geometry + // or fragment stage. + tree.prependMain(t, + "vec4 overlayColor = texture2D(iris_overlay, (gl_TextureMatrix[1] * gl_MultiTexCoord1).xy);", + "entityColor = vec4(overlayColor.rgb, 1.0 - overlayColor.a);", + // Workaround for a shader pack bug: + // https://github.com/IrisShaders/Iris/issues/1549 + // Some shader packs incorrectly ignore the alpha value, and assume that rgb + // will be + // zero if there is no hit flash, we try to emulate that here + "entityColor.rgb *= float(entityColor.a != 0.0);"); + } else if (parameters.type.glShaderType == ShaderType.GEOMETRY) { + // replace read references to grab the color from the first vertex. + root.replaceReferenceExpressions(t, "entityColor", "entityColor[0]"); + + // TODO: this is passthrough behavior + tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_FUNCTIONS, + "out vec4 entityColorGS;"); + tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_FUNCTIONS, + "in vec4 entityColor[];"); + tree.prependMain(t, "entityColorGS = entityColor[0];"); + } else if (parameters.type.glShaderType == ShaderType.FRAGMENT) { + tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_DECLARATIONS, + "varying vec4 entityColor;"); + + // Different output name to avoid a name collision in the geometry shader. + if (parameters.hasGeometry) { + root.rename("entityColor", "entityColorGS"); + } + } + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/CompatibilityTransformer.java b/src/main/java/net/coderbot/iris/pipeline/transform/CompatibilityTransformer.java new file mode 100644 index 000000000..cb31757e1 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/CompatibilityTransformer.java @@ -0,0 +1,544 @@ +package net.coderbot.iris.pipeline.transform; + +import io.github.douira.glsl_transformer.ast.node.Identifier; +import io.github.douira.glsl_transformer.ast.node.TranslationUnit; +import io.github.douira.glsl_transformer.ast.node.basic.ASTNode; +import io.github.douira.glsl_transformer.ast.node.declaration.DeclarationMember; +import io.github.douira.glsl_transformer.ast.node.declaration.FunctionParameter; +import io.github.douira.glsl_transformer.ast.node.declaration.TypeAndInitDeclaration; +import io.github.douira.glsl_transformer.ast.node.expression.Expression; +import io.github.douira.glsl_transformer.ast.node.expression.LiteralExpression; +import io.github.douira.glsl_transformer.ast.node.expression.ReferenceExpression; +import io.github.douira.glsl_transformer.ast.node.expression.unary.FunctionCallExpression; +import io.github.douira.glsl_transformer.ast.node.external_declaration.DeclarationExternalDeclaration; +import io.github.douira.glsl_transformer.ast.node.external_declaration.EmptyDeclaration; +import io.github.douira.glsl_transformer.ast.node.external_declaration.ExternalDeclaration; +import io.github.douira.glsl_transformer.ast.node.external_declaration.FunctionDefinition; +import io.github.douira.glsl_transformer.ast.node.statement.Statement; +import io.github.douira.glsl_transformer.ast.node.type.qualifier.StorageQualifier; +import io.github.douira.glsl_transformer.ast.node.type.qualifier.StorageQualifier.StorageType; +import io.github.douira.glsl_transformer.ast.node.type.qualifier.TypeQualifier; +import io.github.douira.glsl_transformer.ast.node.type.qualifier.TypeQualifierPart; +import io.github.douira.glsl_transformer.ast.node.type.specifier.BuiltinNumericTypeSpecifier; +import io.github.douira.glsl_transformer.ast.node.type.specifier.FunctionPrototype; +import io.github.douira.glsl_transformer.ast.node.type.specifier.TypeSpecifier; +import io.github.douira.glsl_transformer.ast.query.Root; +import io.github.douira.glsl_transformer.ast.query.match.AutoHintedMatcher; +import io.github.douira.glsl_transformer.ast.query.match.Matcher; +import io.github.douira.glsl_transformer.ast.transform.ASTInjectionPoint; +import io.github.douira.glsl_transformer.ast.transform.ASTParser; +import io.github.douira.glsl_transformer.ast.transform.Template; +import io.github.douira.glsl_transformer.util.Type; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.shader.ShaderType; +import net.coderbot.iris.pipeline.PatchedShaderPrinter; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +public class CompatibilityTransformer { + static Logger LOGGER = LogManager.getLogger(CompatibilityTransformer.class); + + private static final AutoHintedMatcher sildursWaterFract = new AutoHintedMatcher<>( + "fract(worldpos.y + 0.001)", Matcher.expressionPattern); + + private static StorageQualifier getConstQualifier(TypeQualifier qualifier) { + if (qualifier == null) { + return null; + } + for (TypeQualifierPart constQualifier : qualifier.getChildren()) { + if (constQualifier instanceof StorageQualifier) { + StorageQualifier storageQualifier = (StorageQualifier) constQualifier; + if (storageQualifier.storageType == StorageQualifier.StorageType.CONST) { + return storageQualifier; + } + } + } + return null; + } + + public static void transformEach(ASTParser t, TranslationUnit tree, Root root, Parameters parameters) { + if (parameters.type == PatchShaderType.VERTEX) { + if (root.replaceExpressionMatches(t, sildursWaterFract, "fract(worldpos.y + 0.01)")) { + Iris.logger.warn("Patched fract(worldpos.y + 0.001) to fract(worldpos.y + 0.01) to fix " + + "waving water disconnecting from other water blocks; See https://github.com/IrisShaders/Iris/issues/509"); + } + } + + /** + * Removes const storage qualifier from declarations in functions if they are + * initialized with const parameters. Const parameters are immutable parameters + * and can't be used to initialize const declarations because they expect + * constant, not just immutable, expressions. This varies between drivers and + * versions. Also removes the const qualifier from declarations that use the + * identifiers from which the declaration was removed previously. + * See https://wiki.shaderlabs.org/wiki/Compiler_Behavior_Notes + */ + Map> constFunctions = new HashMap<>(); + Set processingSet = new HashSet<>(); + List unusedFunctions = new LinkedList<>(); + for (FunctionDefinition definition : root.nodeIndex.get(FunctionDefinition.class)) { + // check if this function is ever used + FunctionPrototype prototype = definition.getFunctionPrototype(); + String functionName = prototype.getName().getName(); + if (!functionName.equals("main") && root.identifierIndex.getStream(functionName).count() <= 1) { + // remove unused functions + // unused function removal can be helpful since some drivers don't do some + // checks on unused functions. Additionally, sometimes bugs in unused code can + // be avoided this way. + // TODO: integrate into debug mode (allow user to disable this behavior for + // debugging purposes) + unusedFunctions.add(definition); + if (PatchedShaderPrinter.prettyPrintShaders) { + LOGGER.warn("Removing unused function " + functionName); + } else if (unusedFunctions.size() == 1) { + LOGGER.warn( + "Removing unused function " + functionName + + " and omitting further such messages outside of debug mode. See debugging.md for more information."); + } + continue; + } + + // stop on functions without parameters + if (prototype.getChildren().isEmpty()) { + continue; + } + + // find the const parameters + Set names = new HashSet<>(prototype.getChildren().size()); + for (FunctionParameter parameter : prototype.getChildren()) { + if (getConstQualifier(parameter.getType().getTypeQualifier()) != null) { + String name = parameter.getName().getName(); + names.add(name); + processingSet.add(name); + } + } + if (!names.isEmpty()) { + constFunctions.put(definition, names); + } + } + + // remove collected unused functions + for (FunctionDefinition definition : unusedFunctions) { + definition.detachAndDelete(); + } + + // find the reference expressions for the const parameters + // and check that they are in the right function and are of the right type + boolean constDeclarationHit = false; + Deque processingQueue = new ArrayDeque<>(processingSet); + while (!processingQueue.isEmpty()) { + String name = processingQueue.poll(); + processingSet.remove(name); + for (Identifier id : root.identifierIndex.get(name)) { + // since this searches for reference expressions, this won't accidentally find + // the name as the name of a declaration member + ReferenceExpression reference = id.getAncestor(ReferenceExpression.class); + if (reference == null) { + continue; + } + TypeAndInitDeclaration taid = reference.getAncestor(TypeAndInitDeclaration.class); + if (taid == null) { + continue; + } + FunctionDefinition inDefinition = taid.getAncestor(FunctionDefinition.class); + if (inDefinition == null) { + continue; + } + Set constIdsInFunction = constFunctions.get(inDefinition); + if (constIdsInFunction == null) { + continue; + } + if (constIdsInFunction.contains(name)) { + // remove the const qualifier from the reference expression + TypeQualifier qualifier = taid.getType().getTypeQualifier(); + StorageQualifier constQualifier = getConstQualifier(qualifier); + if (constQualifier == null) { + continue; + } + constQualifier.detachAndDelete(); + if (qualifier.getChildren().isEmpty()) { + qualifier.detachAndDelete(); + } + constDeclarationHit = true; + + // add all members of the declaration to the list of const parameters to process + for (DeclarationMember member : taid.getMembers()) { + String memberName = member.getName().getName(); + + // the name may not be the same as the parameter name + if (constIdsInFunction.contains(memberName)) { + throw new IllegalStateException("Illegal redefinition of const parameter " + name); + } + + constIdsInFunction.add(memberName); + + // don't add to the queue twice if it's already been added by a different scope + if (!processingSet.contains(memberName)) { + processingQueue.add(memberName); + processingSet.add(memberName); + } + } + } + } + } + + if (constDeclarationHit) { + LOGGER.warn( + "Removed the const keyword from declarations that use const parameters. See debugging.md for more information."); + } + + // remove empty external declarations + boolean emptyDeclarationHit = root.process( + root.nodeIndex.getStream(EmptyDeclaration.class), + ASTNode::detachAndDelete); + if (emptyDeclarationHit) { + LOGGER.warn( + "Removed empty external declarations (\";\")."); + } + } + + private static class DeclarationMatcher extends AutoHintedMatcher { + private final StorageType storageType; + + public DeclarationMatcher(StorageType storageType) { + super("out float name;", Matcher.externalDeclarationPattern); + this.storageType = storageType; + markClassWildcard("qualifier", pattern.getRoot().nodeIndex.getOne(TypeQualifier.class)); + markClassWildcard("type", pattern.getRoot().nodeIndex.getOne(BuiltinNumericTypeSpecifier.class)); + markClassWildcard("name*", pattern.getRoot().identifierIndex.getOne("name").getAncestor(DeclarationMember.class)); + } + + public boolean matchesSpecialized(ExternalDeclaration tree, ShaderType shaderType) { + boolean result = super.matchesExtract(tree); + if (!result) { + return false; + } + TypeQualifier qualifier = getNodeMatch("qualifier", TypeQualifier.class); + for (TypeQualifierPart part : qualifier.getParts()) { + if (part instanceof StorageQualifier) { + StorageQualifier storageQualifier = (StorageQualifier) part; + StorageType qualifierStorageType = storageQualifier.storageType; + // TODO: investigate the specified behavior of varying in geometry shaders and + // the combination of varying with in or out qualifiers + if (qualifierStorageType == storageType || + qualifierStorageType == StorageType.VARYING && + (shaderType == ShaderType.VERTEX && storageType == StorageType.OUT || + shaderType == ShaderType.GEOMETRY && storageType == StorageType.OUT || + shaderType == ShaderType.FRAGMENT && storageType == StorageType.IN)) { + return true; + } + } + } + return false; + } + } + + private static final ShaderType[] pipeline = { ShaderType.VERTEX, ShaderType.GEOMETRY, ShaderType.FRAGMENT }; + private static final DeclarationMatcher outDeclarationMatcher = new DeclarationMatcher(StorageType.OUT); + private static final DeclarationMatcher inDeclarationMatcher = new DeclarationMatcher(StorageType.IN); + + private static final String tagPrefix = "iris_template_"; + private static final Template declarationTemplate = Template + .withExternalDeclaration("out __type __name;"); + private static final Template initTemplate = Template.withStatement("__decl = __value;"); + private static final Template variableTemplate = Template + .withExternalDeclaration("__type __internalDecl;"); + private static final Template statementTemplate = Template + .withStatement("__oldDecl = vec3(__internalDecl);"); + private static final Template statementTemplateVector = Template + .withStatement("__oldDecl = vec3(__internalDecl, vec4(0));"); + + static { + declarationTemplate.markLocalReplacement(declarationTemplate.getSourceRoot().nodeIndex.getOne(TypeQualifier.class)); + declarationTemplate.markLocalReplacement("__type", TypeSpecifier.class); + declarationTemplate.markIdentifierReplacement("__name"); + initTemplate.markIdentifierReplacement("__decl"); + initTemplate.markLocalReplacement("__value", ReferenceExpression.class); + variableTemplate.markLocalReplacement("__type", TypeSpecifier.class); + variableTemplate.markIdentifierReplacement("__internalDecl"); + statementTemplate.markIdentifierReplacement("__oldDecl"); + statementTemplate.markIdentifierReplacement("__internalDecl"); + statementTemplate.markLocalReplacement( + statementTemplate.getSourceRoot().nodeIndex.getStream(BuiltinNumericTypeSpecifier.class) + .filter(specifier -> specifier.type == Type.F32VEC3).findAny().get()); + statementTemplateVector.markIdentifierReplacement("__oldDecl"); + statementTemplateVector.markIdentifierReplacement("__internalDecl"); + statementTemplateVector.markLocalReplacement( + statementTemplateVector.getSourceRoot().nodeIndex.getStream(BuiltinNumericTypeSpecifier.class) + .filter(specifier -> specifier.type == Type.F32VEC3).findAny().get()); + } + + private static Statement getInitializer(Root root, String name, Type type) { + return initTemplate.getInstanceFor(root, + new Identifier(name), + type.isScalar() + ? LiteralExpression.getDefaultValue(type) + : Root.indexNodes(root, () -> new FunctionCallExpression( + new Identifier(type.getMostCompactName()), + Stream.of(LiteralExpression.getDefaultValue(type))))); + } + + private static TypeQualifier makeQualifierOut(TypeQualifier typeQualifier) { + for (TypeQualifierPart qualifierPart : typeQualifier.getParts()) { + if (qualifierPart instanceof StorageQualifier) { + StorageQualifier storageQualifier = (StorageQualifier) qualifierPart; + if (((StorageQualifier) qualifierPart).storageType == StorageType.IN) { + storageQualifier.storageType = StorageType.OUT; + } + } + } + return typeQualifier; + } + + // does transformations that require cross-shader type data + public static void transformGrouped( + ASTParser t, + Map trees, + Parameters parameters) { + /** + * find attributes that are declared as "in" in geometry or fragment but not + * declared as "out" in the previous stage. The missing "out" declarations for + * these attributes are added and initialized. + * + * It doesn't bother with array specifiers because they are only legal in + * geometry shaders, but then also only as an in declaration. The out + * declaration in the vertex shader is still just a single value. Missing out + * declarations in the geometry shader are also just normal. + * + * TODO: + * - fix issues where Iris' own declarations are detected and patched like + * iris_FogFragCoord if there are geometry shaders present + * - improved geometry shader support? They use funky declarations + */ + ShaderType prevType = null; + for (int i = 0; i < pipeline.length; i++) { + ShaderType type = pipeline[i]; + PatchShaderType[] patchTypes = PatchShaderType.fromGlShaderType(type); + + // check if the patch types have sources and continue if not + boolean hasAny = false; + for (PatchShaderType currentType : patchTypes) { + if (trees.get(currentType) != null) { + hasAny = true; + } + } + if (!hasAny) { + continue; + } + + // if the current type has sources but the previous one doesn't, set the + // previous one and continue + if (prevType == null) { + prevType = type; + continue; + } + + PatchShaderType prevPatchTypes = PatchShaderType.fromGlShaderType(prevType)[0]; + TranslationUnit prevTree = trees.get(prevPatchTypes); + Root prevRoot = prevTree.getRoot(); + + // test if the prefix tag is used for some reason + if (prevRoot.identifierIndex.prefixQueryFlat(tagPrefix).findAny().isPresent()) { + LOGGER.warn("The prefix tag " + tagPrefix + " is used in the shader, bailing compatibility transformation."); + return; + } + + // find out declarations + Map outDeclarations = new HashMap<>(); + for (DeclarationExternalDeclaration declaration : prevRoot.nodeIndex.get(DeclarationExternalDeclaration.class)) { + if (outDeclarationMatcher.matchesSpecialized(declaration, prevType)) { + BuiltinNumericTypeSpecifier extractedType = outDeclarationMatcher.getNodeMatch("type", + BuiltinNumericTypeSpecifier.class); + for (DeclarationMember member : outDeclarationMatcher + .getNodeMatch("name*", DeclarationMember.class) + .getAncestor(TypeAndInitDeclaration.class) + .getMembers()) { + String name = member.getName().getName(); + if (!name.startsWith("gl_")) { + outDeclarations.put(name, extractedType); + } + } + } + } + + // add out declarations that are missing for in declarations + for (PatchShaderType currentType : patchTypes) { + TranslationUnit currentTree = trees.get(currentType); + if (currentTree == null) { + continue; + } + Root currentRoot = currentTree.getRoot(); + + for (ExternalDeclaration declaration : currentRoot.nodeIndex.get(DeclarationExternalDeclaration.class)) { + if (!inDeclarationMatcher.matchesSpecialized(declaration, currentType.glShaderType)) { + continue; + } + + BuiltinNumericTypeSpecifier inTypeSpecifier = inDeclarationMatcher.getNodeMatch("type", + BuiltinNumericTypeSpecifier.class); + for (DeclarationMember inDeclarationMember : inDeclarationMatcher + .getNodeMatch("name*", DeclarationMember.class) + .getAncestor(TypeAndInitDeclaration.class) + .getMembers()) { + String name = inDeclarationMember.getName().getName(); + if (name.startsWith("gl_")) { + continue; + } + + // patch missing declarations with an initialization + if (!outDeclarations.containsKey(name)) { + // make sure the declared in is actually used + if (!currentRoot.identifierIndex.getAncestors(name, ReferenceExpression.class).findAny().isPresent()) { + continue; + } + + if (inTypeSpecifier == null) { + LOGGER.warn( + "The in declaration '" + name + "' in the " + currentType.glShaderType.name() + + " shader that has a missing corresponding out declaration in the previous stage " + + prevType.name() + " has a non-numeric type and could not be compatibility-patched. See debugging.md for more information."); + continue; + } + Type inType = inTypeSpecifier.type; + + // insert the new out declaration but copy over the type qualifiers, except for + // the in/out qualifier + TypeQualifier outQualifier = (TypeQualifier) inDeclarationMatcher + .getNodeMatch("qualifier").cloneInto(prevRoot); + makeQualifierOut(outQualifier); + prevTree.injectNode(ASTInjectionPoint.BEFORE_DECLARATIONS, declarationTemplate.getInstanceFor(prevRoot, + outQualifier, + inTypeSpecifier.cloneInto(prevRoot), + new Identifier(name))); + + // add the initializer to the main function + prevTree.prependMain(getInitializer(prevRoot, name, inType)); + + // update out declarations to prevent duplicates + outDeclarations.put(name, null); + + LOGGER.warn( + "The in declaration '" + name + "' in the " + currentType.glShaderType.name() + + " shader is missing a corresponding out declaration in the previous stage " + + prevType.name() + " and has been compatibility-patched. See debugging.md for more information."); + } + + // patch mismatching declaration with a local variable and a cast + else { + // there is an out declaration for this in declaration, check if the types match + BuiltinNumericTypeSpecifier outTypeSpecifier = outDeclarations.get(name); + + // skip newly inserted out declarations + if (outTypeSpecifier == null) { + continue; + } + + Type inType = inTypeSpecifier.type; + Type outType = outTypeSpecifier.type; + + // skip if the type matches, nothing has to be done + if (inType == outType) { + // if the types match but it's never assigned a value, + // an initialization is added + if (prevRoot.identifierIndex.get(name).size() > 1) { + continue; + } + + // add an initialization statement for this declaration + prevTree.prependMain(getInitializer(prevRoot, name, inType)); + outDeclarations.put(name, null); + continue; + } + + // bail and warn on mismatching dimensionality + if (outType.getDimension() != inType.getDimension()) { + LOGGER.warn( + "The in declaration '" + name + "' in the " + currentType.glShaderType.name() + + " shader has a mismatching dimensionality (scalar/vector/matrix) with the out declaration in the previous stage " + + prevType.name() + " and could not be compatibility-patched. See debugging.md for more information."); + continue; + } + + boolean isVector = outType.isVector(); + + // rename all references of this out declaration to a new name (iris_) + String newName = tagPrefix + name; + prevRoot.identifierIndex.rename(name, newName); + + // rename the original out declaration back to the original name + TypeAndInitDeclaration outDeclaration = outTypeSpecifier.getAncestor(TypeAndInitDeclaration.class); + if (outDeclaration == null) { + continue; + } + + List outMembers = outDeclaration.getMembers(); + DeclarationMember outMember = null; + for (DeclarationMember member : outMembers) { + if (member.getName().getName().equals(newName)) { + outMember = member; + } + } + if (outMember == null) { + throw new IllegalStateException("The targeted out declaration member is missing!"); + } + outMember.getName().replaceByAndDelete(new Identifier(name)); + + // move the declaration member out of the declaration in case there is more than + // one member to avoid changing the other member's type as well. + if (outMembers.size() > 1) { + outMember.detach(); + outTypeSpecifier = outTypeSpecifier.cloneInto(prevRoot); + DeclarationExternalDeclaration singleOutDeclaration = (DeclarationExternalDeclaration) declarationTemplate + .getInstanceFor(prevRoot, + makeQualifierOut(outDeclaration.getType().getTypeQualifier().cloneInto(prevRoot)), + outTypeSpecifier, + new Identifier(name)); + ((TypeAndInitDeclaration) singleOutDeclaration.getDeclaration()).getMembers().set(0, outMember); + prevTree.injectNode(ASTInjectionPoint.BEFORE_DECLARATIONS, singleOutDeclaration); + } + + // add a global variable with the new name and the old type + prevTree.injectNode(ASTInjectionPoint.BEFORE_DECLARATIONS, variableTemplate.getInstanceFor(prevRoot, + outTypeSpecifier.cloneInto(prevRoot), + new Identifier(newName))); + + // insert a statement at the end of the main function that sets the value of the + // out declaration to the value of the global variable and does a type cast + prevTree.appendMain( + (isVector && outType.getDimensions()[0] < inType.getDimensions()[0] ? statementTemplateVector + : statementTemplate).getInstanceFor(prevRoot, + new Identifier(name), + new Identifier(newName), + inTypeSpecifier.cloneInto(prevRoot))); + + // make the out declaration use the same type as the fragment shader + outTypeSpecifier.replaceByAndDelete(inTypeSpecifier.cloneInto(prevRoot)); + + // don't do the patch twice + outDeclarations.put(name, null); + + LOGGER.warn( + "The out declaration '" + name + "' in the " + prevType.name() + + " shader has a different type " + outType.getMostCompactName() + + " than the corresponding in declaration of type " + inType.getMostCompactName() + + " in the following stage " + currentType.glShaderType.name() + + " and has been compatibility-patched. See debugging.md for more information."); + } + } + } + } + + prevType = type; + } + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/CompositeDepthTransformer.java b/src/main/java/net/coderbot/iris/pipeline/transform/CompositeDepthTransformer.java new file mode 100644 index 000000000..105a6ba35 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/CompositeDepthTransformer.java @@ -0,0 +1,30 @@ +package net.coderbot.iris.pipeline.transform; + +import io.github.douira.glsl_transformer.ast.node.TranslationUnit; +import io.github.douira.glsl_transformer.ast.node.basic.ASTNode; +import io.github.douira.glsl_transformer.ast.node.external_declaration.ExternalDeclaration; +import io.github.douira.glsl_transformer.ast.query.Root; +import io.github.douira.glsl_transformer.ast.query.match.AutoHintedMatcher; +import io.github.douira.glsl_transformer.ast.query.match.Matcher; +import io.github.douira.glsl_transformer.ast.transform.ASTInjectionPoint; +import io.github.douira.glsl_transformer.ast.transform.ASTParser; + +class CompositeDepthTransformer { + private static final AutoHintedMatcher uniformFloatCenterDepthSmooth = new AutoHintedMatcher<>( + "uniform float centerDepthSmooth;", Matcher.externalDeclarationPattern); + + public static void transform( + ASTParser t, + TranslationUnit tree, + Root root) { + // replace original declaration + if (root.processMatches(t, uniformFloatCenterDepthSmooth, ASTNode::detachAndDelete)) { + tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_DECLARATIONS, + "uniform sampler2D iris_centerDepthSmooth;"); + + // if centerDepthSmooth is not declared as a uniform, we don't make it available + root.replaceReferenceExpressions(t, "centerDepthSmooth", + "texture2D(iris_centerDepthSmooth, vec2(0.5)).r"); + } + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/CompositeTransformer.java b/src/main/java/net/coderbot/iris/pipeline/transform/CompositeTransformer.java new file mode 100644 index 000000000..e058d6c3a --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/CompositeTransformer.java @@ -0,0 +1,30 @@ +package net.coderbot.iris.pipeline.transform; + +import io.github.douira.glsl_transformer.ast.node.TranslationUnit; +import io.github.douira.glsl_transformer.ast.node.expression.unary.FunctionCallExpression; +import io.github.douira.glsl_transformer.ast.query.Root; +import io.github.douira.glsl_transformer.ast.transform.ASTInjectionPoint; +import io.github.douira.glsl_transformer.ast.transform.ASTParser; + +import java.util.stream.Stream; + +class CompositeTransformer { + public static void transform( + ASTParser t, + TranslationUnit tree, + Root root) { + CompositeDepthTransformer.transform(t, tree, root); + + // if using a lod texture sampler and on version 120, patch in the extension + // #extension GL_ARB_shader_texture_lod : require + if (tree.getVersionStatement().version.number <= 120 + && Stream.concat( + root.identifierIndex.getStream("texture2DLod"), + root.identifierIndex.getStream("texture3DLod")) + .filter(id -> id.getParent() instanceof FunctionCallExpression) + .findAny().isPresent()) { + tree.parseAndInjectNode(t, ASTInjectionPoint.BEFORE_DECLARATIONS, + "#extension GL_ARB_shader_texture_lod : require\n"); + } + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/Parameters.java b/src/main/java/net/coderbot/iris/pipeline/transform/Parameters.java new file mode 100644 index 000000000..47d5b2521 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/Parameters.java @@ -0,0 +1,37 @@ +package net.coderbot.iris.pipeline.transform; + +import io.github.douira.glsl_transformer.job_parameter.JobParameters; + +class Parameters extends JobParameters { + public final Patch patch; + public PatchShaderType type; + + public Parameters(Patch patch) { + this.patch = patch; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((patch == null) ? 0 : patch.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Parameters other = (Parameters) obj; + if (patch != other.patch) + return false; + if (type != other.type) + return false; + return true; + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/Patch.java b/src/main/java/net/coderbot/iris/pipeline/transform/Patch.java new file mode 100644 index 000000000..83332bba5 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/Patch.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.pipeline.transform; + +enum Patch { + ATTRIBUTES, + SODIUM_TERRAIN, + COMPOSITE +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/PatchShaderType.java b/src/main/java/net/coderbot/iris/pipeline/transform/PatchShaderType.java new file mode 100644 index 000000000..7c0357706 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/PatchShaderType.java @@ -0,0 +1,28 @@ +package net.coderbot.iris.pipeline.transform; + +import net.coderbot.iris.gl.shader.ShaderType; + +public enum PatchShaderType { + VERTEX(ShaderType.VERTEX), + GEOMETRY(ShaderType.GEOMETRY), + FRAGMENT(ShaderType.FRAGMENT); + + public final ShaderType glShaderType; + + private PatchShaderType(ShaderType glShaderType) { + this.glShaderType = glShaderType; + } + + public static PatchShaderType[] fromGlShaderType(ShaderType glShaderType) { + switch (glShaderType) { + case VERTEX: + return new PatchShaderType[] { VERTEX }; + case GEOMETRY: + return new PatchShaderType[] { GEOMETRY }; + case FRAGMENT: + return new PatchShaderType[] { FRAGMENT }; + default: + throw new IllegalArgumentException("Unknown shader type: " + glShaderType); + } + } +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/SodiumTerrainTransformer.java b/src/main/java/net/coderbot/iris/pipeline/transform/SodiumTerrainTransformer.java new file mode 100644 index 000000000..81473b844 --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/SodiumTerrainTransformer.java @@ -0,0 +1,112 @@ +package net.coderbot.iris.pipeline.transform; + +import io.github.douira.glsl_transformer.ast.node.TranslationUnit; +import io.github.douira.glsl_transformer.ast.node.expression.Expression; +import io.github.douira.glsl_transformer.ast.query.Root; +import io.github.douira.glsl_transformer.ast.query.match.AutoHintedMatcher; +import io.github.douira.glsl_transformer.ast.query.match.Matcher; +import io.github.douira.glsl_transformer.ast.transform.ASTInjectionPoint; +import io.github.douira.glsl_transformer.ast.transform.ASTParser; + +/** + * Does the sodium terrain transformations using glsl-transformer AST. + */ +class SodiumTerrainTransformer { + public static void transform( + ASTParser t, + TranslationUnit tree, + Root root, + Parameters parameters) { + switch (parameters.type) { + // For Sodium patching, treat fragment and geometry the same + case FRAGMENT: + case GEOMETRY: + transformFragment(t, tree, root, parameters); + break; + case VERTEX: + transformVertex(t, tree, root, parameters); + break; + default: + throw new IllegalStateException("Unexpected Sodium terrain patching shader type: " + parameters.type); + } + } + + private static final AutoHintedMatcher glTextureMatrix0 = new AutoHintedMatcher<>( + "gl_TextureMatrix[0]", Matcher.expressionPattern); + + /** + * Transforms vertex shaders. + */ + public static void transformVertex( + ASTParser t, + TranslationUnit tree, + Root root, + Parameters parameters) { + tree.parseAndInjectNodes(t, ASTInjectionPoint.BEFORE_DECLARATIONS, + "attribute vec3 iris_Pos;", + "attribute vec4 iris_Color;", + "attribute vec2 iris_TexCoord;", + "attribute vec2 iris_LightCoord;", + "attribute vec3 iris_Normal;", // some are shared + "uniform vec3 u_ModelScale;", + "uniform vec2 u_TextureScale;", + "attribute vec4 iris_ModelOffset;", + "vec4 iris_LightTexCoord = vec4(iris_LightCoord, 0, 1);", + "vec4 ftransform() { return gl_ModelViewProjectionMatrix * gl_Vertex; }"); + + transformShared(t, tree, root, parameters); + + root.replaceReferenceExpressions(t, "gl_Vertex", + "vec4((iris_Pos * u_ModelScale) + iris_ModelOffset.xyz, 1.0)"); + root.replaceReferenceExpressions(t, "gl_MultiTexCoord0", + "vec4(iris_TexCoord * u_TextureScale, 0.0, 1.0)"); + root.replaceReferenceExpressions(t, "gl_MultiTexCoord1", + "iris_LightTexCoord"); + root.replaceReferenceExpressions(t, "gl_MultiTexCoord2", + "iris_LightTexCoord"); + root.rename("gl_Color", "iris_Color"); + root.rename("gl_Normal", "iris_Normal"); + root.rename("ftransform", "iris_ftransform"); + } + + /** + * Transforms fragment shaders. The fragment shader does only the shared things + * from the vertex shader. + */ + public static void transformFragment( + ASTParser t, + TranslationUnit tree, + Root root, + Parameters parameters) { + // interestingly there is nothing that isn't shared + transformShared(t, tree, root, parameters); + } + + /** + * Does the things that transformVertex and transformFragment have in common. + */ + private static void transformShared( + ASTParser t, + TranslationUnit tree, + Root root, + Parameters parameters) { + tree.parseAndInjectNodes(t, ASTInjectionPoint.BEFORE_DECLARATIONS, + "uniform mat4 iris_ModelViewMatrix;", + "uniform mat4 u_ModelViewProjectionMatrix;", + "uniform mat4 iris_NormalMatrix;", + "uniform mat4 iris_LightmapTextureMatrix;"); + root.rename("gl_ModelViewMatrix", "iris_ModelViewMatrix"); + root.rename("gl_ModelViewProjectionMatrix", "u_ModelViewProjectionMatrix"); + root.replaceReferenceExpressions(t, + "gl_NormalMatrix", "mat3(iris_NormalMatrix)"); + + root.replaceExpressionMatches( + t, + glTextureMatrix0, + "mat4(1.0)"); + root.replaceExpressionMatches(t, glTextureMatrix1, "iris_LightmapTextureMatrix"); + } + private static final String lightmapCoordsExpression = "iris_LightCoord"; + private static final AutoHintedMatcher glTextureMatrix1 = new AutoHintedMatcher<>( + "gl_TextureMatrix[1]", Matcher.expressionPattern); +} diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/TransformPatcher.java b/src/main/java/net/coderbot/iris/pipeline/transform/TransformPatcher.java new file mode 100644 index 000000000..d9371668d --- /dev/null +++ b/src/main/java/net/coderbot/iris/pipeline/transform/TransformPatcher.java @@ -0,0 +1,226 @@ +package net.coderbot.iris.pipeline.transform; + +import io.github.douira.glsl_transformer.ast.node.Identifier; +import io.github.douira.glsl_transformer.ast.node.TranslationUnit; +import io.github.douira.glsl_transformer.ast.node.Version; +import io.github.douira.glsl_transformer.ast.print.PrintType; +import io.github.douira.glsl_transformer.ast.query.Root; +import io.github.douira.glsl_transformer.ast.transform.EnumASTTransformer; +import io.github.douira.glsl_transformer.cst.core.SemanticException; +import io.github.douira.glsl_transformer.cst.token_filter.ChannelFilter; +import io.github.douira.glsl_transformer.cst.token_filter.TokenChannel; +import io.github.douira.glsl_transformer.cst.token_filter.TokenFilter; +import io.github.douira.glsl_transformer.util.LRUCache; +import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; +import net.coderbot.iris.pipeline.PatchedShaderPrinter; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Token; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.EnumMap; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * The transform patcher (triforce 2) uses glsl-transformer's ASTTransformer to + * do shader transformation. + * + * The TransformPatcher does caching on the source string and associated + * parameters. For this to work, all objects contained in a parameter must have + * an equals method and they must never be changed after having been used for + * patching. Since the cache also contains the source string, it doesn't need to + * be disabled when developing shaderpacks. However, when changes are made to + * the patcher, the cache should be disabled with {@link #useCache}. + * + * NOTE: This patcher expects (and ensures) that the string doesn't contain any + * (!) preprocessor directives. The only allowed ones are #extension and #pragma + * as they are considered "parsed" directives. If any other directive appears in + * the string, it will throw. + */ +public class TransformPatcher { + static Logger LOGGER = LogManager.getLogger(TransformPatcher.class); + private static EnumASTTransformer transformer; + private static final boolean useCache = true; + private static final Map> cache = new LRUCache<>(400); + + private static class CacheKey { + final Parameters parameters; + final String vertex; + final String geometry; + final String fragment; + + public CacheKey(Parameters parameters, String vertex, String geometry, String fragment) { + this.parameters = parameters; + this.vertex = vertex; + this.geometry = geometry; + this.fragment = fragment; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((fragment == null) ? 0 : fragment.hashCode()); + result = prime * result + ((geometry == null) ? 0 : geometry.hashCode()); + result = prime * result + ((parameters == null) ? 0 : parameters.hashCode()); + result = prime * result + ((vertex == null) ? 0 : vertex.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CacheKey other = (CacheKey) obj; + if (fragment == null) { + if (other.fragment != null) + return false; + } else if (!fragment.equals(other.fragment)) + return false; + if (geometry == null) { + if (other.geometry != null) + return false; + } else if (!geometry.equals(other.geometry)) + return false; + if (parameters == null) { + if (other.parameters != null) + return false; + } else if (!parameters.equals(other.parameters)) + return false; + if (vertex == null) { + if (other.vertex != null) + return false; + } else if (!vertex.equals(other.vertex)) + return false; + return true; + } + } + + // TODO: Only do the NewLines patches if the source code isn't from + // gbuffers_lines (what does this mean?) + + static TokenFilter parseTokenFilter = new ChannelFilter(TokenChannel.PREPROCESSOR) { + @Override + public boolean isTokenAllowed(Token token) { + if (!super.isTokenAllowed(token)) { + throw new SemanticException("Unparsed preprocessor directives such as '" + token.getText() + + "' may not be present at this stage of shader processing!"); + } + return true; + } + }; + + static { + transformer = new EnumASTTransformer(PatchShaderType.class) { + @Override + public TranslationUnit parseTranslationUnit(String input) throws RecognitionException { + // parse #version directive using an efficient regex before parsing so that the + // parser can be set to the correct version + Matcher matcher = versionPattern.matcher(input); + if (!matcher.find()) { + throw new IllegalArgumentException("No #version directive found in source code! See debugging.md for more information."); + } + Version version = Version.fromNumber(Integer.parseInt(matcher.group(1))); + transformer.getLexer().version = version; + + return super.parseTranslationUnit(input); + } + }; + transformer.setTransformation((trees, parameters) -> { + for (PatchShaderType type : PatchShaderType.values()) { + TranslationUnit tree = trees.get(type); + if (tree == null) { + continue; + } + // @Asek3 I have old GLSL-Transformer on JRE8, so I will off this + //tree.outputOptions.enablePrintInfo(); + + parameters.type = type; + Root root = tree.getRoot(); + + // check for illegal references to internal Iris shader interfaces + Optional violation = root.identifierIndex.prefixQueryFlat("iris_").findAny(); + if (!violation.isPresent()) { + violation = root.identifierIndex.prefixQueryFlat("irisMain").findAny(); + } + violation.ifPresent(id -> { + throw new SemanticException( + "Detected a potential reference to unstable and internal Iris shader interfaces (iris_ and irisMain). This isn't currently supported. Violation: " + + id.getName() + ". See debugging.md for more information."); + }); + + Root.indexBuildSession(tree, () -> { + switch (parameters.patch) { + case ATTRIBUTES: + AttributeTransformer.transform(transformer, tree, root, (AttributeParameters) parameters); + break; + case SODIUM_TERRAIN: + SodiumTerrainTransformer.transform(transformer, tree, root, parameters); + break; + case COMPOSITE: + CompositeTransformer.transform(transformer, tree, root); + break; + } + CompatibilityTransformer.transformEach(transformer, tree, root, parameters); + }); + } + + // the compatibility transformer does a grouped transformation + CompatibilityTransformer.transformGrouped(transformer, trees, parameters); + }); + transformer.setParseTokenFilter(parseTokenFilter); + } + + private static final Pattern versionPattern = Pattern.compile("^.*#version\\s+(\\d+)", Pattern.DOTALL); + + private static Map transform(String vertex, String geometry, String fragment, Parameters parameters) { + // stop if all are null + if (vertex == null && geometry == null && fragment == null) { + return null; + } + + // check if this has been cached + CacheKey key; + Map result = null; + if (useCache) { + key = new CacheKey(parameters, vertex, geometry, fragment); + if (cache.containsKey(key)) { + result = cache.get(key); + } + } + + // if there is no cache result, transform the shaders + if (result == null) { + transformer.setPrintType(PatchedShaderPrinter.prettyPrintShaders ? PrintType.INDENTED : PrintType.SIMPLE); + EnumMap inputs = new EnumMap<>(PatchShaderType.class); + inputs.put(PatchShaderType.VERTEX, vertex); + inputs.put(PatchShaderType.GEOMETRY, geometry); + inputs.put(PatchShaderType.FRAGMENT, fragment); + result = transformer.transform(inputs, parameters); + if (useCache) { + cache.put(key, result); + } + } + + return result; + } + + public static Map patchAttributes(String vertex, String geometry, String fragment, InputAvailability inputs) { + return transform(vertex, geometry, fragment, new AttributeParameters(Patch.ATTRIBUTES, geometry != null, inputs)); + } + + public static Map patchSodiumTerrain(String vertex, String geometry, String fragment) { + return transform(vertex, geometry, fragment, new Parameters(Patch.SODIUM_TERRAIN)); + } + + public static Map patchComposite(String vertex, String geometry, String fragment) { + return transform(vertex, geometry, fragment, new Parameters(Patch.COMPOSITE)); + } +} diff --git a/src/main/java/net/coderbot/iris/postprocess/BufferFlipper.java b/src/main/java/net/coderbot/iris/postprocess/BufferFlipper.java new file mode 100644 index 000000000..a4b6f32ef --- /dev/null +++ b/src/main/java/net/coderbot/iris/postprocess/BufferFlipper.java @@ -0,0 +1,40 @@ +package net.coderbot.iris.postprocess; + +import com.google.common.collect.ImmutableSet; +import it.unimi.dsi.fastutil.ints.IntIterator; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; + +public class BufferFlipper { + private final IntSet flippedBuffers; + + public BufferFlipper() { + this.flippedBuffers = new IntOpenHashSet(); + } + + public void flip(int target) { + if (!flippedBuffers.remove(target)) { + // If the target wasn't in the set, add it to the set. + flippedBuffers.add(target); + } + } + + /** + * Returns true if this buffer is flipped. + * + * If this buffer is not flipped, then users should write to the alternate variant and read from the main variant. + * + * If this buffer is flipped, then users should write to the main variant and read from the alternate variant. + */ + public boolean isFlipped(int target) { + return flippedBuffers.contains(target); + } + + public IntIterator getFlippedBuffers() { + return flippedBuffers.iterator(); + } + + public ImmutableSet snapshot() { + return ImmutableSet.copyOf(flippedBuffers); + } +} diff --git a/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java b/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java new file mode 100644 index 000000000..e33126517 --- /dev/null +++ b/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java @@ -0,0 +1,123 @@ +package net.coderbot.iris.postprocess; + +import com.google.common.collect.ImmutableSet; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.framebuffer.GlFramebuffer; +import net.coderbot.iris.gl.program.Program; +import net.coderbot.iris.gl.program.ProgramBuilder; +import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.program.ProgramUniforms; +import net.coderbot.iris.gl.texture.DepthCopyStrategy; +import net.coderbot.iris.gl.texture.InternalTextureFormat; +import net.coderbot.iris.gl.texture.PixelType; +import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; +import net.coderbot.iris.uniforms.SystemTimeUniforms; +import net.minecraft.client.Minecraft; +import org.apache.commons.io.IOUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.function.IntSupplier; + +public class CenterDepthSampler { + private static final double LN2 = Math.log(2); + private boolean hasFirstSample; + private boolean everRetrieved; + private final Program program; + private final GlFramebuffer framebuffer; + private final int texture; + private final int altTexture; + private boolean destroyed; + + public CenterDepthSampler(IntSupplier depthSupplier, float halfLife) { + this.texture = GL11.glGenTextures(); + this.altTexture = GL11.glGenTextures(); + this.framebuffer = new GlFramebuffer(); + + // Fall back to a less precise format if the system doesn't support OpenGL 3 + InternalTextureFormat format = Iris.capabilities.OpenGL32 ? InternalTextureFormat.R32F : InternalTextureFormat.RGB16; + setupColorTexture(texture, format); + setupColorTexture(altTexture, format); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + + this.framebuffer.addColorAttachment(0, texture); + ProgramBuilder builder; + + try { + String fsh = new String(IOUtils.toByteArray(Objects.requireNonNull(getClass().getResourceAsStream("/centerDepth.fsh"))), StandardCharsets.UTF_8); + + if (Iris.capabilities.OpenGL32) { + fsh = fsh.replace("VERSIONPLACEHOLDER", "150 compatibility"); + } else { + fsh = fsh.replace("#define IS_GL3", ""); + fsh = fsh.replace("VERSIONPLACEHOLDER", "120"); + } + String vsh = new String(IOUtils.toByteArray(Objects.requireNonNull(getClass().getResourceAsStream("/centerDepth.vsh"))), StandardCharsets.UTF_8); + + builder = ProgramBuilder.begin("centerDepthSmooth", vsh, null, fsh, ImmutableSet.of(0, 1, 2)); + } catch (IOException e) { + throw new RuntimeException(e); + } + + builder.addDynamicSampler(depthSupplier, "depth"); + builder.addDynamicSampler(() -> altTexture, "altDepth"); + builder.uniform1f(UniformUpdateFrequency.PER_FRAME, "lastFrameTime", SystemTimeUniforms.TIMER::getLastFrameTime); + builder.uniform1f(UniformUpdateFrequency.ONCE, "decay", () -> (1.0f / ((halfLife * 0.1) / LN2))); + this.program = builder.build(); + } + + public void sampleCenterDepth() { + if ((hasFirstSample && (!everRetrieved)) || destroyed) { + // If the shaderpack isn't reading center depth values, don't bother sampling it + // This improves performance with most shaderpacks + return; + } + + hasFirstSample = true; + + this.framebuffer.bind(); + this.program.use(); + + GL11.glViewport(0, 0, 1, 1); + + FullScreenQuadRenderer.INSTANCE.render(); + + ProgramUniforms.clearActiveUniforms(); + ProgramSamplers.clearActiveSamplers(); + + // The API contract of DepthCopyStrategy claims it can only copy depth, however the 2 non-stencil methods used are entirely capable of copying color as of now. + DepthCopyStrategy.fastest(false).copy(this.framebuffer, texture, null, altTexture, 1, 1); + + //Reset viewport + Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); + } + + public void setupColorTexture(int texture, InternalTextureFormat format) { + IrisRenderSystem.texImage2D(texture, GL11.GL_TEXTURE_2D, 0, format.getGlFormat(), 1, 1, 0, format.getPixelFormat().getGlFormat(), PixelType.FLOAT.getGlFormat(), null); + + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); + } + + public int getCenterDepthTexture() { + return altTexture; + } + + public void setUsage(boolean usage) { + everRetrieved |= usage; + } + + public void destroy() { + GL11.glDeleteTextures(texture); + GL11.glDeleteTextures(altTexture); + framebuffer.destroy(); + program.destroy(); + destroyed = true; + } +} diff --git a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java new file mode 100644 index 000000000..b40e85347 --- /dev/null +++ b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java @@ -0,0 +1,388 @@ +package net.coderbot.iris.postprocess; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.framebuffer.GlFramebuffer; +import net.coderbot.iris.gl.program.ComputeProgram; +import net.coderbot.iris.gl.program.Program; +import net.coderbot.iris.gl.program.ProgramBuilder; +import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.program.ProgramUniforms; +import net.coderbot.iris.gl.sampler.SamplerLimits; +import net.coderbot.iris.pipeline.PatchedShaderPrinter; +import net.coderbot.iris.pipeline.transform.PatchShaderType; +import net.coderbot.iris.pipeline.transform.TransformPatcher; +import net.coderbot.iris.rendertarget.RenderTarget; +import net.coderbot.iris.rendertarget.RenderTargets; +import net.coderbot.iris.samplers.IrisImages; +import net.coderbot.iris.samplers.IrisSamplers; +import net.coderbot.iris.shaderpack.ComputeSource; +import net.coderbot.iris.shaderpack.PackDirectives; +import net.coderbot.iris.shaderpack.PackRenderTargetDirectives; +import net.coderbot.iris.shaderpack.ProgramDirectives; +import net.coderbot.iris.shaderpack.ProgramSource; +import net.coderbot.iris.shadows.ShadowRenderTargets; +import net.coderbot.iris.uniforms.CommonUniforms; +import net.coderbot.iris.uniforms.FrameUpdateNotifier; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.OpenGlHelper; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL30; + +import java.util.Map; +import java.util.Objects; +import java.util.function.IntSupplier; +import java.util.function.Supplier; + +public class CompositeRenderer { + private final RenderTargets renderTargets; + + private final ImmutableList passes; + private final IntSupplier noiseTexture; + private final FrameUpdateNotifier updateNotifier; + private final CenterDepthSampler centerDepthSampler; + private final Object2ObjectMap customTextureIds; + private final ImmutableSet flippedAtLeastOnceFinal; + + public CompositeRenderer(PackDirectives packDirectives, ProgramSource[] sources, ComputeSource[][] computes, RenderTargets renderTargets, + IntSupplier noiseTexture, FrameUpdateNotifier updateNotifier, + CenterDepthSampler centerDepthSampler, BufferFlipper bufferFlipper, + Supplier shadowTargetsSupplier, + Object2ObjectMap customTextureIds, ImmutableMap explicitPreFlips) { + this.noiseTexture = noiseTexture; + this.updateNotifier = updateNotifier; + this.centerDepthSampler = centerDepthSampler; + this.renderTargets = renderTargets; + this.customTextureIds = customTextureIds; + + final PackRenderTargetDirectives renderTargetDirectives = packDirectives.getRenderTargetDirectives(); + final Map renderTargetSettings = + renderTargetDirectives.getRenderTargetSettings(); + + final ImmutableList.Builder passes = ImmutableList.builder(); + final ImmutableSet.Builder flippedAtLeastOnce = new ImmutableSet.Builder<>(); + + explicitPreFlips.forEach((buffer, shouldFlip) -> { + if (shouldFlip) { + bufferFlipper.flip(buffer); + // NB: Flipping deferred_pre or composite_pre does NOT cause the "flippedAtLeastOnce" flag to trigger + } + }); + + for (int i = 0; i < sources.length; i++) { + ProgramSource source = sources[i]; + + ImmutableSet flipped = bufferFlipper.snapshot(); + ImmutableSet flippedAtLeastOnceSnapshot = flippedAtLeastOnce.build(); + + if (source == null || !source.isValid()) { + if (computes[i] != null) { + ComputeOnlyPass pass = new ComputeOnlyPass(); + pass.computes = createComputes(computes[i], flipped, flippedAtLeastOnceSnapshot, shadowTargetsSupplier); + passes.add(pass); + } + continue; + } + + Pass pass = new Pass(); + ProgramDirectives directives = source.getDirectives(); + + pass.program = createProgram(source, flipped, flippedAtLeastOnceSnapshot, shadowTargetsSupplier); + pass.computes = createComputes(computes[i], flipped, flippedAtLeastOnceSnapshot, shadowTargetsSupplier); + int[] drawBuffers = directives.getDrawBuffers(); + + GlFramebuffer framebuffer = renderTargets.createColorFramebuffer(flipped, drawBuffers); + + int passWidth = 0, passHeight = 0; + // Flip the buffers that this shader wrote to, and set pass width and height + ImmutableMap explicitFlips = directives.getExplicitFlips(); + + for (int buffer : drawBuffers) { + RenderTarget target = renderTargets.get(buffer); + if ((passWidth > 0 && passWidth != target.getWidth()) || (passHeight > 0 && passHeight != target.getHeight())) { + throw new IllegalStateException("Pass widths must match"); + } + passWidth = target.getWidth(); + passHeight = target.getHeight(); + + // compare with boxed Boolean objects to avoid NPEs + if (explicitFlips.get(buffer) == Boolean.FALSE) { + continue; + } + + bufferFlipper.flip(buffer); + flippedAtLeastOnce.add(buffer); + } + + explicitFlips.forEach((buffer, shouldFlip) -> { + if (shouldFlip) { + bufferFlipper.flip(buffer); + flippedAtLeastOnce.add(buffer); + } + }); + + pass.drawBuffers = directives.getDrawBuffers(); + pass.viewWidth = passWidth; + pass.viewHeight = passHeight; + pass.stageReadsFromAlt = flipped; + pass.framebuffer = framebuffer; + pass.viewportScale = directives.getViewportScale(); + pass.mipmappedBuffers = directives.getMipmappedBuffers(); + pass.flippedAtLeastOnce = flippedAtLeastOnceSnapshot; + + passes.add(pass); + } + + this.passes = passes.build(); + this.flippedAtLeastOnceFinal = flippedAtLeastOnce.build(); + + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_READ_FRAMEBUFFER, 0); + } + + public ImmutableSet getFlippedAtLeastOnceFinal() { + return this.flippedAtLeastOnceFinal; + } + + + public void recalculateSizes() { + for (Pass pass : passes) { + if (pass instanceof ComputeOnlyPass) { + continue; + } + int passWidth = 0, passHeight = 0; + for (int buffer : pass.drawBuffers) { + RenderTarget target = renderTargets.get(buffer); + if ((passWidth > 0 && passWidth != target.getWidth()) || (passHeight > 0 && passHeight != target.getHeight())) { + throw new IllegalStateException("Pass widths must match"); + } + passWidth = target.getWidth(); + passHeight = target.getHeight(); + } + renderTargets.destroyFramebuffer(pass.framebuffer); + pass.framebuffer = renderTargets.createColorFramebuffer(pass.stageReadsFromAlt, pass.drawBuffers); + pass.viewWidth = passWidth; + pass.viewHeight = passHeight; + } + } + + private static class Pass { + int[] drawBuffers; + int viewWidth; + int viewHeight; + Program program; + ComputeProgram[] computes; + GlFramebuffer framebuffer; + ImmutableSet flippedAtLeastOnce; + ImmutableSet stageReadsFromAlt; + ImmutableSet mipmappedBuffers; + float viewportScale; + + protected void destroy() { + this.program.destroy(); + for (ComputeProgram compute : this.computes) { + if (compute != null) { + compute.destroy(); + } + } + } + } + + private class ComputeOnlyPass extends Pass { + @Override + protected void destroy() { + for (ComputeProgram compute : this.computes) { + if (compute != null) { + compute.destroy(); + } + } + } + } + + public void renderAll() { + GL11.glDisable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_ALPHA_TEST); + + FullScreenQuadRenderer.INSTANCE.begin(); + + for (Pass renderPass : passes) { + boolean ranCompute = false; + for (ComputeProgram computeProgram : renderPass.computes) { + if (computeProgram != null) { + ranCompute = true; + com.mojang.blaze3d.pipeline.RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); + computeProgram.dispatch(main.width, main.height); + } + } + + if (ranCompute) { + IrisRenderSystem.memoryBarrier(40); + } + + Program.unbind(); + + if (renderPass instanceof ComputeOnlyPass) { + continue; + } + + if (!renderPass.mipmappedBuffers.isEmpty()) { + GL13.glActiveTexture(GL13.GL_TEXTURE0); + + for (int index : renderPass.mipmappedBuffers) { + setupMipmapping(CompositeRenderer.this.renderTargets.get(index), renderPass.stageReadsFromAlt.contains(index)); + } + } + + float scaledWidth = renderPass.viewWidth * renderPass.viewportScale; + float scaledHeight = renderPass.viewHeight * renderPass.viewportScale; + GL11.glViewport(0, 0, (int) scaledWidth, (int) scaledHeight); + + renderPass.framebuffer.bind(); + renderPass.program.use(); + + FullScreenQuadRenderer.INSTANCE.renderQuad(); + } + + FullScreenQuadRenderer.end(); + + // Make sure to reset the viewport to how it was before... Otherwise weird issues could occur. + // Also bind the "main" framebuffer if it isn't already bound. + Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); + ProgramUniforms.clearActiveUniforms(); + ProgramSamplers.clearActiveSamplers(); + GL20.glUseProgram(0); + + // NB: Unbinding all of these textures is necessary for proper shaderpack reloading. + for (int i = 0; i < SamplerLimits.get().getMaxTextureUnits(); i++) { + // Unbind all textures that we may have used. + // NB: This is necessary for shader pack reloading to work propely + GL13.glActiveTexture(GL13.GL_TEXTURE0 + i); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + } + + GL13.glActiveTexture(GL13.GL_TEXTURE0); + } + + private static void setupMipmapping(RenderTarget target, boolean readFromAlt) { + int texture = readFromAlt ? target.getAltTexture() : target.getMainTexture(); + + // TODO: Only generate the mipmap if a valid mipmap hasn't been generated or if we've written to the buffer + // (since the last mipmap was generated) + // + // NB: We leave mipmapping enabled even if the buffer is written to again, this appears to match the + // behavior of ShadersMod/OptiFine, however I'm not sure if it's desired behavior. It's possible that a + // program could use mipmapped sampling with a stale mipmap, which probably isn't great. However, the + // sampling mode is always reset between frames, so this only persists after the first program to use + // mipmapping on this buffer. + // + // Also note that this only applies to one of the two buffers in a render target buffer pair - making it + // unlikely that this issue occurs in practice with most shader packs. + IrisRenderSystem.generateMipmaps(texture, GL11.GL_TEXTURE_2D); + + int filter = GL11.GL_LINEAR_MIPMAP_LINEAR; + if (target.getInternalFormat().getPixelFormat().isInteger()) { + filter = GL11.GL_NEAREST_MIPMAP_NEAREST; + } + + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); + } + + // TODO: Don't just copy this from DeferredWorldRenderingPipeline + private Program createProgram(ProgramSource source, ImmutableSet flipped, ImmutableSet flippedAtLeastOnceSnapshot, + Supplier shadowTargetsSupplier) { + // TODO: Properly handle empty shaders + Map transformed = TransformPatcher.patchComposite( + source.getVertexSource().orElseThrow(NullPointerException::new), + source.getGeometrySource().orElse(null), + source.getFragmentSource().orElseThrow(NullPointerException::new)); + String vertex = transformed.get(PatchShaderType.VERTEX); + String geometry = transformed.get(PatchShaderType.GEOMETRY); + String fragment = transformed.get(PatchShaderType.FRAGMENT); + PatchedShaderPrinter.debugPatchedShaders(source.getName(), vertex, geometry, fragment); + + Objects.requireNonNull(flipped); + ProgramBuilder builder; + + try { + builder = ProgramBuilder.begin(source.getName(), vertex, geometry, fragment, + IrisSamplers.COMPOSITE_RESERVED_TEXTURE_UNITS); + } catch (RuntimeException e) { + // TODO: Better error handling + throw new RuntimeException("Shader compilation failed!", e); + } + + ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureIds, flippedAtLeastOnceSnapshot); + + CommonUniforms.addCommonUniforms(builder, source.getParent().getPack().getIdMap(), source.getParent().getPackDirectives(), updateNotifier); + IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true); + IrisImages.addRenderTargetImages(builder, () -> flipped, renderTargets); + + IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, noiseTexture); + IrisSamplers.addCompositeSamplers(customTextureSamplerInterceptor, renderTargets); + + if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { + IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get()); + IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get()); + } + + // TODO: Don't duplicate this with FinalPassRenderer + centerDepthSampler.setUsage(builder.addDynamicSampler(centerDepthSampler::getCenterDepthTexture, "iris_centerDepthSmooth")); + + return builder.build(); + } + + private ComputeProgram[] createComputes(ComputeSource[] compute, ImmutableSet flipped, ImmutableSet flippedAtLeastOnceSnapshot, Supplier shadowTargetsSupplier) { + ComputeProgram[] programs = new ComputeProgram[compute.length]; + for (int i = 0; i < programs.length; i++) { + ComputeSource source = compute[i]; + if (source == null || !source.getSource().isPresent()) { + continue; + } else { + // TODO: Properly handle empty shaders + Objects.requireNonNull(flipped); + ProgramBuilder builder; + + try { + builder = ProgramBuilder.beginCompute(source.getName(), source.getSource().orElse(null), IrisSamplers.COMPOSITE_RESERVED_TEXTURE_UNITS); + } catch (RuntimeException e) { + // TODO: Better error handling + throw new RuntimeException("Shader compilation failed!", e); + } + + ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureIds, flippedAtLeastOnceSnapshot); + + CommonUniforms.addCommonUniforms(builder, source.getParent().getPack().getIdMap(), source.getParent().getPackDirectives(), updateNotifier); + IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true); + IrisImages.addRenderTargetImages(builder, () -> flipped, renderTargets); + + IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, noiseTexture); + IrisSamplers.addCompositeSamplers(customTextureSamplerInterceptor, renderTargets); + + if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { + IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get()); + IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get()); + } + + // TODO: Don't duplicate this with FinalPassRenderer + centerDepthSampler.setUsage(builder.addDynamicSampler(centerDepthSampler::getCenterDepthTexture, "iris_centerDepthSmooth")); + + programs[i] = builder.buildCompute(); + + programs[i].setWorkGroupInfo(source.getWorkGroupRelative(), source.getWorkGroups()); + } + } + + + return programs; + } + + public void destroy() { + for (Pass renderPass : passes) { + renderPass.destroy(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java new file mode 100644 index 000000000..a8701f3a2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java @@ -0,0 +1,402 @@ +package net.coderbot.iris.postprocess; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.framebuffer.GlFramebuffer; +import net.coderbot.iris.gl.program.ComputeProgram; +import net.coderbot.iris.gl.program.Program; +import net.coderbot.iris.gl.program.ProgramBuilder; +import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.program.ProgramUniforms; +import net.coderbot.iris.gl.sampler.SamplerLimits; +import net.coderbot.iris.pipeline.PatchedShaderPrinter; +import net.coderbot.iris.pipeline.transform.PatchShaderType; +import net.coderbot.iris.pipeline.transform.TransformPatcher; +import net.coderbot.iris.rendertarget.Blaze3dRenderTargetExt; +import net.coderbot.iris.rendertarget.RenderTarget; +import net.coderbot.iris.rendertarget.RenderTargets; +import net.coderbot.iris.samplers.IrisImages; +import net.coderbot.iris.samplers.IrisSamplers; +import net.coderbot.iris.shaderpack.ComputeSource; +import net.coderbot.iris.shaderpack.PackRenderTargetDirectives; +import net.coderbot.iris.shaderpack.ProgramDirectives; +import net.coderbot.iris.shaderpack.ProgramSet; +import net.coderbot.iris.shaderpack.ProgramSource; +import net.coderbot.iris.shadows.ShadowRenderTargets; +import net.coderbot.iris.uniforms.CommonUniforms; +import net.coderbot.iris.uniforms.FrameUpdateNotifier; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.OpenGlHelper; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL30; + +import java.util.Map; +import java.util.Objects; +import java.util.function.IntSupplier; +import java.util.function.Supplier; + +public class FinalPassRenderer { + private final RenderTargets renderTargets; + + @Nullable + private final Pass finalPass; + private final ImmutableList swapPasses; + private final GlFramebuffer baseline; + private final GlFramebuffer colorHolder; + private int lastColorTextureId; + private int lastColorTextureVersion; + private final IntSupplier noiseTexture; + private final FrameUpdateNotifier updateNotifier; + private final CenterDepthSampler centerDepthSampler; + private final Object2ObjectMap customTextureIds; + + // TODO: The length of this argument list is getting a bit ridiculous + public FinalPassRenderer(ProgramSet pack, RenderTargets renderTargets, IntSupplier noiseTexture, + FrameUpdateNotifier updateNotifier, ImmutableSet flippedBuffers, + CenterDepthSampler centerDepthSampler, + Supplier shadowTargetsSupplier, + Object2ObjectMap customTextureIds, + ImmutableSet flippedAtLeastOnce) { + this.updateNotifier = updateNotifier; + this.centerDepthSampler = centerDepthSampler; + this.customTextureIds = customTextureIds; + + final PackRenderTargetDirectives renderTargetDirectives = pack.getPackDirectives().getRenderTargetDirectives(); + final Map renderTargetSettings = + renderTargetDirectives.getRenderTargetSettings(); + + this.noiseTexture = noiseTexture; + this.renderTargets = renderTargets; + this.finalPass = pack.getCompositeFinal().map(source -> { + Pass pass = new Pass(); + ProgramDirectives directives = source.getDirectives(); + + pass.program = createProgram(source, flippedBuffers, flippedAtLeastOnce, shadowTargetsSupplier); + pass.computes = createComputes(pack.getFinalCompute(), flippedBuffers, flippedAtLeastOnce, shadowTargetsSupplier); + pass.stageReadsFromAlt = flippedBuffers; + pass.mipmappedBuffers = directives.getMipmappedBuffers(); + + return pass; + }).orElse(null); + + IntList buffersToBeCleared = pack.getPackDirectives().getRenderTargetDirectives().getBuffersToBeCleared(); + + // The name of this method might seem a bit odd here, but we want a framebuffer with color attachments that line + // up with whatever was written last (since we're reading from these framebuffers) instead of trying to create + // a framebuffer with color attachments different from what was written last (as we do with normal composite + // passes that write to framebuffers). + this.baseline = renderTargets.createGbufferFramebuffer(flippedBuffers, new int[] {0}); + this.colorHolder = new GlFramebuffer(); + this.lastColorTextureId = Minecraft.getMinecraft().getMainRenderTarget().getColorTextureId(); + this.lastColorTextureVersion = ((Blaze3dRenderTargetExt) Minecraft.getMinecraft().getMainRenderTarget()).iris$getColorBufferVersion(); + this.colorHolder.addColorAttachment(0, lastColorTextureId); + + // TODO: We don't actually fully swap the content, we merely copy it from alt to main + // This works for the most part, but it's not perfect. A better approach would be creating secondary + // framebuffers for every other frame, but that would be a lot more complex... + ImmutableList.Builder swapPasses = ImmutableList.builder(); + + flippedBuffers.forEach((i) -> { + int target = i; + + if (buffersToBeCleared.contains(target)) { + return; + } + + SwapPass swap = new SwapPass(); + RenderTarget target1 = renderTargets.get(target); + swap.target = target; + swap.width = target1.getWidth(); + swap.height = target1.getHeight(); + swap.from = renderTargets.createColorFramebuffer(ImmutableSet.of(), new int[] {target}); + // NB: This is handled in RenderTargets now. + //swap.from.readBuffer(target); + swap.targetTexture = renderTargets.get(target).getMainTexture(); + + swapPasses.add(swap); + }); + + this.swapPasses = swapPasses.build(); + + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_READ_FRAMEBUFFER, 0); + } + + private static final class Pass { + Program program; + ComputeProgram[] computes; + ImmutableSet stageReadsFromAlt; + ImmutableSet mipmappedBuffers; + + private void destroy() { + this.program.destroy(); + } + } + + private static final class SwapPass { + public int target; + public int width; + public int height; + GlFramebuffer from; + int targetTexture; + } + + public void renderFinalPass() { + GL11.glDisable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_ALPHA_TEST); + GL11.glDepthMask(false); + + final com.mojang.blaze3d.pipeline.RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); + final int baseWidth = main.width; + final int baseHeight = main.height; + + // Note that since DeferredWorldRenderingPipeline uses the depth texture of the main Minecraft framebuffer, + // we'll be writing to that depth buffer directly automatically and won't need to futz around with copying + // depth buffer content. + // + // Previously, we had our own depth texture and then copied its content to the main Minecraft framebuffer. + // This worked with vanilla, but broke with mods that used the stencil buffer. + // + // This approach is a fairly succinct solution to the issue of having to deal with the main Minecraft + // framebuffer potentially having a depth-stencil buffer or similar - we'll automatically enable that to + // work properly since we re-use the depth buffer instead of trying to make our own. + // + // This is not a concern for depthtex1 / depthtex2 since the copy call extracts the depth values, and the + // shader pack only ever uses them to read the depth values. + if (((Blaze3dRenderTargetExt) main).iris$getColorBufferVersion() != lastColorTextureVersion || main.getColorTextureId() != lastColorTextureId) { + lastColorTextureVersion = ((Blaze3dRenderTargetExt) main).iris$getColorBufferVersion(); + this.lastColorTextureId = main.getColorTextureId(); + colorHolder.addColorAttachment(0, lastColorTextureId); + } + + if (this.finalPass != null) { + // If there is a final pass, we use the shader-based full screen quad rendering pathway instead + // of just copying the color buffer. + + colorHolder.bind(); + + FullScreenQuadRenderer.INSTANCE.begin(); + + for (ComputeProgram computeProgram : finalPass.computes) { + if (computeProgram != null) { + computeProgram.dispatch(baseWidth, baseHeight); + } + } + + IrisRenderSystem.memoryBarrier(40); + + if (!finalPass.mipmappedBuffers.isEmpty()) { + GL13.glActiveTexture(GL13.GL_TEXTURE0); + + for (int index : finalPass.mipmappedBuffers) { + setupMipmapping(renderTargets.get(index), finalPass.stageReadsFromAlt.contains(index)); + } + } + + finalPass.program.use(); + FullScreenQuadRenderer.INSTANCE.renderQuad(); + + FullScreenQuadRenderer.end(); + } else { + // If there are no passes, we somehow need to transfer the content of the Iris color render targets into + // the main Minecraft framebuffer. + // + // Thus, the following call transfers the content of colortex0 into the main Minecraft framebuffer. + // + // Note that glCopyTexSubImage2D is not as strict as glBlitFramebuffer, so we don't have to worry about + // colortex0 having a weird format. This should just work. + // + // We could have used a shader here, but it should be about the same performance either way: + // https://stackoverflow.com/a/23994979/18166885 + this.baseline.bindAsReadBuffer(); + + IrisRenderSystem.copyTexSubImage2D(main.getColorTextureId(), GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, baseWidth, baseHeight); + } + + GL13.glActiveTexture(GL13.GL_TEXTURE0); + + for (int i = 0; i < renderTargets.getRenderTargetCount(); i++) { + // Reset mipmapping states at the end of the frame. + resetRenderTarget(renderTargets.get(i)); + } + + for (SwapPass swapPass : swapPasses) { + // NB: We need to use bind(), not bindAsReadBuffer()... Previously we used bindAsReadBuffer() here which + // broke TAA on many packs and on many drivers. + // + // Note that glCopyTexSubImage2D reads from the current GL_READ_BUFFER (given by glReadBuffer()) for the + // current framebuffer bound to GL_FRAMEBUFFER, but that is distinct from the current GL_READ_FRAMEBUFFER, + // which is what bindAsReadBuffer() binds. + // + // Also note that RenderTargets already calls readBuffer(0) for us. + swapPass.from.bind(); + + GL11.glBindTexture(GL11.GL_TEXTURE_2D, swapPass.targetTexture); + GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, swapPass.width, swapPass.height); + } + + // Make sure to reset the viewport to how it was before... Otherwise weird issues could occur. + // Also bind the "main" framebuffer if it isn't already bound. + main.bindWrite(true); + ProgramUniforms.clearActiveUniforms(); + ProgramSamplers.clearActiveSamplers(); + GL20.glUseProgram(0); + + for (int i = 0; i < SamplerLimits.get().getMaxTextureUnits(); i++) { + // Unbind all textures that we may have used. + // NB: This is necessary for shader pack reloading to work properly + GL13.glActiveTexture(GL13.GL_TEXTURE0 + i); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + } + + GL13.glActiveTexture(GL13.GL_TEXTURE0); + } + + public void recalculateSwapPassSize() { + for (SwapPass swapPass : swapPasses) { + RenderTarget target = renderTargets.get(swapPass.target); + renderTargets.destroyFramebuffer(swapPass.from); + swapPass.from = renderTargets.createColorFramebuffer(ImmutableSet.of(), new int[] {swapPass.target}); + swapPass.width = target.getWidth(); + swapPass.height = target.getHeight(); + swapPass.targetTexture = target.getMainTexture(); + } + } + + private static void setupMipmapping(RenderTarget target, boolean readFromAlt) { + int texture = readFromAlt ? target.getAltTexture() : target.getMainTexture(); + + // TODO: Only generate the mipmap if a valid mipmap hasn't been generated or if we've written to the buffer + // (since the last mipmap was generated) + // + // NB: We leave mipmapping enabled even if the buffer is written to again, this appears to match the + // behavior of ShadersMod/OptiFine, however I'm not sure if it's desired behavior. It's possible that a + // program could use mipmapped sampling with a stale mipmap, which probably isn't great. However, the + // sampling mode is always reset between frames, so this only persists after the first program to use + // mipmapping on this buffer. + // + // Also note that this only applies to one of the two buffers in a render target buffer pair - making it + // unlikely that this issue occurs in practice with most shader packs. + IrisRenderSystem.generateMipmaps(texture, GL11.GL_TEXTURE_2D); + + int filter = GL11.GL_LINEAR_MIPMAP_LINEAR; + if (target.getInternalFormat().getPixelFormat().isInteger()) { + filter = GL11.GL_NEAREST_MIPMAP_NEAREST; + } + + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); + } + + private static void resetRenderTarget(RenderTarget target) { + // Resets the sampling mode of the given render target and then unbinds it to prevent accidental sampling of it + // elsewhere. + int filter = GL11.GL_LINEAR; + if (target.getInternalFormat().getPixelFormat().isInteger()) { + filter = GL11.GL_NEAREST; + } + + IrisRenderSystem.texParameteri(target.getMainTexture(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); + IrisRenderSystem.texParameteri(target.getAltTexture(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); + + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + } + + // TODO: Don't just copy this from DeferredWorldRenderingPipeline + private Program createProgram(ProgramSource source, ImmutableSet flipped, ImmutableSet flippedAtLeastOnceSnapshot, + Supplier shadowTargetsSupplier) { + // TODO: Properly handle empty shaders + Map transformed = TransformPatcher.patchComposite( + source.getVertexSource().orElseThrow(NullPointerException::new), + source.getGeometrySource().orElse(null), + source.getFragmentSource().orElseThrow(NullPointerException::new)); + String vertex = transformed.get(PatchShaderType.VERTEX); + String geometry = transformed.get(PatchShaderType.GEOMETRY); + String fragment = transformed.get(PatchShaderType.FRAGMENT); + PatchedShaderPrinter.debugPatchedShaders(source.getName(), vertex, geometry, fragment); + + Objects.requireNonNull(flipped); + ProgramBuilder builder; + + try { + builder = ProgramBuilder.begin(source.getName(), vertex, geometry, fragment, + IrisSamplers.COMPOSITE_RESERVED_TEXTURE_UNITS); + } catch (RuntimeException e) { + // TODO: Better error handling + throw new RuntimeException("Shader compilation failed!", e); + } + + ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureIds, flippedAtLeastOnceSnapshot); + + CommonUniforms.addCommonUniforms(builder, source.getParent().getPack().getIdMap(), source.getParent().getPackDirectives(), updateNotifier); + IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true); + IrisImages.addRenderTargetImages(builder, () -> flipped, renderTargets); + IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, noiseTexture); + IrisSamplers.addCompositeSamplers(customTextureSamplerInterceptor, renderTargets); + + if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { + IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get()); + IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get()); + } + + // TODO: Don't duplicate this with CompositeRenderer + centerDepthSampler.setUsage(builder.addDynamicSampler(centerDepthSampler::getCenterDepthTexture, "iris_centerDepthSmooth")); + + return builder.build(); + } + + private ComputeProgram[] createComputes(ComputeSource[] compute, ImmutableSet flipped, ImmutableSet flippedAtLeastOnceSnapshot, Supplier shadowTargetsSupplier) { + ComputeProgram[] programs = new ComputeProgram[compute.length]; + for (int i = 0; i < programs.length; i++) { + ComputeSource source = compute[i]; + if (source == null || !source.getSource().isPresent()) { + continue; + } else { + // TODO: Properly handle empty shaders + Objects.requireNonNull(flipped); + ProgramBuilder builder; + + try { + builder = ProgramBuilder.beginCompute(source.getName(), source.getSource().orElse(null), IrisSamplers.COMPOSITE_RESERVED_TEXTURE_UNITS); + } catch (RuntimeException e) { + // TODO: Better error handling + throw new RuntimeException("Shader compilation failed!", e); + } + + ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureIds, flippedAtLeastOnceSnapshot); + + CommonUniforms.addCommonUniforms(builder, source.getParent().getPack().getIdMap(), source.getParent().getPackDirectives(), updateNotifier); + IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true); + IrisImages.addRenderTargetImages(builder, () -> flipped, renderTargets); + + IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, noiseTexture); + IrisSamplers.addCompositeSamplers(customTextureSamplerInterceptor, renderTargets); + + if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { + IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get()); + IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get()); + } + + // TODO: Don't duplicate this with FinalPassRenderer + centerDepthSampler.setUsage(builder.addDynamicSampler(centerDepthSampler::getCenterDepthTexture, "iris_centerDepthSmooth")); + + programs[i] = builder.buildCompute(); + + programs[i].setWorkGroupInfo(source.getWorkGroupRelative(), source.getWorkGroups()); + } + } + + + return programs; + } + + public void destroy() { + if (finalPass != null) { + finalPass.destroy(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java new file mode 100644 index 000000000..2acbbc9b3 --- /dev/null +++ b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java @@ -0,0 +1,86 @@ +package net.coderbot.iris.postprocess; + +import net.coderbot.iris.gl.IrisRenderSystem; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL15; + +/** + * Renders a full-screen textured quad to the screen. Used in composite / deferred rendering. + */ +public class FullScreenQuadRenderer { + private final int quadBuffer; + + public static final FullScreenQuadRenderer INSTANCE = new FullScreenQuadRenderer(); + + private FullScreenQuadRenderer() { + this.quadBuffer = createQuad(); + } + + public void render() { + begin(); + + renderQuad(); + + end(); + } + + @SuppressWarnings("deprecation") + public void begin() { + GL11.glDisable(GL11.GL_DEPTH_TEST); + + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glPushMatrix(); + GL11.glLoadIdentity(); + // scale the quad from [0, 1] to [-1, 1] + GL11.glTranslatef(-1.0F, -1.0F, 0.0F); + GL11.glScalef(2.0F, 2.0F, 0.0F); + + GL11.glMatrixMode(GL11.GL_MODELVIEW); + GL11.glPushMatrix(); + GL11.glLoadIdentity(); + + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, quadBuffer); + DefaultVertexFormat.POSITION_TEX.setupBufferState(0L); + } + + public void renderQuad() { + GL11.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, 4); + } + + @SuppressWarnings("deprecation") + public static void end() { + DefaultVertexFormat.POSITION_TEX.clearBufferState(); + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); + + GL11.glEnable(GL11.GL_DEPTH_TEST); + + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glPopMatrix(); + GL11.glMatrixMode(GL11.GL_MODELVIEW); + GL11.glPopMatrix(); + } + + /** + * Creates and uploads a vertex buffer containing a single full-screen quad + */ + private static int createQuad() { + float[] vertices = new float[] { + // Vertex 0: Top right corner + 1.0F, 1.0F, 0.0F, + 1.0F, 1.0F, + // Vertex 1: Top left corner + 0.0F, 1.0F, 0.0F, + 0.0F, 1.0F, + // Vertex 2: Bottom right corner + 1.0F, 0.0F, 0.0F, + 1.0F, 0.0F, + // Vertex 3: Bottom left corner + 0.0F, 0.0F, 0.0F, + 0.0F, 0.0F + }; + + return IrisRenderSystem.bufferStorage(GL15.GL_ARRAY_BUFFER, vertices, GL15.GL_STATIC_DRAW); + } +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/Blaze3dRenderTargetExt.java b/src/main/java/net/coderbot/iris/rendertarget/Blaze3dRenderTargetExt.java new file mode 100644 index 000000000..207ece1d0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/rendertarget/Blaze3dRenderTargetExt.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.rendertarget; + +public interface Blaze3dRenderTargetExt { + int iris$getDepthBufferVersion(); + + int iris$getColorBufferVersion(); +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java b/src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java new file mode 100644 index 000000000..f4aa02873 --- /dev/null +++ b/src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java @@ -0,0 +1,37 @@ +package net.coderbot.iris.rendertarget; + +import net.coderbot.iris.gl.GlResource; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.texture.DepthBufferFormat; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +public class DepthTexture extends GlResource { + public DepthTexture(int width, int height, DepthBufferFormat format) { + super(IrisRenderSystem.createTexture(GL11.GL_TEXTURE_2D)); + int texture = getGlId(); + + resize(width, height, format); + + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); + + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + } + + void resize(int width, int height, DepthBufferFormat format) { + IrisRenderSystem.texImage2D(getTextureId(), GL11.GL_TEXTURE_2D, 0, format.getGlInternalFormat(), width, height, 0, + format.getGlType(), format.getGlFormat(), null); + } + + public int getTextureId() { + return getGlId(); + } + + @Override + protected void destroyInternal() { + GL11.glDeleteTextures(getGlId()); + } +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java new file mode 100644 index 000000000..8d694222f --- /dev/null +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java @@ -0,0 +1,45 @@ +package net.coderbot.iris.rendertarget; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.shaderpack.texture.CustomTextureData; +import net.minecraft.client.renderer.texture.DynamicTexture; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Objects; + +public class NativeImageBackedCustomTexture extends DynamicTexture { + public NativeImageBackedCustomTexture(CustomTextureData.PngData textureData) throws IOException { + super(create(textureData.getContent())); + + // By default, images are unblurred and not clamped. + + if (textureData.getFilteringData().shouldBlur()) { + IrisRenderSystem.texParameteri(getGlTextureId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + IrisRenderSystem.texParameteri(getGlTextureId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + } + + if (textureData.getFilteringData().shouldClamp()) { + IrisRenderSystem.texParameteri(getGlTextureId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); + IrisRenderSystem.texParameteri(getGlTextureId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); + } + } + + private static NativeImage create(byte[] content) throws IOException { + ByteBuffer buffer = ByteBuffer.allocateDirect(content.length); + buffer.put(content); + buffer.flip(); + + return NativeImage.read(buffer); + } + + @Override + public void upload() { + NativeImage image = Objects.requireNonNull(getPixels()); + + bind(); + image.upload(0, 0, 0, 0, 0, image.getWidth(), image.getHeight(), false, false, false, false); + } +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java new file mode 100644 index 000000000..da6ecb0e0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java @@ -0,0 +1,35 @@ +package net.coderbot.iris.rendertarget; + +import net.minecraft.client.renderer.texture.DynamicTexture; + +import java.util.Objects; +import java.util.Random; + +public class NativeImageBackedNoiseTexture extends DynamicTexture { + public NativeImageBackedNoiseTexture(int size) { + super(create(size)); + } + + private static NativeImage create(int size) { + NativeImage image = new NativeImage(NativeImage.Format.RGBA, size, size, false); + Random random = new Random(0); + + for (int x = 0; x < size; x++) { + for (int y = 0; y < size; y++) { + int color = random.nextInt() | (255 << 24); + + image.setPixelRGBA(x, y, color); + } + } + + return image; + } + + @Override + public void upload() { + NativeImage image = Objects.requireNonNull(getPixels()); + + bind(); + image.upload(0, 0, 0, 0, 0, image.getWidth(), image.getHeight(), true, false, false, false); + } +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java new file mode 100644 index 000000000..71eb2720c --- /dev/null +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java @@ -0,0 +1,21 @@ +package net.coderbot.iris.rendertarget; + +import net.minecraft.client.renderer.texture.DynamicTexture; + +public class NativeImageBackedSingleColorTexture extends DynamicTexture { + public NativeImageBackedSingleColorTexture(int red, int green, int blue, int alpha) { + super(create(NativeImage.combine(alpha, blue, green, red))); + } + + public NativeImageBackedSingleColorTexture(int rgba) { + this(rgba >> 24 & 0xFF, rgba >> 16 & 0xFF, rgba >> 8 & 0xFF, rgba & 0xFF); + } + + private static NativeImage create(int color) { + NativeImage image = new NativeImage(NativeImage.Format.RGBA, 1, 1, false); + + image.setPixelRGBA(0, 0, color); + + return image; + } +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/NoiseTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NoiseTexture.java new file mode 100644 index 000000000..2ecf25b4f --- /dev/null +++ b/src/main/java/net/coderbot/iris/rendertarget/NoiseTexture.java @@ -0,0 +1,75 @@ +package net.coderbot.iris.rendertarget; + +import net.coderbot.iris.gl.GlResource; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.texture.TextureUploadHelper; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; +import org.lwjgl.opengl.GL14; + +import java.nio.ByteBuffer; +import java.util.Random; + +/** + * An extremely simple noise texture. Each color channel contains a uniform random value from 0 to 255. Essentially just + * dumps an array of random bytes into a texture and calls it a day, literally could not be any simpler than that. + */ +public class NoiseTexture extends GlResource { + int width; + int height; + + public NoiseTexture(int width, int height) { + super(IrisRenderSystem.createTexture(GL11.GL_TEXTURE_2D)); + + int texture = getGlId(); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); + + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MIN_LOD, 0); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LOD,0); + IrisRenderSystem.texParameterf(texture, GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_LOD_BIAS, 0.0F); + resize(texture, width, height); + + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + } + + void resize(int texture, int width, int height) { + this.width = width; + this.height = height; + + ByteBuffer pixels = generateNoise(); + + TextureUploadHelper.resetTextureUploadState(); + + // Since we're using tightly-packed RGB data, we must use an alignment of 1 byte instead of the usual 4 bytes. + GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1); + IrisRenderSystem.texImage2D(texture, GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, width, height, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, pixels); + + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + } + + private ByteBuffer generateNoise() { + byte[] pixels = new byte[3 * width * height]; + + Random random = new Random(0); + random.nextBytes(pixels); + + ByteBuffer buffer = ByteBuffer.allocateDirect(pixels.length); + buffer.put(pixels); + buffer.flip(); + + return buffer; + } + + public int getTextureId() { + return getGlId(); + } + + @Override + protected void destroyInternal() { + GL11.glDeleteTextures(getGlId()); + } +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java new file mode 100644 index 000000000..685ee3e7c --- /dev/null +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java @@ -0,0 +1,170 @@ +package net.coderbot.iris.rendertarget; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.texture.InternalTextureFormat; +import net.coderbot.iris.gl.texture.PixelFormat; +import net.coderbot.iris.gl.texture.PixelType; +import org.joml.Vector2i; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +public class RenderTarget { + private final InternalTextureFormat internalFormat; + private final PixelFormat format; + private final PixelType type; + private int width; + private int height; + + private boolean isValid; + private final int mainTexture; + private final int altTexture; + + private static final ByteBuffer NULL_BUFFER = null; + + public RenderTarget(Builder builder) { + this.isValid = true; + + this.internalFormat = builder.internalFormat; + this.format = builder.format; + this.type = builder.type; + + this.width = builder.width; + this.height = builder.height; + + int[] textures = new int[2]; + GL11.glGenTextures(IntBuffer.wrap(textures)); + + this.mainTexture = textures[0]; + this.altTexture = textures[1]; + + boolean isPixelFormatInteger = builder.internalFormat.getPixelFormat().isInteger(); + setupTexture(mainTexture, builder.width, builder.height, !isPixelFormatInteger); + setupTexture(altTexture, builder.width, builder.height, !isPixelFormatInteger); + + // Clean up after ourselves + // This is strictly defensive to ensure that other buggy code doesn't tamper with our textures + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + } + + private void setupTexture(int texture, int width, int height, boolean allowsLinear) { + resizeTexture(texture, width, height); + + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, allowsLinear ? GL11.GL_LINEAR : GL11.GL_NEAREST); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, allowsLinear ? GL11.GL_LINEAR : GL11.GL_NEAREST); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); + } + + private void resizeTexture(int texture, int width, int height) { + IrisRenderSystem.texImage2D(texture, GL11.GL_TEXTURE_2D, 0, internalFormat.getGlFormat(), width, height, 0, format.getGlFormat(), type.getGlFormat(), NULL_BUFFER); + } + + void resize(Vector2i textureScaleOverride) { + this.resize(textureScaleOverride.x, textureScaleOverride.y); + } + + // Package private, call CompositeRenderTargets#resizeIfNeeded instead. + void resize(int width, int height) { + requireValid(); + + this.width = width; + this.height = height; + + resizeTexture(mainTexture, width, height); + + resizeTexture(altTexture, width, height); + } + + public InternalTextureFormat getInternalFormat() { + return internalFormat; + } + + public int getMainTexture() { + requireValid(); + + return mainTexture; + } + + public int getAltTexture() { + requireValid(); + + return altTexture; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void destroy() { + requireValid(); + isValid = false; + GL11.glDeleteTextures(mainTexture); + GL11.glDeleteTextures(altTexture); + } + + private void requireValid() { + if (!isValid) { + throw new IllegalStateException("Attempted to use a deleted composite render target"); + } + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private InternalTextureFormat internalFormat = InternalTextureFormat.RGBA8; + private int width = 0; + private int height = 0; + private PixelFormat format = PixelFormat.RGBA; + private PixelType type = PixelType.UNSIGNED_BYTE; + + private Builder() { + // No-op + } + + public Builder setInternalFormat(InternalTextureFormat format) { + this.internalFormat = format; + + return this; + } + + public Builder setDimensions(int width, int height) { + if (width <= 0) { + throw new IllegalArgumentException("Width must be greater than zero"); + } + + if (height <= 0) { + throw new IllegalArgumentException("Height must be greater than zero"); + } + + this.width = width; + this.height = height; + + return this; + } + + public Builder setPixelFormat(PixelFormat pixelFormat) { + this.format = pixelFormat; + + return this; + } + + public Builder setPixelType(PixelType pixelType) { + this.type = pixelType; + + return this; + } + + public RenderTarget build() { + return new RenderTarget(this); + } + } +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java new file mode 100644 index 000000000..bfd204c47 --- /dev/null +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java @@ -0,0 +1,332 @@ +package net.coderbot.iris.rendertarget; + +import com.google.common.collect.ImmutableSet; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.framebuffer.GlFramebuffer; +import net.coderbot.iris.gl.texture.DepthBufferFormat; +import net.coderbot.iris.gl.texture.DepthCopyStrategy; +import net.coderbot.iris.shaderpack.PackDirectives; +import net.coderbot.iris.shaderpack.PackRenderTargetDirectives; +import org.joml.Vector2i; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class RenderTargets { + private final RenderTarget[] targets; + private int currentDepthTexture; + private DepthBufferFormat currentDepthFormat; + + private final DepthTexture noTranslucents; + private final DepthTexture noHand; + private final GlFramebuffer depthSourceFb; + private final GlFramebuffer noTranslucentsDestFb; + private final GlFramebuffer noHandDestFb; + private DepthCopyStrategy copyStrategy; + + private final List ownedFramebuffers; + + private int cachedWidth; + private int cachedHeight; + private boolean fullClearRequired; + private boolean translucentDepthDirty; + private boolean handDepthDirty; + + private int cachedDepthBufferVersion; + + public RenderTargets(int width, int height, int depthTexture, int depthBufferVersion, DepthBufferFormat depthFormat, Map renderTargets, PackDirectives packDirectives) { + targets = new RenderTarget[renderTargets.size()]; + + renderTargets.forEach((index, settings) -> { + // TODO: Handle mipmapping? + Vector2i dimensions = packDirectives.getTextureScaleOverride(index, width, height); + targets[index] = RenderTarget.builder().setDimensions(dimensions.x, dimensions.y) + .setInternalFormat(settings.getInternalFormat()) + .setPixelFormat(settings.getInternalFormat().getPixelFormat()).build(); + }); + + this.currentDepthTexture = depthTexture; + this.currentDepthFormat = depthFormat; + this.copyStrategy = DepthCopyStrategy.fastest(currentDepthFormat.isCombinedStencil()); + + this.cachedWidth = width; + this.cachedHeight = height; + this.cachedDepthBufferVersion = depthBufferVersion; + + this.ownedFramebuffers = new ArrayList<>(); + + // NB: Make sure all buffers are cleared so that they don't contain undefined + // data. Otherwise very weird things can happen. + fullClearRequired = true; + + this.depthSourceFb = createFramebufferWritingToMain(new int[] {0}); + + this.noTranslucents = new DepthTexture(width, height, currentDepthFormat); + this.noHand = new DepthTexture(width, height, currentDepthFormat); + + this.noTranslucentsDestFb = createFramebufferWritingToMain(new int[] {0}); + this.noTranslucentsDestFb.addDepthAttachment(this.noTranslucents.getTextureId()); + + this.noHandDestFb = createFramebufferWritingToMain(new int[] {0}); + this.noHandDestFb.addDepthAttachment(this.noHand.getTextureId()); + + this.translucentDepthDirty = true; + this.handDepthDirty = true; + } + + public void destroy() { + for (GlFramebuffer owned : ownedFramebuffers) { + owned.destroy(); + } + + for (RenderTarget target : targets) { + target.destroy(); + } + + noTranslucents.destroy(); + noHand.destroy(); + } + + public int getRenderTargetCount() { + return targets.length; + } + + public RenderTarget get(int index) { + return targets[index]; + } + + public int getDepthTexture() { + return currentDepthTexture; + } + + public DepthTexture getDepthTextureNoTranslucents() { + return noTranslucents; + } + + public DepthTexture getDepthTextureNoHand() { + return noHand; + } + + public boolean resizeIfNeeded(int newDepthBufferVersion, int newDepthTextureId, int newWidth, int newHeight, DepthBufferFormat newDepthFormat, PackDirectives packDirectives) { + boolean recreateDepth = false; + if (cachedDepthBufferVersion != newDepthBufferVersion) { + recreateDepth = true; + currentDepthTexture = newDepthTextureId; + cachedDepthBufferVersion = newDepthBufferVersion; + } + + boolean sizeChanged = newWidth != cachedWidth || newHeight != cachedHeight; + boolean depthFormatChanged = newDepthFormat != currentDepthFormat; + + if (depthFormatChanged) { + currentDepthFormat = newDepthFormat; + // Might need a new copy strategy + copyStrategy = DepthCopyStrategy.fastest(currentDepthFormat.isCombinedStencil()); + } + + if (recreateDepth) { + // Re-attach the depth textures with the new depth texture ID, since Minecraft re-creates + // the depth texture when resizing its render targets. + // + // I'm not sure if our framebuffers holding on to the old depth texture between frames + // could be a concern, in the case of resizing and similar. I think it should work + // based on what I've seen of the spec, though - it seems like deleting a texture + // automatically detaches it from its framebuffers. + for (GlFramebuffer framebuffer : ownedFramebuffers) { + if (framebuffer == noHandDestFb || framebuffer == noTranslucentsDestFb) { + // NB: Do not change the depth attachment of these framebuffers + // as it is intentionally different + continue; + } + + if (framebuffer.hasDepthAttachment()) { + framebuffer.addDepthAttachment(newDepthTextureId); + } + } + } + + if (depthFormatChanged || sizeChanged) { + // Reallocate depth buffers + noTranslucents.resize(newWidth, newHeight, newDepthFormat); + noHand.resize(newWidth, newHeight, newDepthFormat); + this.translucentDepthDirty = true; + this.handDepthDirty = true; + } + + if (sizeChanged) { + cachedWidth = newWidth; + cachedHeight = newHeight; + + for (int i = 0; i < targets.length; i++) { + targets[i].resize(packDirectives.getTextureScaleOverride(i, newWidth, newHeight)); + } + + fullClearRequired = true; + } + + return sizeChanged; + } + + public void copyPreTranslucentDepth() { + if (translucentDepthDirty) { + translucentDepthDirty = false; + GL11.glBindTexture(GL11.GL_TEXTURE_2D, noTranslucents.getTextureId()); + depthSourceFb.bindAsReadBuffer(); + IrisRenderSystem.copyTexImage2D(GL11.GL_TEXTURE_2D, 0, currentDepthFormat.getGlInternalFormat(), 0, 0, cachedWidth, cachedHeight, 0); + } else { + copyStrategy.copy(depthSourceFb, getDepthTexture(), noTranslucentsDestFb, noTranslucents.getTextureId(), + getCurrentWidth(), getCurrentHeight()); + } + } + + public void copyPreHandDepth() { + if (handDepthDirty) { + handDepthDirty = false; + GL11.glBindTexture(GL11.GL_TEXTURE_2D, noHand.getTextureId()); + depthSourceFb.bindAsReadBuffer(); + IrisRenderSystem.copyTexImage2D(GL11.GL_TEXTURE_2D, 0, currentDepthFormat.getGlInternalFormat(), 0, 0, cachedWidth, cachedHeight, 0); + } else { + copyStrategy.copy(depthSourceFb, getDepthTexture(), noHandDestFb, noHand.getTextureId(), + getCurrentWidth(), getCurrentHeight()); + } + } + + public boolean isFullClearRequired() { + return fullClearRequired; + } + + public void onFullClear() { + fullClearRequired = false; + } + + public GlFramebuffer createFramebufferWritingToMain(int[] drawBuffers) { + return createFullFramebuffer(false, drawBuffers); + } + + public GlFramebuffer createFramebufferWritingToAlt(int[] drawBuffers) { + return createFullFramebuffer(true, drawBuffers); + } + + public GlFramebuffer createClearFramebuffer(boolean alt, int[] clearBuffers) { + ImmutableSet stageWritesToMain = ImmutableSet.of(); + + if (!alt) { + stageWritesToMain = invert(ImmutableSet.of(), clearBuffers); + } + + return createColorFramebuffer(stageWritesToMain, clearBuffers); + } + + private ImmutableSet invert(ImmutableSet base, int[] relevant) { + ImmutableSet.Builder inverted = ImmutableSet.builder(); + + for (int i : relevant) { + if (!base.contains(i)) { + inverted.add(i); + } + } + + return inverted.build(); + } + + private GlFramebuffer createEmptyFramebuffer() { + GlFramebuffer framebuffer = new GlFramebuffer(); + ownedFramebuffers.add(framebuffer); + + framebuffer.addDepthAttachment(currentDepthTexture); + + // NB: Before OpenGL 3.0, all framebuffers are required to have a color + // attachment no matter what. + framebuffer.addColorAttachment(0, get(0).getMainTexture()); + framebuffer.noDrawBuffers(); + + return framebuffer; + } + + public GlFramebuffer createGbufferFramebuffer(ImmutableSet stageWritesToAlt, int[] drawBuffers) { + if (drawBuffers.length == 0) { + return createEmptyFramebuffer(); + } + + ImmutableSet stageWritesToMain = invert(stageWritesToAlt, drawBuffers); + + GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); + + framebuffer.addDepthAttachment(currentDepthTexture); + + return framebuffer; + } + + private GlFramebuffer createFullFramebuffer(boolean clearsAlt, int[] drawBuffers) { + if (drawBuffers.length == 0) { + return createEmptyFramebuffer(); + } + + ImmutableSet stageWritesToMain = ImmutableSet.of(); + + if (!clearsAlt) { + stageWritesToMain = invert(ImmutableSet.of(), drawBuffers); + } + + return createColorFramebufferWithDepth(stageWritesToMain, drawBuffers); + } + + public GlFramebuffer createColorFramebufferWithDepth(ImmutableSet stageWritesToMain, int[] drawBuffers) { + GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); + + framebuffer.addDepthAttachment(currentDepthTexture); + + return framebuffer; + } + + public GlFramebuffer createColorFramebuffer(ImmutableSet stageWritesToMain, int[] drawBuffers) { + if (drawBuffers.length == 0) { + throw new IllegalArgumentException("Framebuffer must have at least one color buffer"); + } + + GlFramebuffer framebuffer = new GlFramebuffer(); + ownedFramebuffers.add(framebuffer); + + int[] actualDrawBuffers = new int[drawBuffers.length]; + + for (int i = 0; i < drawBuffers.length; i++) { + actualDrawBuffers[i] = i; + + if (drawBuffers[i] >= getRenderTargetCount()) { + // TODO: This causes resource leaks, also we should really verify this in the shaderpack parser... + throw new IllegalStateException("Render target with index " + drawBuffers[i] + " is not supported, only " + + getRenderTargetCount() + " render targets are supported."); + } + + RenderTarget target = this.get(drawBuffers[i]); + + int textureId = stageWritesToMain.contains(drawBuffers[i]) ? target.getMainTexture() : target.getAltTexture(); + + framebuffer.addColorAttachment(i, textureId); + } + + framebuffer.drawBuffers(actualDrawBuffers); + framebuffer.readBuffer(0); + + if (!framebuffer.isComplete()) { + throw new IllegalStateException("Unexpected error while creating framebuffer"); + } + + return framebuffer; + } + + public void destroyFramebuffer(GlFramebuffer framebuffer) { + framebuffer.destroy(); + ownedFramebuffers.remove(framebuffer); + } + + public int getCurrentWidth() { + return cachedWidth; + } + + public int getCurrentHeight() { + return cachedHeight; + } +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/SingleColorTexture.java b/src/main/java/net/coderbot/iris/rendertarget/SingleColorTexture.java new file mode 100644 index 000000000..af6a217b4 --- /dev/null +++ b/src/main/java/net/coderbot/iris/rendertarget/SingleColorTexture.java @@ -0,0 +1,40 @@ +package net.coderbot.iris.rendertarget; + +import net.coderbot.iris.gl.GlResource; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.texture.TextureUploadHelper; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; + +import java.nio.ByteBuffer; + +public class SingleColorTexture extends GlResource { + public SingleColorTexture(int red, int green, int blue, int alpha) { + super(IrisRenderSystem.createTexture(GL11.GL_TEXTURE_2D)); + ByteBuffer pixel = BufferUtils.createByteBuffer(4); + pixel.put((byte) red); + pixel.put((byte) green); + pixel.put((byte) blue); + pixel.put((byte) alpha); + pixel.position(0); + + int texture = getGlId(); + + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); + + TextureUploadHelper.resetTextureUploadState(); + IrisRenderSystem.texImage2D(texture, GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, 1, 1, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixel); + } + + public int getTextureId() { + return getGlId(); + } + + @Override + protected void destroyInternal() { + GL11.glDeleteTextures(getGlId()); + } +} diff --git a/src/main/java/net/coderbot/iris/samplers/IrisImages.java b/src/main/java/net/coderbot/iris/samplers/IrisImages.java new file mode 100644 index 000000000..7ed7e9977 --- /dev/null +++ b/src/main/java/net/coderbot/iris/samplers/IrisImages.java @@ -0,0 +1,53 @@ +package net.coderbot.iris.samplers; + +import com.google.common.collect.ImmutableSet; +import net.coderbot.iris.gl.image.ImageHolder; +import net.coderbot.iris.gl.texture.InternalTextureFormat; +import net.coderbot.iris.rendertarget.RenderTarget; +import net.coderbot.iris.rendertarget.RenderTargets; +import net.coderbot.iris.shadows.ShadowRenderTargets; + +import java.util.function.IntSupplier; +import java.util.function.Supplier; + +public class IrisImages { + public static void addRenderTargetImages(ImageHolder images, Supplier> flipped, + RenderTargets renderTargets) { + for (int i = 0; i < renderTargets.getRenderTargetCount(); i++) { + final int index = i; + + // Note: image bindings *are* impacted by buffer flips. + IntSupplier textureID = () -> { + ImmutableSet flippedBuffers = flipped.get(); + RenderTarget target = renderTargets.get(index); + + if (flippedBuffers.contains(index)) { + return target.getAltTexture(); + } else { + return target.getMainTexture(); + } + }; + + final InternalTextureFormat internalFormat = renderTargets.get(i).getInternalFormat(); + final String name = "colorimg" + i; + + images.addTextureImage(textureID, internalFormat, name); + } + } + + public static boolean hasShadowImages(ImageHolder images) { + // TODO: Generalize + return images.hasImage("shadowcolorimg0") || images.hasImage("shadowcolorimg1"); + } + + public static void addShadowColorImages(ImageHolder images, ShadowRenderTargets shadowRenderTargets) { + for (int i = 0; i < shadowRenderTargets.getNumColorTextures(); i++) { + final int index = i; + + IntSupplier textureID = () -> shadowRenderTargets.getColorTextureId(index); + InternalTextureFormat format = shadowRenderTargets.getColorTextureFormat(index); + + images.addTextureImage(textureID, format, "shadowcolorimg" + i); + } + } +} diff --git a/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java b/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java new file mode 100644 index 000000000..25cfa95cf --- /dev/null +++ b/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java @@ -0,0 +1,166 @@ +package net.coderbot.iris.samplers; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; +import net.coderbot.iris.gl.sampler.SamplerHolder; +import net.coderbot.iris.gl.state.StateUpdateNotifiers; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.coderbot.iris.rendertarget.RenderTarget; +import net.coderbot.iris.rendertarget.RenderTargets; +import net.coderbot.iris.shaderpack.PackRenderTargetDirectives; +import net.coderbot.iris.shadows.ShadowRenderTargets; +import net.minecraft.client.renderer.texture.AbstractTexture; + +import java.util.function.IntSupplier; +import java.util.function.Supplier; + +public class IrisSamplers { + public static final int ALBEDO_TEXTURE_UNIT = 0; + public static final int OVERLAY_TEXTURE_UNIT = 1; + public static final int LIGHTMAP_TEXTURE_UNIT = 2; + + public static final ImmutableSet WORLD_RESERVED_TEXTURE_UNITS = ImmutableSet.of(0, 1, 2); + + // TODO: In composite programs, there shouldn't be any reserved textures. + // We need a way to restore these texture bindings. + public static final ImmutableSet COMPOSITE_RESERVED_TEXTURE_UNITS = ImmutableSet.of(1, 2); + + private IrisSamplers() { + // no construction allowed + } + + public static void addRenderTargetSamplers(SamplerHolder samplers, Supplier> flipped, + RenderTargets renderTargets, boolean isFullscreenPass) { + // colortex0,1,2,3 are only able to be sampled from fullscreen passes. + // Iris could lift this restriction, though I'm not sure if it could cause issues. + int startIndex = isFullscreenPass ? 0 : 4; + + for (int i = startIndex; i < renderTargets.getRenderTargetCount(); i++) { + final int index = i; + + IntSupplier sampler = () -> { + ImmutableSet flippedBuffers = flipped.get(); + RenderTarget target = renderTargets.get(index); + + if (flippedBuffers.contains(index)) { + return target.getAltTexture(); + } else { + return target.getMainTexture(); + } + }; + + final String name = "colortex" + i; + + // TODO: How do custom textures interact with aliases? + + if (i < PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.size()) { + String legacyName = PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.get(i); + + // colortex0 is the default sampler in fullscreen passes + if (i == 0 && isFullscreenPass) { + samplers.addDefaultSampler(sampler, name, legacyName); + } else { + samplers.addDynamicSampler(sampler, name, legacyName); + } + } else { + samplers.addDynamicSampler(sampler, name); + } + } + } + + public static void addNoiseSampler(SamplerHolder samplers, IntSupplier sampler) { + samplers.addDynamicSampler(sampler, "noisetex"); + } + + public static boolean hasShadowSamplers(SamplerHolder samplers) { + // TODO: Keep this up to date with the actual definitions. + // TODO: Don't query image presence using the sampler interface even though the current underlying implementation + // is the same. + ImmutableList shadowSamplers = ImmutableList.of("shadowtex0", "shadowtex0HW", "shadowtex1", "shadowtex1HW", "shadow", "watershadow", + "shadowcolor", "shadowcolor0", "shadowcolor1", "shadowcolorimg0", "shadowcolorimg1"); + + for (String samplerName : shadowSamplers) { + if (samplers.hasSampler(samplerName)) { + return true; + } + } + + return false; + } + + public static boolean addShadowSamplers(SamplerHolder samplers, ShadowRenderTargets shadowRenderTargets) { + boolean usesShadows; + + // TODO: figure this out from parsing the shader source code to be 100% compatible with the legacy + // shader packs that rely on this behavior. + boolean waterShadowEnabled = samplers.hasSampler("watershadow"); + + if (waterShadowEnabled) { + usesShadows = true; + samplers.addDynamicSampler(shadowRenderTargets.getDepthTexture()::getTextureId, "shadowtex0", "watershadow"); + samplers.addDynamicSampler(shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, + "shadowtex1", "shadow"); + } else { + usesShadows = samplers.addDynamicSampler(shadowRenderTargets.getDepthTexture()::getTextureId, "shadowtex0", "shadow"); + usesShadows |= samplers.addDynamicSampler(shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, "shadowtex1"); + } + + samplers.addDynamicSampler(() -> shadowRenderTargets.getColorTextureId(0), "shadowcolor", "shadowcolor0"); + samplers.addDynamicSampler(() -> shadowRenderTargets.getColorTextureId(1), "shadowcolor1"); + + if (shadowRenderTargets.isHardwareFiltered(0)) { + samplers.addDynamicSampler(shadowRenderTargets.getDepthTexture()::getTextureId, "shadowtex0HW"); + } + + if (shadowRenderTargets.isHardwareFiltered(1)) { + samplers.addDynamicSampler(shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, "shadowtex1HW"); + } + + return usesShadows; + } + + public static boolean hasPBRSamplers(SamplerHolder samplers) { + return samplers.hasSampler("normals") || samplers.hasSampler("specular"); + } + + public static void addLevelSamplers(SamplerHolder samplers, WorldRenderingPipeline pipeline, AbstractTexture whitePixel, InputAvailability availability) { + if (availability.texture) { + samplers.addExternalSampler(ALBEDO_TEXTURE_UNIT, "tex", "texture", "gtexture"); + } else { + // TODO: Rebind unbound sampler IDs instead of hardcoding a list... + samplers.addDynamicSampler(whitePixel::getId, "tex", "texture", "gtexture", + "gcolor", "colortex0"); + } + + if (availability.lightmap) { + samplers.addExternalSampler(LIGHTMAP_TEXTURE_UNIT, "lightmap"); + } else { + samplers.addDynamicSampler(whitePixel::getId, "lightmap"); + } + + if (availability.overlay) { + samplers.addExternalSampler(OVERLAY_TEXTURE_UNIT, "iris_overlay"); + } else { + samplers.addDynamicSampler(whitePixel::getId, "iris_overlay"); + } + + samplers.addDynamicSampler(pipeline::getCurrentNormalTexture, StateUpdateNotifiers.normalTextureChangeNotifier, "normals"); + samplers.addDynamicSampler(pipeline::getCurrentSpecularTexture, StateUpdateNotifiers.specularTextureChangeNotifier, "specular"); + } + + public static void addWorldDepthSamplers(SamplerHolder samplers, RenderTargets renderTargets) { + samplers.addDynamicSampler(renderTargets::getDepthTexture, "depthtex0"); + // TODO: Should depthtex2 be made available to gbuffer / shadow programs? + samplers.addDynamicSampler(renderTargets.getDepthTextureNoTranslucents()::getTextureId, "depthtex1"); + } + + public static void addCompositeSamplers(SamplerHolder samplers, RenderTargets renderTargets) { + samplers.addDynamicSampler(renderTargets::getDepthTexture, + "gdepthtex", "depthtex0"); + samplers.addDynamicSampler(renderTargets.getDepthTextureNoTranslucents()::getTextureId, + "depthtex1"); + samplers.addDynamicSampler(renderTargets.getDepthTextureNoHand()::getTextureId, + "depthtex2"); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/CloudSetting.java b/src/main/java/net/coderbot/iris/shaderpack/CloudSetting.java new file mode 100644 index 000000000..18a69f6f2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/CloudSetting.java @@ -0,0 +1,8 @@ +package net.coderbot.iris.shaderpack; + +public enum CloudSetting { + DEFAULT, + FAST, + FANCY, + OFF +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/CommentDirective.java b/src/main/java/net/coderbot/iris/shaderpack/CommentDirective.java new file mode 100644 index 000000000..8d64506c2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/CommentDirective.java @@ -0,0 +1,38 @@ +package net.coderbot.iris.shaderpack; + +public class CommentDirective { + public enum Type { + DRAWBUFFERS, + RENDERTARGETS + } + + private final Type type; + private final String directive; + private final int location; + + CommentDirective(Type type, String directive, int location) { + this.type = type; + this.directive = directive; + this.location = location; + } + + public Type getType() { + return type; + } + + /** + * @return The directive without {@literal /}* or *{@literal /} + */ + public String getDirective() { + return directive; + } + + /** + * @return The starting position of the directive in a multi-line string.
+ * This is necessary to check if either the drawbuffer or the rendertarget directive should be applied + * when there are multiple in the same shader file, based on which one is defined last. + */ + public int getLocation() { + return location; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/CommentDirectiveParser.java b/src/main/java/net/coderbot/iris/shaderpack/CommentDirectiveParser.java new file mode 100644 index 000000000..88808c61f --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/CommentDirectiveParser.java @@ -0,0 +1,151 @@ +package net.coderbot.iris.shaderpack; + +import java.util.Optional; +import java.util.function.Supplier; + +/** + * Parses comment-based directives found in shader source files of the form: + * + *
/* KEY:VALUE */
+ *

+ * A common example is draw buffer directives: + * + *

/* DRAWBUFFERS:157 */
+ *

+ * A given directive should only occur once in a shader file. If there are multiple occurrences of a directive with a + * given key, the last occurrence is used. + */ +public class CommentDirectiveParser { + // Directives take the following form: + // /* KEY:VALUE */ + + private CommentDirectiveParser() { + // cannot be constructed + } + + public static Optional findDirective(String haystack, CommentDirective.Type type) { + String needle = type.name(); + String prefix = needle + ":"; + String suffix = "*/"; + + // Search for the last occurrence of the directive within the text, since those take precedence. + int indexOfPrefix = haystack.lastIndexOf(prefix); + + if (indexOfPrefix == -1) { + return Optional.empty(); + } + + String before = haystack.substring(0, indexOfPrefix).trim(); + + if (!before.endsWith("/*")) { + // Reject a match if it doesn't actually start with a comment marker + // TODO: If a line has two directives, one valid, and the other invalid, then this might not work properly + return Optional.empty(); + } + + // Remove everything up to and including the prefix + haystack = haystack.substring(indexOfPrefix + prefix.length()); + + int indexOfSuffix = haystack.indexOf(suffix); + + // If there isn't a proper suffix, this directive is malformed and should be discarded. + if (indexOfSuffix == -1) { + return Optional.empty(); + } + + // Remove the suffix and everything afterwards, also trim any whitespace + haystack = haystack.substring(0, indexOfSuffix).trim(); + + return Optional.of(new CommentDirective(CommentDirective.Type.valueOf(needle), haystack, indexOfPrefix)); + } + + // Test code for directive parsing. It's a bit homegrown but it works. + @SuppressWarnings("unused") + private static class Tests { + private static void test(String name, T expected, Supplier testCase) { + T actual; + + try { + actual = testCase.get(); + } catch (Throwable e) { + System.err.println("Test \"" + name + "\" failed with an exception:"); + e.printStackTrace(); + + return; + } + + if (!expected.equals(actual)) { + System.err.println("Test \"" + name + "\" failed: Expected " + expected + ", got " + actual); + } else { + System.out.println("Test \"" + name + "\" passed"); + } + } + + public static void main(String[] args) { + test("normal text", Optional.empty(), () -> { + String line = "Some normal text that doesn't contain a DRAWBUFFERS directive of any sort"; + + return CommentDirectiveParser.findDirective(line, CommentDirective.Type.DRAWBUFFERS).map(CommentDirective::getDirective); + }); + + test("partial directive", Optional.empty(), () -> { + String line = "Some normal text that doesn't contain a /* DRAWBUFFERS: directive of any sort"; + + return CommentDirectiveParser.findDirective(line, CommentDirective.Type.DRAWBUFFERS).map(CommentDirective::getDirective); + }); + + test("bad spacing", Optional.of("321"), () -> { + String line = "/*DRAWBUFFERS:321*/ OptiFine will detect this directive, but ShadersMod will not..."; + + return CommentDirectiveParser.findDirective(line, CommentDirective.Type.DRAWBUFFERS).map(CommentDirective::getDirective); + }); + + test("matchAtEnd", Optional.of("321"), () -> { + String line = "A line containing a drawbuffers directive: /* DRAWBUFFERS:321 */"; + + return CommentDirectiveParser.findDirective(line, CommentDirective.Type.DRAWBUFFERS).map(CommentDirective::getDirective); + }); + + test("matchAtStart", Optional.of("31"), () -> { + String line = "/* DRAWBUFFERS:31 */ This is a line containing a drawbuffers directive"; + + return CommentDirectiveParser.findDirective(line, CommentDirective.Type.DRAWBUFFERS).map(CommentDirective::getDirective); + }); + + test("matchInMiddle", Optional.of("31"), () -> { + String line = "This is a line /* DRAWBUFFERS:31 */ containing a drawbuffers directive"; + + return CommentDirectiveParser.findDirective(line, CommentDirective.Type.DRAWBUFFERS).map(CommentDirective::getDirective); + }); + + test("emptyMatch", Optional.of(""), () -> { + String line = "/* DRAWBUFFERS: */ This is a line containing an invalid but still matching drawbuffers directive"; + + return CommentDirectiveParser.findDirective(line, CommentDirective.Type.DRAWBUFFERS).map(CommentDirective::getDirective); + }); + + test("duplicates", Optional.of("3"), () -> { + String line = "/* TEST:2 */ This line contains multiple directives, the last one should be used /* TEST:3 */"; + + return CommentDirectiveParser.findDirective(line, CommentDirective.Type.DRAWBUFFERS).map(CommentDirective::getDirective); + }); + + test("multi-line", Optional.of("It works"), () -> { + String lines = + "/* Here's a random comment line */\n" + + "/* RENDERTARGETS:Duplicate handling? */\n" + + "uniform sampler2D test;\n" + + "/* RENDERTARGETS:Duplicate handling within a line? */ Let's see /* RENDERTARGETS:It works */\n"; + + return CommentDirectiveParser.findDirective(lines, CommentDirective.Type.RENDERTARGETS).map(CommentDirective::getDirective); + }); + + // OptiFine finds this directive, but ShadersMod does not... + test("bad spacing from BSL composite6", Optional.of("12"), () -> { + String line = " /*DRAWBUFFERS:12*/"; + + return CommentDirectiveParser.findDirective(line, CommentDirective.Type.DRAWBUFFERS).map(CommentDirective::getDirective); + }); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/ComputeDirectiveParser.java b/src/main/java/net/coderbot/iris/shaderpack/ComputeDirectiveParser.java new file mode 100644 index 000000000..8ef4e266b --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/ComputeDirectiveParser.java @@ -0,0 +1,75 @@ +package net.coderbot.iris.shaderpack; + +import net.coderbot.iris.Iris; +import org.joml.Vector2f; +import org.joml.Vector3i; + +public class ComputeDirectiveParser { + public static void setComputeWorkGroups(ComputeSource source, ConstDirectiveParser.ConstDirective directive) { + if (!directive.getValue().startsWith("ivec3")) { + Iris.logger.error("Failed to process " + directive + ": value was not a valid ivec3 constructor"); + } + + String ivec3Args = directive.getValue().substring("ivec3".length()).trim(); + + if (!ivec3Args.startsWith("(") || !ivec3Args.endsWith(")")) { + Iris.logger.error("Failed to process " + directive + ": value was not a valid ivec3 constructor"); + } + + ivec3Args = ivec3Args.substring(1, ivec3Args.length() - 1); + + String[] parts = ivec3Args.split(","); + + for (int i = 0; i < parts.length; i++) { + parts[i] = parts[i].trim(); + } + + if (parts.length != 3) { + Iris.logger.error("Failed to process " + directive + + ": expected 3 arguments to a ivec3 constructor, got " + parts.length); + } + + try { + source.setWorkGroups(new Vector3i( + Integer.parseInt(parts[0]), + Integer.parseInt(parts[1]), + Integer.parseInt(parts[2]))); + } catch (NumberFormatException e) { + Iris.logger.error("Failed to process " + directive, e); + } + } + + public static void setComputeWorkGroupsRelative(ComputeSource source, ConstDirectiveParser.ConstDirective directive) { + if (!directive.getValue().startsWith("vec2")) { + Iris.logger.error("Failed to process " + directive + ": value was not a valid vec2 constructor"); + } + + String vec2Args = directive.getValue().substring("vec2".length()).trim(); + + if (!vec2Args.startsWith("(") || !vec2Args.endsWith(")")) { + Iris.logger.error("Failed to process " + directive + ": value was not a valid vec2 constructor"); + } + + vec2Args = vec2Args.substring(1, vec2Args.length() - 1); + + String[] parts = vec2Args.split(","); + + for (int i = 0; i < parts.length; i++) { + parts[i] = parts[i].trim(); + } + + if (parts.length != 2) { + Iris.logger.error("Failed to process " + directive + + ": expected 2 arguments to a vec2 constructor, got " + parts.length); + } + + try { + source.setWorkGroupRelative(new Vector2f( + Float.parseFloat(parts[0]), + Float.parseFloat(parts[1]) + )); + } catch (NumberFormatException e) { + Iris.logger.error("Failed to process " + directive, e); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/ComputeSource.java b/src/main/java/net/coderbot/iris/shaderpack/ComputeSource.java new file mode 100644 index 000000000..c0dff55ed --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/ComputeSource.java @@ -0,0 +1,60 @@ +package net.coderbot.iris.shaderpack; + +import org.joml.Vector2f; +import org.joml.Vector3i; + +import java.util.Optional; + +public class ComputeSource { + private final String name; + private final String source; + private final ProgramSet parent; + private Vector3i workGroups; + private Vector2f workGroupRelative; + + public ComputeSource(String name, String source, ProgramSet parent) { + this.name = name; + this.source = source; + this.parent = parent; + } + + public String getName() { + return name; + } + + public Optional getSource() { + return Optional.ofNullable(source); + } + + public ProgramSet getParent() { + return parent; + } + + public boolean isValid() { + return source != null; + } + + public void setWorkGroups(Vector3i workGroups) { + this.workGroups = workGroups; + } + + public void setWorkGroupRelative(Vector2f workGroupRelative) { + this.workGroupRelative = workGroupRelative; + } + + public Vector2f getWorkGroupRelative() { + return workGroupRelative; + } + + public Vector3i getWorkGroups() { + return workGroups; + } + + public Optional requireValid() { + if (this.isValid()) { + return Optional.of(this); + } else { + return Optional.empty(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/ConstDirectiveParser.java b/src/main/java/net/coderbot/iris/shaderpack/ConstDirectiveParser.java new file mode 100644 index 000000000..f8d80d232 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/ConstDirectiveParser.java @@ -0,0 +1,178 @@ +package net.coderbot.iris.shaderpack; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class ConstDirectiveParser { + public static List findDirectives(String source) { + List directives = new ArrayList<>(); + + // Match any valid newline sequence + // https://stackoverflow.com/a/31060125 + for (String line : source.split("\\R")) { + findDirectiveInLine(line).ifPresent(directives::add); + } + + return directives; + } + + public static Optional findDirectiveInLine(String line) { + // Valid const directives contain the following elements: + // * Zero or more whitespace characters + // * A "const" literal + // * At least one whitespace character + // * A type literal (int, float, vec4, or bool) + // * At least one whitespace character + // * The name / key of the const directive (alphanumeric & underscore characters) + // * Zero or more whitespace characters + // * An equals sign + // * Zero or more whitespace characters + // * The value of the const directive (alphanumeric & underscore characters) + // * A semicolon + // * (any content) + + // Bail-out early without doing any processing if required components are not found + // A const directive must contain at the very least a const keyword, then an equals + // sign, then a semicolon. + if (!line.contains("const") || !line.contains("=") || !line.contains(";")) { + return Optional.empty(); + } + + // Trim any surrounding whitespace (such as indentation) from the line before processing it. + line = line.trim(); + + // A valid declaration must have a trimmed line starting with const + if (!line.startsWith("const")) { + return Optional.empty(); + } + + // Remove the const part from the string + line = line.substring("const".length()); + + // There must be at least one whitespace character between the "const" keyword and the type keyword + if (!startsWithWhitespace(line)) { + return Optional.empty(); + } + + // Trim all whitespace between the const keyword and the type keyword + line = line.trim(); + + // Valid const declarations have a type that is either an int, a float, a vec4, or a bool. + Type type; + + if (line.startsWith("int")) { + type = Type.INT; + line = line.substring("int".length()); + } else if (line.startsWith("float")) { + type = Type.FLOAT; + line = line.substring("float".length()); + } else if (line.startsWith("vec2")) { + type = Type.VEC2; + line = line.substring("vec2".length()); + } else if (line.startsWith("ivec3")) { + type = Type.IVEC3; + line = line.substring("ivec3".length()); + } else if (line.startsWith("vec4")) { + type = Type.VEC4; + line = line.substring("vec4".length()); + } else if (line.startsWith("bool")) { + type = Type.BOOL; + line = line.substring("bool".length()); + } else { + return Optional.empty(); + } + + // There must be at least one whitespace character between the type keyword and the key of the const declaration + if (!startsWithWhitespace(line)) { + return Optional.empty(); + } + + // Split the declaration at the equals sign + int equalsIndex = line.indexOf('='); + + if (equalsIndex == -1) { + // No equals sign found, not a valid const declaration + return Optional.empty(); + } + + // The key comes before the equals sign + String key = line.substring(0, equalsIndex).trim(); + + // The key must be a "word" (alphanumeric & underscore characters) + if (!isWord(key)) { + return Optional.empty(); + } + + // Everything after the equals sign but before the semicolon is the value + String remaining = line.substring(equalsIndex + 1); + + int semicolonIndex = remaining.indexOf(';'); + + if (semicolonIndex == -1) { + // No semicolon found, not a valid const declaration + return Optional.empty(); + } + + String value = remaining.substring(0, semicolonIndex).trim(); + + // We make no attempt to properly parse / verify the value here, that responsibility lies with whatever code + // is working with the directives. + return Optional.of(new ConstDirective(type, key, value)); + } + + private static boolean startsWithWhitespace(String text) { + return !text.isEmpty() && Character.isWhitespace(text.charAt(0)); + } + + private static boolean isWord(String text) { + if (text.isEmpty()) { + return false; + } + + for (char character : text.toCharArray()) { + if (!Character.isDigit(character) && !Character.isAlphabetic(character) && character != '_') { + return false; + } + } + + return true; + } + + public static class ConstDirective { + private final Type type; + private final String key; + private final String value; + + ConstDirective(Type type, String key, String value) { + this.type = type; + this.key = key; + this.value = value; + } + + public Type getType() { + return type; + } + + public String getKey() { + return key; + } + + public String getValue() { + return value; + } + + public String toString() { + return "ConstDirective { " + type + " " + key + " = " + value + "; }"; + } + } + + public enum Type { + INT, + FLOAT, + VEC2, + IVEC3, + VEC4, + BOOL + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/DimensionId.java b/src/main/java/net/coderbot/iris/shaderpack/DimensionId.java new file mode 100644 index 000000000..8254ca810 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/DimensionId.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.shaderpack; + +public enum DimensionId { + OVERWORLD, + NETHER, + END +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/DirectiveHolder.java b/src/main/java/net/coderbot/iris/shaderpack/DirectiveHolder.java new file mode 100644 index 000000000..f821d8df1 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/DirectiveHolder.java @@ -0,0 +1,24 @@ +package net.coderbot.iris.shaderpack; + +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import it.unimi.dsi.fastutil.floats.FloatConsumer; +import org.joml.Vector2f; +import org.joml.Vector3i; +import org.joml.Vector4f; + +import java.util.function.Consumer; +import java.util.function.IntConsumer; + +public interface DirectiveHolder { + void acceptUniformDirective(String name, Runnable onDetected); + void acceptCommentStringDirective(String name, Consumer consumer); + void acceptCommentIntDirective(String name, IntConsumer consumer); + void acceptCommentFloatDirective(String name, FloatConsumer consumer); + void acceptConstBooleanDirective(String name, BooleanConsumer consumer); + void acceptConstStringDirective(String name, Consumer consumer); + void acceptConstIntDirective(String name, IntConsumer consumer); + void acceptConstFloatDirective(String name, FloatConsumer consumer); + void acceptConstVec2Directive(String name, Consumer consumer); + void acceptConstIVec3Directive(String name, Consumer consumer); + void acceptConstVec4Directive(String name, Consumer consumer); +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/DispatchingDirectiveHolder.java b/src/main/java/net/coderbot/iris/shaderpack/DispatchingDirectiveHolder.java new file mode 100644 index 000000000..2101306d9 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/DispatchingDirectiveHolder.java @@ -0,0 +1,323 @@ +package net.coderbot.iris.shaderpack; + +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import it.unimi.dsi.fastutil.floats.FloatConsumer; +import net.coderbot.iris.Iris; +import net.coderbot.iris.IrisLogging; +import org.joml.Vector2f; +import org.joml.Vector3i; +import org.joml.Vector4f; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.IntConsumer; + +public class DispatchingDirectiveHolder implements DirectiveHolder { + private final Map booleanConstVariables; + private final Map> stringConstVariables; + private final Map intConstVariables; + private final Map floatConstVariables; + private final Map> vec2ConstVariables; + private final Map> ivec3ConstVariables; + private final Map> vec4ConstVariables; + + public DispatchingDirectiveHolder() { + booleanConstVariables = new HashMap<>(); + stringConstVariables = new HashMap<>(); + intConstVariables = new HashMap<>(); + floatConstVariables = new HashMap<>(); + vec2ConstVariables = new HashMap<>(); + ivec3ConstVariables = new HashMap<>(); + vec4ConstVariables = new HashMap<>(); + } + + public void processDirective(ConstDirectiveParser.ConstDirective directive) { + final ConstDirectiveParser.Type type = directive.getType(); + final String key = directive.getKey(); + final String value = directive.getValue(); + + if (type == ConstDirectiveParser.Type.BOOL) { + BooleanConsumer consumer = booleanConstVariables.get(key); + + if (consumer != null) { + if ("true".equals(value)) { + consumer.accept(true); + } else if ("false".equals(value)) { + consumer.accept(false); + } else { + Iris.logger.error("Failed to process " + directive + ": " + value + " is not a valid boolean value"); + } + + return; + } + + if (IrisLogging.ENABLE_SPAM) { + // Only logspam in dev + Iris.logger.info("Found potential unhandled directive: " + directive); + } + + typeCheckHelper("int", intConstVariables, directive); + typeCheckHelper("int", stringConstVariables, directive); + typeCheckHelper("float", floatConstVariables, directive); + typeCheckHelper("vec4", vec4ConstVariables, directive); + } else if (type == ConstDirectiveParser.Type.INT) { + // GLSL does not actually have a string type, so string constant directives use "const int" instead. + Consumer stringConsumer = stringConstVariables.get(key); + + if (stringConsumer != null) { + stringConsumer.accept(value); + + return; + } + + IntConsumer intConsumer = intConstVariables.get(key); + + if (intConsumer != null) { + try { + intConsumer.accept(Integer.parseInt(value)); + } catch (NumberFormatException e) { + Iris.logger.error("Failed to process " + directive, e); + } + + return; + } + + if (IrisLogging.ENABLE_SPAM) { + // Only logspam in dev + Iris.logger.info("Found potential unhandled directive: " + directive); + } + + typeCheckHelper("bool", booleanConstVariables, directive); + typeCheckHelper("float", floatConstVariables, directive); + typeCheckHelper("vec4", vec4ConstVariables, directive); + } else if (type == ConstDirectiveParser.Type.FLOAT) { + FloatConsumer consumer = floatConstVariables.get(key); + + if (consumer != null) { + try { + consumer.accept(Float.parseFloat(value)); + } catch (NumberFormatException e) { + Iris.logger.error("Failed to process " + directive, e); + } + + return; + } + + if (IrisLogging.ENABLE_SPAM) { + // Only logspam in dev + Iris.logger.info("Found potential unhandled directive: " + directive); + } + + typeCheckHelper("bool", booleanConstVariables, directive); + typeCheckHelper("int", intConstVariables, directive); + typeCheckHelper("int", stringConstVariables, directive); + typeCheckHelper("vec4", vec4ConstVariables, directive); + } else if (type == ConstDirectiveParser.Type.VEC2) { + Consumer consumer = vec2ConstVariables.get(key); + + if (consumer != null) { + if (!value.startsWith("vec2")) { + Iris.logger.error("Failed to process " + directive + ": value was not a valid vec2 constructor"); + } + + String vec2Args = value.substring("vec2".length()).trim(); + + if (!vec2Args.startsWith("(") || !vec2Args.endsWith(")")) { + Iris.logger.error("Failed to process " + directive + ": value was not a valid vec2 constructor"); + } + + vec2Args = vec2Args.substring(1, vec2Args.length() - 1); + + String[] parts = vec2Args.split(","); + + for (int i = 0; i < parts.length; i++) { + parts[i] = parts[i].trim(); + } + + if (parts.length != 2) { + Iris.logger.error("Failed to process " + directive + + ": expected 2 arguments to a vec2 constructor, got " + parts.length); + } + + try { + consumer.accept(new Vector2f( + Float.parseFloat(parts[0]), + Float.parseFloat(parts[1]) + )); + } catch (NumberFormatException e) { + Iris.logger.error("Failed to process " + directive, e); + } + + return; + } + + typeCheckHelper("bool", booleanConstVariables, directive); + typeCheckHelper("int", intConstVariables, directive); + typeCheckHelper("int", stringConstVariables, directive); + typeCheckHelper("float", floatConstVariables, directive); + } else if (type == ConstDirectiveParser.Type.IVEC3) { + Consumer consumer = ivec3ConstVariables.get(key); + + if (consumer != null) { + if (!value.startsWith("ivec3")) { + Iris.logger.error("Failed to process " + directive + ": value was not a valid ivec3 constructor"); + } + + String ivec3Args = value.substring("ivec3".length()).trim(); + + if (!ivec3Args.startsWith("(") || !ivec3Args.endsWith(")")) { + Iris.logger.error("Failed to process " + directive + ": value was not a valid ivec3 constructor"); + } + + ivec3Args = ivec3Args.substring(1, ivec3Args.length() - 1); + + String[] parts = ivec3Args.split(","); + + for (int i = 0; i < parts.length; i++) { + parts[i] = parts[i].trim(); + } + + if (parts.length != 3) { + Iris.logger.error("Failed to process " + directive + + ": expected 3 arguments to a ivec3 constructor, got " + parts.length); + } + + try { + consumer.accept(new Vector3i( + Integer.parseInt(parts[0]), + Integer.parseInt(parts[1]), + Integer.parseInt(parts[2]) + )); + } catch (NumberFormatException e) { + Iris.logger.error("Failed to process " + directive, e); + } + + return; + } + + typeCheckHelper("bool", booleanConstVariables, directive); + typeCheckHelper("int", intConstVariables, directive); + typeCheckHelper("int", stringConstVariables, directive); + typeCheckHelper("float", floatConstVariables, directive); + } else if (type == ConstDirectiveParser.Type.VEC4) { + Consumer consumer = vec4ConstVariables.get(key); + + if (consumer != null) { + if (!value.startsWith("vec4")) { + Iris.logger.error("Failed to process " + directive + ": value was not a valid vec4 constructor"); + } + + String vec4Args = value.substring("vec4".length()).trim(); + + if (!vec4Args.startsWith("(") || !vec4Args.endsWith(")")) { + Iris.logger.error("Failed to process " + directive + ": value was not a valid vec4 constructor"); + } + + vec4Args = vec4Args.substring(1, vec4Args.length() - 1); + + String[] parts = vec4Args.split(","); + + for (int i = 0; i < parts.length; i++) { + parts[i] = parts[i].trim(); + } + + if (parts.length != 4) { + Iris.logger.error("Failed to process " + directive + + ": expected 4 arguments to a vec4 constructor, got " + parts.length); + } + + try { + consumer.accept(new Vector4f( + Float.parseFloat(parts[0]), + Float.parseFloat(parts[1]), + Float.parseFloat(parts[2]), + Float.parseFloat(parts[3]) + )); + } catch (NumberFormatException e) { + Iris.logger.error("Failed to process " + directive, e); + } + + return; + } + + typeCheckHelper("bool", booleanConstVariables, directive); + typeCheckHelper("int", intConstVariables, directive); + typeCheckHelper("int", stringConstVariables, directive); + typeCheckHelper("float", floatConstVariables, directive); + } + } + + private void typeCheckHelper(String expected, Map candidates, ConstDirectiveParser.ConstDirective directive) { + if (candidates.containsKey(directive.getKey())) { + Iris.logger.warn("Ignoring " + directive + " because it is of the wrong type, a type of " + expected + " is expected."); + } + } + + @Override + public void acceptUniformDirective(String name, Runnable onDetected) { + // TODO + if (IrisLogging.ENABLE_SPAM) { + Iris.logger.warn("Not looking for a uniform directive with the name " + name + " since this type of directive is not currently supported."); + } + } + + @Override + public void acceptCommentStringDirective(String name, Consumer consumer) { + // TODO + if (IrisLogging.ENABLE_SPAM) { + Iris.logger.warn("Not looking for a comment string directive with the name " + name + " since this type of directive is not currently supported."); + } + } + + @Override + public void acceptCommentIntDirective(String name, IntConsumer consumer) { + // TODO + if (IrisLogging.ENABLE_SPAM) { + Iris.logger.warn("Not looking for a comment int directive with the name " + name + " since this type of directive is not currently supported."); + } + } + + @Override + public void acceptCommentFloatDirective(String name, FloatConsumer consumer) { + // TODO + if (IrisLogging.ENABLE_SPAM) { + Iris.logger.warn("Not looking for a comment float directive with the name " + name + " since this type of directive is not currently supported."); + } + } + + @Override + public void acceptConstBooleanDirective(String name, BooleanConsumer consumer) { + booleanConstVariables.put(name, consumer); + } + + @Override + public void acceptConstStringDirective(String name, Consumer consumer) { + stringConstVariables.put(name, consumer); + } + + @Override + public void acceptConstIntDirective(String name, IntConsumer consumer) { + intConstVariables.put(name, consumer); + } + + @Override + public void acceptConstFloatDirective(String name, FloatConsumer consumer) { + floatConstVariables.put(name, consumer); + } + + @Override + public void acceptConstVec2Directive(String name, Consumer consumer) { + vec2ConstVariables.put(name, consumer); + } + + @Override + public void acceptConstIVec3Directive(String name, Consumer consumer) { + ivec3ConstVariables.put(name, consumer); + } + + @Override + public void acceptConstVec4Directive(String name, Consumer consumer) { + vec4ConstVariables.put(name, consumer); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/IdMap.java b/src/main/java/net/coderbot/iris/shaderpack/IdMap.java new file mode 100644 index 000000000..836c0aba1 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/IdMap.java @@ -0,0 +1,294 @@ +package net.coderbot.iris.shaderpack; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntFunction; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMaps; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.materialmap.BlockEntry; +import net.coderbot.iris.shaderpack.materialmap.BlockRenderType; +import net.coderbot.iris.shaderpack.materialmap.NamespacedId; +import net.coderbot.iris.shaderpack.option.ShaderPackOptions; +import net.coderbot.iris.shaderpack.preprocessor.PropertiesPreprocessor; + +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Properties; + +/** + * A utility class for parsing entries in item.properties, block.properties, and entities.properties files in shaderpacks + */ +public class IdMap { + /** + * Maps a given item ID to an integer ID + */ + private final Object2IntMap itemIdMap; + + /** + * Maps a given entity ID to an integer ID + */ + private final Object2IntMap entityIdMap; + + /** + * Maps block states to block ids defined in block.properties + */ + private Int2ObjectMap> blockPropertiesMap; + + /** + * A set of render type overrides for specific blocks. Allows shader packs to move blocks to different render types. + */ + private Map blockRenderTypeMap; + + IdMap(Path shaderPath, ShaderPackOptions shaderPackOptions, Iterable environmentDefines) { + itemIdMap = loadProperties(shaderPath, "item.properties", shaderPackOptions, environmentDefines) + .map(IdMap::parseItemIdMap).orElse(Object2IntMaps.emptyMap()); + + entityIdMap = loadProperties(shaderPath, "entity.properties", shaderPackOptions, environmentDefines) + .map(IdMap::parseEntityIdMap).orElse(Object2IntMaps.emptyMap()); + + loadProperties(shaderPath, "block.properties", shaderPackOptions, environmentDefines).ifPresent(blockProperties -> { + blockPropertiesMap = parseBlockMap(blockProperties, "block.", "block.properties"); + blockRenderTypeMap = parseRenderTypeMap(blockProperties, "layer.", "block.properties"); + }); + + // TODO: Properly override block render layers + + if (blockPropertiesMap == null) { + // Fill in with default values... + blockPropertiesMap = new Int2ObjectOpenHashMap<>(); + LegacyIdMap.addLegacyValues(blockPropertiesMap); + } + + if (blockRenderTypeMap == null) { + blockRenderTypeMap = Collections.emptyMap(); + } + } + + /** + * Loads properties from a properties file in a shaderpack path + */ + private static Optional loadProperties(Path shaderPath, String name, ShaderPackOptions shaderPackOptions, + Iterable environmentDefines) { + String fileContents = readProperties(shaderPath, name); + if (fileContents == null) { + return Optional.empty(); + } + + String processed = PropertiesPreprocessor.preprocessSource(fileContents, shaderPackOptions, environmentDefines); + + StringReader propertiesReader = new StringReader(processed); + + // Note: ordering of properties is significant + // See https://github.com/IrisShaders/Iris/issues/1327 and the relevant putIfAbsent calls in + // BlockMaterialMapping + Properties properties = new OrderBackedProperties(); + try { + properties.load(propertiesReader); + } catch (IOException e) { + Iris.logger.error("Error loading " + name + " at " + shaderPath, e); + + return Optional.empty(); + } + + return Optional.of(properties); + } + + private static String readProperties(Path shaderPath, String name) { + try { + // ID maps should be encoded in ISO_8859_1. + return new String(Files.readAllBytes(shaderPath.resolve(name)), StandardCharsets.ISO_8859_1); + } catch (NoSuchFileException e) { + Iris.logger.debug("An " + name + " file was not found in the current shaderpack"); + + return null; + } catch (IOException e) { + Iris.logger.error("An IOException occurred reading " + name + " from the current shaderpack", e); + + return null; + } + } + + private static Object2IntMap parseItemIdMap(Properties properties) { + return parseIdMap(properties, "item.", "item.properties"); + } + + private static Object2IntMap parseEntityIdMap(Properties properties) { + return parseIdMap(properties, "entity.", "entity.properties"); + } + + /** + * Parses a NamespacedId map in OptiFine format + */ + private static Object2IntMap parseIdMap(Properties properties, String keyPrefix, String fileName) { + Object2IntMap idMap = new Object2IntOpenHashMap<>(); + idMap.defaultReturnValue(-1); + + properties.forEach((keyObject, valueObject) -> { + String key = (String) keyObject; + String value = (String) valueObject; + + if (!key.startsWith(keyPrefix)) { + // Not a valid line, ignore it + return; + } + + int intId; + + try { + intId = Integer.parseInt(key.substring(keyPrefix.length())); + } catch (NumberFormatException e) { + // Not a valid property line + Iris.logger.warn("Failed to parse line in " + fileName + ": invalid key " + key); + return; + } + + // Split on any whitespace + for (String part : value.split("\\s+")) { + if (part.contains("=")) { + // Avoid tons of logspam for now + Iris.logger.warn("Failed to parse an ResourceLocation in " + fileName + " for the key " + key + ": state properties are currently not supported: " + part); + continue; + } + + // Note: NamespacedId performs no validation on the content. That will need to be done by whatever is + // converting these things to ResourceLocations. + idMap.put(new NamespacedId(part), intId); + } + }); + + return Object2IntMaps.unmodifiable(idMap); + } + + private static Int2ObjectMap> parseBlockMap(Properties properties, String keyPrefix, String fileName) { + Int2ObjectMap> entriesById = new Int2ObjectOpenHashMap<>(); + + properties.forEach((keyObject, valueObject) -> { + String key = (String) keyObject; + String value = (String) valueObject; + + if (!key.startsWith(keyPrefix)) { + // Not a valid line, ignore it + return; + } + + int intId; + + try { + intId = Integer.parseInt(key.substring(keyPrefix.length())); + } catch (NumberFormatException e) { + // Not a valid property line + Iris.logger.warn("Failed to parse line in " + fileName + ": invalid key " + key); + return; + } + + List entries = new ArrayList<>(); + + // Split on whitespace groups, not just single spaces + for (String part : value.split("\\s+")) { + if (part.isEmpty()) { + continue; + } + + try { + entries.add(BlockEntry.parse(part)); + } catch (Exception e) { + Iris.logger.warn("Unexpected error while parsing an entry from " + fileName + " for the key " + key + ":", e); + } + } + + entriesById.put(intId, Collections.unmodifiableList(entries)); + }); + + return Int2ObjectMaps.unmodifiable(entriesById); + } + + /** + * Parses a render layer map. + * + * This feature is used by Chocapic v9 and Wisdom Shaders. Otherwise, it is a rarely-used feature. + */ + private static Map parseRenderTypeMap(Properties properties, String keyPrefix, String fileName) { + Map overrides = new HashMap<>(); + + properties.forEach((keyObject, valueObject) -> { + String key = (String) keyObject; + String value = (String) valueObject; + + if (!key.startsWith(keyPrefix)) { + // Not a valid line, ignore it + return; + } + + // Note: We have to remove the prefix "layer." because fromString expects "cutout", not "layer.cutout". + String keyWithoutPrefix = key.substring(keyPrefix.length()); + + BlockRenderType renderType = BlockRenderType.fromString(keyWithoutPrefix).orElse(null); + + if (renderType == null) { + Iris.logger.warn("Failed to parse line in " + fileName + ": invalid block render type: " + key); + return; + } + + for (String part : value.split("\\s+")) { + // Note: NamespacedId performs no validation on the content. That will need to be done by whatever is + // converting these things to ResourceLocations. + overrides.put(new NamespacedId(part), renderType); + } + }); + + return overrides; + } + + public Int2ObjectMap> getBlockProperties() { + return blockPropertiesMap; + } + + public Object2IntFunction getItemIdMap() { + return itemIdMap; + } + + public Object2IntFunction getEntityIdMap() { + return entityIdMap; + } + + public Map getBlockRenderTypeMap() { + return blockRenderTypeMap; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + IdMap idMap = (IdMap) o; + + return Objects.equals(itemIdMap, idMap.itemIdMap) + && Objects.equals(entityIdMap, idMap.entityIdMap) + && Objects.equals(blockPropertiesMap, idMap.blockPropertiesMap) + && Objects.equals(blockRenderTypeMap, idMap.blockRenderTypeMap); + } + + @Override + public int hashCode() { + return Objects.hash(itemIdMap, entityIdMap, blockPropertiesMap, blockRenderTypeMap); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/IrisLimits.java b/src/main/java/net/coderbot/iris/shaderpack/IrisLimits.java new file mode 100644 index 000000000..b97143a94 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/IrisLimits.java @@ -0,0 +1,12 @@ +package net.coderbot.iris.shaderpack; + +public class IrisLimits { + /** + * The maximum number of color textures that a shader pack can write to and read from in gbuffer and composite + * programs. + * + * It's not recommended to raise this higher than 16 until code for avoiding allocation of unused color textures + * is implemented. + */ + public static final int MAX_COLOR_BUFFERS = 16; +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/LanguageMap.java b/src/main/java/net/coderbot/iris/shaderpack/LanguageMap.java new file mode 100644 index 000000000..09797e6b0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/LanguageMap.java @@ -0,0 +1,75 @@ +package net.coderbot.iris.shaderpack; + +import com.google.common.collect.ImmutableMap; +import net.coderbot.iris.Iris; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Stream; + +public class LanguageMap { + private final Map> translationMaps; + + public LanguageMap(Path root) throws IOException { + this.translationMaps = new HashMap<>(); + + if (!Files.exists(root)) { + return; + } + + // We are using a max depth of one to ensure we only get the surface level *files* without going deeper + // we also want to avoid any directories while filtering + // Basically, we want the immediate files nested in the path for the langFolder + // There is also Files.list which can be used for similar behavior + try (Stream stream = Files.list(root)) { + stream.filter(path -> !Files.isDirectory(path)).forEach(path -> { + // Shader packs use legacy file name coding which is different than modern minecraft's. + // An example of this is using "en_US.lang" compared to "en_us.json" + // Also note that OptiFine uses a property scheme for loading language entries to keep parity with other + // OptiFine features + String currentFileName = path.getFileName().toString().toLowerCase(Locale.ROOT); + + if (!currentFileName.endsWith(".lang")) { + // This file lacks a .lang file extension and should be ignored. + return; + } + + String currentLangCode = currentFileName.substring(0, currentFileName.lastIndexOf(".")); + Properties properties = new Properties(); + + // Use InputStreamReader to avoid the default charset of ISO-8859-1. + // This is needed since shader language files are specified to be in UTF-8. + try (InputStreamReader isr = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) { + properties.load(isr); + } catch (IOException e) { + Iris.logger.error("Failed to parse shader pack language file " + path, e); + } + + ImmutableMap.Builder builder = ImmutableMap.builder(); + + properties.forEach((key, value) -> builder.put(key.toString(), value.toString())); + + translationMaps.put(currentLangCode, builder.build()); + }); + } + } + + public Set getLanguages() { + // Ensure that the caller can't mess with the language map. + return Collections.unmodifiableSet(translationMaps.keySet()); + } + + public Map getTranslations(String language) { + // We're returning an immutable map, so the caller can't modify it. + return translationMaps.get(language); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/LegacyIdMap.java b/src/main/java/net/coderbot/iris/shaderpack/LegacyIdMap.java new file mode 100644 index 000000000..73a7d5e4b --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/LegacyIdMap.java @@ -0,0 +1,98 @@ +package net.coderbot.iris.shaderpack; + +import com.google.common.collect.ImmutableList; +import it.unimi.dsi.fastutil.Function; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import net.coderbot.iris.shaderpack.materialmap.BlockEntry; +import net.coderbot.iris.shaderpack.materialmap.NamespacedId; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class LegacyIdMap { + private static final ImmutableList COLORS = + ImmutableList.of("white", "orange", "magenta", "light_blue", "yellow", "lime", "pink", "gray", + "light_gray", "cyan", "purple", "blue", "brown", "green", "red", "black"); + + private static final ImmutableList WOOD_TYPES = + ImmutableList.of("oak", "birch", "jungle", "spruce", "acacia", "dark_oak"); + + public static void addLegacyValues(Int2ObjectMap> blockIdMap) { + add(blockIdMap, 1, block("stone"), block("granite"), block("diorite"), block("andesite")); + add(blockIdMap, 2, block("grass_block")); + add(blockIdMap, 4, block("cobblestone")); + + add(blockIdMap, 50, block("torch")); + add(blockIdMap, 89, block("glowstone")); + + // TODO: what about inactive redstone lamps? + add(blockIdMap, 124, block("redstone_lamp")); + + add(blockIdMap, 12, block("sand")); + add(blockIdMap, 24, block("sandstone")); + + add(blockIdMap, 41, block("gold_block")); + add(blockIdMap, 42, block("iron_block")); + add(blockIdMap, 57, block("diamond_block")); + // Apparently this is what SEUS v11 expects? Maybe old shadersmod was buggy. + add(blockIdMap, -123, block("emerald_block")); + + addMany(blockIdMap, 35, COLORS, color -> block(color + "_wool")); + + // NB: Use the "still" IDs for water and lava, since some shader packs don't properly support the "flowing" + // versions: https://github.com/IrisShaders/Iris/issues/1462 + add(blockIdMap, 9, block("water")); + add(blockIdMap, 11, block("lava")); + add(blockIdMap, 79, block("ice")); + + addMany(blockIdMap, 18, WOOD_TYPES, woodType -> block(woodType + "_leaves")); + + addMany(blockIdMap, 95, COLORS, color -> block(color + "_stained_glass")); + addMany(blockIdMap, 160, COLORS, color -> block(color + "_stained_glass_pane")); + + // Short grass / bush + add(blockIdMap, 31, block("grass"), block("seagrass"), block("sweet_berry_bush")); + + // Crops (59 = wheat), but we include carrots and potatoes too. + add(blockIdMap, 59, block("wheat"), block("carrots"), block("potatoes")); + + // Small flowers + add(blockIdMap, 37, block("dandelion"), block("poppy"), block("blue_orchid"), + block("allium"), block("azure_bluet"), block("red_tulip"), block("pink_tulip"), + block("white_tulip"), block("orange_tulip"), block("oxeye_daisy"), + block("cornflower"), block("lily_of_the_valley"), block("wither_rose")); + + // Big tall grass / flowers + // Also include seagrass here + add(blockIdMap, 175, block("sunflower"), block("lilac"), block("tall_grass"), + block("large_fern"), block("rose_bush"), block("peony"), block("tall_seagrass")); + + // Fire + add(blockIdMap, 51, block("fire")); + + // Lily pad + add(blockIdMap, 111, block("lily_pad")); + + // TODO: 76 -> redstone_torch (on) + } + + private static BlockEntry block(String name) { + return new BlockEntry(new NamespacedId("minecraft", name), Collections.emptyMap()); + } + + private static void addMany(Int2ObjectMap> blockIdMap, int id, List prefixes, Function toId) { + List entries = new ArrayList<>(); + + for (String prefix : prefixes) { + entries.add(toId.apply(prefix)); + } + + blockIdMap.put(id, entries); + } + + private static void add(Int2ObjectMap> blockIdMap, int id, BlockEntry... entries) { + blockIdMap.put(id, Arrays.asList(entries)); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/OptionalBoolean.java b/src/main/java/net/coderbot/iris/shaderpack/OptionalBoolean.java new file mode 100644 index 000000000..390eac4ec --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/OptionalBoolean.java @@ -0,0 +1,25 @@ +package net.coderbot.iris.shaderpack; + +import java.util.function.BooleanSupplier; + +public enum OptionalBoolean { + DEFAULT, + FALSE, + TRUE; + + public boolean orElse(boolean defaultValue) { + if (this == DEFAULT) { + return defaultValue; + } + + return this == TRUE; + } + + public boolean orElseGet(BooleanSupplier defaultValue) { + if (this == DEFAULT) { + return defaultValue.getAsBoolean(); + } + + return this == TRUE; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/OrderBackedProperties.java b/src/main/java/net/coderbot/iris/shaderpack/OrderBackedProperties.java new file mode 100644 index 000000000..5c391db42 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/OrderBackedProperties.java @@ -0,0 +1,27 @@ +package net.coderbot.iris.shaderpack; + +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; + +import java.util.Map; +import java.util.Properties; +import java.util.function.BiConsumer; + +/** + * Properties backed by a {@link java.util.LinkedHashMap}, in order to preserve iteration order + */ +public class OrderBackedProperties extends Properties { + private transient final Map backing = Object2ObjectMaps.synchronize(new Object2ObjectLinkedOpenHashMap<>()); + + @Override + public synchronized Object put(Object key, Object value) { + backing.put(key, value); + + return super.put(key, value); + } + + @Override + public synchronized void forEach(BiConsumer action) { + this.backing.forEach(action); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java b/src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java new file mode 100644 index 000000000..c62b817af --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java @@ -0,0 +1,254 @@ +package net.coderbot.iris.shaderpack; + +import com.google.common.collect.ImmutableMap; +import it.unimi.dsi.fastutil.objects.Object2BooleanMap; +import it.unimi.dsi.fastutil.objects.Object2BooleanMaps; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.texture.TextureScaleOverride; +import org.joml.Vector2i; + +import java.util.Set; + +public class PackDirectives { + private int noiseTextureResolution; + private float sunPathRotation; + private float ambientOcclusionLevel; + private float wetnessHalfLife; + private float drynessHalfLife; + private float eyeBrightnessHalfLife; + private float centerDepthHalfLife; + private CloudSetting cloudSetting; + private boolean underwaterOverlay; + private boolean vignette; + private boolean sun; + private boolean moon; + private boolean rainDepth; + private boolean separateAo; + private boolean oldLighting; + private boolean concurrentCompute; + private boolean oldHandLight; + private boolean particlesBeforeDeferred; + private boolean prepareBeforeShadow; + private Object2ObjectMap> explicitFlips = new Object2ObjectOpenHashMap<>(); + private Object2ObjectMap scaleOverrides = new Object2ObjectOpenHashMap<>(); + + private final PackRenderTargetDirectives renderTargetDirectives; + private final PackShadowDirectives shadowDirectives; + + private PackDirectives(Set supportedRenderTargets, PackShadowDirectives packShadowDirectives) { + noiseTextureResolution = 256; + sunPathRotation = 0.0F; + ambientOcclusionLevel = 1.0F; + wetnessHalfLife = 600.0f; + drynessHalfLife = 200.0f; + eyeBrightnessHalfLife = 10.0f; + centerDepthHalfLife = 1.0F; + renderTargetDirectives = new PackRenderTargetDirectives(supportedRenderTargets); + shadowDirectives = packShadowDirectives; + } + + PackDirectives(Set supportedRenderTargets, ShaderProperties properties) { + this(supportedRenderTargets, new PackShadowDirectives(properties)); + cloudSetting = properties.getCloudSetting(); + underwaterOverlay = properties.getUnderwaterOverlay().orElse(false); + vignette = properties.getVignette().orElse(false); + sun = properties.getSun().orElse(true); + moon = properties.getMoon().orElse(true); + rainDepth = properties.getRainDepth().orElse(false); + separateAo = properties.getSeparateAo().orElse(false); + oldLighting = properties.getOldLighting().orElse(false); + concurrentCompute = properties.getConcurrentCompute().orElse(false); + oldHandLight = properties.getOldHandLight().orElse(true); + explicitFlips = properties.getExplicitFlips(); + scaleOverrides = properties.getTextureScaleOverrides(); + particlesBeforeDeferred = properties.getParticlesBeforeDeferred().orElse(false); + prepareBeforeShadow = properties.getPrepareBeforeShadow().orElse(false); + } + + PackDirectives(Set supportedRenderTargets, PackDirectives directives) { + this(supportedRenderTargets, new PackShadowDirectives(directives.getShadowDirectives())); + cloudSetting = directives.cloudSetting; + separateAo = directives.separateAo; + oldLighting = directives.oldLighting; + concurrentCompute = directives.concurrentCompute; + explicitFlips = directives.explicitFlips; + scaleOverrides = directives.scaleOverrides; + particlesBeforeDeferred = directives.particlesBeforeDeferred; + prepareBeforeShadow = directives.prepareBeforeShadow; + } + + public int getNoiseTextureResolution() { + return noiseTextureResolution; + } + + public float getSunPathRotation() { + return sunPathRotation; + } + + public float getAmbientOcclusionLevel() { + return ambientOcclusionLevel; + } + + public float getWetnessHalfLife() { + return wetnessHalfLife; + } + + public float getDrynessHalfLife() { + return drynessHalfLife; + } + + public float getEyeBrightnessHalfLife() { + return eyeBrightnessHalfLife; + } + + public float getCenterDepthHalfLife() { + return centerDepthHalfLife; + } + + public CloudSetting getCloudSetting() { + return cloudSetting; + } + + public boolean underwaterOverlay() { + return underwaterOverlay; + } + + public boolean vignette() { + return vignette; + } + + public boolean shouldRenderSun() { + return sun; + } + + public boolean shouldRenderMoon() { + return moon; + } + + public boolean rainDepth() { + return rainDepth; + } + + public boolean shouldUseSeparateAo() { + return separateAo; + } + + public boolean isOldLighting() { + return oldLighting; + } + + public boolean isOldHandLight() { + return oldHandLight; + } + + public boolean areParticlesBeforeDeferred() { + return particlesBeforeDeferred; + } + + public boolean getConcurrentCompute() { + return concurrentCompute; + } + + public boolean isPrepareBeforeShadow() { + return prepareBeforeShadow; + } + + public PackRenderTargetDirectives getRenderTargetDirectives() { + return renderTargetDirectives; + } + + public PackShadowDirectives getShadowDirectives() { + return shadowDirectives; + } + + private static float clamp(float val, float lo, float hi) { + return Math.max(lo, Math.min(hi, val)); + } + + public void acceptDirectivesFrom(DirectiveHolder directives) { + renderTargetDirectives.acceptDirectives(directives); + shadowDirectives.acceptDirectives(directives); + + directives.acceptConstIntDirective("noiseTextureResolution", + noiseTextureResolution -> this.noiseTextureResolution = noiseTextureResolution); + + directives.acceptConstFloatDirective("sunPathRotation", + sunPathRotation -> this.sunPathRotation = sunPathRotation); + + directives.acceptConstFloatDirective("ambientOcclusionLevel", + ambientOcclusionLevel -> this.ambientOcclusionLevel = clamp(ambientOcclusionLevel, 0.0f, 1.0f)); + + directives.acceptConstFloatDirective("wetnessHalflife", + wetnessHalfLife -> this.wetnessHalfLife = wetnessHalfLife); + + directives.acceptConstFloatDirective("drynessHalflife", + wetnessHalfLife -> this.wetnessHalfLife = wetnessHalfLife); + + directives.acceptConstFloatDirective("eyeBrightnessHalflife", + eyeBrightnessHalfLife -> this.eyeBrightnessHalfLife = eyeBrightnessHalfLife); + + directives.acceptConstFloatDirective("centerDepthHalflife", + centerDepthHalfLife -> this.centerDepthHalfLife = centerDepthHalfLife); + } + + public ImmutableMap getExplicitFlips(String pass) { + ImmutableMap.Builder explicitFlips = ImmutableMap.builder(); + + Object2BooleanMap explicitFlipsStr = this.explicitFlips.get(pass); + + if (explicitFlipsStr == null) { + explicitFlipsStr = Object2BooleanMaps.emptyMap(); + } + + explicitFlipsStr.forEach((buffer, shouldFlip) -> { + int index = PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.indexOf(buffer); + + if (index == -1 && buffer.startsWith("colortex")) { + String id = buffer.substring("colortex".length()); + + try { + index = Integer.parseInt(id); + } catch (NumberFormatException e) { + // fall through to index == null check for unknown buffer. + } + } + + if (index != -1) { + explicitFlips.put(index, shouldFlip); + } else { + Iris.logger.warn("Unknown buffer with ID " + buffer + " specified in flip directive for pass " + + pass); + } + }); + + return explicitFlips.build(); + } + + public Vector2i getTextureScaleOverride(int index, int dimensionX, int dimensionY) { + final String name = "colortex" + index; + + // TODO: How do custom textures interact with aliases? + + Vector2i scale = new Vector2i(); + + if (index < PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.size()) { + String legacyName = PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.get(index); + + if (scaleOverrides.containsKey(legacyName)) { + scale.set(scaleOverrides.get(legacyName).getX(dimensionX), scaleOverrides.get(legacyName).getY(dimensionY)); + } else if (scaleOverrides.containsKey(name)) { + scale.set(scaleOverrides.get(name).getX(dimensionX), scaleOverrides.get(name).getY(dimensionY)); + } else { + scale.set(dimensionX, dimensionY); + } + } else if (scaleOverrides.containsKey(name)) { + scale.set(scaleOverrides.get(name).getX(dimensionX), scaleOverrides.get(name).getY(dimensionY)); + } else { + scale.set(dimensionX, dimensionY); + } + + return scale; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/PackRenderTargetDirectives.java b/src/main/java/net/coderbot/iris/shaderpack/PackRenderTargetDirectives.java new file mode 100644 index 000000000..3276e564e --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/PackRenderTargetDirectives.java @@ -0,0 +1,161 @@ +package net.coderbot.iris.shaderpack; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.texture.InternalTextureFormat; +import org.joml.Vector4f; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +public class PackRenderTargetDirectives { + public static final ImmutableList LEGACY_RENDER_TARGETS = ImmutableList.of( + "gcolor", + "gdepth", + "gnormal", + "composite", + "gaux1", + "gaux2", + "gaux3", + "gaux4" + ); + + // TODO: Instead of just passing this, the shader pack loader should try to figure out what color buffers are in + // use. + public static final Set BASELINE_SUPPORTED_RENDER_TARGETS; + + static { + ImmutableSet.Builder builder = ImmutableSet.builder(); + + for (int i = 0; i < IrisLimits.MAX_COLOR_BUFFERS; i++) { + builder.add(i); + } + + BASELINE_SUPPORTED_RENDER_TARGETS = builder.build(); + } + + private final Int2ObjectMap renderTargetSettings; + + PackRenderTargetDirectives(Set supportedRenderTargets) { + this.renderTargetSettings = new Int2ObjectOpenHashMap<>(); + + supportedRenderTargets.forEach( + (index) -> renderTargetSettings.put(index.intValue(), new RenderTargetSettings())); + } + + public IntList getBuffersToBeCleared() { + IntList buffersToBeCleared = new IntArrayList(); + + renderTargetSettings.forEach((index, settings) -> { + if (settings.shouldClear()) { + buffersToBeCleared.add(index.intValue()); + } + }); + + return buffersToBeCleared; + } + + public Map getRenderTargetSettings() { + return Collections.unmodifiableMap(renderTargetSettings); + } + + public void acceptDirectives(DirectiveHolder directives) { + Optional.ofNullable(renderTargetSettings.get(7)).ifPresent(colortex7 -> { + // Handle legacy GAUX4FORMAT directives + + directives.acceptCommentStringDirective("GAUX4FORMAT", format -> { + if ("RGBA32F".equals(format)) { + colortex7.requestedFormat = InternalTextureFormat.RGBA32F; + } else if ("RGB32F".equals(format)) { + colortex7.requestedFormat = InternalTextureFormat.RGB32F; + } else if ("RGB16".equals(format)) { + colortex7.requestedFormat = InternalTextureFormat.RGB16; + } else { + Iris.logger.warn("Ignoring GAUX4FORMAT directive /* GAUX4FORMAT:" + format + "*/ because " + format + + " must be RGBA32F, RGB32F, or RGB16. Use `const int colortex7Format = " + format + ";` + instead."); + } + }); + }); + + // If a shaderpack declares a gdepth uniform (even if it is not actually sampled or even of the correct type), + // we upgrade the format of gdepth / colortex1 to RGBA32F if it is currently RGBA. + Optional.ofNullable(renderTargetSettings.get(1)).ifPresent(gdepth -> { + directives.acceptUniformDirective("gdepth", () -> { + if (gdepth.requestedFormat == InternalTextureFormat.RGBA) { + gdepth.requestedFormat = InternalTextureFormat.RGBA32F; + } + }); + }); + + renderTargetSettings.forEach((index, settings) -> { + acceptBufferDirectives(directives, settings, "colortex" + index); + + if (index < LEGACY_RENDER_TARGETS.size()) { + acceptBufferDirectives(directives, settings, LEGACY_RENDER_TARGETS.get(index)); + } + }); + } + + private void acceptBufferDirectives(DirectiveHolder directives, RenderTargetSettings settings, String bufferName) { + directives.acceptConstStringDirective(bufferName + "Format", format -> { + Optional internalFormat = InternalTextureFormat.fromString(format); + + if (internalFormat.isPresent()) { + settings.requestedFormat = internalFormat.get(); + } else { + Iris.logger.warn("Unrecognized internal texture format " + format + " specified for " + bufferName + "Format, ignoring."); + } + }); + + // TODO: Only for composite and deferred + directives.acceptConstBooleanDirective(bufferName + "Clear", + shouldClear -> settings.clear = shouldClear); + + // TODO: Only for composite, deferred, and final + + // Note: This is still relevant even if shouldClear is false, + // since this will be the initial color of the buffer. + directives.acceptConstVec4Directive(bufferName + "ClearColor", + clearColor -> settings.clearColor = clearColor); + } + + public static final class RenderTargetSettings { + private InternalTextureFormat requestedFormat; + private boolean clear; + private Vector4f clearColor; + + public RenderTargetSettings() { + this.requestedFormat = InternalTextureFormat.RGBA; + this.clear = true; + this.clearColor = null; + } + + public InternalTextureFormat getInternalFormat() { + return requestedFormat; + } + + public boolean shouldClear() { + return clear; + } + + public Optional getClearColor() { + return Optional.ofNullable(clearColor); + } + + @Override + public String toString() { + return "RenderTargetSettings{" + + "requestedFormat=" + requestedFormat + + ", clear=" + clear + + ", clearColor=" + clearColor + + '}'; + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/PackShadowDirectives.java b/src/main/java/net/coderbot/iris/shaderpack/PackShadowDirectives.java new file mode 100644 index 000000000..e216c1639 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/PackShadowDirectives.java @@ -0,0 +1,450 @@ +package net.coderbot.iris.shaderpack; + +import com.google.common.collect.ImmutableList; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.texture.InternalTextureFormat; +import org.joml.Vector4f; + +import java.util.Optional; + +public class PackShadowDirectives { + // Bump this up if you want more shadow color buffers! + // This is currently set at 2 for ShadersMod / OptiFine parity but can theoretically be bumped up to 8. + // TODO: Make this configurable? + public static final int MAX_SHADOW_COLOR_BUFFERS = 2; + + private final OptionalBoolean shadowEnabled; + + private int resolution; + // Use a boxed form so we can use null to indicate that there is not an FOV specified. + private Float fov; + private float distance; + private float distanceRenderMul; + private float entityShadowDistanceMul; + private boolean explicitRenderDistance; + private float intervalSize; + + private final boolean shouldRenderTerrain; + private final boolean shouldRenderTranslucent; + private final boolean shouldRenderEntities; + private final boolean shouldRenderPlayer; + private final boolean shouldRenderBlockEntities; + private final OptionalBoolean cullingState; + + private final ImmutableList depthSamplingSettings; + private final ImmutableList colorSamplingSettings; + + public PackShadowDirectives(ShaderProperties properties) { + // By default, the shadow map has a resolution of 1024x1024. It's recommended to increase this for better + // quality. + this.resolution = 1024; + + // By default, shadows do not use FOV, and instead use an orthographic projection controlled by shadowDistance + // + // If FOV is defined, shadows will use a perspective projection controlled by the FOV, and shadowDistance will + // be disregarded for the purposes of creating the projection matrix. However, it will still be used to figure + // out the render distance for shadows if shadowRenderDistanceMul is greater than zero. + this.fov = null; + + // By default, an orthographic projection with a half plane of 160 meters is used, corresponding to a render + // distance of 10 chunks. + // + // It's recommended for shader pack authors to lower this setting to meet their needs in addition to setting + // shadowRenderDistanceMul to a nonzero value, since having a high shadow render distance will impact + // performance quite heavily on most systems. + this.distance = 160.0f; + + // By default, shadows are not culled based on distance from the player. However, pack authors may + // enable this by setting shadowRenderDistanceMul to a nonzero value. + // + // Culling shadows based on the shadow matrices is often infeasible because shader packs frequently + // employ non-linear transformations that end up fitting more far away chunks into the shadow map, + // as well as giving higher detail to close up chunks. + // + // However, Iris does still does cull shadows whenever it can - but, it does so by analyzing + // whether or not shadows can possibly be cast into the player's view, instead of just checking + // the shadow matrices. + this.distanceRenderMul = -1.0f; + this.entityShadowDistanceMul = 1.0f; + this.explicitRenderDistance = false; + + // By default, a shadow interval size of 2 meters is used. This means that the shadow camera will be snapped to + // a grid where each grid cell is 2 meters by 2 meters by 2 meters, and it will only move either when the sun / + // moon move, or when the player camera moves into a different grid cell. + this.intervalSize = 2.0f; + + this.shouldRenderTerrain = properties.getShadowTerrain().orElse(true); + this.shouldRenderTranslucent = properties.getShadowTranslucent().orElse(true); + this.shouldRenderEntities = properties.getShadowEntities().orElse(true); + this.shouldRenderPlayer = properties.getShadowPlayer().orElse(false); + this.shouldRenderBlockEntities = properties.getShadowBlockEntities().orElse(true); + this.cullingState = properties.getShadowCulling(); + this.shadowEnabled = properties.getShadowEnabled(); + + this.depthSamplingSettings = ImmutableList.of(new DepthSamplingSettings(), new DepthSamplingSettings()); + + ImmutableList.Builder colorSamplingSettings = ImmutableList.builder(); + + for (int i = 0; i < MAX_SHADOW_COLOR_BUFFERS; i++) { + colorSamplingSettings.add(new SamplingSettings()); + } + + this.colorSamplingSettings = colorSamplingSettings.build(); + } + + public PackShadowDirectives(PackShadowDirectives shadowDirectives) { + this.resolution = shadowDirectives.resolution; + this.fov = shadowDirectives.fov; + this.distance = shadowDirectives.distance; + this.distanceRenderMul = shadowDirectives.distanceRenderMul; + this.entityShadowDistanceMul = shadowDirectives.entityShadowDistanceMul; + this.explicitRenderDistance = shadowDirectives.explicitRenderDistance; + this.intervalSize = shadowDirectives.intervalSize; + this.shouldRenderTerrain = shadowDirectives.shouldRenderTerrain; + this.shouldRenderTranslucent = shadowDirectives.shouldRenderTranslucent; + this.shouldRenderEntities = shadowDirectives.shouldRenderEntities; + this.shouldRenderPlayer = shadowDirectives.shouldRenderPlayer; + this.shouldRenderBlockEntities = shadowDirectives.shouldRenderBlockEntities; + this.cullingState = shadowDirectives.cullingState; + this.depthSamplingSettings = shadowDirectives.depthSamplingSettings; + this.colorSamplingSettings = shadowDirectives.colorSamplingSettings; + this.shadowEnabled = shadowDirectives.shadowEnabled; + } + + public int getResolution() { + return resolution; + } + + public Float getFov() { + return fov; + } + + public float getDistance() { + return distance; + } + + public float getDistanceRenderMul() { + return distanceRenderMul; + } + + public float getEntityShadowDistanceMul() { + return entityShadowDistanceMul; + } + + public boolean isDistanceRenderMulExplicit() { + return explicitRenderDistance; + } + + public float getIntervalSize() { + return intervalSize; + } + + public boolean shouldRenderTerrain() { + return shouldRenderTerrain; + } + + public boolean shouldRenderTranslucent() { + return shouldRenderTranslucent; + } + + public boolean shouldRenderEntities() { + return shouldRenderEntities; + } + + public boolean shouldRenderPlayer() { + return shouldRenderPlayer; + } + + public boolean shouldRenderBlockEntities() { + return shouldRenderBlockEntities; + } + + public OptionalBoolean getCullingState() { + return cullingState; + } + + public OptionalBoolean isShadowEnabled() { + return shadowEnabled; + } + + public ImmutableList getDepthSamplingSettings() { + return depthSamplingSettings; + } + + public ImmutableList getColorSamplingSettings() { + return colorSamplingSettings; + } + + public void acceptDirectives(DirectiveHolder directives) { + directives.acceptCommentIntDirective("SHADOWRES", resolution -> this.resolution = resolution); + directives.acceptConstIntDirective("shadowMapResolution", resolution -> this.resolution = resolution); + + directives.acceptCommentFloatDirective("SHADOWFOV", fov -> this.fov = fov); + directives.acceptConstFloatDirective("shadowMapFov", fov -> this.fov = fov); + + directives.acceptCommentFloatDirective("SHADOWHPL", distance -> this.distance = distance); + directives.acceptConstFloatDirective("shadowDistance", distance -> this.distance = distance); + + directives.acceptConstFloatDirective("entityShadowDistanceMul", distance -> this.entityShadowDistanceMul = distance); + + directives.acceptConstFloatDirective("shadowDistanceRenderMul", distanceRenderMul -> { + this.distanceRenderMul = distanceRenderMul; + this.explicitRenderDistance = true; + }); + + directives.acceptConstFloatDirective("shadowIntervalSize", + intervalSize -> this.intervalSize = intervalSize); + + acceptHardwareFilteringSettings(directives, depthSamplingSettings); + acceptDepthMipmapSettings(directives, depthSamplingSettings); + acceptColorMipmapSettings(directives, colorSamplingSettings); + acceptDepthFilteringSettings(directives, depthSamplingSettings); + acceptColorFilteringSettings(directives, colorSamplingSettings); + acceptBufferDirectives(directives, colorSamplingSettings); + } + + /** + * Handles shadowHardwareFiltering* directives + */ + private static void acceptHardwareFilteringSettings(DirectiveHolder directives, ImmutableList samplers) { + // Get the default base value for the hardware filtering setting + directives.acceptConstBooleanDirective("shadowHardwareFiltering", hardwareFiltering -> { + for (DepthSamplingSettings samplerSettings : samplers) { + samplerSettings.setHardwareFiltering(hardwareFiltering); + } + }); + + // Find any per-sampler overrides for the hardware filtering setting + for (int i = 0; i < samplers.size(); i++) { + String name = "shadowHardwareFiltering" + i; + + directives.acceptConstBooleanDirective(name, samplers.get(i)::setHardwareFiltering); + } + } + + private static void acceptDepthMipmapSettings(DirectiveHolder directives, ImmutableList samplers) { + // Get the default base value for the shadow depth mipmap setting + directives.acceptConstBooleanDirective("generateShadowMipmap", mipmap -> { + for (SamplingSettings samplerSettings : samplers) { + samplerSettings.setMipmap(mipmap); + } + }); + + // Find any per-sampler overrides for the shadow depth mipmap setting + + // Legacy override option: shadowtexMipmap, an alias for shadowtex0Mipmap + if (samplers.size() >= 1) { + directives.acceptConstBooleanDirective("shadowtexMipmap", samplers.get(0)::setMipmap); + } + + // Standard override option: shadowtex0Mipmap and shadowtex1Mipmap + for (int i = 0; i < samplers.size(); i++) { + String name = "shadowtex" + i + "Mipmap"; + + directives.acceptConstBooleanDirective(name, samplers.get(i)::setMipmap); + } + } + + private static void acceptColorMipmapSettings(DirectiveHolder directives, ImmutableList samplers) { + // Get the default base value for the shadow depth mipmap setting + directives.acceptConstBooleanDirective("generateShadowColorMipmap", mipmap -> { + for (SamplingSettings samplerSettings : samplers) { + samplerSettings.setMipmap(mipmap); + } + }); + + // Find any per-sampler overrides for the shadow depth mipmap setting + for (int i = 0; i < samplers.size(); i++) { + String name = "shadowcolor" + i + "Mipmap"; + directives.acceptConstBooleanDirective(name, samplers.get(i)::setMipmap); + + name = "shadowColor" + i + "Mipmap"; + directives.acceptConstBooleanDirective(name, samplers.get(i)::setMipmap); + } + } + + private static void acceptDepthFilteringSettings(DirectiveHolder directives, ImmutableList samplers) { + if (samplers.size() >= 1) { + directives.acceptConstBooleanDirective("shadowtexNearest", samplers.get(0)::setNearest); + } + + for (int i = 0; i < samplers.size(); i++) { + String name = "shadowtex" + i + "Nearest"; + + directives.acceptConstBooleanDirective(name, samplers.get(i)::setNearest); + + name = "shadow" + i + "MinMagNearest"; + + directives.acceptConstBooleanDirective(name, samplers.get(i)::setNearest); + } + } + + private static void acceptColorFilteringSettings(DirectiveHolder directives, ImmutableList samplers) { + for (int i = 0; i < samplers.size(); i++) { + String name = "shadowcolor" + i + "Nearest"; + + directives.acceptConstBooleanDirective(name, samplers.get(i)::setNearest); + + name = "shadowColor" + i + "Nearest"; + + directives.acceptConstBooleanDirective(name, samplers.get(i)::setNearest); + + name = "shadowColor" + i + "MinMagNearest"; + + directives.acceptConstBooleanDirective(name, samplers.get(i)::setNearest); + } + } + + private void acceptBufferDirectives(DirectiveHolder directives, ImmutableList settings) { + for (int i = 0; i < settings.size(); i++) { + String bufferName = "shadowcolor" + i; + int finalI = i; + directives.acceptConstStringDirective(bufferName + "Format", format -> { + Optional internalFormat = InternalTextureFormat.fromString(format); + + if (internalFormat.isPresent()) { + settings.get(finalI).setFormat(internalFormat.get()); + } else { + Iris.logger.warn("Unrecognized internal texture format " + format + " specified for " + bufferName + "Format, ignoring."); + } + }); + + // TODO: Only for composite and deferred + directives.acceptConstBooleanDirective(bufferName + "Clear", + shouldClear -> settings.get(finalI).setClear(shouldClear)); + + // TODO: Only for composite, deferred, and final + + // Note: This is still relevant even if shouldClear is false, + // since this will be the initial color of the buffer. + directives.acceptConstVec4Directive(bufferName + "ClearColor", + clearColor -> settings.get(finalI).setClearColor(clearColor)); + } + } + + @Override + public String toString() { + return "PackShadowDirectives{" + + "resolution=" + resolution + + ", fov=" + fov + + ", distance=" + distance + + ", distanceRenderMul=" + distanceRenderMul + + ", entityDistanceRenderMul=" + entityShadowDistanceMul + + ", intervalSize=" + intervalSize + + ", depthSamplingSettings=" + depthSamplingSettings + + ", colorSamplingSettings=" + colorSamplingSettings + + '}'; + } + + public static class SamplingSettings { + /** + * Whether mipmaps should be generated before sampling. Disabled by default. + */ + private boolean mipmap; + + /** + * Whether nearest texture filtering should be used in place of linear filtering. By default, linear filtering + * is used, which applies some blur, but if this is not desired behavior, nearest filtering can be used. + */ + private boolean nearest; + + /** + * Whether to clear the buffer every frame. + */ + private boolean clear; + + /** + * The color to clear the buffer to. If {@code clear} is false, this has no effect. + */ + private Vector4f clearColor; + + /** + * The internal format to use for the color buffer. + */ + private InternalTextureFormat format; + + public SamplingSettings() { + mipmap = false; + nearest = false; + clear = true; + clearColor = new Vector4f(1.0F); + format = InternalTextureFormat.RGBA; + } + + protected void setMipmap(boolean mipmap) { + this.mipmap = mipmap; + } + + protected void setNearest(boolean nearest) { + this.nearest = nearest; + } + + protected void setClear(boolean clear) { + this.clear = clear; + } + + protected void setClearColor(Vector4f clearColor) { + this.clearColor = clearColor; + } + + protected void setFormat(InternalTextureFormat format) { + this.format = format; + } + + public boolean getMipmap() { + return this.mipmap; + } + + public boolean getNearest() { + return this.nearest; + } + + public boolean getClear() { + return clear; + } + + public Vector4f getClearColor() { + return clearColor; + } + + public InternalTextureFormat getFormat() { + return this.format; + } + + @Override + public String toString() { + return "SamplingSettings{" + + "mipmap=" + mipmap + + ", nearest=" + nearest + + ", clear=" + clear + + ", clearColor=" + clearColor + + ", format=" + format.name() + + '}'; + } + } + + public static class DepthSamplingSettings extends SamplingSettings { + private boolean hardwareFiltering; + + public DepthSamplingSettings() { + hardwareFiltering = false; + } + + private void setHardwareFiltering(boolean hardwareFiltering) { + this.hardwareFiltering = hardwareFiltering; + } + + public boolean getHardwareFiltering() { + return hardwareFiltering; + } + + @Override + public String toString() { + return "DepthSamplingSettings{" + + "mipmap=" + getMipmap() + + ", nearest=" + getNearest() + + ", hardwareFiltering=" + hardwareFiltering + + '}'; + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/ProgramDirectives.java b/src/main/java/net/coderbot/iris/shaderpack/ProgramDirectives.java new file mode 100644 index 000000000..6a121cb59 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/ProgramDirectives.java @@ -0,0 +1,186 @@ +package net.coderbot.iris.shaderpack; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import net.coderbot.iris.gl.blending.AlphaTestOverride; +import net.coderbot.iris.gl.blending.BlendModeOverride; +import net.coderbot.iris.gl.blending.BufferBlendInformation; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +public class ProgramDirectives { + private static final ImmutableList LEGACY_RENDER_TARGETS = PackRenderTargetDirectives.LEGACY_RENDER_TARGETS; + + private final int[] drawBuffers; + private final float viewportScale; + @Nullable + private final AlphaTestOverride alphaTestOverride; + + private final Optional blendModeOverride; + private final List bufferBlendInformations; + private final ImmutableSet mipmappedBuffers; + private final ImmutableMap explicitFlips; + + private ProgramDirectives(int[] drawBuffers, float viewportScale, @Nullable AlphaTestOverride alphaTestOverride, + Optional blendModeOverride, List bufferBlendInformations, ImmutableSet mipmappedBuffers, + ImmutableMap explicitFlips) { + this.drawBuffers = drawBuffers; + this.viewportScale = viewportScale; + this.alphaTestOverride = alphaTestOverride; + this.blendModeOverride = blendModeOverride; + this.bufferBlendInformations = bufferBlendInformations; + this.mipmappedBuffers = mipmappedBuffers; + this.explicitFlips = explicitFlips; + } + + ProgramDirectives(ProgramSource source, ShaderProperties properties, Set supportedRenderTargets, + @Nullable BlendModeOverride defaultBlendOverride) { + // DRAWBUFFERS is only detected in the fragment shader source code (.fsh). + // If there's no explicit declaration, then by default /* DRAWBUFFERS:0 */ is inferred. + // For SEUS v08 and SEUS v10 to work, this will need to be set to 01234567. However, doing this causes + // TAA to break on Sildur's Vibrant Shaders, since gbuffers_skybasic lacks a DRAWBUFFERS directive, causing + // undefined data to be written to colortex7. + // + // TODO: Figure out how to infer the DRAWBUFFERS directive when it is missing. + Optional optionalDrawbuffersDirective = findDrawbuffersDirective(source.getFragmentSource()); + Optional optionalRendertargetsDirective = findRendertargetsDirective(source.getFragmentSource()); + + Optional optionalCommentDirective = getAppliedDirective(optionalDrawbuffersDirective, optionalRendertargetsDirective); + drawBuffers = optionalCommentDirective.map(commentDirective -> { + if (commentDirective.getType() == CommentDirective.Type.DRAWBUFFERS) { + return parseDigits(commentDirective.getDirective().toCharArray()); + } else if (commentDirective.getType() == CommentDirective.Type.RENDERTARGETS) { + return parseDigitList(commentDirective.getDirective()); + } else { + throw new IllegalStateException("Unhandled comment directive type!"); + } + }).orElse(new int[] { 0 }); + + if (properties != null) { + viewportScale = properties.getViewportScaleOverrides().getOrDefault(source.getName(), 1.0f); + alphaTestOverride = properties.getAlphaTestOverrides().get(source.getName()); + + BlendModeOverride blendModeOverride = properties.getBlendModeOverrides().get(source.getName()); + List bufferBlendInformations = properties.getBufferBlendOverrides().get(source.getName()); + this.blendModeOverride = Optional.ofNullable(blendModeOverride != null ? blendModeOverride : defaultBlendOverride); + this.bufferBlendInformations = bufferBlendInformations != null ? bufferBlendInformations : Collections.emptyList(); + + explicitFlips = source.getParent().getPackDirectives().getExplicitFlips(source.getName()); + } else { + viewportScale = 1.0f; + alphaTestOverride = null; + blendModeOverride = Optional.ofNullable(defaultBlendOverride); + bufferBlendInformations = Collections.emptyList(); + explicitFlips = ImmutableMap.of(); + } + + HashSet mipmappedBuffers = new HashSet<>(); + DispatchingDirectiveHolder directiveHolder = new DispatchingDirectiveHolder(); + + supportedRenderTargets.forEach(index -> { + BooleanConsumer mipmapHandler = shouldMipmap -> { + if (shouldMipmap) { + mipmappedBuffers.add(index); + } else { + mipmappedBuffers.remove(index); + } + }; + + directiveHolder.acceptConstBooleanDirective("colortex" + index + "MipmapEnabled", mipmapHandler); + + if (index < LEGACY_RENDER_TARGETS.size()) { + directiveHolder.acceptConstBooleanDirective(LEGACY_RENDER_TARGETS.get(index) + "MipmapEnabled", mipmapHandler); + } + }); + + source.getFragmentSource().map(ConstDirectiveParser::findDirectives).ifPresent(directives -> { + for (ConstDirectiveParser.ConstDirective directive : directives) { + directiveHolder.processDirective(directive); + } + }); + + this.mipmappedBuffers = ImmutableSet.copyOf(mipmappedBuffers); + } + + public ProgramDirectives withOverriddenDrawBuffers(int[] drawBuffersOverride) { + return new ProgramDirectives(drawBuffersOverride, viewportScale, alphaTestOverride, blendModeOverride, bufferBlendInformations, + mipmappedBuffers, explicitFlips); + } + + private static Optional findDrawbuffersDirective(Optional stageSource) { + return stageSource.flatMap(fragment -> CommentDirectiveParser.findDirective(fragment, CommentDirective.Type.DRAWBUFFERS)); + } + + private static Optional findRendertargetsDirective(Optional stageSource) { + return stageSource.flatMap(fragment -> CommentDirectiveParser.findDirective(fragment, CommentDirective.Type.RENDERTARGETS)); + } + + private static int[] parseDigits(char[] directiveChars) { + int[] buffers = new int[directiveChars.length]; + int index = 0; + + for (char buffer : directiveChars) { + buffers[index++] = Character.digit(buffer, 10); + } + + return buffers; + } + + private static int[] parseDigitList(String digitListString) { + return Arrays.stream(digitListString.split(",")) + .mapToInt(Integer::parseInt) + .toArray(); + } + + private static Optional getAppliedDirective(Optional optionalDrawbuffersDirective, Optional optionalRendertargetsDirective) { + if (optionalDrawbuffersDirective.isPresent() && optionalRendertargetsDirective.isPresent()) { + if (optionalDrawbuffersDirective.get().getLocation() > optionalRendertargetsDirective.get().getLocation()) { + return optionalDrawbuffersDirective; + } else { + return optionalRendertargetsDirective; + } + } else if (optionalDrawbuffersDirective.isPresent()) { + return optionalDrawbuffersDirective; + } else if (optionalRendertargetsDirective.isPresent()) { + return optionalRendertargetsDirective; + } else { + return Optional.empty(); + } + } + + public int[] getDrawBuffers() { + return drawBuffers; + } + + public float getViewportScale() { + return viewportScale; + } + + public Optional getAlphaTestOverride() { + return Optional.ofNullable(alphaTestOverride); + } + + public Optional getBlendModeOverride() { + return blendModeOverride; + } + + public List getBufferBlendOverrides() { + return bufferBlendInformations; + } + + public ImmutableSet getMipmappedBuffers() { + return mipmappedBuffers; + } + + public ImmutableMap getExplicitFlips() { + return explicitFlips; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/ProgramFallbackResolver.java b/src/main/java/net/coderbot/iris/shaderpack/ProgramFallbackResolver.java new file mode 100644 index 000000000..aab07205f --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/ProgramFallbackResolver.java @@ -0,0 +1,42 @@ +package net.coderbot.iris.shaderpack; + +import net.coderbot.iris.shaderpack.loading.ProgramId; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class ProgramFallbackResolver { + private final ProgramSet programs; + private final Map cache; + + public ProgramFallbackResolver(ProgramSet programs) { + this.programs = programs; + this.cache = new HashMap<>(); + } + + public Optional resolve(ProgramId id) { + return Optional.ofNullable(resolveNullable(id)); + } + + @Nullable + public ProgramSource resolveNullable(ProgramId id) { + if (cache.containsKey(id)) { + return cache.get(id); + } + + ProgramSource source = programs.get(id).orElse(null); + + if (source == null) { + ProgramId fallback = id.getFallback().orElse(null); + + if (fallback != null) { + source = resolveNullable(fallback); + } + } + + cache.put(id, source); + return source; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java b/src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java new file mode 100644 index 000000000..d8b32f9f2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java @@ -0,0 +1,453 @@ +package net.coderbot.iris.shaderpack; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.blending.BlendModeOverride; +import net.coderbot.iris.shaderpack.include.AbsolutePackPath; +import net.coderbot.iris.shaderpack.loading.ProgramId; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +public class ProgramSet { + private final PackDirectives packDirectives; + + private final ProgramSource shadow; + private final ComputeSource[] shadowCompute; + + private final ProgramSource[] shadowcomp; + private final ComputeSource[][] shadowCompCompute; + private final ProgramSource[] prepare; + private final ComputeSource[][] prepareCompute; + + private final ProgramSource gbuffersBasic; + private final ProgramSource gbuffersLine; + private final ProgramSource gbuffersBeaconBeam; + private final ProgramSource gbuffersTextured; + private final ProgramSource gbuffersTexturedLit; + private final ProgramSource gbuffersTerrain; + private ProgramSource gbuffersDamagedBlock; + private final ProgramSource gbuffersSkyBasic; + private final ProgramSource gbuffersSkyTextured; + private final ProgramSource gbuffersClouds; + private final ProgramSource gbuffersWeather; + private final ProgramSource gbuffersEntities; + private final ProgramSource gbuffersEntitiesTrans; + private final ProgramSource gbuffersEntitiesGlowing; + private final ProgramSource gbuffersGlint; + private final ProgramSource gbuffersEntityEyes; + private final ProgramSource gbuffersBlock; + private final ProgramSource gbuffersHand; + + private final ProgramSource[] deferred; + private final ComputeSource[][] deferredCompute; + + private final ProgramSource gbuffersWater; + private final ProgramSource gbuffersHandWater; + + private final ProgramSource[] composite; + private final ComputeSource[][] compositeCompute; + private final ProgramSource compositeFinal; + private final ComputeSource[] finalCompute; + + + private final ShaderPack pack; + + public ProgramSet(AbsolutePackPath directory, Function sourceProvider, + ShaderProperties shaderProperties, ShaderPack pack) { + this.packDirectives = new PackDirectives(PackRenderTargetDirectives.BASELINE_SUPPORTED_RENDER_TARGETS, shaderProperties); + this.pack = pack; + + // Note: Ensure that blending is properly overridden during the shadow pass. By default, blending is disabled + // in the shadow pass. Shader packs expect this for colored shadows from stained glass and nether portals + // to work properly. + // + // Note: Enabling blending in the shadow pass results in weird results since translucency sorting happens + // relative to the player camera, not the shadow camera, so we can't rely on chunks being properly + // sorted in the shadow pass. + // + // - https://github.com/IrisShaders/Iris/issues/483 + // - https://github.com/IrisShaders/Iris/issues/987 + this.shadow = readProgramSource(directory, sourceProvider, "shadow", this, shaderProperties, + BlendModeOverride.OFF); + this.shadowCompute = readComputeArray(directory, sourceProvider, "shadow"); + + this.shadowcomp = readProgramArray(directory, sourceProvider, "shadowcomp", shaderProperties); + + this.shadowCompCompute = new ComputeSource[shadowcomp.length][]; + for (int i = 0; i < shadowcomp.length; i++) { + this.shadowCompCompute[i] = readComputeArray(directory, sourceProvider, "shadowcomp" + ((i == 0) ? "" : i)); + } + + this.prepare = readProgramArray(directory, sourceProvider, "prepare", shaderProperties); + this.prepareCompute = new ComputeSource[prepare.length][]; + for (int i = 0; i < prepare.length; i++) { + this.prepareCompute[i] = readComputeArray(directory, sourceProvider, "prepare" + ((i == 0) ? "" : i)); + } + + this.gbuffersBasic = readProgramSource(directory, sourceProvider, "gbuffers_basic", this, shaderProperties); + this.gbuffersLine = readProgramSource(directory, sourceProvider, "gbuffers_line", this, shaderProperties); + this.gbuffersBeaconBeam = readProgramSource(directory, sourceProvider, "gbuffers_beaconbeam", this, shaderProperties); + this.gbuffersTextured = readProgramSource(directory, sourceProvider, "gbuffers_textured", this, shaderProperties); + this.gbuffersTexturedLit = readProgramSource(directory, sourceProvider, "gbuffers_textured_lit", this, shaderProperties); + this.gbuffersTerrain = readProgramSource(directory, sourceProvider, "gbuffers_terrain", this, shaderProperties); + this.gbuffersDamagedBlock = readProgramSource(directory, sourceProvider, "gbuffers_damagedblock", this, shaderProperties); + this.gbuffersSkyBasic = readProgramSource(directory, sourceProvider, "gbuffers_skybasic", this, shaderProperties); + this.gbuffersSkyTextured = readProgramSource(directory, sourceProvider, "gbuffers_skytextured", this, shaderProperties); + this.gbuffersClouds = readProgramSource(directory, sourceProvider, "gbuffers_clouds", this, shaderProperties); + this.gbuffersWeather = readProgramSource(directory, sourceProvider, "gbuffers_weather", this, shaderProperties); + this.gbuffersEntities = readProgramSource(directory, sourceProvider, "gbuffers_entities", this, shaderProperties); + this.gbuffersEntitiesTrans = readProgramSource(directory, sourceProvider, "gbuffers_entities_translucent", this, shaderProperties); + this.gbuffersEntitiesGlowing = readProgramSource(directory, sourceProvider, "gbuffers_entities_glowing", this, shaderProperties); + this.gbuffersGlint = readProgramSource(directory, sourceProvider, "gbuffers_armor_glint", this, shaderProperties); + this.gbuffersEntityEyes = readProgramSource(directory, sourceProvider, "gbuffers_spidereyes", this, shaderProperties); + this.gbuffersBlock = readProgramSource(directory, sourceProvider, "gbuffers_block", this, shaderProperties); + this.gbuffersHand = readProgramSource(directory, sourceProvider, "gbuffers_hand", this, shaderProperties); + + this.deferred = readProgramArray(directory, sourceProvider, "deferred", shaderProperties); + this.deferredCompute = new ComputeSource[deferred.length][]; + for (int i = 0; i < deferred.length; i++) { + this.deferredCompute[i] = readComputeArray(directory, sourceProvider, "deferred" + ((i == 0) ? "" : i)); + } + + this.gbuffersWater = readProgramSource(directory, sourceProvider, "gbuffers_water", this, shaderProperties); + this.gbuffersHandWater = readProgramSource(directory, sourceProvider, "gbuffers_hand_water", this, shaderProperties); + + this.composite = readProgramArray(directory, sourceProvider, "composite", shaderProperties); + this.compositeCompute = new ComputeSource[composite.length][]; + for (int i = 0; i < deferred.length; i++) { + this.compositeCompute[i] = readComputeArray(directory, sourceProvider, "composite" + ((i == 0) ? "" : i)); + } + this.compositeFinal = readProgramSource(directory, sourceProvider, "final", this, shaderProperties); + this.finalCompute = readComputeArray(directory, sourceProvider, "final"); + + locateDirectives(); + + if (!gbuffersDamagedBlock.isValid()) { + // Special behavior inherited by OptiFine & Iris from old ShadersMod + // Presumably this was added before DRAWBUFFERS was a thing? Or just a hardcoded hacky fix for some + // shader packs - in any case, Sildurs Vibrant Shaders and other packs rely on it. + first(getGbuffersTerrain(), getGbuffersTexturedLit(), getGbuffersTextured(), getGbuffersBasic()).ifPresent(src -> { + ProgramDirectives overrideDirectives = src.getDirectives().withOverriddenDrawBuffers(new int[] { 0 }); + this.gbuffersDamagedBlock = src.withDirectiveOverride(overrideDirectives); + }); + } + } + + @SafeVarargs + private static Optional first(Optional... candidates) { + for (Optional candidate : candidates) { + if (candidate.isPresent()) { + return candidate; + } + } + + return Optional.empty(); + } + + private ProgramSource[] readProgramArray(AbsolutePackPath directory, + Function sourceProvider, String name, + ShaderProperties shaderProperties) { + ProgramSource[] programs = new ProgramSource[99]; + + for (int i = 0; i < programs.length; i++) { + String suffix = i == 0 ? "" : Integer.toString(i); + + programs[i] = readProgramSource(directory, sourceProvider, name + suffix, this, shaderProperties); + } + + return programs; + } + + private ComputeSource[] readComputeArray(AbsolutePackPath directory, + Function sourceProvider, String name) { + ComputeSource[] programs = new ComputeSource[27]; + + programs[0] = readComputeSource(directory, sourceProvider, name, this); + + for (char c = 'a'; c <= 'z'; ++c) { + String suffix = "_" + c; + + programs[c - 96] = readComputeSource(directory, sourceProvider, name + suffix, this); + + if (programs[c - 96] == null) { + break; + } + } + + return programs; + } + + private void locateDirectives() { + List programs = new ArrayList<>(); + List computes = new ArrayList<>(); + + programs.add(shadow); + programs.addAll(Arrays.asList(shadowcomp)); + programs.addAll(Arrays.asList(prepare)); + + programs.addAll (Arrays.asList( + gbuffersBasic, gbuffersBeaconBeam, gbuffersTextured, gbuffersTexturedLit, gbuffersTerrain, + gbuffersDamagedBlock, gbuffersSkyBasic, gbuffersSkyTextured, gbuffersClouds, gbuffersWeather, + gbuffersEntities, gbuffersEntitiesTrans, gbuffersEntitiesGlowing, gbuffersGlint, gbuffersEntityEyes, gbuffersBlock, + gbuffersHand + )); + + for (ComputeSource[] computeSources : compositeCompute) { + computes.addAll(Arrays.asList(computeSources)); + } + + for (ComputeSource[] computeSources : deferredCompute) { + computes.addAll(Arrays.asList(computeSources)); + } + + for (ComputeSource[] computeSources : prepareCompute) { + computes.addAll(Arrays.asList(computeSources)); + } + + for (ComputeSource[] computeSources : shadowCompCompute) { + computes.addAll(Arrays.asList(computeSources)); + } + + Collections.addAll(computes, finalCompute); + Collections.addAll(computes, shadowCompute); + + for (ComputeSource source : computes) { + if (source != null) { + source.getSource().map(ConstDirectiveParser::findDirectives).ifPresent(constDirectives -> { + for (ConstDirectiveParser.ConstDirective directive : constDirectives) { + if (directive.getType() == ConstDirectiveParser.Type.IVEC3 && directive.getKey().equals("workGroups")) { + ComputeDirectiveParser.setComputeWorkGroups(source, directive); + } else if (directive.getType() == ConstDirectiveParser.Type.VEC2 && directive.getKey().equals("workGroupsRender")) { + ComputeDirectiveParser.setComputeWorkGroupsRelative(source, directive); + } + } + }); + } + } + + programs.addAll(Arrays.asList(deferred)); + programs.add(gbuffersWater); + programs.add(gbuffersHandWater); + programs.addAll(Arrays.asList(composite)); + programs.add(compositeFinal); + + DispatchingDirectiveHolder packDirectiveHolder = new DispatchingDirectiveHolder(); + + packDirectives.acceptDirectivesFrom(packDirectiveHolder); + + for (ProgramSource source : programs) { + if (source == null) { + continue; + } + + source.getFragmentSource().map(ConstDirectiveParser::findDirectives).ifPresent(directives -> { + for (ConstDirectiveParser.ConstDirective directive : directives) { + packDirectiveHolder.processDirective(directive); + } + }); + } + + packDirectives.getRenderTargetDirectives().getRenderTargetSettings().forEach((index, settings) -> + Iris.logger.debug("Render target settings for colortex" + index + ": " + settings)); + } + + public Optional getShadow() { + return shadow.requireValid(); + } + + public ProgramSource[] getShadowComposite() { + return shadowcomp; + } + + public ProgramSource[] getPrepare() { + return prepare; + } + + public Optional getGbuffersBasic() { + return gbuffersBasic.requireValid(); + } + + public Optional getGbuffersBeaconBeam() { + return gbuffersBeaconBeam.requireValid(); + } + + public Optional getGbuffersTextured() { + return gbuffersTextured.requireValid(); + } + + public Optional getGbuffersTexturedLit() { + return gbuffersTexturedLit.requireValid(); + } + + public Optional getGbuffersTerrain() { + return gbuffersTerrain.requireValid(); + } + + public Optional getGbuffersDamagedBlock() { + return gbuffersDamagedBlock.requireValid(); + } + + public Optional getGbuffersSkyBasic() { + return gbuffersSkyBasic.requireValid(); + } + + public Optional getGbuffersSkyTextured() { + return gbuffersSkyTextured.requireValid(); + } + + public Optional getGbuffersClouds() { + return gbuffersClouds.requireValid(); + } + + public Optional getGbuffersWeather() { + return gbuffersWeather.requireValid(); + } + + public Optional getGbuffersEntities() { + return gbuffersEntities.requireValid(); + } + + public Optional getGbuffersEntitiesTrans() { + return gbuffersEntitiesTrans.requireValid(); + } + + public Optional getGbuffersEntitiesGlowing() { + return gbuffersEntitiesGlowing.requireValid(); + } + + public Optional getGbuffersGlint() { + return gbuffersGlint.requireValid(); + } + + public Optional getGbuffersEntityEyes() { + return gbuffersEntityEyes.requireValid(); + } + + public Optional getGbuffersBlock() { + return gbuffersBlock.requireValid(); + } + + public Optional getGbuffersHand() { + return gbuffersHand.requireValid(); + } + + public Optional get(ProgramId programId) { + switch (programId) { + case Shadow: return getShadow(); + case Basic: return getGbuffersBasic(); + case Line: return gbuffersLine.requireValid(); + case Textured: return getGbuffersTextured(); + case TexturedLit: return getGbuffersTexturedLit(); + case SkyBasic: return getGbuffersSkyBasic(); + case SkyTextured: return getGbuffersSkyTextured(); + case Clouds: return getGbuffersClouds(); + case Terrain: return getGbuffersTerrain(); + case DamagedBlock: return getGbuffersDamagedBlock(); + case Block: return getGbuffersBlock(); + case BeaconBeam: return getGbuffersBeaconBeam(); + case Entities: return getGbuffersEntities(); + case EntitiesTrans: return getGbuffersEntitiesTrans(); + case EntitiesGlowing: return getGbuffersEntitiesGlowing(); + case ArmorGlint: return getGbuffersGlint(); + case SpiderEyes: return getGbuffersEntityEyes(); + case Hand: return getGbuffersHand(); + case Weather: return getGbuffersWeather(); + case Water: return getGbuffersWater(); + case HandWater: return getGbuffersHandWater(); + case Final: return getCompositeFinal(); + default: return Optional.empty(); + } + } + + public ProgramSource[] getDeferred() { + return deferred; + } + + public Optional getGbuffersWater() { + return gbuffersWater.requireValid(); + } + + public Optional getGbuffersHandWater() { + return gbuffersHandWater.requireValid(); + } + + public ProgramSource[] getComposite() { + return composite; + } + + public Optional getCompositeFinal() { + return compositeFinal.requireValid(); + } + + public ComputeSource[] getShadowCompute() { + return shadowCompute; + } + + public ComputeSource[][] getShadowCompCompute() { + return shadowCompCompute; + } + + public ComputeSource[][] getPrepareCompute() { + return prepareCompute; + } + + public ComputeSource[][] getDeferredCompute() { + return deferredCompute; + } + + public ComputeSource[][] getCompositeCompute() { + return compositeCompute; + } + + public ComputeSource[] getFinalCompute() { + return finalCompute; + } + + public PackDirectives getPackDirectives() { + return packDirectives; + } + + public ShaderPack getPack() { + return pack; + } + + private static ProgramSource readProgramSource(AbsolutePackPath directory, + Function sourceProvider, String program, + ProgramSet programSet, ShaderProperties properties) { + return readProgramSource(directory, sourceProvider, program, programSet, properties, null); + } + + private static ProgramSource readProgramSource(AbsolutePackPath directory, + Function sourceProvider, String program, + ProgramSet programSet, ShaderProperties properties, + BlendModeOverride defaultBlendModeOverride) { + AbsolutePackPath vertexPath = directory.resolve(program + ".vsh"); + String vertexSource = sourceProvider.apply(vertexPath); + + AbsolutePackPath geometryPath = directory.resolve(program + ".gsh"); + String geometrySource = sourceProvider.apply(geometryPath); + + AbsolutePackPath fragmentPath = directory.resolve(program + ".fsh"); + String fragmentSource = sourceProvider.apply(fragmentPath); + + return new ProgramSource(program, vertexSource, geometrySource, fragmentSource, programSet, properties, + defaultBlendModeOverride); + } + + private static ComputeSource readComputeSource(AbsolutePackPath directory, + Function sourceProvider, String program, + ProgramSet programSet) { + AbsolutePackPath computePath = directory.resolve(program + ".csh"); + String computeSource = sourceProvider.apply(computePath); + + if (computeSource == null) { + return null; + } + + return new ComputeSource(program, computeSource, programSet); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/ProgramSource.java b/src/main/java/net/coderbot/iris/shaderpack/ProgramSource.java new file mode 100644 index 000000000..9ef8500a7 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/ProgramSource.java @@ -0,0 +1,75 @@ +package net.coderbot.iris.shaderpack; + +import net.coderbot.iris.gl.blending.BlendModeOverride; + +import java.util.Optional; + +public class ProgramSource { + private final String name; + private final String vertexSource; + private final String geometrySource; + private final String fragmentSource; + private final ProgramDirectives directives; + private final ProgramSet parent; + + private ProgramSource(String name, String vertexSource, String geometrySource, String fragmentSource, + ProgramDirectives directives, ProgramSet parent) { + this.name = name; + this.vertexSource = vertexSource; + this.geometrySource = geometrySource; + this.fragmentSource = fragmentSource; + this.directives = directives; + this.parent = parent; + } + + public ProgramSource(String name, String vertexSource, String geometrySource, String fragmentSource, + ProgramSet parent, ShaderProperties properties, BlendModeOverride defaultBlendModeOverride) { + this.name = name; + this.vertexSource = vertexSource; + this.geometrySource = geometrySource; + this.fragmentSource = fragmentSource; + this.parent = parent; + this.directives = new ProgramDirectives(this, properties, + PackRenderTargetDirectives.BASELINE_SUPPORTED_RENDER_TARGETS, defaultBlendModeOverride); + } + + public ProgramSource withDirectiveOverride(ProgramDirectives overrideDirectives) { + return new ProgramSource(name, vertexSource, geometrySource, fragmentSource, overrideDirectives, parent); + } + + public String getName() { + return name; + } + + public Optional getVertexSource() { + return Optional.ofNullable(vertexSource); + } + + public Optional getGeometrySource() { + return Optional.ofNullable(geometrySource); + } + + public Optional getFragmentSource() { + return Optional.ofNullable(fragmentSource); + } + + public ProgramDirectives getDirectives() { + return this.directives; + } + + public ProgramSet getParent() { + return parent; + } + + public boolean isValid() { + return vertexSource != null && fragmentSource != null; + } + + public Optional requireValid() { + if (this.isValid()) { + return Optional.of(this); + } else { + return Optional.empty(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java b/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java new file mode 100644 index 000000000..304716b92 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java @@ -0,0 +1,405 @@ +package net.coderbot.iris.shaderpack; + +import com.google.common.collect.ImmutableList; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.stream.JsonReader; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.coderbot.iris.Iris; +import net.coderbot.iris.features.FeatureFlags; +import net.coderbot.iris.gui.FeatureMissingErrorScreen; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.include.AbsolutePackPath; +import net.coderbot.iris.shaderpack.include.IncludeGraph; +import net.coderbot.iris.shaderpack.include.IncludeProcessor; +import net.coderbot.iris.shaderpack.include.ShaderPackSourceNames; +import net.coderbot.iris.shaderpack.option.ProfileSet; +import net.coderbot.iris.shaderpack.option.ShaderPackOptions; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; +import net.coderbot.iris.shaderpack.option.values.MutableOptionValues; +import net.coderbot.iris.shaderpack.option.values.OptionValues; +import net.coderbot.iris.shaderpack.preprocessor.JcppProcessor; +import net.coderbot.iris.shaderpack.texture.CustomTextureData; +import net.coderbot.iris.shaderpack.texture.TextureFilteringData; +import net.coderbot.iris.shaderpack.texture.TextureStage; +import net.irisshaders.iris.api.v0.IrisApi; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; +import org.jetbrains.annotations.Nullable; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ShaderPack { + private static final Gson GSON = new Gson(); + + private final ProgramSet base; + @Nullable + private final ProgramSet overworld; + private final ProgramSet nether; + private final ProgramSet end; + + private final IdMap idMap; + private final LanguageMap languageMap; + private final EnumMap> customTextureDataMap = new EnumMap<>(TextureStage.class); + private final CustomTextureData customNoiseTexture; + private final ShaderPackOptions shaderPackOptions; + private final OptionMenuContainer menuContainer; + + private final ProfileSet.ProfileResult profile; + private final String profileInfo; + + public ShaderPack(Path root, Iterable environmentDefines) throws IOException, IllegalStateException { + this(root, Collections.emptyMap(), environmentDefines); + } + + /** + * Reads a shader pack from the disk. + * + * @param root The path to the "shaders" directory within the shader pack. The created ShaderPack will not retain + * this path in any form; once the constructor exits, all disk I/O needed to load this shader pack will + * have completed, and there is no need to hold on to the path for that reason. + * @throws IOException if there are any IO errors during shader pack loading. + */ + public ShaderPack(Path root, Map changedConfigs, Iterable environmentDefines) throws IOException, IllegalStateException { + // A null path is not allowed. + Objects.requireNonNull(root); + + + ImmutableList.Builder starts = ImmutableList.builder(); + ImmutableList potentialFileNames = ShaderPackSourceNames.POTENTIAL_STARTS; + + ShaderPackSourceNames.findPresentSources(starts, root, AbsolutePackPath.fromAbsolutePath("/"), + potentialFileNames); + + boolean hasWorld0 = ShaderPackSourceNames.findPresentSources(starts, root, + AbsolutePackPath.fromAbsolutePath("/world0"), potentialFileNames); + + boolean hasNether = ShaderPackSourceNames.findPresentSources(starts, root, + AbsolutePackPath.fromAbsolutePath("/world-1"), potentialFileNames); + + boolean hasEnd = ShaderPackSourceNames.findPresentSources(starts, root, + AbsolutePackPath.fromAbsolutePath("/world1"), potentialFileNames); + + // Read all files and included files recursively + IncludeGraph graph = new IncludeGraph(root, starts.build()); + + if (!graph.getFailures().isEmpty()) { + graph.getFailures().forEach((path, error) -> { + Iris.logger.error("{}", error.toString()); + }); + + throw new IOException("Failed to resolve some #include directives, see previous messages for details"); + } + + this.languageMap = new LanguageMap(root.resolve("lang")); + + // Discover, merge, and apply shader pack options + this.shaderPackOptions = new ShaderPackOptions(graph, changedConfigs); + graph = this.shaderPackOptions.getIncludes(); + + Iterable finalEnvironmentDefines = environmentDefines; + ShaderProperties shaderProperties = loadProperties(root, "shaders.properties") + .map(source -> new ShaderProperties(source, shaderPackOptions, finalEnvironmentDefines)) + .orElseGet(ShaderProperties::empty); + + List invalidFlagList = shaderProperties.getRequiredFeatureFlags().stream().filter(FeatureFlags::isInvalid).map(FeatureFlags::getValue).collect(Collectors.toList()); + List invalidFeatureFlags = invalidFlagList.stream().map(FeatureFlags::getHumanReadableName).collect(Collectors.toList()); + + if (!invalidFeatureFlags.isEmpty()) { + if (Minecraft.getMinecraft().screen instanceof ShaderPackScreen) { + Minecraft.getMinecraft().setScreen(new FeatureMissingErrorScreen(Minecraft.getMinecraft().screen, I18n.format("iris.unsupported.pack"), I18n.format("iris.unsupported.pack.description", FeatureFlags.getInvalidStatus(invalidFlagList), invalidFeatureFlags.stream() + .collect(Collectors.joining(", ", ": ", "."))))); + } + IrisApi.getInstance().getConfig().setShadersEnabledAndApply(false); + } + + List optionalFeatureFlags = shaderProperties.getOptionalFeatureFlags().stream().filter(flag -> !FeatureFlags.isInvalid(flag)).collect(Collectors.toList()); + + if (!optionalFeatureFlags.isEmpty()) { + List newEnvDefines = new ArrayList<>(); + environmentDefines.forEach(newEnvDefines::add); + optionalFeatureFlags.forEach(flag -> newEnvDefines.add(new StringPair("IRIS_FEATURE_" + flag, ""))); + environmentDefines = ImmutableList.copyOf(newEnvDefines); + } + + ProfileSet profiles = ProfileSet.fromTree(shaderProperties.getProfiles(), this.shaderPackOptions.getOptionSet()); + this.profile = profiles.scan(this.shaderPackOptions.getOptionSet(), this.shaderPackOptions.getOptionValues()); + + // Get programs that should be disabled from the detected profile + List disabledPrograms = new ArrayList<>(); + this.profile.current.ifPresent(profile -> disabledPrograms.addAll(profile.disabledPrograms)); + // Add programs that are disabled by shader options + shaderProperties.getConditionallyEnabledPrograms().forEach((program, shaderOption) -> { + if ("true".equals(shaderOption)) return; + + if ("false".equals(shaderOption) || !this.shaderPackOptions.getOptionValues().getBooleanValueOrDefault(shaderOption)) { + disabledPrograms.add(program); + } + }); + + this.menuContainer = new OptionMenuContainer(shaderProperties, this.shaderPackOptions, profiles); + + { + String profileName = getCurrentProfileName(); + OptionValues profileOptions = new MutableOptionValues( + this.shaderPackOptions.getOptionSet(), this.profile.current.map(p -> p.optionValues).orElse(new HashMap<>())); + + int userOptionsChanged = this.shaderPackOptions.getOptionValues().getOptionsChanged() - profileOptions.getOptionsChanged(); + + this.profileInfo = "Profile: " + profileName + " (+" + userOptionsChanged + " option" + (userOptionsChanged == 1 ? "" : "s") + " changed by user)"; + } + + Iris.logger.info(this.profileInfo); + + // Prepare our include processor + IncludeProcessor includeProcessor = new IncludeProcessor(graph); + + // Set up our source provider for creating ProgramSets + Iterable finalEnvironmentDefines1 = environmentDefines; + Function sourceProvider = (path) -> { + String pathString = path.getPathString(); + // Removes the first "/" in the path if present, and the file + // extension in order to represent the path as its program name + String programString = pathString.substring(pathString.indexOf("/") == 0 ? 1 : 0, pathString.lastIndexOf(".")); + + // Return an empty program source if the program is disabled by the current profile + if (disabledPrograms.contains(programString)) { + return null; + } + + ImmutableList lines = includeProcessor.getIncludedFile(path); + + if (lines == null) { + return null; + } + + StringBuilder builder = new StringBuilder(); + + for (String line : lines) { + builder.append(line); + builder.append('\n'); + } + + // Apply GLSL preprocessor to source, while making environment defines available. + // + // This uses similar techniques to the *.properties preprocessor to avoid actually putting + // #define statements in the actual source - instead, we tell the preprocessor about them + // directly. This removes one obstacle to accurate reporting of line numbers for errors, + // though there exist many more (such as relocating all #extension directives and similar things) + String source = builder.toString(); + source = JcppProcessor.glslPreprocessSource(source, finalEnvironmentDefines1); + + return source; + }; + + this.base = new ProgramSet(AbsolutePackPath.fromAbsolutePath("/"), sourceProvider, shaderProperties, this); + + this.overworld = loadOverrides(hasWorld0, AbsolutePackPath.fromAbsolutePath("/world0"), sourceProvider, + shaderProperties, this); + this.nether = loadOverrides(hasNether, AbsolutePackPath.fromAbsolutePath("/world-1"), sourceProvider, + shaderProperties, this); + this.end = loadOverrides(hasEnd, AbsolutePackPath.fromAbsolutePath("/world1"), sourceProvider, + shaderProperties, this); + + this.idMap = new IdMap(root, shaderPackOptions, environmentDefines); + + customNoiseTexture = shaderProperties.getNoiseTexturePath().map(path -> { + try { + return readTexture(root, path); + } catch (IOException e) { + Iris.logger.error("Unable to read the custom noise texture at " + path, e); + + return null; + } + }).orElse(null); + + shaderProperties.getCustomTextures().forEach((textureStage, customTexturePropertiesMap) -> { + Object2ObjectMap innerCustomTextureDataMap = new Object2ObjectOpenHashMap<>(); + customTexturePropertiesMap.forEach((samplerName, path) -> { + try { + innerCustomTextureDataMap.put(samplerName, readTexture(root, path)); + } catch (IOException e) { + Iris.logger.error("Unable to read the custom texture at " + path, e); + } + }); + + customTextureDataMap.put(textureStage, innerCustomTextureDataMap); + }); + } + + private String getCurrentProfileName() { + return profile.current.map(p -> p.name).orElse("Custom"); + } + + public String getProfileInfo() { + return profileInfo; + } + + @Nullable + private static ProgramSet loadOverrides(boolean has, AbsolutePackPath path, Function sourceProvider, + ShaderProperties shaderProperties, ShaderPack pack) { + if (has) { + return new ProgramSet(path, sourceProvider, shaderProperties, pack); + } + + return null; + } + + // TODO: Copy-paste from IdMap, find a way to deduplicate this + private static Optional loadProperties(Path shaderPath, String name) { + String fileContents = readProperties(shaderPath, name); + if (fileContents == null) { + return Optional.empty(); + } + + return Optional.of(fileContents); + } + + // TODO: Implement raw texture data types + public CustomTextureData readTexture(Path root, String path) throws IOException { + CustomTextureData customTextureData; + if (path.contains(":")) { + String[] parts = path.split(":"); + + if (parts.length > 2) { + Iris.logger.warn("Resource location " + path + " contained more than two parts?"); + } + + if (parts[0].equals("minecraft") && (parts[1].equals("dynamic/lightmap_1") || parts[1].equals("dynamic/light_map_1"))) { + customTextureData = new CustomTextureData.LightmapMarker(); + } else { + customTextureData = new CustomTextureData.ResourceData(parts[0], parts[1]); + } + } else { + // TODO: Make sure the resulting path is within the shaderpack? + if (path.startsWith("/")) { + // NB: This does not guarantee the resulting path is in the shaderpack as a double slash could be used, + // this just fixes shaderpacks like Continuum 2.0.4 that use a leading slash in texture paths + path = path.substring(1); + } + + boolean blur = false; + boolean clamp = false; + + String mcMetaPath = path + ".mcmeta"; + Path mcMetaResolvedPath = root.resolve(mcMetaPath); + + if (Files.exists(mcMetaResolvedPath)) { + try { + JsonObject meta = loadMcMeta(mcMetaResolvedPath); + if (meta.get("texture") != null) { + if (meta.get("texture").getAsJsonObject().get("blur") != null) { + blur = meta.get("texture").getAsJsonObject().get("blur").getAsBoolean(); + } + if (meta.get("texture").getAsJsonObject().get("clamp") != null) { + clamp = meta.get("texture").getAsJsonObject().get("clamp").getAsBoolean(); + } + } + } catch (IOException e) { + Iris.logger.error("Unable to read the custom texture mcmeta at " + mcMetaPath + ", ignoring: " + e); + } + } + + byte[] content = Files.readAllBytes(root.resolve(path)); + + customTextureData = new CustomTextureData.PngData(new TextureFilteringData(blur, clamp), content); + } + return customTextureData; + } + + private JsonObject loadMcMeta(Path mcMetaPath) throws IOException, JsonParseException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(mcMetaPath), StandardCharsets.UTF_8))) { + JsonReader jsonReader = new JsonReader(reader); + return GSON.getAdapter(JsonObject.class).read(jsonReader); + } + } + + private static String readProperties(Path shaderPath, String name) { + try { + // Property files should be encoded in ISO_8859_1. + return new String(Files.readAllBytes(shaderPath.resolve(name)), StandardCharsets.ISO_8859_1); + } catch (NoSuchFileException e) { + Iris.logger.debug("An " + name + " file was not found in the current shaderpack"); + + return null; + } catch (IOException e) { + Iris.logger.error("An IOException occurred reading " + name + " from the current shaderpack", e); + + return null; + } + } + + public ProgramSet getProgramSet(DimensionId dimension) { + ProgramSet overrides; + + switch (dimension) { + case OVERWORLD: + overrides = overworld; + break; + case NETHER: + overrides = nether; + break; + case END: + overrides = end; + break; + default: + throw new IllegalArgumentException("Unknown dimension " + dimension); + } + + // NB: If a dimension overrides directory is present, none of the files from the parent directory are "merged" + // into the override. Rather, we act as if the overrides directory contains a completely different set of + // shader programs unrelated to that of the base shader pack. + // + // This makes sense because if base defined a composite pass and the override didn't, it would make it + // impossible to "un-define" the composite pass. It also removes a lot of complexity related to "merging" + // program sets. At the same time, this might be desired behavior by shader pack authors. It could make + // sense to bring it back as a configurable option, and have a more maintainable set of code backing it. + if (overrides != null) { + return overrides; + } else { + return base; + } + } + + public IdMap getIdMap() { + return idMap; + } + + public EnumMap> getCustomTextureDataMap() { + return customTextureDataMap; + } + + public Optional getCustomNoiseTexture() { + return Optional.ofNullable(customNoiseTexture); + } + + public LanguageMap getLanguageMap() { + return languageMap; + } + + public ShaderPackOptions getShaderPackOptions() { + return shaderPackOptions; + } + + public OptionMenuContainer getMenuContainer() { + return menuContainer; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/ShaderProperties.java b/src/main/java/net/coderbot/iris/shaderpack/ShaderProperties.java new file mode 100644 index 000000000..fd5ed7257 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/ShaderProperties.java @@ -0,0 +1,623 @@ +package net.coderbot.iris.shaderpack; + +import it.unimi.dsi.fastutil.booleans.BooleanConsumer; +import it.unimi.dsi.fastutil.objects.Object2BooleanMap; +import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2FloatMap; +import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.blending.AlphaTest; +import net.coderbot.iris.gl.blending.AlphaTestFunction; +import net.coderbot.iris.gl.blending.AlphaTestOverride; +import net.coderbot.iris.gl.blending.BlendMode; +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.shaderpack.option.ShaderPackOptions; +import net.coderbot.iris.shaderpack.preprocessor.PropertiesPreprocessor; +import net.coderbot.iris.shaderpack.texture.TextureStage; + +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * The parsed representation of the shaders.properties file. This class is not meant to be stored permanently, rather + * it merely exists as an intermediate step until we build up PackDirectives and ProgramDirectives objects from the + * values in here & the values parsed from shader source code. + */ +public class ShaderProperties { + private CloudSetting cloudSetting = CloudSetting.DEFAULT; + private OptionalBoolean oldHandLight = OptionalBoolean.DEFAULT; + private OptionalBoolean dynamicHandLight = OptionalBoolean.DEFAULT; + private OptionalBoolean oldLighting = OptionalBoolean.DEFAULT; + private OptionalBoolean shadowTerrain = OptionalBoolean.DEFAULT; + private OptionalBoolean shadowTranslucent = OptionalBoolean.DEFAULT; + private OptionalBoolean shadowEntities = OptionalBoolean.DEFAULT; + private OptionalBoolean shadowPlayer = OptionalBoolean.DEFAULT; + private OptionalBoolean shadowBlockEntities = OptionalBoolean.DEFAULT; + private OptionalBoolean underwaterOverlay = OptionalBoolean.DEFAULT; + private OptionalBoolean sun = OptionalBoolean.DEFAULT; + private OptionalBoolean moon = OptionalBoolean.DEFAULT; + private OptionalBoolean vignette = OptionalBoolean.DEFAULT; + private OptionalBoolean backFaceSolid = OptionalBoolean.DEFAULT; + private OptionalBoolean backFaceCutout = OptionalBoolean.DEFAULT; + private OptionalBoolean backFaceCutoutMipped = OptionalBoolean.DEFAULT; + private OptionalBoolean backFaceTranslucent = OptionalBoolean.DEFAULT; + private OptionalBoolean rainDepth = OptionalBoolean.DEFAULT; + private OptionalBoolean concurrentCompute = OptionalBoolean.DEFAULT; + private OptionalBoolean beaconBeamDepth = OptionalBoolean.DEFAULT; + private OptionalBoolean separateAo = OptionalBoolean.DEFAULT; + private OptionalBoolean frustumCulling = OptionalBoolean.DEFAULT; + private OptionalBoolean shadowCulling = OptionalBoolean.DEFAULT; + private OptionalBoolean shadowEnabled = OptionalBoolean.DEFAULT; + private OptionalBoolean particlesBeforeDeferred = OptionalBoolean.DEFAULT; + private OptionalBoolean prepareBeforeShadow = OptionalBoolean.DEFAULT; + private List sliderOptions = new ArrayList<>(); + private final Map> profiles = new LinkedHashMap<>(); + private List mainScreenOptions = null; + private final Map> subScreenOptions = new HashMap<>(); + private Integer mainScreenColumnCount = null; + private final Map subScreenColumnCount = new HashMap<>(); + // TODO: private Map optifineVersionRequirements; + // TODO: Parse custom uniforms / variables + private final Object2ObjectMap alphaTestOverrides = new Object2ObjectOpenHashMap<>(); + private final Object2FloatMap viewportScaleOverrides = new Object2FloatOpenHashMap<>(); + private final Object2ObjectMap textureScaleOverrides = new Object2ObjectOpenHashMap<>(); + private final Object2ObjectMap blendModeOverrides = new Object2ObjectOpenHashMap<>(); + private final Object2ObjectMap> bufferBlendOverrides = new Object2ObjectOpenHashMap<>(); + private final EnumMap> customTextures = new EnumMap<>(TextureStage.class); + private final Object2ObjectMap> explicitFlips = new Object2ObjectOpenHashMap<>(); + private String noiseTexturePath = null; + private Object2ObjectMap conditionallyEnabledPrograms = new Object2ObjectOpenHashMap<>(); + private List requiredFeatureFlags = new ArrayList<>(); + private List optionalFeatureFlags = new ArrayList<>(); + + private ShaderProperties() { + // empty + } + + // TODO: Is there a better solution than having ShaderPack pass a root path to ShaderProperties to be able to read textures? + public ShaderProperties(String contents, ShaderPackOptions shaderPackOptions, Iterable environmentDefines) { + String preprocessedContents = PropertiesPreprocessor.preprocessSource(contents, shaderPackOptions, environmentDefines); + + Properties preprocessed = new OrderBackedProperties(); + Properties original = new OrderBackedProperties(); + try { + preprocessed.load(new StringReader(preprocessedContents)); + original.load(new StringReader(contents)); + } catch (IOException e) { + Iris.logger.error("Error loading shaders.properties!", e); + } + + preprocessed.forEach((keyObject, valueObject) -> { + String key = (String) keyObject; + String value = (String) valueObject; + + if ("texture.noise".equals(key)) { + noiseTexturePath = value; + return; + } + + if ("clouds".equals(key)) { + if ("off".equals(value)) { + cloudSetting = CloudSetting.OFF; + } else if ("fast".equals(value)) { + cloudSetting = CloudSetting.FAST; + } else if ("fancy".equals(value)) { + cloudSetting = CloudSetting.FANCY; + } else { + Iris.logger.error("Unrecognized clouds setting: " + value); + } + } + + handleBooleanDirective(key, value, "oldHandLight", bool -> oldHandLight = bool); + handleBooleanDirective(key, value, "dynamicHandLight", bool -> dynamicHandLight = bool); + handleBooleanDirective(key, value, "oldLighting", bool -> oldLighting = bool); + handleBooleanDirective(key, value, "shadowTerrain", bool -> shadowTerrain = bool); + handleBooleanDirective(key, value, "shadowTranslucent", bool -> shadowTranslucent = bool); + handleBooleanDirective(key, value, "shadowEntities", bool -> shadowEntities = bool); + handleBooleanDirective(key, value, "shadowPlayer", bool -> shadowPlayer = bool); + handleBooleanDirective(key, value, "shadowBlockEntities", bool -> shadowBlockEntities = bool); + handleBooleanDirective(key, value, "underwaterOverlay", bool -> underwaterOverlay = bool); + handleBooleanDirective(key, value, "sun", bool -> sun = bool); + handleBooleanDirective(key, value, "moon", bool -> moon = bool); + handleBooleanDirective(key, value, "vignette", bool -> vignette = bool); + handleBooleanDirective(key, value, "backFace.solid", bool -> backFaceSolid = bool); + handleBooleanDirective(key, value, "backFace.cutout", bool -> backFaceCutout = bool); + handleBooleanDirective(key, value, "backFace.cutoutMipped", bool -> backFaceCutoutMipped = bool); + handleBooleanDirective(key, value, "backFace.translucent", bool -> backFaceTranslucent = bool); + handleBooleanDirective(key, value, "rain.depth", bool -> rainDepth = bool); + handleBooleanDirective(key, value, "allowConcurrentCompute", bool -> concurrentCompute = bool); + handleBooleanDirective(key, value, "beacon.beam.depth", bool -> beaconBeamDepth = bool); + handleBooleanDirective(key, value, "separateAo", bool -> separateAo = bool); + handleBooleanDirective(key, value, "frustum.culling", bool -> frustumCulling = bool); + handleBooleanDirective(key, value, "shadow.culling", bool -> shadowCulling = bool); + handleBooleanDirective(key, value, "particles.before.deferred", bool -> particlesBeforeDeferred = bool); + handleBooleanDirective(key, value, "prepareBeforeShadow", bool -> prepareBeforeShadow = bool); + + // TODO: Min optifine versions, shader options layout / appearance / profiles + // TODO: Custom uniforms + + handlePassDirective("scale.", key, value, pass -> { + float scale; + + try { + scale = Float.parseFloat(value); + } catch (NumberFormatException e) { + Iris.logger.error("Unable to parse scale directive for " + pass + ": " + value, e); + return; + } + + viewportScaleOverrides.put(pass, scale); + }); + + handlePassDirective("size.buffer.", key, value, pass -> { + String[] parts = value.split(" "); + + if (parts.length != 2) { + Iris.logger.error("Unable to parse size.buffer directive for " + pass + ": " + value); + return; + } + + textureScaleOverrides.put(pass, new TextureScaleOverride(parts[0], parts[1])); + }); + + handlePassDirective("alphaTest.", key, value, pass -> { + if ("off".equals(value)) { + alphaTestOverrides.put(pass, AlphaTestOverride.OFF); + return; + } + + String[] parts = value.split(" "); + + if (parts.length > 2) { + Iris.logger.warn("Weird alpha test directive for " + pass + " contains more parts than we expected: " + value); + } else if (parts.length < 2) { + Iris.logger.error("Invalid alpha test directive for " + pass + ": " + value); + return; + } + + Optional function = AlphaTestFunction.fromString(parts[0]); + + if (!function.isPresent()) { + Iris.logger.error("Unable to parse alpha test directive for " + pass + ", unknown alpha test function " + parts[0] + ": " + value); + return; + } + + float reference; + + try { + reference = Float.parseFloat(parts[1]); + } catch (NumberFormatException e) { + Iris.logger.error("Unable to parse alpha test directive for " + pass + ": " + value, e); + return; + } + + alphaTestOverrides.put(pass, new AlphaTestOverride(new AlphaTest(function.get(), reference))); + }); + + handlePassDirective("blend.", key, value, pass -> { + if (pass.contains(".")) { + + if (!IrisRenderSystem.supportsBufferBlending()) { + throw new RuntimeException("Buffer blending is not supported on this platform, however it was attempted to be used!"); + } + + String[] parts = pass.split("\\."); + int index = PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.indexOf(parts[1]); + + if (index == -1 && parts[1].startsWith("colortex")) { + String id = parts[1].substring("colortex".length()); + + try { + index = Integer.parseInt(id); + } catch (NumberFormatException e) { + throw new RuntimeException("Failed to parse buffer blend!", e); + } + } + + if (index == -1) { + throw new RuntimeException("Failed to parse buffer blend! index = " + index); + } + + if ("off".equals(value)) { + bufferBlendOverrides.computeIfAbsent(parts[0], list -> new ArrayList<>()).add(new BufferBlendInformation(index, null)); + return; + } + + String[] modeArray = value.split(" "); + int[] modes = new int[modeArray.length]; + + int i = 0; + for (String modeName : modeArray) { + modes[i] = BlendModeFunction.fromString(modeName).get().getGlId(); + i++; + } + + bufferBlendOverrides.computeIfAbsent(parts[0], list -> new ArrayList<>()).add(new BufferBlendInformation(index, new BlendMode(modes[0], modes[1], modes[2], modes[3]))); + + return; + } + + if ("off".equals(value)) { + blendModeOverrides.put(pass, BlendModeOverride.OFF); + return; + } + + String[] modeArray = value.split(" "); + int[] modes = new int[modeArray.length]; + + int i = 0; + for (String modeName : modeArray) { + modes[i] = BlendModeFunction.fromString(modeName).get().getGlId(); + i++; + } + + blendModeOverrides.put(pass, new BlendModeOverride(new BlendMode(modes[0], modes[1], modes[2], modes[3]))); + }); + + handleProgramEnabledDirective("program.", key, value, program -> { + conditionallyEnabledPrograms.put(program, value); + }); + + handleTwoArgDirective("texture.", key, value, (stageName, samplerName) -> { + String[] parts = value.split(" "); + + // TODO: Support raw textures + if (parts.length > 1) { + Iris.logger.warn("Custom texture directive for stage " + stageName + ", sampler " + samplerName + " contains more parts than we expected: " + value); + return; + } + + Optional optionalTextureStage = TextureStage.parse(stageName); + + if (!optionalTextureStage.isPresent()) { + Iris.logger.warn("Unknown texture stage " + "\"" + stageName + "\"," + " ignoring custom texture directive for " + key); + return; + } + + TextureStage stage = optionalTextureStage.get(); + + customTextures.computeIfAbsent(stage, _stage -> new Object2ObjectOpenHashMap<>()) + .put(samplerName, value); + }); + + handleTwoArgDirective("flip.", key, value, (pass, buffer) -> { + handleBooleanValue(key, value, shouldFlip -> { + explicitFlips.computeIfAbsent(pass, _pass -> new Object2BooleanOpenHashMap<>()) + .put(buffer, shouldFlip); + }); + }); + + + handleWhitespacedListDirective(key, value, "iris.features.required", options -> requiredFeatureFlags = options); + handleWhitespacedListDirective(key, value, "iris.features.optional", options -> optionalFeatureFlags = options); + + // TODO: Buffer size directives + // TODO: Conditional program enabling directives + }); + + // We need to use a non-preprocessed property file here since we don't want any weird preprocessor changes to be applied to the screen/value layout. + original.forEach((keyObject, valueObject) -> { + String key = (String) keyObject; + String value = (String) valueObject; + + // Defining "sliders" multiple times in the properties file will only result in + // the last definition being used, should be tested if behavior matches OptiFine + handleWhitespacedListDirective(key, value, "sliders", sliders -> sliderOptions = sliders); + handlePrefixedWhitespacedListDirective("profile.", key, value, profiles::put); + + if (handleIntDirective(key, value, "screen.columns", columns -> mainScreenColumnCount = columns)) { + return; + } + + if (handleAffixedIntDirective("screen.", ".columns", key, value, subScreenColumnCount::put)) { + return; + } + + handleWhitespacedListDirective(key, value, "screen", options -> mainScreenOptions = options); + handlePrefixedWhitespacedListDirective("screen.", key, value, subScreenOptions::put); + }); + } + + private static void handleBooleanValue(String key, String value, BooleanConsumer handler) { + if ("true".equals(value)) { + handler.accept(true); + } else if ("false".equals(value)) { + handler.accept(false); + } else { + Iris.logger.warn("Unexpected value for boolean key " + key + " in shaders.properties: got " + value + ", but expected either true or false"); + } + } + + private static void handleBooleanDirective(String key, String value, String expectedKey, Consumer handler) { + if (!expectedKey.equals(key)) { + return; + } + + if ("true".equals(value)) { + handler.accept(OptionalBoolean.TRUE); + } else if ("false".equals(value)) { + handler.accept(OptionalBoolean.FALSE); + } else { + Iris.logger.warn("Unexpected value for boolean key " + key + " in shaders.properties: got " + value + ", but expected either true or false"); + } + } + + private static boolean handleIntDirective(String key, String value, String expectedKey, Consumer handler) { + if (!expectedKey.equals(key)) { + return false; + } + + try { + int result = Integer.parseInt(value); + + handler.accept(result); + } catch (NumberFormatException nex) { + Iris.logger.warn("Unexpected value for integer key " + key + " in shaders.properties: got " + value + ", but expected an integer"); + } + + return true; + } + + private static boolean handleAffixedIntDirective(String prefix, String suffix, String key, String value, BiConsumer handler) { + if (key.startsWith(prefix) && key.endsWith(suffix)) { + int substrBegin = prefix.length(); + int substrEnd = key.length() - suffix.length(); + + if (substrEnd <= substrBegin) { + return false; + } + + String affixStrippedKey = key.substring(substrBegin, substrEnd); + + try { + int result = Integer.parseInt(value); + + handler.accept(affixStrippedKey, result); + } catch (NumberFormatException nex) { + Iris.logger.warn("Unexpected value for integer key " + key + " in shaders.properties: got " + value + ", but expected an integer"); + } + + return true; + } + + return false; + } + + private static void handlePassDirective(String prefix, String key, String value, Consumer handler) { + if (key.startsWith(prefix)) { + String pass = key.substring(prefix.length()); + + handler.accept(pass); + } + } + + private static void handleProgramEnabledDirective(String prefix, String key, String value, Consumer handler) { + if (key.startsWith(prefix)) { + String program = key.substring(prefix.length(), key.indexOf(".", prefix.length())); + + handler.accept(program); + } + } + + private static void handleWhitespacedListDirective(String key, String value, String expectedKey, Consumer> handler) { + if (!expectedKey.equals(key)) { + return; + } + + String[] elements = value.split(" +"); + + handler.accept(Arrays.asList(elements)); + } + + private static void handlePrefixedWhitespacedListDirective(String prefix, String key, String value, BiConsumer> handler) { + if (key.startsWith(prefix)) { + String prefixStrippedKey = key.substring(prefix.length()); + String[] elements = value.split(" +"); + + handler.accept(prefixStrippedKey, Arrays.asList(elements)); + } + } + + private static void handleTwoArgDirective(String prefix, String key, String value, BiConsumer handler) { + if (key.startsWith(prefix)) { + int endOfPassIndex = key.indexOf(".", prefix.length()); + String stage = key.substring(prefix.length(), endOfPassIndex); + String sampler = key.substring(endOfPassIndex + 1); + + handler.accept(stage, sampler); + } + } + + public static ShaderProperties empty() { + return new ShaderProperties(); + } + + public CloudSetting getCloudSetting() { + return cloudSetting; + } + + public OptionalBoolean getOldHandLight() { + return oldHandLight; + } + + public OptionalBoolean getDynamicHandLight() { + return dynamicHandLight; + } + + public OptionalBoolean getOldLighting() { + return oldLighting; + } + + public OptionalBoolean getShadowTerrain() { + return shadowTerrain; + } + + public OptionalBoolean getShadowTranslucent() { + return shadowTranslucent; + } + + public OptionalBoolean getShadowEntities() { + return shadowEntities; + } + + public OptionalBoolean getShadowPlayer() { + return shadowPlayer; + } + + public OptionalBoolean getShadowBlockEntities() { + return shadowBlockEntities; + } + + public OptionalBoolean getUnderwaterOverlay() { + return underwaterOverlay; + } + + public OptionalBoolean getSun() { + return sun; + } + + public OptionalBoolean getMoon() { + return moon; + } + + public OptionalBoolean getVignette() { + return vignette; + } + + public OptionalBoolean getBackFaceSolid() { + return backFaceSolid; + } + + public OptionalBoolean getBackFaceCutout() { + return backFaceCutout; + } + + public OptionalBoolean getBackFaceCutoutMipped() { + return backFaceCutoutMipped; + } + + public OptionalBoolean getBackFaceTranslucent() { + return backFaceTranslucent; + } + + public OptionalBoolean getRainDepth() { + return rainDepth; + } + + public OptionalBoolean getBeaconBeamDepth() { + return beaconBeamDepth; + } + + public OptionalBoolean getSeparateAo() { + return separateAo; + } + + public OptionalBoolean getFrustumCulling() { + return frustumCulling; + } + + public OptionalBoolean getShadowCulling() { + return shadowCulling; + } + + public OptionalBoolean getShadowEnabled() { + return shadowEnabled; + } + + public OptionalBoolean getParticlesBeforeDeferred() { + return particlesBeforeDeferred; + } + + public OptionalBoolean getConcurrentCompute() { + return concurrentCompute; + } + + public OptionalBoolean getPrepareBeforeShadow() { + return prepareBeforeShadow; + } + + public Object2ObjectMap getAlphaTestOverrides() { + return alphaTestOverrides; + } + + public Object2FloatMap getViewportScaleOverrides() { + return viewportScaleOverrides; + } + + public Object2ObjectMap getTextureScaleOverrides() { + return textureScaleOverrides; + } + + public Object2ObjectMap getBlendModeOverrides() { + return blendModeOverrides; + } + + public Object2ObjectMap> getBufferBlendOverrides() { + return bufferBlendOverrides; + } + + public EnumMap> getCustomTextures() { + return customTextures; + } + + public Optional getNoiseTexturePath() { + return Optional.ofNullable(noiseTexturePath); + } + + public Object2ObjectMap getConditionallyEnabledPrograms() { + return conditionallyEnabledPrograms; + } + + public List getSliderOptions() { + return sliderOptions; + } + + public Map> getProfiles() { + return profiles; + } + + public Optional> getMainScreenOptions() { + return Optional.ofNullable(mainScreenOptions); + } + + public Map> getSubScreenOptions() { + return subScreenOptions; + } + + public Optional getMainScreenColumnCount() { + return Optional.ofNullable(mainScreenColumnCount); + } + + public Map getSubScreenColumnCount() { + return subScreenColumnCount; + } + + public Object2ObjectMap> getExplicitFlips() { + return explicitFlips; + } + + public List getRequiredFeatureFlags() { + return requiredFeatureFlags; + } + + public List getOptionalFeatureFlags() { + return optionalFeatureFlags; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/StringPair.java b/src/main/java/net/coderbot/iris/shaderpack/StringPair.java new file mode 100644 index 000000000..dc3fbc376 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/StringPair.java @@ -0,0 +1,28 @@ +package net.coderbot.iris.shaderpack; + +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +/** + * An absurdly simple class for storing pairs of strings because Java lacks pair / tuple types. + */ +public class StringPair { + private final String key; + private final String value; + + public StringPair(@NotNull String key, @NotNull String value) { + this.key = Objects.requireNonNull(key); + this.value = Objects.requireNonNull(value); + } + + @NotNull + public String getKey() { + return key; + } + + @NotNull + public String getValue() { + return value; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/discovery/ShaderpackDirectoryManager.java b/src/main/java/net/coderbot/iris/shaderpack/discovery/ShaderpackDirectoryManager.java new file mode 100644 index 000000000..1e1bbf1f0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/discovery/ShaderpackDirectoryManager.java @@ -0,0 +1,103 @@ +package net.coderbot.iris.shaderpack.discovery; + +import net.coderbot.iris.Iris; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; +import java.util.Comparator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ShaderpackDirectoryManager { + private final Path root; + + public ShaderpackDirectoryManager(Path root) { + this.root = root; + } + + public void copyPackIntoDirectory(String name, Path source) throws IOException { + Path target = Iris.getShaderpacksDirectory().resolve(name); + + // Copy the pack file into the shaderpacks folder. + Files.copy(source, target); + // Zip or other archive files will be copied without issue, + // however normal folders will require additional handling below. + + // Manually copy the contents of the pack if it is a folder + if (Files.isDirectory(source)) { + // Use for loops instead of forEach due to createDirectory throwing an IOException + // which requires additional handling when used in a lambda + + // Copy all sub folders, collected as a list in order to prevent issues with non-ordered sets + try (Stream stream = Files.walk(source)) { + for (Path p : stream.filter(Files::isDirectory).collect(Collectors.toList())) { + Path folder = source.relativize(p); + + if (Files.exists(folder)) { + continue; + } + + Files.createDirectory(target.resolve(folder)); + } + } + + // Copy all non-folder files + try (Stream stream = Files.walk(source)) { + for (Path p : stream.filter(p -> !Files.isDirectory(p)).collect(Collectors.toSet())) { + Path file = source.relativize(p); + + Files.copy(p, target.resolve(file)); + } + } + } + } + + public Collection enumerate() throws IOException { + // Make sure the list is sorted since not all OSes sort the list of files in the directory. + // Case-insensitive sorting is the most intuitive for the user, but we then sort naturally + // afterwards so that we don't alternate cases weirdly in the sorted list. + // + // We also ignore chat formatting characters when sorting - some shader packs include chat + // formatting in the file name so that they have fancy text when displayed in the shaders list. + Comparator baseComparator = String.CASE_INSENSITIVE_ORDER.thenComparing(Comparator.naturalOrder()); + Comparator comparator = (a, b) -> { + a = removeFormatting(a); + b = removeFormatting(b); + + return baseComparator.compare(a, b); + }; + + try (Stream list = Files.list(root)) { + return list.filter(Iris::isValidShaderpack) + .map(path -> path.getFileName().toString()) + .sorted(comparator).collect(Collectors.toList()); + } + } + + /** + * Straightforward method to use section-sign based chat formatting from a String + */ + private static String removeFormatting(String formatted) { + char[] original = formatted.toCharArray(); + char[] cleaned = new char[original.length]; + int c = 0; + + for (int i = 0; i < original.length; i++) { + // check if it's a section sign + if (original[i] == '\u00a7') { + i++; + } else { + cleaned[c++] = original[i]; + } + } + + return new String(cleaned, 0, c); + } + + public URI getDirectoryUri() { + return root.toUri(); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/error/RusticError.java b/src/main/java/net/coderbot/iris/shaderpack/error/RusticError.java new file mode 100644 index 000000000..4e188d76f --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/error/RusticError.java @@ -0,0 +1,55 @@ +package net.coderbot.iris.shaderpack.error; + +import org.apache.commons.lang3.StringUtils; + +public class RusticError { + private final String severity; + private final String message; + private final String detailMessage; + private final String file; + private final int lineNumber; + private final String badLine; + + public RusticError(String severity, String message, String detailMessage, String file, int lineNumber, String badLine) { + this.severity = severity; + this.message = message; + this.detailMessage = detailMessage; + this.file = file; + this.lineNumber = lineNumber; + this.badLine = badLine; + } + + public String getSeverity() { + return severity; + } + + public String getMessage() { + return message; + } + + public String getDetailMessage() { + return detailMessage; + } + + public String getFile() { + return file; + } + + public int getLineNumber() { + return lineNumber; + } + + public String getBadLine() { + return badLine; + } + + @Override + public String toString() { + return severity + ": " + message + "\n" + + " --> " + file + ":" + lineNumber + "\n" + + " |\n" + + " | " + badLine + "\n" + + " | " + StringUtils.repeat('^', badLine.length()) + " " + detailMessage + "\n" + + " |"; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/include/AbsolutePackPath.java b/src/main/java/net/coderbot/iris/shaderpack/include/AbsolutePackPath.java new file mode 100644 index 000000000..5ab3183ec --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/include/AbsolutePackPath.java @@ -0,0 +1,113 @@ +package net.coderbot.iris.shaderpack.include; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Pattern; + +// TODO: Write tests for this +public class AbsolutePackPath { + private final String path; + + private AbsolutePackPath(String absolute) { + this.path = absolute; + } + + public static AbsolutePackPath fromAbsolutePath(String absolutePath) { + return new AbsolutePackPath(normalizeAbsolutePath(absolutePath)); + } + + public Optional parent() { + if (path.equals("/")) { + return Optional.empty(); + } + + int lastSlash = path.lastIndexOf('/'); + + return Optional.of(new AbsolutePackPath(path.substring(0, lastSlash))); + } + + public AbsolutePackPath resolve(String path) { + if (path.startsWith("/")) { + return fromAbsolutePath(path); + } + + String merged; + + if (!this.path.endsWith("/") & !path.startsWith("/")) { + merged = this.path + "/" + path; + } else { + merged = this.path + path; + } + + return fromAbsolutePath(merged); + } + + public Path resolved(Path root) { + if (path.equals("/")) { + return root; + } + + return root.resolve(path.substring(1)); + } + + private static String normalizeAbsolutePath(String path) { + if (!path.startsWith("/")) { + throw new IllegalArgumentException("Not an absolute path: " + path); + } + + String[] segments = path.split(Pattern.quote("/")); + List parsedSegments = new ArrayList<>(); + + for (String segment : segments) { + if (segment.isEmpty() || segment.equals(".")) { + continue; + } + + if (segment.equals("..")) { + if (!parsedSegments.isEmpty()) { + parsedSegments.remove(parsedSegments.size() - 1); + } + } else { + parsedSegments.add(segment); + } + } + + if (parsedSegments.isEmpty()) { + return "/"; + } + + StringBuilder normalized = new StringBuilder(); + + for (String segment : parsedSegments) { + normalized.append('/'); + normalized.append(segment); + } + + return normalized.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AbsolutePackPath that = (AbsolutePackPath) o; + return Objects.equals(path, that.path); + } + + @Override + public int hashCode() { + return Objects.hash(path); + } + + @Override + public String toString() { + return "AbsolutePackPath {" + getPathString() + "}"; + } + + public String getPathString() { + return path; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/include/FileNode.java b/src/main/java/net/coderbot/iris/shaderpack/include/FileNode.java new file mode 100644 index 000000000..8a87fc044 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/include/FileNode.java @@ -0,0 +1,98 @@ +package net.coderbot.iris.shaderpack.include; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import net.coderbot.iris.shaderpack.transform.line.LineTransform; + +import java.util.Objects; + +public class FileNode { + private final AbsolutePackPath path; + private final ImmutableList lines; + private final ImmutableMap includes; + + // NB: The caller is responsible for ensuring that the includes map + // is in sync with the lines list. + private FileNode(AbsolutePackPath path, ImmutableList lines, + ImmutableMap includes) { + this.path = path; + this.lines = lines; + this.includes = includes; + } + + public FileNode(AbsolutePackPath path, ImmutableList lines) { + this.path = path; + this.lines = lines; + + AbsolutePackPath currentDirectory = path.parent().orElseThrow( + () -> new IllegalArgumentException("Not a valid shader file name: " + path)); + + this.includes = findIncludes(currentDirectory, lines); + } + + public AbsolutePackPath getPath() { + return path; + } + + public ImmutableList getLines() { + return lines; + } + + public ImmutableMap getIncludes() { + return includes; + } + + public FileNode map(LineTransform transform) { + ImmutableList.Builder newLines = ImmutableList.builder(); + int index = 0; + + for (String line : lines) { + String transformedLine = transform.transform(index, line); + + if (includes.containsKey(index)) { + if (!Objects.equals(line, transformedLine)) { + throw new IllegalStateException("Attempted to modify an #include line in LineTransform."); + } + } + + newLines.add(transformedLine); + index += 1; + } + + return new FileNode(path, newLines.build(), includes); + } + + private static ImmutableMap findIncludes(AbsolutePackPath currentDirectory, + ImmutableList lines) { + ImmutableMap.Builder foundIncludes = ImmutableMap.builder(); + + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i).trim(); + + if (!line.startsWith("#include")) { + continue; + } + + // Remove the "#include " part so that we just have the file path + String target = line.substring("#include ".length()).trim(); + + // Remove quotes if they're present + // All include directives should have quotes, but I'm not sure whether they're required to. + // TODO: Check if quotes are required, and don't permit mismatched quotes + // TODO: This shouldn't be accepted: + // #include "test.glsl + // #include test.glsl" + if (target.startsWith("\"")) { + target = target.substring(1); + } + + if (target.endsWith("\"")) { + target = target.substring(0, target.length() - 1); + } + + foundIncludes.put(i, currentDirectory.resolve(target)); + } + + return foundIncludes.build(); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/include/IncludeGraph.java b/src/main/java/net/coderbot/iris/shaderpack/include/IncludeGraph.java new file mode 100644 index 000000000..e1188115b --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/include/IncludeGraph.java @@ -0,0 +1,260 @@ +package net.coderbot.iris.shaderpack.include; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.error.RusticError; +import net.coderbot.iris.shaderpack.transform.line.LineTransform; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +/** + * A directed graph data structure that holds the loaded source of all shader programs + * and the files included by each source file. Each node / vertex in the graph + * corresponds to a single file in the shader pack, and each edge / connection + * corresponds to an {@code #include} directive on a given line. + * + *

Using a proper graph representation allows us to apply existing and + * efficient algorithms with well-known properties to various tasks and + * transformations necessary during shader pack loading. We receive a number of + * immediate benefits from using a graph-based representation:

+ * + *
    + *
  • Each file is read exactly one time, and it is only necessary to + * parse #include directives from a file once. This ensures efficient + * IO. + *
  • + *
  • Deferring the processing of inclusions allows transformers that only + * need to replace single lines at a time to operate more efficiently, + * avoiding processing lines duplicated across many files more than + * necessary. + *
  • + *
  • As a result, our shader configuration system is able to process and + * apply options much more efficiently than a naive one operating on + * included files only, allowing many operations to scale much more + * nicely, especially in the common case of shader pack authors having + * a single large settings file defining every config option that is + * then included in every shader program in the pack. + *
  • + *
  • Deferred processing of inclusions also allows the shader pack loader + * to reason about cyclic inclusions, allowing us to remove the + * arbitrary file include depth limit, and avoid stack overflows due to + * infinite recursion that a naive implementation might be subject to. + *
  • + *
+ */ +public class IncludeGraph { + private final ImmutableMap nodes; + private final ImmutableMap failures; + + private IncludeGraph(ImmutableMap nodes, + ImmutableMap failures) { + this.nodes = nodes; + this.failures = failures; + } + + public IncludeGraph(Path root, ImmutableList startingPaths) { + Map cameFrom = new HashMap<>(); + Map lineNumberInclude = new HashMap<>(); + + Map nodes = new HashMap<>(); + Map failures = new HashMap<>(); + + List queue = new ArrayList<>(startingPaths); + Set seen = new HashSet<>(startingPaths); + + while (!queue.isEmpty()) { + AbsolutePackPath next = queue.remove(queue.size() - 1); + + String source; + + try { + source = readFile(next.resolved(root)); + } catch (IOException e) { + AbsolutePackPath src = cameFrom.get(next); + + if (src == null) { + throw new RuntimeException("unexpected error: failed to read " + next.getPathString(), e); + } + + String topLevelMessage; + String detailMessage; + + if (e instanceof NoSuchFileException) { + topLevelMessage = "failed to resolve #include directive"; + detailMessage = "file not found"; + } else { + topLevelMessage = "unexpected I/O error while resolving #include directive: " + e; + detailMessage = "IO error"; + } + + String badLine = nodes.get(src).getLines().get(lineNumberInclude.get(next)).trim(); + + RusticError topLevelError = new RusticError("error", topLevelMessage, detailMessage, src.getPathString(), + lineNumberInclude.get(next) + 1, badLine); + + failures.put(next, topLevelError); + + continue; + } + + ImmutableList lines = ImmutableList.copyOf(source.split("\\R")); + + FileNode node = new FileNode(next, lines); + boolean selfInclude = false; + + for (Map.Entry include : node.getIncludes().entrySet()) { + int line = include.getKey(); + AbsolutePackPath included = include.getValue(); + + if (next.equals(included)) { + selfInclude = true; + failures.put(next, new RusticError("error", "trivial #include cycle detected", + "file includes itself", next.getPathString(), line + 1, lines.get(line))); + + break; + } else if (!seen.contains(included)) { + queue.add(included); + seen.add(included); + cameFrom.put(included, next); + lineNumberInclude.put(included, line); + } + } + + if (!selfInclude) { + nodes.put(next, node); + } + } + + this.nodes = ImmutableMap.copyOf(nodes); + this.failures = ImmutableMap.copyOf(failures); + + detectCycle(); + } + + private void detectCycle() { + List cycle = new ArrayList<>(); + Set visited = new HashSet<>(); + + for (AbsolutePackPath start : nodes.keySet()) { + if (exploreForCycles(start, cycle, visited)) { + AbsolutePackPath lastFilePath = null; + + StringBuilder error = new StringBuilder(); + + for (AbsolutePackPath node : cycle) { + if (lastFilePath == null) { + lastFilePath = node; + continue; + } + + FileNode lastFile = nodes.get(lastFilePath); + int lineNumber = -1; + + for (Map.Entry include : lastFile.getIncludes().entrySet()) { + if (include.getValue() == node) { + lineNumber = include.getKey() + 1; + } + } + + String badLine = lastFile.getLines().get(lineNumber - 1); + + String detailMessage = node.equals(start) ? "final #include in cycle" : "#include involved in cycle"; + + if (lastFilePath.equals(start)) { + // first node in cycle + error.append(new RusticError("error", "#include cycle detected", + detailMessage, lastFilePath.getPathString(), lineNumber, badLine)); + } else { + error.append("\n = ").append(new RusticError("note", "cycle involves another file", + detailMessage, lastFilePath.getPathString(), lineNumber, badLine)); + } + + lastFilePath = node; + } + + error.append( + "\n = note: #include directives are resolved before any other preprocessor directives, any form of #include guard will not work" + + "\n = note: other cycles may still exist, only the first detected non-trivial cycle will be reported"); + + // TODO: Expose this to the caller (more semantic error handling) + Iris.logger.error(error.toString()); + + throw new IllegalStateException("Cycle detected in #include graph, see previous messages for details"); + } + } + } + + private boolean exploreForCycles(AbsolutePackPath frontier, List path, Set visited) { + if (visited.contains(frontier)) { + path.add(frontier); + return true; + } + + path.add(frontier); + visited.add(frontier); + + for (AbsolutePackPath included : nodes.get(frontier).getIncludes().values()) { + if (!nodes.containsKey(included)) { + // file that failed to load for another reason, error should already be reported + continue; + } + + if (exploreForCycles(included, path, visited)) { + return true; + } + } + + path.remove(path.size() - 1); + visited.remove(frontier); + + return false; + } + + public ImmutableMap getNodes() { + return nodes; + } + + public List computeWeaklyConnectedComponents() { + //List components = new ArrayList<>(); + + // TODO: WCC + //throw new UnsupportedOperationException(); + + //return components; + + // TODO: This digraph might not be weakly connected + // A digraph is weakly connected if its corresponding undirected + // graph is connected + // Make an adjacency list and then go from there + return Collections.singletonList(this); + } + + public IncludeGraph map(Function transformProvider) { + ImmutableMap.Builder mappedNodes = ImmutableMap.builder(); + + nodes.forEach((path, node) -> mappedNodes.put(path, node.map(transformProvider.apply(path)))); + + return new IncludeGraph(mappedNodes.build(), failures); + } + + public ImmutableMap getFailures() { + return failures; + } + + private static String readFile(Path path) throws IOException { + return new String(Files.readAllBytes(path), StandardCharsets.UTF_8); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/include/IncludeProcessor.java b/src/main/java/net/coderbot/iris/shaderpack/include/IncludeProcessor.java new file mode 100644 index 000000000..b06db48cb --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/include/IncludeProcessor.java @@ -0,0 +1,59 @@ +package net.coderbot.iris.shaderpack.include; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +// TODO: Write tests for this code +public class IncludeProcessor { + private final IncludeGraph graph; + private final Map> cache; + + public IncludeProcessor(IncludeGraph graph) { + this.graph = graph; + this.cache = new HashMap<>(); + } + + // TODO: Actual error handling + + public ImmutableList getIncludedFile(AbsolutePackPath path) { + ImmutableList lines = cache.get(path); + + if (lines == null) { + lines = process(path); + cache.put(path, lines); + } + + return lines; + } + + private ImmutableList process(AbsolutePackPath path) { + FileNode fileNode = graph.getNodes().get(path); + + if (fileNode == null) { + return null; + } + + ImmutableList.Builder builder = ImmutableList.builder(); + + ImmutableList lines = fileNode.getLines(); + ImmutableMap includes = fileNode.getIncludes(); + + for (int i = 0; i < lines.size(); i++) { + AbsolutePackPath include = includes.get(i); + + if (include != null) { + // TODO: Don't recurse like this, and check for cycles + // TODO: Better diagnostics + builder.addAll(Objects.requireNonNull(getIncludedFile(include))); + } else { + builder.add(lines.get(i)); + } + } + + return builder.build(); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/include/ShaderPackSourceNames.java b/src/main/java/net/coderbot/iris/shaderpack/include/ShaderPackSourceNames.java new file mode 100644 index 000000000..7709618e0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/include/ShaderPackSourceNames.java @@ -0,0 +1,97 @@ +package net.coderbot.iris.shaderpack.include; + +import com.google.common.collect.ImmutableList; +import net.coderbot.iris.shaderpack.loading.ProgramArrayId; +import net.coderbot.iris.shaderpack.loading.ProgramId; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Enumerates the possible program source file names to + */ +public class ShaderPackSourceNames { + public static final ImmutableList POTENTIAL_STARTS = findPotentialStarts(); + + public static boolean findPresentSources(ImmutableList.Builder starts, Path packRoot, + AbsolutePackPath directory, ImmutableList candidates) throws IOException { + Path directoryPath = directory.resolved(packRoot); + + if (!Files.exists(directoryPath)) { + return false; + } + + boolean anyFound = false; + + Set found; + try (Stream stream = Files.list(directoryPath)) { + found = stream + .map(path -> path.getFileName().toString()) + .collect(Collectors.toSet()); + } + + for (String candidate : candidates) { + if (found.contains(candidate)) { + starts.add(directory.resolve(candidate)); + anyFound = true; + } + } + + return anyFound; + } + + private static ImmutableList findPotentialStarts() { + ImmutableList.Builder potentialFileNames = ImmutableList.builder(); + + // TODO: Iterate over program groups for exact iteration order. + for (ProgramArrayId programArrayId : ProgramArrayId.values()) { + for (int i = 0; i < programArrayId.getNumPrograms(); i++) { + String name = programArrayId.getSourcePrefix(); + String suffix = ""; + + if (i > 0) { + suffix = Integer.toString(i); + } + + addComputeStarts(potentialFileNames, name + suffix); + } + } + + for (ProgramId programId : ProgramId.values()) { + if (programId == ProgramId.Final || programId == ProgramId.Shadow) { + addComputeStarts(potentialFileNames, programId.getSourceName()); + } else { + addStarts(potentialFileNames, programId.getSourceName()); + } + } + + return potentialFileNames.build(); + } + + private static void addStarts(ImmutableList.Builder potentialFileNames, String baseName) { + potentialFileNames.add(baseName + ".vsh"); + potentialFileNames.add(baseName + ".gsh"); + potentialFileNames.add(baseName + ".fsh"); + } + + private static void addComputeStarts(ImmutableList.Builder potentialFileNames, String baseName) { + addStarts(potentialFileNames, baseName); + + for (int j = 0; j < 27; j++) { + String suffix2; + + if (j == 0) { + suffix2 = ""; + } else { + char letter = (char) ('a' + j - 1); + suffix2 = "_" + letter; + } + + potentialFileNames.add(baseName + suffix2 + ".csh"); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramArrayId.java b/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramArrayId.java new file mode 100644 index 000000000..1a1d0a941 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramArrayId.java @@ -0,0 +1,29 @@ +package net.coderbot.iris.shaderpack.loading; + +public enum ProgramArrayId { + ShadowComposite(ProgramGroup.ShadowComposite, 99), + Prepare(ProgramGroup.Prepare, 99), + Deferred(ProgramGroup.Deferred, 99), + Composite(ProgramGroup.Composite, 99), + ; + + private final ProgramGroup group; + private final int numPrograms; + + ProgramArrayId(ProgramGroup group, int numPrograms) { + this.group = group; + this.numPrograms = numPrograms; + } + + public ProgramGroup getGroup() { + return group; + } + + public String getSourcePrefix() { + return group.getBaseName(); + } + + public int getNumPrograms() { + return numPrograms; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramGroup.java b/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramGroup.java new file mode 100644 index 000000000..468a7cd81 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramGroup.java @@ -0,0 +1,22 @@ +package net.coderbot.iris.shaderpack.loading; + +public enum ProgramGroup { + Shadow("shadow"), + ShadowComposite("shadowcomp"), + Prepare("prepare"), + Gbuffers("gbuffers"), + Deferred("deferred"), + Composite("composite"), + Final("final") + ; + + private final String baseName; + + ProgramGroup(String baseName) { + this.baseName = baseName; + } + + public String getBaseName() { + return baseName; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramId.java b/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramId.java new file mode 100644 index 000000000..1ae3ced09 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/loading/ProgramId.java @@ -0,0 +1,90 @@ +package net.coderbot.iris.shaderpack.loading; + +import net.coderbot.iris.gl.blending.BlendMode; +import net.coderbot.iris.gl.blending.BlendModeFunction; +import net.coderbot.iris.gl.blending.BlendModeOverride; + +import java.util.Objects; +import java.util.Optional; + +public enum ProgramId { + Shadow(ProgramGroup.Shadow, ""), + ShadowSolid(ProgramGroup.Shadow, "solid", Shadow), + ShadowCutout(ProgramGroup.Shadow, "cutout", Shadow), + + Basic(ProgramGroup.Gbuffers, "basic"), + Line(ProgramGroup.Gbuffers, "line", Basic), + + Textured(ProgramGroup.Gbuffers, "textured", Basic), + TexturedLit(ProgramGroup.Gbuffers, "textured_lit", Textured), + SkyBasic(ProgramGroup.Gbuffers, "skybasic", Basic), + SkyTextured(ProgramGroup.Gbuffers, "skytextured", Textured), + Clouds(ProgramGroup.Gbuffers, "clouds", Textured), + + Terrain(ProgramGroup.Gbuffers, "terrain", TexturedLit), + TerrainSolid(ProgramGroup.Gbuffers, "terrain_solid", Terrain), + TerrainCutoutMip(ProgramGroup.Gbuffers, "terrain_cutout_mip", Terrain), + TerrainCutout(ProgramGroup.Gbuffers, "terrain_cutout", Terrain), + DamagedBlock(ProgramGroup.Gbuffers, "damagedblock", Terrain), + + Block(ProgramGroup.Gbuffers, "block", Terrain), + BeaconBeam(ProgramGroup.Gbuffers, "beaconbeam", Textured), + Item(ProgramGroup.Gbuffers, "item", TexturedLit), + + Entities(ProgramGroup.Gbuffers, "entities", TexturedLit), + EntitiesTrans(ProgramGroup.Gbuffers, "entities_translucent", Entities), + EntitiesGlowing(ProgramGroup.Gbuffers, "entities_glowing", Entities), + ArmorGlint(ProgramGroup.Gbuffers, "armor_glint", Textured), + SpiderEyes(ProgramGroup.Gbuffers, "spidereyes", Textured, + new BlendModeOverride(new BlendMode(BlendModeFunction.SRC_ALPHA.getGlId(), BlendModeFunction.ONE.getGlId(), BlendModeFunction.ZERO.getGlId(), BlendModeFunction.ONE.getGlId()))), + + Hand(ProgramGroup.Gbuffers, "hand", TexturedLit), + Weather(ProgramGroup.Gbuffers, "weather", TexturedLit), + Water(ProgramGroup.Gbuffers, "water", Terrain), + HandWater(ProgramGroup.Gbuffers, "hand_water", Hand), + + Final(ProgramGroup.Final, ""), + ; + + private final ProgramGroup group; + private final String sourceName; + private final ProgramId fallback; + private final BlendModeOverride defaultBlendOverride; + + ProgramId(ProgramGroup group, String name) { + this.group = group; + this.sourceName = name.isEmpty() ? group.getBaseName() : group.getBaseName() + "_" + name; + this.fallback = null; + this.defaultBlendOverride = null; + } + + ProgramId(ProgramGroup group, String name, ProgramId fallback) { + this.group = group; + this.sourceName = name.isEmpty() ? group.getBaseName() : group.getBaseName() + "_" + name; + this.fallback = Objects.requireNonNull(fallback); + this.defaultBlendOverride = null; + } + + ProgramId(ProgramGroup group, String name, ProgramId fallback, BlendModeOverride defaultBlendOverride) { + this.group = group; + this.sourceName = name.isEmpty() ? group.getBaseName() : group.getBaseName() + "_" + name; + this.fallback = Objects.requireNonNull(fallback); + this.defaultBlendOverride = defaultBlendOverride; + } + + public ProgramGroup getGroup() { + return group; + } + + public String getSourceName() { + return sourceName; + } + + public Optional getFallback() { + return Optional.ofNullable(fallback); + } + + public BlendModeOverride getBlendModeOverride() { + return defaultBlendOverride; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/loading/SourceSet.java b/src/main/java/net/coderbot/iris/shaderpack/loading/SourceSet.java new file mode 100644 index 000000000..fb728561a --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/loading/SourceSet.java @@ -0,0 +1,13 @@ +package net.coderbot.iris.shaderpack.loading; + +import java.util.function.Function; + +// TODO: Actually implement this class. +public class SourceSet { + //private final EnumMap singlePrograms; + //private final EnumMap programArrays; + + public SourceSet(Function sourceProvider) { + + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockEntry.java b/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockEntry.java new file mode 100644 index 000000000..dc02fce40 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockEntry.java @@ -0,0 +1,113 @@ +package net.coderbot.iris.shaderpack.materialmap; + +import net.coderbot.iris.Iris; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class BlockEntry { + private final NamespacedId id; + private final Map propertyPredicates; + + public BlockEntry(NamespacedId id, Map propertyPredicates) { + this.id = id; + this.propertyPredicates = propertyPredicates; + } + + /** + * Parses a block ID entry. + * + * @param entry The string representation of the entry. Must not be empty. + */ + @NotNull + public static BlockEntry parse(@NotNull String entry) { + if (entry.isEmpty()) { + throw new IllegalArgumentException("Called BlockEntry::parse with an empty string"); + } + + // We can assume that this array is of at least array length because the input string is non-empty. + String[] splitStates = entry.split(":"); + + // Trivial case: no states, no namespace + if (splitStates.length == 1) { + return new BlockEntry(new NamespacedId("minecraft", entry), Collections.emptyMap()); + } + + // Less trivial case: no states involved, just a namespace + // + // The first term MUST be a valid ResourceLocation component without an equals sign + // The second term, if it does not contain an equals sign, must be a valid ResourceLocation component. + if (splitStates.length == 2 && !splitStates[1].contains("=")) { + return new BlockEntry(new NamespacedId(splitStates[0], splitStates[1]), Collections.emptyMap()); + } + + // Complex case: One or more states involved... + int statesStart; + NamespacedId id; + + if (splitStates[1].contains("=")) { + // We have an entry of the form "tall_grass:half=upper" + statesStart = 1; + id = new NamespacedId("minecraft", splitStates[0]); + } else { + // We have an entry of the form "minecraft:tall_grass:half=upper" + statesStart = 2; + id = new NamespacedId(splitStates[0], splitStates[1]); + } + + // We must parse each property key=value pair from the state entry. + // + // These pairs act as a filter on the block states. Thus, the shader pack does not have to specify all the + // individual block properties itself; rather, it only specifies the parts of the block state that it wishes + // to filter in/out. + // + // For example, some shader packs may make it so that hanging lantern blocks wave. They will put something of + // the form "lantern:hanging=false" in the ID map as a result. Note, however, that there are also waterlogged + // hanging lanterns, which would have "lantern:hanging=false:waterlogged=true". We must make sure that when the + // shader pack author writes "lantern:hanging=false", that we do not just match that individual state, but that + // we also match the waterlogged variant too. + Map map = new HashMap<>(); + + for (int index = statesStart; index < splitStates.length; index++) { + // Split "key=value" into the key and value + String[] propertyParts = splitStates[index].split("="); + + if (propertyParts.length != 2) { + Iris.logger.warn("Warning: the block ID map entry \"" + entry + "\" could not be fully parsed:"); + Iris.logger.warn("- Block state property filters must be of the form \"key=value\", but " + + splitStates[index] + " is not of that form!"); + + // Continue and ignore the invalid entry. + continue; + } + + map.put(propertyParts[0], propertyParts[1]); + } + + return new BlockEntry(id, map); + } + + public NamespacedId getId() { + return id; + } + + public Map getPropertyPredicates() { + return propertyPredicates; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BlockEntry that = (BlockEntry) o; + return Objects.equals(id, that.id) && Objects.equals(propertyPredicates, that.propertyPredicates); + } + + @Override + public int hashCode() { + return Objects.hash(id, propertyPredicates); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockRenderType.java b/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockRenderType.java new file mode 100644 index 000000000..b2e2525ff --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockRenderType.java @@ -0,0 +1,46 @@ +package net.coderbot.iris.shaderpack.materialmap; + +import java.util.Optional; + +/** + * Defines the possible render types for blocks. + * + * @see + * the corresponding OptiFine documentation. + */ +public enum BlockRenderType { + /** + * Alpha test disabled, blending disabled, mipmaps enabled. + */ + SOLID, + /** + * Alpha test enabled, blending disabled, mipmaps disabled. + * Used for tall grass, normal glass, etc. + */ + CUTOUT, + /** + * Alpha test enabled, blending disabled, mipmaps enabled. + * Used for leaves. + */ + CUTOUT_MIPPED, + /** + * Alpha test enabled (w/ low cutoff), blending enabled, mipmaps enabled. + * Used for stained glass, nether portals, and water. + */ + TRANSLUCENT; + + public static Optional fromString(String name) { + switch (name) { + case "solid": + return Optional.of(SOLID); + case "cutout": + return Optional.of(CUTOUT); + case "cutout_mipped": + return Optional.of(CUTOUT_MIPPED); + case "translucent": + return Optional.of(TRANSLUCENT); + default: + return Optional.empty(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/materialmap/NamespacedId.java b/src/main/java/net/coderbot/iris/shaderpack/materialmap/NamespacedId.java new file mode 100644 index 000000000..30540d2af --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/materialmap/NamespacedId.java @@ -0,0 +1,61 @@ +package net.coderbot.iris.shaderpack.materialmap; + +import java.util.Objects; + +public class NamespacedId { + private final String namespace; + private final String name; + + public NamespacedId(String combined) { + int colonIdx = combined.indexOf(':'); + + if (colonIdx == -1) { + namespace = "minecraft"; + name = combined; + } else { + namespace = combined.substring(0, colonIdx); + name = combined.substring(colonIdx + 1); + } + } + + public NamespacedId(String namespace, String name) { + this.namespace = Objects.requireNonNull(namespace); + this.name = Objects.requireNonNull(name); + } + + public String getNamespace() { + return namespace; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + NamespacedId that = (NamespacedId) o; + + return namespace.equals(that.namespace) && name.equals(that.name); + } + + @Override + public int hashCode() { + return Objects.hash(namespace, name); + } + + @Override + public String toString() { + return "NamespacedId{" + + "namespace='" + namespace + '\'' + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/BaseOption.java b/src/main/java/net/coderbot/iris/shaderpack/option/BaseOption.java new file mode 100644 index 000000000..f1b3615ab --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/BaseOption.java @@ -0,0 +1,40 @@ +package net.coderbot.iris.shaderpack.option; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public abstract class BaseOption { + @NotNull + private final OptionType type; + @NotNull + private final String name; + @Nullable + private final String comment; + + BaseOption(@NotNull OptionType type, @NotNull String name, @Nullable String comment) { + this.type = type; + this.name = name; + + if (comment == null || comment.isEmpty()) { + this.comment = null; + } else { + this.comment = comment; + } + } + + @NotNull + public OptionType getType() { + return type; + } + + @NotNull + public String getName() { + return name; + } + + public Optional getComment() { + return Optional.ofNullable(comment); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/BooleanOption.java b/src/main/java/net/coderbot/iris/shaderpack/option/BooleanOption.java new file mode 100644 index 000000000..089837b83 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/BooleanOption.java @@ -0,0 +1,24 @@ +package net.coderbot.iris.shaderpack.option; + +public final class BooleanOption extends BaseOption { + private final boolean defaultValue; + + public BooleanOption(OptionType type, String name, String comment, boolean defaultValue) { + super(type, name, comment); + + this.defaultValue = defaultValue; + } + + public boolean getDefaultValue() { + return defaultValue; + } + + @Override + public String toString() { + return "BooleanDefineOption{" + + "name=" + getName() + + ", comment=" + getComment() + + ", defaultValue=" + defaultValue + + '}'; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/MergedBooleanOption.java b/src/main/java/net/coderbot/iris/shaderpack/option/MergedBooleanOption.java new file mode 100644 index 000000000..d3ea6963e --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/MergedBooleanOption.java @@ -0,0 +1,50 @@ +package net.coderbot.iris.shaderpack.option; + +import com.google.common.collect.ImmutableSet; +import org.jetbrains.annotations.Nullable; + +public class MergedBooleanOption { + private final BooleanOption option; + private final ImmutableSet locations; + + MergedBooleanOption(BooleanOption option, ImmutableSet locations) { + this.option = option; + this.locations = locations; + } + + public MergedBooleanOption(OptionLocation location, BooleanOption option) { + this.option = option; + this.locations = ImmutableSet.of(location); + } + + @Nullable + public MergedBooleanOption merge(MergedBooleanOption other) { + if (this.option.getDefaultValue() != other.option.getDefaultValue()) { + return null; + } + + BooleanOption option; + + // TODO: Collect all known comments + if (this.option.getComment().isPresent()) { + option = this.option; + } else { + option = other.option; + } + + ImmutableSet.Builder mergedLocations = ImmutableSet.builder(); + + mergedLocations.addAll(this.locations); + mergedLocations.addAll(other.locations); + + return new MergedBooleanOption(option, mergedLocations.build()); + } + + public BooleanOption getOption() { + return option; + } + + public ImmutableSet getLocations() { + return locations; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/MergedStringOption.java b/src/main/java/net/coderbot/iris/shaderpack/option/MergedStringOption.java new file mode 100644 index 000000000..9ab1afe6f --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/MergedStringOption.java @@ -0,0 +1,50 @@ +package net.coderbot.iris.shaderpack.option; + +import com.google.common.collect.ImmutableSet; +import org.jetbrains.annotations.Nullable; + +public class MergedStringOption { + private final StringOption option; + private final ImmutableSet locations; + + MergedStringOption(StringOption option, ImmutableSet locations) { + this.option = option; + this.locations = locations; + } + + public MergedStringOption(OptionLocation location, StringOption option) { + this.option = option; + this.locations = ImmutableSet.of(location); + } + + @Nullable + public MergedStringOption merge(MergedStringOption other) { + if (!this.option.getDefaultValue().equals(other.option.getDefaultValue())) { + return null; + } + + StringOption option; + + // TODO: Collect all known comments + if (this.option.getComment().isPresent()) { + option = this.option; + } else { + option = other.option; + } + + ImmutableSet.Builder mergedLocations = ImmutableSet.builder(); + + mergedLocations.addAll(this.locations); + mergedLocations.addAll(other.locations); + + return new MergedStringOption(option, mergedLocations.build()); + } + + public StringOption getOption() { + return option; + } + + public ImmutableSet getLocations() { + return locations; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/OptionAnnotatedSource.java b/src/main/java/net/coderbot/iris/shaderpack/option/OptionAnnotatedSource.java new file mode 100644 index 000000000..8c0c9b478 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/OptionAnnotatedSource.java @@ -0,0 +1,563 @@ +package net.coderbot.iris.shaderpack.option; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import net.coderbot.iris.shaderpack.OptionalBoolean; +import net.coderbot.iris.shaderpack.include.AbsolutePackPath; +import net.coderbot.iris.shaderpack.option.values.OptionValues; +import net.coderbot.iris.shaderpack.parsing.ParsedString; +import net.coderbot.iris.shaderpack.transform.line.LineTransform; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * This class encapsulates the source code of a single shader source file along with the + * corresponding configurable options within the source file. + *

+ * The shader configuration system revolves around a carefully defined way of directly editing + * shader source files in order to change configuration options. This class handles the first + * step of that process—discovering configurable options from shader source files—as well as + * the final step of that process—editing shader source files to apply the modified values + * of valid configuration options. + *

+ * Intermediate steps of that process include considering the annotated source for all shader + * source files within a shader pack in order to deduplicate options that are common to multiple + * source files, and discarding options that are ambiguous between source files. In addition, + * another step includes loading changed option values from on-disk configuration files. + *

+ * The name "OptionAnnotatedSource" is based on the fact that this class simultaneously + * stores a snapshot of the shader source code at the time of option discovery, as well + * as data for each line ("annotations") about the relevant option represented by that + * line, or alternatively an optional diagnostic message for that line saying why a potential + * option was not parsed as a valid shader option. + *

+ * Note that for the most part, each line of the file is parsed in isolation from every + * other line. This means that option conflicts can arise even within the same source file, + * where option declarations have the same name and type but different default values. + * The only exception to this isolation is + * {@link OptionAnnotatedSource#getBooleanDefineReferences() boolean define reference tracking}, + * which is nevertheless still relatively context-free. + *

+ * The data stored within this class is immutable. This ensures that once you have discovered + * options from a given shader source file, that you may then apply any changed option values + * without having to re-parse the shader source code for options, and without risking having + * the shader source code fall out of sync with the annotations. + */ +public final class OptionAnnotatedSource { + /** + * The content of each line within this shader source file. + */ + private final ImmutableList lines; + + private final ImmutableMap booleanOptions; + private final ImmutableMap stringOptions; + + /** + * Optional diagnostic messages for each line. The parser may notice that though a shader pack + * author may have intended for a line to be a valid option, Iris might have ignored it due to + * a syntax error or some other issue. + * + * These diagnostic messages provide reasons for why Iris decided to ignore a plausible option + * line, as well as hints for how an invalid option line can be modified to be a valid one. + */ + private final ImmutableMap diagnostics; + + /** + * Keeps track of references to boolean #define options. Correlates the name of the #define + * option to one of the lines it was referenced on. + * + * References to boolean #define options that happen in plain #if directives are not analyzed + * for the purposes of determining whether a boolean #define option is referenced or not, to + * match OptiFine behavior. Though this might have originally been an oversight, shader packs + * now anticipate this behavior, so it must be replicated here. Since it would be complex to + * fully parse #if directives, this also makes the code simpler. + * + * Note that for the purposes of "confirming" a boolean #define option, it does not matter + * where the reference occurs in a given file - only that it is used at least once in the + * same "logical file" (that is, a file after all #includes have been processed) as it is + * defined. This is because shader config options are parsed as if all #include directives + * have already been substituted for the relevant file. + */ + // TODO: Use an immutable list type + private final ImmutableMap booleanDefineReferences; + + private static final ImmutableSet VALID_CONST_OPTION_NAMES = ImmutableSet.of( + "shadowMapResolution", + "shadowDistance", + "shadowDistanceRenderMul", + "entityShadowDistanceMul", + "shadowIntervalSize", + "generateShadowMipmap", + "generateShadowColorMipmap", + "shadowHardwareFiltering", + "shadowHardwareFiltering0", + "shadowHardwareFiltering1", + "shadowtex0Mipmap", + "shadowtexMipmap", + "shadowtex1Mipmap", + "shadowcolor0Mipmap", + "shadowColor0Mipmap", + "shadowcolor1Mipmap", + "shadowColor1Mipmap", + "shadowtex0Nearest", + "shadowtexNearest", + "shadow0MinMagNearest", + "shadowtex1Nearest", + "shadow1MinMagNearest", + "shadowcolor0Nearest", + "shadowColor0Nearest", + "shadowColor0MinMagNearest", + "shadowcolor1Nearest", + "shadowColor1Nearest", + "shadowColor1MinMagNearest", + "wetnessHalflife", + "drynessHalflife", + "eyeBrightnessHalflife", + "centerDepthHalflife", + "sunPathRotation", + "ambientOcclusionLevel", + "superSamplingLevel", + "noiseTextureResolution" + ); + + public OptionAnnotatedSource(final String source) { + // Match any valid newline sequence + // https://stackoverflow.com/a/31060125 + this(ImmutableList.copyOf(source.split("\\R"))); + } + + /** + * Parses the lines of a shader source file in order to locate valid options from it. + */ + public OptionAnnotatedSource(final ImmutableList lines) { + this.lines = lines; + + AnnotationsBuilder builder = new AnnotationsBuilder(); + + for (int index = 0; index < lines.size(); index++) { + String line = lines.get(index); + parseLine(builder, index, line); + } + + this.booleanOptions = builder.booleanOptions.build(); + this.stringOptions = builder.stringOptions.build(); + this.diagnostics = builder.diagnostics.build(); + this.booleanDefineReferences = ImmutableMap.copyOf(builder.booleanDefineReferences); + } + + private static void parseLine(AnnotationsBuilder builder, int index, String lineText) { + // Check to see if this line contains anything of interest before we try to parse it. + if (!lineText.contains("#define") + && !lineText.contains("const") + && !lineText.contains("#ifdef") + && !lineText.contains("#ifndef")) { + // Nothing of interest. + return; + } + + // Parse the trimmed form of the line to ignore indentation and trailing whitespace. + ParsedString line = new ParsedString(lineText.trim()); + + if (line.takeLiteral("#ifdef") || line.takeLiteral("#ifndef")) { + // The presence of #ifdef and #ifndef directives is used to determine whether a given + // boolean option should be recognized as a configurable option. + // + // As noted above, #if and #elif directives are not checked even though they may also + // contain references. + parseIfdef(builder, index, line); + } else if (line.takeLiteral("const")) { + parseConst(builder, index, line); + } else if (line.currentlyContains("#define")) { + parseDefineOption(builder, index, line); + } + } + + private static void parseIfdef(AnnotationsBuilder builder, int index, ParsedString line) { + if (!line.takeSomeWhitespace()) { + return; + } + + String name = line.takeWord(); + + line.takeSomeWhitespace(); + + if (name == null || !line.isEnd()) { + return; + } + + builder.booleanDefineReferences + .computeIfAbsent(name, n -> new IntArrayList()).add(index); + } + + private static void parseConst(AnnotationsBuilder builder, int index, ParsedString line) { + // const is already taken. + + if (!line.takeSomeWhitespace()) { + builder.diagnostics.put(index, "Expected whitespace after const and before type declaration"); + return; + } + + boolean isString; + + if (line.takeLiteral("int") || line.takeLiteral("float")) { + isString = true; + } else if (line.takeLiteral("bool")) { + isString = false; + } else { + builder.diagnostics.put(index, "Unexpected type declaration after const. " + + "Expected int, float, or bool. " + + "Vector const declarations cannot be configured using shader options."); + return; + } + + if (!line.takeSomeWhitespace()) { + builder.diagnostics.put(index, "Expected whitespace after type declaration."); + return; + } + + String name = line.takeWord(); + + if (name == null) { + builder.diagnostics.put(index, "Expected name of option after type declaration, " + + "but an unexpected character was detected first."); + return; + } + + line.takeSomeWhitespace(); + + if (!line.takeLiteral("=")) { + builder.diagnostics.put(index, "Unexpected characters before equals sign in const declaration."); + return; + } + + line.takeSomeWhitespace(); + + String value = line.takeWordOrNumber(); + + if (value == null) { + builder.diagnostics.put(index, "Unexpected non-whitespace characters after equals sign"); + return; + } + + line.takeSomeWhitespace(); + + if (!line.takeLiteral(";")) { + builder.diagnostics.put(index, "Value between the equals sign and the semicolon wasn't parsed as a valid word or number."); + return; + } + + line.takeSomeWhitespace(); + + String comment; + + if (line.takeComments()) { + comment = line.takeRest().trim(); + } else if (!line.isEnd()) { + builder.diagnostics.put(index, "Unexpected non-whitespace characters outside of comment after semicolon"); + return; + } else { + comment = null; + } + + if (!isString) { + boolean booleanValue; + + if ("true".equals(value)) { + booleanValue = true; + } else if ("false".equals(value)) { + booleanValue = false; + } else { + builder.diagnostics.put(index, "Expected true or false as the value of a boolean const option, but got " + + value + "."); + return; + } + + if (!VALID_CONST_OPTION_NAMES.contains(name)) { + builder.diagnostics.put(index, "This was a valid const boolean option declaration, but " + name + + " was not recognized as being a name of one of the configurable const options."); + return; + } + + builder.booleanOptions.put(index, new BooleanOption(OptionType.CONST, name, comment, booleanValue)); + return; + } + + if (!VALID_CONST_OPTION_NAMES.contains(name)) { + builder.diagnostics.put(index, "This was a valid const option declaration, but " + name + + " was not recognized as being a name of one of the configurable const options."); + return; + } + + StringOption option = StringOption.create(OptionType.CONST, name, comment, value); + + if (option != null) { + builder.stringOptions.put(index, option); + } else { + builder.diagnostics.put(index, "Ignoring this const option because it is missing an allowed values list" + + "in a comment, but is not a boolean const option."); + } + } + + private static void parseDefineOption(AnnotationsBuilder builder, int index, ParsedString line) { + // Remove the leading comment for processing. + boolean hasLeadingComment = line.takeComments(); + + // allow but do not require whitespace between comments and #define + line.takeSomeWhitespace(); + + if (!line.takeLiteral("#define")) { + builder.diagnostics.put(index, + "This line contains an occurrence of \"#define\" " + + "but it wasn't in a place we expected, ignoring it."); + return; + } + + if (!line.takeSomeWhitespace()) { + builder.diagnostics.put(index, + "This line properly starts with a #define statement but doesn't have " + + "any whitespace characters after the #define."); + return; + } + + String name = line.takeWord(); + + if (name == null) { + builder.diagnostics.put(index, + "Invalid syntax after #define directive. " + + "No alphanumeric or underscore characters detected."); + return; + } + + // Maybe take some whitespace + boolean tookWhitespace = line.takeSomeWhitespace(); + + if (line.isEnd()) { + // Plain define directive without a comment. + builder.booleanOptions.put(index, new BooleanOption(OptionType.DEFINE, name, null, !hasLeadingComment)); + return; + } + + if (line.takeComments()) { + // Note that this is a bare comment, we don't need to look for the allowed values part. + // Obviously that part isn't necessary since boolean options only have two possible + // values (true and false) + String comment = line.takeRest().trim(); + + builder.booleanOptions.put(index, new BooleanOption(OptionType.DEFINE, name, comment, !hasLeadingComment)); + return; + } else if (!tookWhitespace) { + // Invalid syntax. + builder.diagnostics.put(index, + "Invalid syntax after #define directive. Only alphanumeric or underscore " + + "characters are allowed in option names."); + + return; + } + + if (hasLeadingComment) { + builder.diagnostics.put(index, + "Ignoring potential non-boolean #define option since it has a leading comment. " + + "Leading comments (//) are only allowed on boolean #define options."); + return; + } + + String value = line.takeWordOrNumber(); + + if (value == null) { + builder.diagnostics.put(index, "Ignoring this #define directive because it doesn't appear to be a boolean #define, " + + "and its potential value wasn't a valid number or a valid word."); + return; + } + + tookWhitespace = line.takeSomeWhitespace(); + + if (line.isEnd()) { + builder.diagnostics.put(index, "Ignoring this #define because it doesn't have a comment containing" + + " a list of allowed values afterwards, but it has a value so is therefore not a boolean."); + return; + } else if (!tookWhitespace) { + if (!line.takeComments()) { + builder.diagnostics.put(index, + "Invalid syntax after value #define directive. " + + "Invalid characters after number or word."); + return; + } + } else if (!line.takeComments()) { + builder.diagnostics.put(index, + "Invalid syntax after value #define directive. " + + "Only comments may come after the value."); + return; + } + + String comment = line.takeRest().trim(); + + StringOption option = StringOption.create(OptionType.DEFINE, name, comment, value); + + if (option == null) { + builder.diagnostics.put(index, "Ignoring this #define because it is missing an allowed values list" + + "in a comment, but is not a boolean define."); + return; + } + + builder.stringOptions.put(index, option); + + /* + //#define SHADOWS // Whether shadows are enabled + SHADOWS // Whether shadows are enabled + // Whether shadows are enabled + Whether shadows are enabled + + + + #define OPTION 0.5 // A test option + OPTION 0.5 // A test option + 0.5 // A test option + */ + } + + public ImmutableMap getBooleanOptions() { + return booleanOptions; + } + + public ImmutableMap getStringOptions() { + return stringOptions; + } + + public ImmutableMap getDiagnostics() { + return diagnostics; + } + + public ImmutableMap getBooleanDefineReferences() { + return booleanDefineReferences; + } + + public OptionSet getOptionSet(AbsolutePackPath filePath, Set booleanDefineReferences) { + OptionSet.Builder builder = OptionSet.builder(); + + booleanOptions.forEach((lineIndex, option) -> { + if (booleanDefineReferences.contains(option.getName())) { + OptionLocation location = new OptionLocation(filePath, lineIndex); + builder.addBooleanOption(location, option); + } + }); + + stringOptions.forEach((lineIndex, option) -> { + OptionLocation location = new OptionLocation(filePath, lineIndex); + builder.addStringOption(location, option); + }); + + return builder.build(); + } + + public LineTransform asTransform(OptionValues values) { + return (index, line) -> edit(values, index, line); + } + + public String apply(OptionValues values) { + StringBuilder source = new StringBuilder(); + + for (int index = 0; index < lines.size(); index++) { + source.append(edit(values, index, lines.get(index))); + source.append('\n'); + } + + return source.toString(); + } + + private String edit(OptionValues values, int index, String existing) { + // See if it's a boolean option + BooleanOption booleanOption = booleanOptions.get(index); + + if (booleanOption != null) { + OptionalBoolean value = values.getBooleanValue(booleanOption.getName()); + if (booleanOption.getType() == OptionType.DEFINE) { + return setBooleanDefineValue(existing, value, booleanOption.getDefaultValue()); + } else if (booleanOption.getType() == OptionType.CONST) { + if (value != OptionalBoolean.DEFAULT) { + // Value will never be default here, but we're using orElse just to get a normal boolean out of it. + return editConst(existing, Boolean.toString(booleanOption.getDefaultValue()), Boolean.toString(value.orElse(booleanOption.getDefaultValue()))); + } else { + return existing; + } + } else { + throw new AssertionError("Unknown option type " + booleanOption.getType()); + } + } + + StringOption stringOption = stringOptions.get(index); + + if (stringOption != null) { + return values.getStringValue(stringOption.getName()).map(value -> { + if (stringOption.getType() == OptionType.DEFINE) { + return "#define " + stringOption.getName() + " " + value + " // OptionAnnotatedSource: Changed option"; + } else if (stringOption.getType() == OptionType.CONST) { + return editConst(existing, stringOption.getDefaultValue(), value); + } else { + throw new AssertionError("Unknown option type " + stringOption.getType()); + } + }).orElse(existing); + } + + return existing; + } + + private String editConst(String line, String currentValue, String newValue) { + int equalsIndex = line.indexOf('='); + + if (equalsIndex == -1) { + // This shouldn't be possible. + throw new IllegalStateException(); + } + + String firstPart = line.substring(0, equalsIndex); + String secondPart = line.substring(equalsIndex); + + secondPart = secondPart.replaceFirst(Pattern.quote(currentValue), Matcher.quoteReplacement(newValue)); + + return firstPart + secondPart; + } + + private static boolean hasLeadingComment(String line) { + return line.trim().startsWith("//"); + } + + private static String removeLeadingComment(String line) { + ParsedString parsed = new ParsedString(line); + + parsed.takeSomeWhitespace(); + parsed.takeComments(); + + return parsed.takeRest(); + } + + private static String setBooleanDefineValue(String line, OptionalBoolean newValue, boolean defaultValue) { + if (hasLeadingComment(line) && newValue.orElse(defaultValue)) { + return removeLeadingComment(line); + } else if (!newValue.orElse(defaultValue)) { + return "//" + line; + } else { + return line; + } + } + + private static class AnnotationsBuilder { + private final ImmutableMap.Builder booleanOptions; + private final ImmutableMap.Builder stringOptions; + private final ImmutableMap.Builder diagnostics; + private final Map booleanDefineReferences; + + private AnnotationsBuilder() { + booleanOptions = ImmutableMap.builder(); + stringOptions = ImmutableMap.builder(); + diagnostics = ImmutableMap.builder(); + booleanDefineReferences = new HashMap<>(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/OptionLocation.java b/src/main/java/net/coderbot/iris/shaderpack/option/OptionLocation.java new file mode 100644 index 000000000..36a078dd5 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/OptionLocation.java @@ -0,0 +1,29 @@ +package net.coderbot.iris.shaderpack.option; + +import net.coderbot.iris.shaderpack.include.AbsolutePackPath; + +/** + * Encapsulates a single location of an option. + */ +public class OptionLocation { + private final AbsolutePackPath filePath; + private final int lineIndex; + + public OptionLocation(AbsolutePackPath filePath, int lineIndex) { + this.filePath = filePath; + this.lineIndex = lineIndex; + } + + public AbsolutePackPath getFilePath() { + return filePath; + } + + /** + * Gets the index of the line this option is on. + * Note that this is the index - so the first line is + * 0, the second is 1, etc. + */ + public int getLineIndex() { + return lineIndex; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/OptionSet.java b/src/main/java/net/coderbot/iris/shaderpack/option/OptionSet.java new file mode 100644 index 000000000..27db1825c --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/OptionSet.java @@ -0,0 +1,113 @@ +package net.coderbot.iris.shaderpack.option; + +import com.google.common.collect.ImmutableMap; +import net.coderbot.iris.Iris; + +import java.util.HashMap; +import java.util.Map; + +public class OptionSet { + private final ImmutableMap booleanOptions; + private final ImmutableMap stringOptions; + + private OptionSet(Builder builder) { + this.booleanOptions = ImmutableMap.copyOf(builder.booleanOptions); + this.stringOptions = ImmutableMap.copyOf(builder.stringOptions); + } + + public ImmutableMap getBooleanOptions() { + return this.booleanOptions; + } + + public ImmutableMap getStringOptions() { + return this.stringOptions; + } + + public boolean isBooleanOption(String name) { + return booleanOptions.containsKey(name); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private final Map booleanOptions; + private final Map stringOptions; + + public Builder() { + this.booleanOptions = new HashMap<>(); + this.stringOptions = new HashMap<>(); + } + + public void addAll(OptionSet other) { + if (this.booleanOptions.isEmpty()) { + this.booleanOptions.putAll(other.booleanOptions); + } else { + other.booleanOptions.values().forEach(this::addBooleanOption); + } + + if (this.stringOptions.isEmpty()) { + this.stringOptions.putAll(other.stringOptions); + } else { + other.stringOptions.values().forEach(this::addStringOption); + } + } + + public void addBooleanOption(OptionLocation location, BooleanOption option) { + addBooleanOption(new MergedBooleanOption(location, option)); + } + + public void addBooleanOption(MergedBooleanOption proposed) { + BooleanOption option = proposed.getOption(); + MergedBooleanOption existing = booleanOptions.get(option.getName()); + + MergedBooleanOption merged; + + if (existing != null) { + merged = existing.merge(proposed); + + if (merged == null) { + // TODO: Warn about ambiguous options better + Iris.logger.warn("Ignoring ambiguous boolean option " + option.getName()); + booleanOptions.remove(option.getName()); + return; + } + } else { + merged = proposed; + } + + booleanOptions.put(option.getName(), merged); + } + + public void addStringOption(OptionLocation location, StringOption option) { + addStringOption(new MergedStringOption(location, option)); + } + + public void addStringOption(MergedStringOption proposed) { + StringOption option = proposed.getOption(); + MergedStringOption existing = stringOptions.get(option.getName()); + + MergedStringOption merged; + + if (existing != null) { + merged = existing.merge(proposed); + + if (merged == null) { + // TODO: Warn about ambiguous options better + Iris.logger.warn("Ignoring ambiguous string option " + option.getName()); + stringOptions.remove(option.getName()); + return; + } + } else { + merged = proposed; + } + + stringOptions.put(option.getName(), merged); + } + + public OptionSet build() { + return new OptionSet(this); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/OptionTests.java b/src/main/java/net/coderbot/iris/shaderpack/option/OptionTests.java new file mode 100644 index 000000000..395969cd4 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/OptionTests.java @@ -0,0 +1,68 @@ +package net.coderbot.iris.shaderpack.option; + +import com.google.common.collect.ImmutableList; +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +public class OptionTests { + public static void main(String[] args) throws IOException { + List lines = Files.readAllLines(Paths.get("run/shaderpacks/Sildurs Vibrant Shaders v1.29 Medium/shaders/shaders.settings")); + + OptionAnnotatedSource source = new OptionAnnotatedSource(ImmutableList.copyOf(lines)); + + System.out.println("Boolean Options:"); + + if (source.getBooleanOptions().isEmpty()) { + System.out.println("(none)"); + } else { + System.out.println("[Line] Type | Name | Value | Comment"); + System.out.println(" ------ | -------------------------------- | ----- | -------"); + } + + source.getBooleanOptions().forEach((index, option) -> { + String type = option.getType() == OptionType.CONST ? " Const" : "Define"; + + System.out.println( + "[" + StringUtils.leftPad(Integer.toString(index + 1), 4, ' ') + "] " + type + " | " + + StringUtils.rightPad(option.getName(), 32, ' ') + " | " + + StringUtils.leftPad(Boolean.toString(option.getDefaultValue()), 5, ' ') + + " | " + option.getComment().orElse("")); + }); + + + System.out.println("String Options:"); + + if (source.getStringOptions().isEmpty()) { + System.out.println("(none)"); + } else { + System.out.println("[Line] | Type | Name | Value | Allowed Values"); + System.out.println(" | ------ | -------------------------------- | -------- | -------"); + } + + source.getStringOptions().forEach((index, option) -> { + String type = option.getType() == OptionType.CONST ? " Const" : "Define"; + + System.out.println( + "[" + StringUtils.leftPad(Integer.toString(index + 1), 4, ' ') + "] | " + type + " | " + + StringUtils.rightPad(option.getName(), 32, ' ') + " | " + + StringUtils.leftPad(option.getDefaultValue(), 8, ' ') + + " | " + option.getAllowedValues()); + System.out.println(" " + option.getComment().orElse("(no comment)")); + }); + + System.out.println("Diagnostics:"); + source.getDiagnostics().forEach((index, diagnostic) -> { + System.out.println( + "[" + StringUtils.leftPad(Integer.toString(index + 1), 4, ' ') + "] " + + diagnostic); + }); + + if (source.getDiagnostics().isEmpty()) { + System.out.println("(none)"); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/OptionType.java b/src/main/java/net/coderbot/iris/shaderpack/option/OptionType.java new file mode 100644 index 000000000..8ff93bf9a --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/OptionType.java @@ -0,0 +1,5 @@ +package net.coderbot.iris.shaderpack.option; + +public enum OptionType { + DEFINE, CONST +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/Profile.java b/src/main/java/net/coderbot/iris/shaderpack/option/Profile.java new file mode 100644 index 000000000..4f6620f48 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/Profile.java @@ -0,0 +1,81 @@ +package net.coderbot.iris.shaderpack.option; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import net.coderbot.iris.shaderpack.option.values.OptionValues; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class Profile { + public final String name; + public final int precedence; // Used for prioritizing during matching + public final Map optionValues; + public final List disabledPrograms; + + private Profile(String name, Map optionValues, List disabledPrograms) { + this.name = name; + this.optionValues = optionValues; + this.precedence = optionValues.size(); + this.disabledPrograms = disabledPrograms; + } + + public boolean matches(OptionSet options, OptionValues values) { + for (Map.Entry entry : this.optionValues.entrySet()) { + String option = entry.getKey(); + String value = entry.getValue(); + + if (options.getBooleanOptions().containsKey(option)) { + boolean currentValue = values.getBooleanValueOrDefault(option); + + if (!Boolean.toString(currentValue).equals(value)) { + return false; + } + } + if (options.getStringOptions().containsKey(option)) { + String currentValue = values.getStringValueOrDefault(option); + + if (!value.equals(currentValue)) { + return false; + } + } + } + + return true; + } + + public static class Builder { + private final String name; + private final Map optionValues = new HashMap<>(); + private final List disabledPrograms = new ArrayList<>(); + + public Builder(String name) { + this.name = name; + } + + public Builder option(String optionId, String value) { + this.optionValues.put(optionId, value); + + return this; + } + + public Builder disableProgram(String programId) { + this.disabledPrograms.add(programId); + + return this; + } + + public Builder addAll(Profile other) { + this.optionValues.putAll(other.optionValues); + this.disabledPrograms.addAll(other.disabledPrograms); + + return this; + } + + public Profile build() { + return new Profile(name, ImmutableMap.copyOf(optionValues), ImmutableList.copyOf(disabledPrograms)); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/ProfileSet.java b/src/main/java/net/coderbot/iris/shaderpack/option/ProfileSet.java new file mode 100644 index 000000000..fd6f086b7 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/ProfileSet.java @@ -0,0 +1,130 @@ +package net.coderbot.iris.shaderpack.option; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.IrisLogging; +import net.coderbot.iris.shaderpack.option.values.OptionValues; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiConsumer; + +public class ProfileSet { + private final LinkedHashMap orderedProfiles; // The order that profiles should cycle through + private final List sortedProfiles; // The order that profiles should be scanned through + + public ProfileSet(LinkedHashMap orderedProfiles) { + List sorted = new ArrayList<>(orderedProfiles.values()); + + Comparator lowToHigh = Comparator.comparing(p -> p.precedence); + Comparator highToLow = lowToHigh.reversed(); + + // Compare profiles with many constraints (high precedence) first before comparing ones with + // few constraints, needed for accurate matching when one profile contains an additional constraint + // to another profile but is otherwise the same; + sorted.sort(highToLow); + + if (IrisLogging.ENABLE_SPAM) { + sorted.forEach(p -> System.out.println(p.name + ":" + p.precedence)); + } + + this.sortedProfiles = sorted; + this.orderedProfiles = orderedProfiles; + } + + public void forEach(BiConsumer action) { + orderedProfiles.forEach(action); + } + + public ProfileResult scan(OptionSet options, OptionValues values) { + if (sortedProfiles.size() <= 0) { + return new ProfileResult(null, null, null); + } + + for (int i = 0; i < sortedProfiles.size(); i++) { + Profile current = sortedProfiles.get(i); + + if (current.matches(options, values)) { + Profile next = sortedProfiles.get(Math.floorMod(i + 1, sortedProfiles.size())); + Profile prev = sortedProfiles.get(Math.floorMod(i - 1, sortedProfiles.size())); + + return new ProfileResult(current, next, prev); + } + } + + // Default return if no profiles matched + Profile next = sortedProfiles.get(0); + Profile prev = sortedProfiles.get(sortedProfiles.size() - 1); + + return new ProfileResult(null, next, prev); + } + + public static ProfileSet fromTree(Map> tree, OptionSet optionSet) { + LinkedHashMap profiles = new LinkedHashMap<>(); + + for (String name : tree.keySet()) { + profiles.put(name, parse(name, new ArrayList<>(), tree, optionSet)); + } + + return new ProfileSet(profiles); + } + + private static Profile parse(String name, List parents, Map> tree, OptionSet optionSet) throws IllegalArgumentException { + Profile.Builder builder = new Profile.Builder(name); + List options = tree.get(name); + + if (options == null) { + throw new IllegalArgumentException("Profile \"" + name + "\" does not exist!"); + } + + for (String option : options) { + if (option.startsWith("!program.")) { + builder.disableProgram(option.substring("!program.".length())); + } else if (option.startsWith("profile.")) { + String dependency = option.substring("profile.".length()); + + if (parents.contains(dependency)) { + throw new IllegalArgumentException("Error parsing profile \"" + name + + "\", recursively included by: " + String.join(", ", parents)); + } + + parents.add(dependency); + builder.addAll(parse(dependency, parents, tree, optionSet)); + } else if (option.startsWith("!")) { + builder.option(option.substring(1), "false"); + } else if (option.contains("=")) { + int splitPoint = option.indexOf("="); + builder.option(option.substring(0, splitPoint), option.substring(splitPoint + 1)); + } else if (option.contains(":")) { + int splitPoint = option.indexOf(":"); + builder.option(option.substring(0, splitPoint), option.substring(splitPoint + 1)); + } else if (optionSet.isBooleanOption(option)) { + builder.option(option, "true"); + } else { + Iris.logger.warn("Invalid pack option: " + option); + } + } + + return builder.build(); + } + + public int size() { + return sortedProfiles.size(); + } + + public static class ProfileResult { + public final Optional current; + public final Profile next; + public final Profile previous; + + private ProfileResult(@Nullable Profile current, Profile next, Profile previous) { + this.current = Optional.ofNullable(current); + this.next = next; + this.previous = previous; + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/ShaderPackOptions.java b/src/main/java/net/coderbot/iris/shaderpack/option/ShaderPackOptions.java new file mode 100644 index 000000000..d3aabb954 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/ShaderPackOptions.java @@ -0,0 +1,66 @@ +package net.coderbot.iris.shaderpack.option; + +import com.google.common.collect.ImmutableMap; +import net.coderbot.iris.shaderpack.include.AbsolutePackPath; +import net.coderbot.iris.shaderpack.include.IncludeGraph; +import net.coderbot.iris.shaderpack.option.values.MutableOptionValues; +import net.coderbot.iris.shaderpack.option.values.OptionValues; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * A helper class that dispatches all the heavy lifting needed to discover, merge, and apply shader pack options to + * an existing {@link IncludeGraph}. + */ +public class ShaderPackOptions { + private final OptionSet optionSet; + private final OptionValues optionValues; + private final IncludeGraph includes; + + public ShaderPackOptions(IncludeGraph graph, Map changedConfigs) { + Map allAnnotations = new HashMap<>(); + OptionSet.Builder setBuilder = OptionSet.builder(); + + graph.computeWeaklyConnectedComponents().forEach(subgraph -> { + ImmutableMap.Builder annotationBuilder = ImmutableMap.builder(); + Set referencedBooleanDefines = new HashSet<>(); + + subgraph.getNodes().forEach((path, node) -> { + OptionAnnotatedSource annotatedSource = new OptionAnnotatedSource(node.getLines()); + annotationBuilder.put(path, annotatedSource); + referencedBooleanDefines.addAll(annotatedSource.getBooleanDefineReferences().keySet()); + }); + + ImmutableMap annotations = annotationBuilder.build(); + Set referencedBooleanDefinesU = Collections.unmodifiableSet(referencedBooleanDefines); + + annotations.forEach((path, annotatedSource) -> { + OptionSet set = annotatedSource.getOptionSet(path, referencedBooleanDefinesU); + setBuilder.addAll(set); + }); + + allAnnotations.putAll(annotations); + }); + + this.optionSet = setBuilder.build(); + this.optionValues = new MutableOptionValues(optionSet, changedConfigs); + + this.includes = graph.map(path -> allAnnotations.get(path).asTransform(optionValues)); + } + + public OptionSet getOptionSet() { + return optionSet; + } + + public OptionValues getOptionValues() { + return optionValues; + } + + public IncludeGraph getIncludes() { + return includes; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/StringOption.java b/src/main/java/net/coderbot/iris/shaderpack/option/StringOption.java new file mode 100644 index 000000000..791b6a534 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/StringOption.java @@ -0,0 +1,76 @@ +package net.coderbot.iris.shaderpack.option; + +import com.google.common.collect.ImmutableList; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public class StringOption extends BaseOption { + private final String defaultValue; + private final ImmutableList allowedValues; + + private StringOption(OptionType type, String name, String defaultValue) { + super(type, name, null); + + this.defaultValue = Objects.requireNonNull(defaultValue); + this.allowedValues = ImmutableList.of(defaultValue); + } + + private StringOption(OptionType type, String name, String comment, String defaultValue, ImmutableList allowedValues) { + super(type, name, comment); + + this.defaultValue = Objects.requireNonNull(defaultValue); + this.allowedValues = allowedValues; + } + + @Nullable + public static StringOption create(OptionType type, String name, String comment, String defaultValue) { + if (comment == null) { + return null; + } + + int openingBracket = comment.indexOf('['); + + if (openingBracket == -1) { + return null; + } + + int closingBracket = comment.indexOf(']', openingBracket); + + if (closingBracket == -1) { + return null; + } + + String[] allowedValues = comment.substring(openingBracket + 1, closingBracket).split(" "); + comment = comment.substring(0, openingBracket) + comment.substring(closingBracket + 1); + boolean allowedValuesContainsDefaultValue = false; + + for (String value : allowedValues) { + if (defaultValue.equals(value)) { + allowedValuesContainsDefaultValue = true; + break; + } + } + + ImmutableList.Builder builder = ImmutableList.builder(); + + builder.add(allowedValues); + + if (!allowedValuesContainsDefaultValue) { + builder.add(defaultValue); + } + + return new StringOption(type, name, comment.trim(), defaultValue, builder.build()); + } + + @NotNull + public String getDefaultValue() { + return defaultValue; + } + + @NotNull + public ImmutableList getAllowedValues() { + return allowedValues; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuBooleanOptionElement.java b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuBooleanOptionElement.java new file mode 100644 index 000000000..d40ee3539 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuBooleanOptionElement.java @@ -0,0 +1,14 @@ +package net.coderbot.iris.shaderpack.option.menu; + +import net.coderbot.iris.shaderpack.ShaderProperties; +import net.coderbot.iris.shaderpack.option.BooleanOption; +import net.coderbot.iris.shaderpack.option.values.OptionValues; + +public class OptionMenuBooleanOptionElement extends OptionMenuOptionElement { + public final BooleanOption option; + + public OptionMenuBooleanOptionElement(String elementString, OptionMenuContainer container, ShaderProperties shaderProperties, OptionValues values, BooleanOption option) { + super(elementString, container, shaderProperties, values); + this.option = option; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuContainer.java b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuContainer.java new file mode 100644 index 000000000..fa4712978 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuContainer.java @@ -0,0 +1,89 @@ +package net.coderbot.iris.shaderpack.option.menu; + +import com.google.common.collect.Lists; +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.ShaderProperties; +import net.coderbot.iris.shaderpack.option.ProfileSet; +import net.coderbot.iris.shaderpack.option.ShaderPackOptions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class OptionMenuContainer { + public final OptionMenuElementScreen mainScreen; + public final Map subScreens = new HashMap<>(); + + private final List usedOptionElements = new ArrayList<>(); + private final List usedOptions = new ArrayList<>(); + private final List unusedOptions = new ArrayList<>(); // To be used when screens contain a "*" element + private final Map, Integer> unusedOptionDumpQueue = new HashMap<>(); // Used by screens with "*" element + private final ProfileSet profiles; + + public OptionMenuContainer(ShaderProperties shaderProperties, ShaderPackOptions shaderPackOptions, ProfileSet profiles) { + this.profiles = profiles; + + // note: if the Shader Pack does not provide a list of options for the main screen, then dump all options on to + // the main screen by default. + this.mainScreen = new OptionMenuMainElementScreen( + this, shaderProperties, shaderPackOptions, + shaderProperties.getMainScreenOptions().orElseGet(() -> Collections.singletonList("*")), + shaderProperties.getMainScreenColumnCount()); + + this.unusedOptions.addAll(shaderPackOptions.getOptionSet().getBooleanOptions().keySet()); + this.unusedOptions.addAll(shaderPackOptions.getOptionSet().getStringOptions().keySet()); + + Map subScreenColumnCounts = shaderProperties.getSubScreenColumnCount(); + shaderProperties.getSubScreenOptions().forEach((screenKey, options) -> { + subScreens.put(screenKey, new OptionMenuSubElementScreen( + screenKey, this, shaderProperties, shaderPackOptions, options, Optional.ofNullable(subScreenColumnCounts.get(screenKey)))); + }); + + // Dump all unused options into screens containing "*" + for (Map.Entry, Integer> entry : unusedOptionDumpQueue.entrySet()) { + List elementsToInsert = new ArrayList<>(); + List unusedOptionsCopy = Lists.newArrayList(this.unusedOptions); + + for (String optionId : unusedOptionsCopy) { + try { + OptionMenuElement element = OptionMenuElement.create(optionId, this, shaderProperties, shaderPackOptions); + if (element != null) { + elementsToInsert.add(element); + + if (element instanceof OptionMenuOptionElement) { + this.notifyOptionAdded(optionId, (OptionMenuOptionElement) element); + } + } + } catch (IllegalArgumentException error) { + Iris.logger.warn(error); + + elementsToInsert.add(OptionMenuElement.EMPTY); + } + } + + entry.getKey().addAll(entry.getValue(), elementsToInsert); + } + } + + public ProfileSet getProfiles() { + return profiles; + } + + // Screens will call this when they contain a "*" element, so that the list of + // unused options can be added after all other screens have been resolved + public void queueForUnusedOptionDump(int index, List elementList) { + this.unusedOptionDumpQueue.put(elementList, index); + } + + public void notifyOptionAdded(String optionId, OptionMenuOptionElement option) { + if (!usedOptions.contains(optionId)) { + usedOptionElements.add(option); + usedOptions.add(optionId); + } + + unusedOptions.remove(optionId); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuElement.java b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuElement.java new file mode 100644 index 000000000..1e784534f --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuElement.java @@ -0,0 +1,45 @@ +package net.coderbot.iris.shaderpack.option.menu; + +import net.coderbot.iris.shaderpack.ShaderProperties; +import net.coderbot.iris.shaderpack.option.MergedBooleanOption; +import net.coderbot.iris.shaderpack.option.MergedStringOption; +import net.coderbot.iris.shaderpack.option.ShaderPackOptions; + +import java.util.Map; + +public abstract class OptionMenuElement { + public static final OptionMenuElement EMPTY = new OptionMenuElement() {}; + + private static final String ELEMENT_EMPTY = ""; + private static final String ELEMENT_PROFILE = ""; + + public static OptionMenuElement create(String elementString, OptionMenuContainer container, ShaderProperties shaderProperties, ShaderPackOptions shaderPackOptions) throws IllegalArgumentException { + // Empty element + if (ELEMENT_EMPTY.equals(elementString)) { + return EMPTY; + } + // Profile element + // NB: We don't want to add a profile element if there aren't profiles, even if it's requested. TODO: add this to diagnostics? (lp) + if (ELEMENT_PROFILE.equals(elementString)) { + // null indicates that the element should be forgotten (not treated as empty) + return container.getProfiles().size() > 0 ? new OptionMenuProfileElement(container.getProfiles(), shaderPackOptions.getOptionSet(), shaderPackOptions.getOptionValues()) : null; + } + // Link to sub screen element + if (elementString.startsWith("[") && elementString.endsWith("]")) { + return new OptionMenuLinkElement(elementString.substring(1, elementString.length() - 1)); + } + + Map booleanOptions = shaderPackOptions.getOptionSet().getBooleanOptions(); + Map stringOptions = shaderPackOptions.getOptionSet().getStringOptions(); + + // Option elements (boolean and string), only succeed if the option is defined in the shader source + if (booleanOptions.containsKey(elementString)) { + return new OptionMenuBooleanOptionElement(elementString, container, shaderProperties, shaderPackOptions.getOptionValues(), booleanOptions.get(elementString).getOption()); + } else if (stringOptions.containsKey(elementString)) { + return new OptionMenuStringOptionElement(elementString, container, shaderProperties, shaderPackOptions.getOptionValues(), stringOptions.get(elementString).getOption()); + } + + // Handled and ignored with log warning + throw new IllegalArgumentException("Unable to resolve shader pack option menu element \"" + elementString + "\" defined in shaders.properties"); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuElementScreen.java b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuElementScreen.java new file mode 100644 index 000000000..38185a323 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuElementScreen.java @@ -0,0 +1,47 @@ +package net.coderbot.iris.shaderpack.option.menu; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.ShaderProperties; +import net.coderbot.iris.shaderpack.option.ShaderPackOptions; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class OptionMenuElementScreen { + public final List elements = new ArrayList<>(); + + private final Optional columnCount; + + public OptionMenuElementScreen(OptionMenuContainer container, ShaderProperties shaderProperties, ShaderPackOptions shaderPackOptions, List elementStrings, Optional columnCount) { + this.columnCount = columnCount; + + for (String elementString : elementStrings) { + if ("*".equals(elementString)) { + container.queueForUnusedOptionDump(this.elements.size(), this.elements); + + continue; + } + + try { + OptionMenuElement element = OptionMenuElement.create(elementString, container, shaderProperties, shaderPackOptions); + + if (element != null) { + this.elements.add(element); + + if (element instanceof OptionMenuOptionElement) { + container.notifyOptionAdded(elementString, (OptionMenuOptionElement) element); + } + } + } catch (IllegalArgumentException error) { + Iris.logger.warn(error.getMessage()); + + this.elements.add(OptionMenuElement.EMPTY); + } + } + } + + public int getColumnCount() { + return columnCount.orElse(elements.size() > 18 ? 3 : 2); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuLinkElement.java b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuLinkElement.java new file mode 100644 index 000000000..cc82cb72b --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuLinkElement.java @@ -0,0 +1,9 @@ +package net.coderbot.iris.shaderpack.option.menu; + +public class OptionMenuLinkElement extends OptionMenuElement { + public final String targetScreenId; + + public OptionMenuLinkElement(String targetScreenId) { + this.targetScreenId = targetScreenId; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuMainElementScreen.java b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuMainElementScreen.java new file mode 100644 index 000000000..fbd9476f4 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuMainElementScreen.java @@ -0,0 +1,13 @@ +package net.coderbot.iris.shaderpack.option.menu; + +import net.coderbot.iris.shaderpack.ShaderProperties; +import net.coderbot.iris.shaderpack.option.ShaderPackOptions; + +import java.util.List; +import java.util.Optional; + +public class OptionMenuMainElementScreen extends OptionMenuElementScreen { + public OptionMenuMainElementScreen(OptionMenuContainer container, ShaderProperties shaderProperties, ShaderPackOptions shaderPackOptions, List elementStrings, Optional columnCount) { + super(container, shaderProperties, shaderPackOptions, elementStrings, columnCount); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuOptionElement.java b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuOptionElement.java new file mode 100644 index 000000000..c25646f88 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuOptionElement.java @@ -0,0 +1,39 @@ +package net.coderbot.iris.shaderpack.option.menu; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.ShaderProperties; +import net.coderbot.iris.shaderpack.option.values.MutableOptionValues; +import net.coderbot.iris.shaderpack.option.values.OptionValues; + +public abstract class OptionMenuOptionElement extends OptionMenuElement { + public final boolean slider; + public final OptionMenuContainer container; + public final String optionId; + + private final OptionValues packAppliedValues; + + public OptionMenuOptionElement(String elementString, OptionMenuContainer container, ShaderProperties shaderProperties, OptionValues packAppliedValues) { + this.slider = shaderProperties.getSliderOptions().contains(elementString); + this.container = container; + this.optionId = elementString; + this.packAppliedValues = packAppliedValues; + } + + /** + * @return the {@link OptionValues} currently in use by the shader pack + */ + public OptionValues getAppliedOptionValues() { + return packAppliedValues; + } + + /** + * @return an {@link OptionValues} that also contains values currently + * pending application. + */ + public OptionValues getPendingOptionValues() { + MutableOptionValues values = getAppliedOptionValues().mutableCopy(); + values.addAll(Iris.getShaderPackOptionQueue()); + + return values; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuProfileElement.java b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuProfileElement.java new file mode 100644 index 000000000..78ba4fa13 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuProfileElement.java @@ -0,0 +1,31 @@ +package net.coderbot.iris.shaderpack.option.menu; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.option.OptionSet; +import net.coderbot.iris.shaderpack.option.ProfileSet; +import net.coderbot.iris.shaderpack.option.values.MutableOptionValues; +import net.coderbot.iris.shaderpack.option.values.OptionValues; + +public class OptionMenuProfileElement extends OptionMenuElement { + public final ProfileSet profiles; + public final OptionSet options; + + private final OptionValues packAppliedValues; + + public OptionMenuProfileElement(ProfileSet profiles, OptionSet options, OptionValues packAppliedValues) { + this.profiles = profiles; + this.options = options; + this.packAppliedValues = packAppliedValues; + } + + /** + * @return an {@link OptionValues} that also contains values currently + * pending application. + */ + public OptionValues getPendingOptionValues() { + MutableOptionValues values = packAppliedValues.mutableCopy(); + values.addAll(Iris.getShaderPackOptionQueue()); + + return values; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuStringOptionElement.java b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuStringOptionElement.java new file mode 100644 index 000000000..63f27b20a --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuStringOptionElement.java @@ -0,0 +1,14 @@ +package net.coderbot.iris.shaderpack.option.menu; + +import net.coderbot.iris.shaderpack.ShaderProperties; +import net.coderbot.iris.shaderpack.option.StringOption; +import net.coderbot.iris.shaderpack.option.values.OptionValues; + +public class OptionMenuStringOptionElement extends OptionMenuOptionElement { + public final StringOption option; + + public OptionMenuStringOptionElement(String elementString, OptionMenuContainer container, ShaderProperties shaderProperties, OptionValues values, StringOption option) { + super(elementString, container, shaderProperties, values); + this.option = option; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuSubElementScreen.java b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuSubElementScreen.java new file mode 100644 index 000000000..dd1bd854f --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/menu/OptionMenuSubElementScreen.java @@ -0,0 +1,17 @@ +package net.coderbot.iris.shaderpack.option.menu; + +import net.coderbot.iris.shaderpack.ShaderProperties; +import net.coderbot.iris.shaderpack.option.ShaderPackOptions; + +import java.util.List; +import java.util.Optional; + +public class OptionMenuSubElementScreen extends OptionMenuElementScreen { + public final String screenId; + + public OptionMenuSubElementScreen(String screenId, OptionMenuContainer container, ShaderProperties shaderProperties, ShaderPackOptions shaderPackOptions, List elementStrings, Optional columnCount) { + super(container, shaderProperties, shaderPackOptions, elementStrings, columnCount); + + this.screenId = screenId; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/values/ImmutableOptionValues.java b/src/main/java/net/coderbot/iris/shaderpack/option/values/ImmutableOptionValues.java new file mode 100644 index 000000000..1e3935fb3 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/values/ImmutableOptionValues.java @@ -0,0 +1,55 @@ +package net.coderbot.iris.shaderpack.option.values; + +import com.google.common.collect.ImmutableMap; +import net.coderbot.iris.shaderpack.OptionalBoolean; +import net.coderbot.iris.shaderpack.option.OptionSet; + +import java.util.HashMap; +import java.util.Optional; + +public class ImmutableOptionValues implements OptionValues { + private final OptionSet options; + private final ImmutableMap booleanValues; + private final ImmutableMap stringValues; + + ImmutableOptionValues(OptionSet options, ImmutableMap booleanValues, + ImmutableMap stringValues) { + this.options = options; + this.booleanValues = booleanValues; + this.stringValues = stringValues; + } + + @Override + public OptionalBoolean getBooleanValue(String name) { + if (booleanValues.containsKey(name)) { + return booleanValues.get(name) ? OptionalBoolean.TRUE : OptionalBoolean.FALSE; + } else { + return OptionalBoolean.DEFAULT; + } + } + + @Override + public Optional getStringValue(String name) { + return Optional.ofNullable(stringValues.get(name)); + } + + @Override + public int getOptionsChanged() { + return this.stringValues.size() + this.booleanValues.size(); + } + + @Override + public MutableOptionValues mutableCopy() { + return new MutableOptionValues(options, new HashMap<>(booleanValues), new HashMap<>(stringValues)); + } + + @Override + public ImmutableOptionValues toImmutable() { + return this; + } + + @Override + public OptionSet getOptionSet() { + return options; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/values/MutableOptionValues.java b/src/main/java/net/coderbot/iris/shaderpack/option/values/MutableOptionValues.java new file mode 100644 index 000000000..ca1a446ac --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/values/MutableOptionValues.java @@ -0,0 +1,134 @@ +package net.coderbot.iris.shaderpack.option.values; + +import com.google.common.collect.ImmutableMap; +import net.coderbot.iris.shaderpack.OptionalBoolean; +import net.coderbot.iris.shaderpack.option.OptionSet; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class MutableOptionValues implements OptionValues { + private final OptionSet options; + private final Map booleanValues; + private final Map stringValues; + + MutableOptionValues(OptionSet options, Map booleanValues, Map stringValues) { + Map values = new HashMap<>(); + + booleanValues.forEach((k, v) -> values.put(k, Boolean.toString(v))); + values.putAll(stringValues); + + this.options = options; + this.booleanValues = new HashMap<>(); + this.stringValues = new HashMap<>(); + + this.addAll(values); + } + + public MutableOptionValues(OptionSet options, Map values) { + this.options = options; + this.booleanValues = new HashMap<>(); + this.stringValues = new HashMap<>(); + + this.addAll(values); + } + + public OptionSet getOptions() { + return options; + } + + public Map getBooleanValues() { + return booleanValues; + } + + public Map getStringValues() { + return stringValues; + } + + public void addAll(Map values) { + options.getBooleanOptions().forEach((name, option) -> { + String value = values.get(name); + OptionalBoolean booleanValue; + + if (value == null) { + return; + } + + if (value.equals("false")) { + booleanValue = OptionalBoolean.FALSE; + } else if (value.equals("true")) { + booleanValue = OptionalBoolean.TRUE; + } else { + // Invalid value specified, ignore it + // TODO: Diagnostic message? + booleanValue = OptionalBoolean.DEFAULT; + } + + boolean actualValue = booleanValue.orElse(option.getOption().getDefaultValue()); + + if (actualValue == option.getOption().getDefaultValue()) { + // Just set it to default by removing it from the map + booleanValues.remove(name); + return; + } + + booleanValues.put(name, actualValue); + }); + + options.getStringOptions().forEach((name, option) -> { + String value = values.get(name); + + if (value == null) { + return; + } + + // NB: We don't check if the option is in the allowed values here. This matches OptiFine + // behavior, the allowed values is only used when the user is changing options in the + // GUI. Profiles might specify values for options that aren't in the allowed values + // list, and values typed manually into the config .txt are unchecked. + + if (value.equals(option.getOption().getDefaultValue())) { + stringValues.remove(name); + return; + } + + stringValues.put(name, value); + }); + } + + @Override + public OptionalBoolean getBooleanValue(String name) { + if (booleanValues.containsKey(name)) { + return booleanValues.get(name) ? OptionalBoolean.TRUE : OptionalBoolean.FALSE; + } else { + return OptionalBoolean.DEFAULT; + } + } + + @Override + public Optional getStringValue(String name) { + return Optional.ofNullable(stringValues.get(name)); + } + + @Override + public int getOptionsChanged() { + return this.stringValues.size() + this.booleanValues.size(); + } + + @Override + public MutableOptionValues mutableCopy() { + return new MutableOptionValues(options, new HashMap<>(booleanValues), new HashMap<>(stringValues)); + } + + @Override + public ImmutableOptionValues toImmutable() { + return new ImmutableOptionValues(options, ImmutableMap.copyOf(booleanValues), + ImmutableMap.copyOf(stringValues)); + } + + @Override + public OptionSet getOptionSet() { + return options; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/option/values/OptionValues.java b/src/main/java/net/coderbot/iris/shaderpack/option/values/OptionValues.java new file mode 100644 index 000000000..1abb3f189 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/option/values/OptionValues.java @@ -0,0 +1,32 @@ +package net.coderbot.iris.shaderpack.option.values; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.OptionalBoolean; +import net.coderbot.iris.shaderpack.option.OptionSet; + +import java.util.Optional; + +public interface OptionValues { + OptionalBoolean getBooleanValue(String name); + Optional getStringValue(String name); + + default boolean getBooleanValueOrDefault(String name) { + return getBooleanValue(name).orElseGet(() -> { + if (!getOptionSet().getBooleanOptions().containsKey(name)) { + Iris.logger.warn("Tried to get boolean value for unknown option: " + name + ", defaulting to true!"); + return true; + } + return getOptionSet().getBooleanOptions().get(name).getOption().getDefaultValue(); + }); + } + + default String getStringValueOrDefault(String name) { + return getStringValue(name).orElseGet(() -> getOptionSet().getStringOptions().get(name).getOption().getDefaultValue()); + } + + int getOptionsChanged(); + + MutableOptionValues mutableCopy(); + ImmutableOptionValues toImmutable(); + OptionSet getOptionSet(); +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/parsing/ParsedString.java b/src/main/java/net/coderbot/iris/shaderpack/parsing/ParsedString.java new file mode 100644 index 000000000..7e96a0cef --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/parsing/ParsedString.java @@ -0,0 +1,158 @@ +package net.coderbot.iris.shaderpack.parsing; + +import org.jetbrains.annotations.Nullable; + +public class ParsedString { + private String text; + + public ParsedString(String text) { + this.text = text; + } + + public boolean takeLiteral(String token) { + if (!text.startsWith(token)) { + return false; + } + + text = text.substring(token.length()); + + return true; + } + + public boolean takeSomeWhitespace() { + if (text.isEmpty() || !Character.isWhitespace(text.charAt(0))) { + return false; + } + + // TODO: We do a double sided trim + text = text.trim(); + + return true; + } + + public boolean takeComments() { + if (!text.startsWith("//")) { + return false; + } + + // Remove the initial two comment slashes + text = text.substring(2); + + // Remove any additional comment slashes + while (text.startsWith("/")) { + text = text.substring(1); + } + + return true; + } + + public boolean currentlyContains(String text) { + return this.text.contains(text); + } + + public boolean isEnd() { + return text.isEmpty(); + } + + public String takeRest() { + return text; + } + + private String takeCharacters(int numChars) { + String result = text.substring(0, numChars); + text = text.substring(numChars); + + // TODO: Audit substring calls... + return result; + } + + @Nullable + public String takeWord() { + if (isEnd()) { + return null; + } + + int position = 0; + + for (char character : text.toCharArray()) { + if (!Character.isDigit(character) + && !Character.isAlphabetic(character) + && character != '_') { + break; + } + + position += 1; + } + + if (position == 0) { + return null; + } + + return takeCharacters(position); + } + + @Nullable + public String takeNumber() { + if (isEnd()) { + return null; + } + + int position = 0; + int digitsBefore = 0; + + if (text.charAt(0) == '-') { + position += 1; + } + + while (position < text.length() && Character.isDigit(text.charAt(position))) { + position += 1; + digitsBefore += 1; + } + + if (digitsBefore == 0) { + return null; + } + + if (position < text.length()) { + char next = text.charAt(position); + + if (next == '.') { + position += 1; + + int digitsAfter = 0; + + while (position < text.length() && Character.isDigit(text.charAt(position))) { + position += 1; + digitsAfter += 1; + } + + if (digitsAfter == 0) { + return null; + } + + if (position < text.length()) { + next = text.charAt(position); + + if (next == 'f' || next == 'F') { + position += 1; + } + } + } else if (next == 'f' || next == 'F') { + position += 1; + } + } + + return takeCharacters(position); + } + + @Nullable + public String takeWordOrNumber() { + String number = takeNumber(); + + if (number == null) { + return takeWord(); + } + + return number; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/preprocessor/GlslCollectingListener.java b/src/main/java/net/coderbot/iris/shaderpack/preprocessor/GlslCollectingListener.java new file mode 100644 index 000000000..df3c879aa --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/preprocessor/GlslCollectingListener.java @@ -0,0 +1,33 @@ +package net.coderbot.iris.shaderpack.preprocessor; + +import org.anarres.cpp.DefaultPreprocessorListener; +import org.anarres.cpp.LexerException; +import org.anarres.cpp.Source; + +public class GlslCollectingListener extends DefaultPreprocessorListener { + public static final String VERSION_MARKER = "#warning IRIS_JCPP_GLSL_VERSION"; + public static final String EXTENSION_MARKER = "#warning IRIS_JCPP_GLSL_EXTENSION"; + + private final StringBuilder builder; + + public GlslCollectingListener() { + this.builder = new StringBuilder(); + } + + @Override + public void handleWarning(Source source, int line, int column, String msg) throws LexerException { + if (msg.startsWith(VERSION_MARKER)) { + builder.append(msg.replace(VERSION_MARKER, "#version ")); + builder.append('\n'); + } else if (msg.startsWith(EXTENSION_MARKER)) { + builder.append(msg.replace(EXTENSION_MARKER, "#extension ")); + builder.append('\n'); + } else { + super.handleWarning(source, line, column, msg); + } + } + + public String collectLines() { + return builder.toString(); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/preprocessor/JcppProcessor.java b/src/main/java/net/coderbot/iris/shaderpack/preprocessor/JcppProcessor.java new file mode 100644 index 000000000..bbc217e90 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/preprocessor/JcppProcessor.java @@ -0,0 +1,70 @@ +package net.coderbot.iris.shaderpack.preprocessor; + +import net.coderbot.iris.shaderpack.StringPair; +import org.anarres.cpp.Feature; +import org.anarres.cpp.LexerException; +import org.anarres.cpp.Preprocessor; +import org.anarres.cpp.StringLexerSource; +import org.anarres.cpp.Token; + +public class JcppProcessor { + // Derived from GlShader from Canvas, licenced under LGPL + public static String glslPreprocessSource(String source, Iterable environmentDefines) { + if (source.contains(GlslCollectingListener.VERSION_MARKER) + || source.contains(GlslCollectingListener.EXTENSION_MARKER)) { + throw new RuntimeException("Some shader author is trying to exploit internal Iris implementation details, stop!"); + } + + // Note: This is an absolutely awful hack. But JCPP's lack of extensibility leaves me with no choice... + // We should write our own preprocessor at some point to avoid this. + // + // Why are we doing this awful hack instead of just using the preprocessor like a normal person? Because it lets + // us only hoist #extension directives if they're actually used. This is needed for shader packs written on + // lenient drivers that allow #extension directives to be placed anywhere to work on strict drivers like Mesa + // that require #extension directives to occur at the top. + // + // TODO: This allows #version to not appear as the first non-comment non-whitespace thing in the file. + // That's not the behavior we want. If you're reading this, don't rely on this behavior. + source = source.replace("#version", GlslCollectingListener.VERSION_MARKER); + source = source.replace("#extension", GlslCollectingListener.EXTENSION_MARKER); + + GlslCollectingListener listener = new GlslCollectingListener(); + + @SuppressWarnings("resource") + final Preprocessor pp = new Preprocessor(); + + // Add the values of the environment defines without actually modifying the source code + // of the shader program, one step down the road of having accurate line number reporting + // in errors... + try { + for (StringPair envDefine : environmentDefines) { + pp.addMacro(envDefine.getKey(), envDefine.getValue()); + } + } catch (LexerException e) { + throw new RuntimeException("Unexpected LexerException processing macros", e); + } + + pp.setListener(listener); + pp.addInput(new StringLexerSource(source, true)); + pp.addFeature(Feature.KEEPCOMMENTS); + + final StringBuilder builder = new StringBuilder(); + + try { + for (;;) { + final Token tok = pp.token(); + if (tok == null) break; + if (tok.getType() == Token.EOF) break; + builder.append(tok.getText()); + } + } catch (final Exception e) { + throw new RuntimeException("GLSL source pre-processing failed", e); + } + + builder.append("\n"); + + source = listener.collectLines() + builder; + + return source; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertiesCommentListener.java b/src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertiesCommentListener.java new file mode 100644 index 000000000..20d33d155 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertiesCommentListener.java @@ -0,0 +1,19 @@ +package net.coderbot.iris.shaderpack.preprocessor; + +import org.anarres.cpp.DefaultPreprocessorListener; +import org.anarres.cpp.LexerException; +import org.anarres.cpp.Source; + +public class PropertiesCommentListener extends DefaultPreprocessorListener { + private static final String UNKNOWN_PREPROCESSOR_DIRECTIVE = "Unknown preprocessor directive"; + private static final String NOT_A_WORD = "Preprocessor directive not a word"; + + @Override + public void handleError(Source source, int line, int column, String msg) throws LexerException { + // In .properties files, #'s are also used for comments, so ignore these errors + if (msg.contains(UNKNOWN_PREPROCESSOR_DIRECTIVE) || msg.contains(NOT_A_WORD)) { + return; + } + super.handleError(source, line, column, msg); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertiesPreprocessor.java b/src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertiesPreprocessor.java new file mode 100644 index 000000000..e9ae63b3c --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertiesPreprocessor.java @@ -0,0 +1,138 @@ +package net.coderbot.iris.shaderpack.preprocessor; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.StringPair; +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.StringLexerSource; +import org.anarres.cpp.Token; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +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 environmentDefines) { + if (source.contains(PropertyCollectingListener.PROPERTY_MARKER)) { + throw new RuntimeException("Some shader author is trying to exploit internal Iris implementation details, stop!"); + } + + List booleanValues = getBooleanValues(shaderPackOptions); + Map stringValues = getStringValues(shaderPackOptions); + + try (Preprocessor pp = new Preprocessor()) { + for (String value : booleanValues) { + pp.addMacro(value); + } + + for (StringPair envDefine : environmentDefines) { + pp.addMacro(envDefine.getKey(), envDefine.getValue()); + } + + stringValues.forEach((name, value) -> { + try { + pp.addMacro(name, value); + } catch (LexerException e) { + e.printStackTrace(); + } + }); + + return process(pp, source); + } catch (IOException e) { + throw new RuntimeException("Unexpected IOException while processing macros", e); + } catch (LexerException e) { + throw new RuntimeException("Unexpected LexerException processing macros", e); + } + } + + public static String preprocessSource(String source, Iterable environmentDefines) { + if (source.contains(PropertyCollectingListener.PROPERTY_MARKER)) { + throw new RuntimeException("Some shader author is trying to exploit internal Iris implementation details, stop!"); + } + + Preprocessor preprocessor = new Preprocessor(); + + try { + for (StringPair envDefine : environmentDefines) { + preprocessor.addMacro(envDefine.getKey(), envDefine.getValue()); + } + } catch (LexerException e) { + e.printStackTrace(); + } + + return process(preprocessor, source); + } + + private static String process(Preprocessor preprocessor, String source) { + preprocessor.setListener(new PropertiesCommentListener()); + PropertyCollectingListener listener = new PropertyCollectingListener(); + preprocessor.setListener(listener); + + // 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) + .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; + } + }).collect(Collectors.joining("\n")) + "\n"; + + preprocessor.addInput(new StringLexerSource(source, true)); + preprocessor.addFeature(Feature.KEEPCOMMENTS); + + final StringBuilder builder = new StringBuilder(); + + try { + for (;;) { + final Token tok = preprocessor.token(); + if (tok == null) break; + if (tok.getType() == Token.EOF) break; + builder.append(tok.getText()); + } + } catch (final Exception e) { + Iris.logger.error("Properties pre-processing failed", e); + } + + source = builder.toString(); + + return listener.collectLines() + source; + } + + private static List getBooleanValues(ShaderPackOptions shaderPackOptions) { + List booleanValues = new ArrayList<>(); + + shaderPackOptions.getOptionSet().getBooleanOptions().forEach((string, value) -> { + boolean trueValue = shaderPackOptions.getOptionValues().getBooleanValueOrDefault(string); + + if (trueValue) { + booleanValues.add(string); + } + }); + + return booleanValues; + } + + private static Map getStringValues(ShaderPackOptions shaderPackOptions) { + Map stringValues = new HashMap<>(); + + shaderPackOptions.getOptionSet().getStringOptions().forEach( + (optionName, value) -> stringValues.put(optionName, shaderPackOptions.getOptionValues().getStringValueOrDefault(optionName))); + + return stringValues; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertyCollectingListener.java b/src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertyCollectingListener.java new file mode 100644 index 000000000..031ea6183 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/preprocessor/PropertyCollectingListener.java @@ -0,0 +1,40 @@ +package net.coderbot.iris.shaderpack.preprocessor; + +import org.anarres.cpp.DefaultPreprocessorListener; +import org.anarres.cpp.LexerException; +import org.anarres.cpp.Source; + +public class PropertyCollectingListener extends DefaultPreprocessorListener { + public static final String PROPERTY_MARKER = "#warning IRIS_PASSTHROUGH "; + + private final StringBuilder builder; + + public PropertyCollectingListener() { + this.builder = new StringBuilder(); + } + + @Override + public void handleWarning(Source source, int line, int column, String msg) throws LexerException { + if (msg.startsWith(PROPERTY_MARKER)) { + builder.append(msg.replace(PROPERTY_MARKER, "")); + builder.append('\n'); + } else { + super.handleWarning(source, line, column, msg); + } + } + + @Override + public void handleError(Source source, int line, int column, String msg) throws LexerException { + if (msg.contains("Unknown preprocessor directive") + || msg.contains("Preprocessor directive not a word")) { + // Suppress log spam since hashed lines also function as comments in preprocessed files. + return; + } + + super.handleError(source, line, column, msg); + } + + public String collectLines() { + return builder.toString(); + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/texture/CustomTextureData.java b/src/main/java/net/coderbot/iris/shaderpack/texture/CustomTextureData.java new file mode 100644 index 000000000..3dda4ea30 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/texture/CustomTextureData.java @@ -0,0 +1,161 @@ +package net.coderbot.iris.shaderpack.texture; + +import net.coderbot.iris.gl.texture.InternalTextureFormat; +import net.coderbot.iris.gl.texture.PixelFormat; +import net.coderbot.iris.gl.texture.PixelType; + +public abstract class CustomTextureData { + private CustomTextureData() { + + } + + public static final class PngData extends CustomTextureData { + private final TextureFilteringData filteringData; + private final byte[] content; + + public PngData(TextureFilteringData filteringData, byte[] content) { + this.filteringData = filteringData; + this.content = content; + } + + public TextureFilteringData getFilteringData() { + return filteringData; + } + + public byte[] getContent() { + return content; + } + } + + public static final class LightmapMarker extends CustomTextureData { + @Override + public boolean equals(Object obj) { + return obj.getClass() == this.getClass(); + } + + @Override + public int hashCode() { + return 33; + } + } + + public static final class ResourceData extends CustomTextureData { + private final String namespace; + private final String location; + + public ResourceData(String namespace, String location) { + this.namespace = namespace; + this.location = location; + } + + /** + * @return The namespace of the texture. The caller is responsible for checking whether this is actually + * a valid namespace. + */ + public String getNamespace() { + return namespace; + } + + /** + * @return The path / location of the texture. The caller is responsible for checking whether this is actually + * a valid path. + */ + public String getLocation() { + return location; + } + } + + public abstract static class RawData extends CustomTextureData { + private final byte[] content; + private final InternalTextureFormat internalFormat; + private final PixelFormat pixelFormat; + private final PixelType pixelType; + + private RawData(byte[] content, InternalTextureFormat internalFormat, + PixelFormat pixelFormat, PixelType pixelType) { + this.content = content; + this.internalFormat = internalFormat; + this.pixelFormat = pixelFormat; + this.pixelType = pixelType; + } + + public final byte[] getContent() { + return content; + } + + public final InternalTextureFormat getInternalFormat() { + return internalFormat; + } + + public final PixelFormat getPixelFormat() { + return pixelFormat; + } + + public final PixelType getPixelType() { + return pixelType; + } + } + + public static final class RawData1D extends RawData { + private final int sizeX; + + private RawData1D(byte[] content, InternalTextureFormat internalFormat, + PixelFormat pixelFormat, PixelType pixelType, int sizeX) { + super(content, internalFormat, pixelFormat, pixelType); + + this.sizeX = sizeX; + } + + public int getSizeX() { + return sizeX; + } + } + + public static final class RawData2D extends RawData { + int sizeX; + int sizeY; + + private RawData2D(byte[] content, InternalTextureFormat internalFormat, + PixelFormat pixelFormat, PixelType pixelType, int sizeX, int sizeY) { + super(content, internalFormat, pixelFormat, pixelType); + + this.sizeX = sizeX; + this.sizeY = sizeY; + } + + public int getSizeX() { + return sizeX; + } + + public int getSizeY() { + return sizeY; + } + } + + public static final class RawData3D extends RawData { + int sizeX; + int sizeY; + int sizeZ; + + private RawData3D(byte[] content, InternalTextureFormat internalFormat, + PixelFormat pixelFormat, PixelType pixelType, int sizeX, int sizeY, int sizeZ) { + super(content, internalFormat, pixelFormat, pixelType); + + this.sizeX = sizeX; + this.sizeY = sizeY; + this.sizeZ = sizeZ; + } + + public int getSizeX() { + return sizeX; + } + + public int getSizeY() { + return sizeY; + } + + public int getSizeZ() { + return sizeZ; + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/texture/TextureFilteringData.java b/src/main/java/net/coderbot/iris/shaderpack/texture/TextureFilteringData.java new file mode 100644 index 000000000..55ea5bc9a --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/texture/TextureFilteringData.java @@ -0,0 +1,19 @@ +package net.coderbot.iris.shaderpack.texture; + +public final class TextureFilteringData { + private final boolean blur; + private final boolean clamp; + + public TextureFilteringData(boolean blur, boolean clamp) { + this.blur = blur; + this.clamp = clamp; + } + + public boolean shouldBlur() { + return blur; + } + + public boolean shouldClamp() { + return clamp; + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/texture/TextureStage.java b/src/main/java/net/coderbot/iris/shaderpack/texture/TextureStage.java new file mode 100644 index 000000000..687f7e178 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/texture/TextureStage.java @@ -0,0 +1,47 @@ +package net.coderbot.iris.shaderpack.texture; + +import java.util.Optional; + +public enum TextureStage { + /** + * The shadowcomp passes. + * + * While this is not documented in shaders.txt, it is a valid stage for defining custom textures. + */ + SHADOWCOMP, + /** + * The prepare passes. + * + * While this is not documented in shaders.txt, it is a valid stage for defining custom textures. + */ + PREPARE, + /** + * All of the gbuffer passes, as well as the shadow passes. + */ + GBUFFERS_AND_SHADOW, + /** + * The deferred pass. + */ + DEFERRED, + /** + * The composite pass and final pass. + */ + COMPOSITE_AND_FINAL; + + public static Optional parse(String name) { + switch (name) { + case "shadowcomp": + return Optional.of(SHADOWCOMP); + case "prepare": + return Optional.of(PREPARE); + case "gbuffers": + return Optional.of(GBUFFERS_AND_SHADOW); + case "deferred": + return Optional.of(DEFERRED); + case "composite": + return Optional.of(COMPOSITE_AND_FINAL); + default: + return Optional.empty(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shaderpack/transform/StringTransformations.java b/src/main/java/net/coderbot/iris/shaderpack/transform/StringTransformations.java new file mode 100644 index 000000000..a0c81331a --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/transform/StringTransformations.java @@ -0,0 +1,128 @@ +package net.coderbot.iris.shaderpack.transform; + +public class StringTransformations implements Transformations { + private String prefix; + private String extensions; + private StringBuilder injections; + private String body; + private StringBuilder suffix; + + public StringTransformations(String base) { + int versionStringStart = base.indexOf("#version"); + + if (versionStringStart == -1) { + throw new IllegalArgumentException("A valid shader should include a version string"); + } + + String prefix = base.substring(0, versionStringStart); + base = base.substring(versionStringStart); + + int splitPoint = base.indexOf("\n") + 1; + + this.prefix = prefix + base.substring(0, splitPoint); + this.extensions = ""; + this.injections = new StringBuilder(); + this.body = base.substring(splitPoint); + this.suffix = new StringBuilder("\n"); + + if (!body.contains("#extension")) { + // Don't try to hoist #extension lines if there are none. + return; + } + + // We need to avoid injecting non-preprocessor code fragments before #extension + // declarations. Luckily, JCPP hoists #extension directives to be right after #version + // directives. + StringBuilder extensions = new StringBuilder(); + StringBuilder body = new StringBuilder(); + + boolean inBody = false; + + for (String line : this.body.split("\\R")) { + String trimmedLine = line.trim(); + + if (!trimmedLine.isEmpty() + && !trimmedLine.startsWith("#extension") + && !trimmedLine.startsWith("//")) { + inBody = true; + } + + if (inBody) { + body.append(line); + body.append('\n'); + } else { + extensions.append(line); + extensions.append('\n'); + } + } + + this.extensions = extensions.toString(); + this.body = body.toString(); + } + + @Override + public String getPrefix() { + return prefix; + } + + @Override + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + @Override + public boolean contains(String content) { + return toString().contains(content); + } + + @Override + public void define(String key, String value) { + // TODO: This isn't super efficient, but oh well. + extensions = extensions + "#define " + key + " " + value + "\n"; + } + + @Override + public void injectLine(InjectionPoint at, String line) { + if (at == InjectionPoint.BEFORE_CODE) { + injections.append(line); + injections.append('\n'); + } else if (at == InjectionPoint.DEFINES) { + // TODO: This isn't super efficient, but oh well. + extensions = extensions + line + "\n"; + } else if (at == InjectionPoint.END) { + suffix.append(line); + suffix.append('\n'); + } else { + throw new IllegalArgumentException("Unsupported injection point: " + at); + } + } + + @Override + public void replaceExact(String from, String to) { + if (from.contains("\n")) { + // Block newline replacements for now, since that could mean that we're trying to replace across + // injections / body and that will result in weird behavior. + throw new UnsupportedOperationException(); + } + + prefix = prefix.replace(from, to); + extensions = extensions.replace(from, to); + injections = new StringBuilder(injections.toString().replace(from, to)); + body = body.replace(from, to); + suffix = new StringBuilder(suffix.toString().replace(from, to)); + } + + @Override + public void replaceRegex(String regex, String to) { + prefix = prefix.replaceAll(regex, to); + extensions = extensions.replaceAll(regex, to); + injections = new StringBuilder(injections.toString().replaceAll(regex, to)); + body = body.replaceAll(regex, to); + suffix = new StringBuilder(suffix.toString().replaceAll(regex, to)); + } + + @Override + public String toString() { + return prefix + extensions + injections + body + suffix; + } +} \ No newline at end of file diff --git a/src/main/java/net/coderbot/iris/shaderpack/transform/Transformations.java b/src/main/java/net/coderbot/iris/shaderpack/transform/Transformations.java new file mode 100644 index 000000000..82af8d9ae --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/transform/Transformations.java @@ -0,0 +1,17 @@ +package net.coderbot.iris.shaderpack.transform; + +public interface Transformations { + boolean contains(String content); + void injectLine(InjectionPoint at, String line); + void replaceExact(String from, String to); + void replaceRegex(String regex, String to); + String getPrefix(); + void setPrefix(String prefix); + void define(String key, String value); + + enum InjectionPoint { + DEFINES, + BEFORE_CODE, + END + } +} \ No newline at end of file diff --git a/src/main/java/net/coderbot/iris/shaderpack/transform/line/LineTransform.java b/src/main/java/net/coderbot/iris/shaderpack/transform/line/LineTransform.java new file mode 100644 index 000000000..159526825 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/transform/line/LineTransform.java @@ -0,0 +1,19 @@ +package net.coderbot.iris.shaderpack.transform.line; + +import com.google.common.collect.ImmutableList; + +public interface LineTransform { + String transform(int index, String line); + + static ImmutableList apply(ImmutableList lines, LineTransform transform) { + ImmutableList.Builder newLines = ImmutableList.builder(); + int index = 0; + + for (String line : lines) { + newLines.add(transform.transform(index, line)); + index += 1; + } + + return newLines.build(); + } +} diff --git a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java new file mode 100644 index 000000000..8d50ab9c0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java @@ -0,0 +1,215 @@ +package net.coderbot.iris.shadow; + +import org.joml.Matrix4f; + +import java.nio.FloatBuffer; + +public class ShadowMatrices { + private static final float NEAR = 0.05f; + private static final float FAR = 256.0f; + + // NB: These matrices are in column-major order, not row-major order like what you'd expect! + + public static float[] createOrthoMatrix(float halfPlaneLength) { + return new float[] { + // column 1 + 1.0f / halfPlaneLength, 0f, 0f, 0f, + // column 2 + 0f, 1.0f / halfPlaneLength, 0f, 0f, + // column 3 + 0f, 0f, 2.0f / (NEAR - FAR), 0f, + // column 4 + 0f, 0f, -(FAR + NEAR) / (FAR - NEAR), 1f + }; + } + + public static float[] createPerspectiveMatrix(float fov) { + // This converts from degrees to radians. + float yScale = (float) (1.0f / Math.tan(Math.toRadians(fov) * 0.5f)); + return new float[] { + // column 1 + yScale, 0f, 0f, 0f, + // column 2 + 0f, yScale, 0f, 0f, + // column 3 + 0f, 0f, (FAR + NEAR) / (NEAR - FAR), -1.0F, + // column 4 + 0f, 0f, 2.0F * FAR * NEAR / (NEAR - FAR), 1f + }; + } + + public static void createBaselineModelViewMatrix(PoseStack target, float shadowAngle, float sunPathRotation) { + float skyAngle; + + if (shadowAngle < 0.25f) { + skyAngle = shadowAngle + 0.75f; + } else { + skyAngle = shadowAngle - 0.25f; + } + + target.last().normal().setIdentity(); + target.last().pose().setIdentity(); + + target.last().pose().multiply(Matrix4f.createTranslateMatrix(0.0f, 0.0f, -100.0f)); + target.mulPose(Vector3f.XP.rotationDegrees(90.0F)); + target.mulPose(Vector3f.ZP.rotationDegrees(skyAngle * -360.0f)); + target.mulPose(Vector3f.XP.rotationDegrees(sunPathRotation)); + } + + public static void snapModelViewToGrid(PoseStack target, float shadowIntervalSize, double cameraX, double cameraY, double cameraZ) { + if (Math.abs(shadowIntervalSize) == 0.0F) { + // Avoid a division by zero - semantically, this just means that the snapping does not take place, + // if the shadow interval (size of each grid "cell") is zero. + return; + } + + // Calculate where we are within each grid "cell" + // These values will be in the range of (-shadowIntervalSize, shadowIntervalSize) + // + // It looks like it's intended for these to be within the range [0, shadowIntervalSize), however since the + // expression (-2.0f % 32.0f) returns -2.0f, negative inputs will result in negative outputs. + float offsetX = (float) cameraX % shadowIntervalSize; + float offsetY = (float) cameraY % shadowIntervalSize; + float offsetZ = (float) cameraZ % shadowIntervalSize; + + // Halve the size of each grid cell in order to move to the center of it. + float halfIntervalSize = shadowIntervalSize / 2.0f; + + // Shift by -halfIntervalSize + // + // It's clear that the intent of the algorithm was to place the values into the range: + // [-shadowIntervalSize/2, shadowIntervalSize), however due to the previously-mentioned behavior with negatives, + // it's possible that values will lie in the range (-3shadowIntervalSize/2, shadowIntervalSize/2). + offsetX -= halfIntervalSize; + offsetY -= halfIntervalSize; + offsetZ -= halfIntervalSize; + + target.last().pose().multiply(Matrix4f.createTranslateMatrix(offsetX, offsetY, offsetZ)); + } + + public static void createModelViewMatrix(PoseStack target, float shadowAngle, float shadowIntervalSize, + float sunPathRotation, double cameraX, double cameraY, double cameraZ) { + createBaselineModelViewMatrix(target, shadowAngle, sunPathRotation); + snapModelViewToGrid(target, shadowIntervalSize, cameraX, cameraY, cameraZ); + } + + private static final class Tests { + public static void main(String[] args) { + // const float shadowDistance = 32.0; + // /* SHADOWHPL:32.0 */ + float[] expected = new float[] { + 0.03125f, 0f, 0f, 0f, + 0f, 0.03125f, 0f, 0f, + 0f, 0f, -0.007814026437699795f, 0f, + 0f, 0f, -1.000390648841858f, 1f + }; + + test("ortho projection hpl=32", expected, createOrthoMatrix(32.0f)); + + // const float shadowDistance = 110.0; + // /* SHADOWHPL:110.0 */ + float[] expected110 = new float[] { + 0.00909090880304575f, 0, 0, 0, + 0, 0.00909090880304575f, 0, 0, + 0, 0, -0.007814026437699795f, 0, + 0, 0, -1.000390648841858f, 1 + }; + + test("ortho projection hpl=110", expected110, createOrthoMatrix(110.0f)); + + float[] expected90Proj = new float[] { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -1.0003906f, -1.0f, + 0.0f, 0.0f, -0.10001954f, 0.0f + }; + + test("perspective projection fov=90", expected90Proj, createPerspectiveMatrix(90.0f)); + + float[] expectedModelViewAtDawn = new float[] { + // column 1 + 0.21545040607452393f, + 5.820481518981069E-8f, + 0.9765146970748901f, + 0, + // column 2 + -0.9765147466795349f, + 1.2841844920785661E-8f, + 0.21545039117336273f, + 0, + // column 3 + 0, + -0.9999999403953552f, + 5.960464477539063E-8f, + 0, + // column 4 + 0.38002151250839233f, + 1.0264281034469604f, + -100.4463119506836f, + 1 + }; + + PoseStack modelView = new PoseStack(); + + // NB: At dawn, the shadow angle is NOT zero. + // When DayTime=0, skyAngle = 282 degrees. + // Thus, sunAngle = shadowAngle = 0.03451777f + createModelViewMatrix(modelView, 0.03451777f, 2.0f, + 0.0f, 0.646045982837677f, 82.53274536132812f, -514.0264282226562f); + + test("model view at dawn", expectedModelViewAtDawn, toFloatArray(modelView.last().pose())); + } + + private static float[] toFloatArray(Matrix4f matrix4f) { + FloatBuffer buffer = FloatBuffer.allocate(16); + matrix4f.store(buffer); + + return buffer.array(); + } + + private static void test(String name, float[] expected, float[] created) { + if (!areMatricesEqualWithinEpsilon(expected, created)) { + System.err.println("test " + name + " failed: "); + System.err.println(" expected: "); + System.err.print(printMatrix(expected, 8)); + System.err.println(" created: "); + System.err.print(printMatrix(created, 8)); + } else { + System.out.println("test " + name + " passed"); + } + } + + private static boolean areMatricesEqualWithinEpsilon(float[] expected, float[] created) { + for (int i = 0; i < 16; i++) { + if (Math.abs(expected[i] - created[i]) > 0.0005f) { + return false; + } + } + + return true; + } + + private static String printMatrix(float[] matrix, int spaces) { + StringBuilder lines = new StringBuilder(); + + for (int row = 0; row < 4; row++) { + for (int i = 0; i < spaces; i++) { + lines.append(' '); + } + + lines.append('['); + + for (int column = 0; column < 4; column++) { + lines.append(' '); + lines.append(matrix[column * 4 + row]); + } + + lines.append(" ]"); + + lines.append('\n'); + } + + return lines.toString(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/shadows/CullingDataCache.java b/src/main/java/net/coderbot/iris/shadows/CullingDataCache.java new file mode 100644 index 000000000..010579561 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/CullingDataCache.java @@ -0,0 +1,6 @@ +package net.coderbot.iris.shadows; + +public interface CullingDataCache { + void saveState(); + void restoreState(); +} diff --git a/src/main/java/net/coderbot/iris/shadows/Matrix4fAccess.java b/src/main/java/net/coderbot/iris/shadows/Matrix4fAccess.java new file mode 100644 index 000000000..c0e0b9f24 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/Matrix4fAccess.java @@ -0,0 +1,25 @@ +package net.coderbot.iris.shadows; + +import org.joml.Matrix4f; + +public interface Matrix4fAccess { + /** + * Sets the values of this matrix from an array. The values in the array must be specified in column-major order, + * just like with OpenGL. Keep this in mind, since the natural way of laying out a matrix in array form is row-major + * order! + */ + void copyFromArray(float[] m); + + /** + * Gets the values of this matrix into an array. The values in the array will be laid out in column-major order, + * just like with OpenGL. Keep this in mind, since the natural way of laying out a matrix in array form is row-major + * order! + */ + float[] copyIntoArray(); + + /** + * Converts the matrix into a JOML matrix. This matrix is inherently column-major, and compatible with OpenGL. + * @return JOML matrix + */ + Matrix4f convertToJOML(); +} diff --git a/src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java b/src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java new file mode 100644 index 000000000..5f0048d29 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java @@ -0,0 +1,276 @@ +package net.coderbot.iris.shadows; + +import com.google.common.collect.ImmutableSet; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.framebuffer.GlFramebuffer; +import net.coderbot.iris.gl.texture.DepthBufferFormat; +import net.coderbot.iris.gl.texture.DepthCopyStrategy; +import net.coderbot.iris.gl.texture.InternalTextureFormat; +import net.coderbot.iris.rendertarget.DepthTexture; +import net.coderbot.iris.rendertarget.RenderTarget; +import net.coderbot.iris.shaderpack.PackShadowDirectives; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; + +public class ShadowRenderTargets { + private final RenderTarget[] targets; + private final DepthTexture mainDepth; + private final DepthTexture noTranslucents; + private final GlFramebuffer depthSourceFb; + private final GlFramebuffer noTranslucentsDestFb; + private final boolean[] flipped; + + private final List ownedFramebuffers; + private final int resolution; + + private boolean fullClearRequired; + private boolean translucentDepthDirty; + private boolean[] hardwareFiltered; + private InternalTextureFormat[] formats; + private IntList buffersToBeCleared; + + public ShadowRenderTargets(int resolution, PackShadowDirectives shadowDirectives) { + targets = new RenderTarget[shadowDirectives.getColorSamplingSettings().size()]; + formats = new InternalTextureFormat[shadowDirectives.getColorSamplingSettings().size()]; + flipped = new boolean[shadowDirectives.getColorSamplingSettings().size()]; + hardwareFiltered = new boolean[shadowDirectives.getColorSamplingSettings().size()]; + buffersToBeCleared = new IntArrayList(); + + this.mainDepth = new DepthTexture(resolution, resolution, DepthBufferFormat.DEPTH); + this.noTranslucents = new DepthTexture(resolution, resolution, DepthBufferFormat.DEPTH); + + for (int i = 0; i < shadowDirectives.getColorSamplingSettings().size(); i++) { + PackShadowDirectives.SamplingSettings settings = shadowDirectives.getColorSamplingSettings().get(i); + targets[i] = RenderTarget.builder().setDimensions(resolution, resolution) + .setInternalFormat(settings.getFormat()) + .setPixelFormat(settings.getFormat().getPixelFormat()).build(); + formats[i] = settings.getFormat(); + + if (settings.getClear()) { + buffersToBeCleared.add(i); + } + + this.hardwareFiltered[i] = shadowDirectives.getDepthSamplingSettings().get(i).getHardwareFiltering(); + } + + this.resolution = resolution; + + this.ownedFramebuffers = new ArrayList<>(); + + // NB: Make sure all buffers are cleared so that they don't contain undefined + // data. Otherwise very weird things can happen. + fullClearRequired = true; + + this.depthSourceFb = createFramebufferWritingToMain(new int[] {0}); + + this.noTranslucentsDestFb = createFramebufferWritingToMain(new int[] {0}); + this.noTranslucentsDestFb.addDepthAttachment(this.noTranslucents.getTextureId()); + + this.translucentDepthDirty = true; + } + + // TODO: Actually flip. This is required for shadow composites! + public void flip(int target) { + flipped[target] = !flipped[target]; + } + + public boolean isFlipped(int target) { + return flipped[target]; + } + + public void destroy() { + for (GlFramebuffer owned : ownedFramebuffers) { + owned.destroy(); + } + + for (RenderTarget target : targets) { + target.destroy(); + } + + noTranslucents.destroy(); + } + + public int getRenderTargetCount() { + return targets.length; + } + + public RenderTarget get(int index) { + return targets[index]; + } + + public int getResolution() { + return resolution; + } + + public DepthTexture getDepthTexture() { + return mainDepth; + } + + public DepthTexture getDepthTextureNoTranslucents() { + return noTranslucents; + } + + public GlFramebuffer getDepthSourceFb() { + return depthSourceFb; + } + + public void copyPreTranslucentDepth() { + if (translucentDepthDirty) { + translucentDepthDirty = false; + IrisRenderSystem.blitFramebuffer(depthSourceFb.getId(), noTranslucentsDestFb.getId(), 0, 0, resolution, resolution, + 0, 0, resolution, resolution, GL11.GL_DEPTH_BUFFER_BIT, GL11.GL_NEAREST); + } else { + DepthCopyStrategy.fastest(false).copy(depthSourceFb, mainDepth.getTextureId(), noTranslucentsDestFb, noTranslucents.getTextureId(), + resolution, resolution); + } + } + + public boolean isFullClearRequired() { + return fullClearRequired; + } + + public void onFullClear() { + fullClearRequired = false; + } + + public GlFramebuffer createFramebufferWritingToMain(int[] drawBuffers) { + return createFullFramebuffer(false, drawBuffers); + } + + public GlFramebuffer createFramebufferWritingToAlt(int[] drawBuffers) { + return createFullFramebuffer(true, drawBuffers); + } + + private ImmutableSet invert(ImmutableSet base, int[] relevant) { + ImmutableSet.Builder inverted = ImmutableSet.builder(); + + for (int i : relevant) { + if (!base.contains(i)) { + inverted.add(i); + } + } + + return inverted.build(); + } + + private GlFramebuffer createEmptyFramebuffer() { + GlFramebuffer framebuffer = new GlFramebuffer(); + ownedFramebuffers.add(framebuffer); + + framebuffer.addDepthAttachment(mainDepth.getTextureId()); + + // NB: Before OpenGL 3.0, all framebuffers are required to have a color + // attachment no matter what. + framebuffer.addColorAttachment(0, get(0).getMainTexture()); + framebuffer.noDrawBuffers(); + + return framebuffer; + } + + public GlFramebuffer createShadowFramebuffer(ImmutableSet stageWritesToAlt, int[] drawBuffers) { + if (drawBuffers.length == 0) { + return createEmptyFramebuffer(); + } + + ImmutableSet stageWritesToMain = invert(stageWritesToAlt, drawBuffers); + + GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); + + framebuffer.addDepthAttachment(mainDepth.getTextureId()); + + return framebuffer; + } + + private GlFramebuffer createFullFramebuffer(boolean clearsAlt, int[] drawBuffers) { + if (drawBuffers.length == 0) { + return createEmptyFramebuffer(); + } + + ImmutableSet stageWritesToMain = ImmutableSet.of(); + + if (!clearsAlt) { + stageWritesToMain = invert(ImmutableSet.of(), drawBuffers); + } + + return createColorFramebufferWithDepth(stageWritesToMain, drawBuffers); + } + + public GlFramebuffer createColorFramebufferWithDepth(ImmutableSet stageWritesToMain, int[] drawBuffers) { + GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); + + framebuffer.addDepthAttachment(mainDepth.getTextureId()); + + return framebuffer; + } + + public GlFramebuffer createColorFramebuffer(ImmutableSet stageWritesToMain, int[] drawBuffers) { + if (drawBuffers.length == 0) { + throw new IllegalArgumentException("Framebuffer must have at least one color buffer"); + } + + GlFramebuffer framebuffer = new GlFramebuffer(); + ownedFramebuffers.add(framebuffer); + + int[] actualDrawBuffers = new int[drawBuffers.length]; + + for (int i = 0; i < drawBuffers.length; i++) { + actualDrawBuffers[i] = i; + + if (drawBuffers[i] >= getRenderTargetCount()) { + // TODO: This causes resource leaks, also we should really verify this in the shaderpack parser... + throw new IllegalStateException("Render target with index " + drawBuffers[i] + " is not supported, only " + + getRenderTargetCount() + " render targets are supported."); + } + + RenderTarget target = this.get(drawBuffers[i]); + + int textureId = stageWritesToMain.contains(drawBuffers[i]) ? target.getMainTexture() : target.getAltTexture(); + + framebuffer.addColorAttachment(i, textureId); + } + + framebuffer.drawBuffers(actualDrawBuffers); + framebuffer.readBuffer(0); + + if (!framebuffer.isComplete()) { + throw new IllegalStateException("Unexpected error while creating framebuffer"); + } + + return framebuffer; + } + + public int getColorTextureId(int i) { + return isFlipped(i) ? get(i).getAltTexture() : get(i).getMainTexture(); + } + + public boolean isHardwareFiltered(int i) { + return hardwareFiltered[i]; + } + + public int getNumColorTextures() { + return targets.length; + } + + public InternalTextureFormat getColorTextureFormat(int index) { + return formats[index]; + } + + public ImmutableSet snapshot() { + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (int i = 0; i < flipped.length; i++) { + if (flipped[i]) { + builder.add(i); + } + } + + return builder.build(); + } + + public IntList getBuffersToBeCleared() { + return buffersToBeCleared; + } +} diff --git a/src/main/java/net/coderbot/iris/shadows/ShadowRenderingState.java b/src/main/java/net/coderbot/iris/shadows/ShadowRenderingState.java new file mode 100644 index 000000000..04412a398 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/ShadowRenderingState.java @@ -0,0 +1,14 @@ +package net.coderbot.iris.shadows; + +import net.coderbot.iris.pipeline.ShadowRenderer; +import org.joml.Matrix4f; + +public class ShadowRenderingState { + public static boolean areShadowsCurrentlyBeingRendered() { + return ShadowRenderer.ACTIVE; + } + + public static Matrix4f getShadowOrthoMatrix() { + return ShadowRenderer.ACTIVE ? new Matrix4f(ShadowRenderer.PROJECTION) : null; + } +} diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/BoxCuller.java b/src/main/java/net/coderbot/iris/shadows/frustum/BoxCuller.java new file mode 100644 index 000000000..48a6614f6 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/frustum/BoxCuller.java @@ -0,0 +1,48 @@ +package net.coderbot.iris.shadows.frustum; + +import net.minecraft.util.AxisAlignedBB; + +public class BoxCuller { + private final double maxDistance; + + private double minAllowedX; + private double maxAllowedX; + private double minAllowedY; + private double maxAllowedY; + private double minAllowedZ; + private double maxAllowedZ; + + public BoxCuller(double maxDistance) { + this.maxDistance = maxDistance; + } + + public void setPosition(double cameraX, double cameraY, double cameraZ) { + this.minAllowedX = cameraX - maxDistance; + this.maxAllowedX = cameraX + maxDistance; + this.minAllowedY = cameraY - maxDistance; + this.maxAllowedY = cameraY + maxDistance; + this.minAllowedZ = cameraZ - maxDistance; + this.maxAllowedZ = cameraZ + maxDistance; + } + + public boolean isCulled(AxisAlignedBB aabb) { + return isCulled((float) aabb.minX, (float) aabb.minY, (float) aabb.minZ, + (float) aabb.maxX, (float) aabb.maxY, (float) aabb.maxZ); + } + + public boolean isCulled(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + if (maxX < this.minAllowedX || minX > this.maxAllowedX) { + return true; + } + + if (maxY < this.minAllowedY || minY > this.maxAllowedY) { + return true; + } + + if (maxZ < this.minAllowedZ || minZ > this.maxAllowedZ) { + return true; + } + + return false; + } +} diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java new file mode 100644 index 000000000..188251ef4 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java @@ -0,0 +1,26 @@ +package net.coderbot.iris.shadows.frustum; + +import net.minecraft.util.AxisAlignedBB; +import org.joml.Matrix4f; + +public class CullEverythingFrustum extends Frustum { + public CullEverythingFrustum() { + super(new Matrix4f(), new Matrix4f()); + } + + // for Sodium + public boolean fastAabbTest(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + return false; + } + + // For Immersive Portals + // We return false here since isVisible is going to return false anyways. + public boolean canDetermineInvisible(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { + return false; + } + + @Override + public boolean isVisible(AxisAlignedBB aabb) { + return false; + } +} diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/FrustumHolder.java b/src/main/java/net/coderbot/iris/shadows/frustum/FrustumHolder.java new file mode 100644 index 000000000..61a20b6c5 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/frustum/FrustumHolder.java @@ -0,0 +1,28 @@ +package net.coderbot.iris.shadows.frustum; + +import net.minecraft.client.renderer.culling.Frustum; + +public class FrustumHolder { + private Frustum frustum; + private String distanceInfo = "(unavailable)"; + private String cullingInfo = "(unavailable)"; + + public FrustumHolder setInfo(Frustum frustum, String distanceInfo, String cullingInfo) { + this.frustum = frustum; + this.distanceInfo = distanceInfo; + this.cullingInfo = cullingInfo; + return this; + } + + public Frustum getFrustum() { + return frustum; + } + + public String getDistanceInfo() { + return distanceInfo; + } + + public String getCullingInfo() { + return cullingInfo; + } +} diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java new file mode 100644 index 000000000..c4e39eb1d --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java @@ -0,0 +1,373 @@ +package net.coderbot.iris.shadows.frustum.advanced; + +import net.coderbot.iris.shadows.frustum.BoxCuller; +import net.minecraft.util.AxisAlignedBB; +import org.joml.Math; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.joml.Vector4f; + +/** + * A Frustum implementation that derives a tightly-fitted shadow pass frustum based on the player's camera frustum and + * an assumption that the shadow map will only be sampled for the purposes of direct shadow casting, volumetric lighting, + * and similar effects, but notably not sun-bounce GI or similar effects. + * + *

The key idea of this algorithm is that if you are looking at the sun, something behind you cannot directly cast + * a shadow on things visible to you. It's clear why this wouldn't work for sun-bounce GI, since with sun-bounce GI an + * object behind you could cause light to bounce on to things visible to you.

+ * + *

Derived from L. Spiro's clever algorithm & helpful diagrams described in a two-part blog tutorial:

+ * + * + * + *

Notable changes include switching out some of the sub-algorithms for computing the "extruded" edge planes to ones that + * are not sensitive to the specific internal ordering of planes and corners, in order to avoid potential bugs at the + * cost of slightly more computations.

+ */ +public class AdvancedShadowCullingFrustum extends Frustum { + private static final int MAX_CLIPPING_PLANES = 13; + + /** + * We store each plane equation as a Vector4f. + * + *

We can represent a plane equation of the form ax + by + cz = d as a 4-dimensional vector + * of the form (a, b, c, -d). In the special case of a plane that intersects the origin, we get + * the 4-dimensional vector (a, b, c, 0). (a, b, c) is the normal vector of the plane, and d is the + * distance of the plane from the origin along that normal vector.

+ * + *

Then, to test a given point (x, y, z) against the plane, we simply extend that point to a 4-component + * homogenous vector (x, y, z, 1), and then compute the dot product. Computing the dot product gives us + * ax + by + cz - d = 0, or, rearranged, our original plane equation of ax = by + cz = d.

+ * + *

Note that, for the purposes of frustum culling, we usually aren't interested in computing whether a point + * lies exactly on a plane. Rather, we are interested in determining which side of the plane the point exists on + * - the side closer to the origin, or the side farther away from the origin. Fortunately, doing this with the + * dot product is still simple. If the dot product is negative, then the point lies closer to the origin than the + * plane, and if the dot product is positive, then the point lies further from the origin than the plane.

+ * + *

In this case, if the point is closer to the origin than the plane, it is outside of the area enclosed by the + * plane, and if the point is farther from the origin than the plane, it is inside the area enclosed by the plane.

+ * + *

So: + *

    + *
  • dot(plane, point) > 0 implies the point is inside
  • + *
  • dot(plane, point) < 0 implies that the point is outside
  • + *
+ *

+ */ + private final Vector4f[] planes = new Vector4f[MAX_CLIPPING_PLANES]; + private int planeCount = 0; + + // The center coordinates of this frustum. + private double x; + private double y; + private double z; + + private final Vector3f shadowLightVectorFromOrigin; + private final BoxCuller boxCuller; + + public AdvancedShadowCullingFrustum(Matrix4f playerView, Matrix4f playerProjection, Vector3f shadowLightVectorFromOrigin, + BoxCuller boxCuller) { + // We're overriding all of the methods, don't pass any matrices down. + super(new com.mojang.math.Matrix4f(), new com.mojang.math.Matrix4f()); + + this.shadowLightVectorFromOrigin = shadowLightVectorFromOrigin; + BaseClippingPlanes baseClippingPlanes = new BaseClippingPlanes(playerView, playerProjection); + + boolean[] isBack = addBackPlanes(baseClippingPlanes); + addEdgePlanes(baseClippingPlanes, isBack); + + this.boxCuller = boxCuller; + } + + private void addPlane(Vector4f plane) { + planes[planeCount] = plane; + planeCount += 1; + } + + /** + * Adds the back planes of the player's view frustum from the perspective of the shadow light. + * This can eliminate many chunks, especially if the player is staring at the shadow light + * (sun / moon). + */ + private boolean[] addBackPlanes(BaseClippingPlanes baseClippingPlanes) { + Vector4f[] planes = baseClippingPlanes.getPlanes(); + boolean[] isBack = new boolean[planes.length]; + + for (int planeIndex = 0; planeIndex < planes.length; planeIndex++) { + Vector4f plane = planes[planeIndex]; + Vector3f planeNormal = truncate(plane); + + // Find back planes by looking for planes with a normal vector that points + // in the same general direction as the vector pointing from the origin to the shadow light + // + // That is, the angle between those two vectors is less than or equal to 90 degrees, + // meaning that the dot product is positive or zero. + + float dot = planeNormal.dot(shadowLightVectorFromOrigin); + + boolean back = dot > 0.0; + boolean edge = dot == 0.0; + + // TODO: audit behavior when the dot product is zero + isBack[planeIndex] = back; + + if (back || edge) { + addPlane(plane); + } + } + + return isBack; + } + + private void addEdgePlanes(BaseClippingPlanes baseClippingPlanes, boolean[] isBack) { + Vector4f[] planes = baseClippingPlanes.getPlanes(); + + for (int planeIndex = 0; planeIndex < planes.length; planeIndex++) { + if (!isBack[planeIndex]) { + continue; + } + + Vector4f plane = planes[planeIndex]; + + NeighboringPlaneSet neighbors = NeighboringPlaneSet.forPlane(planeIndex); + + if (!isBack[neighbors.getPlane0()]) { + addEdgePlane(plane, planes[neighbors.getPlane0()]); + } + + if (!isBack[neighbors.getPlane1()]) { + addEdgePlane(plane, planes[neighbors.getPlane1()]); + } + + if (!isBack[neighbors.getPlane2()]) { + addEdgePlane(plane, planes[neighbors.getPlane2()]); + } + + if (!isBack[neighbors.getPlane3()]) { + addEdgePlane(plane, planes[neighbors.getPlane3()]); + } + } + } + + private Vector3f truncate(Vector4f base) { + return new Vector3f(base.x(), base.y(), base.z()); + } + + private Vector4f extend(Vector3f base, float w) { + return new Vector4f(base.x(), base.y(), base.z(), w); + } + + private float lengthSquared(Vector3f v) { + float x = v.x(); + float y = v.y(); + float z = v.z(); + + return x * x + y * y + z * z; + } + + private Vector3f cross(Vector3f first, Vector3f second) { + Vector3f result = new Vector3f(first.x(), first.y(), first.z()); + result.cross(second); + + return result; + } + + private void addEdgePlane(Vector4f backPlane4, Vector4f frontPlane4) { + Vector3f backPlaneNormal = truncate(backPlane4); + Vector3f frontPlaneNormal = truncate(frontPlane4); + + // vector along the intersection of the two planes + Vector3f intersection = cross(backPlaneNormal, frontPlaneNormal); + + // compute edge plane normal, we want the normal vector of the edge plane + // to always be perpendicular to the shadow light vector (since that's + // what makes it an edge plane!) + Vector3f edgePlaneNormal = cross(intersection, shadowLightVectorFromOrigin); + + // At this point, we have a normal vector for our new edge plane, but we don't + // have a value for distance (d). We can solve for it with a little algebra, + // given that we want all 3 planes to intersect at a line. + + // Given the following system of equations: + // a₁x + b₁y + c₁z = d₁ + // a₂x + b₂y + c₂z = d₂ + // a₃x + b₃y + c₃z = d₃ + // + // Solve for -d₃, if a₁, b₁, c₁, -d₁, a₂, b₂, c₂, -d₂, a₃, b₃, and c₃ are all known, such that + // the 3 planes formed by the corresponding 3 plane equations intersect at a line. + + // First, we need to pick a point along the intersection line between our planes. + // Unfortunately, we don't have a complete line - only its vector. + // + // Fortunately, we can compute that point. If we create a plane passing through the origin + // with a normal vector parallel to the intersection line, then the intersection + // of all 3 planes will be a point on the line of intersection between the two planes we care about. + Vector3f point; + + { + // "Line of intersection between two planes" + // https://stackoverflow.com/a/32410473 by ideasman42, CC BY-SA 3.0 + // (a modified version of "Intersection of 2-planes" from Graphics Gems 1, page 305 + + // NB: We can assume that the intersection vector has a non-zero length. + Vector3f ixb = cross(intersection, backPlaneNormal); + Vector3f fxi = cross(frontPlaneNormal, intersection); + + ixb.mul(-frontPlane4.w()); + fxi.mul(-backPlane4.w()); + + ixb.add(fxi); + + point = ixb; + point.mul(1.0F / lengthSquared(intersection)); + } + + // Now that we have a point and a normal vector, we can make a plane. + + Vector4f plane; + + { + // dot(normal, (x, y, z) - point) = 0 + // a(x - point.x) + b(y - point.y) + c(z - point.z) = 0 + // d = a * point.x + b * point.y + c * point.z = dot(normal, point) + // w = -d + + float d = edgePlaneNormal.dot(point); + float w = -d; + + plane = extend(edgePlaneNormal, w); + } + + // Check and make sure our point is actually on all 3 planes. + // This can be removed in production but it's good to check for now while we're still testing. + /*{ + float dp0 = plane.dotProduct(extend(point, 1.0F)); + float dp1 = frontPlane4.dotProduct(extend(point, 1.0F)); + float dp2 = backPlane4.dotProduct(extend(point, 1.0F)); + + if (Math.abs(dp0) > 0.0005) { + throw new IllegalStateException("dp0 should be zero, but was " + dp0); + } + + if (Math.abs(dp1) > 0.0005) { + throw new IllegalStateException("dp1 should be zero, but was " + dp1); + } + + if (Math.abs(dp2) > 0.0005) { + throw new IllegalStateException("dp2 should be zero, but was " + dp2); + } + }*/ + + addPlane(plane); + } + + // Note: These functions are copied & modified from the vanilla Frustum class. + @Override + public void prepare(double cameraX, double cameraY, double cameraZ) { + if (this.boxCuller != null) { + boxCuller.setPosition(cameraX, cameraY, cameraZ); + } + + this.x = cameraX; + this.y = cameraY; + this.z = cameraZ; + } + + @Override + public boolean isVisible(AxisAlignedBB aabb) { + if (boxCuller != null && boxCuller.isCulled(aabb)) { + return false; + } + + return this.isVisible(aabb.minX, aabb.minY, aabb.minZ, aabb.maxX, aabb.maxY, aabb.maxZ); + } + + // For Sodium + // TODO: change this to respect intersections on 1.18+! + public boolean fastAabbTest(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + if (boxCuller != null && boxCuller.isCulled(minX, minY, minZ, maxX, maxY, maxZ)) { + return false; + } + + return isVisible(minX, minY, minZ, maxX, maxY, maxZ); + } + + // For Immersive Portals + // TODO: Figure out if IP culling can somehow be compatible with Iris culling. + public boolean canDetermineInvisible(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { + return false; + } + + private boolean isVisible(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { + float f = (float)(minX - this.x); + float g = (float)(minY - this.y); + float h = (float)(minZ - this.z); + float i = (float)(maxX - this.x); + float j = (float)(maxY - this.y); + float k = (float)(maxZ - this.z); + return this.checkCornerVisibility(f, g, h, i, j, k) != 0; + } + + + /** + * Checks corner visibility. + * @param minX Minimum X value of the AABB. + * @param minY Minimum Y value of the AABB. + * @param minZ Minimum Z value of the AABB. + * @param maxX Maximum X value of the AABB. + * @param maxY Maximum Y value of the AABB. + * @param maxZ Maximum Z value of the AABB. + * @return 0 if nothing is visible, 1 if everything is visible, 2 if only some corners are visible. + */ + private int checkCornerVisibility(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + boolean inside = true; + float outsideBoundX; + float outsideBoundY; + float outsideBoundZ; + float insideBoundX; + float insideBoundY; + float insideBoundZ; + + for (int i = 0; i < planeCount; ++i) { + Vector4f plane = this.planes[i]; + + // Check if plane is inside or intersecting. + // This is ported from JOML's FrustumIntersection. + + if (plane.x() < 0) { + outsideBoundX = minX; + insideBoundX = maxX; + } else { + outsideBoundX = maxX; + insideBoundX = minX; + } + + if (plane.y() < 0) { + outsideBoundY = minY; + insideBoundY = maxY; + } else { + outsideBoundY = maxY; + insideBoundY = minY; + } + + if (plane.z() < 0) { + outsideBoundZ = minZ; + insideBoundZ = maxZ; + } else { + outsideBoundZ = maxZ; + insideBoundZ = minZ; + } + + if (Math.fma(plane.x(), outsideBoundX, Math.fma(plane.y(), outsideBoundY, plane.z() * outsideBoundZ)) < -plane.w()) { + return 0; + } + inside &= Math.fma(plane.x(), insideBoundX, Math.fma(plane.y(), insideBoundY, plane.z() * insideBoundZ)) >= -plane.w(); + } + + return 2; + } +} diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/advanced/BaseClippingPlanes.java b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/BaseClippingPlanes.java new file mode 100644 index 000000000..c4d155350 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/BaseClippingPlanes.java @@ -0,0 +1,41 @@ +package net.coderbot.iris.shadows.frustum.advanced; + +import org.joml.Matrix4f; +import org.joml.Vector4f; + +public class BaseClippingPlanes { + private final Vector4f[] planes = new Vector4f[6]; + + public BaseClippingPlanes(Matrix4f playerView, Matrix4f playerProjection) { + this.init(playerView, playerProjection); + } + + private void init(Matrix4f view, Matrix4f projection) { + // Transform = Transpose(Projection x View) + + Matrix4f transform = new Matrix4f(projection); + transform.mul(view); + transform.transpose(); + + planes[0] = transform(transform, -1, 0, 0); + planes[1] = transform(transform, 1, 0, 0); + planes[2] = transform(transform, 0, -1, 0); + planes[3] = transform(transform, 0, 1, 0); + // FAR clipping plane + planes[4] = transform(transform, 0, 0, -1); + // NEAR clipping plane + planes[5] = transform(transform, 0, 0, 1); + } + + private static Vector4f transform(Matrix4f transform, float x, float y, float z) { + Vector4f vector4f = new Vector4f(x, y, z, 1.0F); + vector4f.mul(transform); + vector4f.normalize(); + + return vector4f; + } + + public Vector4f[] getPlanes() { + return planes; + } +} diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/advanced/NeighboringPlaneSet.java b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/NeighboringPlaneSet.java new file mode 100644 index 000000000..d631f6bc6 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/NeighboringPlaneSet.java @@ -0,0 +1,45 @@ +package net.coderbot.iris.shadows.frustum.advanced; + +public class NeighboringPlaneSet { + private static final NeighboringPlaneSet FOR_PLUS_X = new NeighboringPlaneSet(2, 3, 4, 5); + private static final NeighboringPlaneSet FOR_PLUS_Y = new NeighboringPlaneSet(0, 1, 4, 5); + private static final NeighboringPlaneSet FOR_PLUS_Z = new NeighboringPlaneSet(0, 1, 2, 3); + + private static final NeighboringPlaneSet[] TABLE = new NeighboringPlaneSet[] { + FOR_PLUS_X, + FOR_PLUS_Y, + FOR_PLUS_Z + }; + + private final int plane0; + private final int plane1; + private final int plane2; + private final int plane3; + + public NeighboringPlaneSet(int plane0, int plane1, int plane2, int plane3) { + this.plane0 = plane0; + this.plane1 = plane1; + this.plane2 = plane2; + this.plane3 = plane3; + } + + public static NeighboringPlaneSet forPlane(int planeIndex) { + return TABLE[planeIndex >>> 1]; + } + + public int getPlane0() { + return plane0; + } + + public int getPlane1() { + return plane1; + } + + public int getPlane2() { + return plane2; + } + + public int getPlane3() { + return plane3; + } +} diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java new file mode 100644 index 000000000..8191f83b7 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java @@ -0,0 +1,39 @@ +package net.coderbot.iris.shadows.frustum.fallback; + +import net.coderbot.iris.shadows.frustum.BoxCuller; +import net.minecraft.util.AxisAlignedBB; +import org.joml.Matrix4f; + +public class BoxCullingFrustum extends Frustum { + private final BoxCuller boxCuller; + + public BoxCullingFrustum(BoxCuller boxCuller) { + super(new Matrix4f(), new Matrix4f()); + + this.boxCuller = boxCuller; + } + + @Override + public void prepare(double cameraX, double cameraY, double cameraZ) { + boxCuller.setPosition(cameraX, cameraY, cameraZ); + } + + // for Sodium + // TODO: Better way to do this... Maybe we shouldn't be using a frustum for the box culling in the first place! + public boolean fastAabbTest(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + return !boxCuller.isCulled(minX, minY, minZ, maxX, maxY, maxZ); + } + + // For Immersive Portals + // NB: The shadow culling in Immersive Portals must be disabled, because when Advanced Shadow Frustum Culling + // is not active, we are at a point where we can make no assumptions how the shader pack uses the shadow + // pass beyond what it already tells us. So we cannot use any extra fancy culling methods. + public boolean canDetermineInvisible(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { + return false; + } + + @Override + public boolean isVisible(AxisAlignedBB aabb) { + return !boxCuller.isCulled(aabb); + } +} diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java new file mode 100644 index 000000000..822c72127 --- /dev/null +++ b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java @@ -0,0 +1,28 @@ +package net.coderbot.iris.shadows.frustum.fallback; + +import net.minecraft.util.AxisAlignedBB; +import org.joml.Matrix4f; + +public class NonCullingFrustum extends Frustum { + public NonCullingFrustum() { + super(new Matrix4f(), new Matrix4f()); + } + + // for Sodium + public boolean fastAabbTest(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + return true; + } + + // For Immersive Portals + // NB: The shadow culling in Immersive Portals must be disabled, because when Advanced Shadow Frustum Culling + // is not active, we are at a point where we can make no assumptions how the shader pack uses the shadow + // pass beyond what it already tells us. So we cannot use any extra fancy culling methods. + public boolean canDetermineInvisible(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { + return false; + } + + @Override + public boolean isVisible(AxisAlignedBB aabb) { + return true; + } +} diff --git a/src/main/java/net/coderbot/iris/texture/TextureInfoCache.java b/src/main/java/net/coderbot/iris/texture/TextureInfoCache.java new file mode 100644 index 000000000..883492394 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/TextureInfoCache.java @@ -0,0 +1,91 @@ +package net.coderbot.iris.texture; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL11; + +import java.nio.IntBuffer; + +public class TextureInfoCache { + public static final TextureInfoCache INSTANCE = new TextureInfoCache(); + + private final Int2ObjectMap cache = new Int2ObjectOpenHashMap<>(); + + private TextureInfoCache() { + } + + public TextureInfo getInfo(int id) { + TextureInfo info = cache.get(id); + if (info == null) { + info = new TextureInfo(id); + cache.put(id, info); + } + return info; + } + + public void onTexImage2D(int target, int level, int internalformat, int width, int height, int border, + int format, int type, @Nullable IntBuffer pixels) { + if (level == 0) { + int id = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + TextureInfo info = getInfo(id); + info.internalFormat = internalformat; + info.width = width; + info.height = height; + } + } + + public void onDeleteTexture(int id) { + cache.remove(id); + } + + public static class TextureInfo { + private final int id; + private int internalFormat = -1; + private int width = -1; + private int height = -1; + + private TextureInfo(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public int getInternalFormat() { + if (internalFormat == -1) { + internalFormat = fetchLevelParameter(GL11.GL_TEXTURE_INTERNAL_FORMAT); + } + return internalFormat; + } + + public int getWidth() { + if (width == -1) { + width = fetchLevelParameter(GL11.GL_TEXTURE_WIDTH); + } + return width; + } + + public int getHeight() { + if (height == -1) { + height = fetchLevelParameter(GL11.GL_TEXTURE_HEIGHT); + } + return height; + } + + private int fetchLevelParameter(int pname) { + // Keep track of what texture was bound before + int previousTextureBinding = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + + // Bind this texture and grab the parameter from it. + GL11.glBindTexture(GL11.GL_TEXTURE_2D, id); + int parameter = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, pname); + + // Make sure to re-bind the previous texture to avoid issues. + GL11.glBindTexture(GL11.GL_TEXTURE_2D, previousTextureBinding); + + return parameter; + } + } +} diff --git a/src/main/java/net/coderbot/iris/texture/TextureTracker.java b/src/main/java/net/coderbot/iris/texture/TextureTracker.java new file mode 100644 index 000000000..e2333ea31 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/TextureTracker.java @@ -0,0 +1,60 @@ +package net.coderbot.iris.texture; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.state.StateUpdateNotifiers; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.minecraft.client.renderer.texture.AbstractTexture; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL11; + +public class TextureTracker { + public static final TextureTracker INSTANCE = new TextureTracker(); + + private static Runnable bindTextureListener; + + static { + StateUpdateNotifiers.bindTextureNotifier = listener -> bindTextureListener = listener; + } + + private final Int2ObjectMap textures = new Int2ObjectOpenHashMap<>(); + + private boolean lockBindCallback; + + private TextureTracker() { + } + + public void trackTexture(int id, AbstractTexture texture) { + textures.put(id, texture); + } + + @Nullable + public AbstractTexture getTexture(int id) { + return textures.get(id); + } + + public void onBindTexture(int id) { + if (lockBindCallback) { + return; + } + if (GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D) == 0) { + lockBindCallback = true; + if (bindTextureListener != null) { + bindTextureListener.run(); + } + WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); + if (pipeline != null) { + pipeline.onBindTexture(id); + } + // Reset texture state + IrisRenderSystem.bindTextureToUnit(0, id); + lockBindCallback = false; + } + } + + public void onDeleteTexture(int id) { + textures.remove(id); + } +} diff --git a/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java b/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java new file mode 100644 index 000000000..568a71fe6 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java @@ -0,0 +1,71 @@ +package net.coderbot.iris.texture.format; + +import net.coderbot.iris.texture.mipmap.ChannelMipmapGenerator; +import net.coderbot.iris.texture.mipmap.CustomMipmapGenerator; +import net.coderbot.iris.texture.mipmap.DiscreteBlendFunction; +import net.coderbot.iris.texture.mipmap.LinearBlendFunction; +import net.coderbot.iris.texture.pbr.PBRType; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public class LabPBRTextureFormat implements TextureFormat { + public static final ChannelMipmapGenerator SPECULAR_MIPMAP_GENERATOR = new ChannelMipmapGenerator( + LinearBlendFunction.INSTANCE, + new DiscreteBlendFunction(v -> v < 230 ? 0 : v - 229), + new DiscreteBlendFunction(v -> v < 65 ? 0 : 1), + new DiscreteBlendFunction(v -> v < 255 ? 0 : 1) + ); + + private final String name; + @Nullable + private final String version; + + public LabPBRTextureFormat(String name, @Nullable String version) { + this.name = name; + this.version = version; + } + + @Override + public String getName() { + return name; + } + + @Override + public @Nullable String getVersion() { + return version; + } + + @Override + public boolean canInterpolateValues(PBRType pbrType) { + if (pbrType == PBRType.SPECULAR) { + return false; + } + return true; + } + + @Override + public @Nullable CustomMipmapGenerator getMipmapGenerator(PBRType pbrType) { + if (pbrType == PBRType.SPECULAR) { + return SPECULAR_MIPMAP_GENERATOR; + } + return null; + } + + @Override + public int hashCode() { + return Objects.hash(name, version); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + LabPBRTextureFormat other = (LabPBRTextureFormat) obj; + return Objects.equals(name, other.name) && Objects.equals(version, other.version); + } +} diff --git a/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java b/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java new file mode 100644 index 000000000..d9662078d --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java @@ -0,0 +1,64 @@ +package net.coderbot.iris.texture.format; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.texture.mipmap.CustomMipmapGenerator; +import net.coderbot.iris.texture.pbr.PBRType; +import net.minecraft.client.renderer.texture.AbstractTexture; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public interface TextureFormat { + String getName(); + + @Nullable + String getVersion(); + + default List getDefines() { + List defines = new ArrayList<>(); + + String defineName = getName().toUpperCase(Locale.ROOT).replaceAll("-", "_"); + String define = "MC_TEXTURE_FORMAT_" + defineName; + defines.add(define); + + String version = getVersion(); + if (version != null) { + String defineVersion = version.replaceAll("[.-]", "_"); + String versionDefine = define + "_" + defineVersion; + defines.add(versionDefine); + } + + return defines; + } + + /** + * Dictates whether textures of the given PBR type can have their color values interpolated or not. + * Usually, this controls the texture minification and magification filters - + * a return value of false would signify that the linear filters cannot be used. + * + * @param pbrType The type of PBR texture + * @return If texture values can be interpolated or not + */ + boolean canInterpolateValues(PBRType pbrType); + + default void setupTextureParameters(PBRType pbrType, AbstractTexture texture) { + if (!canInterpolateValues(pbrType)) { + int minFilter = IrisRenderSystem.getTexParameteri(texture.getId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER); + // Non-mipped filters begin at 0x2600 whereas mipped filters begin at 0x2700, + // so this bit mask can be used to check if the filter is mipped or not + boolean mipmap = (minFilter & 1 << 8) == 1; + IrisRenderSystem.texParameteri(texture.getId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mipmap ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_NEAREST); + IrisRenderSystem.texParameteri(texture.getId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + } + } + + @Nullable + CustomMipmapGenerator getMipmapGenerator(PBRType pbrType); + + public interface Factory { + TextureFormat createFormat(String name, @Nullable String version); + } +} diff --git a/src/main/java/net/coderbot/iris/texture/format/TextureFormatLoader.java b/src/main/java/net/coderbot/iris/texture/format/TextureFormatLoader.java new file mode 100644 index 000000000..2c3851aa2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/format/TextureFormatLoader.java @@ -0,0 +1,72 @@ +package net.coderbot.iris.texture.format; + +import net.coderbot.iris.Iris; +import net.minecraft.client.resources.IResource; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.util.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Objects; +import java.util.Properties; + +public class TextureFormatLoader { + public static final ResourceLocation LOCATION = new ResourceLocation("optifine/texture.properties"); + + private static TextureFormat format; + + @Nullable + public static TextureFormat getFormat() { + return format; + } + + public static void reload(IResourceManager resourceManager) { + TextureFormat newFormat = loadFormat(resourceManager); + boolean didFormatChange = !Objects.equals(format, newFormat); + format = newFormat; + if (didFormatChange) { + onFormatChange(); + } + } + + @Nullable + private static TextureFormat loadFormat(IResourceManager resourceManager) { + try (IResource resource = resourceManager.getResource(LOCATION)) { + Properties properties = new Properties(); + properties.load(resource.getInputStream()); + String format = properties.getProperty("format"); + if (format != null && !format.isEmpty()) { + String[] splitFormat = format.split("/"); + if (splitFormat.length > 0) { + String name = splitFormat[0]; + TextureFormat.Factory factory = TextureFormatRegistry.INSTANCE.getFactory(name); + if (factory != null) { + String version; + if (splitFormat.length > 1) { + version = splitFormat[1]; + } else { + version = null; + } + return factory.createFormat(name, version); + } else { + Iris.logger.warn("Invalid texture format '" + name + "' in file '" + LOCATION + "'"); + } + } + } + } catch (FileNotFoundException e) { + // + } catch (Exception e) { + Iris.logger.error("Failed to load texture format from file '" + LOCATION + "'", e); + } + return null; + } + + private static void onFormatChange() { + try { + Iris.reload(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/net/coderbot/iris/texture/format/TextureFormatRegistry.java b/src/main/java/net/coderbot/iris/texture/format/TextureFormatRegistry.java new file mode 100644 index 000000000..513524d67 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/format/TextureFormatRegistry.java @@ -0,0 +1,25 @@ +package net.coderbot.iris.texture.format; + +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public class TextureFormatRegistry { + public static final TextureFormatRegistry INSTANCE = new TextureFormatRegistry(); + + static { + INSTANCE.register("lab-pbr", LabPBRTextureFormat::new); + } + + private final Map factoryMap = new HashMap<>(); + + public void register(String name, TextureFormat.Factory factory) { + factoryMap.put(name, factory); + } + + @Nullable + public TextureFormat.Factory getFactory(String name) { + return factoryMap.get(name); + } +} diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java new file mode 100644 index 000000000..0031af417 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java @@ -0,0 +1,32 @@ +package net.coderbot.iris.texture.mipmap; + + +public abstract class AbstractMipmapGenerator implements CustomMipmapGenerator { + @Override + public NativeImage[] generateMipLevels(NativeImage image, int mipLevel) { + NativeImage[] images = new NativeImage[mipLevel + 1]; + images[0] = image; + if (mipLevel > 0) { + for (int level = 1; level <= mipLevel; ++level) { + NativeImage prevMipmap = images[level - 1]; + NativeImage mipmap = new NativeImage(prevMipmap.getWidth() >> 1, prevMipmap.getHeight() >> 1, false); + int width = mipmap.getWidth(); + int height = mipmap.getHeight(); + for (int x = 0; x < width; ++x) { + for (int y = 0; y < height; ++y) { + mipmap.setPixelRGBA(x, y, blend( + prevMipmap.getPixelRGBA(x * 2 + 0, y * 2 + 0), + prevMipmap.getPixelRGBA(x * 2 + 1, y * 2 + 0), + prevMipmap.getPixelRGBA(x * 2 + 0, y * 2 + 1), + prevMipmap.getPixelRGBA(x * 2 + 1, y * 2 + 1) + )); + } + } + images[level] = mipmap; + } + } + return images; + } + + public abstract int blend(int c0, int c1, int c2, int c3); +} diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java new file mode 100644 index 000000000..eb2b9ecef --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java @@ -0,0 +1,50 @@ +package net.coderbot.iris.texture.mipmap; + + +public class ChannelMipmapGenerator extends AbstractMipmapGenerator { + protected final BlendFunction redFunc; + protected final BlendFunction greenFunc; + protected final BlendFunction blueFunc; + protected final BlendFunction alphaFunc; + + public ChannelMipmapGenerator(BlendFunction redFunc, BlendFunction greenFunc, BlendFunction blueFunc, BlendFunction alphaFunc) { + this.redFunc = redFunc; + this.greenFunc = greenFunc; + this.blueFunc = blueFunc; + this.alphaFunc = alphaFunc; + } + + @Override + public int blend(int c0, int c1, int c2, int c3) { + return NativeImage.combine( + alphaFunc.blend( + NativeImage.getA(c0), + NativeImage.getA(c1), + NativeImage.getA(c2), + NativeImage.getA(c3) + ), + blueFunc.blend( + NativeImage.getB(c0), + NativeImage.getB(c1), + NativeImage.getB(c2), + NativeImage.getB(c3) + ), + greenFunc.blend( + NativeImage.getG(c0), + NativeImage.getG(c1), + NativeImage.getG(c2), + NativeImage.getG(c3) + ), + redFunc.blend( + NativeImage.getR(c0), + NativeImage.getR(c1), + NativeImage.getR(c2), + NativeImage.getR(c3) + ) + ); + } + + public interface BlendFunction { + int blend(int v0, int v1, int v2, int v3); + } +} diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java new file mode 100644 index 000000000..15d462970 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java @@ -0,0 +1,13 @@ +package net.coderbot.iris.texture.mipmap; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import org.jetbrains.annotations.Nullable; + +public interface CustomMipmapGenerator { + NativeImage[] generateMipLevels(NativeImage image, int mipLevel); + + public interface Provider { + @Nullable + CustomMipmapGenerator getMipmapGenerator(TextureAtlasSprite.Info info, int atlasWidth, int atlasHeight); + } +} diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/DiscreteBlendFunction.java b/src/main/java/net/coderbot/iris/texture/mipmap/DiscreteBlendFunction.java new file mode 100644 index 000000000..9abc05879 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/mipmap/DiscreteBlendFunction.java @@ -0,0 +1,58 @@ +package net.coderbot.iris.texture.mipmap; + +import java.util.function.IntUnaryOperator; + +public class DiscreteBlendFunction implements ChannelMipmapGenerator.BlendFunction { + protected final IntUnaryOperator typeFunc; + + public DiscreteBlendFunction(IntUnaryOperator typeFunc) { + this.typeFunc = typeFunc; + } + + @Override + public int blend(int v0, int v1, int v2, int v3) { + int t0 = typeFunc.applyAsInt(v0); + int t1 = typeFunc.applyAsInt(v1); + int t2 = typeFunc.applyAsInt(v2); + int t3 = typeFunc.applyAsInt(v3); + + int targetType = selectTargetType(t0, t1, t2, t3); + + int sum = 0; + int amount = 0; + if (t0 == targetType) { + sum += v0; + amount++; + } + if (t1 == targetType) { + sum += v1; + amount++; + } + if (t2 == targetType) { + sum += v2; + amount++; + } + if (t3 == targetType) { + sum += v3; + amount++; + } + + return sum / amount; + } + + /** + * Selects the type that appears most often among the arguments. + * In the case of a tie, types that appear first in the argument list are given priority. + * A type is represented by an integer. + * */ + public static int selectTargetType(int t0, int t1, int t2, int t3) { + if (t0 != t1 && t0 != t2) { + if (t2 == t3) { + return t2; + } else if (t0 != t3 && (t1 == t2 || t1 == t3)) { + return t1; + } + } + return t0; + } +} diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/LinearBlendFunction.java b/src/main/java/net/coderbot/iris/texture/mipmap/LinearBlendFunction.java new file mode 100644 index 000000000..22faccc7b --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/mipmap/LinearBlendFunction.java @@ -0,0 +1,10 @@ +package net.coderbot.iris.texture.mipmap; + +public class LinearBlendFunction implements ChannelMipmapGenerator.BlendFunction { + public static final LinearBlendFunction INSTANCE = new LinearBlendFunction(); + + @Override + public int blend(int v0, int v1, int v2, int v3) { + return (v0 + v1 + v2 + v3) / 4; + } +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasHolder.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasHolder.java new file mode 100644 index 000000000..49e781712 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasHolder.java @@ -0,0 +1,35 @@ +package net.coderbot.iris.texture.pbr; + +import org.jetbrains.annotations.Nullable; + +public class PBRAtlasHolder { + protected PBRAtlasTexture normalAtlas; + protected PBRAtlasTexture specularAtlas; + + @Nullable + public PBRAtlasTexture getNormalAtlas() { + return normalAtlas; + } + + @Nullable + public PBRAtlasTexture getSpecularAtlas() { + return specularAtlas; + } + + public void setNormalAtlas(PBRAtlasTexture atlas) { + normalAtlas = atlas; + } + + public void setSpecularAtlas(PBRAtlasTexture atlas) { + specularAtlas = atlas; + } + + public void cycleAnimationFrames() { + if (normalAtlas != null) { + normalAtlas.cycleAnimationFrames(); + } + if (specularAtlas != null) { + specularAtlas.cycleAnimationFrames(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java new file mode 100644 index 000000000..bd5b286f8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java @@ -0,0 +1,147 @@ +package net.coderbot.iris.texture.pbr; + +import com.gtnewhorizons.angelica.mixins.early.accessors.TextureAtlasSpriteAccessor; +import com.gtnewhorizons.angelica.mixins.early.textures.MixinTextureAtlasSprite; +import net.coderbot.iris.texture.util.TextureExporter; +import net.coderbot.iris.texture.util.TextureManipulationUtil; +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.client.resources.data.AnimationMetadataSection; +import net.minecraft.crash.CrashReport; +import net.minecraft.crash.CrashReportCategory; +import net.minecraft.util.ReportedException; +import net.minecraft.util.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class PBRAtlasTexture extends AbstractTexture { + protected final TextureAtlas atlasTexture; + protected final PBRType type; + protected final ResourceLocation id; + protected final Map sprites = new HashMap<>(); + protected final Set animatedSprites = new HashSet<>(); + + public PBRAtlasTexture(TextureAtlas atlasTexture, PBRType type) { + this.atlasTexture = atlasTexture; + this.type = type; + id = type.appendToFileLocation(atlasTexture.location()); + } + + public PBRType getType() { + return type; + } + + public ResourceLocation getAtlasId() { + return id; + } + + public void addSprite(TextureAtlasSprite sprite) { + // Wants location + sprites.put(sprite.getName(), sprite); + if (((MixinTextureAtlasSprite) (Object)sprite).isAnimation()) { + animatedSprites.add(sprite); + } + } + + @Nullable + public TextureAtlasSprite getSprite(ResourceLocation id) { + return sprites.get(id); + } + + public void clear() { + sprites.clear(); + animatedSprites.clear(); + } + + public void upload(int atlasWidth, int atlasHeight, int mipLevel) { + int glId = getGlTextureId(); + TextureUtil.prepareImage(glId, mipLevel, atlasWidth, atlasHeight); + TextureManipulationUtil.fillWithColor(glId, mipLevel, type.getDefaultValue()); + + for (TextureAtlasSprite sprite : sprites.values()) { + try { + uploadSprite(sprite); + } catch (Throwable throwable) { + CrashReport crashReport = CrashReport.forThrowable(throwable, "Stitching texture atlas"); + CrashReportCategory crashReportCategory = crashReport.addCategory("Texture being stitched together"); + crashReportCategory.setDetail("Atlas path", id); + crashReportCategory.setDetail("Sprite", sprite); + throw new ReportedException(crashReport); + } + } + + if (!animatedSprites.isEmpty()) { + PBRAtlasHolder pbrHolder = ((TextureAtlasExtension) atlasTexture).getOrCreatePBRHolder(); + switch (type) { + case NORMAL: + pbrHolder.setNormalAtlas(this); + break; + case SPECULAR: + pbrHolder.setSpecularAtlas(this); + break; + } + } + + if (PBRTextureManager.DEBUG) { + TextureExporter.exportTextures("pbr_debug/atlas", id.getResourceDomain() + "_" + id.getResourcePath().replaceAll("/", "_"), glId, mipLevel, atlasWidth, atlasHeight); + } + } + + public boolean tryUpload(int atlasWidth, int atlasHeight, int mipLevel) { + try { + upload(atlasWidth, atlasHeight, mipLevel); + return true; + } catch (Throwable t) { + return false; + } + } + + protected void uploadSprite(TextureAtlasSprite sprite) { + if (((MixinTextureAtlasSprite) (Object)sprite).isAnimation()) { + TextureAtlasSpriteAccessor accessor = (TextureAtlasSpriteAccessor) sprite; + AnimationMetadataSection metadata = accessor.getMetadata(); + + int frameCount = sprite.getFrameCount(); + for (int frame = accessor.getFrame(); frame >= 0; frame--) { + int frameIndex = metadata.getFrameIndex(frame); + if (frameIndex >= 0 && frameIndex < frameCount) { + accessor.callUpload(frameIndex); + return; + } + } + } + + sprite.uploadFirstFrame(); + } + + public void cycleAnimationFrames() { + bind(); + for (TextureAtlasSprite sprite : animatedSprites) { + sprite.cycleFrames(); + } + } + + @Override + public void close() { + PBRAtlasHolder pbrHolder = ((TextureAtlasExtension) atlasTexture).getPBRHolder(); + if (pbrHolder != null) { + switch (type) { + case NORMAL: + pbrHolder.setNormalAtlas(null); + break; + case SPECULAR: + pbrHolder.setSpecularAtlas(null); + break; + } + } + } + +// @Override + public void load(IResourceManager manager) { + } +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java new file mode 100644 index 000000000..2956b01fc --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java @@ -0,0 +1,36 @@ +package net.coderbot.iris.texture.pbr; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import org.jetbrains.annotations.Nullable; + +public class PBRSpriteHolder { + protected TextureAtlasSprite normalSprite; + protected TextureAtlasSprite specularSprite; + + @Nullable + public TextureAtlasSprite getNormalSprite() { + return normalSprite; + } + + @Nullable + public TextureAtlasSprite getSpecularSprite() { + return specularSprite; + } + + public void setNormalSprite(TextureAtlasSprite sprite) { + normalSprite = sprite; + } + + public void setSpecularSprite(TextureAtlasSprite sprite) { + specularSprite = sprite; + } + + public void close() { + if (normalSprite != null) { + normalSprite.close(); + } + if (specularSprite != null) { + specularSprite.close(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRTextureHolder.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRTextureHolder.java new file mode 100644 index 000000000..defaf949f --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRTextureHolder.java @@ -0,0 +1,12 @@ +package net.coderbot.iris.texture.pbr; + +import net.minecraft.client.renderer.texture.AbstractTexture; +import org.jetbrains.annotations.NotNull; + +public interface PBRTextureHolder { + @NotNull + AbstractTexture getNormalTexture(); + + @NotNull + AbstractTexture getSpecularTexture(); +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRTextureManager.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRTextureManager.java new file mode 100644 index 000000000..2a27d24e8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRTextureManager.java @@ -0,0 +1,199 @@ +package net.coderbot.iris.texture.pbr; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.state.StateUpdateNotifiers; +import net.coderbot.iris.rendertarget.NativeImageBackedSingleColorTexture; +import net.coderbot.iris.texture.TextureTracker; +import net.coderbot.iris.texture.pbr.loader.PBRTextureLoader; +import net.coderbot.iris.texture.pbr.loader.PBRTextureLoader.PBRTextureConsumer; +import net.coderbot.iris.texture.pbr.loader.PBRTextureLoaderRegistry; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.AbstractTexture; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.opengl.GL11; + +public class PBRTextureManager { + public static final PBRTextureManager INSTANCE = new PBRTextureManager(); + + public static final boolean DEBUG = System.getProperty("iris.pbr.debug") != null; + + // TODO: Figure out how to merge these two. + private static Runnable normalTextureChangeListener; + private static Runnable specularTextureChangeListener; + + static { + StateUpdateNotifiers.normalTextureChangeNotifier = listener -> normalTextureChangeListener = listener; + StateUpdateNotifiers.specularTextureChangeNotifier = listener -> specularTextureChangeListener = listener; + } + + private final Int2ObjectMap holders = new Int2ObjectOpenHashMap<>(); + private final PBRTextureConsumerImpl consumer = new PBRTextureConsumerImpl(); + + private NativeImageBackedSingleColorTexture defaultNormalTexture; + private NativeImageBackedSingleColorTexture defaultSpecularTexture; + // Not PBRTextureHolderImpl to directly reference fields + private final PBRTextureHolder defaultHolder = new PBRTextureHolder() { + @Override + public @NotNull AbstractTexture getNormalTexture() { + return defaultNormalTexture; + } + + @Override + public @NotNull AbstractTexture getSpecularTexture() { + return defaultSpecularTexture; + } + }; + + private PBRTextureManager() { + } + + public void init() { + defaultNormalTexture = new NativeImageBackedSingleColorTexture(PBRType.NORMAL.getDefaultValue()); + defaultSpecularTexture = new NativeImageBackedSingleColorTexture(PBRType.SPECULAR.getDefaultValue()); + } + + public PBRTextureHolder getHolder(int id) { + PBRTextureHolder holder = holders.get(id); + if (holder == null) { + return defaultHolder; + } + return holder; + } + + public PBRTextureHolder getOrLoadHolder(int id) { + PBRTextureHolder holder = holders.get(id); + if (holder == null) { + holder = loadHolder(id); + holders.put(id, holder); + } + return holder; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private PBRTextureHolder loadHolder(int id) { + AbstractTexture texture = TextureTracker.INSTANCE.getTexture(id); + if (texture != null) { + Class clazz = texture.getClass(); + PBRTextureLoader loader = PBRTextureLoaderRegistry.INSTANCE.getLoader(clazz); + if (loader != null) { + int previousTextureBinding = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + consumer.clear(); + try { + loader.load(texture, Minecraft.getMinecraft().getResourceManager(), consumer); + return consumer.toHolder(); + } catch (Exception e) { + Iris.logger.debug("Failed to load PBR textures for texture " + id, e); + } finally { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, previousTextureBinding); + } + } + } + return defaultHolder; + } + + public void onDeleteTexture(int id) { + PBRTextureHolder holder = holders.remove(id); + if (holder != null) { + closeHolder(holder); + } + } + + public void clear() { + for (PBRTextureHolder holder : holders.values()) { + if (holder != defaultHolder) { + closeHolder(holder); + } + } + holders.clear(); + } + + public void close() { + clear(); + defaultNormalTexture.close(); + defaultSpecularTexture.close(); + } + + private void closeHolder(PBRTextureHolder holder) { + AbstractTexture normalTexture = holder.getNormalTexture(); + AbstractTexture specularTexture = holder.getSpecularTexture(); + if (normalTexture != defaultNormalTexture) { + closeTexture(normalTexture); + } + if (specularTexture != defaultSpecularTexture) { + closeTexture(specularTexture); + } + } + + private static void closeTexture(AbstractTexture texture) { + try { + texture.close(); + } catch (Exception e) { + // + } + texture.releaseId(); + } + + public static void notifyPBRTexturesChanged() { + if (normalTextureChangeListener != null) { + normalTextureChangeListener.run(); + } + + if (specularTextureChangeListener != null) { + specularTextureChangeListener.run(); + } + } + + private class PBRTextureConsumerImpl implements PBRTextureConsumer { + private AbstractTexture normalTexture; + private AbstractTexture specularTexture; + private boolean changed; + + @Override + public void acceptNormalTexture(@NotNull AbstractTexture texture) { + normalTexture = texture; + changed = true; + } + + @Override + public void acceptSpecularTexture(@NotNull AbstractTexture texture) { + specularTexture = texture; + changed = true; + } + + public void clear() { + normalTexture = defaultNormalTexture; + specularTexture = defaultSpecularTexture; + changed = false; + } + + public PBRTextureHolder toHolder() { + if (changed) { + return new PBRTextureHolderImpl(normalTexture, specularTexture); + } else { + return defaultHolder; + } + } + } + + private static class PBRTextureHolderImpl implements PBRTextureHolder { + private final AbstractTexture normalTexture; + private final AbstractTexture specularTexture; + + public PBRTextureHolderImpl(AbstractTexture normalTexture, AbstractTexture specularTexture) { + this.normalTexture = normalTexture; + this.specularTexture = specularTexture; + } + + @Override + public @NotNull AbstractTexture getNormalTexture() { + return normalTexture; + } + + @Override + public @NotNull AbstractTexture getSpecularTexture() { + return specularTexture; + } + } +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRType.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRType.java new file mode 100644 index 000000000..ec5d3fb2e --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRType.java @@ -0,0 +1,56 @@ +package net.coderbot.iris.texture.pbr; + +import net.minecraft.util.ResourceLocation; +import org.apache.commons.io.FilenameUtils; +import org.jetbrains.annotations.Nullable; + +public enum PBRType { + NORMAL("_n", 0x7F7FFFFF), + SPECULAR("_s", 0x00000000); + + private static final PBRType[] VALUES = values(); + + private final String suffix; + private final int defaultValue; + + PBRType(String suffix, int defaultValue) { + this.suffix = suffix; + this.defaultValue = defaultValue; + } + + public String getSuffix() { + return suffix; + } + + public int getDefaultValue() { + return defaultValue; + } + + public ResourceLocation appendToFileLocation(ResourceLocation location) { + String path = location.getResourcePath(); + String newPath; + int extensionIndex = FilenameUtils.indexOfExtension(path); + if (extensionIndex != -1) { + newPath = path.substring(0, extensionIndex) + suffix + path.substring(extensionIndex); + } else { + newPath = path + suffix; + } + return new ResourceLocation(location.getResourceDomain(), newPath); + } + + /** + * Returns the PBR type corresponding to the suffix of the given file location. + * + * @param location The file location without an extension + * @return the PBR type + */ + @Nullable + public static PBRType fromFileLocation(String location) { + for (PBRType type : VALUES) { + if (location.endsWith(type.getSuffix())) { + return type; + } + } + return null; + } +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/TextureAtlasExtension.java b/src/main/java/net/coderbot/iris/texture/pbr/TextureAtlasExtension.java new file mode 100644 index 000000000..d8ce9fcba --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/TextureAtlasExtension.java @@ -0,0 +1,10 @@ +package net.coderbot.iris.texture.pbr; + +import org.jetbrains.annotations.Nullable; + +public interface TextureAtlasExtension { + @Nullable + PBRAtlasHolder getPBRHolder(); + + PBRAtlasHolder getOrCreatePBRHolder(); +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/TextureAtlasSpriteExtension.java b/src/main/java/net/coderbot/iris/texture/pbr/TextureAtlasSpriteExtension.java new file mode 100644 index 000000000..7a46ba5bc --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/TextureAtlasSpriteExtension.java @@ -0,0 +1,10 @@ +package net.coderbot.iris.texture.pbr; + +import org.jetbrains.annotations.Nullable; + +public interface TextureAtlasSpriteExtension { + @Nullable + PBRSpriteHolder getPBRHolder(); + + PBRSpriteHolder getOrCreatePBRHolder(); +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java new file mode 100644 index 000000000..5674ba71d --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java @@ -0,0 +1,222 @@ +package net.coderbot.iris.texture.pbr.loader; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.texture.TextureInfoCache; +import net.coderbot.iris.texture.TextureInfoCache.TextureInfo; +import net.coderbot.iris.texture.format.TextureFormat; +import net.coderbot.iris.texture.format.TextureFormatLoader; +import net.coderbot.iris.texture.mipmap.ChannelMipmapGenerator; +import net.coderbot.iris.texture.mipmap.CustomMipmapGenerator; +import net.coderbot.iris.texture.mipmap.LinearBlendFunction; +import net.coderbot.iris.texture.pbr.PBRAtlasTexture; +import net.coderbot.iris.texture.pbr.PBRSpriteHolder; +import net.coderbot.iris.texture.pbr.PBRType; +import net.coderbot.iris.texture.pbr.TextureAtlasSpriteExtension; +import net.coderbot.iris.texture.util.ImageManipulationUtil; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.IResource; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.client.resources.data.AnimationMetadataSection; +import net.minecraft.util.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.io.FileNotFoundException; +import java.io.IOException; + +public class AtlasPBRLoader implements PBRTextureLoader { + public static final ChannelMipmapGenerator LINEAR_MIPMAP_GENERATOR = new ChannelMipmapGenerator( + LinearBlendFunction.INSTANCE, + LinearBlendFunction.INSTANCE, + LinearBlendFunction.INSTANCE, + LinearBlendFunction.INSTANCE + ); + + @Override + public void load(TextureAtlas atlas, IResourceManager resourceManager, PBRTextureConsumer pbrTextureConsumer) { + TextureInfo textureInfo = TextureInfoCache.INSTANCE.getInfo(atlas.getId()); + int atlasWidth = textureInfo.getWidth(); + int atlasHeight = textureInfo.getHeight(); + int mipLevel = fetchAtlasMipLevel(atlas); + + PBRAtlasTexture normalAtlas = null; + PBRAtlasTexture specularAtlas = null; + for (TextureAtlasSprite sprite : ((TextureAtlasAccessor) atlas).getTexturesByName().values()) { + if (!(sprite instanceof MissingTextureAtlasSprite)) { + TextureAtlasSprite normalSprite = createPBRSprite(sprite, resourceManager, atlas, atlasWidth, atlasHeight, mipLevel, PBRType.NORMAL); + TextureAtlasSprite specularSprite = createPBRSprite(sprite, resourceManager, atlas, atlasWidth, atlasHeight, mipLevel, PBRType.SPECULAR); + if (normalSprite != null) { + if (normalAtlas == null) { + normalAtlas = new PBRAtlasTexture(atlas, PBRType.NORMAL); + } + normalAtlas.addSprite(normalSprite); + PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); + pbrSpriteHolder.setNormalSprite(normalSprite); + } + if (specularSprite != null) { + if (specularAtlas == null) { + specularAtlas = new PBRAtlasTexture(atlas, PBRType.SPECULAR); + } + specularAtlas.addSprite(specularSprite); + PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); + pbrSpriteHolder.setSpecularSprite(specularSprite); + } + } + } + + if (normalAtlas != null) { + if (normalAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { + pbrTextureConsumer.acceptNormalTexture(normalAtlas); + } + } + if (specularAtlas != null) { + if (specularAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { + pbrTextureConsumer.acceptSpecularTexture(specularAtlas); + } + } + } + + protected static int fetchAtlasMipLevel(TextureAtlas atlas) { + TextureAtlasSprite missingSprite = atlas.getSprite(MissingTextureAtlasSprite.getLocation()); + return ((TextureAtlasSpriteAccessor) missingSprite).getMainImage().length - 1; + } + + @Nullable + protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourceManager resourceManager, TextureAtlas atlas, int atlasWidth, int atlasHeight, int mipLevel, PBRType pbrType) { + ResourceLocation spriteName = sprite.getName(); + ResourceLocation imageLocation = ((TextureAtlasAccessor) atlas).callGetResourceLocation(spriteName); + ResourceLocation pbrImageLocation = pbrType.appendToFileLocation(imageLocation); + + TextureAtlasSprite pbrSprite = null; + try (IResource resource = resourceManager.getResource(pbrImageLocation)) { + NativeImage nativeImage = NativeImage.read(resource.getInputStream()); + AnimationMetadataSection animationMetadata = resource.getMetadata(AnimationMetadataSection.SERIALIZER); + if (animationMetadata == null) { + animationMetadata = AnimationMetadataSection.EMPTY; + } + + Pair frameSize = animationMetadata.getFrameSize(nativeImage.getWidth(), nativeImage.getHeight()); + int frameWidth = frameSize.getFirst(); + int frameHeight = frameSize.getSecond(); + int targetFrameWidth = sprite.getWidth(); + int targetFrameHeight = sprite.getHeight(); + if (frameWidth != targetFrameWidth || frameHeight != targetFrameHeight) { + int imageWidth = nativeImage.getWidth(); + int imageHeight = nativeImage.getHeight(); + + // We can assume the following is always true as a result of getFrameSize's check: + // imageWidth % frameWidth == 0 && imageHeight % frameHeight == 0 + int targetImageWidth = imageWidth / frameWidth * targetFrameWidth; + int targetImageHeight = imageHeight / frameHeight * targetFrameHeight; + + NativeImage scaledImage; + if (targetImageWidth % imageWidth == 0 && targetImageHeight % imageHeight == 0) { + scaledImage = ImageManipulationUtil.scaleNearestNeighbor(nativeImage, targetImageWidth, targetImageHeight); + } else { + scaledImage = ImageManipulationUtil.scaleBilinear(nativeImage, targetImageWidth, targetImageHeight); + } + nativeImage.close(); + nativeImage = scaledImage; + + frameWidth = targetFrameWidth; + frameHeight = targetFrameHeight; + + if (animationMetadata != AnimationMetadataSection.EMPTY) { + AnimationMetadataSectionAccessor animationAccessor = (AnimationMetadataSectionAccessor) animationMetadata; + int internalFrameWidth = animationAccessor.getFrameWidth(); + int internalFrameHeight = animationAccessor.getFrameHeight(); + if (internalFrameWidth != -1) { + animationAccessor.setFrameWidth(frameWidth); + } + if (internalFrameHeight != -1) { + animationAccessor.setFrameHeight(frameHeight); + } + } + } + + ResourceLocation pbrSpriteName = new ResourceLocation(spriteName.getNamespace(), spriteName.getPath() + pbrType.getSuffix()); + TextureAtlasSprite.Info pbrSpriteInfo = new PBRTextureAtlasSpriteInfo(pbrSpriteName, frameWidth, frameHeight, animationMetadata, pbrType); + + int x = ((TextureAtlasSpriteAccessor) sprite).getX(); + int y = ((TextureAtlasSpriteAccessor) sprite).getY(); + pbrSprite = new PBRTextureAtlasSprite(atlas, pbrSpriteInfo, mipLevel, atlasWidth, atlasHeight, x, y, nativeImage); + syncAnimation(sprite, pbrSprite); + } catch (FileNotFoundException e) { + // + } catch (RuntimeException e) { + Iris.logger.error("Unable to parse metadata from {} : {}", pbrImageLocation, e); + } catch (IOException e) { + Iris.logger.error("Unable to load {} : {}", pbrImageLocation, e); + } + + return pbrSprite; + } + + protected void syncAnimation(TextureAtlasSprite source, TextureAtlasSprite target) { + // TODO: Iris Shaders - animationMetadata && animationMetadata.getFrameCount() > 0 + if (!source.isAnimation() || !target.isAnimation()) { + return; + } + + TextureAtlasSpriteAccessor sourceAccessor = ((TextureAtlasSpriteAccessor) source); + AnimationMetadataSection sourceMetadata = sourceAccessor.getMetadata(); + + int ticks = 0; + for (int f = 0; f < sourceAccessor.getFrame(); f++) { + ticks += sourceMetadata.getFrameTime(f); + } + + TextureAtlasSpriteAccessor targetAccessor = ((TextureAtlasSpriteAccessor) target); + AnimationMetadataSection targetMetadata = targetAccessor.getMetadata(); + + int cycleTime = 0; + int frameCount = targetMetadata.getFrameCount(); + for (int f = 0; f < frameCount; f++) { + cycleTime += targetMetadata.getFrameTime(f); + } + ticks %= cycleTime; + + int targetFrame = 0; + while (true) { + int time = targetMetadata.getFrameTime(targetFrame); + if (ticks >= time) { + targetFrame++; + ticks -= time; + } else { + break; + } + } + + targetAccessor.setFrame(targetFrame); + targetAccessor.setSubFrame(ticks + sourceAccessor.getSubFrame()); + } + + protected static class PBRTextureAtlasSpriteInfo extends TextureAtlasSprite.Info { + protected final PBRType pbrType; + + public PBRTextureAtlasSpriteInfo(ResourceLocation name, int width, int height, AnimationMetadataSection metadata, PBRType pbrType) { + super(name, width, height, metadata); + this.pbrType = pbrType; + } + } + + public static class PBRTextureAtlasSprite extends TextureAtlasSprite implements CustomMipmapGenerator.Provider { + protected PBRTextureAtlasSprite(TextureAtlas atlas, TextureAtlasSprite.Info info, int mipLevel, int atlasWidth, int atlasHeight, int x, int y, NativeImage nativeImage) { + super(atlas, info, mipLevel, atlasWidth, atlasHeight, x, y, nativeImage); + } + + @Override + public CustomMipmapGenerator getMipmapGenerator(Info info, int atlasWidth, int atlasHeight) { + if (info instanceof PBRTextureAtlasSpriteInfo) { + PBRType pbrType = ((PBRTextureAtlasSpriteInfo) info).pbrType; + TextureFormat format = TextureFormatLoader.getFormat(); + if (format != null) { + CustomMipmapGenerator generator = format.getMipmapGenerator(pbrType); + if (generator != null) { + return generator; + } + } + } + return LINEAR_MIPMAP_GENERATOR; + } + } +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoader.java new file mode 100644 index 000000000..a7c4977f9 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoader.java @@ -0,0 +1,23 @@ +package net.coderbot.iris.texture.pbr.loader; + +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.resources.IResourceManager; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.opengl.GL11; + +public interface PBRTextureLoader { + /** + * This method must not modify global GL state except the texture binding for {@link GL11.GL_TEXTURE_2D}. + * + * @param texture The base texture. + * @param resourceManager The resource manager. + * @param pbrTextureConsumer The consumer that accepts resulting PBR textures. + */ + void load(T texture, IResourceManager resourceManager, PBRTextureConsumer pbrTextureConsumer); + + interface PBRTextureConsumer { + void acceptNormalTexture(@NotNull AbstractTexture texture); + + void acceptSpecularTexture(@NotNull AbstractTexture texture); + } +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java new file mode 100644 index 000000000..b17f294ee --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java @@ -0,0 +1,29 @@ +package net.coderbot.iris.texture.pbr.loader; + +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.renderer.texture.SimpleTexture; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public class PBRTextureLoaderRegistry { + public static final PBRTextureLoaderRegistry INSTANCE = new PBRTextureLoaderRegistry(); + + static { + INSTANCE.register(SimpleTexture.class, new SimplePBRLoader()); + INSTANCE.register(TextureAtlas.class, new AtlasPBRLoader()); + } + + private final Map, PBRTextureLoader> loaderMap = new HashMap<>(); + + public void register(Class clazz, PBRTextureLoader loader) { + loaderMap.put(clazz, loader); + } + + @SuppressWarnings("unchecked") + @Nullable + public PBRTextureLoader getLoader(Class clazz) { + return (PBRTextureLoader) loaderMap.get(clazz); + } +} diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java new file mode 100644 index 000000000..a21ed0354 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java @@ -0,0 +1,42 @@ +package net.coderbot.iris.texture.pbr.loader; + +import com.gtnewhorizons.angelica.mixins.early.accessors.SimpleTextureAccessor; +import net.coderbot.iris.texture.pbr.PBRType; +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.renderer.texture.SimpleTexture; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.util.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; + +public class SimplePBRLoader implements PBRTextureLoader { + @Override + public void load(SimpleTexture texture, IResourceManager resourceManager, PBRTextureConsumer pbrTextureConsumer) { + ResourceLocation location = ((SimpleTextureAccessor) texture).getLocation(); + + AbstractTexture normalTexture = createPBRTexture(location, resourceManager, PBRType.NORMAL); + AbstractTexture specularTexture = createPBRTexture(location, resourceManager, PBRType.SPECULAR); + + if (normalTexture != null) { + pbrTextureConsumer.acceptNormalTexture(normalTexture); + } + if (specularTexture != null) { + pbrTextureConsumer.acceptSpecularTexture(specularTexture); + } + } + + @Nullable + protected AbstractTexture createPBRTexture(ResourceLocation imageLocation, IResourceManager resourceManager, PBRType pbrType) { + ResourceLocation pbrImageLocation = pbrType.appendToFileLocation(imageLocation); + + SimpleTexture pbrTexture = new SimpleTexture(pbrImageLocation); + try { + pbrTexture.load(resourceManager); + } catch (IOException e) { + return null; + } + + return pbrTexture; + } +} diff --git a/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java b/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java new file mode 100644 index 000000000..50df766eb --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java @@ -0,0 +1,120 @@ +package net.coderbot.iris.texture.util; + + +public class ImageManipulationUtil { + public static NativeImage scaleNearestNeighbor(NativeImage image, int newWidth, int newHeight) { + NativeImage scaled = new NativeImage(image.format(), newWidth, newHeight, false); + float xScale = (float) newWidth / image.getWidth(); + float yScale = (float) newHeight / image.getHeight(); + for (int y = 0; y < newHeight; ++y) { + for (int x = 0; x < newWidth; ++x) { + float unscaledX = (x + 0.5f) / xScale; + float unscaledY = (y + 0.5f) / yScale; + scaled.setPixelRGBA(x, y, image.getPixelRGBA((int) unscaledX, (int) unscaledY)); + } + } + return scaled; + } + + public static NativeImage scaleBilinear(NativeImage image, int newWidth, int newHeight) { + NativeImage scaled = new NativeImage(image.format(), newWidth, newHeight, false); + float xScale = (float) newWidth / image.getWidth(); + float yScale = (float) newHeight / image.getHeight(); + for (int y = 0; y < newHeight; ++y) { + for (int x = 0; x < newWidth; ++x) { + float unscaledX = (x + 0.5f) / xScale; + float unscaledY = (y + 0.5f) / yScale; + + int x1 = Math.round(unscaledX); + int y1 = Math.round(unscaledY); + int x0 = x1 - 1; + int y0 = y1 - 1; + + boolean x0valid = true; + boolean y0valid = true; + boolean x1valid = true; + boolean y1valid = true; + if (x0 < 0) { + x0valid = false; + } + if (y0 < 0) { + y0valid = false; + } + if (x1 >= image.getWidth()) { + x1valid = false; + } + if (y1 >= image.getHeight()) { + y1valid = false; + } + + int finalColor = 0; + if (x0valid & y0valid & x1valid & y1valid) { + float leftWeight = (x1 + 0.5f) - unscaledX; + float rightWeight = unscaledX - (x0 + 0.5f); + float topWeight = (y1 + 0.5f) - unscaledY; + float bottomWeight = unscaledY - (y0 + 0.5f); + + float weightTL = leftWeight * topWeight; + float weightTR = rightWeight * topWeight; + float weightBL = leftWeight * bottomWeight; + float weightBR = rightWeight * bottomWeight; + + int colorTL = image.getPixelRGBA(x0, y0); + int colorTR = image.getPixelRGBA(x1, y0); + int colorBL = image.getPixelRGBA(x0, y1); + int colorBR = image.getPixelRGBA(x1, y1); + + finalColor = blendColor(colorTL, colorTR, colorBL, colorBR, weightTL, weightTR, weightBL, weightBR); + } else if (x0valid & x1valid) { + float leftWeight = (x1 + 0.5f) - unscaledX; + float rightWeight = unscaledX - (x0 + 0.5f); + + int validY = y0valid ? y0 : y1; + int colorLeft = image.getPixelRGBA(x0, validY); + int colorRight = image.getPixelRGBA(x1, validY); + + finalColor = blendColor(colorLeft, colorRight, leftWeight, rightWeight); + } else if (y0valid & y1valid) { + float topWeight = (y1 + 0.5f) - unscaledY; + float bottomWeight = unscaledY - (y0 + 0.5f); + + int validX = x0valid ? x0 : x1; + int colorTop = image.getPixelRGBA(validX, y0); + int colorBottom = image.getPixelRGBA(validX, y1); + + finalColor = blendColor(colorTop, colorBottom, topWeight, bottomWeight); + } else { + finalColor = image.getPixelRGBA(x0valid ? x0 : x1, y0valid ? y0 : y1); + } + scaled.setPixelRGBA(x, y, finalColor); + } + } + return scaled; + } + + private static int blendColor(int c0, int c1, int c2, int c3, float w0, float w1, float w2, float w3) { + return NativeImage.combine( + blendChannel(NativeImage.getA(c0), NativeImage.getA(c1), NativeImage.getA(c2), NativeImage.getA(c3), w0, w1, w2, w3), + blendChannel(NativeImage.getB(c0), NativeImage.getB(c1), NativeImage.getB(c2), NativeImage.getB(c3), w0, w1, w2, w3), + blendChannel(NativeImage.getG(c0), NativeImage.getG(c1), NativeImage.getG(c2), NativeImage.getG(c3), w0, w1, w2, w3), + blendChannel(NativeImage.getR(c0), NativeImage.getR(c1), NativeImage.getR(c2), NativeImage.getR(c3), w0, w1, w2, w3) + ); + } + + private static int blendChannel(int v0, int v1, int v2, int v3, float w0, float w1, float w2, float w3) { + return Math.round(v0 * w0 + v1 * w1 + v2 * w2 + v3 * w3); + } + + private static int blendColor(int c0, int c1, float w0, float w1) { + return NativeImage.combine( + blendChannel(NativeImage.getA(c0), NativeImage.getA(c1), w0, w1), + blendChannel(NativeImage.getB(c0), NativeImage.getB(c1), w0, w1), + blendChannel(NativeImage.getG(c0), NativeImage.getG(c1), w0, w1), + blendChannel(NativeImage.getR(c0), NativeImage.getR(c1), w0, w1) + ); + } + + private static int blendChannel(int v0, int v1, float w0, float w1) { + return Math.round(v0 * w0 + v1 * w1); + } +} diff --git a/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java b/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java new file mode 100644 index 000000000..9082159d0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java @@ -0,0 +1,37 @@ +package net.coderbot.iris.texture.util; + +import net.minecraft.client.Minecraft; +import org.apache.commons.io.FilenameUtils; +import org.lwjgl.opengl.GL11; + +import java.io.File; + +public class TextureExporter { + public static void exportTextures(String directory, String filename, int textureId, int mipLevel, int width, int height) { + String extension = FilenameUtils.getExtension(filename); + String baseName = filename.substring(0, filename.length() - extension.length() - 1); + for (int level = 0; level <= mipLevel; ++level) { + exportTexture(directory, baseName + "_" + level + "." + extension, textureId, level, width >> level, height >> level); + } + } + + public static void exportTexture(String directory, String filename, int textureId, int level, int width, int height) { + NativeImage nativeImage = new NativeImage(width, height, false); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId); + nativeImage.downloadTexture(level, false); + + File dir = new File(Minecraft.getMinecraft().mcDataDir, directory); + dir.mkdirs(); + File file = new File(dir, filename); + + Util.ioPool().execute(() -> { + try { + nativeImage.writeToFile(file); + } catch (Exception var7) { + // + } finally { + nativeImage.close(); + } + }); + } +} diff --git a/src/main/java/net/coderbot/iris/texture/util/TextureManipulationUtil.java b/src/main/java/net/coderbot/iris/texture/util/TextureManipulationUtil.java new file mode 100644 index 000000000..acc3bacd9 --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/util/TextureManipulationUtil.java @@ -0,0 +1,51 @@ +package net.coderbot.iris.texture.util; + +import net.coderbot.iris.gl.IrisRenderSystem; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.OpenGlHelper; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL30; + +public class TextureManipulationUtil { + private static int colorFillFBO = -1; + + public static void fillWithColor(int textureId, int maxLevel, int rgba) { + if (colorFillFBO == -1) { + colorFillFBO = OpenGlHelper.func_153165_e/*glGenFramebuffers*/(); + } + + int previousFramebufferId = GL11.glGetInteger(GL30.GL_FRAMEBUFFER_BINDING); + float[] previousClearColor = new float[4]; + IrisRenderSystem.getFloatv(GL11.GL_COLOR_CLEAR_VALUE, previousClearColor); + int previousTextureId = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + int[] previousViewport = new int[4]; + IrisRenderSystem.getIntegerv(GL11.GL_VIEWPORT, previousViewport); + + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, colorFillFBO); + GL11.glClearColor( + (rgba >> 24 & 0xFF) / 255.0f, + (rgba >> 16 & 0xFF) / 255.0f, + (rgba >> 8 & 0xFF) / 255.0f, + (rgba & 0xFF) / 255.0f + ); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId); + for (int level = 0; level <= maxLevel; ++level) { + int width = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_WIDTH); + int height = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_HEIGHT); + GL11.glViewport(0, 0, width, height); + GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, textureId, level); + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); + if (Minecraft.isRunningOnMac) { + GL11.glGetError(); + } + + + GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, 0, level); + } + + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, previousFramebufferId); + GL11.glClearColor(previousClearColor[0], previousClearColor[1], previousClearColor[2], previousClearColor[3]); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, previousTextureId); + GL11.glViewport(previousViewport[0], previousViewport[1], previousViewport[2], previousViewport[3]); + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java new file mode 100644 index 000000000..8e42d40ec --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java @@ -0,0 +1,110 @@ +package net.coderbot.iris.uniforms; + +import net.coderbot.iris.JomlConversions; +import net.coderbot.iris.gl.uniform.UniformHolder; +import org.joml.Vector3d; +import net.minecraft.client.Minecraft; + +import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.ONCE; +import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; + +/** + * @see Uniforms: Camera + */ +public class CameraUniforms { + private static final Minecraft client = Minecraft.getMinecraft(); + + private CameraUniforms() { + } + + public static void addCameraUniforms(UniformHolder uniforms, FrameUpdateNotifier notifier) { + CameraPositionTracker tracker = new CameraPositionTracker(notifier); + + uniforms + .uniform1f(ONCE, "near", () -> 0.05) + .uniform1f(PER_FRAME, "far", CameraUniforms::getRenderDistanceInBlocks) + .uniform3d(PER_FRAME, "cameraPosition", tracker::getCurrentCameraPosition) + .uniform3d(PER_FRAME, "previousCameraPosition", tracker::getPreviousCameraPosition); + } + + private static int getRenderDistanceInBlocks() { + // TODO: Should we ask the game renderer for this? + return client.options.renderDistance * 16; + } + + public static Vector3d getUnshiftedCameraPosition() { + return JomlConversions.fromVec3(client.gameRenderer.getMainCamera().getPosition()); + } + + static class CameraPositionTracker { + /** + * Value range of cameraPosition. We want this to be small enough that precision is maintained when we convert + * from a double to a float, but big enough that shifts happen infrequently, since each shift corresponds with + * a noticeable change in shader animations and similar. 1000024 is the number used by Optifine for walking (however this is too much, so we choose 30000), + * with an extra 1024 check for if the user has teleported between camera positions. + */ + private static final double WALK_RANGE = 30000; + private static final double TP_RANGE = 1000; + + private Vector3d previousCameraPosition = new Vector3d(); + private Vector3d currentCameraPosition = new Vector3d(); + private final Vector3d shift = new Vector3d(); + + CameraPositionTracker(FrameUpdateNotifier notifier) { + notifier.addListener(this::update); + } + + private void update() { + previousCameraPosition = currentCameraPosition; + currentCameraPosition = getUnshiftedCameraPosition().add(shift); + + updateShift(); + } + + /** + * Updates our shift values to try to keep |x| < 30000 and |z| < 30000, to maintain precision with cameraPosition. + * Since our actual range is 60000x60000, this means that we won't excessively move back and forth when moving + * around a chunk border. + */ + private void updateShift() { + double dX = getShift(currentCameraPosition.x, previousCameraPosition.x); + double dZ = getShift(currentCameraPosition.z, previousCameraPosition.z); + + if (dX != 0.0 || dZ != 0.0) { + applyShift(dX, dZ); + } + } + + private static double getShift(double value, double prevValue) { + if (Math.abs(value) > WALK_RANGE || Math.abs(value - prevValue) > TP_RANGE) { + // Only shift by increments of WALK_RANGE - this is required for some packs (like SEUS PTGI) to work properly + return -(value - (value % WALK_RANGE)); + } else { + return 0.0; + } + } + + /** + * Shifts all current and future positions by the given amount. This is done in such a way that the difference + * between cameraPosition and previousCameraPosition remains the same, since they are completely arbitrary + * to the shader for the most part. + */ + private void applyShift(double dX, double dZ) { + shift.x += dX; + currentCameraPosition.x += dX; + previousCameraPosition.x += dX; + + shift.z += dZ; + currentCameraPosition.z += dZ; + previousCameraPosition.z += dZ; + } + + public Vector3d getCurrentCameraPosition() { + return currentCameraPosition; + } + + public Vector3d getPreviousCameraPosition() { + return previousCameraPosition; + } + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java new file mode 100644 index 000000000..d0684dd43 --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java @@ -0,0 +1,93 @@ +package net.coderbot.iris.uniforms; + +import net.coderbot.iris.gl.state.ValueUpdateNotifier; +import net.minecraft.client.Minecraft; +import org.joml.Matrix4f; +import org.joml.Vector3d; + +public class CapturedRenderingState { + public static final CapturedRenderingState INSTANCE = new CapturedRenderingState(); + + private static final Vector3d ZERO_VECTOR_3d = new Vector3d(); + + private Matrix4f gbufferModelView; + private Matrix4f gbufferProjection; + private Vector3d fogColor; + private float tickDelta; + private int currentRenderedBlockEntity; + private Runnable blockEntityIdListener = null; + + private int currentRenderedEntity = -1; + private Runnable entityIdListener = null; + + private CapturedRenderingState() { + } + + public Matrix4f getGbufferModelView() { + return gbufferModelView; + } + + public void setGbufferModelView(Matrix4f gbufferModelView) { + this.gbufferModelView = gbufferModelView.copy(); + } + + public Matrix4f getGbufferProjection() { + return gbufferProjection; + } + + public void setGbufferProjection(Matrix4f gbufferProjection) { + this.gbufferProjection = gbufferProjection.copy(); + } + + public Vector3d getFogColor() { + if (Minecraft.getMinecraft().theWorld == null || fogColor == null) { + return ZERO_VECTOR_3d; + } + + return fogColor; + } + + public void setFogColor(float red, float green, float blue) { + fogColor = new Vector3d(red, green, blue); + } + + public void setTickDelta(float tickDelta) { + this.tickDelta = tickDelta; + } + + public float getTickDelta() { + return tickDelta; + } + + public void setCurrentBlockEntity(int entity) { + this.currentRenderedBlockEntity = entity; + + if (this.blockEntityIdListener != null) { + this.blockEntityIdListener.run(); + } + } + + public int getCurrentRenderedBlockEntity() { + return currentRenderedBlockEntity; + } + + public void setCurrentEntity(int entity) { + this.currentRenderedEntity = entity; + + if (this.entityIdListener != null) { + this.entityIdListener.run(); + } + } + + public ValueUpdateNotifier getEntityIdNotifier() { + return listener -> this.entityIdListener = listener; + } + + public ValueUpdateNotifier getBlockEntityIdNotifier() { + return listener -> this.blockEntityIdListener = listener; + } + + public int getCurrentRenderedEntity() { + return currentRenderedEntity; + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java new file mode 100644 index 000000000..4ff69b3da --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java @@ -0,0 +1,135 @@ +package net.coderbot.iris.uniforms; + +import net.coderbot.iris.JomlConversions; +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; +import org.joml.Matrix4f; +import org.joml.Vector4f; + +import java.util.Objects; + +import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; + +/** + * @see Uniforms: Celestial bodies + */ +public final class CelestialUniforms { + final static float DEGREES_TO_RADIANS = (float)Math.PI / 180.0F; + + private final float sunPathRotation; + + public CelestialUniforms(float sunPathRotation) { + this.sunPathRotation = sunPathRotation; + } + + public void addCelestialUniforms(UniformHolder uniforms) { + uniforms + .uniform1f(PER_FRAME, "sunAngle", CelestialUniforms::getSunAngle) + .uniformTruncated3f(PER_FRAME, "sunPosition", this::getSunPosition) + .uniformTruncated3f(PER_FRAME, "moonPosition", this::getMoonPosition) + .uniform1f(PER_FRAME, "shadowAngle", CelestialUniforms::getShadowAngle) + .uniformTruncated3f(PER_FRAME, "shadowLightPosition", this::getShadowLightPosition) + .uniformTruncated3f(PER_FRAME, "upPosition", CelestialUniforms::getUpPosition); + } + + public static float getSunAngle() { + float skyAngle = getSkyAngle(); + + if (skyAngle < 0.75F) { + return skyAngle + 0.25F; + } else { + return skyAngle - 0.75F; + } + } + + private static float getShadowAngle() { + float shadowAngle = getSunAngle(); + + if (!isDay()) { + shadowAngle -= 0.5F; + } + + return shadowAngle; + } + + private Vector4f getSunPosition() { + return getCelestialPosition(100.0F); + } + + private Vector4f getMoonPosition() { + return getCelestialPosition(-100.0F); + } + + public Vector4f getShadowLightPosition() { + return isDay() ? getSunPosition() : getMoonPosition(); + } + + public Vector4f getShadowLightPositionInWorldSpace() { + return isDay() ? getCelestialPositionInWorldSpace(100.0F) : getCelestialPositionInWorldSpace(-100.0F); + } + + private Vector4f getCelestialPositionInWorldSpace(float y) { + Vector4f position = new Vector4f(0.0F, y, 0.0F, 0.0F); + + // TODO: Deduplicate / remove this function. + Matrix4f celestial = new Matrix4f(); + celestial.identity(); + + // This is the same transformation applied by renderSky, however, it's been moved to here. + // This is because we need the result of it before it's actually performed in vanilla. + celestial.rotateY(-90.F * DEGREES_TO_RADIANS); + celestial.rotateZ(sunPathRotation * DEGREES_TO_RADIANS); + celestial.rotateX(getSkyAngle() * 360.0F); + + celestial.transform(position); + + return position; + } + + private Vector4f getCelestialPosition(float y) { + Vector4f position = new Vector4f(0.0F, y, 0.0F, 0.0F); + + Matrix4f celestial = new Matrix4f(CapturedRenderingState.INSTANCE.getGbufferModelView()); + // This is the same transformation applied by renderSky, however, it's been moved to here. + // This is because we need the result of it before it's actually performed in vanilla. + celestial.rotateY(-90.F * DEGREES_TO_RADIANS); + celestial.rotateZ(sunPathRotation * DEGREES_TO_RADIANS); + celestial.rotateX(getSkyAngle() * 360.0F); + + position = celestial.transform(position); + + return position; + } + + private static Vector4f getUpPosition() { + Vector4f upVector = new Vector4f(0.0F, 100.0F, 0.0F, 0.0F); + + // Get the current GBuffer model view matrix, since that is the basis of the celestial model view matrix + Matrix4f preCelestial = new Matrix4f(CapturedRenderingState.INSTANCE.getGbufferModelView()); + + // Apply the fixed -90.0F degrees rotation to mirror the same transformation in renderSky. + // But, notably, skip the rotation by the skyAngle. + preCelestial.rotateY(-90.F * DEGREES_TO_RADIANS); + + // Use this matrix to transform the vector. + upVector = preCelestial.transform(upVector); + + return upVector; + } + + public static boolean isDay() { + // Determine whether it is day or night based on the sky angle. + // + // World#isDay appears to do some nontrivial calculations that appear to not entirely work for us here. + return getSunAngle() <= 0.5; + } + + private static WorldClient getWorld() { + return Objects.requireNonNull(Minecraft.getMinecraft().theWorld); + } + + private static float getSkyAngle() { + return getWorld().getCelestialAngle(CapturedRenderingState.INSTANCE.getTickDelta()); + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java new file mode 100644 index 000000000..f5e7718f6 --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -0,0 +1,262 @@ +package net.coderbot.iris.uniforms; + +import com.gtnewhorizons.angelica.mixins.early.accessors.EntityRendererAccessor; +import net.coderbot.iris.gl.state.StateUpdateNotifiers; +import net.coderbot.iris.gl.uniform.DynamicUniformHolder; +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.coderbot.iris.layer.GbufferPrograms; +import net.coderbot.iris.shaderpack.IdMap; +import net.coderbot.iris.shaderpack.PackDirectives; +import net.coderbot.iris.texture.TextureInfoCache; +import net.coderbot.iris.texture.TextureInfoCache.TextureInfo; +import net.coderbot.iris.texture.TextureTracker; +import net.coderbot.iris.uniforms.transforms.SmoothedFloat; +import net.coderbot.iris.uniforms.transforms.SmoothedVec2f; +import net.minecraft.block.material.Material; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.AbstractTexture; +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.Vec3; +import org.joml.Math; +import org.joml.Vector2f; +import org.joml.Vector2i; +import org.joml.Vector3d; +import org.joml.Vector4f; +import org.joml.Vector4i; + +import java.util.Objects; + +import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.ONCE; +import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; +import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_TICK; + +public final class CommonUniforms { + private static final Minecraft client = Minecraft.getMinecraft(); + private static final Vector2i ZERO_VECTOR_2i = new Vector2i(); + private static final Vector4i ZERO_VECTOR_4i = new Vector4i(0, 0, 0, 0); + private static final Vector3d ZERO_VECTOR_3d = new Vector3d(); + + private CommonUniforms() { + // no construction allowed + } + + // Needs to use a LocationalUniformHolder as we need it for the common uniforms + public static void addCommonUniforms(DynamicUniformHolder uniforms, IdMap idMap, PackDirectives directives, FrameUpdateNotifier updateNotifier) { + CameraUniforms.addCameraUniforms(uniforms, updateNotifier); + ViewportUniforms.addViewportUniforms(uniforms); + WorldTimeUniforms.addWorldTimeUniforms(uniforms); + SystemTimeUniforms.addSystemTimeUniforms(uniforms); + new CelestialUniforms(directives.getSunPathRotation()).addCelestialUniforms(uniforms); + IdMapUniforms.addIdMapUniforms(updateNotifier, uniforms, idMap, directives.isOldHandLight()); + IrisExclusiveUniforms.addIrisExclusiveUniforms(uniforms); + MatrixUniforms.addMatrixUniforms(uniforms, directives); + HardcodedCustomUniforms.addHardcodedCustomUniforms(uniforms, updateNotifier); + FogUniforms.addFogUniforms(uniforms); + + // TODO: OptiFine doesn't think that atlasSize is a "dynamic" uniform, + // but we do. How will custom uniforms depending on atlasSize work? + uniforms.uniform2i("atlasSize", () -> { + int glId = GlStateManagerAccessor.getTEXTURES()[0].binding; + + AbstractTexture texture = TextureTracker.INSTANCE.getTexture(glId); + if (texture instanceof TextureAtlas) { + TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId); + return new Vector2i(info.getWidth(), info.getHeight()); + } + + return ZERO_VECTOR_2i; + }, StateUpdateNotifiers.bindTextureNotifier); + + uniforms.uniform2i("gtextureSize", () -> { + int glId = GlStateManagerAccessor.getTEXTURES()[0].binding; + + TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId); + return new Vector2i(info.getWidth(), info.getHeight()); + + }, StateUpdateNotifiers.bindTextureNotifier); + + uniforms.uniform4i("blendFunc", () -> { + GlStateManager.BlendState blend = GlStateManagerAccessor.getBLEND(); + + if (((BooleanStateAccessor) blend.mode).isEnabled()) { + return new Vector4i(blend.srcRgb, blend.dstRgb, blend.srcAlpha, blend.dstAlpha); + } else { + return ZERO_VECTOR_4i; + } + }, StateUpdateNotifiers.blendFuncNotifier); + + uniforms.uniform1i("renderStage", () -> GbufferPrograms.getCurrentPhase().ordinal(), StateUpdateNotifiers.phaseChangeNotifier); + + CommonUniforms.generalCommonUniforms(uniforms, updateNotifier, directives); + } + + public static void generalCommonUniforms(UniformHolder uniforms, FrameUpdateNotifier updateNotifier, PackDirectives directives) { + ExternallyManagedUniforms.addExternallyManagedUniforms116(uniforms); + + SmoothedVec2f eyeBrightnessSmooth = new SmoothedVec2f(directives.getEyeBrightnessHalfLife(), directives.getEyeBrightnessHalfLife(), CommonUniforms::getEyeBrightness, updateNotifier); + + uniforms + .uniform1b(PER_FRAME, "hideGUI", () -> client.gameSettings.hideGUI) + .uniform1f(PER_FRAME, "eyeAltitude", () -> Objects.requireNonNull(client.getCameraEntity()).getEyeY()) + .uniform1i(PER_FRAME, "isEyeInWater", CommonUniforms::isEyeInWater) + .uniform1f(PER_FRAME, "blindness", CommonUniforms::getBlindness) + .uniform1f(PER_FRAME, "nightVision", CommonUniforms::getNightVision) + .uniform1b(PER_FRAME, "is_sneaking", CommonUniforms::isSneaking) + .uniform1b(PER_FRAME, "is_sprinting", CommonUniforms::isSprinting) + .uniform1b(PER_FRAME, "is_hurt", CommonUniforms::isHurt) + .uniform1b(PER_FRAME, "is_invisible", CommonUniforms::isInvisible) + .uniform1b(PER_FRAME, "is_burning", CommonUniforms::isBurning) + .uniform1b(PER_FRAME, "is_on_ground", CommonUniforms::isOnGround) + // TODO: Do we need to clamp this to avoid fullbright breaking shaders? Or should shaders be able to detect + // that the player is trying to turn on fullbright? + .uniform1f(PER_FRAME, "screenBrightness", () -> client.gameSettings.gammaSetting) + // just a dummy value for shaders where entityColor isn't supplied through a vertex attribute (and thus is + // not available) - suppresses warnings. See AttributeShaderTransformer for the actual entityColor code. + .uniform4f(ONCE, "entityColor", Vector4f::new) + .uniform1f(PER_TICK, "playerMood", CommonUniforms::getPlayerMood) + .uniform2i(PER_FRAME, "eyeBrightness", CommonUniforms::getEyeBrightness) + .uniform2i(PER_FRAME, "eyeBrightnessSmooth", () -> { + Vector2f smoothed = eyeBrightnessSmooth.get(); + return new Vector2i((int) smoothed.x(),(int) smoothed.y()); + }) + .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", CapturedRenderingState.INSTANCE::getFogColor); + } + + private static boolean isOnGround() { + return client.thePlayer != null && client.thePlayer.onGround; + } + + private static boolean isHurt() { + // Do not use isHurt, that's not what we want! + return (client.thePlayer != null && client.thePlayer.hurtTime > 0); + } + + private static boolean isInvisible() { + return (client.thePlayer != null && client.thePlayer.isInvisible()); + } + + private static boolean isBurning() { + // todo: thePlayer.fire > 0 && !thePlayer.fireResistance + return false; + // if (client.thePlayer != null) { + // return client.thePlayer.isOnFire(); + // } else { + // return false; + // } + } + + private static boolean isSneaking() { + return (client.thePlayer != null && client.thePlayer.isSneaking()); + } + + private static boolean isSprinting() { + return (client.thePlayer != null && client.thePlayer.isSprinting()); + } + + private static Vector3d getSkyColor() { + if (client.theWorld == null || client.renderViewEntity == null) { + return ZERO_VECTOR_3d; + } + final Vec3 skyColor = client.theWorld.getSkyColor(client.renderViewEntity, CapturedRenderingState.INSTANCE.getTickDelta()); + return new Vector3d(skyColor.xCoord, skyColor.yCoord, skyColor.zCoord); + } + + static float getBlindness() { + EntityLivingBase cameraEntity = client.renderViewEntity; + + if (cameraEntity instanceof EntityLiving livingEntity && livingEntity.isPotionActive(Potion.blindness)) { + final PotionEffect blindness = livingEntity.getActivePotionEffect(Potion.blindness); + + if (blindness != null) { + // Guessing that this is what OF uses, based on how vanilla calculates the fog value in BackgroundRenderer + // TODO: Add this to ShaderDoc + return Math.clamp(0.0F, 1.0F, blindness.getDuration() / 20.0F); + } + } + + return 0.0F; + } + + private static float getPlayerMood() { + // TODO: What should this be? + return 0.0F; +// if (!(client.cameraEntity instanceof LocalPlayer)) { +// return 0.0F; +// } +// +// // This should always be 0 to 1 anyways but just making sure +// return Math.clamp(0.0F, 1.0F, ((LocalPlayer) client.cameraEntity).getCurrentMood()); + } + + static float getRainStrength() { + if (client.theWorld == null) { + return 0f; + } + + // Note: Ensure this is in the range of 0 to 1 - some custom servers send out of range values. + return Math.clamp(0.0F, 1.0F, client.theWorld.getRainStrength(CapturedRenderingState.INSTANCE.getTickDelta())); + + } + + private static Vector2i getEyeBrightness() { + if (client.renderViewEntity == null || client.theWorld == null) { + return ZERO_VECTOR_2i; + } + + final int eyeBrightness = client.renderViewEntity.getBrightnessForRender(CapturedRenderingState.INSTANCE.getTickDelta()); + return new Vector2i((eyeBrightness & 0xffff), (eyeBrightness >> 16)); + +// Vec3 feet = client.cameraEntity.position(); +// Vec3 eyes = new Vec3(feet.x, client.cameraEntity.getEyeY(), feet.z); +// BlockPos eyeBlockPos = new BlockPos(eyes); +// +// int blockLight = client.level.getBrightness(LightLayer.BLOCK, eyeBlockPos); +// int skyLight = client.level.getBrightness(LightLayer.SKY, eyeBlockPos); +// +// return new Vector2i(blockLight * 16, skyLight * 16); + } + + private static float getNightVision() { + Entity cameraEntity = client.renderViewEntity; + + if (cameraEntity instanceof EntityPlayer entityPlayer) { + if (!entityPlayer.isPotionActive(Potion.nightVision)) { + return 0.0F; + } + float nightVisionStrength = ((EntityRendererAccessor)client.entityRenderer).invokeGetNightVisionBrightness(entityPlayer, CapturedRenderingState.INSTANCE.getTickDelta()); + + try { + if (nightVisionStrength > 0) { + // Just protecting against potential weird mod behavior + return Math.clamp(0.0F, 1.0F, nightVisionStrength); + } + } catch (NullPointerException e) { + return 0.0F; + } + } + + return 0.0F; + } + + static int isEyeInWater() { + if (client.gameSettings.thirdPersonView == 0 && !client.renderViewEntity.isPlayerSleeping()) { + if (client.thePlayer.isInsideOfMaterial(Material.water)) + return 1; + else if (client.thePlayer.isInsideOfMaterial(Material.lava)) + return 2; + } + return 0; + } + + static { + GbufferPrograms.init(); + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/ExternallyManagedUniforms.java b/src/main/java/net/coderbot/iris/uniforms/ExternallyManagedUniforms.java new file mode 100644 index 000000000..c4976a447 --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/ExternallyManagedUniforms.java @@ -0,0 +1,65 @@ +package net.coderbot.iris.uniforms; + +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.coderbot.iris.gl.uniform.UniformType; + +public class ExternallyManagedUniforms { + private ExternallyManagedUniforms() { + // no construction allowed + } + + public static void addExternallyManagedUniforms(UniformHolder uniformHolder) { + addMat4(uniformHolder, "iris_ModelViewMatrix"); + addMat4(uniformHolder, "u_ModelViewProjectionMatrix"); + addMat4(uniformHolder, "iris_NormalMatrix"); + // Exclusive to pre-1.19 + addFloat(uniformHolder, "darknessFactor"); + addFloat(uniformHolder, "darknessLightFactor"); + } + + public static void addExternallyManagedUniforms116(UniformHolder uniformHolder) { + addExternallyManagedUniforms(uniformHolder); + + uniformHolder.externallyManagedUniform("u_ModelScale", UniformType.VEC3); + uniformHolder.externallyManagedUniform("u_TextureScale", UniformType.VEC2); + } + + public static void addExternallyManagedUniforms117(UniformHolder uniformHolder) { + addExternallyManagedUniforms(uniformHolder); + + // Sodium + addFloat(uniformHolder, "iris_FogStart"); + addFloat(uniformHolder, "iris_FogEnd"); + addVec4(uniformHolder, "iris_FogColor"); + addMat4(uniformHolder, "iris_ProjectionMatrix"); + addFloat(uniformHolder, "u_TextureScale"); + addFloat(uniformHolder, "u_ModelScale"); + addFloat(uniformHolder, "iris_ModelOffset"); + uniformHolder.externallyManagedUniform("iris_CameraTranslation", UniformType.VEC3); + + // Vanilla + uniformHolder.externallyManagedUniform("iris_TextureMat", UniformType.MAT4); + uniformHolder.externallyManagedUniform("iris_ModelViewMat", UniformType.MAT4); + uniformHolder.externallyManagedUniform("iris_ProjMat", UniformType.MAT4); + uniformHolder.externallyManagedUniform("iris_ChunkOffset", UniformType.VEC3); + uniformHolder.externallyManagedUniform("iris_ColorModulator", UniformType.VEC4); + uniformHolder.externallyManagedUniform("iris_FogStart", UniformType.FLOAT); + uniformHolder.externallyManagedUniform("iris_FogEnd", UniformType.FLOAT); + uniformHolder.externallyManagedUniform("iris_FogDensity", UniformType.FLOAT); + uniformHolder.externallyManagedUniform("iris_LineWidth", UniformType.FLOAT); + uniformHolder.externallyManagedUniform("iris_ScreenSize", UniformType.VEC2); + uniformHolder.externallyManagedUniform("iris_FogColor", UniformType.VEC4); + } + + private static void addMat4(UniformHolder uniformHolder, String name) { + uniformHolder.externallyManagedUniform(name, UniformType.MAT4); + } + + private static void addVec4(UniformHolder uniformHolder, String name) { + uniformHolder.externallyManagedUniform(name, UniformType.VEC4); + } + + private static void addFloat(UniformHolder uniformHolder, String name) { + uniformHolder.externallyManagedUniform(name, UniformType.FLOAT); + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/FogUniforms.java b/src/main/java/net/coderbot/iris/uniforms/FogUniforms.java new file mode 100644 index 000000000..b6423492e --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/FogUniforms.java @@ -0,0 +1,40 @@ +package net.coderbot.iris.uniforms; + +import net.coderbot.iris.gl.state.StateUpdateNotifiers; +import net.coderbot.iris.gl.uniform.DynamicUniformHolder; + +public class FogUniforms { + private FogUniforms() { + // no construction + } + + public static void addFogUniforms(DynamicUniformHolder uniforms) { + uniforms.uniform1i("fogMode", () -> { + GlStateManager.FogState fog = GlStateManagerAccessor.getFOG(); + + if (!((BooleanStateAccessor) fog.enable).isEnabled()) { + return 0; + } + + return GlStateManagerAccessor.getFOG().mode; + }, listener -> { + StateUpdateNotifiers.fogToggleNotifier.setListener(listener); + StateUpdateNotifiers.fogModeNotifier.setListener(listener); + }); + + uniforms.uniform1f("fogDensity", () -> GlStateManagerAccessor.getFOG().density, listener -> { + StateUpdateNotifiers.fogToggleNotifier.setListener(listener); + StateUpdateNotifiers.fogDensityNotifier.setListener(listener); + }); + + uniforms.uniform1f("fogStart", () -> GlStateManagerAccessor.getFOG().start, listener -> { + StateUpdateNotifiers.fogToggleNotifier.setListener(listener); + StateUpdateNotifiers.fogStartNotifier.setListener(listener); + }); + + uniforms.uniform1f("fogEnd", () -> GlStateManagerAccessor.getFOG().end, listener -> { + StateUpdateNotifiers.fogToggleNotifier.setListener(listener); + StateUpdateNotifiers.fogEndNotifier.setListener(listener); + }); + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/FrameUpdateNotifier.java b/src/main/java/net/coderbot/iris/uniforms/FrameUpdateNotifier.java new file mode 100644 index 000000000..b7745ffce --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/FrameUpdateNotifier.java @@ -0,0 +1,20 @@ +package net.coderbot.iris.uniforms; + +import java.util.ArrayList; +import java.util.List; + +public class FrameUpdateNotifier { + private final List listeners; + + public FrameUpdateNotifier() { + listeners = new ArrayList<>(); + } + + public void addListener(Runnable onNewFrame) { + listeners.add(onNewFrame); + } + + public void onNewFrame() { + listeners.forEach(Runnable::run); + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java b/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java new file mode 100644 index 000000000..6b77e9783 --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java @@ -0,0 +1,224 @@ +package net.coderbot.iris.uniforms; + +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; +import net.coderbot.iris.uniforms.transforms.SmoothedFloat; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.Vec3; +import org.joml.Math; + +// These expressions are copied directly from BSL and Complementary. + +// TODO: Remove once custom uniforms are actually supported, this is just a temporary thing to get BSL & Complementary +// mostly working under Iris. +public class HardcodedCustomUniforms { + private static final Minecraft client = Minecraft.getMinecraft(); + private static Biome storedBiome; + + public static void addHardcodedCustomUniforms(UniformHolder holder, FrameUpdateNotifier updateNotifier) { + updateNotifier.addListener(() -> { +// if (Minecraft.getMinecraft().level != null) { +// storedBiome = Minecraft.getMinecraft().level.getBiome(Minecraft.getMinecraft().getCameraEntity().blockPosition()); +// } else { +// storedBiome = null; +// } + }); + + CameraUniforms.CameraPositionTracker tracker = new CameraUniforms.CameraPositionTracker(updateNotifier); + + SmoothedFloat eyeInCave = new SmoothedFloat(6, 12, HardcodedCustomUniforms::getEyeInCave, updateNotifier); + SmoothedFloat rainStrengthS = rainStrengthS(updateNotifier, 15, 15); + SmoothedFloat rainStrengthShining = rainStrengthS(updateNotifier, 10, 11); + SmoothedFloat rainStrengthS2 = rainStrengthS(updateNotifier, 70, 1); + + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "timeAngle", HardcodedCustomUniforms::getTimeAngle); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "timeBrightness", HardcodedCustomUniforms::getTimeBrightness); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "moonBrightness", HardcodedCustomUniforms::getMoonBrightness); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "shadowFade", HardcodedCustomUniforms::getShadowFade); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "rainStrengthS", rainStrengthS); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "rainStrengthShiningStars", rainStrengthShining); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "rainStrengthS2", rainStrengthS2); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "blindFactor", HardcodedCustomUniforms::getBlindFactor); + // The following uniforms are Complementary specific, used for the biome check and starter/TAA features. + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "isDry", new SmoothedFloat(20, 10, () -> getRawPrecipitation() == 0 ? 1 : 0, updateNotifier)); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "isRainy", new SmoothedFloat(20, 10, () -> getRawPrecipitation() == 1 ? 1 : 0, updateNotifier)); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "isSnowy", new SmoothedFloat(20, 10, () -> getRawPrecipitation() == 2 ? 1 : 0, updateNotifier)); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "isEyeInCave", () -> CommonUniforms.isEyeInWater() == 0 ? eyeInCave.getAsFloat() : 0); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "velocity", () -> getVelocity(tracker)); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "starter", getStarter(tracker, updateNotifier)); + // The following uniforms are Project Reimagined specific. + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "frameTimeSmooth", new SmoothedFloat(5, 5, SystemTimeUniforms.TIMER::getLastFrameTime, updateNotifier)); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "eyeBrightnessM", new SmoothedFloat(5, 5, HardcodedCustomUniforms::getEyeBrightnessM, updateNotifier)); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "rainFactor", rainStrengthS); + + // The following uniforms are Sildur's specific. + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "inSwamp", new SmoothedFloat(5, 5, () -> { + return 0; +// if (storedBiome == null) { +// return 0; +// } else { +// return storedBiome.getBiomeCategory() == Biome.BiomeCategory.SWAMP ? 1 : 0; +// } + }, updateNotifier)); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "BiomeTemp", () -> { + return 0; +// if (storedBiome == null) { +// return 0; +// } else { +// return storedBiome.getTemperature(Minecraft.getMinecraft().getCameraEntity().blockPosition()); +// } + }); + + // The following uniforms are specific to Super Duper Vanilla Shaders. + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "day", HardcodedCustomUniforms::getDay); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "night", HardcodedCustomUniforms::getNight); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "dawnDusk", HardcodedCustomUniforms::getDawnDusk); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "shdFade", HardcodedCustomUniforms::getShdFade); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "isPrecipitationRain", new SmoothedFloat(6, 6, () -> (getRawPrecipitation() == 1 && tracker.getCurrentCameraPosition().y < 96.0f) ? 1 : 0, updateNotifier)); + + // The following uniforms are specific to AstralEX, and require an active player. + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "touchmybody", new SmoothedFloat(0f, 0.1f, HardcodedCustomUniforms::getHurtFactor, updateNotifier)); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "sneakSmooth", new SmoothedFloat(2.0f, 0.9f, HardcodedCustomUniforms::getSneakFactor, updateNotifier)); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "burningSmooth", new SmoothedFloat(1.0f, 2.0f, HardcodedCustomUniforms::getBurnFactor, updateNotifier)); + SmoothedFloat smoothSpeed = new SmoothedFloat(1.0f, 1.5f, () -> getVelocity(tracker) / SystemTimeUniforms.TIMER.getLastFrameTime(), updateNotifier); + holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "effectStrength", () -> getHyperSpeedStrength(smoothSpeed)); + } + + private static float getHyperSpeedStrength(SmoothedFloat smoothSpeed) { + return (float) (1.0f - Math.exp(-smoothSpeed.getAsFloat() * 0.003906f)); + } + + private static float getBurnFactor() { + // todo: thePlayer.fire > 0 && !thePlayer.fireResistance + return 0f; +// return Minecraft.getMinecraft().thePlayer.isOnFire() ? 1.0f : 0f; + } + + private static float getSneakFactor() { + return Minecraft.getMinecraft().thePlayer.isSneaking() ? 1.0f : 0f; + } + + private static float getHurtFactor() { + EntityPlayer player = Minecraft.getMinecraft().thePlayer; + return player.hurtTime > 0 || player.deathTime > 0 ? 0.4f : 0f; + } + + private static float getEyeInCave() { + if (client.getCameraEntity().getEyeY() < 5.0) { + return 1.0f - getEyeSkyBrightness() / 240F; + } + return 0.0f; + } + + private static float getEyeBrightnessM() { + return getEyeSkyBrightness() / 240F; + } + + private static float getEyeSkyBrightness() { + final int eyeBrightness = client.renderViewEntity.getBrightnessForRender(CapturedRenderingState.INSTANCE.getTickDelta()); + return (eyeBrightness & 0xffff); +// if (client.cameraEntity == null || client.level == null) { +// return 0; +// } + +// Vec3 feet = client.cameraEntity.position(); +// Vec3 eyes = new Vec3(feet.x, client.cameraEntity.getEyeY(), feet.z); +// BlockPos eyeBlockPos = new BlockPos(eyes); +// +// int skyLight = client.level.getBrightness(LightLayer.SKY, eyeBlockPos); +// +// return skyLight * 16; + } + + private static float getVelocity(CameraUniforms.CameraPositionTracker tracker) { + float difX = (float) (tracker.getCurrentCameraPosition().x - tracker.getPreviousCameraPosition().x); + float difY = (float) (tracker.getCurrentCameraPosition().y - tracker.getPreviousCameraPosition().y); + float difZ = (float) (tracker.getCurrentCameraPosition().z - tracker.getPreviousCameraPosition().z); + return Math.sqrt(difX*difX + difY*difY + difZ*difZ); + } + + private static SmoothedFloat getStarter(CameraUniforms.CameraPositionTracker tracker, FrameUpdateNotifier notifier) { + return new SmoothedFloat(20, 20, new SmoothedFloat(0, 31536000, () -> getMoving(tracker), notifier), notifier); + } + + private static float getMoving(CameraUniforms.CameraPositionTracker tracker) { + float difX = (float) (tracker.getCurrentCameraPosition().x - tracker.getPreviousCameraPosition().x); + float difY = (float) (tracker.getCurrentCameraPosition().y - tracker.getPreviousCameraPosition().y); + float difZ = (float) (tracker.getCurrentCameraPosition().z - tracker.getPreviousCameraPosition().z); + float difSum = Math.abs(difX) + Math.abs(difY) + Math.abs(difZ); + return (difSum > 0.0F && difSum < 1.0F) ? 1 : 0; + } + + private static float getTimeAngle() { + return getWorldDayTime() / 24000F; + } + + private static int getWorldDayTime() { + long timeOfDay = Minecraft.getMinecraft().theWorld.getWorldTime(); +// Level level = Minecraft.getMinecraft().theWorld; +// long timeOfDay = level.getDayTime(); +// long dayTime = ((DimensionTypeAccessor) level.dimensionType()).getFixedTime().orElse(timeOfDay % 24000L); + + return (int) timeOfDay; + } + + private static float getTimeBrightness() { + return (float) java.lang.Math.max(java.lang.Math.sin(getTimeAngle() * java.lang.Math.PI * 2.0),0.0); + } + + private static float getMoonBrightness() { + return (float) java.lang.Math.max(java.lang.Math.sin(getTimeAngle() * java.lang.Math.PI * (-2.0)),0.0); + } + + private static float getShadowFade() { + return (float) Math.clamp(0.0, 1.0, 1.0 - (java.lang.Math.abs(java.lang.Math.abs(CelestialUniforms.getSunAngle() - 0.5) - 0.25) - 0.23) * 100.0); + } + + private static SmoothedFloat rainStrengthS(FrameUpdateNotifier updateNotifier, float halfLifeUp, float halfLifeDown) { + return new SmoothedFloat(halfLifeUp, halfLifeDown, CommonUniforms::getRainStrength, updateNotifier); + } + + private static float getRawPrecipitation() { + if (storedBiome == null) { + return 0; + } + return 0; +// Biome.Precipitation precipitation = storedBiome.getPrecipitation(); +// return switch (precipitation) { +// case RAIN -> 1; +// case SNOW -> 2; +// default -> 0; +// }; + } + + private static float getBlindFactor() { + float blindFactorSqrt = (float) Math.clamp(0.0, 1.0, CommonUniforms.getBlindness() * 2.0 - 1.0); + return blindFactorSqrt * blindFactorSqrt; + } + + private static float frac(float value) { + return java.lang.Math.abs(value % 1); + } + + private static float getAdjTime() { + return Math.abs(((((WorldTimeUniforms.getWorldDayTime()) / 1000.0f) + 6.0f) % 24.0f) - 12.0f); + } + + private static float getDay() { + return Math.clamp(0.0f, 1.0f, 5.4f - getAdjTime()); + } + + private static float getNight() { + return Math.clamp(0.0f, 1.0f, getAdjTime() - 6.0f); + } + + private static float getDawnDusk() { + return (1.0f - getDay()) - getNight(); + } + + + private static float getShdFade() { + return (float) Math.clamp(0.0, 1.0, 1.0 - (Math.abs(Math.abs(CelestialUniforms.getSunAngle() - 0.5) - 0.25) - 0.225) * 40.0); + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java b/src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java new file mode 100644 index 000000000..2ec5a295b --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java @@ -0,0 +1,141 @@ +package net.coderbot.iris.uniforms; + +import it.unimi.dsi.fastutil.objects.Object2IntFunction; +import net.coderbot.iris.gl.uniform.DynamicUniformHolder; +import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; +import net.coderbot.iris.shaderpack.IdMap; +import net.coderbot.iris.shaderpack.materialmap.NamespacedId; +import net.irisshaders.iris.api.v0.item.IrisItemLightProvider; +import net.minecraft.client.Minecraft; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector3f; + +import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; + +public final class IdMapUniforms { + + private IdMapUniforms() { + } + + public static void addIdMapUniforms(FrameUpdateNotifier notifier, DynamicUniformHolder uniforms, IdMap idMap, boolean isOldHandLight) { + HeldItemSupplier mainHandSupplier = new HeldItemSupplier(InteractionHand.MAIN_HAND, idMap.getItemIdMap(), isOldHandLight); + HeldItemSupplier offHandSupplier = new HeldItemSupplier(InteractionHand.OFF_HAND, idMap.getItemIdMap(), false); + notifier.addListener(mainHandSupplier::update); + notifier.addListener(offHandSupplier::update); + + uniforms + .uniform1i(UniformUpdateFrequency.PER_FRAME, "heldItemId", mainHandSupplier::getIntID) + .uniform1i(UniformUpdateFrequency.PER_FRAME, "heldItemId2", offHandSupplier::getIntID) + .uniform1i(PER_FRAME, "heldBlockLightValue", mainHandSupplier::getLightValue) + .uniform1i(PER_FRAME, "heldBlockLightValue2", offHandSupplier::getLightValue); + // TODO: Figure out API. + //.uniformVanilla3f(PER_FRAME, "heldBlockLightColor", mainHandSupplier::getLightColor) + //.uniformVanilla3f(PER_FRAME, "heldBlockLightColor2", offHandSupplier::getLightColor); + + uniforms.uniform1i("entityId", CapturedRenderingState.INSTANCE::getCurrentRenderedEntity, + CapturedRenderingState.INSTANCE.getEntityIdNotifier()); + + uniforms.uniform1i("blockEntityId", CapturedRenderingState.INSTANCE::getCurrentRenderedBlockEntity, + CapturedRenderingState.INSTANCE.getBlockEntityIdNotifier()); + } + + /** + * Provides the currently held item, and it's light value, in the given hand as a uniform. Uses the item.properties ID map to map the item + * to an integer, and the old hand light value to map offhand to main hand. + */ + private static class HeldItemSupplier { + private final InteractionHand hand; + private final Object2IntFunction itemIdMap; + private final boolean applyOldHandLight; + private int intID; + private int lightValue; + private Vector3f lightColor; + + HeldItemSupplier(InteractionHand hand, Object2IntFunction itemIdMap, boolean shouldApplyOldHandLight) { + this.hand = hand; + this.itemIdMap = itemIdMap; + this.applyOldHandLight = shouldApplyOldHandLight && hand == InteractionHand.MAIN_HAND; + } + + private void invalidate() { + intID = -1; + lightValue = 0; + lightColor = IrisItemLightProvider.DEFAULT_LIGHT_COLOR; + } + + public void update() { + LocalPlayer player = Minecraft.getMinecraft().thePlayer; + + if (player == null) { + // Not valid when the player doesn't exist + invalidate(); + return; + } + + ItemStack heldStack = player.getItemInHand(hand); + + if (heldStack == null) { + invalidate(); + return; + } + + Item heldItem = heldStack.getItem(); + + if (heldItem == null) { + invalidate(); + return; + } + + ResourceLocation heldItemId = Registry.ITEM.getKey(heldItem); + intID = itemIdMap.applyAsInt(new NamespacedId(heldItemId.getNamespace(), heldItemId.getPath())); + + IrisItemLightProvider lightProvider = (IrisItemLightProvider) heldItem; + lightValue = lightProvider.getLightEmission(Minecraft.getMinecraft().thePlayer, heldStack); + + if (applyOldHandLight) { + lightProvider = applyOldHandLighting(player, lightProvider); + } + + lightColor = lightProvider.getLightColor(Minecraft.getMinecraft().thePlayer, heldStack); + } + + private IrisItemLightProvider applyOldHandLighting(@NotNull LocalPlayer player, IrisItemLightProvider existing) { + ItemStack offHandStack = player.getItemInHand(InteractionHand.OFF_HAND); + + if (offHandStack == null) { + return existing; + } + + Item offHandItem = offHandStack.getItem(); + + if (offHandItem == null) { + return existing; + } + + IrisItemLightProvider lightProvider = (IrisItemLightProvider) offHandItem; + int newEmission = lightProvider.getLightEmission(Minecraft.getMinecraft().thePlayer, offHandStack); + + if (lightValue < newEmission) { + lightValue = newEmission; + return lightProvider; + } + + return existing; + } + + public int getIntID() { + return intID; + } + + public int getLightValue() { + return lightValue; + } + + public Vector3f getLightColor() { + return lightColor; + } + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/IrisExclusiveUniforms.java b/src/main/java/net/coderbot/iris/uniforms/IrisExclusiveUniforms.java new file mode 100644 index 000000000..64f971e53 --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/IrisExclusiveUniforms.java @@ -0,0 +1,148 @@ +package net.coderbot.iris.uniforms; + +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.entity.EntityLivingBase; +import org.joml.Math; +import org.joml.Vector3d; +import org.joml.Vector4f; + +public class IrisExclusiveUniforms { + public static void addIrisExclusiveUniforms(UniformHolder uniforms) { + WorldInfoUniforms.addWorldInfoUniforms(uniforms); + + //All Iris-exclusive uniforms (uniforms which do not exist in either OptiFine or ShadersMod) should be registered here. + uniforms.uniform1f(UniformUpdateFrequency.PER_FRAME, "thunderStrength", IrisExclusiveUniforms::getThunderStrength); + uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "currentPlayerHealth", IrisExclusiveUniforms::getCurrentHealth); + uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "maxPlayerHealth", IrisExclusiveUniforms::getMaxHealth); + uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "currentPlayerHunger", IrisExclusiveUniforms::getCurrentHunger); + uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "maxPlayerHunger", () -> 20); + uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "currentPlayerAir", IrisExclusiveUniforms::getCurrentAir); + 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.uniform3d(UniformUpdateFrequency.PER_FRAME, "eyePosition", IrisExclusiveUniforms::getEyePosition); + Vector4f zero = new Vector4f(0, 0, 0, 0); + // TODO: Iris Shaders +// 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; +// } +// }); + } + + private static float getThunderStrength() { + // Note: Ensure this is in the range of 0 to 1 - some custom servers send out of range values. + return Math.clamp(0.0F, 1.0F, Minecraft.getMinecraft().theWorld.thunderingStrength); + } + + private static float getCurrentHealth() { + if (Minecraft.getMinecraft().thePlayer == null || !Minecraft.getMinecraft().playerController.gameIsSurvivalOrAdventure()) { + return -1; + } + + return Minecraft.getMinecraft().thePlayer.getHealth() / Minecraft.getMinecraft().thePlayer.getMaxHealth(); + } + + private static float getCurrentHunger() { + if (Minecraft.getMinecraft().thePlayer == null || !Minecraft.getMinecraft().playerController.gameIsSurvivalOrAdventure()) { + return -1; + } + + return Minecraft.getMinecraft().thePlayer.getFoodStats().getFoodLevel() / 20f; + } + + private static float getCurrentAir() { + if (Minecraft.getMinecraft().thePlayer == null || !Minecraft.getMinecraft().playerController.gameIsSurvivalOrAdventure()) { + return -1; + } + + return (float) Minecraft.getMinecraft().thePlayer.getAir() / (float) Minecraft.getMinecraft().thePlayer.getAir(); + } + + private static float getMaxAir() { + if (Minecraft.getMinecraft().thePlayer == null || !Minecraft.getMinecraft().playerController.gameIsSurvivalOrAdventure()) { + return -1; + } + +// return Minecraft.getMinecraft().thePlayer.getMaxAirSupply(); + return 300.0F; + } + + private static float getMaxHealth() { + if (Minecraft.getMinecraft().thePlayer == null || !Minecraft.getMinecraft().playerController.gameIsSurvivalOrAdventure()) { + return -1; + } + + return Minecraft.getMinecraft().thePlayer.getMaxHealth(); + } + + private static boolean isFirstPersonCamera() { + // If camera type is not explicitly third-person, assume it's first-person. + return (Minecraft.getMinecraft().gameSettings.thirdPersonView == 1); + } + + private static boolean isSpectator() { +// return Minecraft.getMinecraft().gameMode.getPlayerMode() == GameType.SPECTATOR; + // TODO: AF? EFR? + return false; + } + + private static Vector3d getEyePosition() { +// Objects.requireNonNull(Minecraft.getMinecraft().getCameraEntity()); +// return new Vector3d(Minecraft.getMinecraft().getCameraEntity().getX(), Minecraft.getMinecraft().getCameraEntity().getEyeY(), Minecraft.getMinecraft().getCameraEntity().getZ()); + EntityLivingBase eye = Minecraft.getMinecraft().renderViewEntity; + return new Vector3d(eye.posX, eye.posY, eye.posZ); + } + + public static class WorldInfoUniforms { + public static void addWorldInfoUniforms(UniformHolder uniforms) { + WorldClient level = Minecraft.getMinecraft().theWorld; + uniforms.uniform1i(UniformUpdateFrequency.PER_FRAME, "bedrockLevel", () -> 0); + uniforms.uniform1f(UniformUpdateFrequency.PER_FRAME, "cloudHeight", () -> { + if (level != null && level.provider != null) { + return level.provider.getCloudHeight(); + } else { + return 192.0; + } + }); + uniforms.uniform1i(UniformUpdateFrequency.PER_FRAME, "heightLimit", () -> { + if (level != null && level.provider != null) { + return level.provider.getHeight(); + } else { + return 256; + } + }); + uniforms.uniform1b(UniformUpdateFrequency.PER_FRAME, "hasCeiling", () -> { + if (level != null && level.provider != null) { + return level.provider.hasNoSky; + } else { + return false; + } + }); + uniforms.uniform1b(UniformUpdateFrequency.PER_FRAME, "hasSkylight", () -> { + if (level != null && level.provider != null) { + return !level.provider.hasNoSky; + } else { + return true; + } + }); + uniforms.uniform1f(UniformUpdateFrequency.PER_FRAME, "ambientLight", () -> { + if (level != null && level.provider != null) { + return level.provider.lightBrightnessTable[0]; + } else { + return 0f; + } + }); + + } + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java new file mode 100644 index 000000000..6a2cfe236 --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java @@ -0,0 +1,110 @@ +package net.coderbot.iris.uniforms; + +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.coderbot.iris.pipeline.ShadowRenderer; +import net.coderbot.iris.shaderpack.PackDirectives; +import net.coderbot.iris.shadow.ShadowMatrices; +import org.joml.Matrix4f; + +import java.nio.FloatBuffer; +import java.util.function.Supplier; + +import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; + +public final class MatrixUniforms { + private MatrixUniforms() { + } + + public static void addMatrixUniforms(UniformHolder uniforms, PackDirectives directives) { + addMatrix(uniforms, "ModelView", CapturedRenderingState.INSTANCE::getGbufferModelView); + // TODO: In some cases, gbufferProjectionInverse takes on a value much different than OptiFine... + // We need to audit Mojang's linear algebra. + addMatrix(uniforms, "Projection", CapturedRenderingState.INSTANCE::getGbufferProjection); + addShadowMatrix(uniforms, "ModelView", () -> + ShadowRenderer.createShadowModelView(directives.getSunPathRotation(), directives.getShadowDirectives().getIntervalSize()).last().pose().copy()); + addShadowArrayMatrix(uniforms, "Projection", () -> ShadowMatrices.createOrthoMatrix(directives.getShadowDirectives().getDistance())); + } + + private static void addMatrix(UniformHolder uniforms, String name, Supplier supplier) { + uniforms + .uniformMatrix(PER_FRAME, "gbuffer" + name, supplier) + .uniformMatrix(PER_FRAME, "gbuffer" + name + "Inverse", new Inverted(supplier)) + .uniformMatrix(PER_FRAME, "gbufferPrevious" + name, new Previous(supplier)); + } + + private static void addShadowMatrix(UniformHolder uniforms, String name, Supplier supplier) { + uniforms + .uniformMatrix(PER_FRAME, "shadow" + name, supplier) + .uniformMatrix(PER_FRAME, "shadow" + name + "Inverse", new Inverted(supplier)); + } + + private static void addShadowArrayMatrix(UniformHolder uniforms, String name, Supplier supplier) { + uniforms + .uniformMatrixFromArray(PER_FRAME, "shadow" + name, supplier) + .uniformMatrix(PER_FRAME, "shadow" + name + "Inverse", new InvertedArrayMatrix(supplier)); + } + + private static class Inverted implements Supplier { + private final Supplier parent; + + Inverted(Supplier parent) { + this.parent = parent; + } + + @Override + public Matrix4f get() { + // PERF: Don't copy + allocate this matrix every time? + Matrix4f copy = parent.get().copy(); + + FloatBuffer buffer = FloatBuffer.allocate(16); + copy.store(buffer); + buffer.rewind(); + + Matrix4f matrix4f = new Matrix4f(buffer); + matrix4f.invert(); + + return matrix4f; + } + } + + private static class InvertedArrayMatrix implements Supplier { + private final Supplier parent; + + InvertedArrayMatrix(Supplier parent) { + this.parent = parent; + } + + @Override + public Matrix4f get() { + FloatBuffer buffer = FloatBuffer.allocate(16); + buffer.put(parent.get()); + buffer.rewind(); + + Matrix4f matrix4f = new Matrix4f(buffer); + matrix4f.invert(); + + return matrix4f; + } + } + + private static class Previous implements Supplier { + private final Supplier parent; + private Matrix4f previous; + + Previous(Supplier parent) { + this.parent = parent; + this.previous = new Matrix4f(); + } + + @Override + public Matrix4f get() { + // PERF: Don't copy + allocate these matrices every time? + Matrix4f copy = parent.get().copy(); + Matrix4f previous = this.previous.copy(); + + this.previous = copy; + + return previous; + } + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/SystemTimeUniforms.java b/src/main/java/net/coderbot/iris/uniforms/SystemTimeUniforms.java new file mode 100644 index 000000000..c2c9fdc66 --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/SystemTimeUniforms.java @@ -0,0 +1,117 @@ +package net.coderbot.iris.uniforms; + +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; + +import java.util.OptionalLong; +import java.util.function.IntSupplier; + +/** + * Implements uniforms relating the system time (as opposed to the world time) + * + * @see Uniforms: System time + */ +public final class SystemTimeUniforms { + public static final Timer TIMER = new Timer(); + public static final FrameCounter COUNTER = new FrameCounter(); + + private SystemTimeUniforms() { + } + + /** + * Makes system time uniforms available to the given program + * + * @param uniforms the program to make the uniforms available to + */ + public static void addSystemTimeUniforms(UniformHolder uniforms) { + uniforms + .uniform1i(UniformUpdateFrequency.PER_FRAME, "frameCounter", COUNTER) + // TODO: Don't hardcode framemod8 here for Sildur's Vibrant Shaders + .uniform1i(UniformUpdateFrequency.PER_FRAME, "framemod8", () -> COUNTER.getAsInt() % 8) + .uniform1f(UniformUpdateFrequency.PER_FRAME, "frameTime", TIMER::getLastFrameTime) + .uniform1f(UniformUpdateFrequency.PER_FRAME, "frameTimeCounter", TIMER::getFrameTimeCounter); + } + + public static void addFloatFrameMod8Uniform(UniformHolder uniforms) { + uniforms.uniform1f(UniformUpdateFrequency.PER_FRAME, "framemod8", () -> COUNTER.getAsInt() % 8); + } + + /** + * A simple frame counter. On each frame, it is incremented by 1, and it wraps around every 720720 frames. It starts + * at zero and goes from there. + */ + public static class FrameCounter implements IntSupplier { + private int count; + + private FrameCounter() { + this.count = 0; + } + + @Override + public int getAsInt() { + return count; + } + + public void beginFrame() { + count = (count + 1) % 720720; + } + + public void reset() { + count = 0; + } + } + + /** + * Keeps track of the time that the last frame took to render as well as the number of milliseconds since the start + * of the first frame to the start of the current frame. Updated at the start of each frame. + */ + public static final class Timer { + private float frameTimeCounter; + private float lastFrameTime; + + // Disabling this because OptionalLong provides a nice wrapper around (boolean valid, long value) + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + private OptionalLong lastStartTime; + + public Timer() { + reset(); + } + + public void beginFrame(long frameStartTime) { + // Track how much time passed since the last time we began rendering a frame. + // If this is the first frame, then use a value of 0. + long diffNs = frameStartTime - lastStartTime.orElse(frameStartTime); + // Convert to milliseconds + long diffMs = (diffNs / 1000) / 1000; + + // Convert to seconds with a resolution of 1 millisecond, and store as the time taken for the last frame to complete. + lastFrameTime = diffMs / 1000.0F; + + // Advance the current frameTimeCounter by the amount of time the last frame took. + frameTimeCounter += lastFrameTime; + + // Prevent the frameTimeCounter from getting too large, since that causes issues with some shaderpacks + // This means that it should reset every hour. + if (frameTimeCounter >= 3600.0F) { + frameTimeCounter = 0.0F; + } + + // Finally, update the "last start time" value. + lastStartTime = OptionalLong.of(frameStartTime); + } + + public float getFrameTimeCounter() { + return frameTimeCounter; + } + + public float getLastFrameTime() { + return lastFrameTime; + } + + public void reset() { + frameTimeCounter = 0.0F; + lastFrameTime = 0.0F; + lastStartTime = OptionalLong.empty(); + } + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java b/src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java new file mode 100644 index 000000000..b166552c6 --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java @@ -0,0 +1,38 @@ +package net.coderbot.iris.uniforms; + +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.minecraft.client.Minecraft; + +import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; + +/** + * Implements uniforms relating the current viewport + * + * @see Uniforms: Viewport + */ +public final class ViewportUniforms { + // cannot be constructed + private ViewportUniforms() { + } + + /** + * Makes the viewport uniforms available to the given program + * + * @param uniforms the program to make the uniforms available to + */ + public static void addViewportUniforms(UniformHolder uniforms) { + // TODO: What about the custom scale.composite3 property? + // NB: It is not safe to cache the render target due to mods like Resolution Control modifying the render target field. + uniforms + .uniform1f(PER_FRAME, "viewHeight", () -> Minecraft.getMinecraft().getMainRenderTarget().height) + .uniform1f(PER_FRAME, "viewWidth", () -> Minecraft.getMinecraft().getMainRenderTarget().width) + .uniform1f(PER_FRAME, "aspectRatio", ViewportUniforms::getAspectRatio); + } + + /** + * @return the current viewport aspect ratio, calculated from the current Minecraft window size + */ + private static float getAspectRatio() { + return ((float) Minecraft.getMinecraft().getMainRenderTarget().width) / ((float) Minecraft.getMinecraft().getMainRenderTarget().height); + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java b/src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java new file mode 100644 index 000000000..b4923b60c --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java @@ -0,0 +1,54 @@ +package net.coderbot.iris.uniforms; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.coderbot.iris.shaderpack.DimensionId; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; + +import java.util.Objects; + +import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_TICK; + +public final class WorldTimeUniforms { + private WorldTimeUniforms() { + } + + /** + * Makes world time uniforms available to the given program + * + * @param uniforms the program to make the uniforms available to + */ + public static void addWorldTimeUniforms(UniformHolder uniforms) { + uniforms + .uniform1i(PER_TICK, "worldTime", WorldTimeUniforms::getWorldDayTime) + .uniform1i(PER_TICK, "worldDay", WorldTimeUniforms::getWorldDay) + .uniform1i(PER_TICK, "moonPhase", () -> getWorld().getMoonPhase()); + } + + static int getWorldDayTime() { + long timeOfDay = getWorld().getWorldTime(); + + if (Iris.getCurrentDimension() == DimensionId.END || Iris.getCurrentDimension() == DimensionId.NETHER) { + // If the dimension is the nether or the end, don't override the fixed time. + // This was an oversight in versions before and including 1.2.5 causing inconsistencies, such as Complementary's ender beams not moving. + return (int) (timeOfDay % 24000L); + } + + long dayTime = ((DimensionTypeAccessor) getWorld().dimensionType()).getFixedTime() + .orElse(timeOfDay % 24000L); + + return (int) dayTime; + } + + private static int getWorldDay() { + long timeOfDay = getWorld().getWorldTime(); + long day = timeOfDay / 24000L; + + return (int) day; + } + + private static WorldClient getWorld() { + return Objects.requireNonNull(Minecraft.getMinecraft().theWorld); + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/builtin/BuiltinReplacementUniforms.java b/src/main/java/net/coderbot/iris/uniforms/builtin/BuiltinReplacementUniforms.java new file mode 100644 index 000000000..7a3450abe --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/builtin/BuiltinReplacementUniforms.java @@ -0,0 +1,31 @@ +package net.coderbot.iris.uniforms.builtin; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; +import org.joml.Matrix4f; + +public class BuiltinReplacementUniforms { + private static final Matrix4f lightmapTextureMatrix; + + static { + // This mimics the transformations done in LightmapTextureManager to the GL_TEXTURE matrix. + lightmapTextureMatrix = new Matrix4f(); + lightmapTextureMatrix.identity(); + lightmapTextureMatrix.scale(0.00390625f); + + // TODO: Iris-Shaders - Is this logic correct? + final Matrix4f translateMatrix = new Matrix4f(); + translateMatrix.translate(8.0f, 8.0f, 8.0f); + lightmapTextureMatrix.mul(translateMatrix); + } + + public static void addBuiltinReplacementUniforms(UniformHolder uniforms) { + uniforms.uniformMatrix(UniformUpdateFrequency.ONCE, "iris_LightmapTextureMatrix", () -> { + Iris.logger.warn("A shader appears to require the lightmap texture matrix even after transformations have occurred"); + Iris.logger.warn("Iris handles this correctly but it indicates that the shader is doing weird things with lightmap coordinates"); + + return lightmapTextureMatrix; + }); + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/transforms/SmoothedFloat.java b/src/main/java/net/coderbot/iris/uniforms/transforms/SmoothedFloat.java new file mode 100644 index 000000000..76ac51ca1 --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/transforms/SmoothedFloat.java @@ -0,0 +1,141 @@ +package net.coderbot.iris.uniforms.transforms; + +import net.coderbot.iris.gl.uniform.FloatSupplier; +import net.coderbot.iris.uniforms.FrameUpdateNotifier; +import net.coderbot.iris.uniforms.SystemTimeUniforms; + +/** + * An implementation of basic exponential smoothing that converts a sequence of unsmoothed values into a sequence of + * smoothed values. + * + * @see + * Wikipedia: Basic (simple) exponential smoothing (Holt linear) + */ +public class SmoothedFloat implements FloatSupplier { + /** + * Natural logarithm of 2, ie. {@code ln(2)} + */ + private static final double LN_OF_2 = Math.log(2.0); + + /** + * The input sequence of unsmoothed values + */ + private final FloatSupplier unsmoothed; + + /** + * An accumulator for smoothed values. + */ + private float accumulator; + + /** + * Tracks whether an initial value has already been generated, because otherwise there will be nothing to smooth + * with. + */ + private boolean hasInitialValue; + + /** + * The decay constant upward, k (as used in e^(-kt)) + */ + private final float decayConstantUp; + + /** + * The decay constant downward, k (as used in e^(-kt)) + */ + private final float decayConstantDown; + + /** + * Creates a new SmoothedFloat with a given half life. + * + * @param halfLifeUp the half life in the exponential decay, in deciseconds (1/10th of a second) / 2 ticks. + * For example, a half life of value of 2.0 is 4 ticks or 0.2 seconds + * @param unsmoothed the input sequence of unsmoothed values to be smoothed. {@code unsmoothed.getAsFloat()} will be + * called exactly once for every time {@code smoothed.getAsFloat()} is called. + */ + public SmoothedFloat(float halfLifeUp, float halfLifeDown, FloatSupplier unsmoothed, FrameUpdateNotifier updateNotifier) { + // Half life is measured in units of 10ths of a second, or 2 ticks + // For example, a half life of value of 2.0 is 4 ticks or 0.2 seconds + this.decayConstantUp = computeDecay(halfLifeUp * 0.1F); + this.decayConstantDown = computeDecay(halfLifeDown * 0.1F); + + this.unsmoothed = unsmoothed; + + updateNotifier.addListener(this::update); + } + + /** + * Takes one value from the unsmoothed value sequence, and smooths it into our accumulator + */ + private void update() { + if (!hasInitialValue) { + // There is no smoothing on the first value. + // This is not an optimal approach to choosing the initial value: + // https://en.wikipedia.org/wiki/Exponential_smoothing#Choosing_the_initial_smoothed_value + // + // However, it works well enough for now. + accumulator = unsmoothed.getAsFloat(); + hasInitialValue = true; + + return; + } + + // Implements the basic variant of exponential smoothing + // https://en.wikipedia.org/wiki/Exponential_smoothing#Basic_(simple)_exponential_smoothing_(Holt_linear) + + // xₜ + float newValue = unsmoothed.getAsFloat(); + + // 𝚫t + float lastFrameTime = SystemTimeUniforms.TIMER.getLastFrameTime(); + + // Compute the smoothing factor based on our + // α = 1 - e^(-𝚫t/τ) = 1 - e^(-k𝚫t) + float smoothingFactor = 1.0f - exponentialDecayFactor(newValue > this.accumulator ? this.decayConstantUp : decayConstantDown, lastFrameTime); + + // sₜ = αxₜ + (1 - α)sₜ₋₁ + accumulator = lerp(accumulator, newValue, smoothingFactor); + } + + private float computeDecay(float halfLife) { + // Compute the decay constant from the half life + // https://en.wikipedia.org/wiki/Exponential_decay#Measuring_rates_of_decay + // https://en.wikipedia.org/wiki/Exponential_smoothing#Time_constant + // k = 1 / τ + return (float) (1.0f / (halfLife / LN_OF_2)); + } + + /** + * @return the current smoothed value + */ + @Override + public float getAsFloat() { + if (!hasInitialValue) { + return unsmoothed.getAsFloat(); + } + + return accumulator; + } + + /** + * Computes an exponential decay factor based on the given decay constant and time value + * + * @param k the decay constant, derived from the half life + * @param t the time that has passed since the decay started + */ + private static float exponentialDecayFactor(float k, float t) { + // https://en.wikipedia.org/wiki/Exponential_decay + // e^(-kt) + return (float) Math.exp(-k * t); + } + + /** + * Computes a linearly interpolated value between v0 and v1 + * + * @param v0 the starting value (t = 0) + * @param v1 the ending value (t = 1) + * @param t the time/progress value - should be in the range of 0.0 to 1.0 + */ + private static float lerp(float v0, float v1, float t) { + // https://en.wikipedia.org/wiki/Linear_interpolation + return (1 - t) * v0 + t * v1; + } +} diff --git a/src/main/java/net/coderbot/iris/uniforms/transforms/SmoothedVec2f.java b/src/main/java/net/coderbot/iris/uniforms/transforms/SmoothedVec2f.java new file mode 100644 index 000000000..aba7a642a --- /dev/null +++ b/src/main/java/net/coderbot/iris/uniforms/transforms/SmoothedVec2f.java @@ -0,0 +1,22 @@ +package net.coderbot.iris.uniforms.transforms; + +import net.coderbot.iris.uniforms.FrameUpdateNotifier; +import org.joml.Vector2f; +import org.joml.Vector2i; + +import java.util.function.Supplier; + +public class SmoothedVec2f implements Supplier { + private final SmoothedFloat x; + private final SmoothedFloat y; + + public SmoothedVec2f(float halfLifeUp, float halfLifeDown, Supplier unsmoothed, FrameUpdateNotifier updateNotifier) { + x = new SmoothedFloat(halfLifeUp, halfLifeDown, () -> unsmoothed.get().x, updateNotifier); + y = new SmoothedFloat(halfLifeUp, halfLifeDown, () -> unsmoothed.get().y, updateNotifier); + } + + @Override + public Vector2f get() { + return new Vector2f(x.getAsFloat(), y.getAsFloat()); + } +} diff --git a/src/main/java/net/coderbot/iris/vertices/BlockSensitiveBufferBuilder.java b/src/main/java/net/coderbot/iris/vertices/BlockSensitiveBufferBuilder.java new file mode 100644 index 000000000..4a8d123c7 --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/BlockSensitiveBufferBuilder.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.vertices; + +public interface BlockSensitiveBufferBuilder { + void beginBlock(short block, short renderType, int localPosX, int localPosY, int localPosZ); + + void endBlock(); +} diff --git a/src/main/java/net/coderbot/iris/vertices/BufferBuilderPolygonView.java b/src/main/java/net/coderbot/iris/vertices/BufferBuilderPolygonView.java new file mode 100644 index 000000000..6bf47c07b --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/BufferBuilderPolygonView.java @@ -0,0 +1,42 @@ +package net.coderbot.iris.vertices; + +import java.nio.ByteBuffer; + +public class BufferBuilderPolygonView implements QuadView { + private ByteBuffer buffer; + private int writePointer; + private int stride = 48; + private int vertexAmount; + + public void setup(ByteBuffer buffer, int writePointer, int stride, int vertexAmount) { + this.buffer = buffer; + this.writePointer = writePointer; + this.stride = stride; + this.vertexAmount = vertexAmount; + } + + @Override + public float x(int index) { + return buffer.getFloat(writePointer - stride * (vertexAmount - index)); + } + + @Override + public float y(int index) { + return buffer.getFloat(writePointer + 4 - stride * (vertexAmount - index)); + } + + @Override + public float z(int index) { + return buffer.getFloat(writePointer + 8 - stride * (vertexAmount - index)); + } + + @Override + public float u(int index) { + return buffer.getFloat(writePointer + 16 - stride * (vertexAmount - index)); + } + + @Override + public float v(int index) { + return buffer.getFloat(writePointer + 20 - stride * (vertexAmount - index)); + } +} diff --git a/src/main/java/net/coderbot/iris/vertices/ExtendedDataHelper.java b/src/main/java/net/coderbot/iris/vertices/ExtendedDataHelper.java new file mode 100644 index 000000000..4824927f0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/ExtendedDataHelper.java @@ -0,0 +1,20 @@ +package net.coderbot.iris.vertices; + +public final class ExtendedDataHelper { + // TODO: Resolve render types for normal blocks? + public static final short BLOCK_RENDER_TYPE = -1; + /** All fluids have a ShadersMod render type of 1, to match behavior of Minecraft 1.7 and earlier. */ + public static final short FLUID_RENDER_TYPE = 1; + + public static int packMidBlock(float x, float y, float z) { + return ((int) (x * 64) & 0xFF) | (((int) (y * 64) & 0xFF) << 8) | (((int) (z * 64) & 0xFF) << 16); + } + + public static int computeMidBlock(float x, float y, float z, int localPosX, int localPosY, int localPosZ) { + return packMidBlock( + localPosX + 0.5f - x, + localPosY + 0.5f - y, + localPosZ + 0.5f - z + ); + } +} diff --git a/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java b/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java new file mode 100644 index 000000000..b616c731a --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java @@ -0,0 +1,5 @@ +package net.coderbot.iris.vertices; + +public interface ExtendingBufferBuilder { + void iris$beginWithoutExtending(int drawMode, VertexFormat vertexFormat); +} diff --git a/src/main/java/net/coderbot/iris/vertices/ImmediateState.java b/src/main/java/net/coderbot/iris/vertices/ImmediateState.java new file mode 100644 index 000000000..2762c6bda --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/ImmediateState.java @@ -0,0 +1,9 @@ +package net.coderbot.iris.vertices; + +/** + * Some annoying global state needed for the extended vertex format disabling optimization. + */ +public class ImmediateState { + public static boolean isRenderingLevel = false; + public static boolean renderWithExtendedVertexFormat = true; +} diff --git a/src/main/java/net/coderbot/iris/vertices/IrisTextVertexSinkImpl.java b/src/main/java/net/coderbot/iris/vertices/IrisTextVertexSinkImpl.java new file mode 100644 index 000000000..83ddba08a --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/IrisTextVertexSinkImpl.java @@ -0,0 +1,121 @@ +package net.coderbot.iris.vertices; + +import org.joml.Vector3f; +import net.irisshaders.iris.api.v0.IrisTextVertexSink; + +import java.nio.ByteBuffer; +import java.util.function.IntFunction; + +public class IrisTextVertexSinkImpl implements IrisTextVertexSink { + static VertexFormat format = IrisVertexFormats.TERRAIN; + private final ByteBuffer buffer; + private final TextQuadView quad = new TextQuadView(); + private final Vector3f saveNormal = new Vector3f(); + private static final int STRIDE = IrisVertexFormats.TERRAIN.getVertexSize(); + private int vertexCount; + private long elementOffset; + private float uSum; + private float vSum; + + public IrisTextVertexSinkImpl(int maxQuadCount, IntFunction buffer) { + this.buffer = buffer.apply(format.getVertexSize() * 4 * maxQuadCount); + this.elementOffset = MemoryUtil.memAddress(this.buffer); + } + + @Override + public VertexFormat getUnderlyingVertexFormat() { + return format; + } + + @Override + public ByteBuffer getUnderlyingByteBuffer() { + return buffer; + } + + @Override + public void quad(float minX, float minY, float maxX, float maxY, float z, int color, float minU, float minV, float maxU, float maxV, int light) { + vertex(minX, minY, z, color, minU, minV, light); + vertex(minX, maxY, z, color, minU, maxV, light); + vertex(maxX, maxY, z, color, maxU, maxV, light); + vertex(maxX, minY, z, color, maxU, minV, light); + } + + private void vertex(float x, float y, float z, int color, float u, float v, int light) { + vertexCount++; + uSum += u; + vSum += v; + + long i = elementOffset; + + MemoryUtil.memPutFloat(i, x); + MemoryUtil.memPutFloat(i + 4, y); + MemoryUtil.memPutFloat(i + 8, z); + MemoryUtil.memPutInt(i + 12, color); + MemoryUtil.memPutFloat(i + 16, u); + MemoryUtil.memPutFloat(i + 20, v); + MemoryUtil.memPutInt(i + 24, light); + + if (vertexCount == 4) { + // TODO: compute this at the head of quad() + vertexCount = 0; + uSum *= 0.25; + vSum *= 0.25; + quad.setup(elementOffset, IrisVertexFormats.TERRAIN.getVertexSize()); + + NormalHelper.computeFaceNormal(saveNormal, quad); + float normalX = saveNormal.x; + float normalY = saveNormal.y; + float normalZ = saveNormal.z; + int normal = NormalHelper.packNormal(saveNormal, 0.0F); + + int tangent = NormalHelper.computeTangent(normalX, normalY, normalZ, quad); + + for (long vertex = 0; vertex < 4; vertex++) { + MemoryUtil.memPutFloat(i + 36 - STRIDE * vertex, uSum); + MemoryUtil.memPutFloat(i + 40 - STRIDE * vertex, vSum); + MemoryUtil.memPutInt(i + 28 - STRIDE * vertex, normal); + MemoryUtil.memPutInt(i + 44 - STRIDE * vertex, tangent); + } + + uSum = 0; + vSum = 0; + } + + buffer.position(buffer.position() + STRIDE); + elementOffset += STRIDE; + } + + static class TextQuadView implements QuadView { + long writePointer; + int stride; + + public TextQuadView() { + + } + + public void setup(long writePointer, int stride) { + this.writePointer = writePointer; + this.stride = stride; + } + + public float x(int index) { + return MemoryUtil.memGetFloat(writePointer - stride * (3L - index)); + } + + public float y(int index) { + return MemoryUtil.memGetFloat(writePointer + 4 - stride * (3L - index)); + } + + public float z(int index) { + return MemoryUtil.memGetFloat(writePointer + 8 - stride * (3L - index)); + } + + public float u(int index) { + return MemoryUtil.memGetFloat(writePointer + 16 - stride * (3L - index)); + } + + public float v(int index) { + return MemoryUtil.memGetFloat(writePointer + 20 - stride * (3L - index)); + } + } +} diff --git a/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java b/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java new file mode 100644 index 000000000..914d90ce7 --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java @@ -0,0 +1,48 @@ +package net.coderbot.iris.vertices; + +import com.google.common.collect.ImmutableList; + +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 terrainElements = ImmutableList.builder(); + ImmutableList.Builder entityElements = ImmutableList.builder(); + + terrainElements.add(DefaultVertexFormat.ELEMENT_POSITION); // 12 + terrainElements.add(DefaultVertexFormat.ELEMENT_COLOR); // 16 + terrainElements.add(DefaultVertexFormat.ELEMENT_UV0); // 24 + terrainElements.add(DefaultVertexFormat.ELEMENT_UV2); // 28 + terrainElements.add(DefaultVertexFormat.ELEMENT_NORMAL); // 31 + terrainElements.add(DefaultVertexFormat.ELEMENT_PADDING); // 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.ELEMENT_PADDING); // 52 + + entityElements.add(DefaultVertexFormat.ELEMENT_POSITION); // 12 + entityElements.add(DefaultVertexFormat.ELEMENT_COLOR); // 16 + entityElements.add(DefaultVertexFormat.ELEMENT_UV0); // 24 + entityElements.add(DefaultVertexFormat.ELEMENT_UV1); // 28 + entityElements.add(DefaultVertexFormat.ELEMENT_UV2); // 32 + entityElements.add(DefaultVertexFormat.ELEMENT_NORMAL); // 35 + entityElements.add(DefaultVertexFormat.ELEMENT_PADDING); // 36 + entityElements.add(MID_TEXTURE_ELEMENT); // 44 + entityElements.add(TANGENT_ELEMENT); // 48 + + TERRAIN = new VertexFormat(terrainElements.build()); + ENTITY = new VertexFormat(entityElements.build()); + } +} diff --git a/src/main/java/net/coderbot/iris/vertices/NormI8.java b/src/main/java/net/coderbot/iris/vertices/NormI8.java new file mode 100644 index 000000000..61bc793b8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/NormI8.java @@ -0,0 +1,97 @@ +package net.coderbot.iris.vertices; + +import org.joml.Vector3f; +import org.joml.Math; + +/** + * Provides some utilities for working with packed normal vectors. Each normal component provides 8 bits of + * precision in the range of [-1.0,1.0]. + * Copied from Sodium, licensed under the LGPLv3. Modified to support a W component. + * + * | 32 | 24 | 16 | 8 | + * | 0000 0000 | 0110 1100 | 0110 1100 | 0110 1100 | + * | W | X | Y | Z | + */ +public class NormI8 { + private static final int X_COMPONENT_OFFSET = 0; + private static final int Y_COMPONENT_OFFSET = 8; + private static final int Z_COMPONENT_OFFSET = 16; + private static final int W_COMPONENT_OFFSET = 24; + + /** + * The maximum value of a normal's vector component. + */ + private static final float COMPONENT_RANGE = 127.0f; + + /** + * Constant value which can be multiplied with a floating-point vector component to get the normalized value. The + * multiplication is slightly faster than a floating point division, and this code is a hot path which justifies it. + */ + private static final float NORM = 1.0f / COMPONENT_RANGE; + + public static int pack(Vector3f normal) { + return pack(normal.x(), normal.y(), normal.z(), 0); + } + + /** + * Packs the specified vector components into a 32-bit integer in XYZ ordering with the 8 bits of padding at the + * end. + * @param x The x component of the normal's vector + * @param y The y component of the normal's vector + * @param z The z component of the normal's vector + */ + public static int pack(float x, float y, float z, float w) { + return ((int) (x * 127) & 0xFF) | (((int) (y * 127) & 0xFF) << 8) | (((int) (z * 127) & 0xFF) << 16) | (((int) (w * 127) & 0xFF) << 24); + } + /** + * Packs the specified vector components into a 32-bit integer in XYZ ordering with the 8 bits of padding at the + * end. + * @param x The x component of the normal's vector + * @param y The y component of the normal's vector + * @param z The z component of the normal's vector + */ + public static int packColor(float x, float y, float z, float w) { + return ((int) (x * 127) & 0xFF) | (((int) (y * 127) & 0xFF) << 8) | (((int) (z * 127) & 0xFF) << 16) | (((int) w & 0xFF) << 24); + } + + /** + * Encodes a float in the range of -1.0..1.0 to a normalized unsigned integer in the range of 0..255 which can then + * be passed to graphics memory. + */ + private static int encode(float comp) { + // TODO: is the clamp necessary here? our inputs should always be normalized vector components + return ((int) (Math.clamp(comp, -1.0F, 1.0F) * COMPONENT_RANGE) & 255); + } + + /** + * Unpacks the x-component of the packed normal, denormalizing it to a float in the range of -1.0..1.0. + * @param norm The packed normal + */ + public static float unpackX(int norm) { + return ((byte) ((norm >> X_COMPONENT_OFFSET) & 0xFF)) * NORM; + } + + /** + * Unpacks the y-component of the packed normal, denormalizing it to a float in the range of -1.0..1.0. + * @param norm The packed normal + */ + public static float unpackY(int norm) { + return ((byte) ((norm >> Y_COMPONENT_OFFSET) & 0xFF)) * NORM; + } + + /** + * Unpacks the z-component of the packed normal, denormalizing it to a float in the range of -1.0..1.0. + * @param norm The packed normal + */ + public static float unpackZ(int norm) { + return ((byte) ((norm >> Z_COMPONENT_OFFSET) & 0xFF)) * NORM; + } + + /** + * Unpacks the w-component of the packed normal, denormalizing it to a float in the range of -1.0..1.0. + * @param norm The packed normal + */ + public static float unpackW(int norm) { + return ((byte) ((norm >> W_COMPONENT_OFFSET) & 0xFF)) * NORM; + } +} diff --git a/src/main/java/net/coderbot/iris/vertices/NormalHelper.java b/src/main/java/net/coderbot/iris/vertices/NormalHelper.java new file mode 100644 index 000000000..d37ac81d3 --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/NormalHelper.java @@ -0,0 +1,345 @@ +package net.coderbot.iris.vertices; + +import org.joml.Vector3f; +import org.joml.Math; +import org.jetbrains.annotations.NotNull; + +public abstract class NormalHelper { + private NormalHelper() { } + + /** + * Stores a normal plus an extra value as a quartet of signed bytes. + * This is the same normal format that vanilla item rendering expects. + * The extra value is for use by shaders. + */ + public static int packNormal(float x, float y, float z, float w) { + x = Math.clamp(x, -1, 1); + y = Math.clamp(y, -1, 1); + z = Math.clamp(z, -1, 1); + w = Math.clamp(w, -1, 1); + + return ((int) (x * 127) & 0xFF) | (((int) (y * 127) & 0xFF) << 8) | (((int) (z * 127) & 0xFF) << 16) | (((int) (w * 127) & 0xFF) << 24); + } + + /** + * Version of {@link #packNormal(float, float, float, float)} that accepts a vector type. + */ + public static int packNormal(Vector3f normal, float w) { + return packNormal(normal.x, normal.y, normal.z, w); + } + + /** + * Retrieves values packed by {@link #packNormal(float, float, float, float)}. + * + *

Components are x, y, z, w - zero based. + */ + public static float getPackedNormalComponent(int packedNormal, int component) { + return ((byte) (packedNormal >> (8 * component))) / 127f; + } + + /** + * Computes the face normal of the given quad and saves it in the provided non-null vector. + * + *

Assumes counter-clockwise winding order, which is the norm. + * Expects convex quads with all points co-planar. + */ + public static void computeFaceNormal(@NotNull Vector3f saveTo, QuadView q) { +// final Direction nominalFace = q.nominalFace(); +// +// if (GeometryHelper.isQuadParallelToFace(nominalFace, q)) { +// Vec3i vec = nominalFace.getVector(); +// saveTo.set(vec.getX(), vec.getY(), vec.getZ()); +// return; +// } + + final float x0 = q.x(0); + final float y0 = q.y(0); + final float z0 = q.z(0); + final float x1 = q.x(1); + final float y1 = q.y(1); + final float z1 = q.z(1); + final float x2 = q.x(2); + final float y2 = q.y(2); + final float z2 = q.z(2); + final float x3 = q.x(3); + final float y3 = q.y(3); + final float z3 = q.z(3); + + final float dx0 = x2 - x0; + final float dy0 = y2 - y0; + final float dz0 = z2 - z0; + final float dx1 = x3 - x1; + final float dy1 = y3 - y1; + final float dz1 = z3 - z1; + + float normX = dy0 * dz1 - dz0 * dy1; + float normY = dz0 * dx1 - dx0 * dz1; + float normZ = dx0 * dy1 - dy0 * dx1; + + float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ); + + if (l != 0) { + normX /= l; + normY /= l; + normZ /= l; + } + + saveTo.set(normX, normY, normZ); + } + + /** + * Computes the face normal of the given tri and saves it in the provided non-null vector. + * + *

Assumes counter-clockwise winding order, which is the norm. + */ + public static void computeFaceNormalTri(@NotNull Vector3f saveTo, TriView t) { +// final Direction nominalFace = q.nominalFace(); +// +// if (GeometryHelper.isQuadParallelToFace(nominalFace, q)) { +// Vec3i vec = nominalFace.getVector(); +// saveTo.set(vec.getX(), vec.getY(), vec.getZ()); +// return; +// } + + final float x0 = t.x(0); + final float y0 = t.y(0); + final float z0 = t.z(0); + final float x1 = t.x(1); + final float y1 = t.y(1); + final float z1 = t.z(1); + final float x2 = t.x(2); + final float y2 = t.y(2); + final float z2 = t.z(2); + + // note: subtraction order is significant here because of how the cross product works. + // If we're wrong our calculated normal will be pointing in the opposite direction of how it should. + // This current order is similar enough to the order in the quad variant. + final float dx0 = x2 - x0; + final float dy0 = y2 - y0; + final float dz0 = z2 - z0; + final float dx1 = x0 - x1; + final float dy1 = y0 - y1; + final float dz1 = z0 - z1; + + float normX = dy0 * dz1 - dz0 * dy1; + float normY = dz0 * dx1 - dx0 * dz1; + float normZ = dx0 * dy1 - dy0 * dx1; + + float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ); + + if (l != 0) { + normX /= l; + normY /= l; + normZ /= l; + } + + saveTo.set(normX, normY, normZ); + } + + public static int computeTangentSmooth(float normalX, float normalY, float normalZ, TriView t) { + // Capture all of the relevant vertex positions + float x0 = t.x(0); + float y0 = t.y(0); + float z0 = t.z(0); + + float x1 = t.x(1); + float y1 = t.y(1); + float z1 = t.z(1); + + float x2 = t.x(2); + float y2 = t.y(2); + float z2 = t.z(2); + + // Project all vertices onto normal plane (for smooth normal support). Optionally skip this step for flat shading. + // Procedure: + // project v onto normal + // offset v by the projection to get the point on the plane + // project x0, y0, z0 onto normal + float d0 = x0 * normalX + y0 * normalY + z0 * normalZ; + float d1 = x1 * normalX + y1 * normalY + z1 * normalZ; + float d2 = x2 * normalX + y2 * normalY + z2 * normalZ; + + // offset x, y, z by the projection to get the projected point on the normal plane + x0 -= d0 * normalX; + y0 -= d0 * normalY; + z0 -= d0 * normalZ; + + x1 -= d1 * normalX; + y1 -= d1 * normalY; + z1 -= d1 * normalZ; + + x2 -= d2 * normalX; + y2 -= d2 * normalY; + z2 -= d2 * normalZ; + + + float edge1x = x1 - x0; + float edge1y = y1 - y0; + float edge1z = z1 - z0; + + float edge2x = x2 - x0; + float edge2y = y2 - y0; + float edge2z = z2 - z0; + + float u0 = t.u(0); + float v0 = t.v(0); + + float u1 = t.u(1); + float v1 = t.v(1); + + float u2 = t.u(2); + float v2 = t.v(2); + + float deltaU1 = u1 - u0; + float deltaV1 = v1 - v0; + float deltaU2 = u2 - u0; + float deltaV2 = v2 - v0; + + float fdenom = deltaU1 * deltaV2 - deltaU2 * deltaV1; + float f; + + if (fdenom == 0.0) { + f = 1.0f; + } else { + f = 1.0f / fdenom; + } + + float tangentx = f * (deltaV2 * edge1x - deltaV1 * edge2x); + float tangenty = f * (deltaV2 * edge1y - deltaV1 * edge2y); + float tangentz = f * (deltaV2 * edge1z - deltaV1 * edge2z); + float tcoeff = rsqrt(tangentx * tangentx + tangenty * tangenty + tangentz * tangentz); + tangentx *= tcoeff; + tangenty *= tcoeff; + tangentz *= tcoeff; + + float bitangentx = f * (-deltaU2 * edge1x + deltaU1 * edge2x); + float bitangenty = f * (-deltaU2 * edge1y + deltaU1 * edge2y); + float bitangentz = f * (-deltaU2 * edge1z + deltaU1 * edge2z); + float bitcoeff = rsqrt(bitangentx * bitangentx + bitangenty * bitangenty + bitangentz * bitangentz); + bitangentx *= bitcoeff; + bitangenty *= bitcoeff; + bitangentz *= bitcoeff; + + // predicted bitangent = tangent × normal + // Compute the determinant of the following matrix to get the cross product + // i j k + // tx ty tz + // nx ny nz + + // Be very careful when writing out complex multi-step calculations + // such as vector cross products! The calculation for pbitangentz + // used to be broken because it multiplied values in the wrong order. + + float pbitangentx = tangenty * normalZ - tangentz * normalY; + float pbitangenty = tangentz * normalX - tangentx * normalZ; + float pbitangentz = tangentx * normalY - tangenty * normalX; + + float dot = (bitangentx * pbitangentx) + (bitangenty * pbitangenty) + (bitangentz * pbitangentz); + float tangentW; + + if (dot < 0) { + tangentW = -1.0F; + } else { + tangentW = 1.0F; + } + + return NormI8.pack(tangentx, tangenty, tangentz, tangentW); + } + + public static int computeTangent(float normalX, float normalY, float normalZ, TriView t) { + // Capture all of the relevant vertex positions + float x0 = t.x(0); + float y0 = t.y(0); + float z0 = t.z(0); + + float x1 = t.x(1); + float y1 = t.y(1); + float z1 = t.z(1); + + float x2 = t.x(2); + float y2 = t.y(2); + float z2 = t.z(2); + + float edge1x = x1 - x0; + float edge1y = y1 - y0; + float edge1z = z1 - z0; + + float edge2x = x2 - x0; + float edge2y = y2 - y0; + float edge2z = z2 - z0; + + float u0 = t.u(0); + float v0 = t.v(0); + + float u1 = t.u(1); + float v1 = t.v(1); + + float u2 = t.u(2); + float v2 = t.v(2); + + float deltaU1 = u1 - u0; + float deltaV1 = v1 - v0; + float deltaU2 = u2 - u0; + float deltaV2 = v2 - v0; + + float fdenom = deltaU1 * deltaV2 - deltaU2 * deltaV1; + float f; + + if (fdenom == 0.0) { + f = 1.0f; + } else { + f = 1.0f / fdenom; + } + + float tangentx = f * (deltaV2 * edge1x - deltaV1 * edge2x); + float tangenty = f * (deltaV2 * edge1y - deltaV1 * edge2y); + float tangentz = f * (deltaV2 * edge1z - deltaV1 * edge2z); + float tcoeff = rsqrt(tangentx * tangentx + tangenty * tangenty + tangentz * tangentz); + tangentx *= tcoeff; + tangenty *= tcoeff; + tangentz *= tcoeff; + + float bitangentx = f * (-deltaU2 * edge1x + deltaU1 * edge2x); + float bitangenty = f * (-deltaU2 * edge1y + deltaU1 * edge2y); + float bitangentz = f * (-deltaU2 * edge1z + deltaU1 * edge2z); + float bitcoeff = rsqrt(bitangentx * bitangentx + bitangenty * bitangenty + bitangentz * bitangentz); + bitangentx *= bitcoeff; + bitangenty *= bitcoeff; + bitangentz *= bitcoeff; + + // predicted bitangent = tangent × normal + // Compute the determinant of the following matrix to get the cross product + // i j k + // tx ty tz + // nx ny nz + + // Be very careful when writing out complex multi-step calculations + // such as vector cross products! The calculation for pbitangentz + // used to be broken because it multiplied values in the wrong order. + + float pbitangentx = tangenty * normalZ - tangentz * normalY; + float pbitangenty = tangentz * normalX - tangentx * normalZ; + float pbitangentz = tangentx * normalY - tangenty * normalX; + + float dot = (bitangentx * pbitangentx) + (bitangenty * pbitangenty) + (bitangentz * pbitangentz); + float tangentW; + + if (dot < 0) { + tangentW = -1.0F; + } else { + tangentW = 1.0F; + } + + return packNormal(tangentx, tangenty, tangentz, tangentW); + } + + private static float rsqrt(float value) { + if (value == 0.0f) { + // You heard it here first, folks: 1 divided by 0 equals 1 + // In actuality, this is a workaround for normalizing a zero length vector (leaving it as zero length) + return 1.0f; + } else { + return (float) (1.0 / Math.sqrt(value)); + } + } +} diff --git a/src/main/java/net/coderbot/iris/vertices/PolygonView.java b/src/main/java/net/coderbot/iris/vertices/PolygonView.java new file mode 100644 index 000000000..017793cd9 --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/PolygonView.java @@ -0,0 +1,13 @@ +package net.coderbot.iris.vertices; + +public interface PolygonView { + float x(int index); + + float y(int index); + + float z(int index); + + float u(int index); + + float v(int index); +} diff --git a/src/main/java/net/coderbot/iris/vertices/QuadView.java b/src/main/java/net/coderbot/iris/vertices/QuadView.java new file mode 100644 index 000000000..3db437790 --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/QuadView.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.vertices; + +/** + * Implementations of this class must support at least four vertices. + */ +public interface QuadView extends TriView { +} diff --git a/src/main/java/net/coderbot/iris/vertices/TriView.java b/src/main/java/net/coderbot/iris/vertices/TriView.java new file mode 100644 index 000000000..e33996f8b --- /dev/null +++ b/src/main/java/net/coderbot/iris/vertices/TriView.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.vertices; + +/** + * Implementations of this class must support at least three vertices. + */ +public interface TriView extends PolygonView { +} diff --git a/src/main/java/net/irisshaders/iris/api/v0/IrisApi.java b/src/main/java/net/irisshaders/iris/api/v0/IrisApi.java new file mode 100644 index 000000000..ceba45ece --- /dev/null +++ b/src/main/java/net/irisshaders/iris/api/v0/IrisApi.java @@ -0,0 +1,108 @@ +package net.irisshaders.iris.api.v0; + +import net.coderbot.iris.apiimpl.IrisApiV0Impl; + +import java.nio.ByteBuffer; +import java.util.function.IntFunction; + +/** + * The entry point to the Iris API, major version 0. This is currently the latest + * version of the API. + * + * To access the API, use {@link #getInstance()}. + */ +public interface IrisApi { + /** + * @since API v0.0 + */ + static IrisApi getInstance() { + return IrisApiV0Impl.INSTANCE; + } + + /** + * Gets the minor revision of this API. This is incremented when + * new methods are added without breaking API. Mods can check this + * if they wish to check whether given API calls are available on + * the currently installed Iris version. + * + * @return The current minor revision. Currently, revision 1. + */ + int getMinorApiRevision(); + + /** + * Checks whether a shader pack is currently in use and being used + * for rendering. If there is no shader pack enabled or a shader + * pack failed to compile and is therefore not in use, this will + * return false. + * + *

Mods that need to enable custom workarounds for shaders + * should use this method. + * + * @return Whether shaders are being used for rendering. + * @since {@link #getMinorApiRevision() API v0.0} + */ + boolean isShaderPackInUse(); + + /** + * Checks whether the shadow pass is currently being rendered. + * + *

Generally, mods won't need to call this function for much. + * Mods should be fine with things being rendered multiple times + * each frame from different camera perspectives. Often, there's + * a better approach to fixing bugs than calling this function. + * + *

Pretty much the main legitimate use for this function that + * I've seen is in a mod like Immersive Portals, where it has + * very custom culling that doesn't work when the Iris shadow + * pass is active. + * + *

Naturally, this function can only return true if + * {@link #isShaderPackInUse()} returns true. + * + * @return Whether Iris is currently rendering the shadow pass. + * @since API v0.0 + */ + boolean isRenderingShadowPass(); + + /** + * Opens the main Iris GUI screen. It's up to Iris to decide + * what this screen is, but generally this is the shader selection + * screen. + * + * This method takes and returns Objects instead of any concrete + * Minecraft screen class to avoid referencing Minecraft classes. + * Nevertheless, the passed parent must either be null, or an + * object that is a subclass of the appropriate {@code Screen} + * class for the given Minecraft version. + * + * @param parent The parent screen, an instance of the appropriate + * {@code Screen} class. + * @return A {@code Screen} class for the main Iris GUI screen. + * @since API v0.0 + */ + Object openMainIrisScreenObj(Object parent); + + /** + * Gets the language key of the main screen. Currently, this + * is "options.iris.shaderPackSelection". + * + * @return the language key, for use with {@code TranslatableText} + * / {@code TranslatableComponent} + * @since API v0.0 + */ + String getMainScreenLanguageKey(); + + /** + * Gets a config object that can edit the Iris configuration. + * @since API v0.0 + */ + IrisApiConfig getConfig(); + + /** + * Gets a text vertex sink to render into. + * @param maxQuadCount Maximum amount of quads that will be rendered with this sink + * @param bufferProvider An IntFunction that can provide a {@code ByteBuffer} with at minimum the bytes provided by the input parameter + * @since API 0.1 + */ + IrisTextVertexSink createTextVertexSink(int maxQuadCount, IntFunction bufferProvider); +} diff --git a/src/main/java/net/irisshaders/iris/api/v0/IrisApiConfig.java b/src/main/java/net/irisshaders/iris/api/v0/IrisApiConfig.java new file mode 100644 index 000000000..66285a3d6 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/api/v0/IrisApiConfig.java @@ -0,0 +1,22 @@ +package net.irisshaders.iris.api.v0; + +/** + * @since API v0.0 + */ +public interface IrisApiConfig { + /** + * Checks whether there is a shader pack loaded. Note that it is possible for a + * shader pack to be loaded, but not in use, if the shader pack failed to compile. + * You probably meant to call {@link IrisApi#isShaderPackInUse()}! + * + * @return Whether a shader pack was loaded from disk + * @since API v0.0 + */ + boolean areShadersEnabled(); + + /** + * Sets whether shaders are enabled or not, and then applies the change. + * @since API v0.0 + */ + void setShadersEnabledAndApply(boolean enabled); +} diff --git a/src/main/java/net/irisshaders/iris/api/v0/IrisTextVertexSink.java b/src/main/java/net/irisshaders/iris/api/v0/IrisTextVertexSink.java new file mode 100644 index 000000000..87a834a64 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/api/v0/IrisTextVertexSink.java @@ -0,0 +1,32 @@ +package net.irisshaders.iris.api.v0; + +import java.nio.ByteBuffer; + +public interface IrisTextVertexSink { + /** + * Gets the underlying vertex format used for rendering text. + * @return a valid {@code VertexFormat} instance + */ + VertexFormat getUnderlyingVertexFormat(); + /** + * Gets the underlying buffer used for rendering text in the current sink. + * @return a valid {@code ByteBuffer} + */ + ByteBuffer getUnderlyingByteBuffer(); + + /** + * Writes a singular quad with all vertex attributes needed by the current format into the current {@code ByteBuffer}. + * @param x1 Left-most x coordinate of the quad + * @param y1 Top Y coordinate of the quad + * @param x2 Right-most x coordinate of the quad + * @param y2 Bottom Y coordinate of the quad + * @param z Z coordinate of the quad + * @param color Integer-packed ABGR value, with the equation {@code int color = ((int) (a * 255.0F) & 0xFF) << 24 | ((int) (b * 255.0F) & 0xFF) << 16 | ((int) (g * 255.0F) & 0xFF) << 8 | ((int) (r * 255.0F) & 0xFF)} + * @param u1 Top-left U coordinate of the quad texture + * @param v1 Top-left V coordinate of the quad texture + * @param u2 Bottom-right U coordinate of the quad texture + * @param v2 Bottom right V coordinate of the quad texture + * @param light Integer packed light coordinate + */ + void quad(float x1, float y1, float x2, float y2, float z, int color, float u1, float v1, float u2, float v2, int light); +} diff --git a/src/main/java/net/irisshaders/iris/api/v0/item/IrisItemLightProvider.java b/src/main/java/net/irisshaders/iris/api/v0/item/IrisItemLightProvider.java new file mode 100644 index 000000000..f697d53b6 --- /dev/null +++ b/src/main/java/net/irisshaders/iris/api/v0/item/IrisItemLightProvider.java @@ -0,0 +1,24 @@ +package net.irisshaders.iris.api.v0.item; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import org.joml.Vector3f; + +public interface IrisItemLightProvider { + + Vector3f DEFAULT_LIGHT_COLOR = new Vector3f(1, 1, 1); + + default int getLightEmission(EntityPlayer player, ItemStack stack) { + if (stack.getItem() instanceof ItemBlock item) { + + return item.field_150939_a.getLightValue(); + } + + return 0; + } + + default Vector3f getLightColor(EntityPlayer player, ItemStack stack) { + return DEFAULT_LIGHT_COLOR; + } +} From 1b418f26254cd529d0e85208de1992be4dc9c023 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 18 Oct 2023 23:32:50 -0700 Subject: [PATCH 008/301] Second pass at Iris compiles, but doesn't do anything. --- build.gradle | 2 +- .../java/com/gtnewhorizons/angelica/TODO.md | 10 + .../angelica/client/Shaders.java | 232 +++++-- .../angelica/client/ShadersTex.java | 198 ++---- .../accessors/TextureAtlasSpriteAccessor.java | 3 +- .../early/renderer/MixinEntityRenderer.java | 190 ++---- .../early/shaders/MixinInitRenderer.java | 1 + .../textures/MixinTextureAtlasSprite.java | 12 + .../impl/BatchingDebugMessageHelper.java | 3 +- .../impl/BufferBuilderExt.java | 3 +- .../impl/BufferSegment.java | 8 +- .../impl/BufferSegmentRenderer.java | 4 +- .../impl/FullyBufferedMultiBufferSource.java | 10 +- .../OldFullyBufferedMultiBufferSource.java | 6 +- .../impl/RenderTypeUtil.java | 1 + .../impl/SegmentedBufferBuilder.java | 14 +- .../impl/WrappableRenderType.java | 2 + .../GraphTranslucencyRenderOrderManager.java | 5 +- .../impl/ordering/RenderOrderManager.java | 2 +- .../ordering/SimpleRenderOrderManager.java | 1 + .../TranslucencyRenderOrderManager.java | 1 + .../wrappers/TaggingRenderTypeWrapper.java | 5 +- src/main/java/net/coderbot/iris/Iris.java | 5 +- .../coderbot/iris/apiimpl/IrisApiV0Impl.java | 15 +- .../block_rendering/BlockMaterialMapping.java | 179 +++--- .../BlockRenderingSettings.java | 11 +- .../mojang/AutoClosableAbstractTexture.java | 20 + .../iris/compat/mojang/BufferBuilder.java | 39 ++ .../iris/compat/mojang/BufferSource.java | 14 + .../mojang/ByteBufferBackedInputStream.java | 32 + .../coderbot/iris/compat/mojang/Camera.java | 12 + .../compat/mojang/DefaultVertexFormat.java | 20 + .../iris/compat/mojang/DrawState.java | 19 + .../iris/compat/mojang/GameRenderer.java | 16 + .../iris/compat/mojang/InteractionHand.java | 9 + .../iris/compat/mojang/LevelRenderer.java | 6 + .../iris/compat/mojang/MultiBufferSource.java | 11 + .../iris/compat/mojang/NativeImage.java | 120 ++++ .../iris/compat/mojang/PoseStack.java | 28 + .../iris/compat/mojang/RenderBuffers.java | 8 + .../iris/compat/mojang/RenderStateShard.java | 41 ++ .../iris/compat/mojang/RenderType.java | 64 ++ .../iris/compat/mojang/TextureAtlas.java | 19 + .../iris/compat/mojang/VertexBuffer.java | 18 + .../iris/compat/mojang/VertexConsumer.java | 7 + .../iris/compat/mojang/VertexFormat.java | 25 + .../compat/mojang/VertexFormatElement.java | 120 ++++ .../net/coderbot/iris/config/IrisConfig.java | 19 +- .../fantastic/IrisParticleRenderTypes.java | 42 +- .../fantastic/WrappingMultiBufferSource.java | 2 +- .../coderbot/iris/gl/IrisRenderSystem.java | 6 +- .../iris/gl/blending/DepthColorStorage.java | 31 +- .../iris/gl/framebuffer/GlFramebuffer.java | 6 +- .../iris/gl/program/ProgramImages.java | 5 +- .../net/coderbot/iris/gl/shader/GlShader.java | 4 +- .../iris/gl/shader/ShaderWorkarounds.java | 50 -- .../iris/gui/FeatureMissingErrorScreen.java | 31 - .../net/coderbot/iris/gui/FileDialogUtil.java | 63 -- .../java/net/coderbot/iris/gui/GuiUtil.java | 207 ------- .../iris/gui/NavigationController.java | 66 -- .../iris/gui/element/IrisElementRow.java | 225 ------- .../gui/element/IrisObjectSelectionList.java | 23 - .../gui/element/ShaderPackOptionList.java | 365 ----------- .../gui/element/ShaderPackSelectionList.java | 310 ---------- .../screen/ElementWidgetScreenData.java | 15 - .../element/widget/AbstractElementWidget.java | 30 - .../widget/BaseOptionElementWidget.java | 180 ------ .../element/widget/BooleanElementWidget.java | 112 ---- .../widget/CommentedElementWidget.java | 16 - .../gui/element/widget/LinkElementWidget.java | 84 --- .../element/widget/OptionMenuConstructor.java | 87 --- .../element/widget/ProfileElementWidget.java | 101 --- .../element/widget/SliderElementWidget.java | 115 ---- .../element/widget/StringElementWidget.java | 109 ---- .../iris/gui/option/IrisVideoSettings.java | 68 --- .../ShaderPackSelectionButtonOption.java | 27 - .../iris/gui/option/ShadowDistanceOption.java | 22 - .../option/ShadowDistanceSliderButton.java | 20 - .../coderbot/iris/gui/screen/HudHideable.java | 9 - .../iris/gui/screen/ShaderPackScreen.java | 574 ------------------ .../layer/BlockEntityRenderStateShard.java | 1 + .../iris/layer/EntityRenderStateShard.java | 1 + .../layer/IsBlockEntityRenderStateShard.java | 1 + .../iris/layer/IsEntityRenderStateShard.java | 1 + .../iris/layer/IsOutlineRenderStateShard.java | 1 + .../iris/layer/OuterWrappedRenderType.java | 6 +- .../iris/pipeline/CustomTextureManager.java | 29 +- .../DeferredWorldRenderingPipeline.java | 60 +- .../FixedFunctionWorldRenderingPipeline.java | 8 +- .../coderbot/iris/pipeline/HandRenderer.java | 70 ++- .../iris/pipeline/HorizonRenderer.java | 7 +- .../iris/pipeline/PipelineManager.java | 3 +- .../iris/pipeline/ShadowRenderer.java | 136 +++-- .../iris/pipeline/WorldRenderingPhase.java | 1 + .../iris/pipeline/WorldRenderingPipeline.java | 4 +- .../iris/postprocess/CenterDepthSampler.java | 4 +- .../iris/postprocess/CompositeRenderer.java | 12 +- .../iris/postprocess/FinalPassRenderer.java | 30 +- .../postprocess/FullScreenQuadRenderer.java | 1 + .../rendertarget/Blaze3dRenderTargetExt.java | 7 - .../NativeImageBackedCustomTexture.java | 10 +- .../NativeImageBackedNoiseTexture.java | 13 +- .../NativeImageBackedSingleColorTexture.java | 1 + .../iris/rendertarget/RenderTarget.java | 17 +- .../coderbot/iris/samplers/IrisSamplers.java | 6 +- .../coderbot/iris/shaderpack/ShaderPack.java | 75 +-- .../coderbot/iris/shadow/ShadowMatrices.java | 20 +- .../frustum/CullEverythingFrustum.java | 8 +- .../iris/shadows/frustum/FrustumHolder.java | 8 +- .../AdvancedShadowCullingFrustum.java | 10 +- .../frustum/fallback/BoxCullingFrustum.java | 10 +- .../frustum/fallback/NonCullingFrustum.java | 10 +- .../texture/format/LabPBRTextureFormat.java | 17 +- .../iris/texture/format/TextureFormat.java | 12 +- .../texture/format/TextureFormatLoader.java | 3 +- .../mipmap/AbstractMipmapGenerator.java | 1 + .../mipmap/ChannelMipmapGenerator.java | 30 +- .../texture/mipmap/CustomMipmapGenerator.java | 12 +- .../iris/texture/pbr/PBRAtlasTexture.java | 40 +- .../iris/texture/pbr/PBRSpriteHolder.java | 13 +- .../iris/texture/pbr/PBRTextureManager.java | 11 +- .../texture/pbr/loader/AtlasPBRLoader.java | 389 ++++++------ .../pbr/loader/PBRTextureLoaderRegistry.java | 10 +- .../texture/pbr/loader/SimplePBRLoader.java | 2 +- .../texture/util/ImageManipulationUtil.java | 5 +- .../iris/texture/util/TextureExporter.java | 15 +- .../iris/uniforms/CameraUniforms.java | 9 +- .../iris/uniforms/CapturedRenderingState.java | 4 +- .../iris/uniforms/CommonUniforms.java | 61 +- .../coderbot/iris/uniforms/FogUniforms.java | 17 +- .../uniforms/HardcodedCustomUniforms.java | 15 +- .../coderbot/iris/uniforms/IdMapUniforms.java | 19 +- .../iris/uniforms/MatrixUniforms.java | 19 +- .../iris/uniforms/ViewportUniforms.java | 9 +- .../iris/uniforms/WorldTimeUniforms.java | 5 +- .../iris/vertices/ExtendingBufferBuilder.java | 2 + .../iris/vertices/IrisTextVertexSinkImpl.java | 121 ---- .../iris/vertices/IrisVertexFormats.java | 3 + .../net/irisshaders/iris/api/v0/IrisApi.java | 11 - .../iris/api/v0/IrisTextVertexSink.java | 32 - 140 files changed, 1780 insertions(+), 4273 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/TODO.md create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/AutoClosableAbstractTexture.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/BufferBuilder.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/BufferSource.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/ByteBufferBackedInputStream.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/Camera.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/DefaultVertexFormat.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/DrawState.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/GameRenderer.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/InteractionHand.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/LevelRenderer.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/MultiBufferSource.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/NativeImage.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/PoseStack.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/RenderBuffers.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/RenderStateShard.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/RenderType.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/TextureAtlas.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/VertexBuffer.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/VertexConsumer.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/VertexFormat.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/VertexFormatElement.java delete mode 100644 src/main/java/net/coderbot/iris/gl/shader/ShaderWorkarounds.java delete mode 100644 src/main/java/net/coderbot/iris/gui/FeatureMissingErrorScreen.java delete mode 100644 src/main/java/net/coderbot/iris/gui/FileDialogUtil.java delete mode 100644 src/main/java/net/coderbot/iris/gui/GuiUtil.java delete mode 100644 src/main/java/net/coderbot/iris/gui/NavigationController.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/IrisObjectSelectionList.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java delete mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java delete mode 100644 src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java delete mode 100644 src/main/java/net/coderbot/iris/gui/option/ShaderPackSelectionButtonOption.java delete mode 100644 src/main/java/net/coderbot/iris/gui/option/ShadowDistanceOption.java delete mode 100644 src/main/java/net/coderbot/iris/gui/option/ShadowDistanceSliderButton.java delete mode 100644 src/main/java/net/coderbot/iris/gui/screen/HudHideable.java delete mode 100644 src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java delete mode 100644 src/main/java/net/coderbot/iris/rendertarget/Blaze3dRenderTargetExt.java delete mode 100644 src/main/java/net/coderbot/iris/vertices/IrisTextVertexSinkImpl.java delete mode 100644 src/main/java/net/irisshaders/iris/api/v0/IrisTextVertexSink.java diff --git a/build.gradle b/build.gradle index 6a54d13b0..c090c03ac 100644 --- a/build.gradle +++ b/build.gradle @@ -793,7 +793,7 @@ ext.java17PatchDependenciesCfg = configurations.create("java17PatchDependencies" } dependencies { - def lwjgl3ifyVersion = '1.5.0' + def lwjgl3ifyVersion = '1.5.3-pre' if (modId != 'lwjgl3ify') { java17Dependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}") } diff --git a/src/main/java/com/gtnewhorizons/angelica/TODO.md b/src/main/java/com/gtnewhorizons/angelica/TODO.md new file mode 100644 index 000000000..3c9dd3529 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/TODO.md @@ -0,0 +1,10 @@ +- [x] Frustum (Seems related to Frustrum) +- [X] NativeImage +- [ ] PoseStack +- [ ] RenderType +- [ ] MultiBufferSource.BufferSource +- [ ] VertexBuffer +- [ ] VertexConsumer +- [ ] VertextFormat +- [ ] TextureAtlas (Seems related to TextureManager) - PBR related +- [ ] GUI diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index 707c69fd7..201e0ed7c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -10,6 +10,7 @@ import com.gtnewhorizons.angelica.client.shaders.shaderpack.option.values.MutableOptionValues; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import com.gtnewhorizons.angelica.mixins.interfaces.IModelRenderer; +import lombok.Getter; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.client.Minecraft; @@ -182,6 +183,7 @@ public class Shaders { private static int eyeBrightness = 0; private static float eyeBrightnessFadeX = 0; private static float eyeBrightnessFadeY = 0; + @Getter private static float eyePosY = 0; private static float centerDepth = 0; private static float centerDepthSmooth = 0; @@ -192,6 +194,7 @@ public class Shaders { private static boolean updateChunksErrorRecorded = false; private static boolean lightmapEnabled = false; + @Getter private static boolean fogEnabled = true; public static int entityAttrib = 10; @@ -207,8 +210,8 @@ public class Shaders { public static int uniformEntityFlash = -1; public static boolean useEntityHurtFlash; - private static double[] previousCameraPosition = new double[3]; - private static double[] cameraPosition = new double[3]; + private static final double[] previousCameraPosition = new double[3]; + private static final double[] cameraPosition = new double[3]; // Shadow stuff @@ -260,39 +263,76 @@ public class Shaders { public static final int ProgramTexturedLit = 3; public static final int ProgramSkyBasic = 4; public static final int ProgramSkyTextured = 5; - public static final int ProgramTerrain = 6; - public static final int ProgramWater = 7; - public static final int ProgramEntities = 8; - public static final int ProgramSpiderEyes = 9; - public static final int ProgramHand = 10; - public static final int ProgramWeather = 11; - public static final int ProgramComposite = 12; - public static final int ProgramComposite1 = 13; - public static final int ProgramComposite2 = 14; - public static final int ProgramComposite3 = 15; - public static final int ProgramComposite4 = 16; - public static final int ProgramComposite5 = 17; - public static final int ProgramComposite6 = 18; - public static final int ProgramComposite7 = 19; - public static final int ProgramFinal = 20; - public static final int ProgramShadow = 21; - public static final int ProgramCount = 22; + public static final int ProgramClouds = 6; + public static final int ProgramTerrain = 7; + public static final int ProgramTerrainSolid = 8; + public static final int ProgramTerrainCutoutMip = 9; + public static final int ProgramTerrainCutout = 10; + public static final int ProgramDamagedBlock = 11; + public static final int ProgramWater = 12; + public static final int ProgramBlock = 13; + public static final int ProgramBeaconBeam = 14; + public static final int ProgramItem = 15; + public static final int ProgramEntities = 16; + public static final int ProgramArmorGlint = 17; + public static final int ProgramSpiderEyes = 18; + public static final int ProgramHand = 19; + public static final int ProgramWeather = 20; + public static final int ProgramComposite = 21; + public static final int ProgramComposite1 = 22; + public static final int ProgramComposite2 = 23; + public static final int ProgramComposite3 = 24; + public static final int ProgramComposite4 = 25; + public static final int ProgramComposite5 = 26; + public static final int ProgramComposite6 = 27; + public static final int ProgramComposite7 = 28; + public static final int ProgramFinal = 29; + public static final int ProgramShadow = 30; + public static final int ProgramShadowSolid = 31; + public static final int ProgramShadowCutout = 32; + public static final int ProgramDeferred = 33; + public static final int ProgramDeferred1 = 34; + public static final int ProgramDeferred2 = 35; + public static final int ProgramDeferred3 = 36; + public static final int ProgramDeferred4 = 37; + public static final int ProgramDeferred5 = 38; + public static final int ProgramDeferred6 = 39; + public static final int ProgramDeferred7 = 40; + public static final int ProgramHandWater = 41; + public static final int ProgramDeferredLast = 42; + public static final int ProgramCompositeLast = 43; + public static final int ProgramCount = 44; public static final int MaxCompositePasses = 8; + public static final int MaxDeferredPasses = 8; private static final String[] programNames = new String[] { "", "gbuffers_basic", "gbuffers_textured", - "gbuffers_textured_lit", "gbuffers_skybasic", "gbuffers_skytextured", "gbuffers_terrain", "gbuffers_water", - "gbuffers_entities", "gbuffers_spidereyes", "gbuffers_hand", "gbuffers_weather", "composite", "composite1", - "composite2", "composite3", "composite4", "composite5", "composite6", "composite7", "final", "shadow", }; - - private static final int[] programBackups = new int[] { ProgramNone, // none + "gbuffers_textured_lit", "gbuffers_skybasic", "gbuffers_skytextured", "gbuffers_clouds", "gbuffers_terrain", + "gbuffers_terrain_solid", "gbuffers_terrain_cutout_mip", "gbuffers_terrain_cutout", "gbuffers_damagedblock", "gbuffers_water", + "gbuffers_block", "gbuffers_beaconbeam", "gbuffers_item", "gbuffers_entities", "gbuffers_armor_glint", "gbuffers_spidereyes", + "gbuffers_hand", "gbuffers_weather", "composite", "composite1", "composite2", "composite3", "composite4", "composite5", + "composite6", "composite7", "final", "shadow", "shadow_solid", "shadow_cutout", "deferred", "deferred1", "deferred2", "deferred3", + "deferred4", "deferred5", "deferred6", "deferred7", "gbuffers_hand_water", "deferred_last", "composite_last" + }; + + private static final int[] programBackups = new int[] { + ProgramNone, // none ProgramNone, // basic ProgramBasic, // textured ProgramTextured, // textured/lit ProgramBasic, // skybasic ProgramTextured, // skytextured + ProgramTextured, // clouds ProgramTexturedLit, // terrain + ProgramTerrain, // terrain solid + ProgramTerrain, // terrain solid cutout mip + ProgramTerrain, // terrain solid cutout + ProgramTerrain, // block damage ProgramTerrain, // water + ProgramTerrain, // block + ProgramTextured, // beacon beam + ProgramTexturedLit, // item ProgramTexturedLit, // entities + ProgramTextured, // armor glint ProgramTextured, // spidereyes ProgramTexturedLit, // hand ProgramTexturedLit, // weather @@ -306,6 +346,20 @@ public class Shaders { ProgramNone, // composite7 ProgramNone, // final ProgramNone, // shadow + ProgramShadow, // shadow solid + ProgramShadow, // shadow solid cutout + ProgramNone, // deferred + ProgramNone, // deferred1 + ProgramNone, // deferred2 + ProgramNone, // deferred3 + ProgramNone, // deferred4 + ProgramNone, // deferred5 + ProgramNone, // deferred6 + ProgramNone, // deferred7 + ProgramHand, // hand water + ProgramNone, // deferred last + ProgramNone, // composite last + }; private static final int[] programsID = new int[ProgramCount]; @@ -388,6 +442,10 @@ public class Shaders { public static float sunPathRotation = 0.0f; public static float shadowAngleInterval = 0.0f; public static int fogMode = 0; + public static float fogDensity = 0; + public static float fogStart = 0; + public static float fogEnd = 0; + public static float fogColorR, fogColorG, fogColorB; public static float shadowIntervalSize = 2.0f; public static int terrainIconSize = 16; @@ -1396,11 +1454,19 @@ public static void useProgram(int program) { case ProgramTexturedLit: case ProgramSkyBasic: case ProgramSkyTextured: + case ProgramClouds: case ProgramTerrain: + case ProgramTerrainSolid: + case ProgramTerrainCutoutMip: + case ProgramTerrainCutout: + case ProgramDamagedBlock: case ProgramWater: + case ProgramBlock: case ProgramEntities: + case ProgramSpiderEyes: case ProgramHand: case ProgramWeather: + case ProgramHandWater: normalMapEnabled = true; setProgramUniform1i("texture", 0); setProgramUniform1i("lightmap", 1); @@ -1426,6 +1492,16 @@ public static void useProgram(int program) { case ProgramComposite6: case ProgramComposite7: case ProgramFinal: + case ProgramDeferred: + case ProgramDeferred1: + case ProgramDeferred2: + case ProgramDeferred3: + case ProgramDeferred4: + case ProgramDeferred5: + case ProgramDeferred6: + case ProgramDeferred7: + case ProgramDeferredLast: + case ProgramCompositeLast: normalMapEnabled = false; setProgramUniform1i("gcolor", 0); setProgramUniform1i("gdepth", 1); @@ -1457,6 +1533,8 @@ public static void useProgram(int program) { setProgramUniform1i("noisetex", 15); break; case ProgramShadow: + case ProgramShadowSolid: + case ProgramShadowCutout: setProgramUniform1i("tex", 0); setProgramUniform1i("texture", 0); setProgramUniform1i("lightmap", 1); @@ -1505,16 +1583,8 @@ public static void useProgram(int program) { setProgramUniform3f("sunPosition", sunPosition[0], sunPosition[1], sunPosition[2]); setProgramUniform3f("moonPosition", moonPosition[0], moonPosition[1], moonPosition[2]); setProgramUniform3f("upPosition", upPosition[0], upPosition[1], upPosition[2]); - setProgramUniform3f( - "previousCameraPosition", - (float) previousCameraPosition[0], - (float) previousCameraPosition[1], - (float) previousCameraPosition[2]); - setProgramUniform3f( - "cameraPosition", - (float) cameraPosition[0], - (float) cameraPosition[1], - (float) cameraPosition[2]); + setProgramUniform3f("previousCameraPosition", (float) previousCameraPosition[0], (float) previousCameraPosition[1], (float) previousCameraPosition[2]); + setProgramUniform3f("cameraPosition", (float) cameraPosition[0], (float) cameraPosition[1], (float) cameraPosition[2]); setProgramUniformMatrix4ARB("gbufferModelView", false, modelView); setProgramUniformMatrix4ARB("gbufferModelViewInverse", false, modelViewInverse); setProgramUniformMatrix4ARB("gbufferPreviousProjection", false, previousProjection); @@ -1742,12 +1812,7 @@ private static void setupFrameBuffer() { GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_DEPTH_COMPONENT, renderWidth, renderHeight, 0, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (ByteBuffer) null); } - glFramebufferTexture2DEXT( - GL_FRAMEBUFFER_EXT, - GL_DEPTH_ATTACHMENT_EXT, - GL11.GL_TEXTURE_2D, - dfbDepthTextures.get(0), - 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, dfbDepthTextures.get(0), 0); GL20.glDrawBuffers(dfbDrawBuffers); GL11.glReadBuffer(GL11.GL_NONE); checkGLError("FT d"); @@ -2359,13 +2424,24 @@ public static void drawComposite() { GL11.glEnd(); } + public static void renderDeferred() { + checkGLError("pre-renderDeferred"); + renderComposites(ProgramDeferred, 8, false); + //OF: mc.getTextureManager().bindTexture(TextureMap.locationBlocksTexture); + } + public static void renderCompositeFinal() { + checkGLError("pre-renderCompositeFinal"); + renderComposites(ProgramComposite, 8, true); + } + + public static void renderComposites(int programBase, int programCount, boolean renderFinal) { if (isShadowPass) { // useProgram(ProgramNone); return; } - checkGLError("pre-renderCompositeFinal"); + GL11.glPushMatrix(); GL11.glLoadIdentity(); GL11.glMatrixMode(GL11.GL_PROJECTION); @@ -2438,12 +2514,7 @@ public static void renderCompositeFinal() { GL13.glActiveTexture(GL13.GL_TEXTURE0); // set depth buffer - glFramebufferTexture2DEXT( - GL_FRAMEBUFFER_EXT, - GL_DEPTH_ATTACHMENT_EXT, - GL11.GL_TEXTURE_2D, - dfbDepthTextures.get(0), - 0); + glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, dfbDepthTextures.get(0), 0); // detach depth buffer // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, 0, 0); @@ -2451,10 +2522,10 @@ public static void renderCompositeFinal() { GL20.glDrawBuffers(dfbDrawBuffers); checkGLError("pre-composite"); - for (int i = 0; i < MaxCompositePasses; ++i) { - if (programsID[ProgramComposite + i] != 0) { - useProgram(ProgramComposite + i); - checkGLError(programNames[ProgramComposite + i]); + for (int i = 0; i < programCount; ++i) { + if (programsID[programBase + i] != 0) { + useProgram(programBase + i); + checkGLError(programNames[programBase + i]); if (activeCompositeMipmapSetting != 0) genCompositeMipmap(); drawComposite(); } @@ -2463,11 +2534,32 @@ public static void renderCompositeFinal() { // reattach depth buffer // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, dfbDepthTexture, 0); + // final + if(renderFinal) { + renderFinal(); + } + + isCompositeRendered = true; + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glEnable(GL11.GL_BLEND); + GL11.glDepthFunc(GL11.GL_LEQUAL); + GL11.glDepthMask(true); + + // GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glPopMatrix(); + GL11.glMatrixMode(GL11.GL_MODELVIEW); + GL11.glPopMatrix(); + + useProgram(ProgramNone); + } + + private static void renderFinal() { // final render target isRenderingDfb = false; + mc.getFramebuffer().bindFramebuffer(true); // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // GL11.glViewport(0, 0, mc.displayWidth, mc.displayHeight); - mc.getFramebuffer().bindFramebuffer(true); if (EntityRenderer.anaglyphEnable) { boolean maskR = (EntityRenderer.anaglyphField != 0); GL11.glColorMask(maskR, !maskR, !maskR, true); @@ -2483,7 +2575,6 @@ public static void renderCompositeFinal() { GL11.glDepthFunc(GL11.GL_ALWAYS); GL11.glDepthMask(false); - // final checkGLError("pre-final"); useProgram(ProgramFinal); checkGLError("final"); @@ -2497,21 +2588,9 @@ public static void renderCompositeFinal() { // end checkGLError("renderCompositeFinal"); - isCompositeRendered = true; - GL11.glEnable(GL11.GL_TEXTURE_2D); - GL11.glEnable(GL11.GL_ALPHA_TEST); - GL11.glEnable(GL11.GL_BLEND); - GL11.glDepthFunc(GL11.GL_LEQUAL); - GL11.glDepthMask(true); - - // GL11.glMatrixMode(GL11.GL_PROJECTION); - GL11.glPopMatrix(); - GL11.glMatrixMode(GL11.GL_MODELVIEW); - GL11.glPopMatrix(); - - useProgram(ProgramNone); } + public static void endRender() { if (isShadowPass) { // useProgram(ProgramNone); @@ -3022,6 +3101,21 @@ public static void sglFogi(int pname, int param) { } } + public static void sglFogf(int pname, float param) { + GL11.glFogf(pname, param); + switch (pname) { + case GL11.GL_FOG_DENSITY: + fogDensity = param; + break; + case GL11.GL_FOG_START: + fogStart = param; + break; + case GL11.GL_FOG_END: + fogEnd = param; + break; + } + } + public static void enableLightmap() { lightmapEnabled = true; if (activeProgram == ProgramTextured) { @@ -3070,6 +3164,9 @@ public static void pushEntity(int data0) { } public static void pushEntity(Block block) { + final int metadata = 0; + // BlockAliases.getMappedBlockId + final int blockId = Block.blockRegistry.getIDForObject(block); entityDataIndex++; entityData[entityDataIndex * 2] = (Block.blockRegistry.getIDForObject(block) & 0xFFFF) | (block.getRenderType() << 16); @@ -3077,6 +3174,9 @@ public static void pushEntity(Block block) { } public static void pushEntity(RenderBlocks rb, Block block, int x, int y, int z) { + final int metadata = rb.blockAccess.getBlockMetadata(x, y, z); + // BlockAliases.getMappedBlockId( + final int blockId = Block.blockRegistry.getIDForObject(block); entityDataIndex++; entityData[entityDataIndex * 2] = (Block.blockRegistry.getIDForObject(block) & 0xFFFF) | (block.getRenderType() << 16); diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java index d501a1529..4074f81dd 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java @@ -1,18 +1,6 @@ package com.gtnewhorizons.angelica.client; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.IntBuffer; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import javax.imageio.ImageIO; - +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.DynamicTexture; @@ -26,13 +14,22 @@ import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResourceManager; import net.minecraft.util.ResourceLocation; - import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL13; -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; public class ShadersTex { @@ -211,16 +208,8 @@ public static void allocTexStorage(int width, int height, int maxLevel) { Shaders.checkGLError("pre allocTexStorage"); int level; for (level = 0; (width >> level) > 0 && (height >> level) > 0 /* && level<=maxLevel */; ++level) { - GL11.glTexImage2D( - GL11.GL_TEXTURE_2D, - level, - GL11.GL_RGBA, - (width >> level), - (height >> level), - 0, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - (IntBuffer) null); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, level, GL11.GL_RGBA, (width >> level), (height >> level), 0, + GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (IntBuffer) null); } GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, level - 1); Shaders.checkGLError("allocTexStorage"); @@ -280,13 +269,7 @@ public static ITextureObject createDefaultTexture() { // for TextureMap public static void allocateTextureMap(int texID, int mipmapLevels, int width, int height, float anisotropy, Stitcher stitcher, TextureMap tex) { - AngelicaTweaker.LOGGER.trace( - "allocateTextureMap {} {} {} {} {}", - tex.getTextureType(), - mipmapLevels, - width, - height, - anisotropy); + AngelicaTweaker.LOGGER.trace("allocateTextureMap {} {} {} {} {}", tex.getTextureType(), mipmapLevels, width, height, anisotropy); updatingTextureMap = tex; tex.angelica$atlasWidth = width; tex.angelica$atlasHeight = height; @@ -383,11 +366,7 @@ public static int[][] genMipmapsSimple(int maxLevel, int width, int[][] data) { for (y = 0; y < cw; ++y) { for (x = 0; x < cw; ++x) { int ppos = y * 2 * pw + x * 2; - aintc[y * cw + x] = blend4Simple( - aintp[ppos], - aintp[ppos + 1], - aintp[ppos + pw], - aintp[ppos + pw + 1]); + aintc[y * cw + x] = blend4Simple(aintp[ppos], aintp[ppos + 1], aintp[ppos + pw], aintp[ppos + pw + 1]); } } } @@ -575,16 +554,7 @@ public static void updateSubImage1(int[] src, int width, int height, int posX, i int lsize = lw * lh; intBuf.clear(); intBuf.put(aint, offset, lsize).position(0).limit(lsize); - GL11.glTexSubImage2D( - GL11.GL_TEXTURE_2D, - level, - px, - py, - lw, - lh, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - intBuf); + GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, level, px, py, lw, lh, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); offset += lsize; lw /= 2; lh /= 2; @@ -616,16 +586,7 @@ public static void updateSubImage1(int[][] src, int width, int height, int posX, int lsize = lw * lh; intBuf.clear(); intBuf.put(src[level], 0 /* offset */, lsize).position(0).limit(lsize); - GL11.glTexSubImage2D( - GL11.GL_TEXTURE_2D, - level, - px, - py, - lw, - lh, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - intBuf); + GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, level, px, py, lw, lh, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); // offset += lsize; lw /= 2; lh /= 2; @@ -697,16 +658,7 @@ public static void setupTexture(MultiTexID multiTex, int[] src, int width, int h intBuf.clear(); intBuf.put(src, 0, size).position(0).limit(size); GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); - GL11.glTexImage2D( - GL11.GL_TEXTURE_2D, - 0, - GL11.GL_RGBA, - width, - height, - 0, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - intBuf); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mmfilter); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, mmfilter); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wraptype); @@ -714,16 +666,7 @@ public static void setupTexture(MultiTexID multiTex, int[] src, int width, int h // intBuf.put(src, size, size).position(0).limit(size); GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - GL11.glTexImage2D( - GL11.GL_TEXTURE_2D, - 0, - GL11.GL_RGBA, - width, - height, - 0, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - intBuf); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mmfilter); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, mmfilter); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wraptype); @@ -731,16 +674,7 @@ public static void setupTexture(MultiTexID multiTex, int[] src, int width, int h // intBuf.put(src, size * 2, size).position(0).limit(size); GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); - GL11.glTexImage2D( - GL11.GL_TEXTURE_2D, - 0, - GL11.GL_RGBA, - width, - height, - 0, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - intBuf); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mmfilter); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, mmfilter); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wraptype); @@ -763,16 +697,7 @@ public static void updateSubImage(MultiTexID multiTex, int[] src, int width, int GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexSubImage2D( - GL11.GL_TEXTURE_2D, - 0, - posX, - posY, - width, - height, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - intBuf); + GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, posX, posY, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); if (src.length == size * 3) { intBuf.clear(); intBuf.put(src, size, size).position(0); @@ -783,16 +708,7 @@ public static void updateSubImage(MultiTexID multiTex, int[] src, int width, int GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexSubImage2D( - GL11.GL_TEXTURE_2D, - 0, - posX, - posY, - width, - height, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - intBuf); + GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, posX, posY, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); if (src.length == size * 3) { intBuf.clear(); intBuf.put(src, size * 2, size); @@ -803,16 +719,7 @@ public static void updateSubImage(MultiTexID multiTex, int[] src, int width, int GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexSubImage2D( - GL11.GL_TEXTURE_2D, - 0, - posX, - posY, - width, - height, - GL12.GL_BGRA, - GL12.GL_UNSIGNED_INT_8_8_8_8_REV, - intBuf); + GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, posX, posY, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); GL13.glActiveTexture(GL13.GL_TEXTURE0); } @@ -825,26 +732,13 @@ public static ResourceLocation getNSMapLocation(ResourceLocation location, Strin public static void loadNSMap(IResourceManager manager, ResourceLocation location, int width, int height, int[] aint) { - if (Shaders.configNormalMap) ShadersTex.loadNSMap1( - manager, - getNSMapLocation(location, "n"), - width, - height, - aint, - width * height, - defNormTexColor); - if (Shaders.configSpecularMap) ShadersTex.loadNSMap1( - manager, - getNSMapLocation(location, "s"), - width, - height, - aint, - width * height * 2, - defSpecTexColor); - } - - public static void loadNSMap1(IResourceManager manager, ResourceLocation location, int width, int height, - int[] aint, int offset, int defaultColor) { + if (Shaders.configNormalMap) + ShadersTex.loadNSMap1(manager, getNSMapLocation(location, "n"), width, height, aint, width * height, defNormTexColor); + if (Shaders.configSpecularMap) + ShadersTex.loadNSMap1(manager, getNSMapLocation(location, "s"), width, height, aint, width * height * 2, defSpecTexColor); + } + + public static void loadNSMap1(IResourceManager manager, ResourceLocation location, int width, int height, int[] aint, int offset, int defaultColor) { boolean good = false; try { IResource res = manager.getResource(location); @@ -933,35 +827,17 @@ public static void updateTextureMinMagFilter() { MultiTexID multiTex = texObj.angelica$getMultiTexID(); // base texture GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); - GL11.glTexParameteri( - GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MIN_FILTER, - Shaders.texMinFilValue[Shaders.configTexMinFilB]); - GL11.glTexParameteri( - GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MAG_FILTER, - Shaders.texMagFilValue[Shaders.configTexMagFilB]); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilB]); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilB]); // norm texture GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - GL11.glTexParameteri( - GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MIN_FILTER, - Shaders.texMinFilValue[Shaders.configTexMinFilN]); - GL11.glTexParameteri( - GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MAG_FILTER, - Shaders.texMagFilValue[Shaders.configTexMagFilN]); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilN]); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilN]); // spec texture GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); - GL11.glTexParameteri( - GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MIN_FILTER, - Shaders.texMinFilValue[Shaders.configTexMinFilS]); - GL11.glTexParameteri( - GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MAG_FILTER, - Shaders.texMagFilValue[Shaders.configTexMagFilS]); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilS]); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilS]); GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/TextureAtlasSpriteAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/TextureAtlasSpriteAccessor.java index d5a0cdcb5..2e436563c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/TextureAtlasSpriteAccessor.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/TextureAtlasSpriteAccessor.java @@ -31,7 +31,8 @@ public interface TextureAtlasSpriteAccessor { @Accessor("tickCounter") void setSubFrame(int subFrame); -// + + // // @Invoker("upload") // void callUpload(int frameIndex); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java index ccf6f30cc..dfe445074 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java @@ -1,7 +1,8 @@ package com.gtnewhorizons.angelica.mixins.early.renderer; -import java.nio.FloatBuffer; - +import com.gtnewhorizon.mixinextras.injector.ModifyExpressionValue; +import com.gtnewhorizons.angelica.client.Shaders; +import com.gtnewhorizons.angelica.client.ShadersRender; import net.minecraft.client.Minecraft; import net.minecraft.client.particle.EffectRenderer; import net.minecraft.client.renderer.EntityRenderer; @@ -11,7 +12,6 @@ import net.minecraft.client.renderer.culling.ICamera; import net.minecraft.client.settings.GameSettings; import net.minecraft.entity.EntityLivingBase; - import org.lwjgl.opengl.GL11; import org.spongepowered.asm.lib.Opcodes; import org.spongepowered.asm.mixin.Mixin; @@ -24,9 +24,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import com.gtnewhorizon.mixinextras.injector.ModifyExpressionValue; -import com.gtnewhorizons.angelica.client.Shaders; -import com.gtnewhorizons.angelica.client.ShadersRender; +import java.nio.FloatBuffer; @Mixin(EntityRenderer.class) public abstract class MixinEntityRenderer { @@ -39,19 +37,14 @@ public abstract class MixinEntityRenderer { // renderHand - @Inject( - method = "renderHand(FI)V", + @Inject(method = "renderHand(FI)V", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) private void angelica$applyHandDepth(CallbackInfo ci) { Shaders.applyHandDepth(); } - @Inject( - method = "renderHand(FI)V", - at = @At( - value = "FIELD", - target = "Lnet/minecraft/client/settings/GameSettings;thirdPersonView:I", - ordinal = 1), + @Inject(method = "renderHand(FI)V", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;thirdPersonView:I", ordinal = 1), cancellable = true) private void angelica$checkCompositeRendered(float p_78476_1_, int p_78476_2_, CallbackInfo ci) { if (!Shaders.isCompositeRendered) { @@ -60,11 +53,8 @@ public abstract class MixinEntityRenderer { this.disableLightmap(p_78476_1_); } - @Redirect( - method = "renderHand(FI)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/ItemRenderer;renderItemInFirstPerson(F)V")) + @Redirect(method = "renderHand(FI)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemRenderer;renderItemInFirstPerson(F)V")) private void angelica$renderItemInFirstPerson(ItemRenderer itemRenderer, float partialTicks) { ShadersRender.renderItemFP(itemRenderer, partialTicks); } @@ -97,37 +87,22 @@ public abstract class MixinEntityRenderer { Shaders.setViewport(x, y, width, height); } - @Inject( - at = @At( - remap = false, - shift = At.Shift.AFTER, - target = "Lorg/lwjgl/opengl/GL11;glClear(I)V", - value = "INVOKE"), + @Inject(at = @At(remap = false, shift = At.Shift.AFTER, target = "Lorg/lwjgl/opengl/GL11;glClear(I)V", value = "INVOKE"), method = "renderWorld(FJ)V", slice = @Slice( - from = @At( - args = "intValue=" + (GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT), - value = "CONSTANT"), + from = @At(args = "intValue=" + (GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT), value = "CONSTANT"), to = @At(args = "intValue=" + GL11.GL_CULL_FACE, ordinal = 1, value = "CONSTANT"))) private void angelica$clearRenderBuffer(CallbackInfo ci) { Shaders.clearRenderBuffer(); } - @Inject( - at = @At( - shift = At.Shift.AFTER, - target = "Lnet/minecraft/client/renderer/EntityRenderer;setupCameraTransform(FI)V", - value = "INVOKE"), + @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/EntityRenderer;setupCameraTransform(FI)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$setCamera(float p_78471_1_, long p_78471_2_, CallbackInfo ci) { Shaders.setCamera(p_78471_1_); } - @Redirect( - at = @At( - opcode = Opcodes.GETFIELD, - target = "Lnet/minecraft/client/settings/GameSettings;renderDistanceChunks:I", - value = "FIELD"), + @Redirect(at = @At(opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/settings/GameSettings;renderDistanceChunks:I", value = "FIELD"), method = "renderWorld(FJ)V") private int angelica$isShadowPass(GameSettings gameSettings) { // A better way would be replacing the if-expression completely but I don't know how. If you figure it how, @@ -136,55 +111,37 @@ public abstract class MixinEntityRenderer { return Shaders.isShadowPass ? 3 : 4; } - @Inject( - at = @At(target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(F)V", value = "INVOKE"), + @Inject(at = @At(target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(F)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$beginSky(CallbackInfo ci) { Shaders.beginSky(); } - @Inject( - at = @At( - shift = At.Shift.AFTER, - target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(F)V", - value = "INVOKE"), + @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(F)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$endSky(CallbackInfo ci) { Shaders.endSky(); } - @Redirect( - at = @At(target = "Lnet/minecraft/client/renderer/culling/Frustrum;setPosition(DDD)V", value = "INVOKE"), + @Redirect(at = @At(target = "Lnet/minecraft/client/renderer/culling/Frustrum;setPosition(DDD)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$setFrustrumPosition(Frustrum frustrum, double x, double y, double z) { ShadersRender.setFrustrumPosition(frustrum, x, y, z); } - @Redirect( - at = @At( - target = "Lnet/minecraft/client/renderer/RenderGlobal;clipRenderersByFrustum(Lnet/minecraft/client/renderer/culling/ICamera;F)V", - value = "INVOKE"), + @Redirect(at = @At(target = "Lnet/minecraft/client/renderer/RenderGlobal;clipRenderersByFrustum(Lnet/minecraft/client/renderer/culling/ICamera;F)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$clipRenderersByFrustrum(RenderGlobal renderGlobal, ICamera p_72729_1_, float p_72729_2_) { ShadersRender.clipRenderersByFrustrum(renderGlobal, (Frustrum) p_72729_1_, p_72729_2_); } - @Inject( - at = @At( - ordinal = 7, - target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", - value = "INVOKE"), + @Inject(at = @At(ordinal = 7, target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$beginUpdateChunks(CallbackInfo ci) { Shaders.beginUpdateChunks(); } - @Inject( - at = @At( - opcode = Opcodes.GETFIELD, - ordinal = 1, - target = "Lnet/minecraft/entity/EntityLivingBase;posY:D", - value = "FIELD"), + @Inject(at = @At(opcode = Opcodes.GETFIELD, ordinal = 1, target = "Lnet/minecraft/entity/EntityLivingBase;posY:D", value = "FIELD"), locals = LocalCapture.CAPTURE_FAILEXCEPTION, method = "renderWorld(FJ)V") private void angelica$endUpdateChunks(float p_78471_1_, long p_78471_2_, CallbackInfo ci, @@ -197,79 +154,49 @@ public abstract class MixinEntityRenderer { } } - @Inject( - at = @At( - ordinal = 0, - target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - value = "INVOKE"), + @Inject(at = @At(ordinal = 0, target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$beginTerrain(CallbackInfo ci) { Shaders.beginTerrain(); } - @Inject( - at = @At( - ordinal = 0, - shift = At.Shift.AFTER, - target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - value = "INVOKE"), + @Inject(at = @At(ordinal = 0, shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$endTerrain(CallbackInfo ci) { Shaders.endTerrain(); } - @Inject( - at = @At( - target = "Lnet/minecraft/client/particle/EffectRenderer;renderLitParticles(Lnet/minecraft/entity/Entity;F)V", - value = "INVOKE"), + @Inject(at = @At(target = "Lnet/minecraft/client/particle/EffectRenderer;renderLitParticles(Lnet/minecraft/entity/Entity;F)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$beginLitParticles(CallbackInfo ci) { Shaders.beginLitParticles(); } - @Inject( - at = @At( - target = "Lnet/minecraft/client/particle/EffectRenderer;renderParticles(Lnet/minecraft/entity/Entity;F)V", - value = "INVOKE"), + @Inject(at = @At(target = "Lnet/minecraft/client/particle/EffectRenderer;renderParticles(Lnet/minecraft/entity/Entity;F)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$beginParticles(CallbackInfo ci) { Shaders.beginParticles(); } - @Inject( - at = @At( - shift = At.Shift.AFTER, - target = "Lnet/minecraft/client/particle/EffectRenderer;renderParticles(Lnet/minecraft/entity/Entity;F)V", - value = "INVOKE"), + @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/particle/EffectRenderer;renderParticles(Lnet/minecraft/entity/Entity;F)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$endParticles(CallbackInfo ci) { Shaders.endParticles(); } - @Inject( - at = @At(target = "Lnet/minecraft/client/renderer/EntityRenderer;renderRainSnow(F)V", value = "INVOKE"), + @Inject(at = @At(target = "Lnet/minecraft/client/renderer/EntityRenderer;renderRainSnow(F)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$beginWeather(CallbackInfo ci) { Shaders.beginWeather(); } - @Inject( - at = @At( - shift = At.Shift.AFTER, - target = "Lnet/minecraft/client/renderer/EntityRenderer;renderRainSnow(F)V", - value = "INVOKE"), + @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/EntityRenderer;renderRainSnow(F)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$endWeather(CallbackInfo ci) { Shaders.endWeather(); } - @Inject( - at = @At( - ordinal = 1, - remap = false, - shift = At.Shift.AFTER, - target = "Lorg/lwjgl/opengl/GL11;glDepthMask(Z)V", - value = "INVOKE"), + @Inject(at = @At(ordinal = 1, remap = false, shift = At.Shift.AFTER, target = "Lorg/lwjgl/opengl/GL11;glDepthMask(Z)V", value = "INVOKE"), locals = LocalCapture.CAPTURE_FAILEXCEPTION, method = "renderWorld(FJ)V") private void angelica$renderHand0AndPreWater(float p_78471_1_, long p_78471_2_, CallbackInfo ci, @@ -279,32 +206,21 @@ public abstract class MixinEntityRenderer { Shaders.preWater(); } - @Inject( - at = @At( - target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - value = "INVOKE"), + @Inject(at = @At(target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", value = "INVOKE"), method = "renderWorld(FJ)V", slice = @Slice(from = @At(args = "stringValue=water", ordinal = 0, value = "CONSTANT"))) private void angelica$beginWater(CallbackInfo ci) { Shaders.beginWater(); } - @Inject( - at = @At( - shift = At.Shift.AFTER, - target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - value = "INVOKE"), + @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", value = "INVOKE"), method = "renderWorld(FJ)V", slice = @Slice(from = @At(args = "stringValue=water", ordinal = 0, value = "CONSTANT"))) private void angelica$endWater(CallbackInfo ci) { Shaders.endWater(); } - @Inject( - at = @At( - opcode = Opcodes.GETFIELD, - target = "Lnet/minecraft/entity/EntityLivingBase;posY:D", - value = "FIELD"), + @Inject(at = @At(opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/entity/EntityLivingBase;posY:D", value = "FIELD"), method = "renderWorld(FJ)V", slice = @Slice( from = @At(args = "stringValue=entities", value = "CONSTANT"), @@ -314,17 +230,13 @@ public abstract class MixinEntityRenderer { } @ModifyExpressionValue( - at = @At( - remap = false, - target = "Lnet/minecraftforge/client/ForgeHooksClient;renderFirstPersonHand(Lnet/minecraft/client/renderer/RenderGlobal;FI)Z", - value = "INVOKE"), + at = @At(remap = false, target = "Lnet/minecraftforge/client/ForgeHooksClient;renderFirstPersonHand(Lnet/minecraft/client/renderer/RenderGlobal;FI)Z", value = "INVOKE"), method = "renderWorld(FJ)V") private boolean angelica$isShadowPass(boolean renderFirstPersonHand) { return renderFirstPersonHand || Shaders.isShadowPass; } - @Inject( - at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glClear(I)V", value = "INVOKE"), + @Inject(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glClear(I)V", value = "INVOKE"), locals = LocalCapture.CAPTURE_FAILEXCEPTION, method = "renderWorld(FJ)V", slice = @Slice(from = @At(args = "stringValue=hand", value = "CONSTANT"))) @@ -335,19 +247,13 @@ public abstract class MixinEntityRenderer { Shaders.renderCompositeFinal(); } - @Redirect( - at = @At(target = "Lnet/minecraft/client/renderer/EntityRenderer;renderHand(FI)V", value = "INVOKE"), + @Redirect(at = @At(target = "Lnet/minecraft/client/renderer/EntityRenderer;renderHand(FI)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$renderFPOverlay(EntityRenderer thizz, float p_78476_1_, int p_78476_2_) { ShadersRender.renderFPOverlay(thizz, p_78476_1_, p_78476_2_); } - @Inject( - at = @At( - opcode = Opcodes.GETFIELD, - ordinal = 0, - target = "Lnet/minecraft/client/renderer/EntityRenderer;mc:Lnet/minecraft/client/Minecraft;", - value = "FIELD"), + @Inject(at = @At(opcode = Opcodes.GETFIELD, ordinal = 0, target = "Lnet/minecraft/client/renderer/EntityRenderer;mc:Lnet/minecraft/client/Minecraft;", value = "FIELD"), method = "renderWorld(FJ)V", slice = @Slice(from = @At(args = "stringValue=hand", value = "CONSTANT"))) private void angelica$endRender(CallbackInfo ci) { @@ -356,25 +262,19 @@ public abstract class MixinEntityRenderer { // renderCloudsCheck - @Redirect( - at = @At(target = "Lnet/minecraft/client/settings/GameSettings;shouldRenderClouds()Z", value = "INVOKE"), + @Redirect(at = @At(target = "Lnet/minecraft/client/settings/GameSettings;shouldRenderClouds()Z", value = "INVOKE"), method = "renderCloudsCheck(Lnet/minecraft/client/renderer/RenderGlobal;F)V") private boolean angelica$shouldRenderClouds(GameSettings gameSettings) { return Shaders.shouldRenderClouds(gameSettings); } - @Inject( - at = @At(target = "Lnet/minecraft/client/renderer/RenderGlobal;renderClouds(F)V", value = "INVOKE"), + @Inject(at = @At(target = "Lnet/minecraft/client/renderer/RenderGlobal;renderClouds(F)V", value = "INVOKE"), method = "renderCloudsCheck(Lnet/minecraft/client/renderer/RenderGlobal;F)V") private void angelica$beginClouds(CallbackInfo ci) { Shaders.beginClouds(); } - @Inject( - at = @At( - shift = At.Shift.AFTER, - target = "Lnet/minecraft/client/renderer/RenderGlobal;renderClouds(F)V", - value = "INVOKE"), + @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/RenderGlobal;renderClouds(F)V", value = "INVOKE"), method = "renderCloudsCheck(Lnet/minecraft/client/renderer/RenderGlobal;F)V") private void angelica$endClouds(CallbackInfo ci) { Shaders.endClouds(); @@ -382,27 +282,27 @@ public abstract class MixinEntityRenderer { // updateFogColor - @Redirect( - at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glClearColor(FFFF)V", value = "INVOKE"), - method = "updateFogColor(F)V") + @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glClearColor(FFFF)V", value = "INVOKE"), method = "updateFogColor(F)V") private void angelica$setClearColor(float red, float green, float blue, float alpha) { Shaders.setClearColor(red, green, blue, alpha); } // setupFog - @Redirect( - at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glFogi(II)V", value = "INVOKE"), - method = "setupFog(IF)V") + @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glFogi(II)V", value = "INVOKE"), method = "setupFog(IF)V") private void angelica$sglFogi(int pname, int param) { Shaders.sglFogi(pname, param); } + @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glFogf(IF)V", value = "INVOKE"), method = "setupFog(IF)V") + private void angelica$sglFogf(int pname, float param) { + Shaders.sglFogf(pname, param); + } + // setFogColorBuffer @Inject(at = @At("HEAD"), method = "setFogColorBuffer(FFFF)Ljava/nio/FloatBuffer;") - private void angelica$setFogColor(float red, float green, float blue, float alpha, - CallbackInfoReturnable cir) { + private void angelica$setFogColor(float red, float green, float blue, float alpha, CallbackInfoReturnable cir) { Shaders.setFogColor(red, green, blue); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinInitRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinInitRenderer.java index d200b1332..fa075e274 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinInitRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinInitRenderer.java @@ -13,6 +13,7 @@ public class MixinInitRenderer { @Inject(method = "initializeTextures", at = @At("RETURN")) private static void angelica$initializeRenderer(CallbackInfo ci) { + Iris.identifyCapabilities(); GLDebug.initRenderer(); IrisRenderSystem.initRenderer(); Iris.onRenderSystemInit(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java index f27e555af..34bbb54d0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java @@ -10,8 +10,20 @@ public abstract class MixinTextureAtlasSprite { @Shadow private AnimationMetadataSection animationMetadata; + @Shadow + protected int frameCounter; + public boolean isAnimation() { return animationMetadata != null && animationMetadata.getFrameCount() > 1; } + public int getFrame() { + return frameCounter; + } + + public void callUpload(int frameIndex) {} + + public AnimationMetadataSection getMetadata() { + return animationMetadata; + } } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BatchingDebugMessageHelper.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BatchingDebugMessageHelper.java index 4f13c5200..7cdc60b66 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BatchingDebugMessageHelper.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BatchingDebugMessageHelper.java @@ -9,8 +9,7 @@ public static String getDebugMessage(DrawCallTrackingRenderBuffers drawTracker) int effectivenessTimes10 = renderTypes * 1000 / drawCalls; float effectiveness = effectivenessTimes10 / 10.0F; - return drawCalls + " draw calls / " + renderTypes + " render types = " - + effectiveness + "% effective"; + return drawCalls + " draw calls / " + renderTypes + " render types = " + effectiveness + "% effective"; } else { return "(no draw calls)"; } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java index 0fb15f232..e70df8d28 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java @@ -1,10 +1,11 @@ package net.coderbot.batchedentityrendering.impl; +import net.coderbot.iris.compat.mojang.DrawState; import java.nio.ByteBuffer; public interface BufferBuilderExt { - void setupBufferSlice(ByteBuffer buffer, BufferBuilder.DrawState drawState); + void setupBufferSlice(ByteBuffer buffer, DrawState drawState); void teardownBufferSlice(); void splitStrip(); } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java index 5b93e6ad6..503d685eb 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java @@ -1,14 +1,16 @@ package net.coderbot.batchedentityrendering.impl; +import net.coderbot.iris.compat.mojang.DrawState; +import net.coderbot.iris.compat.mojang.RenderType; import java.nio.ByteBuffer; public class BufferSegment { private final ByteBuffer slice; - private final BufferBuilder.DrawState drawState; + private final DrawState drawState; private final RenderType type; - public BufferSegment(ByteBuffer slice, BufferBuilder.DrawState drawState, RenderType type) { + public BufferSegment(ByteBuffer slice, DrawState drawState, RenderType type) { this.slice = slice; this.drawState = drawState; this.type = type; @@ -18,7 +20,7 @@ public ByteBuffer getSlice() { return slice; } - public BufferBuilder.DrawState getDrawState() { + public DrawState getDrawState() { return drawState; } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java index fed318a90..fa52f06fd 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java @@ -1,5 +1,6 @@ package net.coderbot.batchedentityrendering.impl; +import net.coderbot.iris.compat.mojang.BufferBuilder; public class BufferSegmentRenderer { private final BufferBuilder fakeBufferBuilder; @@ -24,7 +25,8 @@ public void draw(BufferSegment segment) { */ public void drawInner(BufferSegment segment) { fakeBufferBuilderExt.setupBufferSlice(segment.getSlice(), segment.getDrawState()); - BufferUploader.end(fakeBufferBuilder); + // TODO: BufferUploader +// BufferUploader.end(fakeBufferBuilder); fakeBufferBuilderExt.teardownBufferSlice(); } } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java index 3d7318266..034ff7dbd 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java @@ -2,6 +2,10 @@ import net.coderbot.batchedentityrendering.impl.ordering.GraphTranslucencyRenderOrderManager; import net.coderbot.batchedentityrendering.impl.ordering.RenderOrderManager; +import net.coderbot.iris.compat.mojang.BufferBuilder; +import net.coderbot.iris.compat.mojang.BufferSource; +import net.coderbot.iris.compat.mojang.RenderType; +import net.coderbot.iris.compat.mojang.VertexConsumer; import net.coderbot.iris.fantastic.WrappingMultiBufferSource; import net.minecraft.client.Minecraft; import net.minecraft.profiler.Profiler; @@ -15,7 +19,7 @@ import java.util.Map; import java.util.function.Function; -public class FullyBufferedMultiBufferSource extends MultiBufferSource.BufferSource implements MemoryTrackingBuffer, Groupable, WrappingMultiBufferSource { +public class FullyBufferedMultiBufferSource extends BufferSource implements MemoryTrackingBuffer, Groupable, WrappingMultiBufferSource { private static final int NUM_BUFFERS = 32; private final RenderOrderManager renderOrderManager; @@ -144,7 +148,7 @@ public void endBatch(RenderType type) { // Disable explicit flushing } - public MultiBufferSource.BufferSource getUnflushableWrapper() { + public BufferSource getUnflushableWrapper() { return unflushableWrapper; } @@ -213,7 +217,7 @@ public void assertWrapStackEmpty() { /** * A wrapper that prevents callers from explicitly flushing anything. */ - private static class UnflushableWrapper extends MultiBufferSource.BufferSource implements Groupable { + private static class UnflushableWrapper extends BufferSource implements Groupable { private final FullyBufferedMultiBufferSource wrapped; UnflushableWrapper(FullyBufferedMultiBufferSource wrapped) { diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java index 908a16e2a..6faf177f4 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java @@ -2,6 +2,10 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import net.coderbot.iris.compat.mojang.BufferBuilder; +import net.coderbot.iris.compat.mojang.BufferSource; +import net.coderbot.iris.compat.mojang.RenderType; +import net.coderbot.iris.compat.mojang.VertexConsumer; import java.util.ArrayList; import java.util.Collections; @@ -12,7 +16,7 @@ import java.util.Map; import java.util.Set; -public class OldFullyBufferedMultiBufferSource extends MultiBufferSource.BufferSource { +public class OldFullyBufferedMultiBufferSource extends BufferSource { private final Map bufferBuilders; private final Object2IntMap unused; private final Set activeBuffers; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java index 9b29a0959..d30d9ebe3 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java @@ -1,5 +1,6 @@ package net.coderbot.batchedentityrendering.impl; +import net.coderbot.iris.compat.mojang.RenderType; import org.lwjgl.opengl.GL11; public class RenderTypeUtil { diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java b/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java index fa355375e..0164977e5 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java @@ -1,5 +1,11 @@ package net.coderbot.batchedentityrendering.impl; +import net.coderbot.iris.compat.mojang.BufferBuilder; +import net.coderbot.iris.compat.mojang.DrawState; +import net.coderbot.iris.compat.mojang.MultiBufferSource; +import net.coderbot.iris.compat.mojang.RenderType; +import net.coderbot.iris.compat.mojang.VertexConsumer; +import org.apache.commons.lang3.tuple.Pair; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -65,10 +71,10 @@ public List getSegments() { List segments = new ArrayList<>(usedTypes.size()); for (RenderType type : usedTypes) { - Pair pair = buffer.popNextBuffer(); + Pair pair = buffer.popNextBuffer(); - BufferBuilder.DrawState drawState = pair.getFirst(); - ByteBuffer slice = pair.getSecond(); + DrawState drawState = pair.getLeft(); + ByteBuffer slice = pair.getRight(); segments.add(new BufferSegment(slice, drawState, type)); } @@ -79,7 +85,7 @@ public List getSegments() { } private static boolean shouldSortOnUpload(RenderType type) { - return ((RenderTypeAccessor) type).shouldSortOnUpload(); + return type.shouldSortOnUpload(); } @Override diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java b/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java index 0392ef8b3..d33e69c4e 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java @@ -1,5 +1,7 @@ package net.coderbot.batchedentityrendering.impl; +import net.coderbot.iris.compat.mojang.RenderType; + public interface WrappableRenderType { /** * Returns the underlying wrapped RenderType. Might return itself if this RenderType doesn't wrap anything. diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java index b8172b770..b8ea53e31 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java @@ -10,6 +10,7 @@ import net.coderbot.batchedentityrendering.impl.BlendingStateHolder; import net.coderbot.batchedentityrendering.impl.TransparencyType; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; +import net.coderbot.iris.compat.mojang.RenderType; import java.util.ArrayList; import java.util.EnumMap; @@ -37,8 +38,8 @@ private static TransparencyType getTransparencyType(RenderType type) { type = ((WrappableRenderType) type).unwrap(); } - if (type instanceof BlendingStateHolder) { - return ((BlendingStateHolder) type).getTransparencyType(); + if (type instanceof BlendingStateHolder blendingState) { + return blendingState.getTransparencyType(); } // Default to "generally transparent" if we can't figure it out. diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java index 6e6c6407d..590bdd40a 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl.ordering; -import net.minecraft.client.renderer.RenderType; +import net.coderbot.iris.compat.mojang.RenderType; public interface RenderOrderManager { void begin(RenderType type); diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java index 43d36888b..25f18c4c7 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java @@ -1,5 +1,6 @@ package net.coderbot.batchedentityrendering.impl.ordering; +import net.coderbot.iris.compat.mojang.RenderType; import java.util.LinkedHashSet; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java index 18def0b43..75ac1f2d2 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java @@ -3,6 +3,7 @@ import net.coderbot.batchedentityrendering.impl.BlendingStateHolder; import net.coderbot.batchedentityrendering.impl.TransparencyType; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; +import net.coderbot.iris.compat.mojang.RenderType; import java.util.ArrayList; import java.util.EnumMap; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java index 05e3253a4..89677eea7 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java @@ -1,6 +1,7 @@ package net.coderbot.batchedentityrendering.impl.wrappers; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; +import net.coderbot.iris.compat.mojang.RenderType; import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -61,6 +62,8 @@ public String toString() { } private static boolean shouldSortOnUpload(RenderType type) { - return ((RenderTypeAccessor) type).shouldSortOnUpload(); + return true; + // TODO: Iris +// return ((RenderTypeAccessor) type).shouldSortOnUpload(); } } diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index c48d7fcb5..e7d75d7ee 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -146,7 +146,9 @@ public void onEarlyInitialize() { // public void onKeyInput(InputEvent.KeyInputEvent event) { // handleKeybinds(Minecraft.getMinecraft()); // } - + public static void identifyCapabilities() { + capabilities = GLContext.getCapabilities(); + } /** * Called once RenderSystem#initRenderer has completed. This means that we can safely access OpenGL. */ @@ -156,7 +158,6 @@ public static void onRenderSystemInit() { + " Trying to avoid a crash but this is an odd state."); return; } - capabilities = GLContext.getCapabilities(); setDebug(irisConfig.areDebugOptionsEnabled()); diff --git a/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java b/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java index b716db439..81bd0e8e3 100644 --- a/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java +++ b/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java @@ -1,17 +1,11 @@ package net.coderbot.iris.apiimpl; import net.coderbot.iris.Iris; -import net.coderbot.iris.gui.screen.ShaderPackScreen; import net.coderbot.iris.pipeline.FixedFunctionWorldRenderingPipeline; import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.coderbot.iris.shadows.ShadowRenderingState; -import net.coderbot.iris.vertices.IrisTextVertexSinkImpl; import net.irisshaders.iris.api.v0.IrisApi; import net.irisshaders.iris.api.v0.IrisApiConfig; -import net.irisshaders.iris.api.v0.IrisTextVertexSink; - -import java.nio.ByteBuffer; -import java.util.function.IntFunction; public class IrisApiV0Impl implements IrisApi { public static final IrisApiV0Impl INSTANCE = new IrisApiV0Impl(); @@ -40,7 +34,9 @@ public boolean isRenderingShadowPass() { @Override public Object openMainIrisScreenObj(Object parent) { - return new ShaderPackScreen((Screen) parent); + return new Object(); + // TODO: GUI +// return new ShaderPackScreen((GuiScreen) parent); } @Override @@ -52,9 +48,4 @@ public String getMainScreenLanguageKey() { public IrisApiConfig getConfig() { return CONFIG; } - - @Override - public IrisTextVertexSink createTextVertexSink(int maxQuadCount, IntFunction bufferProvider) { - return new IrisTextVertexSinkImpl(maxQuadCount, bufferProvider); - } } diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java index 018a134aa..9b04c5a86 100644 --- a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java @@ -4,26 +4,26 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import net.coderbot.iris.Iris; +import net.coderbot.iris.compat.mojang.RenderType; import net.coderbot.iris.shaderpack.materialmap.BlockEntry; import net.coderbot.iris.shaderpack.materialmap.BlockRenderType; import net.coderbot.iris.shaderpack.materialmap.NamespacedId; import net.minecraft.block.Block; import net.minecraft.util.ResourceLocation; -import java.util.HashMap; import java.util.List; import java.util.Map; public class BlockMaterialMapping { - public static Object2IntMap createBlockStateIdMap(Int2ObjectMap> blockPropertiesMap) { - Object2IntMap blockStateIds = new Object2IntOpenHashMap<>(); + public static Object2IntMap createBlockStateIdMap(Int2ObjectMap> blockPropertiesMap) { + Object2IntMap blockStateIds = new Object2IntOpenHashMap<>(); - blockPropertiesMap.forEach((intId, entries) -> { - for (BlockEntry entry : entries) { - addBlockStates(entry, blockStateIds, intId); - } - }); + // TODO: BlockStateIdMap +// blockPropertiesMap.forEach((intId, entries) -> { +// for (BlockEntry entry : entries) { +// addBlockStates(entry, blockStateIds, intId); +// } +// }); return blockStateIds; } @@ -34,7 +34,7 @@ public static Map createBlockTypeMap(Map { ResourceLocation resourceLocation = new ResourceLocation(id.getNamespace(), id.getName()); - Block block = Registry.BLOCK.get(resourceLocation); + Block block = Block.getBlockFromName(resourceLocation.toString()); blockTypeIds.put(block, convertBlockToRenderType(blockType)); }); @@ -47,90 +47,93 @@ private static RenderType convertBlockToRenderType(BlockRenderType type) { return null; } - switch (type) { - case SOLID: return RenderType.solid(); - case CUTOUT: return RenderType.cutout(); - case CUTOUT_MIPPED: return RenderType.cutoutMipped(); - case TRANSLUCENT: return RenderType.translucent(); - default: return null; - } + return switch (type) { + // TODO: RenderType +// case SOLID -> RenderType.solid(); +// case CUTOUT -> RenderType.cutout(); +// case CUTOUT_MIPPED -> RenderType.cutoutMipped(); +// case TRANSLUCENT -> RenderType.translucent(); + default -> null; + }; } - private static void addBlockStates(BlockEntry entry, Object2IntMap idMap, int intId) { - NamespacedId id = entry.getId(); - ResourceLocation resourceLocation = new ResourceLocation(id.getNamespace(), id.getName()); - - Block block = Registry.BLOCK.get(resourceLocation); - - // If the block doesn't exist, by default the registry will return AIR. That probably isn't what we want. - // TODO: Assuming that Registry.BLOCK.getDefaultId() == "minecraft:air" here - if (block == Blocks.AIR) { - return; - } - - Map propertyPredicates = entry.getPropertyPredicates(); - - if (propertyPredicates.isEmpty()) { - // Just add all the states if there aren't any predicates - for (BlockState state : block.getStateDefinition().getPossibleStates()) { - // NB: Using putIfAbsent means that the first successful mapping takes precedence - // Needed for OptiFine parity: - // https://github.com/IrisShaders/Iris/issues/1327 - idMap.putIfAbsent(state, intId); - } - - return; - } - - // As a result, we first collect each key=value pair in order to determine what properties we need to filter on. - // We already get this from BlockEntry, but we convert the keys to `Property`s to ensure they exist and to avoid - // string comparisons later. - Map, String> properties = new HashMap<>(); - StateDefinition stateManager = block.getStateDefinition(); - - propertyPredicates.forEach((key, value) -> { - Property property = stateManager.getProperty(key); - - if (property == null) { - Iris.logger.warn("Error while parsing the block ID map entry for \"" + "block." + intId + "\":"); - Iris.logger.warn("- The block " + resourceLocation + " has no property with the name " + key + ", ignoring!"); - - return; - } - - properties.put(property, value); - }); - - // Once we have a list of properties and their expected values, we iterate over every possible state of this - // block and check for ones that match the filters. This isn't particularly efficient, but it works! - for (BlockState state : stateManager.getPossibleStates()) { - if (checkState(state, properties)) { - // NB: Using putIfAbsent means that the first successful mapping takes precedence - // Needed for OptiFine parity: - // https://github.com/IrisShaders/Iris/issues/1327 - idMap.putIfAbsent(state, intId); - } - } - } + // TODO: BlockStateIdMap +// private static void addBlockStates(BlockEntry entry, Object2IntMap idMap, int intId) { +// NamespacedId id = entry.getId(); +// ResourceLocation resourceLocation = new ResourceLocation(id.getNamespace(), id.getName()); +// +// Block block = Registry.BLOCK.get(resourceLocation); +// +// // If the block doesn't exist, by default the registry will return AIR. That probably isn't what we want. +// // TODO: Assuming that Registry.BLOCK.getDefaultId() == "minecraft:air" here +// if (block == Blocks.air) { +// return; +// } +// +// Map propertyPredicates = entry.getPropertyPredicates(); +// +// if (propertyPredicates.isEmpty()) { +// // Just add all the states if there aren't any predicates +// for (BlockState state : block.getStateDefinition().getPossibleStates()) { +// // NB: Using putIfAbsent means that the first successful mapping takes precedence +// // Needed for OptiFine parity: +// // https://github.com/IrisShaders/Iris/issues/1327 +// idMap.putIfAbsent(state, intId); +// } +// +// return; +// } +// +// // As a result, we first collect each key=value pair in order to determine what properties we need to filter on. +// // We already get this from BlockEntry, but we convert the keys to `Property`s to ensure they exist and to avoid +// // string comparisons later. +// Map, String> properties = new HashMap<>(); +// StateDefinition stateManager = block.getStateDefinition(); +// +// propertyPredicates.forEach((key, value) -> { +// Property property = stateManager.getProperty(key); +// +// if (property == null) { +// Iris.logger.warn("Error while parsing the block ID map entry for \"" + "block." + intId + "\":"); +// Iris.logger.warn("- The block " + resourceLocation + " has no property with the name " + key + ", ignoring!"); +// +// return; +// } +// +// properties.put(property, value); +// }); +// +// // Once we have a list of properties and their expected values, we iterate over every possible state of this +// // block and check for ones that match the filters. This isn't particularly efficient, but it works! +// for (BlockState state : stateManager.getPossibleStates()) { +// if (checkState(state, properties)) { +// // NB: Using putIfAbsent means that the first successful mapping takes precedence +// // Needed for OptiFine parity: +// // https://github.com/IrisShaders/Iris/issues/1327 +// idMap.putIfAbsent(state, intId); +// } +// } +// } // We ignore generics here, the actual types don't matter because we just convert // them to strings anyways, and the compiler checks just get in the way. // // If you're able to rewrite this function without SuppressWarnings, feel free. // But otherwise it works fine. - @SuppressWarnings({"rawtypes", "unchecked"}) - private static boolean checkState(BlockState state, Map, String> expectedValues) { - for (Map.Entry, String> condition : expectedValues.entrySet()) { - Property property = condition.getKey(); - String expectedValue = condition.getValue(); - - String actualValue = property.getName(state.getValue(property)); - - if (!expectedValue.equals(actualValue)) { - return false; - } - } - - return true; - } + // TODO: BlockStateIdMap +// @SuppressWarnings({"rawtypes", "unchecked"}) +// private static boolean checkState(BlockState state, Map, String> expectedValues) { +// for (Map.Entry, String> condition : expectedValues.entrySet()) { +// Property property = condition.getKey(); +// String expectedValue = condition.getValue(); +// +// String actualValue = property.getName(state.getValue(property)); +// +// if (!expectedValue.equals(actualValue)) { +// return false; +// } +// } +// +// return true; +// } } diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java index eb70fa299..0f91ee52b 100644 --- a/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java @@ -2,7 +2,9 @@ import it.unimi.dsi.fastutil.objects.Object2IntFunction; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.coderbot.iris.compat.mojang.RenderType; import net.coderbot.iris.shaderpack.materialmap.NamespacedId; +import net.minecraft.block.Block; import org.jetbrains.annotations.Nullable; import java.util.Map; @@ -11,7 +13,8 @@ public class BlockRenderingSettings { public static final BlockRenderingSettings INSTANCE = new BlockRenderingSettings(); private boolean reloadRequired; - private Object2IntMap blockStateIds; + // TODO: BlockStateIdMap + private Object2IntMap blockStateIds; private Map blockTypeIds; private Object2IntFunction entityIds; private float ambientOcclusionLevel; @@ -37,8 +40,9 @@ public void clearReloadRequired() { reloadRequired = false; } + // TODO: BlockStateIdMap @Nullable - public Object2IntMap getBlockStateIds() { + public Object2IntMap getBlockStateIds() { return blockStateIds; } @@ -53,7 +57,8 @@ public Object2IntFunction getEntityIds() { return entityIds; } - public void setBlockStateIds(Object2IntMap blockStateIds) { + // TODO: BlockStateIdMap + public void setBlockStateIds(Object2IntMap blockStateIds) { if (this.blockStateIds != null && this.blockStateIds.equals(blockStateIds)) { return; } diff --git a/src/main/java/net/coderbot/iris/compat/mojang/AutoClosableAbstractTexture.java b/src/main/java/net/coderbot/iris/compat/mojang/AutoClosableAbstractTexture.java new file mode 100644 index 000000000..4ffee4a24 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/AutoClosableAbstractTexture.java @@ -0,0 +1,20 @@ +package net.coderbot.iris.compat.mojang; + +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.resources.IResourceManager; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; + +public abstract class AutoClosableAbstractTexture extends AbstractTexture implements AutoCloseable { + + public abstract void load(IResourceManager manager) throws IOException; + + @Override + public void close() throws Exception {} + + // TODO: Is this needed? + public void bind() { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, getGlTextureId()); + } +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/BufferBuilder.java b/src/main/java/net/coderbot/iris/compat/mojang/BufferBuilder.java new file mode 100644 index 000000000..880cca0e8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/BufferBuilder.java @@ -0,0 +1,39 @@ +package net.coderbot.iris.compat.mojang; + +import org.apache.commons.lang3.tuple.Pair; + +import java.nio.ByteBuffer; + +public class BufferBuilder implements VertexConsumer { + int i; + + public BufferBuilder() { + this(0); + } + + public BufferBuilder(int i) { + this.i = i; + } + + public void begin(int glQuads, VertexFormat position) {} + + public void end() {} + + @Override + public VertexConsumer vertex(double d, double e, double f) { + return null; + } + + @Override + public void endVertex() { + + } + + public void sortQuads(int i, int i1, int i2) {} + + public Pair popNextBuffer() { + return null; + } + + public void clear() {} +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/BufferSource.java b/src/main/java/net/coderbot/iris/compat/mojang/BufferSource.java new file mode 100644 index 000000000..d4fd7ba73 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/BufferSource.java @@ -0,0 +1,14 @@ +package net.coderbot.iris.compat.mojang; + +import java.util.Map; + +public class BufferSource implements MultiBufferSource { + + public BufferSource(BufferBuilder bufferBuilder, Map kvMap) {} + + public VertexConsumer getBuffer(RenderType renderType) { + return null; + } + public void endBatch() {} + public void endBatch(RenderType type) {} +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/ByteBufferBackedInputStream.java b/src/main/java/net/coderbot/iris/compat/mojang/ByteBufferBackedInputStream.java new file mode 100644 index 000000000..511321021 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/ByteBufferBackedInputStream.java @@ -0,0 +1,32 @@ +package net.coderbot.iris.compat.mojang; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +public class ByteBufferBackedInputStream extends InputStream { + + ByteBuffer buf; + + public ByteBufferBackedInputStream(ByteBuffer buf) { + this.buf = buf; + } + + public int read() throws IOException { + if (!buf.hasRemaining()) { + return -1; + } + return buf.get() & 0xFF; + } + + public int read(byte[] bytes, int off, int len) + throws IOException { + if (!buf.hasRemaining()) { + return -1; + } + + len = Math.min(len, buf.remaining()); + buf.get(bytes, off, len); + return len; + } +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/Camera.java b/src/main/java/net/coderbot/iris/compat/mojang/Camera.java new file mode 100644 index 000000000..a0abb362f --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/Camera.java @@ -0,0 +1,12 @@ +package net.coderbot.iris.compat.mojang; + +public class Camera { + + public boolean isDetached() { + return true; + } + + public Object getEntity() { + return null; + } +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/DefaultVertexFormat.java b/src/main/java/net/coderbot/iris/compat/mojang/DefaultVertexFormat.java new file mode 100644 index 000000000..5c80f7aa4 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/DefaultVertexFormat.java @@ -0,0 +1,20 @@ +package net.coderbot.iris.compat.mojang; + +import com.google.common.collect.ImmutableList; +import net.coderbot.iris.compat.mojang.VertexFormatElement.Type; +import net.coderbot.iris.compat.mojang.VertexFormatElement.Usage; + +public class DefaultVertexFormat { + + public static final VertexFormatElement ELEMENT_POSITION = new VertexFormatElement(0, Type.FLOAT, Usage.POSITION, 3); + public static final VertexFormatElement ELEMENT_COLOR = new VertexFormatElement(0, Type.UBYTE, Usage.COLOR, 4); + public static final VertexFormatElement ELEMENT_UV0 = new VertexFormatElement(0, Type.FLOAT, Usage.UV, 2); + public static final VertexFormatElement ELEMENT_UV1 = new VertexFormatElement(1, Type.SHORT, Usage.UV, 2); + public static final VertexFormatElement ELEMENT_UV2 = new VertexFormatElement(2, Type.SHORT, Usage.UV, 2); + public static final VertexFormatElement ELEMENT_NORMAL = new VertexFormatElement(0, Type.BYTE, Usage.NORMAL, 3); + public static final VertexFormatElement ELEMENT_PADDING = new VertexFormatElement(0, Type.BYTE, Usage.PADDING, 1); + + public static final VertexFormat POSITION = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).build()); + public static final VertexFormat POSITION_TEX = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_UV0).build()); + +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/DrawState.java b/src/main/java/net/coderbot/iris/compat/mojang/DrawState.java new file mode 100644 index 000000000..6572c19a8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/DrawState.java @@ -0,0 +1,19 @@ +package net.coderbot.iris.compat.mojang; + +import lombok.Getter; + +public class DrawState { + @Getter + private final VertexFormat format; + @Getter + private final int vertexCount; + @Getter + private final int mode; + + public DrawState(VertexFormat format, int vertexCount, int mode) { + this.format = format; + this.vertexCount = vertexCount; + this.mode = mode; + } + +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/GameRenderer.java b/src/main/java/net/coderbot/iris/compat/mojang/GameRenderer.java new file mode 100644 index 000000000..48359fcbb --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/GameRenderer.java @@ -0,0 +1,16 @@ +package net.coderbot.iris.compat.mojang; + +public class GameRenderer { + + public void invokeBobHurt(PoseStack poseStack, float tickDelta) {} + + public void invokeBobView(PoseStack poseStack, float tickDelta) {} + + public boolean getRenderHand() { + return true; + } + + public boolean getPanoramicMode() { + return true; + } +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/InteractionHand.java b/src/main/java/net/coderbot/iris/compat/mojang/InteractionHand.java new file mode 100644 index 000000000..560312a37 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/InteractionHand.java @@ -0,0 +1,9 @@ +package net.coderbot.iris.compat.mojang; + +public enum InteractionHand { + MAIN_HAND, + OFF_HAND; + + InteractionHand() { + } +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/LevelRenderer.java b/src/main/java/net/coderbot/iris/compat/mojang/LevelRenderer.java new file mode 100644 index 000000000..fe4a77d78 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/LevelRenderer.java @@ -0,0 +1,6 @@ +package net.coderbot.iris.compat.mojang; + +public class LevelRenderer { + + public void invokeRenderChunkLayer(RenderType solid, PoseStack modelView, double cameraX, double cameraY, double cameraZ) {} +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/MultiBufferSource.java b/src/main/java/net/coderbot/iris/compat/mojang/MultiBufferSource.java new file mode 100644 index 000000000..018427031 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/MultiBufferSource.java @@ -0,0 +1,11 @@ +package net.coderbot.iris.compat.mojang; + +import java.util.Map; + +public interface MultiBufferSource { + static BufferSource immediateWithBuffers(Map map, BufferBuilder arg) { + return new BufferSource(arg, map); + } + + VertexConsumer getBuffer(RenderType arg); +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/NativeImage.java b/src/main/java/net/coderbot/iris/compat/mojang/NativeImage.java new file mode 100644 index 000000000..7bbfd6cac --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/NativeImage.java @@ -0,0 +1,120 @@ +package net.coderbot.iris.compat.mojang; + +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import lombok.Getter; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +public class NativeImage extends BufferedImage { + @Getter + private final Format format; + @Getter + private final int width; + @Getter + private final int height; + @Getter + private final int size; + + public NativeImage(int width, int height, boolean useStb) { + this(NativeImage.Format.RGBA, width, height, useStb); + } + + public NativeImage(Format format, int width, int height, boolean useStb) { + super(width, height, BufferedImage.TYPE_INT_ARGB); + this.format = format; + this.width = width; + this.height = height; + this.size = width * height * format.components; + } + public NativeImage(Format format, int width, int height, BufferedImage image) { + super(image.getColorModel(), image.getRaster(), image.isAlphaPremultiplied(), null); + this.format = format; + this.width = width; + this.height = height; + this.size = width * height * format.components; + } + + public static NativeImage read(ByteBuffer buf) throws IOException { + return read(new ByteBufferBackedInputStream(buf)); + } + public static NativeImage read(InputStream inputStream) throws IOException { + BufferedImage image = ImageIO.read(inputStream); + return new NativeImage(Format.RGBA, image.getWidth(), image.getHeight(), image); + } + + public void downloadTexture(int level, boolean bl) { +// this.checkAllocated(); + GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, format.components); +// GlStateManager._getTexImage(3553, level, format.glFormat, GL11.GL_UNSIGNED_BYTE, this.pixels); + +// final int width = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_WIDTH); +// final int height = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_HEIGHT); + IntBuffer buffer = BufferUtils.createIntBuffer(size); + int[] data = new int[size]; + + GL11.glGetTexImage(GL11.GL_TEXTURE_2D, level, format.glFormat, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, buffer); + buffer.get(data); + setRGB(0, 0, width, height, data, 0, width); + } + public void writeToFile(File file) throws IOException{ + try { + ImageIO.write(this, "png", file); + } catch(IOException ioexception) { + AngelicaTweaker.LOGGER.info("[TextureDump] Unable to write: ", ioexception); + } + } + public static int combine(int i, int j, int k, int l) { + return (i & 255) << 24 | (j & 255) << 16 | (k & 255) << 8 | (l & 255); + } + + public static int getA(int i) { + return i >> 24 & 255; + } + + public static int getR(int i) { + return i >> 0 & 255; + } + + public static int getG(int i) { + return i >> 8 & 255; + } + + public static int getB(int i) { + return i >> 16 & 255; + } + + public int getPixelRGBA(int x, int y) { + return getRGB(x, y); + } + + public void setPixelRGBA(int x, int y, int rgb) { + setRGB(x, y, rgb); + } + + + public enum Format { + RGBA(4, GL11.GL_RGBA, BufferedImage.TYPE_INT_ARGB), + RGB(3, GL11.GL_RGB, BufferedImage.TYPE_INT_RGB); + + private final int components; + private final int glFormat; + private final int imageType; + + + Format(int components, int glFormat, int imageType) { + this.components = components; + this.glFormat = glFormat; + this.imageType = imageType; + } + } + +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/PoseStack.java b/src/main/java/net/coderbot/iris/compat/mojang/PoseStack.java new file mode 100644 index 000000000..df75e025c --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/PoseStack.java @@ -0,0 +1,28 @@ +package net.coderbot.iris.compat.mojang; + +import org.joml.Matrix4f; + +public class PoseStack { + + public Pose last() { + return null; + } + + public void pushPose() {} + + public void popPose() {} + + public void translate(double v, double v1, double v2) {} + + public static final class Pose { + + public Matrix4f pose() { + return null; + } + + public Matrix4f normal() { + return null; + } + } + +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/RenderBuffers.java b/src/main/java/net/coderbot/iris/compat/mojang/RenderBuffers.java new file mode 100644 index 000000000..34f31181a --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/RenderBuffers.java @@ -0,0 +1,8 @@ +package net.coderbot.iris.compat.mojang; + +public class RenderBuffers { + + public BufferSource bufferSource() { + return null; + } +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/RenderStateShard.java b/src/main/java/net/coderbot/iris/compat/mojang/RenderStateShard.java new file mode 100644 index 000000000..c1b271e70 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/RenderStateShard.java @@ -0,0 +1,41 @@ +package net.coderbot.iris.compat.mojang; + +import javax.annotation.Nullable; + +public abstract class RenderStateShard { + protected final String name; + protected Runnable setupState; + protected final Runnable clearState; + + public RenderStateShard(String name, Runnable setupState, Runnable clearState) { + this.name = name; + this.setupState = setupState; + this.clearState = clearState; + } + + public boolean equals(@Nullable Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + final RenderStateShard lv = (RenderStateShard)object; + return this.name.equals(lv.name); + } else { + return false; + } + } + public int hashCode() { + return this.name.hashCode(); + } + + public String toString() { + return this.name; + } + + public void setupRenderState() { + this.setupState.run(); + } + + public void clearRenderState() { + this.clearState.run(); + } +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/RenderType.java b/src/main/java/net/coderbot/iris/compat/mojang/RenderType.java new file mode 100644 index 000000000..300c0d405 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/RenderType.java @@ -0,0 +1,64 @@ +package net.coderbot.iris.compat.mojang; + +import java.util.Optional; + +public abstract class RenderType { + + public RenderType(String name, VertexFormat format, int mode, int i, Object o, boolean b, Runnable setupRenderState, Runnable clearRenderState) {} + + public static RenderType solid() { + return null; + } + + public static RenderType cutout() { + return null; + } + + public static RenderType cutoutMipped() { + return null; + } + + public static RenderType translucent() { + return null; + } + + public static RenderType tripwire() { + return null; + } + + public void setupRenderState() {} + + public void clearRenderState() {} + + public int mode() { + return 1; + } + + public VertexFormat format() { + return null; + } + + public boolean shouldSortOnUpload() { + return true; + } + + public int bufferSize() { + return 0; + } + + public void end(BufferBuilder buffer, int i, int i1, int i2) {} + + public Object affectsCrumbling() { + return null; + } + + public Optional outline() { + return Optional.empty(); + } + + public boolean isOutline() { + return false; + } + + +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/TextureAtlas.java b/src/main/java/net/coderbot/iris/compat/mojang/TextureAtlas.java new file mode 100644 index 000000000..6be3dcb64 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/TextureAtlas.java @@ -0,0 +1,19 @@ +package net.coderbot.iris.compat.mojang; + +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.renderer.texture.ITickable; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.client.resources.IResourceManagerReloadListener; + +public class TextureAtlas extends AbstractTexture implements ITickable, IResourceManagerReloadListener { + + @Override + public void tick() { + + } + + @Override + public void onResourceManagerReload(IResourceManager p_110549_1_) { + + } +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/VertexBuffer.java b/src/main/java/net/coderbot/iris/compat/mojang/VertexBuffer.java new file mode 100644 index 000000000..6697e2cca --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/VertexBuffer.java @@ -0,0 +1,18 @@ +package net.coderbot.iris.compat.mojang; + +import org.joml.Matrix4f; + +public class VertexBuffer { + + public VertexBuffer(VertexFormat position) {} + + public static void unbind() {} + + public void bind() {} + + public void upload(BufferBuilder buffer) {} + + public void close() {} + + public void draw(Matrix4f matrix, int glQuads) {} +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/VertexConsumer.java b/src/main/java/net/coderbot/iris/compat/mojang/VertexConsumer.java new file mode 100644 index 000000000..c0e938963 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/VertexConsumer.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.compat.mojang; + +public interface VertexConsumer { + + VertexConsumer vertex(double d, double e, double f); + void endVertex(); +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/VertexFormat.java b/src/main/java/net/coderbot/iris/compat/mojang/VertexFormat.java new file mode 100644 index 000000000..1815b0636 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/VertexFormat.java @@ -0,0 +1,25 @@ +package net.coderbot.iris.compat.mojang; + +import com.google.common.collect.ImmutableList; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; + +public class VertexFormat { + protected final ImmutableList elements; + protected final IntList offsets = new IntArrayList(); + protected final int vertexSize; + + public VertexFormat(ImmutableList elements) { + this.elements = elements; + int i = 0; + for (VertexFormatElement element : elements) { + offsets.add(i); + i += element.getByteSize(); + } + vertexSize = i; + } + + public void setupBufferState(long l) {} + + public void clearBufferState() {} +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/VertexFormatElement.java b/src/main/java/net/coderbot/iris/compat/mojang/VertexFormatElement.java new file mode 100644 index 000000000..b7c3593c8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/VertexFormatElement.java @@ -0,0 +1,120 @@ +package net.coderbot.iris.compat.mojang; + +import lombok.Getter; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL20; + +import java.util.function.IntConsumer; + +public class VertexFormatElement { + @Getter + protected final Type type; + @Getter + protected final Usage usage; + @Getter + protected final int index; + @Getter + protected final int count; + @Getter + protected final int byteSize; + + public VertexFormatElement(int index, Type type, Usage usage, int count) { + this.index = index; + this.type = type; + this.usage = usage; + this.count = count; + this.byteSize = type.getSize() * count; + } + + public enum Usage { + POSITION("Position", (i, j, k, l, m) -> { + GL11.glVertexPointer(i, j, k, l); + GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); + }, (i) -> { + GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY); + }), + NORMAL("Normal", (i, j, k, l, m) -> { + GL11.glNormalPointer(j, k, l); + GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY); + }, (i) -> { + GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY); + }), + COLOR("Vertex Color", (i, j, k, l, m) -> { + GL11.glColorPointer(i, j, k, l); + GL11.glEnableClientState(GL11.GL_COLOR_ARRAY); + }, (i) -> { + GL11.glDisableClientState(GL11.GL_COLOR_ARRAY); + }), + UV("UV", (i, j, k, l, m) -> { + GL13.glClientActiveTexture('蓀' + m); + GL11.glTexCoordPointer(i, j, k, l); + GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + GL13.glClientActiveTexture(GL13.GL_TEXTURE0); + }, (i) -> { + GL13.glClientActiveTexture('蓀' + i); + GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + GL13.glClientActiveTexture(GL13.GL_TEXTURE0); + }), + PADDING("Padding", (i, j, k, l, m) -> { + }, (i) -> { + }), + GENERIC("Generic", (i, j, k, l, m) -> { + GL20.glEnableVertexAttribArray(m); + GL20.glVertexAttribPointer(m, i, j, false, k, l); + }, (i) -> { + // blah + GL20.glDisableVertexAttribArray(i); + }); + + private final String name; + private final SetupState setupState; + private final IntConsumer clearState; + + Usage(String name, SetupState setupState, IntConsumer clearState) { + this.name = name; + this.setupState = setupState; + this.clearState = clearState; + } + + private void setupBufferState(int i, int j, int k, long l, int m) { + this.setupState.setupBufferState(i, j, k, l, m); + } + + public void clearBufferState(int i) { + this.clearState.accept(i); + } + + public String getName() { + return this.name; + } + + + interface SetupState { + void setupBufferState(int i, int j, int k, long l, int m); + } + } + + public static enum Type { + FLOAT(4, "Float", GL11.GL_FLOAT), + UBYTE(1, "Unsigned Byte", GL11.GL_UNSIGNED_BYTE), + BYTE(1, "Byte", GL11.GL_BYTE), + USHORT(2, "Unsigned Short", GL11.GL_UNSIGNED_SHORT), + SHORT(2, "Short", GL11.GL_SHORT), + UINT(4, "Unsigned Int", GL11.GL_UNSIGNED_INT), + INT(4, "Int", GL11.GL_INT); + + @Getter + private final int size; + @Getter + private final String name; + @Getter + private final int glType; + + Type(int size, String name, int glType) { + this.size = size; + this.name = name; + this.glType = glType; + } + } +} diff --git a/src/main/java/net/coderbot/iris/config/IrisConfig.java b/src/main/java/net/coderbot/iris/config/IrisConfig.java index a9fad4fa2..df9fb21ed 100644 --- a/src/main/java/net/coderbot/iris/config/IrisConfig.java +++ b/src/main/java/net/coderbot/iris/config/IrisConfig.java @@ -1,7 +1,6 @@ package net.coderbot.iris.config; import net.coderbot.iris.Iris; -import net.coderbot.iris.gui.option.IrisVideoSettings; import java.io.IOException; import java.io.InputStream; @@ -137,13 +136,14 @@ public void load() throws IOException { enableShaders = !"false".equals(properties.getProperty("enableShaders")); enableDebugOptions = "true".equals(properties.getProperty("enableDebugOptions")); disableUpdateMessage = "true".equals(properties.getProperty("disableUpdateMessage")); - try { - IrisVideoSettings.shadowDistance = Integer.parseInt(properties.getProperty("maxShadowRenderDistance", "32")); - } catch (NumberFormatException e) { - Iris.logger.error("Shadow distance setting reset; value is invalid."); - IrisVideoSettings.shadowDistance = 32; - save(); - } + // TODO: GUI +// try { +// IrisVideoSettings.shadowDistance = Integer.parseInt(properties.getProperty("maxShadowRenderDistance", "32")); +// } catch (NumberFormatException e) { +// Iris.logger.error("Shadow distance setting reset; value is invalid."); +// IrisVideoSettings.shadowDistance = 32; +// save(); +// } if (shaderPackName != null) { if (shaderPackName.equals("(internal)") || shaderPackName.isEmpty()) { @@ -163,7 +163,8 @@ public void save() throws IOException { properties.setProperty("enableShaders", enableShaders ? "true" : "false"); properties.setProperty("enableDebugOptions", enableDebugOptions ? "true" : "false"); properties.setProperty("disableUpdateMessage", disableUpdateMessage ? "true" : "false"); - properties.setProperty("maxShadowRenderDistance", String.valueOf(IrisVideoSettings.shadowDistance)); +// properties.setProperty("maxShadowRenderDistance", String.valueOf(IrisVideoSettings.shadowDistance)); + properties.setProperty("maxShadowRenderDistance", String.valueOf(32)); // NB: This uses ISO-8859-1 with unicode escapes as the encoding try (OutputStream os = Files.newOutputStream(propertiesPath)) { properties.store(os, COMMENT); diff --git a/src/main/java/net/coderbot/iris/fantastic/IrisParticleRenderTypes.java b/src/main/java/net/coderbot/iris/fantastic/IrisParticleRenderTypes.java index 42c4502fc..1d1a146ce 100644 --- a/src/main/java/net/coderbot/iris/fantastic/IrisParticleRenderTypes.java +++ b/src/main/java/net/coderbot/iris/fantastic/IrisParticleRenderTypes.java @@ -1,24 +1,22 @@ package net.coderbot.iris.fantastic; -import net.minecraft.client.renderer.texture.TextureManager; -import org.lwjgl.opengl.GL11; - -public class IrisParticleRenderTypes { - public static final ParticleRenderType OPAQUE_TERRAIN = new ParticleRenderType() { - public void begin(BufferBuilder bufferBuilder, TextureManager textureManager) { - GL11.glDisable(GL11.GL_BLEND); - GL11.glDepthMask(true); - GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F); - textureManager.bind(TextureAtlas.LOCATION_BLOCKS); - bufferBuilder.begin(7, DefaultVertexFormat.PARTICLE); - } - - public void end(Tesselator tesselator) { - tesselator.end(); - } - - public String toString() { - return "OPAQUE_TERRAIN_SHEET"; - } - }; -} +// TODO: RenderType +//public class IrisParticleRenderTypes { +// public static final ParticleRenderType OPAQUE_TERRAIN = new ParticleRenderType() { +// public void begin(BufferBuilder bufferBuilder, TextureManager textureManager) { +// GL11.glDisable(GL11.GL_BLEND); +// GL11.glDepthMask(true); +// GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F); +// textureManager.bind(TextureAtlas.LOCATION_BLOCKS); +// bufferBuilder.begin(7, DefaultVertexFormat.PARTICLE); +// } +// +// public void end(Tesselator tesselator) { +// tesselator.end(); +// } +// +// public String toString() { +// return "OPAQUE_TERRAIN_SHEET"; +// } +// }; +//} diff --git a/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java b/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java index 34c99a14a..08bd06128 100644 --- a/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java +++ b/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java @@ -1,6 +1,6 @@ package net.coderbot.iris.fantastic; - +import net.coderbot.iris.compat.mojang.RenderType; import java.util.function.Function; public interface WrappingMultiBufferSource { diff --git a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java index f1c9f2fd6..bd5c14cc1 100644 --- a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java +++ b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java @@ -40,11 +40,7 @@ public static void initRenderer() { Iris.logger.info("DSA support not detected."); } - if (Iris.capabilities.OpenGL45 || Iris.capabilities.GL_ARB_multi_bind) { - hasMultibind = true; - } else { - hasMultibind = false; - } + hasMultibind = Iris.capabilities.OpenGL45 || Iris.capabilities.GL_ARB_multi_bind; supportsCompute = supportsCompute(); } diff --git a/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java b/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java index 973a6ff7d..f3cbdd7a6 100644 --- a/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java +++ b/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java @@ -12,21 +12,22 @@ public static boolean isDepthColorLocked() { } public static void disableDepthColor() { - if (!depthColorLocked) { - // Only save the previous state if the depth and color mask wasn't already locked - GlStateManager.ColorMask colorMask = GlStateManagerAccessor.getCOLOR_MASK(); - GlStateManager.DepthState depthState = GlStateManagerAccessor.getDEPTH(); - - originalDepthEnable = depthState.mask; - originalColor = new ColorMask(colorMask.red, colorMask.green, colorMask.blue, colorMask.alpha); - } - - depthColorLocked = false; - - GL11.glDepthMask(false); - GL11.glColorMask(false, false, false, false); - - depthColorLocked = true; + throw new RuntimeException("Iris disabled depth color"); +// if (!depthColorLocked) { +// // Only save the previous state if the depth and color mask wasn't already locked +// GlStateManager.ColorMask colorMask = GlStateManagerAccessor.getCOLOR_MASK(); +// GlStateManager.DepthState depthState = GlStateManagerAccessor.getDEPTH(); +// +// originalDepthEnable = depthState.mask; +// originalColor = new ColorMask(colorMask.red, colorMask.green, colorMask.blue, colorMask.alpha); +// } +// +// depthColorLocked = false; +// +// GL11.glDepthMask(false); +// GL11.glColorMask(false, false, false, false); +// +// depthColorLocked = true; } public static void deferDepthEnable(boolean enabled) { diff --git a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java index 9725e30b8..7f6d746e8 100644 --- a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java +++ b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java @@ -92,16 +92,16 @@ public void bindAsReadBuffer() { } public void bindAsDrawBuffer() { - OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30C.GL_DRAW_FRAMEBUFFER, getGlId()); + OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_DRAW_FRAMEBUFFER, getGlId()); } protected void destroyInternal() { - GlStateManager._glDeleteFramebuffers(getGlId()); + OpenGlHelper.func_153184_g/*glDeleteFramebuffers*/(getGlId()); } public boolean isComplete() { bind(); - int status = GlStateManager.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER); + int status = OpenGlHelper.func_153167_i/*glCheckFramebufferStatus*/(GL30.GL_FRAMEBUFFER); return status == GL30.GL_FRAMEBUFFER_COMPLETE; } diff --git a/src/main/java/net/coderbot/iris/gl/program/ProgramImages.java b/src/main/java/net/coderbot/iris/gl/program/ProgramImages.java index 23710a596..014ebd7f9 100644 --- a/src/main/java/net/coderbot/iris/gl/program/ProgramImages.java +++ b/src/main/java/net/coderbot/iris/gl/program/ProgramImages.java @@ -6,6 +6,7 @@ import net.coderbot.iris.gl.image.ImageHolder; import net.coderbot.iris.gl.image.ImageLimits; import net.coderbot.iris.gl.texture.InternalTextureFormat; +import org.lwjgl.opengl.GL20; import java.util.ArrayList; import java.util.List; @@ -59,12 +60,12 @@ private Builder(int program) { @Override public boolean hasImage(String name) { - return GlStateManager._glGetUniformLocation(program, name) != -1; + return GL20.glGetUniformLocation(program, name) != -1; } @Override public void addTextureImage(IntSupplier textureID, InternalTextureFormat internalFormat, String name) { - int location = GlStateManager._glGetUniformLocation(program, name); + int location = GL20.glGetUniformLocation(program, name); if (location == -1) { return; diff --git a/src/main/java/net/coderbot/iris/gl/shader/GlShader.java b/src/main/java/net/coderbot/iris/gl/shader/GlShader.java index c1e9126ef..9955d562d 100644 --- a/src/main/java/net/coderbot/iris/gl/shader/GlShader.java +++ b/src/main/java/net/coderbot/iris/gl/shader/GlShader.java @@ -29,7 +29,9 @@ public GlShader(ShaderType type, String name, String src) { private static int createShader(ShaderType type, String name, String src) { int handle = GL20.glCreateShader(type.id); - ShaderWorkarounds.safeShaderSource(handle, src); + // TODO: Iris +// ShaderWorkarounds.safeShaderSource(handle, src); + GL20.glShaderSource(handle, src + '\0'); GL20.glCompileShader(handle); GLDebug.nameObject(KHRDebug.GL_SHADER, handle, name + "(" + type.name().toLowerCase(Locale.ROOT) + ")"); diff --git a/src/main/java/net/coderbot/iris/gl/shader/ShaderWorkarounds.java b/src/main/java/net/coderbot/iris/gl/shader/ShaderWorkarounds.java deleted file mode 100644 index cb4f4d76f..000000000 --- a/src/main/java/net/coderbot/iris/gl/shader/ShaderWorkarounds.java +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2020 Grondag -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package net.coderbot.iris.gl.shader; - -import org.lwjgl.PointerBuffer; - -import java.nio.ByteBuffer; - -/** - * Contains a workaround for a crash in nglShaderSource on some AMD drivers. Copied from the following Canvas commit: - * https://github.com/grondag/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96 - */ -public class ShaderWorkarounds { - /** - * Identical in function to {@link GL20C#glShaderSource(int, CharSequence)} but - * passes a null pointer for string length to force the driver to rely on the null - * terminator for string length. This is a workaround for an apparent flaw with some - * AMD drivers that don't receive or interpret the length correctly, resulting in - * an access violation when the driver tries to read past the string memory. - * - *

Hat tip to fewizz for the find and the fix. - */ - public static void safeShaderSource(int glId, CharSequence source) { - final MemoryStack stack = MemoryStack.stackGet(); - final int stackPointer = stack.getPointer(); - - try { - final ByteBuffer sourceBuffer = MemoryUtil.memUTF8(source, true); - final PointerBuffer pointers = stack.mallocPointer(1); - pointers.put(sourceBuffer); - - GL20C.nglShaderSource(glId, 1, pointers.address0(), 0); - org.lwjgl.system.APIUtil.apiArrayFree(pointers.address0(), 1); - } finally { - stack.setPointer(stackPointer); - } - } -} diff --git a/src/main/java/net/coderbot/iris/gui/FeatureMissingErrorScreen.java b/src/main/java/net/coderbot/iris/gui/FeatureMissingErrorScreen.java deleted file mode 100644 index be4c7ef15..000000000 --- a/src/main/java/net/coderbot/iris/gui/FeatureMissingErrorScreen.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.coderbot.iris.gui; - - -import net.minecraft.client.gui.GuiScreen; - -public class FeatureMissingErrorScreen extends GuiScreen { - private final GuiScreen parent; - private MultiLineLabel message; - private final FormattedText messageTemp; - - public FeatureMissingErrorScreen(GuiScreen parent, Component title, Component message) { - super(title); - this.parent = parent; - this.messageTemp = message; - } - - @Override - protected void init() { - super.init(); - this.message = MultiLineLabel.create(this.font, messageTemp, this.width - 50); - this.addButton(new Button(this.width / 2 - 100, 140, 200, 20, CommonComponents.GUI_BACK, arg -> this.minecraft.setScreen(parent))); - } - - @Override - public void render(PoseStack poseStack, int mouseX, int mouseY, float delta) { - this.renderBackground(poseStack); - ErrorScreen.drawCenteredString(poseStack, this.font, this.title, this.width / 2, 90, 0xFFFFFF); - message.renderCentered(poseStack, this.width / 2, 110, 9, 0xFFFFFF); - super.render(poseStack, mouseX, mouseY, delta); - } -} diff --git a/src/main/java/net/coderbot/iris/gui/FileDialogUtil.java b/src/main/java/net/coderbot/iris/gui/FileDialogUtil.java deleted file mode 100644 index 5249346ce..000000000 --- a/src/main/java/net/coderbot/iris/gui/FileDialogUtil.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.coderbot.iris.gui; - -import org.jetbrains.annotations.Nullable; -import org.lwjgl.PointerBuffer; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * Class used to make interfacing with {@link TinyFileDialogs} easier and asynchronous. - */ -public final class FileDialogUtil { - private static final ExecutorService FILE_DIALOG_EXECUTOR = Executors.newSingleThreadExecutor(); - - private FileDialogUtil() {} - - /** - * Opens an asynchronous file select dialog window. - * - * @param dialog Whether to open a "save" dialog or an "open" dialog - * @param title The title of the dialog window - * @param origin The path that the window should start at - * @param filterLabel A label used to describe what file extensions are allowed and their purpose - * @param filters The file extension filters used by the dialog, each formatted as {@code "*.extension"} - * @return a {@link CompletableFuture} which is completed once a file is selected or the dialog is cancelled. - */ - public static CompletableFuture> fileSelectDialog(DialogType dialog, String title, @Nullable Path origin, @Nullable String filterLabel, String ... filters) { - CompletableFuture> future = new CompletableFuture<>(); - - FILE_DIALOG_EXECUTOR.submit(() -> { - String result = null; - - try (MemoryStack stack = MemoryStack.stackPush()) { - PointerBuffer filterBuffer = stack.mallocPointer(filters.length); - - for (String filter : filters) { - filterBuffer.put(stack.UTF8(filter)); - } - filterBuffer.flip(); - - String path = origin != null ? origin.toAbsolutePath().toString() : null; - - if (dialog == DialogType.SAVE) { - result = TinyFileDialogs.tinyfd_saveFileDialog(title, path, filterBuffer, filterLabel); - } else if (dialog == DialogType.OPEN) { - result = TinyFileDialogs.tinyfd_openFileDialog(title, path, filterBuffer, filterLabel, false); - } - } - - future.complete(Optional.ofNullable(result).map(Paths::get)); - }); - - return future; - } - - public enum DialogType { - SAVE, OPEN - } -} diff --git a/src/main/java/net/coderbot/iris/gui/GuiUtil.java b/src/main/java/net/coderbot/iris/gui/GuiUtil.java deleted file mode 100644 index 32bf36a19..000000000 --- a/src/main/java/net/coderbot/iris/gui/GuiUtil.java +++ /dev/null @@ -1,207 +0,0 @@ -package net.coderbot.iris.gui; - - -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.I18n; -import net.minecraft.util.ResourceLocation; - -/** - * Class serving as abstraction and - * centralization for common GUI - * rendering/other code calls. - * - * Helps allow for easier portability - * to Minecraft 1.17 by abstracting - * some code that will be changed. - */ -public final class GuiUtil { - public static final ResourceLocation IRIS_WIDGETS_TEX = new ResourceLocation("iris", "textures/gui/widgets.png"); - private static final Component ELLIPSIS = new TextComponent("..."); - - private GuiUtil() {} - - private static Minecraft client() { - return Minecraft.getMinecraft(); - } - - /** - * Binds Iris's widgets texture to be - * used for succeeding draw calls. - */ - public static void bindIrisWidgetsTexture() { - client().getTextureManager().bind(IRIS_WIDGETS_TEX); - } - - /** - * Draws a button. Button textures must be mapped with the - * same coordinates as those on the vanilla widgets texture. - * - * @param x X position of the left of the button - * @param y Y position of the top of the button - * @param width Width of the button, maximum 398 - * @param height Height of the button, maximum 20 - * @param hovered Whether the button is being hovered over with the mouse - * @param disabled Whether the button should use the "disabled" texture - */ - public static void drawButton(PoseStack poseStack, int x, int y, int width, int height, boolean hovered, boolean disabled) { - // Create variables for half of the width and height. - // Will not be exact when width and height are odd, but - // that case is handled within the draw calls. - int halfWidth = width / 2; - int halfHeight = height / 2; - - // V offset for which button texture to use - int vOffset = disabled ? 46 : hovered ? 86 : 66; - - // Sets RenderSystem to use solid white as the tint color for blend mode, and enables blend mode - RenderSystem.blendColor(1.0f, 1.0f, 1.0f, 1.0f); - RenderSystem.enableBlend(); - - // Sets RenderSystem to be able to use textures when drawing - RenderSystem.enableTexture(); - - // Top left section - GuiComponent.blit(poseStack, x, y, 0, vOffset, halfWidth, halfHeight, 256, 256); - // Top right section - GuiComponent.blit(poseStack, x + halfWidth, y, 200 - (width - halfWidth), vOffset, width - halfWidth, halfHeight, 256, 256); - // Bottom left section - GuiComponent.blit(poseStack, x, y + halfHeight, 0, vOffset + (20 - (height - halfHeight)), halfWidth, height - halfHeight, 256, 256); - // Bottom right section - GuiComponent.blit(poseStack, x + halfWidth, y + halfHeight, 200 - (width - halfWidth), vOffset + (20 - (height - halfHeight)), width - halfWidth, height - halfHeight, 256, 256); - } - - /** - * Draws a translucent black panel - * with a light border. - * - * @param x The x position of the panel - * @param y The y position of the panel - * @param width The width of the panel - * @param height The height of the panel - */ - public static void drawPanel(PoseStack poseStack, int x, int y, int width, int height) { - int borderColor = 0xDEDEDEDE; - int innerColor = 0xDE000000; - - // Top border section - GuiComponent.fill(poseStack, x, y, x + width, y + 1, borderColor); - // Bottom border section - GuiComponent.fill(poseStack, x, (y + height) - 1, x + width, y + height, borderColor); - // Left border section - GuiComponent.fill(poseStack, x, y + 1, x + 1, (y + height) - 1, borderColor); - // Right border section - GuiComponent.fill(poseStack, (x + width) - 1, y + 1, x + width, (y + height) - 1, borderColor); - // Inner section - GuiComponent.fill(poseStack, x + 1, y + 1, (x + width) - 1, (y + height) - 1, innerColor); - } - - /** - * Draws a text with a panel behind it. - * - * @param text The text component to draw - * @param x The x position of the panel - * @param y The y position of the panel - */ - public static void drawTextPanel(Font font, PoseStack poseStack, Component text, int x, int y) { - drawPanel(poseStack, x, y, font.width(text) + 8, 16); - font.drawShadow(poseStack, text, x + 4, y + 4, 0xFFFFFF); - } - - /** - * Shorten a text to a specific length, adding an ellipsis (...) - * to the end if shortened. - * - * Text may lose formatting. - * - * @param font Font to use for determining the width of text - * @param text Text to shorten - * @param width Width to shorten text to - * @return a shortened text - */ - public static MutableComponent shortenText(Font font, MutableComponent text, int width) { - if (font.width(text) > width) { - return new TextComponent(font.plainSubstrByWidth(text.getString(), width - font.width(ELLIPSIS))).append(ELLIPSIS).setStyle(text.getStyle()); - } - return text; - } - - /** - * Creates a new translated text, if a translation - * is present. If not, will return the default text - * component passed. - * - * @param defaultText Default text to use if no translation is found - * @param translationDesc Translation key to try and use - * @param format Formatting arguments for the translated text, if created - * @return the translated text if found, otherwise the default provided - */ - public static MutableComponent translateOrDefault(MutableComponent defaultText, String translationDesc, Object ... format) { - if (I18n.exists(translationDesc)) { - return I18n.format(translationDesc, format); - } - return defaultText; - } - - /** - * Plays the {@code UI_BUTTON_CLICK} sound event as a - * master sound effect. - * - * Used in non-{@code ButtonWidget} UI elements upon click - * or other action. - */ - public static void playButtonClickSound() { - client().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1)); - } - - /** - * A class representing a section of a - * texture, to be easily drawn in GUIs. - */ - public static class Icon { - public static final Icon SEARCH = new Icon(0, 0, 7, 8); - public static final Icon CLOSE = new Icon(7, 0, 5, 6); - public static final Icon REFRESH = new Icon(12, 0, 10, 10); - public static final Icon EXPORT = new Icon(22, 0, 7, 8); - public static final Icon EXPORT_COLORED = new Icon(29, 0, 7, 8); - public static final Icon IMPORT = new Icon(22, 8, 7, 8); - public static final Icon IMPORT_COLORED = new Icon(29, 8, 7, 8); - - private final int u; - private final int v; - private final int width; - private final int height; - - public Icon(int u, int v, int width, int height) { - this.u = u; - this.v = v; - this.width = width; - this.height = height; - } - - /** - * Draws this icon to the screen at the specified coordinates. - * - * @param x The x position to draw the icon at (left) - * @param y The y position to draw the icon at (top) - */ - public void draw(PoseStack poseStack, int x, int y) { - // Sets RenderSystem to use solid white as the tint color for blend mode, and enables blend mode - RenderSystem.blendColor(1.0f, 1.0f, 1.0f, 1.0f); - RenderSystem.enableBlend(); - - // Sets RenderSystem to be able to use textures when drawing - RenderSystem.enableTexture(); - - // Draw the texture to the screen - GuiComponent.blit(poseStack, x, y, u, v, width, height, 256, 256); - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - } -} diff --git a/src/main/java/net/coderbot/iris/gui/NavigationController.java b/src/main/java/net/coderbot/iris/gui/NavigationController.java deleted file mode 100644 index 0c7aa8481..000000000 --- a/src/main/java/net/coderbot/iris/gui/NavigationController.java +++ /dev/null @@ -1,66 +0,0 @@ -package net.coderbot.iris.gui; - -import net.coderbot.iris.gui.element.ShaderPackOptionList; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; - -import java.util.ArrayDeque; -import java.util.Deque; - -public class NavigationController { - private final OptionMenuContainer container; - private ShaderPackOptionList optionList; - - private String currentScreen = null; - private final Deque history = new ArrayDeque<>(); - - public NavigationController(OptionMenuContainer container) { - this.container = container; - } - - public void back() { - if (history.size() > 0) { - history.removeLast(); - - if (history.size() > 0) { - currentScreen = history.getLast(); - } else { - currentScreen = null; - } - } else { - currentScreen = null; - } - - this.rebuild(); - } - - public void open(String screen) { - currentScreen = screen; - history.addLast(screen); - - this.rebuild(); - } - - public void rebuild() { - if (optionList != null) { - optionList.rebuild(); - } - } - - public void refresh() { - if (optionList != null) { - optionList.refresh(); - } - } - - public boolean hasHistory() { - return this.history.size() > 0; - } - - public void setActiveOptionList(ShaderPackOptionList optionList) { - this.optionList = optionList; - } - - public String getCurrentScreen() { - return currentScreen; - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java b/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java deleted file mode 100644 index 25c8ceaf4..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java +++ /dev/null @@ -1,225 +0,0 @@ -package net.coderbot.iris.gui.element; - -import net.coderbot.iris.gui.GuiUtil; - -import net.minecraft.client.Minecraft; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; - -/** - * Intended to make very simple rows of buttons easier to make - */ -public class IrisElementRow { - private final Map elements = new HashMap<>(); - private final List orderedElements = new ArrayList<>(); - private final int spacing; - private int x; - private int y; - private int width; - private int height; - - public IrisElementRow(int spacing) { - this.spacing = spacing; - } - - public IrisElementRow() { - this(1); - } - - /** - * Adds an element to the right of this row. - * - * @param element The element to add - * @param width The width of the element in this row - * @return {@code this}, to be used for chaining statements - */ - public IrisElementRow add(Element element, int width) { - if (!this.orderedElements.contains(element)) { - this.orderedElements.add(element); - } - this.elements.put(element, width); - - this.width += width + this.spacing; - - return this; - } - - /** - * Modifies the width of an element. - * - * @param element The element whose width to modify - * @param width The width to be assigned to the specified element - */ - public void setWidth(Element element, int width) { - if (!this.elements.containsKey(element)) { - return; - } - - this.width -= this.elements.get(element) + 2; - - add(element, width); - } - - /** - * Renders the row, with the anchor point being the top left. - */ - public void render(PoseStack poseStack, int x, int y, int height, int mouseX, int mouseY, float tickDelta, boolean rowHovered) { - this.x = x; - this.y = y; - this.height = height; - - int currentX = x; - - for (Element element : this.orderedElements) { - int currentWidth = this.elements.get(element); - - element.render(poseStack, currentX, y, currentWidth, height, mouseX, mouseY, tickDelta, - rowHovered && sectionHovered(currentX, currentWidth, mouseX, mouseY)); - - currentX += currentWidth + this.spacing; - } - } - - /** - * Renders the row, with the anchor point being the top right. - */ - public void renderRightAligned(PoseStack poseStack, int x, int y, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - render(poseStack, x - this.width, y, height, mouseX, mouseY, tickDelta, hovered); - } - - private boolean sectionHovered(int sectionX, int sectionWidth, double mx, double my) { - return mx > sectionX && mx < sectionX + sectionWidth && - my > this.y && my < this.y + this.height; - } - - private Optional getHovered(double mx, double my) { - int currentX = this.x; - - for (Element element : this.orderedElements) { - int currentWidth = this.elements.get(element); - - if (sectionHovered(currentX, currentWidth, mx, my)) { - return Optional.of(element); - } - - currentX += currentWidth + this.spacing; - } - - return Optional.empty(); - } - - public boolean mouseClicked(double mx, double my, int button) { - return getHovered(mx, my).map(element -> element.mouseClicked(mx, my, button)).orElse(false); - } - - public boolean mouseReleased(double mx, double my, int button) { - return getHovered(mx, my).map(element -> element.mouseReleased(mx, my, button)).orElse(false); - } - - public static abstract class Element { - public boolean disabled = false; - private boolean hovered = false; - - public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - GuiUtil.bindIrisWidgetsTexture(); - GuiUtil.drawButton(poseStack, x, y, width, height, hovered, this.disabled); - - this.hovered = hovered; - this.renderLabel(poseStack, x, y, width, height, mouseX, mouseY, tickDelta, hovered); - } - - public abstract void renderLabel(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered); - - public boolean mouseClicked(double mx, double my, int button) { - return false; - } - - public boolean mouseReleased(double mx, double my, int button) { - return false; - } - - public boolean isHovered() { - return hovered; - } - } - - public static abstract class ButtonElement> extends Element { - private final Function onClick; - - protected ButtonElement(Function onClick) { - this.onClick = onClick; - } - - @Override - public boolean mouseClicked(double mx, double my, int button) { - if (this.disabled) { - return false; - } - - if (button == GLFW.GLFW_MOUSE_BUTTON_1) { - return this.onClick.apply((T) this); - } - - return super.mouseClicked(mx, my, button); - } - } - - /** - * A clickable button element that uses a {@link GuiUtil.Icon} as its label. - */ - public static class IconButtonElement extends ButtonElement { - public GuiUtil.Icon icon; - public GuiUtil.Icon hoveredIcon; - - public IconButtonElement(GuiUtil.Icon icon, GuiUtil.Icon hoveredIcon, Function onClick) { - super(onClick); - this.icon = icon; - this.hoveredIcon = hoveredIcon; - } - - public IconButtonElement(GuiUtil.Icon icon, Function onClick) { - this(icon, icon, onClick); - } - - @Override - public void renderLabel(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - int iconX = x + (int)((width - this.icon.getWidth()) * 0.5); - int iconY = y + (int)((height - this.icon.getHeight()) * 0.5); - - GuiUtil.bindIrisWidgetsTexture(); - if (!this.disabled && hovered) { - this.hoveredIcon.draw(poseStack, iconX, iconY); - } else { - this.icon.draw(poseStack, iconX, iconY); - } - } - } - - /** - * A clickable button element that uses a text component as its label. - */ - public static class TextButtonElement extends ButtonElement { - protected final Font font; - public Component text; - - public TextButtonElement(Component text, Function onClick) { - super(onClick); - - this.font = Minecraft.getMinecraft().font; - this.text = text; - } - - @Override - public void renderLabel(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - int textX = x + (int)((width - this.font.width(this.text)) * 0.5); - int textY = y + (int)((height - 8) * 0.5); - - this.font.drawShadow(poseStack, this.text, textX, textY, 0xFFFFFF); - } - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisObjectSelectionList.java b/src/main/java/net/coderbot/iris/gui/element/IrisObjectSelectionList.java deleted file mode 100644 index 100478dc6..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/IrisObjectSelectionList.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.coderbot.iris.gui.element; - -import net.minecraft.client.Minecraft; - -public class IrisObjectSelectionList> extends ObjectSelectionList { - public IrisObjectSelectionList(Minecraft client, int width, int height, int top, int bottom, int left, int right, int itemHeight) { - super(client, width, height, top, bottom, itemHeight); - - this.x0 = left; - this.x1 = right; - } - - @Override - protected int getScrollbarPosition() { - // Position the scrollbar at the rightmost edge of the screen. - // By default, the scrollbar is positioned moderately offset from the center. - return width - 6; - } - - public void select(int entry) { - setSelected(this.getEntry(entry)); - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java deleted file mode 100644 index 92fe7dcdf..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java +++ /dev/null @@ -1,365 +0,0 @@ -package net.coderbot.iris.gui.element; - -import com.mojang.realmsclient.gui.ChatFormatting; -import net.coderbot.iris.Iris; -import net.coderbot.iris.gui.FileDialogUtil; -import net.coderbot.iris.gui.GuiUtil; -import net.coderbot.iris.gui.NavigationController; -import net.coderbot.iris.gui.element.widget.AbstractElementWidget; -import net.coderbot.iris.gui.element.widget.OptionMenuConstructor; -import net.coderbot.iris.gui.screen.ShaderPackScreen; -import net.coderbot.iris.shaderpack.ShaderPack; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.I18n; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -public class ShaderPackOptionList extends IrisObjectSelectionList { - private final List> elementWidgets = new ArrayList<>(); - private final ShaderPackScreen screen; - private final NavigationController navigation; - private OptionMenuContainer container; - - public ShaderPackOptionList(ShaderPackScreen screen, NavigationController navigation, ShaderPack pack, Minecraft client, int width, int height, int top, int bottom, int left, int right) { - super(client, width, height, top, bottom, left, right, 24); - this.navigation = navigation; - this.screen = screen; - - applyShaderPack(pack); - } - - public void applyShaderPack(ShaderPack pack) { - this.container = pack.getMenuContainer(); - } - - public void rebuild() { - this.clearEntries(); - this.setScrollAmount(0); - OptionMenuConstructor.constructAndApplyToScreen(this.container, this.screen, this, navigation); - } - - public void refresh() { - this.elementWidgets.forEach(widget -> widget.init(this.screen, this.navigation)); - } - - @Override - public int getRowWidth() { - return Math.min(400, width - 12); - } - - public void addHeader(Component text, boolean backButton) { - this.addEntry(new HeaderEntry(this.screen, this.navigation, text, backButton)); - } - - public void addWidgets(int columns, List> elements) { - this.elementWidgets.addAll(elements); - - List> row = new ArrayList<>(); - for (AbstractElementWidget element : elements) { - row.add(element); - - if (row.size() >= columns) { - this.addEntry(new ElementRowEntry(screen, this.navigation, row)); - row = new ArrayList<>(); // Clearing the list would affect the row entry created above - } - } - - if (row.size() > 0) { - while (row.size() < columns) { - row.add(AbstractElementWidget.EMPTY); - } - - this.addEntry(new ElementRowEntry(screen, this.navigation, row)); - } - } - - public NavigationController getNavigation() { - return navigation; - } - - public abstract static class BaseEntry extends ObjectSelectionList.Entry { - protected final NavigationController navigation; - - protected BaseEntry(NavigationController navigation) { - this.navigation = navigation; - } - } - - public static class HeaderEntry extends BaseEntry { - public static final Component BACK_BUTTON_TEXT = new TextComponent("< ").append(I18n.format("options.iris.back").withStyle(ChatFormatting.ITALIC)); - public static final MutableComponent RESET_BUTTON_TEXT_INACTIVE = I18n.format("options.iris.reset").withStyle(ChatFormatting.GRAY); - public static final MutableComponent RESET_BUTTON_TEXT_ACTIVE = I18n.format("options.iris.reset").withStyle(ChatFormatting.YELLOW); - - public static final MutableComponent RESET_HOLD_SHIFT_TOOLTIP = I18n.format("options.iris.reset.tooltip.holdShift").withStyle(ChatFormatting.GOLD); - public static final MutableComponent RESET_TOOLTIP = I18n.format("options.iris.reset.tooltip").withStyle(ChatFormatting.RED); - public static final MutableComponent IMPORT_TOOLTIP = I18n.format("options.iris.importSettings.tooltip") - .withStyle(style -> style.withColor(TextColor.fromRgb(0x4da6ff))); - public static final MutableComponent EXPORT_TOOLTIP = I18n.format("options.iris.exportSettings.tooltip") - .withStyle(style -> style.withColor(TextColor.fromRgb(0xfc7d3d))); - - private static final int MIN_SIDE_BUTTON_WIDTH = 42; - private static final int BUTTON_HEIGHT = 16; - - private final ShaderPackScreen screen; - private final @Nullable IrisElementRow backButton; - private final IrisElementRow utilityButtons = new IrisElementRow(); - private final IrisElementRow.TextButtonElement resetButton; - private final IrisElementRow.IconButtonElement importButton; - private final IrisElementRow.IconButtonElement exportButton; - private final Component text; - - public HeaderEntry(ShaderPackScreen screen, NavigationController navigation, Component text, boolean hasBackButton) { - super(navigation); - - if (hasBackButton) { - this.backButton = new IrisElementRow().add( - new IrisElementRow.TextButtonElement(BACK_BUTTON_TEXT, this::backButtonClicked), - Math.max(MIN_SIDE_BUTTON_WIDTH, Minecraft.getMinecraft().font.width(BACK_BUTTON_TEXT) + 8) - ); - } else { - this.backButton = null; - } - - this.resetButton = new IrisElementRow.TextButtonElement( - RESET_BUTTON_TEXT_INACTIVE, this::resetButtonClicked); - this.importButton = new IrisElementRow.IconButtonElement( - GuiUtil.Icon.IMPORT, GuiUtil.Icon.IMPORT_COLORED, this::importSettingsButtonClicked); - this.exportButton = new IrisElementRow.IconButtonElement( - GuiUtil.Icon.EXPORT, GuiUtil.Icon.EXPORT_COLORED, this::exportSettingsButtonClicked); - - this.utilityButtons - .add(this.importButton, 15) - .add(this.exportButton, 15) - .add(this.resetButton, Math.max(MIN_SIDE_BUTTON_WIDTH, Minecraft.getMinecraft().font.width(RESET_BUTTON_TEXT_INACTIVE) + 8)); - - this.screen = screen; - this.text = text; - } - - @Override - public void render(PoseStack poseStack, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - // Draw dividing line - fill(poseStack, x - 3, (y + entryHeight) - 2, x + entryWidth, (y + entryHeight) - 1, 0x66BEBEBE); - - Font font = Minecraft.getMinecraft().font; - - // Draw header text - drawCenteredString(poseStack, font, text, x + (int)(entryWidth * 0.5), y + 5, 0xFFFFFF); - - GuiUtil.bindIrisWidgetsTexture(); - - // Draw back button if present - if (this.backButton != null) { - backButton.render(poseStack, x, y, BUTTON_HEIGHT, mouseX, mouseY, tickDelta, hovered); - } - - boolean shiftDown = Screen.hasShiftDown(); - - // Set the appearance of the reset button - this.resetButton.disabled = !shiftDown; - this.resetButton.text = shiftDown ? RESET_BUTTON_TEXT_ACTIVE : RESET_BUTTON_TEXT_INACTIVE; - - // Draw the utility buttons - this.utilityButtons.renderRightAligned(poseStack, (x + entryWidth) - 3, y, BUTTON_HEIGHT, mouseX, mouseY, tickDelta, hovered); - - // Draw the reset button's tooltip - if (this.resetButton.isHovered()) { - Component tooltip = shiftDown ? RESET_TOOLTIP : RESET_HOLD_SHIFT_TOOLTIP; - queueBottomRightAnchoredTooltip(poseStack, mouseX, mouseY, font, tooltip); - } - // Draw the import/export button tooltips - if (this.importButton.isHovered()) { - queueBottomRightAnchoredTooltip(poseStack, mouseX, mouseY, font, IMPORT_TOOLTIP); - } - if (this.exportButton.isHovered()) { - queueBottomRightAnchoredTooltip(poseStack, mouseX, mouseY, font, EXPORT_TOOLTIP); - } - } - - private void queueBottomRightAnchoredTooltip(PoseStack poseStack, int x, int y, Font font, Component text) { - ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel( - font, poseStack, text, - x - (font.width(text) + 10), y - 16 - )); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - boolean backButtonResult = backButton != null && backButton.mouseClicked(mouseX, mouseY, button); - boolean utilButtonResult = utilityButtons.mouseClicked(mouseX, mouseY, button); - - return backButtonResult || utilButtonResult; - } - - private boolean backButtonClicked(IrisElementRow.TextButtonElement button) { - this.navigation.back(); - GuiUtil.playButtonClickSound(); - - return true; - } - - private boolean resetButtonClicked(IrisElementRow.TextButtonElement button) { - if (Screen.hasShiftDown()) { - Iris.resetShaderPackOptionsOnNextReload(); - this.screen.applyChanges(); - GuiUtil.playButtonClickSound(); - - return true; - } - - return false; - } - - private boolean importSettingsButtonClicked(IrisElementRow.IconButtonElement button) { - GuiUtil.playButtonClickSound(); - - // Invalid state to be in - if (!Iris.getCurrentPack().isPresent()) { - return false; - } - - // Displaying a dialog when the game is full-screened can cause severe issues - // https://github.com/IrisShaders/Iris/issues/1258 - if (Minecraft.getMinecraft().getWindow().isFullscreen()) { - this.screen.displayNotification( - I18n.format("options.iris.mustDisableFullscreen") - .withStyle(ChatFormatting.RED).withStyle(ChatFormatting.BOLD)); - return false; - } - - final ShaderPackScreen originalScreen = this.screen; // Also used to prevent invalid state - - FileDialogUtil.fileSelectDialog( - FileDialogUtil.DialogType.OPEN, "Import Shader Settings from File", - Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"), - "Shader Pack Settings (.txt)", "*.txt") - .whenComplete((path, err) -> { - if (err != null) { - Iris.logger.error("Error selecting shader settings from file", err); - - return; - } - - if (Minecraft.getMinecraft().screen == originalScreen) { - path.ifPresent(originalScreen::importPackOptions); - } - }); - - return true; - } - - private boolean exportSettingsButtonClicked(IrisElementRow.IconButtonElement button) { - GuiUtil.playButtonClickSound(); - - // Invalid state to be in - if (!Iris.getCurrentPack().isPresent()) { - return false; - } - - // Displaying a dialog when the game is full-screened can cause severe issues - // https://github.com/IrisShaders/Iris/issues/1258 - if (Minecraft.getMinecraft().getWindow().isFullscreen()) { - this.screen.displayNotification( - I18n.format("options.iris.mustDisableFullscreen") - .withStyle(ChatFormatting.RED).withStyle(ChatFormatting.BOLD)); - return false; - } - - FileDialogUtil.fileSelectDialog( - FileDialogUtil.DialogType.SAVE, "Export Shader Settings to File", - Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"), - "Shader Pack Settings (.txt)", "*.txt") - .whenComplete((path, err) -> { - if (err != null) { - Iris.logger.error("Error selecting file to export shader settings", err); - - return; - } - - path.ifPresent(p -> { - Properties toSave = new Properties(); - - // Dirty way of getting the currently applied settings as a Properties, directly - // opens and copies out of the saved settings file if it is present - Path sourceTxtPath = Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"); - if (Files.exists(sourceTxtPath)) { - try (InputStream in = Files.newInputStream(sourceTxtPath)) { - toSave.load(in); - } catch (IOException ignored) {} - } - - // Save properties to user determined file - try (OutputStream out = Files.newOutputStream(p)) { - toSave.store(out, null); - } catch (IOException e) { - Iris.logger.error("Error saving properties to \"" + p + "\"", e); - } - }); - }); - - return true; - } - } - - public static class ElementRowEntry extends BaseEntry { - private final List> widgets; - private final ShaderPackScreen screen; - - private int cachedWidth; - private int cachedPosX; - - public ElementRowEntry(ShaderPackScreen screen, NavigationController navigation, List> widgets) { - super(navigation); - - this.screen = screen; - this.widgets = widgets; - } - - @Override - public void render(PoseStack poseStack, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - this.cachedWidth = entryWidth; - this.cachedPosX = x; - - // The amount of space widgets will occupy, excluding margins. Will be divided up between widgets. - int totalWidthWithoutMargins = entryWidth - (2 * (widgets.size() - 1)); - - totalWidthWithoutMargins -= 3; // Centers it for some reason - - // Width of a single widget - float singleWidgetWidth = (float) totalWidthWithoutMargins / widgets.size(); - - for (int i = 0; i < widgets.size(); i++) { - AbstractElementWidget widget = widgets.get(i); - boolean widgetHovered = hovered && (getHoveredWidget(mouseX) == i); - widget.render(poseStack, x + (int)((singleWidgetWidth + 2) * i), y, (int) singleWidgetWidth, entryHeight + 2, mouseX, mouseY, tickDelta, widgetHovered); - - screen.setElementHoveredStatus(widget, widgetHovered); - } - } - - public int getHoveredWidget(int mouseX) { - float positionAcrossWidget = ((float) Mth.clamp(mouseX - cachedPosX, 0, cachedWidth)) / cachedWidth; - - return Mth.clamp((int) Math.floor(widgets.size() * positionAcrossWidget), 0, widgets.size() - 1); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - return this.widgets.get(getHoveredWidget((int) mouseX)).mouseClicked(mouseX, mouseY, button); - } - - @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { - return this.widgets.get(getHoveredWidget((int) mouseX)).mouseReleased(mouseX, mouseY, button); - } - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java deleted file mode 100644 index 57c57c198..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java +++ /dev/null @@ -1,310 +0,0 @@ -package net.coderbot.iris.gui.element; - -import net.coderbot.iris.Iris; -import net.coderbot.iris.gui.GuiUtil; -import net.coderbot.iris.gui.screen.ShaderPackScreen; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.I18n; - -import java.util.Collection; -import java.util.function.Function; - -public class ShaderPackSelectionList extends IrisObjectSelectionList { - private static final Component PACK_LIST_LABEL = I18n.format("pack.iris.list.label").withStyle(ChatFormatting.ITALIC, ChatFormatting.GRAY); - - private final ShaderPackScreen screen; - private final TopButtonRowEntry topButtonRow; - private ShaderPackEntry applied = null; - - public ShaderPackSelectionList(ShaderPackScreen screen, Minecraft client, int width, int height, int top, int bottom, int left, int right) { - super(client, width, height, top, bottom, left, right, 20); - - this.screen = screen; - this.topButtonRow = new TopButtonRowEntry(this, Iris.getIrisConfig().areShadersEnabled()); - - refresh(); - } - - @Override - public int getRowWidth() { - return Math.min(308, width - 50); - } - - @Override - protected int getRowTop(int index) { - return super.getRowTop(index) + 2; - } - - public void refresh() { - this.clearEntries(); - - Collection names; - - try { - names = Iris.getShaderpacksDirectoryManager().enumerate(); - } catch (Throwable e) { - Iris.logger.error("Error reading files while constructing selection UI", e); - - // Not translating this since it's going to be seen very rarely, - // We're just trying to get more information on a seemingly untraceable bug: - // - https://github.com/IrisShaders/Iris/issues/785 - this.addLabelEntries( - TextComponent.EMPTY, - new TextComponent("There was an error reading your shaderpacks directory") - .withStyle(ChatFormatting.RED, ChatFormatting.BOLD), - TextComponent.EMPTY, - new TextComponent("Check your logs for more information."), - new TextComponent("Please file an issue report including a log file."), - new TextComponent("If you are able to identify the file causing this, " + - "please include it in your report as well."), - new TextComponent("Note that this might be an issue with folder " + - "permissions; ensure those are correct first.") - ); - - return; - } - - this.addEntry(topButtonRow); - - // Only allow the enable/disable shaders button if the user has - // added a shader pack. Otherwise, the button will be disabled. - topButtonRow.allowEnableShadersButton = names.size() > 0; - - int index = 0; - - for (String name : names) { - index++; - addPackEntry(index, name); - } - - this.addLabelEntries(PACK_LIST_LABEL); - } - - public void addPackEntry(int index, String name) { - ShaderPackEntry entry = new ShaderPackEntry(index, this, name); - - Iris.getIrisConfig().getShaderPackName().ifPresent(currentPackName -> { - if (name.equals(currentPackName)) { - setSelected(entry); - setApplied(entry); - } - }); - - this.addEntry(entry); - } - - public void addLabelEntries(Component ... lines) { - for (Component text : lines) { - this.addEntry(new LabelEntry(text)); - } - } - - public void select(String name) { - for (int i = 0; i < getItemCount(); i++) { - BaseEntry entry = getEntry(i); - - if (entry instanceof ShaderPackEntry && ((ShaderPackEntry)entry).packName.equals(name)) { - setSelected(entry); - - return; - } - } - } - - public void setApplied(ShaderPackEntry entry) { - this.applied = entry; - } - - public ShaderPackEntry getApplied() { - return this.applied; - } - - public TopButtonRowEntry getTopButtonRow() { - return topButtonRow; - } - - public static abstract class BaseEntry extends ObjectSelectionList.Entry { - protected BaseEntry() {} - } - - public static class ShaderPackEntry extends BaseEntry { - private final String packName; - private final ShaderPackSelectionList list; - private final int index; - - public ShaderPackEntry(int index, ShaderPackSelectionList list, String packName) { - this.packName = packName; - this.list = list; - this.index = index; - } - - public boolean isApplied() { - return list.getApplied() == this; - } - - public boolean isSelected() { - return list.getSelected() == this; - } - - public String getPackName() { - return packName; - } - - @Override - public void render(PoseStack poseStack, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - Font font = Minecraft.getMinecraft().font; - int color = 0xFFFFFF; - String name = packName; - - boolean shadersEnabled = list.getTopButtonRow().shadersEnabled; - - if (font.width(new TextComponent(name).withStyle(ChatFormatting.BOLD)) > this.list.getRowWidth() - 3) { - name = font.plainSubstrByWidth(name, this.list.getRowWidth() - 8) + "..."; - } - - MutableComponent text = new TextComponent(name); - - if (this.isMouseOver(mouseX, mouseY)) { - text = text.withStyle(ChatFormatting.BOLD); - } - - if (shadersEnabled && this.isApplied()) { - color = 0xFFF263; - } - - if (!shadersEnabled && !this.isMouseOver(mouseX, mouseY)) { - color = 0xA2A2A2; - } - - drawCenteredString(poseStack, font, text, (x + entryWidth / 2) - 2, y + (entryHeight - 11) / 2, color); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - // Only do anything on left-click - if (button != 0) { - return false; - } - - boolean didAnything = false; - - // UX: If shaders are disabled, then clicking a shader in the list will also - // enable shaders on apply. Previously, it was not possible to select - // a pack when shaders were disabled, but this was a source of confusion - // - people did not realize that they needed to enable shaders before - // selecting a shader pack. - if (!list.getTopButtonRow().shadersEnabled) { - list.getTopButtonRow().setShadersEnabled(true); - didAnything = true; - } - - if (!this.isSelected()) { - this.list.select(this.index); - didAnything = true; - } - - return didAnything; - } - } - - public static class LabelEntry extends BaseEntry { - private final Component label; - - public LabelEntry(Component label) { - this.label = label; - } - - @Override - public void render(PoseStack poseStack, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - drawCenteredString(poseStack, Minecraft.getMinecraft().font, label, (x + entryWidth / 2) - 2, y + (entryHeight - 11) / 2, 0xC2C2C2); - } - } - - public static class TopButtonRowEntry extends BaseEntry { - private static final Component REFRESH_SHADER_PACKS_LABEL = I18n.format("options.iris.refreshShaderPacks").withStyle(style -> style.withColor(TextColor.fromRgb(0x99ceff))); - private static final Component NONE_PRESENT_LABEL = I18n.format("options.iris.shaders.nonePresent").withStyle(ChatFormatting.GRAY); - private static final Component SHADERS_DISABLED_LABEL = I18n.format("options.iris.shaders.disabled"); - private static final Component SHADERS_ENABLED_LABEL = I18n.format("options.iris.shaders.enabled"); - private static final int REFRESH_BUTTON_WIDTH = 18; - - private final ShaderPackSelectionList list; - private final IrisElementRow buttons = new IrisElementRow(); - private final EnableShadersButtonElement enableDisableButton; - private final IrisElementRow.Element refreshPacksButton; - - public boolean allowEnableShadersButton = true; - public boolean shadersEnabled; - - public TopButtonRowEntry(ShaderPackSelectionList list, boolean shadersEnabled) { - this.list = list; - this.shadersEnabled = shadersEnabled; - this.enableDisableButton = new EnableShadersButtonElement( - getEnableDisableLabel(), - button -> { - if (this.allowEnableShadersButton) { - setShadersEnabled(!this.shadersEnabled); - GuiUtil.playButtonClickSound(); - return true; - } - - return false; - }); - this.refreshPacksButton = new IrisElementRow.IconButtonElement( - GuiUtil.Icon.REFRESH, - button -> { - this.list.refresh(); - - GuiUtil.playButtonClickSound(); - return true; - }); - this.buttons.add(this.enableDisableButton, 0).add(this.refreshPacksButton, REFRESH_BUTTON_WIDTH); - } - - public void setShadersEnabled(boolean shadersEnabled) { - this.shadersEnabled = shadersEnabled; - this.enableDisableButton.text = getEnableDisableLabel(); - this.list.screen.refreshScreenSwitchButton(); - } - - @Override - public void render(PoseStack poseStack, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - this.buttons.setWidth(this.enableDisableButton, (entryWidth - 1) - REFRESH_BUTTON_WIDTH); - this.enableDisableButton.centerX = x + (int)(entryWidth * 0.5); - - this.buttons.render(poseStack, x - 2, y - 3, 18, mouseX, mouseY, tickDelta, hovered); - - if (this.refreshPacksButton.isHovered()) { - ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> - GuiUtil.drawTextPanel(Minecraft.getMinecraft().font, poseStack, REFRESH_SHADER_PACKS_LABEL, - (mouseX - 8) - Minecraft.getMinecraft().font.width(REFRESH_SHADER_PACKS_LABEL), mouseY - 16)); - } - } - - private Component getEnableDisableLabel() { - return this.allowEnableShadersButton ? this.shadersEnabled ? SHADERS_ENABLED_LABEL : SHADERS_DISABLED_LABEL : NONE_PRESENT_LABEL; - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - return this.buttons.mouseClicked(mouseX, mouseY, button); - } - - // Renders the label at an offset as to not look misaligned with the rest of the menu - public static class EnableShadersButtonElement extends IrisElementRow.TextButtonElement { - private int centerX; - - public EnableShadersButtonElement(Component text, Function onClick) { - super(text, onClick); - } - - @Override - public void renderLabel(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - int textX = this.centerX - (int)(this.font.width(this.text) * 0.5); - int textY = y + (int)((height - 8) * 0.5); - - this.font.drawShadow(poseStack, this.text, textX, textY, 0xFFFFFF); - } - } - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java b/src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java deleted file mode 100644 index 78eb212a0..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.coderbot.iris.gui.element.screen; - - - -public class ElementWidgetScreenData { - public static final ElementWidgetScreenData EMPTY = new ElementWidgetScreenData(TextComponent.EMPTY, true); - - public final Component heading; - public final boolean backButton; - - public ElementWidgetScreenData(Component heading, boolean backButton) { - this.heading = heading; - this.backButton = backButton; - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java deleted file mode 100644 index 8b780878c..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.coderbot.iris.gui.element.widget; - -import net.coderbot.iris.gui.NavigationController; -import net.coderbot.iris.gui.screen.ShaderPackScreen; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; - -public abstract class AbstractElementWidget { - protected final T element; - - public static final AbstractElementWidget EMPTY = new AbstractElementWidget(null) { - @Override - public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) {} - }; - - public AbstractElementWidget(T element) { - this.element = element; - } - - public void init(ShaderPackScreen screen, NavigationController navigation) {} - - public abstract void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered); - - public boolean mouseClicked(double mx, double my, int button) { - return false; - } - - public boolean mouseReleased(double mx, double my, int button) { - return false; - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java deleted file mode 100644 index 6512f95cf..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java +++ /dev/null @@ -1,180 +0,0 @@ -package net.coderbot.iris.gui.element.widget; - -import net.coderbot.iris.gui.GuiUtil; -import net.coderbot.iris.gui.NavigationController; -import net.coderbot.iris.gui.screen.ShaderPackScreen; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.I18n; -import org.jetbrains.annotations.Nullable; - -import java.util.Optional; - -public abstract class BaseOptionElementWidget extends CommentedElementWidget { - protected static final Component SET_TO_DEFAULT = I18n.format("options.iris.setToDefault").withStyle(ChatFormatting.GREEN); - protected static final Component DIVIDER = new TextComponent(": "); - - protected MutableComponent unmodifiedLabel; - protected ShaderPackScreen screen; - protected NavigationController navigation; - private MutableComponent label; - - protected Component trimmedLabel; - protected Component valueLabel; - - private boolean isLabelTrimmed; - private int maxLabelWidth; - private int valueSectionWidth; - - public BaseOptionElementWidget(T element) { - super(element); - } - - @Override - public void init(ShaderPackScreen screen, NavigationController navigation) { - this.screen = screen; - this.navigation = navigation; - this.valueLabel = null; - this.trimmedLabel = null; - } - - protected final void setLabel(MutableComponent label) { - this.label = label.copy().append(DIVIDER); - this.unmodifiedLabel = label; - } - - protected final void updateRenderParams(int width, int minValueSectionWidth) { - // Lazy init of value label - if (this.valueLabel == null) { - this.valueLabel = createValueLabel(); - } - - // Determine the width of the value box - Font font = Minecraft.getMinecraft().font; - this.valueSectionWidth = Math.max(minValueSectionWidth, font.width(this.valueLabel) + 8); - - // Determine maximum width of trimmed label - this.maxLabelWidth = (width - 8) - this.valueSectionWidth; - - // Lazy init of trimmed label, and make sure it is only trimmed when necessary - if (this.trimmedLabel == null || font.width(this.label) > this.maxLabelWidth != isLabelTrimmed) { - updateLabels(); - } - - // Set whether the label has been trimmed (used when updating label and determining whether to render tooltips) - this.isLabelTrimmed = font.width(this.label) > this.maxLabelWidth; - } - - protected final void renderOptionWithValue(PoseStack poseStack, int x, int y, int width, int height, boolean hovered, float sliderPosition, int sliderWidth) { - GuiUtil.bindIrisWidgetsTexture(); - - // Draw button background - GuiUtil.drawButton(poseStack, x, y, width, height, hovered, false); - - // Draw the value box - GuiUtil.drawButton(poseStack, (x + width) - (this.valueSectionWidth + 2), y + 2, this.valueSectionWidth, height - 4, false, true); - - // Draw the preview slider - if (sliderPosition >= 0) { - // Range of x values the slider can occupy - int sliderSpace = (this.valueSectionWidth - 4) - sliderWidth; - - // Position of slider - int sliderPos = ((x + width) - this.valueSectionWidth) + (int)(sliderPosition * sliderSpace); - - GuiUtil.drawButton(poseStack, sliderPos, y + 4, sliderWidth, height - 8, false, false); - } - - Font font = Minecraft.getMinecraft().font; - - // Draw the label - font.drawShadow(poseStack, this.trimmedLabel, x + 6, y + 7, 0xFFFFFF); - // Draw the value label - font.drawShadow(poseStack, this.valueLabel, (x + (width - 2)) - (int)(this.valueSectionWidth * 0.5) - (int)(font.width(this.valueLabel) * 0.5), y + 7, 0xFFFFFF); - } - - protected final void renderOptionWithValue(PoseStack poseStack, int x, int y, int width, int height, boolean hovered) { - this.renderOptionWithValue(poseStack, x, y, width, height, hovered, -1, 0); - } - - protected final void tryRenderTooltip(PoseStack poseStack, int mouseX, int mouseY, boolean hovered) { - if (Screen.hasShiftDown()) { - renderTooltip(poseStack, SET_TO_DEFAULT, mouseX, mouseY, hovered); - } else if (this.isLabelTrimmed && !this.screen.isDisplayingComment()) { - renderTooltip(poseStack, this.unmodifiedLabel, mouseX, mouseY, hovered); - } - } - - protected final void renderTooltip(PoseStack poseStack, Component text, int mouseX, int mouseY, boolean hovered) { - if (hovered) { - ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel(Minecraft.getMinecraft().font, poseStack, text, mouseX + 2, mouseY - 16)); - } - } - - protected final void updateLabels() { - this.trimmedLabel = createTrimmedLabel(); - this.valueLabel = createValueLabel(); - } - - protected final Component createTrimmedLabel() { - MutableComponent label = GuiUtil.shortenText( - Minecraft.getMinecraft().font, - this.label.copy(), - this.maxLabelWidth); - - if (this.isValueModified()) { - label = label.withStyle(style -> style.withColor(TextColor.fromRgb(0xffc94a))); - } - - return label; - } - - protected abstract Component createValueLabel(); - - public abstract boolean applyNextValue(); - - public abstract boolean applyPreviousValue(); - - public abstract boolean applyOriginalValue(); - - public abstract boolean isValueModified(); - - public abstract @Nullable String getCommentKey(); - - @Override - public Optional getCommentTitle() { - return Optional.of(this.unmodifiedLabel); - } - - @Override - public Optional getCommentBody() { - return Optional.ofNullable(getCommentKey()).map(key -> I18n.exists(key) ? I18n.format(key) : null); - } - - @Override - public boolean mouseClicked(double mx, double my, int button) { - if (button == GLFW.GLFW_MOUSE_BUTTON_1 || button == GLFW.GLFW_MOUSE_BUTTON_2) { - boolean refresh = false; - - if (Screen.hasShiftDown()) { - refresh = applyOriginalValue(); - } - if (!refresh) { - if (button == GLFW.GLFW_MOUSE_BUTTON_1) { - refresh = applyNextValue(); - } else { - refresh = applyPreviousValue(); - } - } - - if (refresh) { - this.navigation.refresh(); - } - - GuiUtil.playButtonClickSound(); - - return true; - } - return super.mouseClicked(mx, my, button); - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java deleted file mode 100644 index 40ca5b3f0..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java +++ /dev/null @@ -1,112 +0,0 @@ -package net.coderbot.iris.gui.element.widget; - -import net.coderbot.iris.Iris; -import net.coderbot.iris.gui.GuiUtil; -import net.coderbot.iris.gui.NavigationController; -import net.coderbot.iris.gui.screen.ShaderPackScreen; -import net.coderbot.iris.shaderpack.option.BooleanOption; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuBooleanOptionElement; - -import net.minecraft.client.resources.I18n; - -public class BooleanElementWidget extends BaseOptionElementWidget { - private static final Component TEXT_TRUE = I18n.format("label.iris.true").withStyle(ChatFormatting.GREEN); - private static final Component TEXT_FALSE = I18n.format("label.iris.false").withStyle(ChatFormatting.RED); - private static final Component TEXT_TRUE_DEFAULT = I18n.format("label.iris.true"); - private static final Component TEXT_FALSE_DEFAULT = I18n.format("label.iris.false"); - - private final BooleanOption option; - - private boolean appliedValue; - private boolean value; - private boolean defaultValue; - - public BooleanElementWidget(OptionMenuBooleanOptionElement element) { - super(element); - - this.option = element.option; - } - - @Override - public void init(ShaderPackScreen screen, NavigationController navigation) { - super.init(screen, navigation); - - // The value currently in use by the shader pack - this.appliedValue = this.element.getAppliedOptionValues().getBooleanValueOrDefault(this.option.getName()); - - // The yet-to-be-applied value that has been queued (if that is the case) - // Might be equal to the applied value - this.value = this.element.getPendingOptionValues().getBooleanValueOrDefault(this.option.getName()); - - this.defaultValue = this.element.getAppliedOptionValues().getOptionSet().getBooleanOptions() - .get(this.option.getName()).getOption().getDefaultValue(); - - this.setLabel(GuiUtil.translateOrDefault(new TextComponent(this.option.getName()), "option." + this.option.getName())); - } - - @Override - public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - this.updateRenderParams(width, 28); - - this.renderOptionWithValue(poseStack, x, y, width, height, hovered); - this.tryRenderTooltip(poseStack, mouseX, mouseY, hovered); - } - - @Override - protected Component createValueLabel() { - // UX: Do not use color if the value is set to default. - // - // This is because the red color for "Off" and green color of "On" - // was causing people to want to change options to On when that was - // unnecessary due to red having a bad association. - // - // This was changed on request of Emin, since people kept on changing - // Compatibility Mode to "On" when not needed. Now we use white for - // default to avoid giving a positive or negative connotation to a - // default value. - if (this.value == this.defaultValue) { - return this.value ? TEXT_TRUE_DEFAULT : TEXT_FALSE_DEFAULT; - } - - return this.value ? TEXT_TRUE : TEXT_FALSE; - } - - @Override - public String getCommentKey() { - return "option." + this.option.getName() + ".comment"; - } - - public String getValue() { - return Boolean.toString(this.value); - } - - private void queue() { - Iris.getShaderPackOptionQueue().put(this.option.getName(), this.getValue()); - } - - @Override - public boolean applyNextValue() { - this.value = !this.value; - this.queue(); - - return true; - } - - @Override - public boolean applyPreviousValue() { - return this.applyNextValue(); - } - - @Override - public boolean applyOriginalValue() { - this.value = this.option.getDefaultValue(); - this.queue(); - - return true; - } - - @Override - public boolean isValueModified() { - return this.value != this.appliedValue; - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java deleted file mode 100644 index 603f2b971..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java +++ /dev/null @@ -1,16 +0,0 @@ -package net.coderbot.iris.gui.element.widget; - -import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; - - -import java.util.Optional; - -public abstract class CommentedElementWidget extends AbstractElementWidget { - public CommentedElementWidget(T element) { - super(element); - } - - public abstract Optional getCommentTitle(); - - public abstract Optional getCommentBody(); -} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java deleted file mode 100644 index 0a76dbb88..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.coderbot.iris.gui.element.widget; - -import net.coderbot.iris.gui.GuiUtil; -import net.coderbot.iris.gui.NavigationController; -import net.coderbot.iris.gui.screen.ShaderPackScreen; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuLinkElement; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.I18n; - -import java.util.Optional; - -public class LinkElementWidget extends CommentedElementWidget { - private static final Component ARROW = new TextComponent(">"); - - private final String targetScreenId; - private final MutableComponent label; - - private NavigationController navigation; - private MutableComponent trimmedLabel = null; - private boolean isLabelTrimmed = false; - - public LinkElementWidget(OptionMenuLinkElement element) { - super(element); - - this.targetScreenId = element.targetScreenId; - this.label = GuiUtil.translateOrDefault(new TextComponent(element.targetScreenId), "screen." + element.targetScreenId); - } - - @Override - public void init(ShaderPackScreen screen, NavigationController navigation) { - this.navigation = navigation; - } - - @Override - public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - GuiUtil.bindIrisWidgetsTexture(); - GuiUtil.drawButton(poseStack, x, y, width, height, hovered, false); - - Font font = Minecraft.getMinecraft().font; - - int maxLabelWidth = width - 9; - - if (font.width(this.label) > maxLabelWidth) { - this.isLabelTrimmed = true; - } - - if (this.trimmedLabel == null) { - this.trimmedLabel = GuiUtil.shortenText(font, this.label, maxLabelWidth); - } - - int labelWidth = font.width(this.trimmedLabel); - - font.drawShadow(poseStack, this.trimmedLabel, x + (int)(width * 0.5) - (int)(labelWidth * 0.5) - (int)(0.5 * Math.max(labelWidth - (width - 18), 0)), y + 7, 0xFFFFFF); - font.draw(poseStack, ARROW, (x + width) - 9, y + 7, 0xFFFFFF); - - if (hovered && this.isLabelTrimmed) { - // To prevent other elements from being drawn on top of the tooltip - ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel(font, poseStack, this.label, mouseX + 2, mouseY - 16)); - } - } - - @Override - public boolean mouseClicked(double mx, double my, int button) { - if (button == GLFW.GLFW_MOUSE_BUTTON_1) { - this.navigation.open(targetScreenId); - GuiUtil.playButtonClickSound(); - - return true; - } - return super.mouseClicked(mx, my, button); - } - - @Override - public Optional getCommentTitle() { - return Optional.of(this.label); - } - - @Override - public Optional getCommentBody() { - String translation = "screen." + this.targetScreenId + ".comment"; - return Optional.ofNullable(I18n.exists(translation) ? I18n.format(translation) : null); - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java b/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java deleted file mode 100644 index 5003ee4b2..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java +++ /dev/null @@ -1,87 +0,0 @@ -package net.coderbot.iris.gui.element.widget; - -import net.coderbot.iris.Iris; -import net.coderbot.iris.gui.GuiUtil; -import net.coderbot.iris.gui.NavigationController; -import net.coderbot.iris.gui.element.ShaderPackOptionList; -import net.coderbot.iris.gui.element.screen.ElementWidgetScreenData; -import net.coderbot.iris.gui.screen.ShaderPackScreen; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuBooleanOptionElement; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuElementScreen; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuLinkElement; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuMainElementScreen; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuProfileElement; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuStringOptionElement; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuSubElementScreen; - -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; - -public final class OptionMenuConstructor { - private static final Map, WidgetProvider> WIDGET_CREATORS = new HashMap<>(); - private static final Map, ScreenDataProvider> SCREEN_DATA_CREATORS = new HashMap<>(); - - private OptionMenuConstructor() {} - - @SuppressWarnings("unchecked") - public static void registerWidget(Class element, WidgetProvider widget) { - WIDGET_CREATORS.put(element, (WidgetProvider) widget); - } - - @SuppressWarnings("unchecked") - public static void registerScreen(Class screen, ScreenDataProvider data) { - SCREEN_DATA_CREATORS.put(screen, (ScreenDataProvider) data); - } - - public static AbstractElementWidget createWidget(OptionMenuElement element) { - return WIDGET_CREATORS.getOrDefault(element.getClass(), e -> AbstractElementWidget.EMPTY).create(element); - } - - public static ElementWidgetScreenData createScreenData(OptionMenuElementScreen screen) { - return SCREEN_DATA_CREATORS.getOrDefault(screen.getClass(), s -> ElementWidgetScreenData.EMPTY).create(screen); - } - - @SuppressWarnings("unchecked") - public static void constructAndApplyToScreen(OptionMenuContainer container, ShaderPackScreen packScreen, ShaderPackOptionList optionList, NavigationController navigation) { - OptionMenuElementScreen screen = container.mainScreen; - - if (navigation.getCurrentScreen() != null && container.subScreens.containsKey(navigation.getCurrentScreen())) { - screen = container.subScreens.get(navigation.getCurrentScreen()); - } - - ElementWidgetScreenData data = createScreenData(screen); - - optionList.addHeader(data.heading, data.backButton); - optionList.addWidgets(screen.getColumnCount(), screen.elements.stream().map(element -> { - AbstractElementWidget widget = (AbstractElementWidget) createWidget(element); - widget.init(packScreen, navigation); - return widget; - }).collect(Collectors.toList())); - } - - static { - registerScreen(OptionMenuMainElementScreen.class, screen -> - new ElementWidgetScreenData(new TextComponent(Iris.getCurrentPackName()).append(Iris.isFallback() ? " (fallback)" : "").withStyle(ChatFormatting.BOLD), false)); - - registerScreen(OptionMenuSubElementScreen.class, screen -> - new ElementWidgetScreenData(GuiUtil.translateOrDefault(new TextComponent(screen.screenId), "screen." + screen.screenId), true)); - - registerWidget(OptionMenuBooleanOptionElement.class, BooleanElementWidget::new); - registerWidget(OptionMenuProfileElement.class, ProfileElementWidget::new); - registerWidget(OptionMenuLinkElement.class, LinkElementWidget::new); - - registerWidget(OptionMenuStringOptionElement.class, element -> - element.slider ? new SliderElementWidget(element) : new StringElementWidget(element)); - } - - public interface WidgetProvider { - AbstractElementWidget create(T element); - } - - public interface ScreenDataProvider { - ElementWidgetScreenData create(T screen); - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java deleted file mode 100644 index c839d63db..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java +++ /dev/null @@ -1,101 +0,0 @@ -package net.coderbot.iris.gui.element.widget; - -import net.coderbot.iris.Iris; -import net.coderbot.iris.gui.GuiUtil; -import net.coderbot.iris.gui.NavigationController; -import net.coderbot.iris.gui.screen.ShaderPackScreen; -import net.coderbot.iris.shaderpack.option.OptionSet; -import net.coderbot.iris.shaderpack.option.Profile; -import net.coderbot.iris.shaderpack.option.ProfileSet; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuProfileElement; -import net.coderbot.iris.shaderpack.option.values.OptionValues; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.I18n; - -import java.util.Optional; - -public class ProfileElementWidget extends BaseOptionElementWidget { - private static final MutableComponent PROFILE_LABEL = I18n.format("options.iris.profile"); - private static final MutableComponent PROFILE_CUSTOM = I18n.format("options.iris.profile.custom").withStyle(ChatFormatting.YELLOW); - - private Profile next; - private Profile previous; - private Component profileLabel; - - public ProfileElementWidget(OptionMenuProfileElement element) { - super(element); - } - - @Override - public void init(ShaderPackScreen screen, NavigationController navigation) { - super.init(screen, navigation); - this.setLabel(PROFILE_LABEL); - - ProfileSet profiles = this.element.profiles; - OptionSet options = this.element.options; - OptionValues pendingValues = this.element.getPendingOptionValues(); - - ProfileSet.ProfileResult result = profiles.scan(options, pendingValues); - - this.next = result.next; - this.previous = result.previous; - Optional profileName = result.current.map(p -> p.name); - - this.profileLabel = profileName.map(name -> GuiUtil.translateOrDefault(new TextComponent(name), "profile." + name)).orElse(PROFILE_CUSTOM); - } - - @Override - public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - this.updateRenderParams(width, width - (Minecraft.getMinecraft().font.width(PROFILE_LABEL) + 16)); - - this.renderOptionWithValue(poseStack, x, y, width, height, hovered); - } - - @Override - protected Component createValueLabel() { - return this.profileLabel; - } - - @Override - public Optional getCommentTitle() { - return Optional.of(PROFILE_LABEL); - } - - @Override - public String getCommentKey() { - return "profile.comment"; - } - - @Override - public boolean applyNextValue() { - if (this.next == null) { - return false; - } - - Iris.queueShaderPackOptionsFromProfile(this.next); - - return true; - } - - @Override - public boolean applyPreviousValue() { - if (this.previous == null) { - return false; - } - - Iris.queueShaderPackOptionsFromProfile(this.previous); - - return true; - } - - @Override - public boolean applyOriginalValue() { - return false; // Resetting options is the way to return to the "default profile" - } - - @Override - public boolean isValueModified() { - return false; - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java deleted file mode 100644 index c6e347108..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java +++ /dev/null @@ -1,115 +0,0 @@ -package net.coderbot.iris.gui.element.widget; - -import net.coderbot.iris.gui.GuiUtil; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuStringOptionElement; -import net.minecraft.client.Minecraft; - -public class SliderElementWidget extends StringElementWidget { - private static final int PREVIEW_SLIDER_WIDTH = 4; - private static final int ACTIVE_SLIDER_WIDTH = 6; - - private boolean mouseDown = false; - - public SliderElementWidget(OptionMenuStringOptionElement element) { - super(element); - } - - @Override - public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - this.updateRenderParams(width, 35); - - if (!hovered) { - this.renderOptionWithValue(poseStack, x, y, width, height, false, (float)valueIndex / (valueCount - 1), PREVIEW_SLIDER_WIDTH); - } else { - this.renderSlider(poseStack, x, y, width, height, mouseX, mouseY, tickDelta); - } - - if (Screen.hasShiftDown()) { - renderTooltip(poseStack, SET_TO_DEFAULT, mouseX, mouseY, hovered); - } else if (!this.screen.isDisplayingComment()) { - renderTooltip(poseStack, this.unmodifiedLabel, mouseX, mouseY, hovered); - } - - if (this.mouseDown) { - // Release if the mouse went off the slider - if (!hovered) { - this.onReleased(); - } - - whileDragging(x, width, mouseX); - } - } - - private void renderSlider(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta) { - GuiUtil.bindIrisWidgetsTexture(); - - // Draw background button - GuiUtil.drawButton(poseStack, x, y, width, height, false, false); - // Draw slider area - GuiUtil.drawButton(poseStack, x + 2, y + 2, width - 4, height - 4, false, true); - - // Range of x values the slider can occupy - int sliderSpace = (width - 8) - ACTIVE_SLIDER_WIDTH; - // Position of slider - int sliderPos = (x + 4) + (int)(((float)valueIndex / (valueCount - 1)) * sliderSpace); - // Draw slider - GuiUtil.drawButton(poseStack, sliderPos, y + 4, ACTIVE_SLIDER_WIDTH, height - 8, this.mouseDown, false); - - // Draw value label - Font font = Minecraft.getMinecraft().font; - font.drawShadow(poseStack, this.valueLabel, (int)(x + (width * 0.5)) - (int)(font.width(this.valueLabel) * 0.5), y + 7, 0xFFFFFF); - } - - private void whileDragging(int x, int width, int mouseX) { - float mousePositionAcrossWidget = Mth.clamp((float)(mouseX - (x + 4)) / (width - 8), 0, 1); - - int newValueIndex = Math.min(valueCount - 1, (int)(mousePositionAcrossWidget * valueCount)); - - if (valueIndex != newValueIndex) { - this.valueIndex = newValueIndex; - - this.updateLabels(); - } - } - - private void onReleased() { - mouseDown = false; - - this.queue(); - this.navigation.refresh(); - - GuiUtil.playButtonClickSound(); - } - - @Override - public boolean mouseClicked(double mx, double my, int button) { - if (button == GLFW.GLFW_MOUSE_BUTTON_1) { - if (Screen.hasShiftDown()) { - if (this.applyOriginalValue()) { - this.navigation.refresh(); - } - GuiUtil.playButtonClickSound(); - - return true; - } - - mouseDown = true; - GuiUtil.playButtonClickSound(); - - return true; - } - - // Do not use base widget's button click behavior - return false; - } - - @Override - public boolean mouseReleased(double mx, double my, int button) { - if (button == GLFW.GLFW_MOUSE_BUTTON_1) { - this.onReleased(); - - return true; - } - return super.mouseReleased(mx, my, button); - } -} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java deleted file mode 100644 index efcd0aabd..000000000 --- a/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java +++ /dev/null @@ -1,109 +0,0 @@ -package net.coderbot.iris.gui.element.widget; - -import net.coderbot.iris.Iris; -import net.coderbot.iris.gui.GuiUtil; -import net.coderbot.iris.gui.NavigationController; -import net.coderbot.iris.gui.screen.ShaderPackScreen; -import net.coderbot.iris.shaderpack.option.StringOption; -import net.coderbot.iris.shaderpack.option.menu.OptionMenuStringOptionElement; - -import java.util.List; - -public class StringElementWidget extends BaseOptionElementWidget { - protected final StringOption option; - - protected String appliedValue; - protected int valueCount; - protected int valueIndex; - - public StringElementWidget(OptionMenuStringOptionElement element) { - super(element); - - this.option = element.option; - } - - @Override - public void init(ShaderPackScreen screen, NavigationController navigation) { - super.init(screen, navigation); - - // The yet-to-be-applied value that has been queued (if that is the case) - // Might be equal to the applied value - String actualPendingValue = this.element.getPendingOptionValues().getStringValueOrDefault(this.option.getName()); - - // The value currently in use by the shader pack - this.appliedValue = this.element.getAppliedOptionValues().getStringValueOrDefault(this.option.getName()); - - this.setLabel(GuiUtil.translateOrDefault(new TextComponent(this.option.getName()), "option." + this.option.getName())); - - List values = this.option.getAllowedValues(); - - this.valueCount = values.size(); - this.valueIndex = values.indexOf(actualPendingValue); - } - - @Override - public void render(PoseStack poseStack, int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - this.updateRenderParams(width, 0); - - this.renderOptionWithValue(poseStack, x, y, width, height, hovered); - this.tryRenderTooltip(poseStack, mouseX, mouseY, hovered); - } - - private void increment(int amount) { - this.valueIndex = Math.max(this.valueIndex, 0); - - this.valueIndex = Math.floorMod(this.valueIndex + amount, this.valueCount); - } - - @Override - protected Component createValueLabel() { - return GuiUtil.translateOrDefault( - new TextComponent(getValue()).withStyle(style -> style.withColor(TextColor.fromRgb(0x6688ff))), - "value." + this.option.getName() + "." + getValue()); - } - - @Override - public String getCommentKey() { - return "option." + this.option.getName() + ".comment"; - } - - public String getValue() { - if (this.valueIndex < 0) { - return this.appliedValue; - } - return this.option.getAllowedValues().get(this.valueIndex); - } - - protected void queue() { - Iris.getShaderPackOptionQueue().put(this.option.getName(), this.getValue()); - } - - @Override - public boolean applyNextValue() { - this.increment(1); - this.queue(); - - return true; - } - - @Override - public boolean applyPreviousValue() { - this.increment(-1); - this.queue(); - - return true; - } - - @Override - public boolean applyOriginalValue() { - this.valueIndex = this.option.getAllowedValues().indexOf(this.option.getDefaultValue()); - this.queue(); - - return true; - } - - @Override - public boolean isValueModified() { - return !this.appliedValue.equals(this.getValue()); - } -} diff --git a/src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java b/src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java deleted file mode 100644 index 59e601eef..000000000 --- a/src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java +++ /dev/null @@ -1,68 +0,0 @@ -package net.coderbot.iris.gui.option; - -import net.coderbot.iris.Iris; -import net.coderbot.iris.pipeline.WorldRenderingPipeline; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.I18n; - -import java.io.IOException; - -public class IrisVideoSettings { - public static int shadowDistance = 32; - - // TODO: Tell the user to check in the shader options once that's supported. - private static final Component DISABLED_TOOLTIP = I18n.format("options.iris.shadowDistance.disabled"); - private static final Component ENABLED_TOOLTIP = I18n.format("options.iris.shadowDistance.enabled"); - - public static int getOverriddenShadowDistance(int base) { - return Iris.getPipelineManager().getPipeline() - .map(pipeline -> pipeline.getForcedShadowRenderDistanceChunksForDisplay().orElse(base)) - .orElse(base); - } - - public static boolean isShadowDistanceSliderEnabled() { - return Iris.getPipelineManager().getPipeline() - .map(pipeline -> !pipeline.getForcedShadowRenderDistanceChunksForDisplay().isPresent()) - .orElse(true); - } - - public static final ProgressOption RENDER_DISTANCE = new ShadowDistanceOption("options.iris.shadowDistance", 0.0D, 32.0D, 1.0F, (gameOptions) -> { - return (double) getOverriddenShadowDistance(shadowDistance); - }, (gameOptions, viewDistance) -> { - double outputShadowDistance = viewDistance; - shadowDistance = (int) outputShadowDistance; - try { - Iris.getIrisConfig().save(); - } catch (IOException e) { - e.printStackTrace(); - } - }, (gameOptions, option) -> { - int d = (int) option.get(gameOptions); - - WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); - - Component tooltip; - - if (pipeline != null) { - d = pipeline.getForcedShadowRenderDistanceChunksForDisplay().orElse(d); - - if (pipeline.getForcedShadowRenderDistanceChunksForDisplay().isPresent()) { - tooltip = DISABLED_TOOLTIP; - } else { - tooltip = ENABLED_TOOLTIP; - } - } else { - tooltip = ENABLED_TOOLTIP; - } - - option.setTooltip(Minecraft.getMinecraft().font.split(tooltip, 200)); - - if (d <= 0.0) { - return I18n.format("options.generic_value", I18n.format("options.iris.shadowDistance"), "0 (disabled)"); - } else { - return I18n.format("options.generic_value", - I18n.format("options.iris.shadowDistance"), - I18n.format("options.chunks", d)); - } - }); -} diff --git a/src/main/java/net/coderbot/iris/gui/option/ShaderPackSelectionButtonOption.java b/src/main/java/net/coderbot/iris/gui/option/ShaderPackSelectionButtonOption.java deleted file mode 100644 index 26f2c56c3..000000000 --- a/src/main/java/net/coderbot/iris/gui/option/ShaderPackSelectionButtonOption.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.coderbot.iris.gui.option; - -import codechicken.nei.config.OptionButton; -import net.coderbot.iris.gui.screen.ShaderPackScreen; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.I18n; - -public class ShaderPackSelectionButtonOption extends Option { - private final Screen parent; - private final Minecraft client; - - public ShaderPackSelectionButtonOption(Screen parent, Minecraft client) { - super("options.iris.shaderPackSelection"); - this.parent = parent; - this.client = client; - } - - @Override - public AbstractWidget createButton(Options options, int x, int y, int width) { - return new OptionButton( - x, y, width, 20, - this, - I18n.format("options.iris.shaderPackSelection"), - button -> client.setScreen(new ShaderPackScreen(parent)) - ); - } -} diff --git a/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceOption.java b/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceOption.java deleted file mode 100644 index b90e68746..000000000 --- a/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceOption.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.coderbot.iris.gui.option; - - -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Function; - -public class ShadowDistanceOption extends ProgressOption { - - public ShadowDistanceOption(String string, double d, double e, float f, Function function, BiConsumer biConsumer, BiFunction biFunction) { - super(string, d, e, f, function, biConsumer, biFunction); - } - - @Override - public AbstractWidget createButton(Options options, int x, int y, int width) { - AbstractWidget widget = new ShadowDistanceSliderButton(options, x, y, width, 20, this); - - widget.active = IrisVideoSettings.isShadowDistanceSliderEnabled(); - - return widget; - } -} diff --git a/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceSliderButton.java b/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceSliderButton.java deleted file mode 100644 index 706168651..000000000 --- a/src/main/java/net/coderbot/iris/gui/option/ShadowDistanceSliderButton.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.coderbot.iris.gui.option; - - -public class ShadowDistanceSliderButton extends SliderButton { - public ShadowDistanceSliderButton(Options gameOptions, int x, int y, int width, int height, ProgressOption option) { - super(gameOptions, x, y, width, height, option); - } - - public boolean isMouseOver(double mouseX, double mouseY) { - boolean actuallyActive = this.active; - this.active = true; - - // Temporarily set active to true so that isMouseOver doesn't immediately bail out. - // We don't just copy the code here in case some other mod wants to change how it works. - boolean mouseOver = super.isMouseOver(mouseX, mouseY); - - this.active = actuallyActive; - return mouseOver; - } -} diff --git a/src/main/java/net/coderbot/iris/gui/screen/HudHideable.java b/src/main/java/net/coderbot/iris/gui/screen/HudHideable.java deleted file mode 100644 index 71a88e4e2..000000000 --- a/src/main/java/net/coderbot/iris/gui/screen/HudHideable.java +++ /dev/null @@ -1,9 +0,0 @@ -package net.coderbot.iris.gui.screen; - -/** - * Screens implementing this will hide the player hand and HUD - * - * Only used for instanceof checks - */ -public interface HudHideable { -} diff --git a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java deleted file mode 100644 index 48735a195..000000000 --- a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java +++ /dev/null @@ -1,574 +0,0 @@ -package net.coderbot.iris.gui.screen; - -import net.coderbot.iris.Iris; -import net.coderbot.iris.gui.GuiUtil; -import net.coderbot.iris.gui.NavigationController; -import net.coderbot.iris.gui.element.ShaderPackOptionList; -import net.coderbot.iris.gui.element.ShaderPackSelectionList; -import net.coderbot.iris.gui.element.widget.AbstractElementWidget; -import net.coderbot.iris.gui.element.widget.CommentedElementWidget; -import net.coderbot.iris.shaderpack.ShaderPack; -import net.irisshaders.iris.api.v0.IrisApi; - -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.resources.I18n; -import net.minecraft.util.ChatComponentText; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Properties; -import java.util.Set; -import java.util.stream.Collectors; - -public class ShaderPackScreen extends GuiScreen implements HudHideable { - /** - * Queue rendering to happen on top of all elements. Useful for tooltips or dialogs. - */ - public static final Set TOP_LAYER_RENDER_QUEUE = new HashSet<>(); - - private static final Component SELECT_TITLE = I18n.format("pack.iris.select.title").withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC); - private static final Component CONFIGURE_TITLE = I18n.format("pack.iris.configure.title").withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC); - private static final int COMMENT_PANEL_WIDTH = 314; - - private final GuiScreen parent; - private final MutableComponent irisTextComponent; - - private ShaderPackSelectionList shaderPackList; - - private @Nullable ShaderPackOptionList shaderOptionList = null; - private @Nullable NavigationController navigation = null; - private GuiButton screenSwitchButton; - - private Component notificationDialog = null; - private int notificationDialogTimer = 0; - - private @Nullable AbstractElementWidget hoveredElement = null; - private Optional hoveredElementCommentTitle = Optional.empty(); - private List hoveredElementCommentBody = new ArrayList<>(); - private int hoveredElementCommentTimer = 0; - - private boolean optionMenuOpen = false; - - private boolean dropChanges = false; - private static String development = "Development Environment"; - private MutableComponent developmentComponent; - private MutableComponent updateComponent; - - private boolean guiHidden = false; - private float guiButtonHoverTimer = 0.0f; - - public ShaderPackScreen(GuiScreen parent) { - super(I18n.format("options.iris.shaderPackSelection.title")); - - this.parent = parent; - - String irisName = Iris.MODNAME + " " + Iris.getVersion(); - - if (irisName.contains("-development-environment")) { - this.developmentComponent = new ChatComponentText("Development Environment").withStyle(ChatFormatting.GOLD); - irisName = irisName.replace("-development-environment", ""); - } - - this.irisTextComponent = new TextComponent(irisName).withStyle(ChatFormatting.GRAY); - - refreshForChangedPack(); - } - - @Override - public void render(PoseStack poseStack, int mouseX, int mouseY, float delta) { - if (this.minecraft.level == null) { - this.renderBackground(poseStack); - } else if (!this.guiHidden) { - this.fillGradient(poseStack, 0, 0, width, height, 0x4F232323, 0x4F232323); - } - - if (!this.guiHidden) { - if (optionMenuOpen && this.shaderOptionList != null) { - this.shaderOptionList.render(poseStack, mouseX, mouseY, delta); - } else { - this.shaderPackList.render(poseStack, mouseX, mouseY, delta); - } - } - - float previousHoverTimer = this.guiButtonHoverTimer; - super.render(poseStack, mouseX, mouseY, delta); - if (previousHoverTimer == this.guiButtonHoverTimer) { - this.guiButtonHoverTimer = 0.0f; - } - - if (!this.guiHidden) { - drawCenteredString(poseStack, this.font, this.title, (int) (this.width * 0.5), 8, 0xFFFFFF); - - if (notificationDialog != null && notificationDialogTimer > 0) { - drawCenteredString(poseStack, this.font, notificationDialog, (int) (this.width * 0.5), 21, 0xFFFFFF); - } else { - if (optionMenuOpen) { - drawCenteredString(poseStack, this.font, CONFIGURE_TITLE, (int) (this.width * 0.5), 21, 0xFFFFFF); - } else { - drawCenteredString(poseStack, this.font, SELECT_TITLE, (int) (this.width * 0.5), 21, 0xFFFFFF); - } - } - - // Draw the comment panel - if (this.isDisplayingComment()) { - // Determine panel height and position - int panelHeight = Math.max(50, 18 + (this.hoveredElementCommentBody.size() * 10)); - int x = (int) (0.5 * this.width) - 157; - int y = this.height - (panelHeight + 4); - // Draw panel - GuiUtil.drawPanel(poseStack, x, y, COMMENT_PANEL_WIDTH, panelHeight); - // Draw text - this.font.drawShadow(poseStack, this.hoveredElementCommentTitle.orElse(TextComponent.EMPTY), x + 4, y + 4, 0xFFFFFF); - for (int i = 0; i < this.hoveredElementCommentBody.size(); i++) { - this.font.drawShadow(poseStack, this.hoveredElementCommentBody.get(i), x + 4, (y + 16) + (i * 10), 0xFFFFFF); - } - } - } - - // Render everything queued to render last - for (Runnable render : TOP_LAYER_RENDER_QUEUE) { - render.run(); - } - TOP_LAYER_RENDER_QUEUE.clear(); - - if (this.developmentComponent != null) { - this.font.drawShadow(poseStack, developmentComponent, 2, this.height - 10, 0xFFFFFF); - this.font.drawShadow(poseStack, irisTextComponent, 2, this.height - 20, 0xFFFFFF); - } else if (this.updateComponent != null) { - this.font.drawShadow(poseStack, updateComponent, 2, this.height - 10, 0xFFFFFF); - this.font.drawShadow(poseStack, irisTextComponent, 2, this.height - 20, 0xFFFFFF); - } else { - this.font.drawShadow(poseStack, irisTextComponent, 2, this.height - 10, 0xFFFFFF); - } - } - - @Override - protected void init() { - super.init(); - int bottomCenter = this.width / 2 - 50; - int topCenter = this.width / 2 - 76; - boolean inWorld = this.minecraft.level != null; - - this.children.remove(this.shaderPackList); - this.children.remove(this.shaderOptionList); - - this.shaderPackList = new ShaderPackSelectionList(this, this.minecraft, this.width, this.height, 32, this.height - 58, 0, this.width); - - if (Iris.getCurrentPack().isPresent() && this.navigation != null) { - ShaderPack currentPack = Iris.getCurrentPack().get(); - - this.shaderOptionList = new ShaderPackOptionList(this, this.navigation, currentPack, this.minecraft, this.width, this.height, 32, this.height - 58, 0, this.width); - this.navigation.setActiveOptionList(this.shaderOptionList); - - this.shaderOptionList.rebuild(); - } else { - optionMenuOpen = false; - this.shaderOptionList = null; - } - - if (inWorld) { - this.shaderPackList.setRenderBackground(false); - if (shaderOptionList != null) { - this.shaderOptionList.setRenderBackground(false); - } - } - - this.buttons.clear(); - this.children.clear(); - - if (!this.guiHidden) { - if (optionMenuOpen && shaderOptionList != null) { - this.children.add(shaderOptionList); - } else { - this.children.add(shaderPackList); - } - - this.addButton(new Button(bottomCenter + 104, this.height - 27, 100, 20, - CommonComponents.GUI_DONE, button -> onClose())); - - this.addButton(new Button(bottomCenter, this.height - 27, 100, 20, - I18n.format("options.iris.apply"), button -> this.applyChanges())); - - this.addButton(new Button(bottomCenter - 104, this.height - 27, 100, 20, - CommonComponents.GUI_CANCEL, button -> this.dropChangesAndClose())); - - this.addButton(new Button(topCenter - 78, this.height - 51, 152, 20, - I18n.format("options.iris.openShaderPackFolder"), button -> openShaderPackFolder())); - - this.screenSwitchButton = this.addButton(new Button(topCenter + 78, this.height - 51, 152, 20, - I18n.format("options.iris.shaderPackList"), button -> { - this.optionMenuOpen = !this.optionMenuOpen; - - // UX: Apply changes before switching screens to avoid unintuitive behavior - // - // Not doing this leads to unintuitive behavior, since selecting a pack in the - // list (but not applying) would open the settings for the previous pack, rather - // than opening the settings for the selected (but not applied) pack. - this.applyChanges(); - - this.init(); - } - )); - - refreshScreenSwitchButton(); - } - - if (inWorld) { - Component showOrHide = this.guiHidden - ? I18n.format("options.iris.gui.show") - : I18n.format("options.iris.gui.hide"); - - float endOfLastButton = this.width / 2.0f + 154.0f; - float freeSpace = this.width - endOfLastButton; - int x; - if (freeSpace > 100.0f) { - x = this.width - 50; - } else if (freeSpace < 20.0f) { - x = this.width - 20; - } else { - x = (int) (endOfLastButton + (freeSpace / 2.0f)) - 10; - } - - this.addButton(new ImageButton( - x, this.height - 39, - 20, 20, - this.guiHidden ? 20 : 0, 146, 20, - GuiUtil.IRIS_WIDGETS_TEX, - 256, 256, - button -> { - this.guiHidden = !this.guiHidden; - this.init(); - }, - (button, poseStack, i, j) -> { - this.guiButtonHoverTimer += this.minecraft.getDeltaFrameTime(); - if (this.guiButtonHoverTimer >= 10.0f) { - TOP_LAYER_RENDER_QUEUE.add(() -> this.renderTooltip(poseStack, showOrHide, i, j)); - } - }, - showOrHide - )); - } - - // NB: Don't let comment remain when exiting options screen - // https://github.com/IrisShaders/Iris/issues/1494 - this.hoveredElement = null; - this.hoveredElementCommentTimer = 0; - } - - public void refreshForChangedPack() { - if (Iris.getCurrentPack().isPresent()) { - ShaderPack currentPack = Iris.getCurrentPack().get(); - - this.navigation = new NavigationController(currentPack.getMenuContainer()); - - if (this.shaderOptionList != null) { - this.shaderOptionList.applyShaderPack(currentPack); - this.shaderOptionList.rebuild(); - } - } else { - this.navigation = null; - } - - refreshScreenSwitchButton(); - } - - public void refreshScreenSwitchButton() { - if (this.screenSwitchButton != null) { - this.screenSwitchButton.setMessage( - optionMenuOpen ? - I18n.format("options.iris.shaderPackList") - : I18n.format("options.iris.shaderPackSettings") - ); - this.screenSwitchButton.active = optionMenuOpen || shaderPackList.getTopButtonRow().shadersEnabled; - } - } - - @Override - public void tick() { - super.tick(); - - if (this.notificationDialogTimer > 0) { - this.notificationDialogTimer--; - } - - if (this.hoveredElement != null) { - this.hoveredElementCommentTimer++; - } else { - this.hoveredElementCommentTimer = 0; - } - } - - @Override - public boolean keyPressed(int key, int j, int k) { - if (key == GLFW.GLFW_KEY_ESCAPE) { - if (this.guiHidden) { - this.guiHidden = false; - this.init(); - - return true; - } else if (this.navigation != null && this.navigation.hasHistory()) { - this.navigation.back(); - - return true; - } else if (this.optionMenuOpen) { - this.optionMenuOpen = false; - this.init(); - - return true; - } - } - - return this.guiHidden || super.keyPressed(key, j, k); - } - - @Override - public void onFilesDrop(List paths) { - if (this.optionMenuOpen) { - onOptionMenuFilesDrop(paths); - } else { - onPackListFilesDrop(paths); - } - } - - public void onPackListFilesDrop(List paths) { - List packs = paths.stream().filter(Iris::isValidShaderpack).collect(Collectors.toList()); - - for (Path pack : packs) { - String fileName = pack.getFileName().toString(); - - try { - Iris.getShaderpacksDirectoryManager().copyPackIntoDirectory(fileName, pack); - } catch (FileAlreadyExistsException e) { - this.notificationDialog = I18n.format( - "options.iris.shaderPackSelection.copyErrorAlreadyExists", - fileName - ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); - - this.notificationDialogTimer = 100; - this.shaderPackList.refresh(); - - return; - } catch (IOException e) { - Iris.logger.warn("Error copying dragged shader pack", e); - - this.notificationDialog = I18n.format( - "options.iris.shaderPackSelection.copyError", - fileName - ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); - - this.notificationDialogTimer = 100; - this.shaderPackList.refresh(); - - return; - } - } - - // After copying the relevant files over to the folder, make sure to refresh the shader pack list. - this.shaderPackList.refresh(); - - if (packs.size() == 0) { - // If zero packs were added, then notify the user that the files that they added weren't actually shader - // packs. - - if (paths.size() == 1) { - // If a single pack could not be added, provide a message with that pack in the file name - String fileName = paths.get(0).getFileName().toString(); - - this.notificationDialog = I18n.format( - "options.iris.shaderPackSelection.failedAddSingle", - fileName - ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); - } else { - // Otherwise, show a generic message. - - this.notificationDialog = I18n.format( - "options.iris.shaderPackSelection.failedAdd" - ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); - } - - } else if (packs.size() == 1) { - // In most cases, users will drag a single pack into the selection menu. So, let's special case it. - String packName = packs.get(0).getFileName().toString(); - - this.notificationDialog = I18n.format( - "options.iris.shaderPackSelection.addedPack", - packName - ).withStyle(ChatFormatting.ITALIC, ChatFormatting.YELLOW); - - // Select the pack that the user just added, since if a user just dragged a pack in, they'll probably want - // to actually use that pack afterwards. - this.shaderPackList.select(packName); - } else { - // We also support multiple packs being dragged and dropped at a time. Just show a generic success message - // in that case. - this.notificationDialog = I18n.format( - "options.iris.shaderPackSelection.addedPacks", - packs.size() - ).withStyle(ChatFormatting.ITALIC, ChatFormatting.YELLOW); - } - - // Show the relevant message for 5 seconds (100 ticks) - this.notificationDialogTimer = 100; - } - - public void displayNotification(Component component) { - this.notificationDialog = component; - this.notificationDialogTimer = 100; - } - - public void onOptionMenuFilesDrop(List paths) { - // If more than one option file has been dragged, display an error - // as only one option file should be imported at a time - if (paths.size() != 1) { - this.notificationDialog = I18n.format( - "options.iris.shaderPackOptions.tooManyFiles" - ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); - this.notificationDialogTimer = 100; // 5 seconds (100 ticks) - - return; - } - - this.importPackOptions(paths.get(0)); - } - - public void importPackOptions(Path settingFile) { - try (InputStream in = Files.newInputStream(settingFile)) { - Properties properties = new Properties(); - properties.load(in); - - Iris.queueShaderPackOptionsFromProperties(properties); - - this.notificationDialog = I18n.format( - "options.iris.shaderPackOptions.importedSettings", - settingFile.getFileName().toString() - ).withStyle(ChatFormatting.ITALIC, ChatFormatting.YELLOW); - this.notificationDialogTimer = 100; // 5 seconds (100 ticks) - - if (this.navigation != null) { - this.navigation.refresh(); - } - } catch (Exception e) { - // If the file could not be properly parsed or loaded, - // log the error and display a message to the user - Iris.logger.error("Error importing shader settings file \""+ settingFile.toString() +"\"", e); - - this.notificationDialog = I18n.format( - "options.iris.shaderPackOptions.failedImport", - settingFile.getFileName().toString() - ).withStyle(ChatFormatting.ITALIC, ChatFormatting.RED); - this.notificationDialogTimer = 100; // 5 seconds (100 ticks) - } - } - - @Override - public void onClose() { - if (!dropChanges) { - applyChanges(); - } else { - discardChanges(); - } - - this.minecraft.setScreen(parent); - } - - private void dropChangesAndClose() { - dropChanges = true; - onClose(); - } - - public void applyChanges() { - ShaderPackSelectionList.BaseEntry base = this.shaderPackList.getSelected(); - - if (!(base instanceof ShaderPackSelectionList.ShaderPackEntry)) { - return; - } - - ShaderPackSelectionList.ShaderPackEntry entry = (ShaderPackSelectionList.ShaderPackEntry)base; - this.shaderPackList.setApplied(entry); - - String name = entry.getPackName(); - - // If the pack is being changed, clear pending options from the previous pack to - // avoid possible undefined behavior from applying one pack's options to another pack - if (!name.equals(Iris.getCurrentPackName())) { - Iris.clearShaderPackOptionQueue(); - } - - boolean enabled = this.shaderPackList.getTopButtonRow().shadersEnabled; - - String previousPackName = Iris.getIrisConfig().getShaderPackName().orElse(null); - boolean previousShadersEnabled = Iris.getIrisConfig().areShadersEnabled(); - - // Only reload if the pack would be different from before, or shaders were toggled, or options were changed, or if we're about to reset options. - if (!name.equals(previousPackName) || enabled != previousShadersEnabled || !Iris.getShaderPackOptionQueue().isEmpty() || Iris.shouldResetShaderPackOptionsOnNextReload()) { - Iris.getIrisConfig().setShaderPackName(name); - IrisApi.getInstance().getConfig().setShadersEnabledAndApply(enabled); - } - - refreshForChangedPack(); - } - - private void discardChanges() { - Iris.clearShaderPackOptionQueue(); - } - - private void openShaderPackFolder() { - Util.getPlatform().openUri(Iris.getShaderpacksDirectoryManager().getDirectoryUri()); - } - - // Let the screen know if an element is hovered or not, allowing for accurately updating which element is hovered - public void setElementHoveredStatus(AbstractElementWidget widget, boolean hovered) { - if (hovered && widget != this.hoveredElement) { - this.hoveredElement = widget; - - if (widget instanceof CommentedElementWidget) { - this.hoveredElementCommentTitle = ((CommentedElementWidget) widget).getCommentTitle(); - - Optional commentBody = ((CommentedElementWidget) widget).getCommentBody(); - if (!commentBody.isPresent()) { - this.hoveredElementCommentBody.clear(); - } else { - String rawCommentBody = commentBody.get().getString(); - - // Strip any trailing "."s - if (rawCommentBody.endsWith(".")) { - rawCommentBody = rawCommentBody.substring(0, rawCommentBody.length() - 1); - } - // Split comment body into lines by separator ". " - List splitByPeriods = Arrays.stream(rawCommentBody.split("\\. [ ]*")).map(TextComponent::new).collect(Collectors.toList()); - // Line wrap - this.hoveredElementCommentBody = new ArrayList<>(); - for (MutableComponent text : splitByPeriods) { - this.hoveredElementCommentBody.addAll(this.font.split(text, COMMENT_PANEL_WIDTH - 8)); - } - } - } else { - this.hoveredElementCommentTitle = Optional.empty(); - this.hoveredElementCommentBody.clear(); - } - - this.hoveredElementCommentTimer = 0; - } else if (!hovered && widget == this.hoveredElement) { - this.hoveredElement = null; - this.hoveredElementCommentTitle = Optional.empty(); - this.hoveredElementCommentBody.clear(); - this.hoveredElementCommentTimer = 0; - } - } - - public boolean isDisplayingComment() { - return this.hoveredElementCommentTimer > 20 && - this.hoveredElementCommentTitle.isPresent() && - !this.hoveredElementCommentBody.isEmpty(); - } -} diff --git a/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java index bdbde7db8..f14e19251 100644 --- a/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java @@ -1,5 +1,6 @@ package net.coderbot.iris.layer; +import net.coderbot.iris.compat.mojang.RenderStateShard; import net.coderbot.iris.uniforms.CapturedRenderingState; public final class BlockEntityRenderStateShard extends RenderStateShard { diff --git a/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java index c4e648b76..91c0d31c4 100644 --- a/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java @@ -1,5 +1,6 @@ package net.coderbot.iris.layer; +import net.coderbot.iris.compat.mojang.RenderStateShard; import net.coderbot.iris.uniforms.CapturedRenderingState; public final class EntityRenderStateShard extends RenderStateShard { diff --git a/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java index 9650bcfe5..3b7247f8b 100644 --- a/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java @@ -1,5 +1,6 @@ package net.coderbot.iris.layer; +import net.coderbot.iris.compat.mojang.RenderStateShard; public class IsBlockEntityRenderStateShard extends RenderStateShard { public static final IsBlockEntityRenderStateShard INSTANCE = new IsBlockEntityRenderStateShard(); diff --git a/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java index a0b262786..c032f8bf2 100644 --- a/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java @@ -1,5 +1,6 @@ package net.coderbot.iris.layer; +import net.coderbot.iris.compat.mojang.RenderStateShard; public class IsEntityRenderStateShard extends RenderStateShard { public static final IsEntityRenderStateShard INSTANCE = new IsEntityRenderStateShard(); diff --git a/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java index 21db48abe..c6f29b64e 100644 --- a/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java @@ -1,5 +1,6 @@ package net.coderbot.iris.layer; +import net.coderbot.iris.compat.mojang.RenderStateShard; public class IsOutlineRenderStateShard extends RenderStateShard { public static final IsOutlineRenderStateShard INSTANCE = new IsOutlineRenderStateShard(); diff --git a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java index 7a2d07c28..5e9daff4d 100644 --- a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java +++ b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java @@ -1,6 +1,8 @@ package net.coderbot.iris.layer; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; +import net.coderbot.iris.compat.mojang.RenderStateShard; +import net.coderbot.iris.compat.mojang.RenderType; import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -83,6 +85,8 @@ public String toString() { } private static boolean shouldSortOnUpload(RenderType type) { - return ((RenderTypeAccessor) type).shouldSortOnUpload(); + return true; + // TODO: Iris +// return ((RenderTypeAccessor) type).shouldSortOnUpload(); } } diff --git a/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java b/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java index bf8b49f1b..5a12861d6 100644 --- a/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java +++ b/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java @@ -16,7 +16,9 @@ import net.coderbot.iris.texture.pbr.PBRType; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.renderer.texture.ITextureObject; import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.renderer.texture.TextureUtil; import net.minecraft.util.ResourceLocation; import org.apache.commons.io.FilenameUtils; import org.lwjgl.opengl.GL11; @@ -81,13 +83,14 @@ private IntSupplier createCustomTexture(CustomTextureData textureData) throws IO ownedTextures.add(texture); return texture::getGlTextureId; - } else if (textureData instanceof CustomTextureData.LightmapMarker) { - // Special code path for the light texture. While shader packs hardcode the primary light texture, it's - // possible that a mod will create a different light texture, so this code path is robust to that. - return () -> - ((LightTextureAccessor) Minecraft.getMinecraft().gameRenderer.lightTexture()) - .getLightTexture().getId(); - } else if (textureData instanceof CustomTextureData.ResourceData) { + } + // TODO: Iris +// else if (textureData instanceof CustomTextureData.LightmapMarker) { +// // Special code path for the light texture. While shader packs hardcode the primary light texture, it's +// // possible that a mod will create a different light texture, so this code path is robust to that. +// return () -> ((LightTextureAccessor) Minecraft.getMinecraft().gameRenderer.lightTexture()).getLightTexture().getId(); +// } + else if (textureData instanceof CustomTextureData.ResourceData) { CustomTextureData.ResourceData resourceData = (CustomTextureData.ResourceData) textureData; String namespace = resourceData.getNamespace(); String location = resourceData.getLocation(); @@ -112,17 +115,17 @@ private IntSupplier createCustomTexture(CustomTextureData textureData) throws IO // reloads. Re-fetching the texture from the TextureManager every time is the most robust approach for // now. return () -> { - AbstractTexture texture = textureManager.getTexture(textureLocation); + ITextureObject texture = textureManager.getTexture(textureLocation); // TODO: Should we give something else if the texture isn't there? This will need some thought - return texture != null ? texture.getId() : MissingTextureAtlasSprite.getTexture().getId(); + return texture != null ? texture.getGlTextureId() : TextureUtil.missingTexture.getGlTextureId(); }; } else { location = location.substring(0, extensionIndex - pbrType.getSuffix().length()) + location.substring(extensionIndex); ResourceLocation textureLocation = new ResourceLocation(namespace, location); return () -> { - AbstractTexture texture = textureManager.getTexture(textureLocation); + ITextureObject texture = textureManager.getTexture(textureLocation); if (texture != null) { int id = texture.getGlTextureId(); @@ -150,7 +153,8 @@ private IntSupplier createCustomTexture(CustomTextureData textureData) throws IO return pbrTexture.getGlTextureId(); } - return MissingTextureAtlasSprite.getTexture().getId(); +// return MissingTextureAtlasSprite.getTexture().getId(); + return TextureUtil.missingTexture.getGlTextureId(); }; } } else { @@ -171,6 +175,7 @@ public IntSupplier getNoiseTexture() { } public void destroy() { - ownedTextures.forEach(AbstractTexture::close); + // TODO :Iris +// ownedTextures.forEach(AbstractTexture::close); } } diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index f72068a71..22d299575 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -6,6 +6,8 @@ import net.coderbot.iris.Iris; import net.coderbot.iris.block_rendering.BlockMaterialMapping; import net.coderbot.iris.block_rendering.BlockRenderingSettings; +import net.coderbot.iris.compat.mojang.Camera; +import net.coderbot.iris.compat.mojang.LevelRenderer; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.ProgramTable; import net.coderbot.iris.gbuffer_overrides.matching.RenderCondition; @@ -28,7 +30,6 @@ import net.coderbot.iris.postprocess.CenterDepthSampler; import net.coderbot.iris.postprocess.CompositeRenderer; import net.coderbot.iris.postprocess.FinalPassRenderer; -import net.coderbot.iris.rendertarget.Blaze3dRenderTargetExt; import net.coderbot.iris.rendertarget.NativeImageBackedSingleColorTexture; import net.coderbot.iris.rendertarget.RenderTarget; import net.coderbot.iris.rendertarget.RenderTargets; @@ -164,14 +165,16 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { this.packDirectives = programs.getPackDirectives(); - RenderTarget mainTarget = Minecraft.getMinecraft().getMainRenderTarget(); + // TODO: IRIS +// RenderTarget mainTarget = Minecraft.getMinecraft().getMainRenderTarget(); + RenderTarget mainTarget = null; - int depthTextureId = mainTarget.getDepthTextureId(); + int depthTextureId = 0; //mainTarget.getDepthTextureId(); int internalFormat = TextureInfoCache.INSTANCE.getInfo(depthTextureId).getInternalFormat(); DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); - this.renderTargets = new RenderTargets(mainTarget.width, mainTarget.height, depthTextureId, - ((Blaze3dRenderTargetExt) mainTarget).iris$getDepthBufferVersion(), + this.renderTargets = new RenderTargets(/*mainTarget.width, mainTarget.height,*/ 0, 0, depthTextureId, + 0 /*((Blaze3dRenderTargetExt) mainTarget).iris$getDepthBufferVersion()*/, depthBufferFormat, programs.getPackDirectives().getRenderTargetDirectives().getRenderTargetSettings(), programs.getPackDirectives()); this.sunPathRotation = programs.getPackDirectives().getSunPathRotation(); @@ -190,8 +193,8 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { forcedShadowRenderDistanceChunks = OptionalInt.empty(); } - BlockRenderingSettings.INSTANCE.setBlockStateIds( - BlockMaterialMapping.createBlockStateIdMap(programs.getPack().getIdMap().getBlockProperties())); + // TODO: BlockStateIdMap + BlockRenderingSettings.INSTANCE.setBlockStateIds(BlockMaterialMapping.createBlockStateIdMap(programs.getPack().getIdMap().getBlockProperties())); BlockRenderingSettings.INSTANCE.setBlockTypeIds(BlockMaterialMapping.createBlockTypeMap(programs.getPack().getIdMap().getBlockRenderTypeMap())); BlockRenderingSettings.INSTANCE.setEntityIds(programs.getPack().getIdMap().getEntityIdMap()); @@ -526,7 +529,10 @@ private RenderCondition getCondition(WorldRenderingPhase phase) { case TERRAIN_CUTOUT_MIPPED: return RenderCondition.TERRAIN_OPAQUE; case ENTITIES: - if (GlStateManagerAccessor.getBLEND().srcRgb == GlStateManager.SourceFactor.SRC_ALPHA.value && GlStateManagerAccessor.getBLEND().dstRgb == GlStateManager.SourceFactor.ONE_MINUS_SRC_ALPHA.value && GlStateManagerAccessor.getBLEND().srcAlpha == GlStateManager.SourceFactor.ONE.value && GlStateManagerAccessor.getBLEND().dstAlpha == GlStateManager.SourceFactor.ONE_MINUS_SRC_ALPHA.value) { + if (true /*GlStateManagerAccessor.getBLEND().srcRgb == GlStateManager.SourceFactor.SRC_ALPHA.value + && GlStateManagerAccessor.getBLEND().dstRgb == GlStateManager.SourceFactor.ONE_MINUS_SRC_ALPHA.value + && GlStateManagerAccessor.getBLEND().srcAlpha == GlStateManager.SourceFactor.ONE.value + && GlStateManagerAccessor.getBLEND().dstAlpha == GlStateManager.SourceFactor.ONE_MINUS_SRC_ALPHA.value*/) { return RenderCondition.ENTITIES_TRANSLUCENT; } else { return RenderCondition.ENTITIES; @@ -761,8 +767,8 @@ public void use() { if (shadowViewport) { GL11.glViewport(0, 0, shadowMapResolution, shadowMapResolution); } else { - RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); - GL11.glViewport(0, 0, main.width, main.height); +// RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); + GL11.glViewport(0, 0, /*main.getWidth(), main.getHeight()*/0,0); } if (program != null && !sodiumTerrainRendering) { @@ -832,7 +838,7 @@ public void destroy() { OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_DRAW_FRAMEBUFFER, 0); OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, 0); - Minecraft.getMinecraft().getMainRenderTarget().bindWrite(false); +// Minecraft.getMinecraft().getMainRenderTarget().bindWrite(false); // Destroy our render targets // @@ -847,7 +853,7 @@ public void destroy() { // Destroy custom textures and the static samplers (normals, specular, and noise) customTextureManager.destroy(); - whitePixel.releaseId(); +// whitePixel.releaseId(); } private static void destroyPasses(ProgramTable table) { @@ -910,15 +916,15 @@ private void prepareRenderTargets() { } } - RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); - Blaze3dRenderTargetExt mainExt = (Blaze3dRenderTargetExt) main; +// RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); +// Blaze3dRenderTargetExt mainExt = (Blaze3dRenderTargetExt) main; - int depthTextureId = main.getDepthTextureId(); - int internalFormat = TextureInfoCache.INSTANCE.getInfo(depthTextureId).getInternalFormat(); - DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); +// int depthTextureId = main.getDepthTextureId(); +// int internalFormat = TextureInfoCache.INSTANCE.getInfo(depthTextureId).getInternalFormat(); +// DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); - boolean changed = renderTargets.resizeIfNeeded(mainExt.iris$getDepthBufferVersion(), depthTextureId, main.width, - main.height, depthBufferFormat, packDirectives); + boolean changed = true;//renderTargets.resizeIfNeeded(mainExt.iris$getDepthBufferVersion(), depthTextureId, main.width, +// main.height, depthBufferFormat, packDirectives); if (changed) { prepareRenderer.recalculateSizes(); @@ -955,7 +961,7 @@ private void prepareRenderTargets() { } // Reset framebuffer and viewport - Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); +// Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); } private ComputeProgram[] createShadowComputes(ComputeSource[] compute, ProgramSet programSet) { @@ -1033,8 +1039,8 @@ public void beginTranslucents() { deferredRenderer.renderAll(); - RenderSystem.enableBlend(); - RenderSystem.enableAlphaTest(); + GL11.glEnable(GL11.GL_BLEND); + GL11.glEnable(GL11.GL_ALPHA_TEST); // note: we are careful not to touch the lightmap texture unit or overlay color texture unit here, // so we don't need to do anything to restore them if needed. @@ -1049,7 +1055,7 @@ public void beginTranslucents() { } @Override - public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCamera) { + public void renderShadows(LevelRenderer levelRenderer, Camera playerCamera) { if (shouldRenderPrepareBeforeShadow) { isRenderingFullScreenPass = true; @@ -1130,9 +1136,9 @@ public void beginLevelRendering() { // while rendering the sky. // // A lot of dimension mods touch sky rendering, FabricSkyboxes injects at HEAD and cancels, etc. - DimensionSpecialEffects.SkyType skyType = Minecraft.getMinecraft().theWorld.effects().skyType(); +// DimensionSpecialEffects.SkyType skyType = Minecraft.getMinecraft().theWorld.effects().skyType(); - if (skyType == DimensionSpecialEffects.SkyType.NORMAL) { + if (true/*skyType == DimensionSpecialEffects.SkyType.NORMAL*/) { GL11.glDisable(GL11.GL_TEXTURE_2D); GL11.glDepthMask(false); @@ -1254,8 +1260,8 @@ public int getCurrentSpecularTexture() { public void onBindTexture(int id) { if (shouldBindPBR && isRenderingWorld) { PBRTextureHolder pbrHolder = PBRTextureManager.INSTANCE.getOrLoadHolder(id); - currentNormalTexture = pbrHolder.getNormalTexture().getId(); - currentSpecularTexture = pbrHolder.getSpecularTexture().getId(); + currentNormalTexture = pbrHolder.getNormalTexture().getGlTextureId(); + currentSpecularTexture = pbrHolder.getSpecularTexture().getGlTextureId(); TextureFormat textureFormat = TextureFormatLoader.getFormat(); if (textureFormat != null) { diff --git a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java index d8b7103c7..b580d06f7 100644 --- a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java @@ -1,12 +1,13 @@ package net.coderbot.iris.pipeline; import net.coderbot.iris.block_rendering.BlockRenderingSettings; +import net.coderbot.iris.compat.mojang.Camera; +import net.coderbot.iris.compat.mojang.LevelRenderer; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; import net.coderbot.iris.shaderpack.CloudSetting; import net.coderbot.iris.uniforms.FrameUpdateNotifier; -import net.minecraft.client.Minecraft; import org.lwjgl.opengl.GL20; import java.util.List; @@ -24,12 +25,13 @@ public FixedFunctionWorldRenderingPipeline() { @Override public void beginLevelRendering() { // Use the default Minecraft framebuffer and ensure that no programs are in use - Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); + // TODO: Iris +// Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); GL20.glUseProgram(0); } @Override - public void renderShadows(LevelRendererAccessor levelRenderer, Camera camera) { + public void renderShadows(LevelRenderer levelRenderer, Camera camera) { // stub: nothing to do here } diff --git a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java index ac463eb06..d5d8c5fd6 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java @@ -1,9 +1,14 @@ package net.coderbot.iris.pipeline; import net.coderbot.batchedentityrendering.impl.FullyBufferedMultiBufferSource; -import net.coderbot.iris.uniforms.CapturedRenderingState; +import net.coderbot.iris.compat.mojang.Camera; +import net.coderbot.iris.compat.mojang.GameRenderer; +import net.coderbot.iris.compat.mojang.InteractionHand; +import net.coderbot.iris.compat.mojang.PoseStack; import net.irisshaders.iris.api.v0.IrisApi; import net.minecraft.client.Minecraft; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import org.joml.Matrix4f; @@ -21,35 +26,45 @@ private void setupGlState(GameRenderer gameRenderer, Camera camera, PoseStack po final PoseStack.Pose pose = poseStack.last(); // We need to scale the matrix by 0.125 so the hand doesn't clip through blocks. - Matrix4f scaleMatrix = Matrix4f.createScaleMatrix(1F, 1F, DEPTH); - scaleMatrix.multiply(gameRenderer.getProjectionMatrix(camera, tickDelta, false)); - gameRenderer.resetProjectionMatrix(scaleMatrix); - - pose.pose().setIdentity(); - pose.normal().setIdentity(); - - ((GameRendererAccessor) gameRenderer).invokeBobHurt(poseStack, tickDelta); - - if (Minecraft.getMinecraft().gameSettings.bobView) { - ((GameRendererAccessor) gameRenderer).invokeBobView(poseStack, tickDelta); + Matrix4f scaleMatrix = new Matrix4f().scale(1F, 1F, DEPTH); + // TODO: ProjectionMatrix +// scaleMatrix.multiply(gameRenderer.getProjectionMatrix(camera, tickDelta, false)); +// scaleMatrix.mul(projectionMatrix); +// RenderSystem.matrixMode(5889); +// RenderSystem.loadIdentity(); +// RenderSystem.multMatrix(arg); +// RenderSystem.matrixMode(5888); + + pose.pose().identity(); + pose.normal().identity(); + + gameRenderer.invokeBobHurt(poseStack, tickDelta); + + if (Minecraft.getMinecraft().gameSettings.viewBobbing) { + gameRenderer.invokeBobView(poseStack, tickDelta); } } private boolean canRender(Camera camera, GameRenderer gameRenderer) { - return !(!((GameRendererAccessor) gameRenderer).getRenderHand() + return !(!gameRenderer.getRenderHand() || camera.isDetached() - || !(camera.getEntity() instanceof Player) - || ((GameRendererAccessor)gameRenderer).getPanoramicMode() - || Minecraft.getMinecraft().gameSettings.hideGui - || (camera.getEntity() instanceof LivingEntity && ((LivingEntity)camera.getEntity()).isSleeping()) - || Minecraft.getMinecraft().gameMode.getPlayerMode() == GameType.SPECTATOR); + || !(camera.getEntity() instanceof EntityPlayer) + || gameRenderer.getPanoramicMode() + || Minecraft.getMinecraft().gameSettings.hideGUI + || (camera.getEntity() instanceof EntityLiving && ((EntityLiving)camera.getEntity()).isPlayerSleeping()) + // TODO: SPECTATOR + /*|| Minecraft.getMinecraft().gameMode.getPlayerMode() == GameType.SPECTATOR*/); } public boolean isHandTranslucent(InteractionHand hand) { - Item item = Minecraft.getMinecraft().thePlayer.getItemBySlot(hand == InteractionHand.OFF_HAND ? EquipmentSlot.OFFHAND : EquipmentSlot.MAINHAND).getItem(); + // TODO: Offhand +// Item item = Minecraft.getMinecraft().thePlayer.getItemBySlot(hand == InteractionHand.OFF_HAND ? EquipmentSlot.OFFHAND : EquipmentSlot.MAINHAND).getItem(); + Item item = Minecraft.getMinecraft().thePlayer.getHeldItem().getItem(); if (item instanceof ItemBlock itemBlock) { - return ItemBlockRenderTypes.getChunkRenderType(itemBlock.getBlock().defaultBlockState()) == RenderType.translucent(); + // TODO: RenderType +// return ItemBlockRenderTypes.getChunkRenderType(itemBlock.getBlock().defaultBlockState()) == RenderType.translucent(); + return false; } return false; @@ -70,17 +85,18 @@ public void renderSolid(PoseStack poseStack, float tickDelta, Camera camera, Gam poseStack.pushPose(); - Minecraft.getMinecraft().mcProfiler.push("iris_hand"); + Minecraft.getMinecraft().mcProfiler.startSection("iris_hand"); setupGlState(gameRenderer, camera, poseStack, tickDelta); renderingSolid = true; - - Minecraft.getMinecraft().getItemInHandRenderer().renderHandsWithItems(tickDelta, poseStack, bufferSource, Minecraft.getMinecraft().thePlayer, Minecraft.getMinecraft().getEntityRenderDispatcher().getPackedLightCoords(camera.getEntity(), tickDelta)); + // TODO: Hand +// Minecraft.getMinecraft().getItemInHandRenderer().renderHandsWithItems(tickDelta, poseStack, bufferSource, Minecraft.getMinecraft().thePlayer, Minecraft.getMinecraft().getEntityRenderDispatcher().getPackedLightCoords(camera.getEntity(), tickDelta)); Minecraft.getMinecraft().mcProfiler.endSection(); - gameRenderer.resetProjectionMatrix(CapturedRenderingState.INSTANCE.getGbufferProjection()); + // TODO: ProjectionMatrix +// gameRenderer.resetProjectionMatrix(CapturedRenderingState.INSTANCE.getGbufferProjection()); poseStack.popPose(); @@ -108,13 +124,15 @@ public void renderTranslucent(PoseStack poseStack, float tickDelta, Camera camer setupGlState(gameRenderer, camera, poseStack, tickDelta); - Minecraft.getMinecraft().getItemInHandRenderer().renderHandsWithItems(tickDelta, poseStack, bufferSource, Minecraft.getMinecraft().thePlayer, Minecraft.getMinecraft().getEntityRenderDispatcher().getPackedLightCoords(camera.getEntity(), tickDelta)); + // TODO: Hand +// Minecraft.getMinecraft().getItemInHandRenderer().renderHandsWithItems(tickDelta, poseStack, bufferSource, Minecraft.getMinecraft().thePlayer, Minecraft.getMinecraft().getEntityRenderDispatcher().getPackedLightCoords(camera.getEntity(), tickDelta)); poseStack.popPose(); Minecraft.getMinecraft().mcProfiler.endSection(); - gameRenderer.resetProjectionMatrix(CapturedRenderingState.INSTANCE.getGbufferProjection()); + // TODO: ProjectionMatrix +// gameRenderer.resetProjectionMatrix(CapturedRenderingState.INSTANCE.getGbufferProjection()); bufferSource.endBatch(); diff --git a/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java index a2a88b219..8fa1ee876 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java @@ -1,5 +1,9 @@ package net.coderbot.iris.pipeline; +import net.coderbot.iris.compat.mojang.BufferBuilder; +import net.coderbot.iris.compat.mojang.DefaultVertexFormat; +import net.coderbot.iris.compat.mojang.VertexBuffer; +import net.coderbot.iris.compat.mojang.VertexConsumer; import net.minecraft.client.Minecraft; import org.joml.Matrix4f; import org.lwjgl.opengl.GL11; @@ -49,7 +53,8 @@ private void rebuildBuffer() { this.buffer.close(); } - BufferBuilder buffer = Tesselator.getInstance().getBuilder(); +// BufferBuilder buffer = Tesselator.getInstance().getBuilder(); + BufferBuilder buffer = new BufferBuilder(); // Build the horizon quads into a buffer buffer.begin(GL11.GL_QUADS, DefaultVertexFormat.POSITION); diff --git a/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java b/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java index 5dd9c8eeb..fbacbe020 100644 --- a/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java +++ b/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java @@ -36,7 +36,8 @@ public WorldRenderingPipeline preparePipeline(DimensionId currentDimension) { if (BlockRenderingSettings.INSTANCE.isReloadRequired()) { if (Minecraft.getMinecraft().renderGlobal != null) { - Minecraft.getMinecraft().renderGlobal.allChanged(); + // TODO: Iris +// Minecraft.getMinecraft().renderGlobal.allChanged(); } BlockRenderingSettings.INSTANCE.clearReloadRequired(); diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index ad54f7fef..2a32ab513 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -5,8 +5,13 @@ import net.coderbot.batchedentityrendering.impl.DrawCallTrackingRenderBuffers; import net.coderbot.batchedentityrendering.impl.RenderBuffersExt; import net.coderbot.iris.Iris; +import net.coderbot.iris.compat.mojang.BufferSource; +import net.coderbot.iris.compat.mojang.Camera; +import net.coderbot.iris.compat.mojang.LevelRenderer; +import net.coderbot.iris.compat.mojang.PoseStack; +import net.coderbot.iris.compat.mojang.RenderBuffers; +import net.coderbot.iris.compat.mojang.RenderType; import net.coderbot.iris.gl.IrisRenderSystem; -import net.coderbot.iris.gui.option.IrisVideoSettings; import net.coderbot.iris.shaderpack.OptionalBoolean; import net.coderbot.iris.shaderpack.PackDirectives; import net.coderbot.iris.shaderpack.PackShadowDirectives; @@ -26,6 +31,7 @@ import net.coderbot.iris.uniforms.CelestialUniforms; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.entity.Entity; import net.minecraft.profiler.Profiler; import net.minecraft.tileentity.TileEntity; @@ -40,7 +46,6 @@ import org.lwjgl.opengl.GL30; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.Objects; @@ -147,7 +152,8 @@ private static WorldClient getLevel() { } private static float getSkyAngle() { - return getLevel().getTimeOfDay(CapturedRenderingState.INSTANCE.getTickDelta()); + return getLevel().getWorldTime(); +// return getLevel().getTimeOfDay(CapturedRenderingState.INSTANCE.getTickDelta()); } private static float getSunAngle() { @@ -271,7 +277,9 @@ private FrustumHolder createShadowFrustum(float renderMultiplier, FrustumHolder String setter = "(set by shader pack)"; if (renderMultiplier < 0) { - distance = IrisVideoSettings.shadowDistance * 16; + // TODO: GUI +// distance = IrisVideoSettings.shadowDistance * 16; + distance = 32 * 16; setter = "(set by user)"; } @@ -335,8 +343,9 @@ private void copyPreTranslucentDepth() { targets.copyPreTranslucentDepth(); } - private void renderEntities(LevelRendererAccessor levelRenderer, Frustum frustum, MultiBufferSource.BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { - EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); + private void renderEntities(LevelRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { + // TODO: Render +// EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); int shadowEntities = 0; @@ -345,59 +354,63 @@ private void renderEntities(LevelRendererAccessor levelRenderer, Frustum frustum List renderedEntities = new ArrayList<>(32); // TODO: I'm sure that this can be improved / optimized. - for (Entity entity : getLevel().entitiesForRendering()) { - if (!dispatcher.shouldRender(entity, frustum, cameraX, cameraY, cameraZ) || entity.isSpectator()) { - continue; - } - - renderedEntities.add(entity); - } + // TODO: Render +// for (Entity entity : getLevel().entitiesForRendering()) { +// if (!dispatcher.shouldRender(entity, frustum, cameraX, cameraY, cameraZ) || entity.isSpectator()) { +// continue; +// } +// +// renderedEntities.add(entity); +// } profiler.endStartSection("sort"); + // TODO: Render // Sort the entities by type first in order to allow vanilla's entity batching system to work better. - renderedEntities.sort(Comparator.comparingInt(entity -> entity.getType().hashCode())); +// renderedEntities.sort(Comparator.comparingInt(entity -> entity.getType().hashCode())); profiler.endStartSection("build geometry"); - for (Entity entity : renderedEntities) { - levelRenderer.invokeRenderEntity(entity, cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); - shadowEntities++; - } + // TODO: Render +// for (Entity entity : renderedEntities) { +// levelRenderer.invokeRenderEntity(entity, cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); +// shadowEntities++; +// } renderedShadowEntities = shadowEntities; profiler.endSection(); } - private void renderPlayerEntity(LevelRendererAccessor levelRenderer, Frustum frustum, MultiBufferSource.BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { - EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); + private void renderPlayerEntity(LevelRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { + // TODO: Render +// EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); profiler.startSection("cull"); Entity player = Minecraft.getMinecraft().thePlayer; - if (!dispatcher.shouldRender(player, frustum, cameraX, cameraY, cameraZ) || player.isSpectator()) { - return; - } +// if (!dispatcher.shouldRender(player, frustum, cameraX, cameraY, cameraZ) || player.isSpectator()) { +// return; +// } profiler.endStartSection("build geometry"); int shadowEntities = 0; - if (!player.getPassengers().isEmpty()) { - for (int i = 0; i < player.getPassengers().size(); i++) { - levelRenderer.invokeRenderEntity(player.getPassengers().get(i), cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); - shadowEntities++; - } - } - - if (player.getVehicle() != null) { - levelRenderer.invokeRenderEntity(player.getVehicle(), cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); - shadowEntities++; - } - - levelRenderer.invokeRenderEntity(player, cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); +// if (!player.getPassengers().isEmpty()) { +// for (int i = 0; i < player.getPassengers().size(); i++) { +// levelRenderer.invokeRenderEntity(player.getPassengers().get(i), cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); +// shadowEntities++; +// } +// } +// +// if (player.getVehicle() != null) { +// levelRenderer.invokeRenderEntity(player.getVehicle(), cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); +// shadowEntities++; +// } +// +// levelRenderer.invokeRenderEntity(player, cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); shadowEntities++; @@ -406,7 +419,7 @@ private void renderPlayerEntity(LevelRendererAccessor levelRenderer, Frustum fru profiler.endSection(); } - private void renderBlockEntities(MultiBufferSource.BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta, boolean hasEntityFrustum) { + private void renderBlockEntities(BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta, boolean hasEntityFrustum) { profiler.startSection("build blockentities"); int shadowBlockEntities = 0; @@ -423,8 +436,9 @@ private void renderBlockEntities(MultiBufferSource.BufferSource bufferSource, Po } } modelView.pushPose(); + // TODO: Render modelView.translate(entity.xCoord - cameraX, entity.yCoord - cameraY, entity.zCoord - cameraZ); - BlockEntityRenderDispatcher.instance.render(entity, tickDelta, modelView, bufferSource); +// BlockEntityRenderDispatcher.instance.render(entity, tickDelta, modelView, bufferSource); modelView.popPose(); shadowBlockEntities++; @@ -435,7 +449,7 @@ private void renderBlockEntities(MultiBufferSource.BufferSource bufferSource, Po profiler.endSection(); } - public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCamera) { + public void renderShadows(LevelRenderer levelRenderer, Camera playerCamera) { // We have to re-query this each frame since this changes based on whether the profiler is active // If the profiler is inactive, it will return InactiveProfiler.INSTANCE this.profiler = Minecraft.getMinecraft().mcProfiler; @@ -446,14 +460,16 @@ public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCame ACTIVE = true; // NB: We store the previous player buffers in order to be able to allow mods rendering entities in the shadow pass (Flywheel) to use the shadow buffers instead. - RenderBuffers playerBuffers = levelRenderer.getRenderBuffers(); - levelRenderer.setRenderBuffers(buffers); + // TODO: Render +// RenderBuffers playerBuffers = levelRenderer.getRenderBuffers(); +// levelRenderer.setRenderBuffers(buffers); visibleTileEntities = new ArrayList<>(); // Create our camera PoseStack modelView = createShadowModelView(this.sunPathRotation, this.intervalSize); - MODELVIEW = modelView.last().pose().copy(); + // TODO: Render +// MODELVIEW = modelView.last().pose().copy(); float[] projMatrix; if (this.fov != null) { // If FOV is not null, the pack wants a perspective based projection matrix. (This is to support legacy packs) @@ -465,13 +481,13 @@ public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCame PROJECTION = new Matrix4f(); ((Matrix4fAccess) (Object) PROJECTION).copyFromArray(projMatrix); - profiler.push("terrain_setup"); + profiler.startSection("terrain_setup"); if (levelRenderer instanceof CullingDataCache) { ((CullingDataCache) levelRenderer).saveState(); } - profiler.push("initialize frustum"); + profiler.startSection("initialize frustum"); terrainFrustumHolder = createShadowFrustum(renderDistanceMultiplier, terrainFrustumHolder); @@ -483,7 +499,8 @@ public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCame double cameraZ = cameraPos.z(); // Center the frustum on the player camera position - terrainFrustumHolder.getFrustum().prepare(cameraX, cameraY, cameraZ); + // TODO: Render +// terrainFrustumHolder.getFrustum().prepare(cameraX, cameraY, cameraZ); profiler.endSection(); @@ -491,26 +508,27 @@ public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCame // as-is, however in the future it will be good to work on restoring it for a nice performance boost. // // TODO: Get chunk occlusion working with shadows - boolean wasChunkCullingEnabled = client.smartCull; - client.smartCull = false; + // TODO: Render +// boolean wasChunkCullingEnabled = client.smartCull; +// client.smartCull = false; // Always schedule a terrain update // TODO: Only schedule a terrain update if the sun / moon is moving, or the shadow map camera moved. // We have to ensure that we don't regenerate clouds every frame, since that's what needsUpdate ends up doing. // This took up to 10% of the frame time before we applied this fix! That's really bad! - boolean regenerateClouds = levelRenderer.shouldRegenerateClouds(); - ((LevelRenderer) levelRenderer).needsUpdate(); - levelRenderer.setShouldRegenerateClouds(regenerateClouds); +// boolean regenerateClouds = levelRenderer.shouldRegenerateClouds(); +// ((LevelRenderer) levelRenderer).needsUpdate(); +// levelRenderer.setShouldRegenerateClouds(regenerateClouds); // Execute the vanilla terrain setup / culling routines using our shadow frustum. - levelRenderer.invokeSetupRender(playerCamera, terrainFrustumHolder.getFrustum(), false, levelRenderer.getFrameId(), false); +// levelRenderer.invokeSetupRender(playerCamera, terrainFrustumHolder.getFrustum(), false, levelRenderer.getFrameId(), false); // Don't forget to increment the frame counter! This variable is arbitrary and only used in terrain setup, // and if it's not incremented, the vanilla culling code will get confused and think that it's already seen // chunks during traversal, and break rendering in concerning ways. - levelRenderer.setFrameId(levelRenderer.getFrameId() + 1); +// levelRenderer.setFrameId(levelRenderer.getFrameId() + 1); - client.smartCull = wasChunkCullingEnabled; +// client.smartCull = wasChunkCullingEnabled; profiler.endStartSection("terrain"); @@ -540,8 +558,8 @@ public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCame entityFrustumHolder = createShadowFrustum(renderDistanceMultiplier * entityShadowDistanceMultiplier, entityFrustumHolder); } - Frustum entityShadowFrustum = entityFrustumHolder.getFrustum(); - entityShadowFrustum.prepare(cameraX, cameraY, cameraZ); + Frustrum entityShadowFrustum = entityFrustumHolder.getFrustum(); + entityShadowFrustum.setPosition(cameraX, cameraY, cameraZ); // Render nearby entities // @@ -555,7 +573,7 @@ public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCame ((DrawCallTrackingRenderBuffers) buffers).resetDrawCounts(); } - MultiBufferSource.BufferSource bufferSource = buffers.bufferSource(); + BufferSource bufferSource = buffers.bufferSource(); if (shouldRenderEntities) { renderEntities(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); @@ -592,7 +610,8 @@ public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCame renderBuffersExt.endLevelRendering(); } - debugStringTerrain = ((LevelRenderer) levelRenderer).getChunkStatistics(); + // TODO: Render +// debugStringTerrain = ((LevelRenderer) levelRenderer).getChunkStatistics(); profiler.endStartSection("generate mipmaps"); @@ -606,7 +625,8 @@ public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCame ((CullingDataCache) levelRenderer).restoreState(); } - levelRenderer.setRenderBuffers(playerBuffers); + // TODO: Render +// levelRenderer.setRenderBuffers(playerBuffers); ACTIVE = false; profiler.endSection(); diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java index 71230de51..0bfda9ed9 100644 --- a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java @@ -1,5 +1,6 @@ package net.coderbot.iris.pipeline; +import net.coderbot.iris.compat.mojang.RenderType; public enum WorldRenderingPhase { NONE, diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java index 6a735c065..2bdc1ff4e 100644 --- a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java @@ -1,5 +1,7 @@ package net.coderbot.iris.pipeline; +import net.coderbot.iris.compat.mojang.Camera; +import net.coderbot.iris.compat.mojang.LevelRenderer; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; @@ -11,7 +13,7 @@ public interface WorldRenderingPipeline { void beginLevelRendering(); - void renderShadows(LevelRendererAccessor levelRenderer, Camera camera); + void renderShadows(LevelRenderer levelRenderer, Camera camera); void addDebugText(List messages); OptionalInt getForcedShadowRenderDistanceChunksForDisplay(); diff --git a/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java b/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java index e33126517..9e8711fa6 100644 --- a/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java +++ b/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java @@ -13,7 +13,6 @@ import net.coderbot.iris.gl.texture.PixelType; import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; import net.coderbot.iris.uniforms.SystemTimeUniforms; -import net.minecraft.client.Minecraft; import org.apache.commons.io.IOUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; @@ -93,7 +92,8 @@ public void sampleCenterDepth() { DepthCopyStrategy.fastest(false).copy(this.framebuffer, texture, null, altTexture, 1, 1); //Reset viewport - Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); + // TODO: Iris +// Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); } public void setupColorTexture(int texture, InternalTextureFormat format) { diff --git a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java index b40e85347..23b78e3c7 100644 --- a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java @@ -208,14 +208,17 @@ public void renderAll() { GL11.glDisable(GL11.GL_ALPHA_TEST); FullScreenQuadRenderer.INSTANCE.begin(); - + final Minecraft mc = Minecraft.getMinecraft(); for (Pass renderPass : passes) { boolean ranCompute = false; for (ComputeProgram computeProgram : renderPass.computes) { if (computeProgram != null) { ranCompute = true; - com.mojang.blaze3d.pipeline.RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); - computeProgram.dispatch(main.width, main.height); + + // TODO: Iris +// com.mojang.blaze3d.pipeline.RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); +// computeProgram.dispatch(main.width, main.height); + computeProgram.dispatch(mc.displayWidth, mc.displayHeight); } } @@ -251,7 +254,8 @@ public void renderAll() { // Make sure to reset the viewport to how it was before... Otherwise weird issues could occur. // Also bind the "main" framebuffer if it isn't already bound. - Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); + // TODO: Iris +// Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); ProgramUniforms.clearActiveUniforms(); ProgramSamplers.clearActiveSamplers(); GL20.glUseProgram(0); diff --git a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java index a8701f3a2..4957ffbc5 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java @@ -15,7 +15,6 @@ import net.coderbot.iris.pipeline.PatchedShaderPrinter; import net.coderbot.iris.pipeline.transform.PatchShaderType; import net.coderbot.iris.pipeline.transform.TransformPatcher; -import net.coderbot.iris.rendertarget.Blaze3dRenderTargetExt; import net.coderbot.iris.rendertarget.RenderTarget; import net.coderbot.iris.rendertarget.RenderTargets; import net.coderbot.iris.samplers.IrisImages; @@ -93,8 +92,9 @@ public FinalPassRenderer(ProgramSet pack, RenderTargets renderTargets, IntSuppli // passes that write to framebuffers). this.baseline = renderTargets.createGbufferFramebuffer(flippedBuffers, new int[] {0}); this.colorHolder = new GlFramebuffer(); - this.lastColorTextureId = Minecraft.getMinecraft().getMainRenderTarget().getColorTextureId(); - this.lastColorTextureVersion = ((Blaze3dRenderTargetExt) Minecraft.getMinecraft().getMainRenderTarget()).iris$getColorBufferVersion(); + // TODO: Iris + this.lastColorTextureId = 0; //Minecraft.getMinecraft().getMainRenderTarget().getColorTextureId(); + this.lastColorTextureVersion = 0; //((Blaze3dRenderTargetExt) Minecraft.getMinecraft().getMainRenderTarget()).iris$getColorBufferVersion(); this.colorHolder.addColorAttachment(0, lastColorTextureId); // TODO: We don't actually fully swap the content, we merely copy it from alt to main @@ -151,9 +151,9 @@ public void renderFinalPass() { GL11.glDisable(GL11.GL_ALPHA_TEST); GL11.glDepthMask(false); - final com.mojang.blaze3d.pipeline.RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); - final int baseWidth = main.width; - final int baseHeight = main.height; + final Minecraft mc = Minecraft.getMinecraft(); + final int baseWidth = mc.displayWidth; + final int baseHeight = mc.displayHeight; // Note that since DeferredWorldRenderingPipeline uses the depth texture of the main Minecraft framebuffer, // we'll be writing to that depth buffer directly automatically and won't need to futz around with copying @@ -168,11 +168,13 @@ public void renderFinalPass() { // // This is not a concern for depthtex1 / depthtex2 since the copy call extracts the depth values, and the // shader pack only ever uses them to read the depth values. - if (((Blaze3dRenderTargetExt) main).iris$getColorBufferVersion() != lastColorTextureVersion || main.getColorTextureId() != lastColorTextureId) { - lastColorTextureVersion = ((Blaze3dRenderTargetExt) main).iris$getColorBufferVersion(); - this.lastColorTextureId = main.getColorTextureId(); - colorHolder.addColorAttachment(0, lastColorTextureId); - } + + // TODO: Iris +// if (((Blaze3dRenderTargetExt) main).iris$getColorBufferVersion() != lastColorTextureVersion || main.getColorTextureId() != lastColorTextureId) { +// lastColorTextureVersion = ((Blaze3dRenderTargetExt) main).iris$getColorBufferVersion(); +// this.lastColorTextureId = main.getColorTextureId(); +// colorHolder.addColorAttachment(0, lastColorTextureId); +// } if (this.finalPass != null) { // If there is a final pass, we use the shader-based full screen quad rendering pathway instead @@ -215,7 +217,8 @@ public void renderFinalPass() { // https://stackoverflow.com/a/23994979/18166885 this.baseline.bindAsReadBuffer(); - IrisRenderSystem.copyTexSubImage2D(main.getColorTextureId(), GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, baseWidth, baseHeight); + // TODO: Iris + IrisRenderSystem.copyTexSubImage2D(0/*main.getColorTextureId()*/, GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, baseWidth, baseHeight); } GL13.glActiveTexture(GL13.GL_TEXTURE0); @@ -242,7 +245,8 @@ public void renderFinalPass() { // Make sure to reset the viewport to how it was before... Otherwise weird issues could occur. // Also bind the "main" framebuffer if it isn't already bound. - main.bindWrite(true); + // TODO: Iris +// main.bindWrite(true); ProgramUniforms.clearActiveUniforms(); ProgramSamplers.clearActiveSamplers(); GL20.glUseProgram(0); diff --git a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java index 2acbbc9b3..3f9492e12 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java @@ -1,6 +1,7 @@ package net.coderbot.iris.postprocess; import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.compat.mojang.DefaultVertexFormat; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; diff --git a/src/main/java/net/coderbot/iris/rendertarget/Blaze3dRenderTargetExt.java b/src/main/java/net/coderbot/iris/rendertarget/Blaze3dRenderTargetExt.java deleted file mode 100644 index 207ece1d0..000000000 --- a/src/main/java/net/coderbot/iris/rendertarget/Blaze3dRenderTargetExt.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.coderbot.iris.rendertarget; - -public interface Blaze3dRenderTargetExt { - int iris$getDepthBufferVersion(); - - int iris$getColorBufferVersion(); -} diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java index 8d694222f..3a809e10a 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java @@ -1,5 +1,6 @@ package net.coderbot.iris.rendertarget; +import net.coderbot.iris.compat.mojang.NativeImage; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.shaderpack.texture.CustomTextureData; import net.minecraft.client.renderer.texture.DynamicTexture; @@ -8,7 +9,6 @@ import java.io.IOException; import java.nio.ByteBuffer; -import java.util.Objects; public class NativeImageBackedCustomTexture extends DynamicTexture { public NativeImageBackedCustomTexture(CustomTextureData.PngData textureData) throws IOException { @@ -34,12 +34,4 @@ private static NativeImage create(byte[] content) throws IOException { return NativeImage.read(buffer); } - - @Override - public void upload() { - NativeImage image = Objects.requireNonNull(getPixels()); - - bind(); - image.upload(0, 0, 0, 0, 0, image.getWidth(), image.getHeight(), false, false, false, false); - } } diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java index da6ecb0e0..68b15b375 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java @@ -1,8 +1,9 @@ package net.coderbot.iris.rendertarget; +import net.coderbot.iris.compat.mojang.NativeImage; import net.minecraft.client.renderer.texture.DynamicTexture; +import org.lwjgl.opengl.GL11; -import java.util.Objects; import java.util.Random; public class NativeImageBackedNoiseTexture extends DynamicTexture { @@ -26,10 +27,10 @@ private static NativeImage create(int size) { } @Override - public void upload() { - NativeImage image = Objects.requireNonNull(getPixels()); + public void updateDynamicTexture() { + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + super.updateDynamicTexture(); + } - bind(); - image.upload(0, 0, 0, 0, 0, image.getWidth(), image.getHeight(), true, false, false, false); - } } diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java index 71eb2720c..162c14285 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java @@ -1,5 +1,6 @@ package net.coderbot.iris.rendertarget; +import net.coderbot.iris.compat.mojang.NativeImage; import net.minecraft.client.renderer.texture.DynamicTexture; public class NativeImageBackedSingleColorTexture extends DynamicTexture { diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java index 685ee3e7c..257505426 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java @@ -1,5 +1,6 @@ package net.coderbot.iris.rendertarget; +import lombok.Getter; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.texture.InternalTextureFormat; import net.coderbot.iris.gl.texture.PixelFormat; @@ -15,8 +16,10 @@ public class RenderTarget { private final InternalTextureFormat internalFormat; private final PixelFormat format; private final PixelType type; - private int width; - private int height; + @Getter + private int width; + @Getter + private int height; private boolean isValid; private final int mainTexture; @@ -94,15 +97,7 @@ public int getAltTexture() { return altTexture; } - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public void destroy() { + public void destroy() { requireValid(); isValid = false; GL11.glDeleteTextures(mainTexture); diff --git a/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java b/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java index 25cfa95cf..7fd4941bc 100644 --- a/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java +++ b/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java @@ -129,20 +129,20 @@ public static void addLevelSamplers(SamplerHolder samplers, WorldRenderingPipeli samplers.addExternalSampler(ALBEDO_TEXTURE_UNIT, "tex", "texture", "gtexture"); } else { // TODO: Rebind unbound sampler IDs instead of hardcoding a list... - samplers.addDynamicSampler(whitePixel::getId, "tex", "texture", "gtexture", + samplers.addDynamicSampler(whitePixel::getGlTextureId, "tex", "texture", "gtexture", "gcolor", "colortex0"); } if (availability.lightmap) { samplers.addExternalSampler(LIGHTMAP_TEXTURE_UNIT, "lightmap"); } else { - samplers.addDynamicSampler(whitePixel::getId, "lightmap"); + samplers.addDynamicSampler(whitePixel::getGlTextureId, "lightmap"); } if (availability.overlay) { samplers.addExternalSampler(OVERLAY_TEXTURE_UNIT, "iris_overlay"); } else { - samplers.addDynamicSampler(whitePixel::getId, "iris_overlay"); + samplers.addDynamicSampler(whitePixel::getGlTextureId, "iris_overlay"); } samplers.addDynamicSampler(pipeline::getCurrentNormalTexture, StateUpdateNotifiers.normalTextureChangeNotifier, "normals"); diff --git a/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java b/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java index 304716b92..3f76073ba 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java +++ b/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java @@ -7,10 +7,9 @@ import com.google.gson.stream.JsonReader; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import lombok.Getter; import net.coderbot.iris.Iris; import net.coderbot.iris.features.FeatureFlags; -import net.coderbot.iris.gui.FeatureMissingErrorScreen; -import net.coderbot.iris.gui.screen.ShaderPackScreen; import net.coderbot.iris.shaderpack.include.AbsolutePackPath; import net.coderbot.iris.shaderpack.include.IncludeGraph; import net.coderbot.iris.shaderpack.include.IncludeProcessor; @@ -25,8 +24,6 @@ import net.coderbot.iris.shaderpack.texture.TextureFilteringData; import net.coderbot.iris.shaderpack.texture.TextureStage; import net.irisshaders.iris.api.v0.IrisApi; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.I18n; import org.jetbrains.annotations.Nullable; import java.io.BufferedReader; @@ -56,12 +53,17 @@ public class ShaderPack { private final ProgramSet nether; private final ProgramSet end; - private final IdMap idMap; - private final LanguageMap languageMap; - private final EnumMap> customTextureDataMap = new EnumMap<>(TextureStage.class); + @Getter + private final IdMap idMap; + @Getter + private final LanguageMap languageMap; + @Getter + private final EnumMap> customTextureDataMap = new EnumMap<>(TextureStage.class); private final CustomTextureData customNoiseTexture; - private final ShaderPackOptions shaderPackOptions; - private final OptionMenuContainer menuContainer; + @Getter + private final ShaderPackOptions shaderPackOptions; + @Getter + private final OptionMenuContainer menuContainer; private final ProfileSet.ProfileResult profile; private final String profileInfo; @@ -124,10 +126,11 @@ public ShaderPack(Path root, Map changedConfigs, Iterable invalidFeatureFlags = invalidFlagList.stream().map(FeatureFlags::getHumanReadableName).collect(Collectors.toList()); if (!invalidFeatureFlags.isEmpty()) { - if (Minecraft.getMinecraft().screen instanceof ShaderPackScreen) { - Minecraft.getMinecraft().setScreen(new FeatureMissingErrorScreen(Minecraft.getMinecraft().screen, I18n.format("iris.unsupported.pack"), I18n.format("iris.unsupported.pack.description", FeatureFlags.getInvalidStatus(invalidFlagList), invalidFeatureFlags.stream() - .collect(Collectors.joining(", ", ": ", "."))))); - } + // TODO: GUI +// if (Minecraft.getMinecraft().screen instanceof ShaderPackScreen) { +// Minecraft.getMinecraft().setScreen(new FeatureMissingErrorScreen(Minecraft.getMinecraft().screen, I18n.format("iris.unsupported.pack"), I18n.format("iris.unsupported.pack.description", FeatureFlags.getInvalidStatus(invalidFlagList), invalidFeatureFlags.stream() +// .collect(Collectors.joining(", ", ": ", "."))))); +// } IrisApi.getInstance().getConfig().setShadersEnabledAndApply(false); } @@ -348,23 +351,14 @@ private static String readProperties(Path shaderPath, String name) { } public ProgramSet getProgramSet(DimensionId dimension) { - ProgramSet overrides; - - switch (dimension) { - case OVERWORLD: - overrides = overworld; - break; - case NETHER: - overrides = nether; - break; - case END: - overrides = end; - break; - default: - throw new IllegalArgumentException("Unknown dimension " + dimension); - } - - // NB: If a dimension overrides directory is present, none of the files from the parent directory are "merged" + ProgramSet overrides = switch (dimension) { + case OVERWORLD -> overworld; + case NETHER -> nether; + case END -> end; + default -> throw new IllegalArgumentException("Unknown dimension " + dimension); + }; + + // NB: If a dimension overrides directory is present, none of the files from the parent directory are "merged" // into the override. Rather, we act as if the overrides directory contains a completely different set of // shader programs unrelated to that of the base shader pack. // @@ -379,27 +373,8 @@ public ProgramSet getProgramSet(DimensionId dimension) { } } - public IdMap getIdMap() { - return idMap; - } - - public EnumMap> getCustomTextureDataMap() { - return customTextureDataMap; - } - - public Optional getCustomNoiseTexture() { + public Optional getCustomNoiseTexture() { return Optional.ofNullable(customNoiseTexture); } - public LanguageMap getLanguageMap() { - return languageMap; - } - - public ShaderPackOptions getShaderPackOptions() { - return shaderPackOptions; - } - - public OptionMenuContainer getMenuContainer() { - return menuContainer; - } } diff --git a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java index 8d50ab9c0..0349baa7b 100644 --- a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java +++ b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java @@ -1,5 +1,6 @@ package net.coderbot.iris.shadow; +import net.coderbot.iris.compat.mojang.PoseStack; import org.joml.Matrix4f; import java.nio.FloatBuffer; @@ -47,13 +48,14 @@ public static void createBaselineModelViewMatrix(PoseStack target, float shadowA skyAngle = shadowAngle - 0.25f; } - target.last().normal().setIdentity(); - target.last().pose().setIdentity(); + target.last().normal().identity(); + target.last().pose().identity(); - target.last().pose().multiply(Matrix4f.createTranslateMatrix(0.0f, 0.0f, -100.0f)); - target.mulPose(Vector3f.XP.rotationDegrees(90.0F)); - target.mulPose(Vector3f.ZP.rotationDegrees(skyAngle * -360.0f)); - target.mulPose(Vector3f.XP.rotationDegrees(sunPathRotation)); + // TODO: Render +// target.last().pose().multiply(Matrix4f.createTranslateMatrix(0.0f, 0.0f, -100.0f)); +// target.mulPose(Vector3f.XP.rotationDegrees(90.0F)); +// target.mulPose(Vector3f.ZP.rotationDegrees(skyAngle * -360.0f)); +// target.mulPose(Vector3f.XP.rotationDegrees(sunPathRotation)); } public static void snapModelViewToGrid(PoseStack target, float shadowIntervalSize, double cameraX, double cameraY, double cameraZ) { @@ -84,7 +86,8 @@ public static void snapModelViewToGrid(PoseStack target, float shadowIntervalSiz offsetY -= halfIntervalSize; offsetZ -= halfIntervalSize; - target.last().pose().multiply(Matrix4f.createTranslateMatrix(offsetX, offsetY, offsetZ)); + // TODO: Render +// target.last().pose().multiply(Matrix4f.createTranslateMatrix(offsetX, offsetY, offsetZ)); } public static void createModelViewMatrix(PoseStack target, float shadowAngle, float shadowIntervalSize, @@ -162,7 +165,8 @@ public static void main(String[] args) { private static float[] toFloatArray(Matrix4f matrix4f) { FloatBuffer buffer = FloatBuffer.allocate(16); - matrix4f.store(buffer); + // TODO: Render +// matrix4f.store(buffer); return buffer.array(); } diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java index 188251ef4..7f17cf0d4 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java @@ -1,12 +1,10 @@ package net.coderbot.iris.shadows.frustum; +import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.util.AxisAlignedBB; import org.joml.Matrix4f; -public class CullEverythingFrustum extends Frustum { - public CullEverythingFrustum() { - super(new Matrix4f(), new Matrix4f()); - } +public class CullEverythingFrustum extends Frustrum { // for Sodium public boolean fastAabbTest(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { @@ -20,7 +18,7 @@ public boolean canDetermineInvisible(double minX, double minY, double minZ, doub } @Override - public boolean isVisible(AxisAlignedBB aabb) { + public boolean isBoundingBoxInFrustum(AxisAlignedBB aabb) { return false; } } diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/FrustumHolder.java b/src/main/java/net/coderbot/iris/shadows/frustum/FrustumHolder.java index 61a20b6c5..701bb70c1 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/FrustumHolder.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/FrustumHolder.java @@ -1,20 +1,20 @@ package net.coderbot.iris.shadows.frustum; -import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.client.renderer.culling.Frustrum; public class FrustumHolder { - private Frustum frustum; + private Frustrum frustum; private String distanceInfo = "(unavailable)"; private String cullingInfo = "(unavailable)"; - public FrustumHolder setInfo(Frustum frustum, String distanceInfo, String cullingInfo) { + public FrustumHolder setInfo(Frustrum frustum, String distanceInfo, String cullingInfo) { this.frustum = frustum; this.distanceInfo = distanceInfo; this.cullingInfo = cullingInfo; return this; } - public Frustum getFrustum() { + public Frustrum getFrustum() { return frustum; } diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java index c4e39eb1d..43d843c22 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/advanced/AdvancedShadowCullingFrustum.java @@ -1,6 +1,7 @@ package net.coderbot.iris.shadows.frustum.advanced; import net.coderbot.iris.shadows.frustum.BoxCuller; +import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.util.AxisAlignedBB; import org.joml.Math; import org.joml.Matrix4f; @@ -27,7 +28,7 @@ * are not sensitive to the specific internal ordering of planes and corners, in order to avoid potential bugs at the * cost of slightly more computations.

*/ -public class AdvancedShadowCullingFrustum extends Frustum { +public class AdvancedShadowCullingFrustum extends Frustrum { private static final int MAX_CLIPPING_PLANES = 13; /** @@ -71,9 +72,6 @@ public class AdvancedShadowCullingFrustum extends Frustum { public AdvancedShadowCullingFrustum(Matrix4f playerView, Matrix4f playerProjection, Vector3f shadowLightVectorFromOrigin, BoxCuller boxCuller) { - // We're overriding all of the methods, don't pass any matrices down. - super(new com.mojang.math.Matrix4f(), new com.mojang.math.Matrix4f()); - this.shadowLightVectorFromOrigin = shadowLightVectorFromOrigin; BaseClippingPlanes baseClippingPlanes = new BaseClippingPlanes(playerView, playerProjection); @@ -267,7 +265,7 @@ private void addEdgePlane(Vector4f backPlane4, Vector4f frontPlane4) { // Note: These functions are copied & modified from the vanilla Frustum class. @Override - public void prepare(double cameraX, double cameraY, double cameraZ) { + public void setPosition(double cameraX, double cameraY, double cameraZ) { if (this.boxCuller != null) { boxCuller.setPosition(cameraX, cameraY, cameraZ); } @@ -278,7 +276,7 @@ public void prepare(double cameraX, double cameraY, double cameraZ) { } @Override - public boolean isVisible(AxisAlignedBB aabb) { + public boolean isBoundingBoxInFrustum(AxisAlignedBB aabb) { if (boxCuller != null && boxCuller.isCulled(aabb)) { return false; } diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java index 8191f83b7..233dfece7 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/BoxCullingFrustum.java @@ -1,20 +1,18 @@ package net.coderbot.iris.shadows.frustum.fallback; import net.coderbot.iris.shadows.frustum.BoxCuller; +import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.util.AxisAlignedBB; -import org.joml.Matrix4f; -public class BoxCullingFrustum extends Frustum { +public class BoxCullingFrustum extends Frustrum { private final BoxCuller boxCuller; public BoxCullingFrustum(BoxCuller boxCuller) { - super(new Matrix4f(), new Matrix4f()); - this.boxCuller = boxCuller; } @Override - public void prepare(double cameraX, double cameraY, double cameraZ) { + public void setPosition(double cameraX, double cameraY, double cameraZ) { boxCuller.setPosition(cameraX, cameraY, cameraZ); } @@ -33,7 +31,7 @@ public boolean canDetermineInvisible(double minX, double minY, double minZ, doub } @Override - public boolean isVisible(AxisAlignedBB aabb) { + public boolean isBoundingBoxInFrustum(AxisAlignedBB aabb) { return !boxCuller.isCulled(aabb); } } diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java index 822c72127..284debfa6 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/fallback/NonCullingFrustum.java @@ -1,12 +1,10 @@ package net.coderbot.iris.shadows.frustum.fallback; +import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.util.AxisAlignedBB; -import org.joml.Matrix4f; -public class NonCullingFrustum extends Frustum { - public NonCullingFrustum() { - super(new Matrix4f(), new Matrix4f()); - } + +public class NonCullingFrustum extends Frustrum { // for Sodium public boolean fastAabbTest(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { @@ -22,7 +20,7 @@ public boolean canDetermineInvisible(double minX, double minY, double minZ, doub } @Override - public boolean isVisible(AxisAlignedBB aabb) { + public boolean isBoundingBoxInFrustum(AxisAlignedBB aabb) { return true; } } diff --git a/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java b/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java index 568a71fe6..3bfc873b5 100644 --- a/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java +++ b/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java @@ -1,7 +1,6 @@ package net.coderbot.iris.texture.format; import net.coderbot.iris.texture.mipmap.ChannelMipmapGenerator; -import net.coderbot.iris.texture.mipmap.CustomMipmapGenerator; import net.coderbot.iris.texture.mipmap.DiscreteBlendFunction; import net.coderbot.iris.texture.mipmap.LinearBlendFunction; import net.coderbot.iris.texture.pbr.PBRType; @@ -9,6 +8,7 @@ import java.util.Objects; +// TODO: PBR public class LabPBRTextureFormat implements TextureFormat { public static final ChannelMipmapGenerator SPECULAR_MIPMAP_GENERATOR = new ChannelMipmapGenerator( LinearBlendFunction.INSTANCE, @@ -44,13 +44,14 @@ public boolean canInterpolateValues(PBRType pbrType) { return true; } - @Override - public @Nullable CustomMipmapGenerator getMipmapGenerator(PBRType pbrType) { - if (pbrType == PBRType.SPECULAR) { - return SPECULAR_MIPMAP_GENERATOR; - } - return null; - } + // TODO: PBR +// @Override +// public @Nullable CustomMipmapGenerator getMipmapGenerator(PBRType pbrType) { +// if (pbrType == PBRType.SPECULAR) { +// return SPECULAR_MIPMAP_GENERATOR; +// } +// return null; +// } @Override public int hashCode() { diff --git a/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java b/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java index d9662078d..f4d4e04d2 100644 --- a/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java +++ b/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java @@ -1,7 +1,6 @@ package net.coderbot.iris.texture.format; import net.coderbot.iris.gl.IrisRenderSystem; -import net.coderbot.iris.texture.mipmap.CustomMipmapGenerator; import net.coderbot.iris.texture.pbr.PBRType; import net.minecraft.client.renderer.texture.AbstractTexture; import org.jetbrains.annotations.Nullable; @@ -46,17 +45,18 @@ default List getDefines() { default void setupTextureParameters(PBRType pbrType, AbstractTexture texture) { if (!canInterpolateValues(pbrType)) { - int minFilter = IrisRenderSystem.getTexParameteri(texture.getId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER); + int minFilter = IrisRenderSystem.getTexParameteri(texture.getGlTextureId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER); // Non-mipped filters begin at 0x2600 whereas mipped filters begin at 0x2700, // so this bit mask can be used to check if the filter is mipped or not boolean mipmap = (minFilter & 1 << 8) == 1; - IrisRenderSystem.texParameteri(texture.getId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mipmap ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_NEAREST); - IrisRenderSystem.texParameteri(texture.getId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + IrisRenderSystem.texParameteri(texture.getGlTextureId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mipmap ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_NEAREST); + IrisRenderSystem.texParameteri(texture.getGlTextureId(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); } } - @Nullable - CustomMipmapGenerator getMipmapGenerator(PBRType pbrType); + // TODO: PBR +// @Nullable +// CustomMipmapGenerator getMipmapGenerator(PBRType pbrType); public interface Factory { TextureFormat createFormat(String name, @Nullable String version); diff --git a/src/main/java/net/coderbot/iris/texture/format/TextureFormatLoader.java b/src/main/java/net/coderbot/iris/texture/format/TextureFormatLoader.java index 2c3851aa2..3dbdffb63 100644 --- a/src/main/java/net/coderbot/iris/texture/format/TextureFormatLoader.java +++ b/src/main/java/net/coderbot/iris/texture/format/TextureFormatLoader.java @@ -32,7 +32,8 @@ public static void reload(IResourceManager resourceManager) { @Nullable private static TextureFormat loadFormat(IResourceManager resourceManager) { - try (IResource resource = resourceManager.getResource(LOCATION)) { + try { + IResource resource = resourceManager.getResource(LOCATION); Properties properties = new Properties(); properties.load(resource.getInputStream()); String format = properties.getProperty("format"); diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java index 0031af417..4217b23d1 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java @@ -1,5 +1,6 @@ package net.coderbot.iris.texture.mipmap; +import net.coderbot.iris.compat.mojang.NativeImage; public abstract class AbstractMipmapGenerator implements CustomMipmapGenerator { @Override diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java index eb2b9ecef..2a51d977e 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java @@ -1,5 +1,5 @@ package net.coderbot.iris.texture.mipmap; - +import net.coderbot.iris.compat.mojang.NativeImage; public class ChannelMipmapGenerator extends AbstractMipmapGenerator { protected final BlendFunction redFunc; @@ -17,30 +17,10 @@ public ChannelMipmapGenerator(BlendFunction redFunc, BlendFunction greenFunc, Bl @Override public int blend(int c0, int c1, int c2, int c3) { return NativeImage.combine( - alphaFunc.blend( - NativeImage.getA(c0), - NativeImage.getA(c1), - NativeImage.getA(c2), - NativeImage.getA(c3) - ), - blueFunc.blend( - NativeImage.getB(c0), - NativeImage.getB(c1), - NativeImage.getB(c2), - NativeImage.getB(c3) - ), - greenFunc.blend( - NativeImage.getG(c0), - NativeImage.getG(c1), - NativeImage.getG(c2), - NativeImage.getG(c3) - ), - redFunc.blend( - NativeImage.getR(c0), - NativeImage.getR(c1), - NativeImage.getR(c2), - NativeImage.getR(c3) - ) + alphaFunc.blend(NativeImage.getA(c0), NativeImage.getA(c1), NativeImage.getA(c2), NativeImage.getA(c3)), + blueFunc.blend(NativeImage.getB(c0), NativeImage.getB(c1), NativeImage.getB(c2), NativeImage.getB(c3)), + greenFunc.blend(NativeImage.getG(c0), NativeImage.getG(c1), NativeImage.getG(c2), NativeImage.getG(c3)), + redFunc.blend(NativeImage.getR(c0), NativeImage.getR(c1), NativeImage.getR(c2), NativeImage.getR(c3)) ); } diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java index 15d462970..8059c3046 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java @@ -1,13 +1,13 @@ package net.coderbot.iris.texture.mipmap; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import org.jetbrains.annotations.Nullable; +import net.coderbot.iris.compat.mojang.NativeImage; public interface CustomMipmapGenerator { NativeImage[] generateMipLevels(NativeImage image, int mipLevel); - public interface Provider { - @Nullable - CustomMipmapGenerator getMipmapGenerator(TextureAtlasSprite.Info info, int atlasWidth, int atlasHeight); - } + // TODO: PBR +// public interface Provider { +// @Nullable +// CustomMipmapGenerator getMipmapGenerator(TextureAtlasSprite.Info info, int atlasWidth, int atlasHeight); +// } } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java index bd5b286f8..8673ec9cb 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java @@ -1,10 +1,10 @@ package net.coderbot.iris.texture.pbr; -import com.gtnewhorizons.angelica.mixins.early.accessors.TextureAtlasSpriteAccessor; import com.gtnewhorizons.angelica.mixins.early.textures.MixinTextureAtlasSprite; +import net.coderbot.iris.compat.mojang.AutoClosableAbstractTexture; +import net.coderbot.iris.compat.mojang.TextureAtlas; import net.coderbot.iris.texture.util.TextureExporter; import net.coderbot.iris.texture.util.TextureManipulationUtil; -import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.data.AnimationMetadataSection; @@ -19,7 +19,7 @@ import java.util.Map; import java.util.Set; -public class PBRAtlasTexture extends AbstractTexture { +public class PBRAtlasTexture extends AutoClosableAbstractTexture { protected final TextureAtlas atlasTexture; protected final PBRType type; protected final ResourceLocation id; @@ -29,7 +29,9 @@ public class PBRAtlasTexture extends AbstractTexture { public PBRAtlasTexture(TextureAtlas atlasTexture, PBRType type) { this.atlasTexture = atlasTexture; this.type = type; - id = type.appendToFileLocation(atlasTexture.location()); +// id = type.appendToFileLocation(atlasTexture.location()); + + id = type.appendToFileLocation(new ResourceLocation("stuff", getType().name())); } public PBRType getType() { @@ -41,8 +43,9 @@ public ResourceLocation getAtlasId() { } public void addSprite(TextureAtlasSprite sprite) { - // Wants location - sprites.put(sprite.getName(), sprite); + // TODO: PBR - Wants location +// sprites.put(sprite.getName(), sprite); + sprites.put(new ResourceLocation("stuff", sprite.getIconName()), sprite); if (((MixinTextureAtlasSprite) (Object)sprite).isAnimation()) { animatedSprites.add(sprite); } @@ -60,17 +63,17 @@ public void clear() { public void upload(int atlasWidth, int atlasHeight, int mipLevel) { int glId = getGlTextureId(); - TextureUtil.prepareImage(glId, mipLevel, atlasWidth, atlasHeight); +// TextureUtil.prepareImage(glId, mipLevel, atlasWidth, atlasHeight); TextureManipulationUtil.fillWithColor(glId, mipLevel, type.getDefaultValue()); for (TextureAtlasSprite sprite : sprites.values()) { try { uploadSprite(sprite); } catch (Throwable throwable) { - CrashReport crashReport = CrashReport.forThrowable(throwable, "Stitching texture atlas"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Texture being stitched together"); - crashReportCategory.setDetail("Atlas path", id); - crashReportCategory.setDetail("Sprite", sprite); + CrashReport crashReport = CrashReport.makeCrashReport(throwable, "Stitching texture atlas"); + CrashReportCategory crashReportCategory = crashReport.makeCategory("Texture being stitched together"); + crashReportCategory.addCrashSection("Atlas path", id); + crashReportCategory.addCrashSection("Sprite", sprite); throw new ReportedException(crashReport); } } @@ -103,26 +106,27 @@ public boolean tryUpload(int atlasWidth, int atlasHeight, int mipLevel) { protected void uploadSprite(TextureAtlasSprite sprite) { if (((MixinTextureAtlasSprite) (Object)sprite).isAnimation()) { - TextureAtlasSpriteAccessor accessor = (TextureAtlasSpriteAccessor) sprite; - AnimationMetadataSection metadata = accessor.getMetadata(); + MixinTextureAtlasSprite mixinSprite = ((MixinTextureAtlasSprite) (Object) sprite); + AnimationMetadataSection metadata = mixinSprite.getMetadata(); int frameCount = sprite.getFrameCount(); - for (int frame = accessor.getFrame(); frame >= 0; frame--) { + for (int frame = mixinSprite.getFrame(); frame >= 0; frame--) { int frameIndex = metadata.getFrameIndex(frame); if (frameIndex >= 0 && frameIndex < frameCount) { - accessor.callUpload(frameIndex); + mixinSprite.callUpload(frameIndex); return; } } } - sprite.uploadFirstFrame(); +// sprite.uploadFirstFrame(); } public void cycleAnimationFrames() { bind(); for (TextureAtlasSprite sprite : animatedSprites) { - sprite.cycleFrames(); +// sprite.cycleFrames(); + sprite.updateAnimation(); } } @@ -141,7 +145,7 @@ public void close() { } } -// @Override + @Override public void load(IResourceManager manager) { } } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java index 2956b01fc..8913b04d5 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java @@ -26,11 +26,12 @@ public void setSpecularSprite(TextureAtlasSprite sprite) { } public void close() { - if (normalSprite != null) { - normalSprite.close(); - } - if (specularSprite != null) { - specularSprite.close(); - } + // TODO: AutoClosable +// if (normalSprite != null) { +// normalSprite.close(); +// } +// if (specularSprite != null) { +// specularSprite.close(); +// } } } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRTextureManager.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRTextureManager.java index 2a27d24e8..4cfd1200c 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/PBRTextureManager.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRTextureManager.java @@ -111,8 +111,8 @@ public void clear() { public void close() { clear(); - defaultNormalTexture.close(); - defaultSpecularTexture.close(); +// defaultNormalTexture.close(); +// defaultSpecularTexture.close(); } private void closeHolder(PBRTextureHolder holder) { @@ -127,12 +127,7 @@ private void closeHolder(PBRTextureHolder holder) { } private static void closeTexture(AbstractTexture texture) { - try { - texture.close(); - } catch (Exception e) { - // - } - texture.releaseId(); + texture.deleteGlTexture(); } public static void notifyPBRTexturesChanged() { diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java index 5674ba71d..9dd146600 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java @@ -1,27 +1,9 @@ package net.coderbot.iris.texture.pbr.loader; -import net.coderbot.iris.Iris; -import net.coderbot.iris.texture.TextureInfoCache; -import net.coderbot.iris.texture.TextureInfoCache.TextureInfo; -import net.coderbot.iris.texture.format.TextureFormat; -import net.coderbot.iris.texture.format.TextureFormatLoader; +import net.coderbot.iris.compat.mojang.TextureAtlas; import net.coderbot.iris.texture.mipmap.ChannelMipmapGenerator; -import net.coderbot.iris.texture.mipmap.CustomMipmapGenerator; import net.coderbot.iris.texture.mipmap.LinearBlendFunction; -import net.coderbot.iris.texture.pbr.PBRAtlasTexture; -import net.coderbot.iris.texture.pbr.PBRSpriteHolder; -import net.coderbot.iris.texture.pbr.PBRType; -import net.coderbot.iris.texture.pbr.TextureAtlasSpriteExtension; -import net.coderbot.iris.texture.util.ImageManipulationUtil; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResourceManager; -import net.minecraft.client.resources.data.AnimationMetadataSection; -import net.minecraft.util.ResourceLocation; -import org.jetbrains.annotations.Nullable; - -import java.io.FileNotFoundException; -import java.io.IOException; public class AtlasPBRLoader implements PBRTextureLoader { public static final ChannelMipmapGenerator LINEAR_MIPMAP_GENERATOR = new ChannelMipmapGenerator( @@ -33,190 +15,191 @@ public class AtlasPBRLoader implements PBRTextureLoader { @Override public void load(TextureAtlas atlas, IResourceManager resourceManager, PBRTextureConsumer pbrTextureConsumer) { - TextureInfo textureInfo = TextureInfoCache.INSTANCE.getInfo(atlas.getId()); - int atlasWidth = textureInfo.getWidth(); - int atlasHeight = textureInfo.getHeight(); - int mipLevel = fetchAtlasMipLevel(atlas); - - PBRAtlasTexture normalAtlas = null; - PBRAtlasTexture specularAtlas = null; - for (TextureAtlasSprite sprite : ((TextureAtlasAccessor) atlas).getTexturesByName().values()) { - if (!(sprite instanceof MissingTextureAtlasSprite)) { - TextureAtlasSprite normalSprite = createPBRSprite(sprite, resourceManager, atlas, atlasWidth, atlasHeight, mipLevel, PBRType.NORMAL); - TextureAtlasSprite specularSprite = createPBRSprite(sprite, resourceManager, atlas, atlasWidth, atlasHeight, mipLevel, PBRType.SPECULAR); - if (normalSprite != null) { - if (normalAtlas == null) { - normalAtlas = new PBRAtlasTexture(atlas, PBRType.NORMAL); - } - normalAtlas.addSprite(normalSprite); - PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); - pbrSpriteHolder.setNormalSprite(normalSprite); - } - if (specularSprite != null) { - if (specularAtlas == null) { - specularAtlas = new PBRAtlasTexture(atlas, PBRType.SPECULAR); - } - specularAtlas.addSprite(specularSprite); - PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); - pbrSpriteHolder.setSpecularSprite(specularSprite); - } - } - } - - if (normalAtlas != null) { - if (normalAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { - pbrTextureConsumer.acceptNormalTexture(normalAtlas); - } - } - if (specularAtlas != null) { - if (specularAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { - pbrTextureConsumer.acceptSpecularTexture(specularAtlas); - } - } - } - - protected static int fetchAtlasMipLevel(TextureAtlas atlas) { - TextureAtlasSprite missingSprite = atlas.getSprite(MissingTextureAtlasSprite.getLocation()); - return ((TextureAtlasSpriteAccessor) missingSprite).getMainImage().length - 1; + // TODO: PBR +// TextureInfo textureInfo = TextureInfoCache.INSTANCE.getInfo(atlas.getId()); +// int atlasWidth = textureInfo.getWidth(); +// int atlasHeight = textureInfo.getHeight(); +// int mipLevel = fetchAtlasMipLevel(atlas); +// +// PBRAtlasTexture normalAtlas = null; +// PBRAtlasTexture specularAtlas = null; +// for (TextureAtlasSprite sprite : atlas.getTexturesByName().values()) { +// if (!(sprite instanceof MissingTextureAtlasSprite)) { +// TextureAtlasSprite normalSprite = createPBRSprite(sprite, resourceManager, atlas, atlasWidth, atlasHeight, mipLevel, PBRType.NORMAL); +// TextureAtlasSprite specularSprite = createPBRSprite(sprite, resourceManager, atlas, atlasWidth, atlasHeight, mipLevel, PBRType.SPECULAR); +// if (normalSprite != null) { +// if (normalAtlas == null) { +// normalAtlas = new PBRAtlasTexture(atlas, PBRType.NORMAL); +// } +// normalAtlas.addSprite(normalSprite); +// PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); +// pbrSpriteHolder.setNormalSprite(normalSprite); +// } +// if (specularSprite != null) { +// if (specularAtlas == null) { +// specularAtlas = new PBRAtlasTexture(atlas, PBRType.SPECULAR); +// } +// specularAtlas.addSprite(specularSprite); +// PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); +// pbrSpriteHolder.setSpecularSprite(specularSprite); +// } +// } +// } +// +// if (normalAtlas != null) { +// if (normalAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { +// pbrTextureConsumer.acceptNormalTexture(normalAtlas); +// } +// } +// if (specularAtlas != null) { +// if (specularAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { +// pbrTextureConsumer.acceptSpecularTexture(specularAtlas); +// } +// } } - @Nullable - protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourceManager resourceManager, TextureAtlas atlas, int atlasWidth, int atlasHeight, int mipLevel, PBRType pbrType) { - ResourceLocation spriteName = sprite.getName(); - ResourceLocation imageLocation = ((TextureAtlasAccessor) atlas).callGetResourceLocation(spriteName); - ResourceLocation pbrImageLocation = pbrType.appendToFileLocation(imageLocation); - - TextureAtlasSprite pbrSprite = null; - try (IResource resource = resourceManager.getResource(pbrImageLocation)) { - NativeImage nativeImage = NativeImage.read(resource.getInputStream()); - AnimationMetadataSection animationMetadata = resource.getMetadata(AnimationMetadataSection.SERIALIZER); - if (animationMetadata == null) { - animationMetadata = AnimationMetadataSection.EMPTY; - } - - Pair frameSize = animationMetadata.getFrameSize(nativeImage.getWidth(), nativeImage.getHeight()); - int frameWidth = frameSize.getFirst(); - int frameHeight = frameSize.getSecond(); - int targetFrameWidth = sprite.getWidth(); - int targetFrameHeight = sprite.getHeight(); - if (frameWidth != targetFrameWidth || frameHeight != targetFrameHeight) { - int imageWidth = nativeImage.getWidth(); - int imageHeight = nativeImage.getHeight(); - - // We can assume the following is always true as a result of getFrameSize's check: - // imageWidth % frameWidth == 0 && imageHeight % frameHeight == 0 - int targetImageWidth = imageWidth / frameWidth * targetFrameWidth; - int targetImageHeight = imageHeight / frameHeight * targetFrameHeight; - - NativeImage scaledImage; - if (targetImageWidth % imageWidth == 0 && targetImageHeight % imageHeight == 0) { - scaledImage = ImageManipulationUtil.scaleNearestNeighbor(nativeImage, targetImageWidth, targetImageHeight); - } else { - scaledImage = ImageManipulationUtil.scaleBilinear(nativeImage, targetImageWidth, targetImageHeight); - } - nativeImage.close(); - nativeImage = scaledImage; - - frameWidth = targetFrameWidth; - frameHeight = targetFrameHeight; - - if (animationMetadata != AnimationMetadataSection.EMPTY) { - AnimationMetadataSectionAccessor animationAccessor = (AnimationMetadataSectionAccessor) animationMetadata; - int internalFrameWidth = animationAccessor.getFrameWidth(); - int internalFrameHeight = animationAccessor.getFrameHeight(); - if (internalFrameWidth != -1) { - animationAccessor.setFrameWidth(frameWidth); - } - if (internalFrameHeight != -1) { - animationAccessor.setFrameHeight(frameHeight); - } - } - } - - ResourceLocation pbrSpriteName = new ResourceLocation(spriteName.getNamespace(), spriteName.getPath() + pbrType.getSuffix()); - TextureAtlasSprite.Info pbrSpriteInfo = new PBRTextureAtlasSpriteInfo(pbrSpriteName, frameWidth, frameHeight, animationMetadata, pbrType); - - int x = ((TextureAtlasSpriteAccessor) sprite).getX(); - int y = ((TextureAtlasSpriteAccessor) sprite).getY(); - pbrSprite = new PBRTextureAtlasSprite(atlas, pbrSpriteInfo, mipLevel, atlasWidth, atlasHeight, x, y, nativeImage); - syncAnimation(sprite, pbrSprite); - } catch (FileNotFoundException e) { - // - } catch (RuntimeException e) { - Iris.logger.error("Unable to parse metadata from {} : {}", pbrImageLocation, e); - } catch (IOException e) { - Iris.logger.error("Unable to load {} : {}", pbrImageLocation, e); - } - - return pbrSprite; - } - - protected void syncAnimation(TextureAtlasSprite source, TextureAtlasSprite target) { - // TODO: Iris Shaders - animationMetadata && animationMetadata.getFrameCount() > 0 - if (!source.isAnimation() || !target.isAnimation()) { - return; - } - - TextureAtlasSpriteAccessor sourceAccessor = ((TextureAtlasSpriteAccessor) source); - AnimationMetadataSection sourceMetadata = sourceAccessor.getMetadata(); - - int ticks = 0; - for (int f = 0; f < sourceAccessor.getFrame(); f++) { - ticks += sourceMetadata.getFrameTime(f); - } - - TextureAtlasSpriteAccessor targetAccessor = ((TextureAtlasSpriteAccessor) target); - AnimationMetadataSection targetMetadata = targetAccessor.getMetadata(); - - int cycleTime = 0; - int frameCount = targetMetadata.getFrameCount(); - for (int f = 0; f < frameCount; f++) { - cycleTime += targetMetadata.getFrameTime(f); - } - ticks %= cycleTime; - - int targetFrame = 0; - while (true) { - int time = targetMetadata.getFrameTime(targetFrame); - if (ticks >= time) { - targetFrame++; - ticks -= time; - } else { - break; - } - } - - targetAccessor.setFrame(targetFrame); - targetAccessor.setSubFrame(ticks + sourceAccessor.getSubFrame()); - } - - protected static class PBRTextureAtlasSpriteInfo extends TextureAtlasSprite.Info { - protected final PBRType pbrType; - - public PBRTextureAtlasSpriteInfo(ResourceLocation name, int width, int height, AnimationMetadataSection metadata, PBRType pbrType) { - super(name, width, height, metadata); - this.pbrType = pbrType; - } - } - - public static class PBRTextureAtlasSprite extends TextureAtlasSprite implements CustomMipmapGenerator.Provider { - protected PBRTextureAtlasSprite(TextureAtlas atlas, TextureAtlasSprite.Info info, int mipLevel, int atlasWidth, int atlasHeight, int x, int y, NativeImage nativeImage) { - super(atlas, info, mipLevel, atlasWidth, atlasHeight, x, y, nativeImage); - } - - @Override - public CustomMipmapGenerator getMipmapGenerator(Info info, int atlasWidth, int atlasHeight) { - if (info instanceof PBRTextureAtlasSpriteInfo) { - PBRType pbrType = ((PBRTextureAtlasSpriteInfo) info).pbrType; - TextureFormat format = TextureFormatLoader.getFormat(); - if (format != null) { - CustomMipmapGenerator generator = format.getMipmapGenerator(pbrType); - if (generator != null) { - return generator; - } - } - } - return LINEAR_MIPMAP_GENERATOR; - } - } +// protected static int fetchAtlasMipLevel(TextureAtlas atlas) { +// TextureAtlasSprite missingSprite = atlas.getSprite(MissingTextureAtlasSprite.getLocation()); +// return ((TextureAtlasSpriteAccessor) missingSprite).getMainImage().length - 1; +// } +// +// @Nullable +// protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourceManager resourceManager, TextureAtlas atlas, int atlasWidth, int atlasHeight, int mipLevel, PBRType pbrType) { +// ResourceLocation spriteName = sprite.getName(); +// ResourceLocation imageLocation = ((TextureAtlasAccessor) atlas).callGetResourceLocation(spriteName); +// ResourceLocation pbrImageLocation = pbrType.appendToFileLocation(imageLocation); +// +// TextureAtlasSprite pbrSprite = null; +// try (IResource resource = resourceManager.getResource(pbrImageLocation)) { +// NativeImage nativeImage = NativeImage.read(resource.getInputStream()); +// AnimationMetadataSection animationMetadata = resource.getMetadata(AnimationMetadataSection.SERIALIZER); +// if (animationMetadata == null) { +// animationMetadata = AnimationMetadataSection.EMPTY; +// } +// +// Pair frameSize = animationMetadata.getFrameSize(nativeImage.getWidth(), nativeImage.getHeight()); +// int frameWidth = frameSize.getFirst(); +// int frameHeight = frameSize.getSecond(); +// int targetFrameWidth = sprite.getWidth(); +// int targetFrameHeight = sprite.getHeight(); +// if (frameWidth != targetFrameWidth || frameHeight != targetFrameHeight) { +// int imageWidth = nativeImage.getWidth(); +// int imageHeight = nativeImage.getHeight(); +// +// // We can assume the following is always true as a result of getFrameSize's check: +// // imageWidth % frameWidth == 0 && imageHeight % frameHeight == 0 +// int targetImageWidth = imageWidth / frameWidth * targetFrameWidth; +// int targetImageHeight = imageHeight / frameHeight * targetFrameHeight; +// +// NativeImage scaledImage; +// if (targetImageWidth % imageWidth == 0 && targetImageHeight % imageHeight == 0) { +// scaledImage = ImageManipulationUtil.scaleNearestNeighbor(nativeImage, targetImageWidth, targetImageHeight); +// } else { +// scaledImage = ImageManipulationUtil.scaleBilinear(nativeImage, targetImageWidth, targetImageHeight); +// } +// nativeImage.close(); +// nativeImage = scaledImage; +// +// frameWidth = targetFrameWidth; +// frameHeight = targetFrameHeight; +// +// if (animationMetadata != AnimationMetadataSection.EMPTY) { +// AnimationMetadataSectionAccessor animationAccessor = (AnimationMetadataSectionAccessor) animationMetadata; +// int internalFrameWidth = animationAccessor.getFrameWidth(); +// int internalFrameHeight = animationAccessor.getFrameHeight(); +// if (internalFrameWidth != -1) { +// animationAccessor.setFrameWidth(frameWidth); +// } +// if (internalFrameHeight != -1) { +// animationAccessor.setFrameHeight(frameHeight); +// } +// } +// } +// +// ResourceLocation pbrSpriteName = new ResourceLocation(spriteName.getNamespace(), spriteName.getPath() + pbrType.getSuffix()); +// TextureAtlasSprite.Info pbrSpriteInfo = new PBRTextureAtlasSpriteInfo(pbrSpriteName, frameWidth, frameHeight, animationMetadata, pbrType); +// +// int x = ((TextureAtlasSpriteAccessor) sprite).getX(); +// int y = ((TextureAtlasSpriteAccessor) sprite).getY(); +// pbrSprite = new PBRTextureAtlasSprite(atlas, pbrSpriteInfo, mipLevel, atlasWidth, atlasHeight, x, y, nativeImage); +// syncAnimation(sprite, pbrSprite); +// } catch (FileNotFoundException e) { +// // +// } catch (RuntimeException e) { +// Iris.logger.error("Unable to parse metadata from {} : {}", pbrImageLocation, e); +// } catch (IOException e) { +// Iris.logger.error("Unable to load {} : {}", pbrImageLocation, e); +// } +// +// return pbrSprite; +// } +// +// protected void syncAnimation(TextureAtlasSprite source, TextureAtlasSprite target) { +// // TODO: Iris Shaders - animationMetadata && animationMetadata.getFrameCount() > 0 +// if (!source.isAnimation() || !target.isAnimation()) { +// return; +// } +// +// TextureAtlasSpriteAccessor sourceAccessor = ((TextureAtlasSpriteAccessor) source); +// AnimationMetadataSection sourceMetadata = sourceAccessor.getMetadata(); +// +// int ticks = 0; +// for (int f = 0; f < sourceAccessor.getFrame(); f++) { +// ticks += sourceMetadata.getFrameTime(f); +// } +// +// TextureAtlasSpriteAccessor targetAccessor = ((TextureAtlasSpriteAccessor) target); +// AnimationMetadataSection targetMetadata = targetAccessor.getMetadata(); +// +// int cycleTime = 0; +// int frameCount = targetMetadata.getFrameCount(); +// for (int f = 0; f < frameCount; f++) { +// cycleTime += targetMetadata.getFrameTime(f); +// } +// ticks %= cycleTime; +// +// int targetFrame = 0; +// while (true) { +// int time = targetMetadata.getFrameTime(targetFrame); +// if (ticks >= time) { +// targetFrame++; +// ticks -= time; +// } else { +// break; +// } +// } +// +// targetAccessor.setFrame(targetFrame); +// targetAccessor.setSubFrame(ticks + sourceAccessor.getSubFrame()); +// } +// +// protected static class PBRTextureAtlasSpriteInfo extends TextureAtlasSprite.Info { +// protected final PBRType pbrType; +// +// public PBRTextureAtlasSpriteInfo(ResourceLocation name, int width, int height, AnimationMetadataSection metadata, PBRType pbrType) { +// super(name, width, height, metadata); +// this.pbrType = pbrType; +// } +// } +// +// public static class PBRTextureAtlasSprite extends TextureAtlasSprite implements CustomMipmapGenerator.Provider { +// protected PBRTextureAtlasSprite(TextureAtlas atlas, TextureAtlasSprite.Info info, int mipLevel, int atlasWidth, int atlasHeight, int x, int y, NativeImage nativeImage) { +// super(atlas, info, mipLevel, atlasWidth, atlasHeight, x, y, nativeImage); +// } +// +// @Override +// public CustomMipmapGenerator getMipmapGenerator(Info info, int atlasWidth, int atlasHeight) { +// if (info instanceof PBRTextureAtlasSpriteInfo) { +// PBRType pbrType = ((PBRTextureAtlasSpriteInfo) info).pbrType; +// TextureFormat format = TextureFormatLoader.getFormat(); +// if (format != null) { +// CustomMipmapGenerator generator = format.getMipmapGenerator(pbrType); +// if (generator != null) { +// return generator; +// } +// } +// } +// return LINEAR_MIPMAP_GENERATOR; +// } +// } } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java index b17f294ee..0d5594496 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java @@ -1,7 +1,6 @@ package net.coderbot.iris.texture.pbr.loader; import net.minecraft.client.renderer.texture.AbstractTexture; -import net.minecraft.client.renderer.texture.SimpleTexture; import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -10,10 +9,11 @@ public class PBRTextureLoaderRegistry { public static final PBRTextureLoaderRegistry INSTANCE = new PBRTextureLoaderRegistry(); - static { - INSTANCE.register(SimpleTexture.class, new SimplePBRLoader()); - INSTANCE.register(TextureAtlas.class, new AtlasPBRLoader()); - } +// TODO: PBR +// static { +// INSTANCE.register(SimpleTexture.class, new SimplePBRLoader()); +// INSTANCE.register(TextureAtlas.class, new AtlasPBRLoader()); +// } private final Map, PBRTextureLoader> loaderMap = new HashMap<>(); diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java index a21ed0354..a2613cd33 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java @@ -32,7 +32,7 @@ protected AbstractTexture createPBRTexture(ResourceLocation imageLocation, IReso SimpleTexture pbrTexture = new SimpleTexture(pbrImageLocation); try { - pbrTexture.load(resourceManager); + pbrTexture.loadTexture(resourceManager); } catch (IOException e) { return null; } diff --git a/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java b/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java index 50df766eb..1c27c5049 100644 --- a/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java +++ b/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java @@ -1,9 +1,10 @@ package net.coderbot.iris.texture.util; +import net.coderbot.iris.compat.mojang.NativeImage; public class ImageManipulationUtil { public static NativeImage scaleNearestNeighbor(NativeImage image, int newWidth, int newHeight) { - NativeImage scaled = new NativeImage(image.format(), newWidth, newHeight, false); + NativeImage scaled = new NativeImage(image.getFormat(), newWidth, newHeight, false); float xScale = (float) newWidth / image.getWidth(); float yScale = (float) newHeight / image.getHeight(); for (int y = 0; y < newHeight; ++y) { @@ -17,7 +18,7 @@ public static NativeImage scaleNearestNeighbor(NativeImage image, int newWidth, } public static NativeImage scaleBilinear(NativeImage image, int newWidth, int newHeight) { - NativeImage scaled = new NativeImage(image.format(), newWidth, newHeight, false); + NativeImage scaled = new NativeImage(image.getFormat(), newWidth, newHeight, false); float xScale = (float) newWidth / image.getWidth(); float yScale = (float) newHeight / image.getHeight(); for (int y = 0; y < newHeight; ++y) { diff --git a/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java b/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java index 9082159d0..ad9dc6496 100644 --- a/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java +++ b/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java @@ -1,5 +1,6 @@ package net.coderbot.iris.texture.util; +import net.coderbot.iris.compat.mojang.NativeImage; import net.minecraft.client.Minecraft; import org.apache.commons.io.FilenameUtils; import org.lwjgl.opengl.GL11; @@ -15,7 +16,7 @@ public static void exportTextures(String directory, String filename, int texture } } - public static void exportTexture(String directory, String filename, int textureId, int level, int width, int height) { + public static void exportTexture(String directory, String filename, int textureId, int level, int width, int height) { NativeImage nativeImage = new NativeImage(width, height, false); GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId); nativeImage.downloadTexture(level, false); @@ -24,14 +25,8 @@ public static void exportTexture(String directory, String filename, int textureI dir.mkdirs(); File file = new File(dir, filename); - Util.ioPool().execute(() -> { - try { - nativeImage.writeToFile(file); - } catch (Exception var7) { - // - } finally { - nativeImage.close(); - } - }); + try { + nativeImage.writeToFile(file); + } catch (Exception ignored) {} } } diff --git a/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java index 8e42d40ec..0d79dbdd6 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java @@ -1,9 +1,9 @@ package net.coderbot.iris.uniforms; -import net.coderbot.iris.JomlConversions; +import com.gtnewhorizons.angelica.client.Shaders; import net.coderbot.iris.gl.uniform.UniformHolder; -import org.joml.Vector3d; import net.minecraft.client.Minecraft; +import org.joml.Vector3d; import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.ONCE; import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; @@ -29,11 +29,12 @@ public static void addCameraUniforms(UniformHolder uniforms, FrameUpdateNotifier private static int getRenderDistanceInBlocks() { // TODO: Should we ask the game renderer for this? - return client.options.renderDistance * 16; + return client.gameSettings.renderDistanceChunks * 16; } public static Vector3d getUnshiftedCameraPosition() { - return JomlConversions.fromVec3(client.gameRenderer.getMainCamera().getPosition()); + return Shaders.getCameraPosition(); +// return JomlConversions.fromVec3(client.gameRenderer.getMainCamera().getPosition()); } static class CameraPositionTracker { diff --git a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java index d0684dd43..129e7c715 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java +++ b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java @@ -28,7 +28,7 @@ public Matrix4f getGbufferModelView() { } public void setGbufferModelView(Matrix4f gbufferModelView) { - this.gbufferModelView = gbufferModelView.copy(); + this.gbufferModelView = new Matrix4f(gbufferModelView); } public Matrix4f getGbufferProjection() { @@ -36,7 +36,7 @@ public Matrix4f getGbufferProjection() { } public void setGbufferProjection(Matrix4f gbufferProjection) { - this.gbufferProjection = gbufferProjection.copy(); + this.gbufferProjection = new Matrix4f(gbufferProjection); } public Vector3d getFogColor() { diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index f5e7718f6..40f779965 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -1,5 +1,6 @@ package net.coderbot.iris.uniforms; +import com.gtnewhorizons.angelica.client.Shaders; import com.gtnewhorizons.angelica.mixins.early.accessors.EntityRendererAccessor; import net.coderbot.iris.gl.state.StateUpdateNotifiers; import net.coderbot.iris.gl.uniform.DynamicUniformHolder; @@ -7,14 +8,10 @@ import net.coderbot.iris.layer.GbufferPrograms; import net.coderbot.iris.shaderpack.IdMap; import net.coderbot.iris.shaderpack.PackDirectives; -import net.coderbot.iris.texture.TextureInfoCache; -import net.coderbot.iris.texture.TextureInfoCache.TextureInfo; -import net.coderbot.iris.texture.TextureTracker; import net.coderbot.iris.uniforms.transforms.SmoothedFloat; import net.coderbot.iris.uniforms.transforms.SmoothedVec2f; import net.minecraft.block.material.Material; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -29,8 +26,6 @@ import org.joml.Vector4f; import org.joml.Vector4i; -import java.util.Objects; - import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.ONCE; import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_TICK; @@ -61,33 +56,37 @@ public static void addCommonUniforms(DynamicUniformHolder uniforms, IdMap idMap, // TODO: OptiFine doesn't think that atlasSize is a "dynamic" uniform, // but we do. How will custom uniforms depending on atlasSize work? uniforms.uniform2i("atlasSize", () -> { - int glId = GlStateManagerAccessor.getTEXTURES()[0].binding; - - AbstractTexture texture = TextureTracker.INSTANCE.getTexture(glId); - if (texture instanceof TextureAtlas) { - TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId); - return new Vector2i(info.getWidth(), info.getHeight()); - } - - return ZERO_VECTOR_2i; + return new Vector2i(Shaders.atlasSizeX, Shaders.atlasSizeY); +// int glId = GlStateManagerAccessor.getTEXTURES()[0].binding; +// +// AbstractTexture texture = TextureTracker.INSTANCE.getTexture(glId); +// if (texture instanceof TextureAtlas) { +// TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId); +// return new Vector2i(info.getWidth(), info.getHeight()); +// } +// +// return ZERO_VECTOR_2i; }, StateUpdateNotifiers.bindTextureNotifier); - uniforms.uniform2i("gtextureSize", () -> { - int glId = GlStateManagerAccessor.getTEXTURES()[0].binding; - - TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId); - return new Vector2i(info.getWidth(), info.getHeight()); - - }, StateUpdateNotifiers.bindTextureNotifier); + // TODO: gTextureSize +// uniforms.uniform2i("gtextureSize", () -> { +// int glId = GlStateManagerAccessor.getTEXTURES()[0].binding; +// +// TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId); +// return new Vector2i(info.getWidth(), info.getHeight()); +// +// }, StateUpdateNotifiers.bindTextureNotifier); uniforms.uniform4i("blendFunc", () -> { - GlStateManager.BlendState blend = GlStateManagerAccessor.getBLEND(); - - if (((BooleanStateAccessor) blend.mode).isEnabled()) { - return new Vector4i(blend.srcRgb, blend.dstRgb, blend.srcAlpha, blend.dstAlpha); - } else { - return ZERO_VECTOR_4i; - } + return ZERO_VECTOR_4i; + // TODO: blendFunc +// GlStateManager.BlendState blend = GlStateManagerAccessor.getBLEND(); +// +// if (((BooleanStateAccessor) blend.mode).isEnabled()) { +// return new Vector4i(blend.srcRgb, blend.dstRgb, blend.srcAlpha, blend.dstAlpha); +// } else { +// return ZERO_VECTOR_4i; +// } }, StateUpdateNotifiers.blendFuncNotifier); uniforms.uniform1i("renderStage", () -> GbufferPrograms.getCurrentPhase().ordinal(), StateUpdateNotifiers.phaseChangeNotifier); @@ -100,9 +99,9 @@ public static void generalCommonUniforms(UniformHolder uniforms, FrameUpdateNoti SmoothedVec2f eyeBrightnessSmooth = new SmoothedVec2f(directives.getEyeBrightnessHalfLife(), directives.getEyeBrightnessHalfLife(), CommonUniforms::getEyeBrightness, updateNotifier); - uniforms + uniforms .uniform1b(PER_FRAME, "hideGUI", () -> client.gameSettings.hideGUI) - .uniform1f(PER_FRAME, "eyeAltitude", () -> Objects.requireNonNull(client.getCameraEntity()).getEyeY()) + .uniform1f(PER_FRAME, "eyeAltitude", Shaders::getEyePosY) // Objects.requireNonNull(client.getCameraEntity()).getEyeY()) .uniform1i(PER_FRAME, "isEyeInWater", CommonUniforms::isEyeInWater) .uniform1f(PER_FRAME, "blindness", CommonUniforms::getBlindness) .uniform1f(PER_FRAME, "nightVision", CommonUniforms::getNightVision) diff --git a/src/main/java/net/coderbot/iris/uniforms/FogUniforms.java b/src/main/java/net/coderbot/iris/uniforms/FogUniforms.java index b6423492e..77f8b1680 100644 --- a/src/main/java/net/coderbot/iris/uniforms/FogUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/FogUniforms.java @@ -1,5 +1,6 @@ package net.coderbot.iris.uniforms; +import com.gtnewhorizons.angelica.client.Shaders; import net.coderbot.iris.gl.state.StateUpdateNotifiers; import net.coderbot.iris.gl.uniform.DynamicUniformHolder; @@ -10,29 +11,29 @@ private FogUniforms() { public static void addFogUniforms(DynamicUniformHolder uniforms) { uniforms.uniform1i("fogMode", () -> { - GlStateManager.FogState fog = GlStateManagerAccessor.getFOG(); + if(!Shaders.isFogEnabled()) return 0; - if (!((BooleanStateAccessor) fog.enable).isEnabled()) { - return 0; - } + return Shaders.fogMode; - return GlStateManagerAccessor.getFOG().mode; +// GlStateManager.FogState fog = GlStateManagerAccessor.getFOG(); +// if (!((BooleanStateAccessor) fog.enable).isEnabled()) { return 0; } +// return GlStateManagerAccessor.getFOG().mode; }, listener -> { StateUpdateNotifiers.fogToggleNotifier.setListener(listener); StateUpdateNotifiers.fogModeNotifier.setListener(listener); }); - uniforms.uniform1f("fogDensity", () -> GlStateManagerAccessor.getFOG().density, listener -> { + uniforms.uniform1f("fogDensity", () -> Shaders.fogDensity/*GlStateManagerAccessor.getFOG().density*/, listener -> { StateUpdateNotifiers.fogToggleNotifier.setListener(listener); StateUpdateNotifiers.fogDensityNotifier.setListener(listener); }); - uniforms.uniform1f("fogStart", () -> GlStateManagerAccessor.getFOG().start, listener -> { + uniforms.uniform1f("fogStart", () -> Shaders.fogStart/*GlStateManagerAccessor.getFOG().start*/, listener -> { StateUpdateNotifiers.fogToggleNotifier.setListener(listener); StateUpdateNotifiers.fogStartNotifier.setListener(listener); }); - uniforms.uniform1f("fogEnd", () -> GlStateManagerAccessor.getFOG().end, listener -> { + uniforms.uniform1f("fogEnd", () -> Shaders.fogEnd/*GlStateManagerAccessor.getFOG().end*/, listener -> { StateUpdateNotifiers.fogToggleNotifier.setListener(listener); StateUpdateNotifiers.fogEndNotifier.setListener(listener); }); diff --git a/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java b/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java index 6b77e9783..ce2e30522 100644 --- a/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java @@ -1,11 +1,11 @@ package net.coderbot.iris.uniforms; +import com.gtnewhorizons.angelica.client.Shaders; import net.coderbot.iris.gl.uniform.UniformHolder; import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; import net.coderbot.iris.uniforms.transforms.SmoothedFloat; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.Vec3; import org.joml.Math; // These expressions are copied directly from BSL and Complementary. @@ -14,7 +14,8 @@ // mostly working under Iris. public class HardcodedCustomUniforms { private static final Minecraft client = Minecraft.getMinecraft(); - private static Biome storedBiome; + // TODO: Biome +// private static Biome storedBiome; public static void addHardcodedCustomUniforms(UniformHolder holder, FrameUpdateNotifier updateNotifier) { updateNotifier.addListener(() -> { @@ -105,7 +106,8 @@ private static float getHurtFactor() { } private static float getEyeInCave() { - if (client.getCameraEntity().getEyeY() < 5.0) { +// if (client.getCameraEntity().getEyeY() < 5.0) { + if (Shaders.getEyePosY() < 5.0) { return 1.0f - getEyeSkyBrightness() / 240F; } return 0.0f; @@ -180,9 +182,10 @@ private static SmoothedFloat rainStrengthS(FrameUpdateNotifier updateNotifier, f } private static float getRawPrecipitation() { - if (storedBiome == null) { - return 0; - } + // TODO: Biome +// if (storedBiome == null) { +// return 0; +// } return 0; // Biome.Precipitation precipitation = storedBiome.getPrecipitation(); // return switch (precipitation) { diff --git a/src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java b/src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java index 2ec5a295b..d6a1808ce 100644 --- a/src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java @@ -1,12 +1,14 @@ package net.coderbot.iris.uniforms; import it.unimi.dsi.fastutil.objects.Object2IntFunction; +import net.coderbot.iris.compat.mojang.InteractionHand; import net.coderbot.iris.gl.uniform.DynamicUniformHolder; import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; import net.coderbot.iris.shaderpack.IdMap; import net.coderbot.iris.shaderpack.materialmap.NamespacedId; import net.irisshaders.iris.api.v0.item.IrisItemLightProvider; import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; @@ -67,15 +69,16 @@ private void invalidate() { } public void update() { - LocalPlayer player = Minecraft.getMinecraft().thePlayer; + EntityPlayer player = Minecraft.getMinecraft().thePlayer; if (player == null) { // Not valid when the player doesn't exist invalidate(); return; } - - ItemStack heldStack = player.getItemInHand(hand); +// ItemStack heldStack = player.getItemInHand(hand); + // TODO: Offhand + ItemStack heldStack = player.getHeldItem(); if (heldStack == null) { invalidate(); @@ -89,8 +92,8 @@ public void update() { return; } - ResourceLocation heldItemId = Registry.ITEM.getKey(heldItem); - intID = itemIdMap.applyAsInt(new NamespacedId(heldItemId.getNamespace(), heldItemId.getPath())); + ResourceLocation heldItemId = new ResourceLocation(Item.itemRegistry.getNameForObject(heldItem)); + intID = itemIdMap.applyAsInt(new NamespacedId(heldItemId.getResourceDomain(), heldItemId.getResourcePath())); IrisItemLightProvider lightProvider = (IrisItemLightProvider) heldItem; lightValue = lightProvider.getLightEmission(Minecraft.getMinecraft().thePlayer, heldStack); @@ -102,8 +105,10 @@ public void update() { lightColor = lightProvider.getLightColor(Minecraft.getMinecraft().thePlayer, heldStack); } - private IrisItemLightProvider applyOldHandLighting(@NotNull LocalPlayer player, IrisItemLightProvider existing) { - ItemStack offHandStack = player.getItemInHand(InteractionHand.OFF_HAND); + private IrisItemLightProvider applyOldHandLighting(@NotNull EntityPlayer player, IrisItemLightProvider existing) { + // TODO: Offhand +// ItemStack offHandStack = player.getItemInHand(InteractionHand.OFF_HAND); + ItemStack offHandStack = null; if (offHandStack == null) { return existing; diff --git a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java index 6a2cfe236..cf8ce7790 100644 --- a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java @@ -21,7 +21,7 @@ public static void addMatrixUniforms(UniformHolder uniforms, PackDirectives dire // We need to audit Mojang's linear algebra. addMatrix(uniforms, "Projection", CapturedRenderingState.INSTANCE::getGbufferProjection); addShadowMatrix(uniforms, "ModelView", () -> - ShadowRenderer.createShadowModelView(directives.getSunPathRotation(), directives.getShadowDirectives().getIntervalSize()).last().pose().copy()); + ShadowRenderer.createShadowModelView(directives.getSunPathRotation(), directives.getShadowDirectives().getIntervalSize()).last().pose()); addShadowArrayMatrix(uniforms, "Projection", () -> ShadowMatrices.createOrthoMatrix(directives.getShadowDirectives().getDistance())); } @@ -54,16 +54,11 @@ private static class Inverted implements Supplier { @Override public Matrix4f get() { // PERF: Don't copy + allocate this matrix every time? - Matrix4f copy = parent.get().copy(); + final Matrix4f copy = new Matrix4f(parent.get()); - FloatBuffer buffer = FloatBuffer.allocate(16); - copy.store(buffer); - buffer.rewind(); + copy.invert(); - Matrix4f matrix4f = new Matrix4f(buffer); - matrix4f.invert(); - - return matrix4f; + return copy; } } @@ -80,7 +75,7 @@ public Matrix4f get() { buffer.put(parent.get()); buffer.rewind(); - Matrix4f matrix4f = new Matrix4f(buffer); + final Matrix4f matrix4f = new Matrix4f(buffer); matrix4f.invert(); return matrix4f; @@ -99,8 +94,8 @@ private static class Previous implements Supplier { @Override public Matrix4f get() { // PERF: Don't copy + allocate these matrices every time? - Matrix4f copy = parent.get().copy(); - Matrix4f previous = this.previous.copy(); + final Matrix4f copy = new Matrix4f(parent.get()); + final Matrix4f previous = new Matrix4f(this.previous); this.previous = copy; diff --git a/src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java b/src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java index b166552c6..c70c1c201 100644 --- a/src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java @@ -24,8 +24,10 @@ public static void addViewportUniforms(UniformHolder uniforms) { // TODO: What about the custom scale.composite3 property? // NB: It is not safe to cache the render target due to mods like Resolution Control modifying the render target field. uniforms - .uniform1f(PER_FRAME, "viewHeight", () -> Minecraft.getMinecraft().getMainRenderTarget().height) - .uniform1f(PER_FRAME, "viewWidth", () -> Minecraft.getMinecraft().getMainRenderTarget().width) +// .uniform1f(PER_FRAME, "viewHeight", () -> Minecraft.getMinecraft().getMainRenderTarget().height) + .uniform1f(PER_FRAME, "viewHeight", () -> Minecraft.getMinecraft().displayHeight) +// .uniform1f(PER_FRAME, "viewWidth", () -> Minecraft.getMinecraft().getMainRenderTarget().width) + .uniform1f(PER_FRAME, "viewWidth", () -> Minecraft.getMinecraft().displayWidth) .uniform1f(PER_FRAME, "aspectRatio", ViewportUniforms::getAspectRatio); } @@ -33,6 +35,7 @@ public static void addViewportUniforms(UniformHolder uniforms) { * @return the current viewport aspect ratio, calculated from the current Minecraft window size */ private static float getAspectRatio() { - return ((float) Minecraft.getMinecraft().getMainRenderTarget().width) / ((float) Minecraft.getMinecraft().getMainRenderTarget().height); +// return ((float) Minecraft.getMinecraft().getMainRenderTarget().width) / ((float) Minecraft.getMinecraft().getMainRenderTarget().height); + return ((float) Minecraft.getMinecraft().displayWidth) / ((float) Minecraft.getMinecraft().displayHeight); } } diff --git a/src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java b/src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java index b4923b60c..dca8f8330 100644 --- a/src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java @@ -35,8 +35,9 @@ static int getWorldDayTime() { return (int) (timeOfDay % 24000L); } - long dayTime = ((DimensionTypeAccessor) getWorld().dimensionType()).getFixedTime() - .orElse(timeOfDay % 24000L); + long dayTime = Minecraft.getMinecraft().theWorld.getWorldTime(); +// long dayTime = ((DimensionTypeAccessor) getWorld().dimensionType()).getFixedTime() +// .orElse(timeOfDay % 24000L); return (int) dayTime; } diff --git a/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java b/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java index b616c731a..2ebd2b6b8 100644 --- a/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java +++ b/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java @@ -1,5 +1,7 @@ package net.coderbot.iris.vertices; +import net.coderbot.iris.compat.mojang.VertexFormat; + public interface ExtendingBufferBuilder { void iris$beginWithoutExtending(int drawMode, VertexFormat vertexFormat); } diff --git a/src/main/java/net/coderbot/iris/vertices/IrisTextVertexSinkImpl.java b/src/main/java/net/coderbot/iris/vertices/IrisTextVertexSinkImpl.java deleted file mode 100644 index 83ddba08a..000000000 --- a/src/main/java/net/coderbot/iris/vertices/IrisTextVertexSinkImpl.java +++ /dev/null @@ -1,121 +0,0 @@ -package net.coderbot.iris.vertices; - -import org.joml.Vector3f; -import net.irisshaders.iris.api.v0.IrisTextVertexSink; - -import java.nio.ByteBuffer; -import java.util.function.IntFunction; - -public class IrisTextVertexSinkImpl implements IrisTextVertexSink { - static VertexFormat format = IrisVertexFormats.TERRAIN; - private final ByteBuffer buffer; - private final TextQuadView quad = new TextQuadView(); - private final Vector3f saveNormal = new Vector3f(); - private static final int STRIDE = IrisVertexFormats.TERRAIN.getVertexSize(); - private int vertexCount; - private long elementOffset; - private float uSum; - private float vSum; - - public IrisTextVertexSinkImpl(int maxQuadCount, IntFunction buffer) { - this.buffer = buffer.apply(format.getVertexSize() * 4 * maxQuadCount); - this.elementOffset = MemoryUtil.memAddress(this.buffer); - } - - @Override - public VertexFormat getUnderlyingVertexFormat() { - return format; - } - - @Override - public ByteBuffer getUnderlyingByteBuffer() { - return buffer; - } - - @Override - public void quad(float minX, float minY, float maxX, float maxY, float z, int color, float minU, float minV, float maxU, float maxV, int light) { - vertex(minX, minY, z, color, minU, minV, light); - vertex(minX, maxY, z, color, minU, maxV, light); - vertex(maxX, maxY, z, color, maxU, maxV, light); - vertex(maxX, minY, z, color, maxU, minV, light); - } - - private void vertex(float x, float y, float z, int color, float u, float v, int light) { - vertexCount++; - uSum += u; - vSum += v; - - long i = elementOffset; - - MemoryUtil.memPutFloat(i, x); - MemoryUtil.memPutFloat(i + 4, y); - MemoryUtil.memPutFloat(i + 8, z); - MemoryUtil.memPutInt(i + 12, color); - MemoryUtil.memPutFloat(i + 16, u); - MemoryUtil.memPutFloat(i + 20, v); - MemoryUtil.memPutInt(i + 24, light); - - if (vertexCount == 4) { - // TODO: compute this at the head of quad() - vertexCount = 0; - uSum *= 0.25; - vSum *= 0.25; - quad.setup(elementOffset, IrisVertexFormats.TERRAIN.getVertexSize()); - - NormalHelper.computeFaceNormal(saveNormal, quad); - float normalX = saveNormal.x; - float normalY = saveNormal.y; - float normalZ = saveNormal.z; - int normal = NormalHelper.packNormal(saveNormal, 0.0F); - - int tangent = NormalHelper.computeTangent(normalX, normalY, normalZ, quad); - - for (long vertex = 0; vertex < 4; vertex++) { - MemoryUtil.memPutFloat(i + 36 - STRIDE * vertex, uSum); - MemoryUtil.memPutFloat(i + 40 - STRIDE * vertex, vSum); - MemoryUtil.memPutInt(i + 28 - STRIDE * vertex, normal); - MemoryUtil.memPutInt(i + 44 - STRIDE * vertex, tangent); - } - - uSum = 0; - vSum = 0; - } - - buffer.position(buffer.position() + STRIDE); - elementOffset += STRIDE; - } - - static class TextQuadView implements QuadView { - long writePointer; - int stride; - - public TextQuadView() { - - } - - public void setup(long writePointer, int stride) { - this.writePointer = writePointer; - this.stride = stride; - } - - public float x(int index) { - return MemoryUtil.memGetFloat(writePointer - stride * (3L - index)); - } - - public float y(int index) { - return MemoryUtil.memGetFloat(writePointer + 4 - stride * (3L - index)); - } - - public float z(int index) { - return MemoryUtil.memGetFloat(writePointer + 8 - stride * (3L - index)); - } - - public float u(int index) { - return MemoryUtil.memGetFloat(writePointer + 16 - stride * (3L - index)); - } - - public float v(int index) { - return MemoryUtil.memGetFloat(writePointer + 20 - stride * (3L - index)); - } - } -} diff --git a/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java b/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java index 914d90ce7..6dc2f44f8 100644 --- a/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java +++ b/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java @@ -1,6 +1,9 @@ package net.coderbot.iris.vertices; import com.google.common.collect.ImmutableList; +import net.coderbot.iris.compat.mojang.DefaultVertexFormat; +import net.coderbot.iris.compat.mojang.VertexFormat; +import net.coderbot.iris.compat.mojang.VertexFormatElement; public class IrisVertexFormats { public static final VertexFormatElement ENTITY_ELEMENT; diff --git a/src/main/java/net/irisshaders/iris/api/v0/IrisApi.java b/src/main/java/net/irisshaders/iris/api/v0/IrisApi.java index ceba45ece..cf4c52076 100644 --- a/src/main/java/net/irisshaders/iris/api/v0/IrisApi.java +++ b/src/main/java/net/irisshaders/iris/api/v0/IrisApi.java @@ -2,9 +2,6 @@ import net.coderbot.iris.apiimpl.IrisApiV0Impl; -import java.nio.ByteBuffer; -import java.util.function.IntFunction; - /** * The entry point to the Iris API, major version 0. This is currently the latest * version of the API. @@ -97,12 +94,4 @@ static IrisApi getInstance() { * @since API v0.0 */ IrisApiConfig getConfig(); - - /** - * Gets a text vertex sink to render into. - * @param maxQuadCount Maximum amount of quads that will be rendered with this sink - * @param bufferProvider An IntFunction that can provide a {@code ByteBuffer} with at minimum the bytes provided by the input parameter - * @since API 0.1 - */ - IrisTextVertexSink createTextVertexSink(int maxQuadCount, IntFunction bufferProvider); } diff --git a/src/main/java/net/irisshaders/iris/api/v0/IrisTextVertexSink.java b/src/main/java/net/irisshaders/iris/api/v0/IrisTextVertexSink.java deleted file mode 100644 index 87a834a64..000000000 --- a/src/main/java/net/irisshaders/iris/api/v0/IrisTextVertexSink.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.irisshaders.iris.api.v0; - -import java.nio.ByteBuffer; - -public interface IrisTextVertexSink { - /** - * Gets the underlying vertex format used for rendering text. - * @return a valid {@code VertexFormat} instance - */ - VertexFormat getUnderlyingVertexFormat(); - /** - * Gets the underlying buffer used for rendering text in the current sink. - * @return a valid {@code ByteBuffer} - */ - ByteBuffer getUnderlyingByteBuffer(); - - /** - * Writes a singular quad with all vertex attributes needed by the current format into the current {@code ByteBuffer}. - * @param x1 Left-most x coordinate of the quad - * @param y1 Top Y coordinate of the quad - * @param x2 Right-most x coordinate of the quad - * @param y2 Bottom Y coordinate of the quad - * @param z Z coordinate of the quad - * @param color Integer-packed ABGR value, with the equation {@code int color = ((int) (a * 255.0F) & 0xFF) << 24 | ((int) (b * 255.0F) & 0xFF) << 16 | ((int) (g * 255.0F) & 0xFF) << 8 | ((int) (r * 255.0F) & 0xFF)} - * @param u1 Top-left U coordinate of the quad texture - * @param v1 Top-left V coordinate of the quad texture - * @param u2 Bottom-right U coordinate of the quad texture - * @param v2 Bottom right V coordinate of the quad texture - * @param light Integer packed light coordinate - */ - void quad(float x1, float y1, float x2, float y2, float z, int color, float u1, float v1, float u2, float v2, int light); -} From d25686919746d507b04bdb04c8dea21303eb846d Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 21 Oct 2023 16:04:27 -0700 Subject: [PATCH 009/301] Shaderpacks now load --- .../angelica/client/Shaders.java | 37 ++++++------------- .../angelica/loading/AngelicaTweaker.java | 27 ++++++-------- src/main/java/net/coderbot/iris/Iris.java | 6 +-- .../iris/compat/mojang/NativeImage.java | 4 +- .../java/net/coderbot/iris/gl/GLDebug.java | 18 +++++---- .../coderbot/iris/gl/IrisRenderSystem.java | 12 +++--- .../iris/gl/framebuffer/GlFramebuffer.java | 13 ++++--- .../iris/gl/program/ProgramUniforms.java | 10 ++--- .../DeferredWorldRenderingPipeline.java | 7 +--- .../iris/rendertarget/RenderTarget.java | 9 +++-- src/main/resources/centerDepth.fsh | 32 ++++++++++++++++ src/main/resources/centerDepth.vsh | 2 + 12 files changed, 98 insertions(+), 79 deletions(-) create mode 100644 src/main/resources/centerDepth.fsh create mode 100644 src/main/resources/centerDepth.vsh diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index 201e0ed7c..c3aef9fb0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -4,10 +4,6 @@ package com.gtnewhorizons.angelica.client; import com.gtnewhorizons.angelica.Tags; -import com.gtnewhorizons.angelica.client.shaders.config.ShadersConfig; -import com.gtnewhorizons.angelica.client.shaders.gl.shader.StandardMacros; -import com.gtnewhorizons.angelica.client.shaders.shaderpack.ShaderPack; -import com.gtnewhorizons.angelica.client.shaders.shaderpack.option.values.MutableOptionValues; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import com.gtnewhorizons.angelica.mixins.interfaces.IModelRenderer; import lombok.Getter; @@ -41,6 +37,8 @@ import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GLContext; +import org.joml.Vector3d; + import java.io.File; import java.io.FileNotFoundException; @@ -48,30 +46,16 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystem; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.InvalidPathException; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Optional; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Stream; -import java.util.zip.ZipException; import static org.lwjgl.opengl.ARBFragmentShader.GL_FRAGMENT_SHADER_ARB; import static org.lwjgl.opengl.ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB; @@ -213,6 +197,11 @@ public class Shaders { private static final double[] previousCameraPosition = new double[3]; private static final double[] cameraPosition = new double[3]; + + public static Vector3d getCameraPosition() { + return new Vector3d(cameraPosition[0], cameraPosition[1], cameraPosition[2]); + } + // Shadow stuff // configuration @@ -3168,19 +3157,17 @@ public static void pushEntity(Block block) { // BlockAliases.getMappedBlockId final int blockId = Block.blockRegistry.getIDForObject(block); entityDataIndex++; - entityData[entityDataIndex * 2] = (Block.blockRegistry.getIDForObject(block) & 0xFFFF) - | (block.getRenderType() << 16); - entityData[entityDataIndex * 2 + 1] = 0; + entityData[entityDataIndex * 2] = (blockId & 0xFFFF) | (block.getRenderType() << 16); + entityData[entityDataIndex * 2 + 1] = metadata; } public static void pushEntity(RenderBlocks rb, Block block, int x, int y, int z) { final int metadata = rb.blockAccess.getBlockMetadata(x, y, z); - // BlockAliases.getMappedBlockId( + // BlockAliases.getMappedBlockId final int blockId = Block.blockRegistry.getIDForObject(block); entityDataIndex++; - entityData[entityDataIndex * 2] = (Block.blockRegistry.getIDForObject(block) & 0xFFFF) - | (block.getRenderType() << 16); - entityData[entityDataIndex * 2 + 1] = rb.blockAccess.getBlockMetadata(x, y, z); + entityData[entityDataIndex * 2] = (blockId & 0xFFFF) | (block.getRenderType() << 16); + entityData[entityDataIndex * 2 + 1] = metadata; } public static void popEntity() { diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index 01ba321e3..4f95c2b0c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -1,19 +1,11 @@ package com.gtnewhorizons.angelica.loading; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - import com.google.common.collect.ImmutableMap; +import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader; import com.gtnewhorizons.angelica.mixins.ArchaicMixins; +import com.gtnewhorizons.angelica.mixins.Mixins; import com.gtnewhorizons.angelica.mixins.TargetedMod; -import net.minecraft.client.Minecraft; +import cpw.mods.fml.relauncher.IFMLLoadingPlugin; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -26,16 +18,19 @@ import org.spongepowered.asm.launch.GlobalProperties; import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper; -import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader; -import com.gtnewhorizons.angelica.mixins.Mixins; - -import cpw.mods.fml.relauncher.IFMLLoadingPlugin; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; @IFMLLoadingPlugin.MCVersion("1.7.10") @IFMLLoadingPlugin.SortingIndex(1100) public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader { - public static final Logger LOGGER = LogManager.getLogger("angelica"); + public static final Logger LOGGER = LogManager.getLogger("Angelica"); // public static boolean ENABLE_SPAM = false; // Enable for more spam public static boolean ENABLE_SPAM = true; diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index e7d75d7ee..0bd9b4605 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -56,7 +56,7 @@ public class Iris { */ public static final String MODNAME = "Angelica"; - public static final IrisLogging logger = new IrisLogging(MODNAME); + public static final IrisLogging logger = new IrisLogging(MODNAME + "Shaders"); private static Path shaderpacksDirectory; private static ShaderpackDirectoryManager shaderpacksDirectoryManager; @@ -122,7 +122,7 @@ public void onEarlyInitialize() { try { irisConfig.initialize(); } catch (IOException e) { - logger.error("Failed to initialize Oculus configuration, default values will be used instead"); + logger.error("Failed to initialize Angelica configuration, default values will be used instead"); logger.error("", e); } @@ -239,7 +239,7 @@ public static void loadShaderpack() { } if (!irisConfig.areShadersEnabled()) { - logger.info("Shaders are disabled because enableShaders is set to false in oculus.properties"); + logger.info("Shaders are disabled because enableShaders is set to false in shaders.properties"); setShadersDisabled(); diff --git a/src/main/java/net/coderbot/iris/compat/mojang/NativeImage.java b/src/main/java/net/coderbot/iris/compat/mojang/NativeImage.java index 7bbfd6cac..83b22b63d 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/NativeImage.java +++ b/src/main/java/net/coderbot/iris/compat/mojang/NativeImage.java @@ -1,7 +1,7 @@ package net.coderbot.iris.compat.mojang; -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import lombok.Getter; +import net.coderbot.iris.Iris; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; @@ -69,7 +69,7 @@ public void writeToFile(File file) throws IOException{ try { ImageIO.write(this, "png", file); } catch(IOException ioexception) { - AngelicaTweaker.LOGGER.info("[TextureDump] Unable to write: ", ioexception); + Iris.logger.info("[TextureDump] Unable to write: ", ioexception); } } public static int combine(int i, int j, int k, int l) { diff --git a/src/main/java/net/coderbot/iris/gl/GLDebug.java b/src/main/java/net/coderbot/iris/gl/GLDebug.java index d55220c9d..fca204d43 100644 --- a/src/main/java/net/coderbot/iris/gl/GLDebug.java +++ b/src/main/java/net/coderbot/iris/gl/GLDebug.java @@ -5,7 +5,6 @@ package net.coderbot.iris.gl; -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.coderbot.iris.Iris; import org.lwjgl.opengl.AMDDebugOutput; import org.lwjgl.opengl.AMDDebugOutputCallback; @@ -73,21 +72,24 @@ public void accept(String str) { */ public static int setupDebugMessageCallback() { if (Iris.capabilities.OpenGL43 || Iris.capabilities.GL_KHR_debug) { - AngelicaTweaker.LOGGER.info("[GL] Using KHR_debug for error logging."); + Iris.logger.info("[GL] Using KHR_debug for error logging."); + GL11.glEnable(GL43.GL_DEBUG_OUTPUT); + GL11.glEnable(GL43.GL_DEBUG_OUTPUT_SYNCHRONOUS); + KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_LOW, null, false); KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, null, false); KHRDebug.glDebugMessageCallback(new KHRDebugCallback()); - if (Iris.capabilities.OpenGL30 && (GL11.glGetInteger(GL30.GL_CONTEXT_FLAGS) & 2) == 0) { - AngelicaTweaker.LOGGER.warn("[GL] Warning: A non-debug context may not produce any debug output."); + if (Iris.capabilities.OpenGL30 && (GL11.glGetInteger(GL30.GL_CONTEXT_FLAGS) & GL43.GL_CONTEXT_FLAG_DEBUG_BIT) == 0) { + Iris.logger.warn("[GL] Warning: A non-debug context may not produce any debug output."); GL11.glDisable(GL43.GL_DEBUG_OUTPUT); return 2; } return 1; } else if (Iris.capabilities.GL_ARB_debug_output) { - AngelicaTweaker.LOGGER.info("[GL] Using ARB_debug_output for error logging."); + Iris.logger.info("[GL] Using ARB_debug_output for error logging."); ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); @@ -96,7 +98,7 @@ public static int setupDebugMessageCallback() { glDebugMessageCallbackARB(new ARBDebugOutputCallback()); return 1; } else if (Iris.capabilities.GL_AMD_debug_output) { - AngelicaTweaker.LOGGER.info("[GL] Using AMD_debug_output for error logging."); + Iris.logger.info("[GL] Using AMD_debug_output for error logging."); AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); @@ -105,7 +107,7 @@ public static int setupDebugMessageCallback() { AMDDebugOutput.glDebugMessageCallbackAMD(new AMDDebugOutputCallback()); return 1; } else { - AngelicaTweaker.LOGGER.info("[GL] No debug output implementation is available, cannot return debug info."); + Iris.logger.info("[GL] No debug output implementation is available, cannot return debug info."); return 0; } } @@ -127,7 +129,7 @@ public static int disableDebugMessages() { AMDDebugOutput.glDebugMessageCallbackAMD(null); return 1; } else { - AngelicaTweaker.LOGGER.info("[GL] No debug output implementation is available, cannot disable debug info."); + Iris.logger.info("[GL] No debug output implementation is available, cannot disable debug info."); return 0; } } diff --git a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java index bd5c14cc1..179c6aacc 100644 --- a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java +++ b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java @@ -136,7 +136,7 @@ public static String getShaderInfoLog(int shader) { return GL20.glGetShaderInfoLog(shader, GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH)); } - public static void drawBuffers(int framebuffer, int[] buffers) { + public static void drawBuffers(int framebuffer, IntBuffer buffers) { dsaState.drawBuffers(framebuffer, buffers); } @@ -266,7 +266,7 @@ public interface DSAAccess { void readBuffer(int framebuffer, int buffer); - void drawBuffers(int framebuffer, int[] buffers); + void drawBuffers(int framebuffer, IntBuffer buffers); int getTexParameteri(int texture, int target, int pname); @@ -316,8 +316,8 @@ public void readBuffer(int framebuffer, int buffer) { } @Override - public void drawBuffers(int framebuffer, int[] buffers) { - ARBDirectStateAccess.glNamedFramebufferDrawBuffers(framebuffer, IntBuffer.wrap(buffers)); + public void drawBuffers(int framebuffer, IntBuffer buffers) { + ARBDirectStateAccess.glNamedFramebufferDrawBuffers(framebuffer, buffers); } @Override @@ -399,9 +399,9 @@ public void readBuffer(int framebuffer, int buffer) { } @Override - public void drawBuffers(int framebuffer, int[] buffers) { + public void drawBuffers(int framebuffer, IntBuffer buffers) { OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, framebuffer); - GL20.glDrawBuffers(IntBuffer.wrap(buffers)); + GL20.glDrawBuffers(buffers); } @Override diff --git a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java index 7f6d746e8..7905ce1ae 100644 --- a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java +++ b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java @@ -7,10 +7,13 @@ import net.coderbot.iris.gl.texture.DepthBufferFormat; import net.coderbot.iris.texture.TextureInfoCache; import net.minecraft.client.renderer.OpenGlHelper; +import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; +import java.nio.IntBuffer; + public class GlFramebuffer extends GlResource { private final Int2IntMap attachments; private final int maxDrawBuffers; @@ -49,12 +52,13 @@ public void addColorAttachment(int index, int texture) { } public void noDrawBuffers() { - IrisRenderSystem.drawBuffers(getGlId(), new int[] { GL11.GL_NONE }); + IntBuffer buffer = BufferUtils.createIntBuffer(1); + buffer.put(GL11.GL_NONE); + IrisRenderSystem.drawBuffers(getGlId(), buffer); } public void drawBuffers(int[] buffers) { - int[] glBuffers = new int[buffers.length]; - int index = 0; + IntBuffer glBuffers = BufferUtils.createIntBuffer(buffers.length); if (buffers.length > maxDrawBuffers) { throw new IllegalArgumentException("Cannot write to more than " + maxDrawBuffers + " draw buffers on this GPU"); @@ -64,8 +68,7 @@ public void drawBuffers(int[] buffers) { if (buffer >= maxColorAttachments) { throw new IllegalArgumentException("Only " + maxColorAttachments + " color attachments are supported on this GPU, but an attempt was made to write to a color attachment with index " + buffer); } - - glBuffers[index++] = GL30.GL_COLOR_ATTACHMENT0 + buffer; + glBuffers.put(GL30.GL_COLOR_ATTACHMENT0 + buffer); } IrisRenderSystem.drawBuffers(getGlId(), glBuffers); diff --git a/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java b/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java index c066959fc..afa585d5d 100644 --- a/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java +++ b/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java @@ -190,14 +190,14 @@ public ProgramUniforms buildUniforms() { continue; } - int size = sizeType.get(0); - int type = sizeType.get(1); + final int size = sizeType.get(0); + final int type = sizeType.get(1); UniformType provided = uniformNames.get(name); - UniformType expected = getExpectedType(type); + final UniformType expected = getExpectedType(type); if (provided == null && !name.startsWith("gl_")) { - String typeName = getTypeName(type); + final String typeName = getTypeName(type); if (isSampler(type) || isImage(type)) { // don't print a warning, samplers and images are managed elsewhere. @@ -205,7 +205,7 @@ public ProgramUniforms buildUniforms() { continue; } - UniformType externalProvided = externalUniformNames.get(name); + final UniformType externalProvided = externalUniformNames.get(name); if (externalProvided != null) { if (externalProvided != expected) { diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 22d299575..c6b5be94d 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -31,7 +31,6 @@ import net.coderbot.iris.postprocess.CompositeRenderer; import net.coderbot.iris.postprocess.FinalPassRenderer; import net.coderbot.iris.rendertarget.NativeImageBackedSingleColorTexture; -import net.coderbot.iris.rendertarget.RenderTarget; import net.coderbot.iris.rendertarget.RenderTargets; import net.coderbot.iris.samplers.IrisImages; import net.coderbot.iris.samplers.IrisSamplers; @@ -165,15 +164,13 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { this.packDirectives = programs.getPackDirectives(); - // TODO: IRIS -// RenderTarget mainTarget = Minecraft.getMinecraft().getMainRenderTarget(); - RenderTarget mainTarget = null; + Minecraft mc = Minecraft.getMinecraft(); int depthTextureId = 0; //mainTarget.getDepthTextureId(); int internalFormat = TextureInfoCache.INSTANCE.getInfo(depthTextureId).getInternalFormat(); DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); - this.renderTargets = new RenderTargets(/*mainTarget.width, mainTarget.height,*/ 0, 0, depthTextureId, + this.renderTargets = new RenderTargets(mc.displayWidth, mc.displayHeight, depthTextureId, 0 /*((Blaze3dRenderTargetExt) mainTarget).iris$getDepthBufferVersion()*/, depthBufferFormat, programs.getPackDirectives().getRenderTargetDirectives().getRenderTargetSettings(), programs.getPackDirectives()); diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java index 257505426..43986dbef 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java @@ -6,6 +6,7 @@ import net.coderbot.iris.gl.texture.PixelFormat; import net.coderbot.iris.gl.texture.PixelType; import org.joml.Vector2i; +import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; @@ -37,11 +38,11 @@ public RenderTarget(Builder builder) { this.width = builder.width; this.height = builder.height; - int[] textures = new int[2]; - GL11.glGenTextures(IntBuffer.wrap(textures)); + IntBuffer textures = BufferUtils.createIntBuffer(2); + GL11.glGenTextures(textures); - this.mainTexture = textures[0]; - this.altTexture = textures[1]; + this.mainTexture = textures.get(0); + this.altTexture = textures.get(1); boolean isPixelFormatInteger = builder.internalFormat.getPixelFormat().isInteger(); setupTexture(mainTexture, builder.width, builder.height, !isPixelFormatInteger); diff --git a/src/main/resources/centerDepth.fsh b/src/main/resources/centerDepth.fsh new file mode 100644 index 000000000..edf76e80a --- /dev/null +++ b/src/main/resources/centerDepth.fsh @@ -0,0 +1,32 @@ +#version VERSIONPLACEHOLDER + +// This will be removed by Iris if the system does not support GL3. +#define IS_GL3 + +uniform sampler2D depth; +uniform sampler2D altDepth; +uniform float lastFrameTime; +uniform float decay; + +#ifdef IS_GL3 +out float oculus_fragColor; +#endif + +void main() { + float currentDepth = texture2D(depth, vec2(0.5)).r; + float decay2 = 1.0 - exp(-decay * lastFrameTime); + float oldDepth = texture2D(altDepth, vec2(0.5)).r; + + #ifdef IS_GL3 + if (isnan(oldDepth)) { + oldDepth = currentDepth; + } + + oculus_fragColor = mix(oldDepth, currentDepth, decay2); + #else + if (oldDepth != oldDepth) { // cheap isNaN + oldDepth = currentDepth; + } + gl_FragColor = vec4(mix(texture2D(altDepth, vec2(0.5)).r, currentDepth, decay2), 0, 0, 0); + #endif +} \ No newline at end of file diff --git a/src/main/resources/centerDepth.vsh b/src/main/resources/centerDepth.vsh new file mode 100644 index 000000000..ce81abb06 --- /dev/null +++ b/src/main/resources/centerDepth.vsh @@ -0,0 +1,2 @@ +#version 120 +void main() { gl_Position = ftransform(); } From a7d59c4d43c169192cb2a1248b22393520a1cca7 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 21 Oct 2023 16:42:38 -0700 Subject: [PATCH 010/301] Ok that was the actual quote... --- README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 284a25f7b..3bdba195d 100644 --- a/README.MD +++ b/README.MD @@ -1,5 +1,5 @@ # Angelica -The little Angel that supports shaders while saving your fps from a certain death -boubou +The little Angle that supports shaders while saving your fps from a certain death -boubou Not yet in an usable state From c57ca455a5fa1e42f52ffb78c2f3417407fcbbfb Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 21 Oct 2023 16:56:39 -0700 Subject: [PATCH 011/301] Found an equivalent for bindWrite --- .../iris/pipeline/DeferredWorldRenderingPipeline.java | 11 +++++------ .../pipeline/FixedFunctionWorldRenderingPipeline.java | 4 ++-- .../coderbot/iris/postprocess/CenterDepthSampler.java | 4 ++-- .../coderbot/iris/postprocess/CompositeRenderer.java | 3 +-- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index c6b5be94d..04e6e89fa 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -310,8 +310,7 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { return null; } else if (source == null) { // still need the custom framebuffer, viewport, and blend mode behavior - GlFramebuffer shadowFb = - shadowTargetsSupplier.get().createShadowFramebuffer(shadowRenderTargets.snapshot(), new int[] {0}); + GlFramebuffer shadowFb = shadowTargetsSupplier.get().createShadowFramebuffer(shadowRenderTargets.snapshot(), new int[] {0}); return new Pass(null, shadowFb, shadowFb, null, BlendModeOverride.OFF, Collections.emptyList(), true); } @@ -764,8 +763,8 @@ public void use() { if (shadowViewport) { GL11.glViewport(0, 0, shadowMapResolution, shadowMapResolution); } else { -// RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); - GL11.glViewport(0, 0, /*main.getWidth(), main.getHeight()*/0,0); + final Minecraft mc = Minecraft.getMinecraft(); + GL11.glViewport(0, 0, mc.displayWidth, mc.displayHeight); } if (program != null && !sodiumTerrainRendering) { @@ -835,7 +834,7 @@ public void destroy() { OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_DRAW_FRAMEBUFFER, 0); OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, 0); -// Minecraft.getMinecraft().getMainRenderTarget().bindWrite(false); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); // Destroy our render targets // @@ -958,7 +957,7 @@ private void prepareRenderTargets() { } // Reset framebuffer and viewport -// Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); } private ComputeProgram[] createShadowComputes(ComputeSource[] compute, ProgramSet programSet) { diff --git a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java index b580d06f7..38ca8bb83 100644 --- a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java @@ -8,6 +8,7 @@ import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; import net.coderbot.iris.shaderpack.CloudSetting; import net.coderbot.iris.uniforms.FrameUpdateNotifier; +import net.minecraft.client.Minecraft; import org.lwjgl.opengl.GL20; import java.util.List; @@ -25,8 +26,7 @@ public FixedFunctionWorldRenderingPipeline() { @Override public void beginLevelRendering() { // Use the default Minecraft framebuffer and ensure that no programs are in use - // TODO: Iris -// Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); GL20.glUseProgram(0); } diff --git a/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java b/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java index 9e8711fa6..53f0b6de6 100644 --- a/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java +++ b/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java @@ -13,6 +13,7 @@ import net.coderbot.iris.gl.texture.PixelType; import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; import net.coderbot.iris.uniforms.SystemTimeUniforms; +import net.minecraft.client.Minecraft; import org.apache.commons.io.IOUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; @@ -92,8 +93,7 @@ public void sampleCenterDepth() { DepthCopyStrategy.fastest(false).copy(this.framebuffer, texture, null, altTexture, 1, 1); //Reset viewport - // TODO: Iris -// Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); } public void setupColorTexture(int texture, InternalTextureFormat format) { diff --git a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java index 23b78e3c7..f4c2d00b7 100644 --- a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java @@ -254,8 +254,7 @@ public void renderAll() { // Make sure to reset the viewport to how it was before... Otherwise weird issues could occur. // Also bind the "main" framebuffer if it isn't already bound. - // TODO: Iris -// Minecraft.getMinecraft().getMainRenderTarget().bindWrite(true); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); ProgramUniforms.clearActiveUniforms(); ProgramSamplers.clearActiveSamplers(); GL20.glUseProgram(0); From 7f806ea1862e50b606e002cd28332c5450b70666 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 22 Oct 2023 22:53:03 -0700 Subject: [PATCH 012/301] Neuter ShaderMod, start using Iris * Mixins * Fix drawBuffers() & bufferStorage() to use direct allocted buffers Swap out GTNH MixinExtras with base --- .../angelica/client/Shaders.java | 163 +++++++++++++----- .../gtnewhorizons/angelica/mixins/Mixins.java | 7 + .../early/renderer/MixinEntityRenderer.java | 6 +- .../early/renderer/MixinRenderBlocks.java | 4 +- .../early/renderer/MixinRenderGlobal.java | 4 +- .../early/shaders/MixinEntityRenderer.java | 46 +++++ .../mixins/early/shaders/MixinItem.java | 10 ++ src/main/java/net/coderbot/iris/Iris.java | 1 + .../iris/compat/mojang/BufferBuilder.java | 89 +++++++++- .../iris/compat/mojang/VertexFormat.java | 3 + .../coderbot/iris/gl/IrisRenderSystem.java | 14 +- .../iris/gl/framebuffer/GlFramebuffer.java | 5 +- .../postprocess/FullScreenQuadRenderer.java | 27 ++- 13 files changed, 299 insertions(+), 80 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinItem.java diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index c3aef9fb0..4771c9d3d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -28,6 +28,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.joml.Vector3d; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.ContextCapabilities; import org.lwjgl.opengl.GL11; @@ -37,8 +38,6 @@ import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GLContext; -import org.joml.Vector3d; - import java.io.File; import java.io.FileNotFoundException; @@ -93,7 +92,6 @@ import static org.lwjgl.opengl.EXTFramebufferObject.glFramebufferTexture2DEXT; import static org.lwjgl.opengl.EXTFramebufferObject.glGenFramebuffersEXT; import static org.lwjgl.util.glu.GLU.gluErrorString; -import static org.lwjgl.util.glu.GLU.gluPerspective; public class Shaders { @@ -647,6 +645,7 @@ public static int checkFramebufferStatus(String location) { } public static int checkGLError(String location) { + if (true) return 0; int errorCode = GL11.glGetError(); if (errorCode != GL11.GL_NO_ERROR) { boolean skipPrint = false; @@ -716,6 +715,7 @@ public static void updateBlockLightLevel() { } public static void init() { + if (true) return; if (isInitialized) { return; } @@ -925,6 +925,7 @@ public static void init() { } public static void resetDisplayList() { + if (true) return; ++numberResetDisplayList; AngelicaTweaker.LOGGER.debug("Reset model renderers"); if (Shaders.useMidTexCoordAttrib || Shaders.useMultiTexCoord3Attrib) { @@ -941,6 +942,7 @@ public static void resetDisplayList() { } public static void resetDisplayListModel(ModelBase mbase) { + if (true) return; if (mbase != null) { for (ModelRenderer obj : mbase.boxList) { if (obj != null) { @@ -951,6 +953,7 @@ public static void resetDisplayListModel(ModelBase mbase) { } public static void resetDisplayListModelRenderer(ModelRenderer mrr) { + if (true) return; ((IModelRenderer) mrr).angelica$resetDisplayList(); if (mrr.childModels != null) { @@ -963,6 +966,7 @@ public static void resetDisplayListModelRenderer(ModelRenderer mrr) { // ---------------------------------------- private static int setupProgram(int program, String vShaderPath, String fShaderPath) { + if (true) return 0; checkGLError("pre setupProgram"); int programid = glCreateProgramObjectARB(); checkGLError("create"); @@ -1061,6 +1065,7 @@ private static String getPreprocessedShaderSources(String filename) { } private static int createVertShader(String filename) { + if (true) return 0; int vertShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); if (vertShader == 0) { return 0; @@ -1104,6 +1109,7 @@ private static void processVertShaderLine(String line) { .compile("^\\s*#include\\s+\"([A-Za-z0-9_\\/\\.]+)\".*$", Pattern.MULTILINE | Pattern.UNIX_LINES); private static int createFragShader(String filename) { + if (true) return 0; int fragShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); if (fragShader == 0) { return 0; @@ -1397,6 +1403,7 @@ private static boolean printLogInfo(int obj, String name) { } public static void setDrawBuffers(IntBuffer drawBuffers) { + if (true) return; if (activeDrawBuffers != drawBuffers) { // printIntBuffer("setDrawBuffers", drawBuffers); activeDrawBuffers = drawBuffers; @@ -1407,6 +1414,7 @@ public static void setDrawBuffers(IntBuffer drawBuffers) { } public static void useProgram(int program) { + if (true) return; // System.out.println((new StringBuilder(32)).append("useProgram ").append(programNames[program])); Shaders.checkGLError("pre-useProgram"); if (isShadowPass) { @@ -1602,6 +1610,7 @@ public static void useProgram(int program) { } public static void setProgramUniform1i(String name, int x) { + if (true) return; int gp = programsID[activeProgram]; if (gp != GL11.GL_NONE) { int uniform = glGetUniformLocationARB(gp, name); @@ -1611,6 +1620,7 @@ public static void setProgramUniform1i(String name, int x) { } public static void setProgramUniform2i(String name, int x, int y) { + if (true) return; int gp = programsID[activeProgram]; if (gp != GL11.GL_NONE) { int uniform = glGetUniformLocationARB(gp, name); @@ -1620,6 +1630,7 @@ public static void setProgramUniform2i(String name, int x, int y) { } public static void setProgramUniform1f(String name, float x) { + if (true) return; int gp = programsID[activeProgram]; if (gp != GL11.GL_NONE) { int uniform = glGetUniformLocationARB(gp, name); @@ -1629,6 +1640,7 @@ public static void setProgramUniform1f(String name, float x) { } public static void setProgramUniform3f(String name, float x, float y, float z) { + if (true) return; int gp = programsID[activeProgram]; if (gp != GL11.GL_NONE) { int uniform = glGetUniformLocationARB(gp, name); @@ -1638,6 +1650,7 @@ public static void setProgramUniform3f(String name, float x, float y, float z) { } public static void setProgramUniformMatrix4ARB(String name, boolean transpose, FloatBuffer matrix) { + if (true) return; int gp = programsID[activeProgram]; if (gp != GL11.GL_NONE && matrix != null) { int uniform = glGetUniformLocationARB(gp, name); @@ -1687,6 +1700,7 @@ private static IntBuffer fillIntBufferZero(IntBuffer buf) { } public static void uninit() { + if (true) return; if (!isInitialized) { return; } @@ -1775,6 +1789,7 @@ private static void resizeShadow() { } private static void setupFrameBuffer() { + if (true) return; if (dfb != 0) { glDeleteFramebuffersEXT(dfb); GL11.glDeleteTextures(dfbDepthTextures); @@ -1843,6 +1858,7 @@ private static void setupFrameBuffer() { } private static void setupShadowFrameBuffer() { + if (true) return; if (usedShadowDepthBuffers == 0) { return; } @@ -1904,6 +1920,8 @@ private static void setupShadowFrameBuffer() { } public static void beginRender(Minecraft minecraft, float f, long l) { + if (true) return; + if (isShadowPass) { return; } @@ -1930,9 +1948,7 @@ public static void beginRender(Minecraft minecraft, float f, long l) { systemTime = System.currentTimeMillis(); if (lastSystemTime == 0) { - lastSystemTime = systemTime; // Initialize lastSystemTime on the first tick so that it is equal to current - // system - // time + lastSystemTime = systemTime; // Initialize lastSystemTime on the first tick so that it is equal to current system time } diffSystemTime = systemTime - lastSystemTime; lastSystemTime = systemTime; @@ -1943,10 +1959,8 @@ public static void beginRender(Minecraft minecraft, float f, long l) { rainStrength = minecraft.theWorld.getRainStrength(f); { float fadeScalar = diffSystemTime * 0.01f; - // float temp1 = (float)Math.exp(Math.log(0.5)*diffWorldTime/((wetness < rainStrength)? drynessHalfLife : - // wetnessHalfLife)); - float temp1 = (float) Math - .exp(Math.log(0.5) * fadeScalar / ((wetness < rainStrength) ? drynessHalfLife : wetnessHalfLife)); + // float temp1 = (float)Math.exp(Math.log(0.5)*diffWorldTime/((wetness < rainStrength)? drynessHalfLife : wetnessHalfLife)); + float temp1 = (float) Math.exp(Math.log(0.5) * fadeScalar / ((wetness < rainStrength) ? drynessHalfLife : wetnessHalfLife)); wetness = wetness * (temp1) + rainStrength * (1 - temp1); } @@ -2123,6 +2137,8 @@ public static void beginRender(Minecraft minecraft, float f, long l) { } public static void setViewport(int vx, int vy, int vw, int vh) { + GL11.glViewport(vx, vy, vw, vh); + if (true) return; GL11.glColorMask(true, true, true, true); if (isShadowPass) { GL11.glViewport(0, 0, shadowMapWidth, shadowMapHeight); @@ -2156,6 +2172,7 @@ public static void setClearColor(float red, float green, float blue, float alpha } public static void clearRenderBuffer() { + if (true) return; if (isShadowPass) { checkGLError("shadow clear pre"); glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, sfbDepthTextures.get(0), 0); GL11.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); @@ -2215,22 +2232,22 @@ public static void setCamera(float f) { modelViewInverse.position(0); if (isShadowPass) { - GL11.glViewport(0, 0, shadowMapWidth, shadowMapHeight); - - GL11.glMatrixMode(GL11.GL_PROJECTION); - GL11.glLoadIdentity(); - - if (shadowMapIsOrtho) { - GL11.glOrtho( -shadowMapHalfPlane, shadowMapHalfPlane, -shadowMapHalfPlane, shadowMapHalfPlane, 0.05f, 256.0f); - } else { - // just backwards compatibility. it's only used when SHADOWFOV is set in the shaders. - gluPerspective(shadowMapFOV, (float) shadowMapWidth / (float) shadowMapHeight, 0.05f, 256.0f); - } - - GL11.glMatrixMode(GL11.GL_MODELVIEW); - GL11.glLoadIdentity(); - GL11.glTranslatef(0.0f, 0.0f, -100.0f); - GL11.glRotatef(90.0f, 1.0f, 0.0f, 0.0f); +// GL11.glViewport(0, 0, shadowMapWidth, shadowMapHeight); +// +// GL11.glMatrixMode(GL11.GL_PROJECTION); +// GL11.glLoadIdentity(); +// +// if (shadowMapIsOrtho) { +// GL11.glOrtho( -shadowMapHalfPlane, shadowMapHalfPlane, -shadowMapHalfPlane, shadowMapHalfPlane, 0.05f, 256.0f); +// } else { +// // just backwards compatibility. it's only used when SHADOWFOV is set in the shaders. +// gluPerspective(shadowMapFOV, (float) shadowMapWidth / (float) shadowMapHeight, 0.05f, 256.0f); +// } +// +// GL11.glMatrixMode(GL11.GL_MODELVIEW); +// GL11.glLoadIdentity(); +// GL11.glTranslatef(0.0f, 0.0f, -100.0f); +// GL11.glRotatef(90.0f, 1.0f, 0.0f, 0.0f); float celestialAngle = mc.theWorld.getCelestialAngle(f); sunAngle = (celestialAngle < 0.75f) ? celestialAngle + 0.25f : celestialAngle - 0.75f; float angle = celestialAngle * (-360.0f); @@ -2239,21 +2256,21 @@ public static void setCamera(float f) { : 0.0f; if (sunAngle <= 0.5) { // day time - GL11.glRotatef(angle - angleInterval, 0.0f, 0.0f, 1.0f); - GL11.glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); // rotate +// GL11.glRotatef(angle - angleInterval, 0.0f, 0.0f, 1.0f); +// GL11.glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); // rotate shadowAngle = sunAngle; } else { // night time - GL11.glRotatef(angle + 180.0f - angleInterval, 0.0f, 0.0f, 1.0f); - GL11.glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); // rotate +// GL11.glRotatef(angle + 180.0f - angleInterval, 0.0f, 0.0f, 1.0f); +// GL11.glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); // rotate shadowAngle = sunAngle - 0.5f; } - if (shadowMapIsOrtho) { - // reduces jitter - float trans = shadowIntervalSize; - float trans2 = trans / 2.0f; - GL11.glTranslatef((float) x % trans - trans2, (float) y % trans - trans2, (float) z % trans - trans2); - } +// if (shadowMapIsOrtho) { +// // reduces jitter +// float trans = shadowIntervalSize; +// float trans2 = trans / 2.0f; +// GL11.glTranslatef((float) x % trans - trans2, (float) y % trans - trans2, (float) z % trans - trans2); +// } GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, (FloatBuffer) shadowProjection.position(0)); invertMat4x((FloatBuffer) shadowProjection.position(0), (FloatBuffer) shadowProjectionInverse.position(0)); @@ -2265,16 +2282,16 @@ public static void setCamera(float f) { shadowModelView.position(0); shadowModelViewInverse.position(0); - setProgramUniformMatrix4ARB("gbufferProjection", false, projection); - setProgramUniformMatrix4ARB("gbufferProjectionInverse", false, projectionInverse); - setProgramUniformMatrix4ARB("gbufferPreviousProjection", false, previousProjection); - setProgramUniformMatrix4ARB("gbufferModelView", false, modelView); - setProgramUniformMatrix4ARB("gbufferModelViewInverse", false, modelViewInverse); - setProgramUniformMatrix4ARB("gbufferPreviousModelView", false, previousModelView); - setProgramUniformMatrix4ARB("shadowProjection", false, shadowProjection); - setProgramUniformMatrix4ARB("shadowProjectionInverse", false, shadowProjectionInverse); - setProgramUniformMatrix4ARB("shadowModelView", false, shadowModelView); - setProgramUniformMatrix4ARB("shadowModelViewInverse", false, shadowModelViewInverse); +// setProgramUniformMatrix4ARB("gbufferProjection", false, projection); +// setProgramUniformMatrix4ARB("gbufferProjectionInverse", false, projectionInverse); +// setProgramUniformMatrix4ARB("gbufferPreviousProjection", false, previousProjection); +// setProgramUniformMatrix4ARB("gbufferModelView", false, modelView); +// setProgramUniformMatrix4ARB("gbufferModelViewInverse", false, modelViewInverse); +// setProgramUniformMatrix4ARB("gbufferPreviousModelView", false, previousModelView); +// setProgramUniformMatrix4ARB("shadowProjection", false, shadowProjection); +// setProgramUniformMatrix4ARB("shadowProjectionInverse", false, shadowProjectionInverse); +// setProgramUniformMatrix4ARB("shadowModelView", false, shadowModelView); +// setProgramUniformMatrix4ARB("shadowModelViewInverse", false, shadowModelViewInverse); // Also render player shadow mc.gameSettings.thirdPersonView = 1; @@ -2286,7 +2303,7 @@ public static void setCamera(float f) { public static void preCelestialRotate() { Shaders.setUpPosition(); - GL11.glRotatef(Shaders.sunPathRotation * 1.0f, 0.0f, 0.0f, 1.0f); +// GL11.glRotatef(Shaders.sunPathRotation * 1.0f, 0.0f, 0.0f, 1.0f); checkGLError("preCelestialRotate"); } @@ -2362,6 +2379,7 @@ private static FloatBuffer invertMat4x(FloatBuffer matIn, FloatBuffer invMatOut) } public static void genCompositeMipmap() { + if (true) return; if (hasGlGenMipmap) { if ((activeCompositeMipmapSetting & (1 << 0)) != 0) { GL13.glActiveTexture(GL13.GL_TEXTURE0); @@ -2400,6 +2418,7 @@ public static void genCompositeMipmap() { } public static void drawComposite() { + if (true) return; GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); GL11.glBegin(GL11.GL_QUADS); GL11.glTexCoord2f(0.0f, 0.0f); @@ -2415,16 +2434,19 @@ public static void drawComposite() { public static void renderDeferred() { checkGLError("pre-renderDeferred"); + if (true) return; renderComposites(ProgramDeferred, 8, false); //OF: mc.getTextureManager().bindTexture(TextureMap.locationBlocksTexture); } public static void renderCompositeFinal() { + if (true) return; checkGLError("pre-renderCompositeFinal"); renderComposites(ProgramComposite, 8, true); } public static void renderComposites(int programBase, int programCount, boolean renderFinal) { + if (true) return; if (isShadowPass) { // useProgram(ProgramNone); return; @@ -2546,6 +2568,7 @@ public static void renderComposites(int programBase, int programCount, boolean r private static void renderFinal() { // final render target isRenderingDfb = false; + if (true) return; mc.getFramebuffer().bindFramebuffer(true); // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // GL11.glViewport(0, 0, mc.displayWidth, mc.displayHeight); @@ -2581,6 +2604,7 @@ private static void renderFinal() { public static void endRender() { + if (true) return; if (isShadowPass) { // useProgram(ProgramNone); checkGLError("shadow endRender"); @@ -2601,6 +2625,7 @@ public static void endRender() { public static void beginSky() { isRenderingSky = true; fogEnabled = true; + if (true) return; setDrawBuffers(dfbDrawBuffers); useProgram(ProgramSkyTextured); pushEntity(-2, 0); @@ -2610,10 +2635,12 @@ public static void setSkyColor(Vec3 v3color) { skyColorR = (float) v3color.xCoord; skyColorG = (float) v3color.yCoord; skyColorB = (float) v3color.zCoord; + if (true) return; setProgramUniform3f("skyColor", skyColorR, skyColorG, skyColorB); } public static void drawHorizon() { + if (true) return; Tessellator tess = Tessellator.instance; float farDistance = mc.gameSettings.renderDistanceChunks * 16; double xzq = farDistance * 0.9238; @@ -2674,6 +2701,7 @@ public static void drawHorizon() { } public static void preSkyList() { + if (true) return; GL11.glColor3f(fogColorR, fogColorG, fogColorB); // GL11.glColor3f(0f, 1f, 0f); // GL11.glDisable(GL11.GL_FOG); @@ -2686,6 +2714,7 @@ public static void preSkyList() { public static void endSky() { isRenderingSky = false; + if (true) return; setDrawBuffers(dfbDrawBuffers); useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); popEntity(); @@ -2699,6 +2728,7 @@ public static void endSky() { // useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); // } public static void beginUpdateChunks() { + if (true) return; // System.out.println("beginUpdateChunks"); checkGLError("beginUpdateChunks1"); checkFramebufferStatus("beginUpdateChunks1"); @@ -2710,6 +2740,7 @@ public static void beginUpdateChunks() { } public static void endUpdateChunks() { + if (true) return; // System.out.println("endUpdateChunks"); checkGLError("endUpdateChunks1"); checkFramebufferStatus("endUpdateChunks1"); @@ -2726,17 +2757,20 @@ public static boolean shouldRenderClouds(GameSettings gs) { } public static void beginClouds() { + if (true) return; fogEnabled = true; pushEntity(-3, 0); useProgram(ProgramTextured); } public static void endClouds() { + if (true) return; disableFog(); popEntity(); } public static void beginTerrain() { + if (true) return; if (isRenderingWorld) { if (isShadowPass) { GL11.glDisable(GL11.GL_CULL_FACE); @@ -2748,6 +2782,7 @@ public static void beginTerrain() { } public static void endTerrain() { + if (true) return; if (isRenderingWorld) { if (isShadowPass) { GL11.glEnable(GL11.GL_CULL_FACE); @@ -2758,6 +2793,7 @@ public static void endTerrain() { } public static void beginBlockEntities() { + if (true) return; if (isRenderingWorld) { checkGLError("beginBlockEntities"); useProgram(Shaders.ProgramTerrain); @@ -2765,6 +2801,7 @@ public static void beginBlockEntities() { } public static void endBlockEntities() { + if (true) return; if (isRenderingWorld) { checkGLError("endBlockEntities"); useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); @@ -2773,6 +2810,7 @@ public static void endBlockEntities() { } public static void beginBlockDestroyProgress() { + if (true) return; if (isRenderingWorld) { useProgram(ProgramTerrain); if (Shaders.configTweakBlockDamage) { @@ -2784,6 +2822,7 @@ public static void beginBlockDestroyProgress() { } public static void endBlockDestroyProgress() { + if (true) return; if (isRenderingWorld) { GL11.glDepthMask(true); useProgram(ProgramTexturedLit); @@ -2791,6 +2830,7 @@ public static void endBlockDestroyProgress() { } public static void beginEntities() { + if (true) return; if (isRenderingWorld) { useProgram(ProgramEntities); if (programsID[activeProgram] != 0) { @@ -2804,12 +2844,14 @@ public static void beginEntities() { } public static void nextEntity() { + if (true) return; if (isRenderingWorld) { useProgram(ProgramEntities); } } public static void beginSpiderEyes() { + if (true) return; if (isRenderingWorld) { useProgram(ProgramSpiderEyes); if (programsID[ProgramSpiderEyes] == programsID[ProgramTextured]) { @@ -2820,12 +2862,14 @@ public static void beginSpiderEyes() { } public static void endEntities() { + if (true) return; if (isRenderingWorld) { useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); } } public static void setEntityHurtFlash(int hurt, int flash) { + if (true) return; if (useEntityHurtFlash && isRenderingWorld && !isShadowPass) { if (uniformEntityHurt != -1) glUniform1iARB(uniformEntityHurt, hurt); if (uniformEntityFlash != -1) glUniform1iARB(uniformEntityFlash, flash >> 24); @@ -2834,10 +2878,12 @@ public static void setEntityHurtFlash(int hurt, int flash) { } public static void resetEntityHurtFlash() { + if (true) return; setEntityHurtFlash(0, 0); } public static void beginLivingDamage() { + if (true) return; if (isRenderingWorld) { ShadersTex.bindTexture(defaultTexture); if (!isShadowPass) { @@ -2848,6 +2894,7 @@ public static void beginLivingDamage() { } public static void endLivingDamage() { + if (true) return; if (isRenderingWorld) { if (!isShadowPass) { // useProgram(ProgramEntities); @@ -2857,23 +2904,27 @@ public static void endLivingDamage() { } public static void beginLitParticles() { + if (true) return; // GL11.glDepthMask(false); Tessellator.instance.setNormal(0f, 0f, 0f); useProgram(ProgramTexturedLit); } public static void beginParticles() { + if (true) return; // GL11.glDepthMask(false); Tessellator.instance.setNormal(0f, 0f, 0f); useProgram(ProgramTextured); } public static void endParticles() { + if (true) return; Tessellator.instance.setNormal(0f, 0f, 0f); useProgram(ProgramTexturedLit); } public static void preWater() { + if (true) return; if (isShadowPass) { if (usedShadowDepthBuffers >= 2) { // copy depth buffer to shadowtex1 @@ -2897,6 +2948,7 @@ public static void preWater() { } public static void beginWater() { + if (true) return; if (isRenderingWorld) { if (!isShadowPass) { // program water @@ -2910,6 +2962,7 @@ public static void beginWater() { } public static void endWater() { + if (true) return; if (isRenderingWorld) { if (isShadowPass) { // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, @@ -2923,6 +2976,7 @@ public static void endWater() { } public static void readCenterDepth() { + if (true) return; if (!isShadowPass) { // Read depth buffer at center of screen for DOF if (centerDepthSmoothEnabled) { @@ -2939,6 +2993,7 @@ public static void readCenterDepth() { } public static void beginWeather() { + if (true) return; if (!isShadowPass) { if (usedDepthBuffers >= 3) { // copy depth buffer to depthtex2 @@ -2962,6 +3017,7 @@ public static void beginWeather() { } public static void endWeather() { + if (true) return; // GL11.glDepthMask(true); GL11.glDisable(GL11.GL_BLEND); useProgram(ProgramTexturedLit); @@ -2973,20 +3029,24 @@ public static void endWeather() { } public static void beginProjectRedHalo() { + if (true) return; useProgram(ProgramBasic); } public static void endProjectRedHalo() { + if (true) return; useProgram(ProgramTexturedLit); } public static void applyHandDepth() { + if (true) return; if (Shaders.configHandDepthMul != 1.0) { GL11.glScaled(1.0, 1.0, Shaders.configHandDepthMul); } } public static void beginHand() { + if (true) return; // GL11.glEnable(GL11.GL_BLEND); // GL11.glDisable(GL11.GL_BLEND); GL11.glMatrixMode(GL11.GL_MODELVIEW); @@ -3000,6 +3060,7 @@ public static void beginHand() { } public static void endHand() { + if (true) return; // GL11.glDisable(GL11.GL_BLEND); checkGLError("pre endHand"); checkFramebufferStatus("pre endHand"); @@ -3013,12 +3074,14 @@ public static void endHand() { } public static void beginFPOverlay() { + if (true) return; // GL11.glDisable(GL11.GL_BLEND); // GL11.glEnable(GL11.GL_BLEND); // GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); } public static void endFPOverlay() { + if (true) return; // GL11.glDisable(GL11.GL_BLEND); } @@ -3057,6 +3120,7 @@ public static void glDisableFog(int cap) { } public static void enableTexture2D() { + if (true) return; if (isRenderingSky) { useProgram(ProgramSkyTextured); } else if (activeProgram == ProgramBasic) { @@ -3065,6 +3129,7 @@ public static void enableTexture2D() { } public static void disableTexture2D() { + if (true) return; if (isRenderingSky) { useProgram(ProgramSkyBasic); } else if (activeProgram == ProgramTextured || activeProgram == ProgramTexturedLit) { @@ -3073,11 +3138,13 @@ public static void disableTexture2D() { } public static void enableFog() { + if (true) return; fogEnabled = true; setProgramUniform1i("fogMode", fogMode); } public static void disableFog() { + if (true) return; fogEnabled = false; setProgramUniform1i("fogMode", 0); } @@ -3107,6 +3174,7 @@ public static void sglFogf(int pname, float param) { public static void enableLightmap() { lightmapEnabled = true; + if (true) return; if (activeProgram == ProgramTextured) { useProgram(ProgramTexturedLit); } @@ -3114,6 +3182,7 @@ public static void enableLightmap() { public static void disableLightmap() { lightmapEnabled = false; + if (true) return; if (activeProgram == ProgramTexturedLit) { useProgram(ProgramTextured); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index fc7e97238..f80a95a4e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -17,6 +17,13 @@ public enum Mixins { "shaders.MixinGuiMainMenu", "shaders.MixinInitRenderer") ), + IRIS_RENDERING(new Builder("Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).addMixinClasses( + "shaders.MixinEntityRenderer", + "shaders.MixinItem" + ) + ), + ANGELICA_ACCESSORS(new Builder("Angelica Accessors").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java index dfe445074..09ba2d0b1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java @@ -1,8 +1,8 @@ package com.gtnewhorizons.angelica.mixins.early.renderer; -import com.gtnewhorizon.mixinextras.injector.ModifyExpressionValue; import com.gtnewhorizons.angelica.client.Shaders; import com.gtnewhorizons.angelica.client.ShadersRender; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import net.minecraft.client.Minecraft; import net.minecraft.client.particle.EffectRenderer; import net.minecraft.client.renderer.EntityRenderer; @@ -76,8 +76,8 @@ public abstract class MixinEntityRenderer { // renderWorld @Inject(at = @At("HEAD"), method = "renderWorld(FJ)V") - private void angelica$beginRender(float p_78471_1_, long p_78471_2_, CallbackInfo ci) { - Shaders.beginRender(this.mc, p_78471_1_, p_78471_2_); + private void angelica$beginRender(float renderPartialTicks, long tickDelta, CallbackInfo ci) { + Shaders.beginRender(this.mc, renderPartialTicks, tickDelta); } @Redirect( diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderBlocks.java index 23ac47815..114527344 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderBlocks.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderBlocks.java @@ -10,8 +10,8 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import com.gtnewhorizon.mixinextras.injector.wrapoperation.Operation; -import com.gtnewhorizon.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.gtnewhorizons.angelica.client.Shaders; @Mixin(RenderBlocks.class) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java index 969fb5cc5..6ec3feffe 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java @@ -17,8 +17,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import com.gtnewhorizon.mixinextras.injector.wrapoperation.Operation; -import com.gtnewhorizon.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.gtnewhorizons.angelica.client.Shaders; @Mixin(RenderGlobal.class) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java new file mode 100644 index 000000000..18d078440 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -0,0 +1,46 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.program.Program; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.coderbot.iris.uniforms.CapturedRenderingState; +import net.coderbot.iris.uniforms.SystemTimeUniforms; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.EntityRenderer; +import org.spongepowered.asm.mixin.Mixin; +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.CallbackInfo; + +@Mixin(EntityRenderer.class) +public class MixinEntityRenderer { + @Unique + private WorldRenderingPipeline pipeline; + + @Inject(at = @At("HEAD"), method = "renderWorld(FJ)V") + private void iris$beginRender(float tickDelta, long startTime, CallbackInfo ci) { + // TODO: Iris +// CapturedRenderingState.INSTANCE.setGbufferModelView(poseStack.last().pose()); +// CapturedRenderingState.INSTANCE.setGbufferProjection(projection); + CapturedRenderingState.INSTANCE.setTickDelta(tickDelta); + SystemTimeUniforms.COUNTER.beginFrame(); + SystemTimeUniforms.TIMER.beginFrame(startTime); + + Program.unbind(); + + pipeline = Iris.getPipelineManager().preparePipeline(Iris.getCurrentDimension()); + + pipeline.beginLevelRendering(); + } + @Inject(method = "renderWorld(FJ)V", at = @At(value = "RETURN", shift = At.Shift.BEFORE)) + private void iris$endLevelRender(float tickDelta, long limitTime, CallbackInfo callback) { + // TODO: Iris +// HandRenderer.INSTANCE.renderTranslucent(poseStack, tickDelta, camera, gameRenderer, pipeline); + Minecraft.getMinecraft().mcProfiler.endStartSection("iris_final"); + pipeline.finalizeLevelRendering(); + pipeline = null; + Program.unbind(); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinItem.java new file mode 100644 index 000000000..e972eebe1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinItem.java @@ -0,0 +1,10 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.irisshaders.iris.api.v0.item.IrisItemLightProvider; +import net.minecraft.item.Item; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(Item.class) +public class MixinItem implements IrisItemLightProvider { + +} diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 0bd9b4605..022d0054f 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -390,6 +390,7 @@ private static void setShadersDisabled() { } private static void setDebug(boolean enable) { + if (true) return; int success; if (enable) { success = GLDebug.setupDebugMessageCallback(); diff --git a/src/main/java/net/coderbot/iris/compat/mojang/BufferBuilder.java b/src/main/java/net/coderbot/iris/compat/mojang/BufferBuilder.java index 880cca0e8..57eccbe6b 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/BufferBuilder.java +++ b/src/main/java/net/coderbot/iris/compat/mojang/BufferBuilder.java @@ -1,10 +1,23 @@ package net.coderbot.iris.compat.mojang; +import net.coderbot.batchedentityrendering.impl.BufferBuilderExt; import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; +import java.util.List; -public class BufferBuilder implements VertexConsumer { +public class BufferBuilder implements VertexConsumer, BufferBuilderExt { + private ByteBuffer buffer; + private List vertexCounts; + private int lastRenderedCountIndex; + private int totalRenderedBytes; + private int nextElementByte; + private int totalUploadedBytes; + private int vertices; + private VertexFormat format; + + private boolean dupeNextVertex; int i; public BufferBuilder() { @@ -12,7 +25,7 @@ public BufferBuilder() { } public BufferBuilder(int i) { - this.i = i; + this.buffer = BufferUtils.createByteBuffer(i * 4); } public void begin(int glQuads, VertexFormat position) {} @@ -36,4 +49,76 @@ public Pair popNextBuffer() { } public void clear() {} + + @Override + public void setupBufferSlice(ByteBuffer buffer, DrawState drawState) { + // add the buffer slice + this.buffer = buffer; + + // add our singular parameter + this.vertexCounts.clear(); + this.vertexCounts.add(drawState); + + // should be zero, just making sure + this.lastRenderedCountIndex = 0; + + // configure the build start (to avoid a warning message) and element offset (probably not important) + this.totalRenderedBytes = drawState.getVertexCount() * drawState.getFormat().getVertexSize(); + this.nextElementByte = this.totalRenderedBytes; + + // should be zero, just making sure + this.totalUploadedBytes = 0; + + // target.vertexCount is never nonzero in this process. + // target.currentElement is never non-null in this process. + // target.currentElementId is never nonzero. + // target.drawMode is irrelevant. + // target.format is irrelevant. + // The final 3 booleans are also irrelevant. + } + + @Override + public void teardownBufferSlice() { + // the parameters got popped by the render call, we don't need to worry about them + // make sure to un-set the buffer to prevent anything bad from happening with it. + this.buffer = null; + + // target.parameters gets reset. + // target.lastParameterIndex gets reset. + // target.buildStart gets reset. + // target.elementOffset gets reset. + // target.nextDrawStart gets reset. + + // target.vertexCount is never nonzero in this process. + // target.currentElement is never non-null in this process. + // target.currentElementId is never nonzero. + // target.drawMode is irrelevant. + // target.format is irrelevant. + // The final 3 booleans are also irrelevant. + } + + @Override + public void splitStrip() { + if (vertices == 0) { + // no strip to split, not building. + return; + } + + duplicateLastVertex(); + dupeNextVertex = true; + } + + private void duplicateLastVertex() { + int i = this.format.getVertexSize(); + this.buffer.position(this.nextElementByte); + ByteBuffer byteBuffer = this.buffer.duplicate(); + byteBuffer.position(this.nextElementByte - i).limit(this.nextElementByte); + this.buffer.put(byteBuffer); + this.nextElementByte += i; + ++this.vertices; + this.ensureVertexCapacity(); + } + protected void ensureVertexCapacity() { + + } } diff --git a/src/main/java/net/coderbot/iris/compat/mojang/VertexFormat.java b/src/main/java/net/coderbot/iris/compat/mojang/VertexFormat.java index 1815b0636..9884e1cc8 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/VertexFormat.java +++ b/src/main/java/net/coderbot/iris/compat/mojang/VertexFormat.java @@ -3,10 +3,12 @@ import com.google.common.collect.ImmutableList; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; +import lombok.Getter; public class VertexFormat { protected final ImmutableList elements; protected final IntList offsets = new IntArrayList(); + @Getter protected final int vertexSize; public VertexFormat(ImmutableList elements) { @@ -22,4 +24,5 @@ public VertexFormat(ImmutableList elements) { public void setupBufferState(long l) {} public void clearBufferState() {} + } diff --git a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java index 179c6aacc..f0d838fa1 100644 --- a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java +++ b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java @@ -152,11 +152,11 @@ public static void readPixels(int x, int y, int width, int height, int format, i GL11.glReadPixels(x, y, width, height, format, type, FloatBuffer.wrap(pixels)); } - public static void bufferData(int target, float[] data, int usage) { - GL15.glBufferData(target, FloatBuffer.wrap(data), usage); + public static void bufferData(int target, FloatBuffer data, int usage) { + GL15.glBufferData(target, data, usage); } - public static int bufferStorage(int target, float[] data, int usage) { + public static int bufferStorage(int target, FloatBuffer data, int usage) { return dsaState.bufferStorage(target, data, usage); } @@ -274,7 +274,7 @@ public interface DSAAccess { void bindTextureToUnit(int unit, int texture); - int bufferStorage(int target, float[] data, int usage); + int bufferStorage(int target, FloatBuffer data, int usage); void blitFramebuffer(int source, int dest, int offsetX, int offsetY, int width, int height, int offsetX2, int offsetY2, int width2, int height2, int bufferChoice, int filter); @@ -340,9 +340,9 @@ public void bindTextureToUnit(int unit, int texture) { } @Override - public int bufferStorage(int target, float[] data, int usage) { + public int bufferStorage(int target, FloatBuffer data, int usage) { int buffer = GL45.glCreateBuffers(); - GL45.glNamedBufferData(buffer, FloatBuffer.wrap(data), usage); + GL45.glNamedBufferData(buffer, data, usage); return buffer; } @@ -425,7 +425,7 @@ public void bindTextureToUnit(int unit, int texture) { } @Override - public int bufferStorage(int target, float[] data, int usage) { + public int bufferStorage(int target, FloatBuffer data, int usage) { int buffer = GL15.glGenBuffers(); GL15.glBindBuffer(target, buffer); bufferData(target, data, usage); diff --git a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java index 7905ce1ae..eaea1105f 100644 --- a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java +++ b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java @@ -59,18 +59,17 @@ public void noDrawBuffers() { public void drawBuffers(int[] buffers) { IntBuffer glBuffers = BufferUtils.createIntBuffer(buffers.length); + int index = 0; if (buffers.length > maxDrawBuffers) { throw new IllegalArgumentException("Cannot write to more than " + maxDrawBuffers + " draw buffers on this GPU"); } - for (int buffer : buffers) { if (buffer >= maxColorAttachments) { throw new IllegalArgumentException("Only " + maxColorAttachments + " color attachments are supported on this GPU, but an attempt was made to write to a color attachment with index " + buffer); } - glBuffers.put(GL30.GL_COLOR_ATTACHMENT0 + buffer); + glBuffers.put(index++, GL30.GL_COLOR_ATTACHMENT0 + buffer); } - IrisRenderSystem.drawBuffers(getGlId(), glBuffers); } diff --git a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java index 3f9492e12..933f08466 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java @@ -2,9 +2,12 @@ import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.compat.mojang.DefaultVertexFormat; +import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; +import java.nio.FloatBuffer; + /** * Renders a full-screen textured quad to the screen. Used in composite / deferred rendering. */ @@ -67,20 +70,16 @@ public static void end() { * Creates and uploads a vertex buffer containing a single full-screen quad */ private static int createQuad() { - float[] vertices = new float[] { - // Vertex 0: Top right corner - 1.0F, 1.0F, 0.0F, - 1.0F, 1.0F, - // Vertex 1: Top left corner - 0.0F, 1.0F, 0.0F, - 0.0F, 1.0F, - // Vertex 2: Bottom right corner - 1.0F, 0.0F, 0.0F, - 1.0F, 0.0F, - // Vertex 3: Bottom left corner - 0.0F, 0.0F, 0.0F, - 0.0F, 0.0F - }; + FloatBuffer vertices = BufferUtils.createFloatBuffer(20); + vertices.put(new float[] { + // Vertex 0: Top right corner + 1.0F, 1.0F, 0.0F, 1.0F, 1.0F, + // Vertex 1: Top left corner + 0.0F, 1.0F, 0.0F, 0.0F, 1.0F, + // Vertex 2: Bottom right corner + 1.0F, 0.0F, 0.0F, 1.0F, 0.0F, + // Vertex 3: Bottom left corner + 0.0F, 0.0F, 0.0F, 0.0F, 0.0F }).rewind(); return IrisRenderSystem.bufferStorage(GL15.GL_ARRAY_BUFFER, vertices, GL15.GL_STATIC_DRAW); } From 5c0cfdb069c2d1906023826d0eb61749ad1d3834 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 28 Oct 2023 17:19:06 -0700 Subject: [PATCH 013/301] Fixes * BSL_v7.1.04.1_Neon now "loads" * Move camera/fog/clear color/blend mixins to Iris and hook into the state update notifiers * First pass at getting Depth & Color Buffers setup * Implement required MatrixStack/PoseStack functionality * Debugging information about uniforms and their locations to help track down non implemented uniforms * More int[] -> IntBuffer * Camera Uniforms should now work * More CapturedRenderingState --- .../angelica/client/Shaders.java | 23 +--- .../early/renderer/MixinEntityRenderer.java | 32 ----- .../early/shaders/MixinEntityRenderer.java | 127 +++++++++++++++++- .../mixins/early/shaders/MixinMinecraft.java | 40 ++++-- .../early/shaders/MixinOpenGlHelper.java | 52 +++++++ .../iris/compat/mojang/Constants.java | 6 + .../iris/compat/mojang/PoseStack.java | 60 ++++++++- .../coderbot/iris/gl/IrisRenderSystem.java | 12 +- .../iris/gl/program/ProgramUniforms.java | 8 ++ .../iris/gl/uniform/MatrixUniform.java | 4 +- .../DeferredWorldRenderingPipeline.java | 85 ++++-------- .../iris/pipeline/ShadowRenderer.java | 7 +- .../iris/postprocess/FinalPassRenderer.java | 26 ++-- .../iris/rendertarget/ColorTexture.java | 35 +++++ .../iris/rendertarget/DepthTexture.java | 2 +- .../iris/rendertarget/IRenderTargetExt.java | 7 + .../iris/rendertarget/RenderTargets.java | 74 ++++------ .../coderbot/iris/shadow/ShadowMatrices.java | 19 ++- .../iris/uniforms/CameraUniforms.java | 4 +- .../iris/uniforms/CapturedRenderingState.java | 75 +++++++++-- .../iris/uniforms/CelestialUniforms.java | 15 +-- .../iris/uniforms/CommonUniforms.java | 11 +- .../iris/uniforms/MatrixUniforms.java | 3 +- 23 files changed, 489 insertions(+), 238 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinOpenGlHelper.java create mode 100644 src/main/java/net/coderbot/iris/compat/mojang/Constants.java create mode 100644 src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java create mode 100644 src/main/java/net/coderbot/iris/rendertarget/IRenderTargetExt.java diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index 4771c9d3d..1f5515fb7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -2210,12 +2210,12 @@ public static void clearRenderBuffer() { checkGLError("clear"); } - public static void setCamera(float f) { + public static void setCamera(float tickDelta) { EntityLivingBase viewEntity = mc.renderViewEntity; - double x = viewEntity.lastTickPosX + (viewEntity.posX - viewEntity.lastTickPosX) * f; - double y = viewEntity.lastTickPosY + (viewEntity.posY - viewEntity.lastTickPosY) * f; - double z = viewEntity.lastTickPosZ + (viewEntity.posZ - viewEntity.lastTickPosZ) * f; + double x = viewEntity.lastTickPosX + (viewEntity.posX - viewEntity.lastTickPosX) * tickDelta; + double y = viewEntity.lastTickPosY + (viewEntity.posY - viewEntity.lastTickPosY) * tickDelta; + double z = viewEntity.lastTickPosZ + (viewEntity.posZ - viewEntity.lastTickPosZ) * tickDelta; cameraPosition[0] = x; cameraPosition[1] = y; @@ -2248,7 +2248,7 @@ public static void setCamera(float f) { // GL11.glLoadIdentity(); // GL11.glTranslatef(0.0f, 0.0f, -100.0f); // GL11.glRotatef(90.0f, 1.0f, 0.0f, 0.0f); - float celestialAngle = mc.theWorld.getCelestialAngle(f); + float celestialAngle = mc.theWorld.getCelestialAngle(tickDelta); sunAngle = (celestialAngle < 0.75f) ? celestialAngle + 0.25f : celestialAngle - 0.75f; float angle = celestialAngle * (-360.0f); float angleInterval = shadowAngleInterval > 0.0f @@ -2282,22 +2282,13 @@ public static void setCamera(float f) { shadowModelView.position(0); shadowModelViewInverse.position(0); -// setProgramUniformMatrix4ARB("gbufferProjection", false, projection); -// setProgramUniformMatrix4ARB("gbufferProjectionInverse", false, projectionInverse); -// setProgramUniformMatrix4ARB("gbufferPreviousProjection", false, previousProjection); -// setProgramUniformMatrix4ARB("gbufferModelView", false, modelView); -// setProgramUniformMatrix4ARB("gbufferModelViewInverse", false, modelViewInverse); -// setProgramUniformMatrix4ARB("gbufferPreviousModelView", false, previousModelView); -// setProgramUniformMatrix4ARB("shadowProjection", false, shadowProjection); -// setProgramUniformMatrix4ARB("shadowProjectionInverse", false, shadowProjectionInverse); -// setProgramUniformMatrix4ARB("shadowModelView", false, shadowModelView); -// setProgramUniformMatrix4ARB("shadowModelViewInverse", false, shadowModelViewInverse); - // Also render player shadow mc.gameSettings.thirdPersonView = 1; checkGLError("setCamera"); return; } + + checkGLError("setCamera"); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java index 09ba2d0b1..738d5e89c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java @@ -21,11 +21,8 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import java.nio.FloatBuffer; - @Mixin(EntityRenderer.class) public abstract class MixinEntityRenderer { @@ -96,12 +93,6 @@ public abstract class MixinEntityRenderer { Shaders.clearRenderBuffer(); } - @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/EntityRenderer;setupCameraTransform(FI)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$setCamera(float p_78471_1_, long p_78471_2_, CallbackInfo ci) { - Shaders.setCamera(p_78471_1_); - } - @Redirect(at = @At(opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/settings/GameSettings;renderDistanceChunks:I", value = "FIELD"), method = "renderWorld(FJ)V") private int angelica$isShadowPass(GameSettings gameSettings) { @@ -280,29 +271,6 @@ public abstract class MixinEntityRenderer { Shaders.endClouds(); } - // updateFogColor - - @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glClearColor(FFFF)V", value = "INVOKE"), method = "updateFogColor(F)V") - private void angelica$setClearColor(float red, float green, float blue, float alpha) { - Shaders.setClearColor(red, green, blue, alpha); - } - - // setupFog - - @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glFogi(II)V", value = "INVOKE"), method = "setupFog(IF)V") - private void angelica$sglFogi(int pname, int param) { - Shaders.sglFogi(pname, param); - } - - @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glFogf(IF)V", value = "INVOKE"), method = "setupFog(IF)V") - private void angelica$sglFogf(int pname, float param) { - Shaders.sglFogf(pname, param); - } - // setFogColorBuffer - @Inject(at = @At("HEAD"), method = "setFogColorBuffer(FFFF)Ljava/nio/FloatBuffer;") - private void angelica$setFogColor(float red, float green, float blue, float alpha, CallbackInfoReturnable cir) { - Shaders.setFogColor(red, green, blue); - } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index 18d078440..b9143cfc9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -2,27 +2,80 @@ import net.coderbot.iris.Iris; import net.coderbot.iris.gl.program.Program; +import net.coderbot.iris.gl.state.StateUpdateNotifiers; import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.coderbot.iris.uniforms.CapturedRenderingState; import net.coderbot.iris.uniforms.SystemTimeUniforms; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.renderer.OpenGlHelper; +import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; 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.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.nio.FloatBuffer; @Mixin(EntityRenderer.class) public class MixinEntityRenderer { - @Unique - private WorldRenderingPipeline pipeline; + @Unique private static Runnable fogToggleListener; + @Unique private static Runnable fogModeListener; + @Unique private static Runnable fogStartListener; + @Unique private static Runnable fogEndListener; + @Unique private static Runnable fogDensityListener; + @Unique private static Runnable blendFuncListener; + @Unique private WorldRenderingPipeline pipeline; + + + private void sglFogf(int pname, float param) { + GL11.glFogf(pname, param); + switch (pname) { + case GL11.GL_FOG_DENSITY: + if (fogDensityListener != null) { + fogDensityListener.run(); + } + break; + case GL11.GL_FOG_START: + if (fogStartListener != null) { + fogStartListener.run(); + } + break; + case GL11.GL_FOG_END: + if (fogEndListener != null) { + fogEndListener.run(); + } + break; + } + } + + private void sglFogi(int pname, int param) { + GL11.glFogi(pname, param); + if (pname == GL11.GL_FOG_MODE) { + if (fogModeListener != null) { + fogModeListener.run(); + } + } + } + + private void toggleFog(boolean enable) { + if (fogToggleListener != null) { + fogToggleListener.run(); + } + } + + + @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/EntityRenderer;setupCameraTransform(FI)V", value = "INVOKE"), method = "renderWorld(FJ)V") + private void iris$setCamera(float tickDelta, long startTime, CallbackInfo ci) { + CapturedRenderingState.INSTANCE.setCamera(tickDelta); + } + @Inject(at = @At("HEAD"), method = "renderWorld(FJ)V") private void iris$beginRender(float tickDelta, long startTime, CallbackInfo ci) { - // TODO: Iris -// CapturedRenderingState.INSTANCE.setGbufferModelView(poseStack.last().pose()); -// CapturedRenderingState.INSTANCE.setGbufferProjection(projection); CapturedRenderingState.INSTANCE.setTickDelta(tickDelta); SystemTimeUniforms.COUNTER.beginFrame(); SystemTimeUniforms.TIMER.beginFrame(startTime); @@ -33,6 +86,30 @@ public class MixinEntityRenderer { pipeline.beginLevelRendering(); } + // Blend + + @Redirect(method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/OpenGlHelper;glBlendFunc(IIII)V")) + private void iris$glBlendFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { + OpenGlHelper.glBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); + CapturedRenderingState.INSTANCE.setBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); + + } + @Redirect(method="renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V")) + private void iris$glEnable(int cap) { + GL11.glEnable(cap); + if (cap == GL11.GL_BLEND) { + CapturedRenderingState.INSTANCE.setBlendEnabled(true); + } + } + + @Redirect(method="renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V")) + private void iris$glDisable(int cap) { + GL11.glDisable(cap); + if (cap == GL11.GL_BLEND) { + CapturedRenderingState.INSTANCE.setBlendEnabled(false); + } + } + @Inject(method = "renderWorld(FJ)V", at = @At(value = "RETURN", shift = At.Shift.BEFORE)) private void iris$endLevelRender(float tickDelta, long limitTime, CallbackInfo callback) { // TODO: Iris @@ -43,4 +120,44 @@ public class MixinEntityRenderer { Program.unbind(); } + // setFogColorBuffer + @Inject(at = @At("HEAD"), method = "setFogColorBuffer(FFFF)Ljava/nio/FloatBuffer;") + private void iris$setFogColor(float red, float green, float blue, float alpha, CallbackInfoReturnable cir) { + CapturedRenderingState.INSTANCE.setFogColor(red, green, blue); + } + + // updateFogColor + + @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glClearColor(FFFF)V", value = "INVOKE"), method = "updateFogColor(F)V") + private void iris$setClearColor(float red, float green, float blue, float alpha) { + CapturedRenderingState.INSTANCE.setClearColor(red, green, blue, alpha); + } + + + + + // setupFog + + @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glFogi(II)V", value = "INVOKE"), method = "setupFog(IF)V") + private void iris$sglFogi(int pname, int param) { + sglFogi(pname, param); + } + + @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glFogf(IF)V", value = "INVOKE"), method = "setupFog(IF)V") + private void iris$sglFogf(int pname, float param) { + sglFogf(pname, param); + } + + + + + static { + StateUpdateNotifiers.fogToggleNotifier = listener -> fogToggleListener = listener; + StateUpdateNotifiers.fogModeNotifier = listener -> fogModeListener = listener; + StateUpdateNotifiers.fogStartNotifier = listener -> fogStartListener = listener; + StateUpdateNotifiers.fogEndNotifier = listener -> fogEndListener = listener; + StateUpdateNotifiers.fogDensityNotifier = listener -> fogDensityListener = listener; + StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener; + } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinMinecraft.java index 8d80674f3..b559db801 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinMinecraft.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinMinecraft.java @@ -1,27 +1,43 @@ package com.gtnewhorizons.angelica.mixins.early.shaders; +import com.gtnewhorizons.angelica.client.Shaders; +import net.coderbot.iris.rendertarget.IRenderTargetExt; import net.minecraft.client.Minecraft; import net.minecraft.profiler.IPlayerUsage; - import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.gtnewhorizons.angelica.client.Shaders; - @Mixin(Minecraft.class) -public abstract class MixinMinecraft implements IPlayerUsage { - - @Inject( - method = "startGame()V", - at = @At( - ordinal = 1, - shift = At.Shift.AFTER, - value = "INVOKE", - target = "Lnet/minecraft/client/Minecraft;checkGLError(Ljava/lang/String;)V")) +public abstract class MixinMinecraft implements IPlayerUsage, IRenderTargetExt { + private int iris$depthBufferVersion; + + private int iris$colorBufferVersion; + + + @Inject(method = "startGame()V", + at = @At(ordinal = 1, shift = At.Shift.AFTER, value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;checkGLError(Ljava/lang/String;)V")) private void angelica$Startup(CallbackInfo ci) { // Start the Shaders Shaders.startup(((Minecraft) ((Object) this))); } + + + @Inject(method = "updateFramebufferSize()V", at = @At("HEAD")) + private void iris$onDestroyBuffers(CallbackInfo ci) { + iris$depthBufferVersion++; + iris$colorBufferVersion++; + } + + @Override + public int iris$getDepthBufferVersion() { + return iris$depthBufferVersion; + } + + @Override + public int iris$getColorBufferVersion() { + return iris$colorBufferVersion; + } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinOpenGlHelper.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinOpenGlHelper.java new file mode 100644 index 000000000..59e125c7d --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinOpenGlHelper.java @@ -0,0 +1,52 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.minecraft.client.renderer.OpenGlHelper; +import org.lwjgl.opengl.GL30; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(OpenGlHelper.class) +public class MixinOpenGlHelper { + private static int iris$drawFramebuffer = 0; + private static int iris$readFramebuffer = 0; + + @Inject(method="func_153171_g", at=@At("HEAD"), cancellable=true) + private static void iris$avoidRedundantBind(int target, int framebuffer, CallbackInfo ci) { + if (target == GL30.GL_FRAMEBUFFER) { + if (iris$drawFramebuffer == target && iris$readFramebuffer == target) { + ci.cancel(); + } else { + iris$drawFramebuffer = framebuffer; + iris$readFramebuffer = framebuffer; + } + } else if (target == GL30.GL_DRAW_FRAMEBUFFER) { + if (iris$drawFramebuffer == target) { + ci.cancel(); + } else { + iris$drawFramebuffer = framebuffer; + } + } else if (target == GL30.GL_READ_FRAMEBUFFER) { + if (iris$readFramebuffer == target) { + ci.cancel(); + } else { + iris$readFramebuffer = framebuffer; + } + } else { + throw new IllegalStateException("Invalid framebuffer target: " + target); + } + } + + @Inject(method="func_153174_h", at=@At("HEAD")) + private static void iris$trackFramebufferDelete(int framebuffer, CallbackInfo ci) { + if (iris$drawFramebuffer == framebuffer) { + iris$drawFramebuffer = 0; + } + + if (iris$readFramebuffer == framebuffer) { + iris$readFramebuffer = 0; + } + } + +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/Constants.java b/src/main/java/net/coderbot/iris/compat/mojang/Constants.java new file mode 100644 index 000000000..6e16f32d8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/compat/mojang/Constants.java @@ -0,0 +1,6 @@ +package net.coderbot.iris.compat.mojang; + +public class Constants { + + public final static float DEGREES_TO_RADIANS = (float)Math.PI / 180.0F; +} diff --git a/src/main/java/net/coderbot/iris/compat/mojang/PoseStack.java b/src/main/java/net/coderbot/iris/compat/mojang/PoseStack.java index df75e025c..4c16e56d9 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/PoseStack.java +++ b/src/main/java/net/coderbot/iris/compat/mojang/PoseStack.java @@ -1,27 +1,73 @@ package net.coderbot.iris.compat.mojang; +import com.google.common.collect.Queues; +import org.joml.Matrix3f; import org.joml.Matrix4f; +import java.util.Deque; + public class PoseStack { + private final Deque poseStack; + + public PoseStack() { + this.poseStack = Queues.newArrayDeque(); + poseStack.add(new Pose(new Matrix4f().identity(), new Matrix3f().identity())); + } public Pose last() { - return null; + return (Pose)this.poseStack.getLast(); } - public void pushPose() {} + public void pushPose() { + final Pose lv = (Pose)this.poseStack.getLast(); + this.poseStack.addLast(new Pose(new Matrix4f(lv.pose), new Matrix3f(lv.normal))); + } - public void popPose() {} + public void popPose() { + this.poseStack.removeLast(); + } + public boolean clear() { + return this.poseStack.size() == 1; + } + + public void translate(double d, double e, double f) { + final Pose lv = (Pose)this.poseStack.getLast(); + lv.pose.translate((float)d, (float)e, (float)f); + } + public void rotateX(float f) { + final Pose lv = (Pose)this.poseStack.getLast(); + lv.pose.rotateX(f); + lv.normal.rotateX(f); + } + + public void rotateY(float f) { + final Pose lv = (Pose)this.poseStack.getLast(); + lv.pose.rotateY(f); + lv.normal.rotateY(f); + } + + public void rotateZ(float f) { + final Pose lv = (Pose)this.poseStack.getLast(); + lv.pose.rotateZ(f); + lv.normal.rotateZ(f); + } - public void translate(double v, double v1, double v2) {} public static final class Pose { + private final Matrix4f pose; + private final Matrix3f normal; + + private Pose(Matrix4f pose, Matrix3f normal) { + this.pose = pose; + this.normal = normal; + } public Matrix4f pose() { - return null; + return pose; } - public Matrix4f normal() { - return null; + public Matrix3f normal() { + return normal; } } diff --git a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java index f0d838fa1..e1b04a173 100644 --- a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java +++ b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java @@ -112,7 +112,7 @@ public static int getUniformLocation(int programId, String name) { return GL20.glGetUniformLocation(programId, name); } - public static void texParameteriv(int texture, int target, int pname, int[] params) { + public static void texParameteriv(int texture, int target, int pname, IntBuffer params) { dsaState.texParameteriv(texture, target, pname, params); } @@ -262,7 +262,7 @@ public interface DSAAccess { void texParameteri(int texture, int target, int pname, int param); void texParameterf(int texture, int target, int pname, float param); - void texParameteriv(int texture, int target, int pname, int[] params); + void texParameteriv(int texture, int target, int pname, IntBuffer params); void readBuffer(int framebuffer, int buffer); @@ -306,8 +306,8 @@ public void texParameterf(int texture, int target, int pname, float param) { } @Override - public void texParameteriv(int texture, int target, int pname, int[] params) { - ARBDirectStateAccess.glTextureParameter(texture, pname, IntBuffer.wrap(params)); + public void texParameteriv(int texture, int target, int pname, IntBuffer params) { + ARBDirectStateAccess.glTextureParameter(texture, pname, params); } @Override @@ -387,9 +387,9 @@ public void texParameterf(int texture, int target, int pname, float param) { } @Override - public void texParameteriv(int texture, int target, int pname, int[] params) { + public void texParameteriv(int texture, int target, int pname, IntBuffer params) { GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); - GL11.glTexParameter(target, pname, IntBuffer.wrap(params)); + GL11.glTexParameter(target, pname, params); } @Override diff --git a/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java b/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java index afa585d5d..22238f65b 100644 --- a/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java +++ b/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java @@ -140,6 +140,9 @@ protected Builder(String name, int program) { @Override public Builder addUniform(UniformUpdateFrequency updateFrequency, Uniform uniform) { Objects.requireNonNull(uniform); + if(uniform == null) { + throw new NullPointerException("uniform"); + } switch (updateFrequency) { case ONCE: @@ -255,6 +258,11 @@ public ProgramUniforms buildUniforms() { dynamic.remove(name); } } + // iterate over perFrame and print each uniform + Iris.logger.info("UNIFORMS"); + for (Map.Entry entry : perFrame.entrySet()) { + Iris.logger.debug("[" + this.name + "] perFrame uniform: " + entry.getKey() + " " + entry.getValue().getLocation()); + } return new ProgramUniforms(ImmutableList.copyOf(once.values()), ImmutableList.copyOf(perTick.values()), ImmutableList.copyOf(perFrame.values()), ImmutableList.copyOf(dynamic.values()), ImmutableList.copyOf(notifiersToReset)); diff --git a/src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java b/src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java index 6c3928ebd..8b7d84fed 100644 --- a/src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java +++ b/src/main/java/net/coderbot/iris/gl/uniform/MatrixUniform.java @@ -22,7 +22,9 @@ public class MatrixUniform extends Uniform { @Override public void update() { final Matrix4f newValue = value.get(); - + if( newValue == null ){ + throw new RuntimeException("MatrixUniform value is null"); + } if (!newValue.equals(cachedValue)) { cachedValue = new Matrix4f(newValue); diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 04e6e89fa..d9f717ad4 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -3,6 +3,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Ints; +import net.coderbot.iris.rendertarget.IRenderTargetExt; import net.coderbot.iris.Iris; import net.coderbot.iris.block_rendering.BlockMaterialMapping; import net.coderbot.iris.block_rendering.BlockRenderingSettings; @@ -22,7 +23,6 @@ import net.coderbot.iris.gl.program.ProgramBuilder; import net.coderbot.iris.gl.program.ProgramImages; import net.coderbot.iris.gl.program.ProgramSamplers; -import net.coderbot.iris.gl.texture.DepthBufferFormat; import net.coderbot.iris.layer.GbufferPrograms; import net.coderbot.iris.pipeline.transform.PatchShaderType; import net.coderbot.iris.pipeline.transform.TransformPatcher; @@ -47,7 +47,6 @@ import net.coderbot.iris.shaderpack.loading.ProgramId; import net.coderbot.iris.shaderpack.texture.TextureStage; import net.coderbot.iris.shadows.ShadowRenderTargets; -import net.coderbot.iris.texture.TextureInfoCache; import net.coderbot.iris.texture.format.TextureFormat; import net.coderbot.iris.texture.format.TextureFormatLoader; import net.coderbot.iris.texture.pbr.PBRTextureHolder; @@ -63,6 +62,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3d; import org.joml.Vector4f; +import org.joml.Vector4i; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL30; @@ -83,6 +83,9 @@ * Encapsulates the compiled shader program objects for the currently loaded shaderpack. */ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, RenderTargetStateListener { + private final static int SRC_ALPHA = 770; + private final static int ONE_MINUS_SRC_ALPHA = 771; + private final static int ONE = 1; private final RenderTargets renderTargets; @Nullable @@ -166,13 +169,8 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { Minecraft mc = Minecraft.getMinecraft(); - int depthTextureId = 0; //mainTarget.getDepthTextureId(); - int internalFormat = TextureInfoCache.INSTANCE.getInfo(depthTextureId).getInternalFormat(); - DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); - - this.renderTargets = new RenderTargets(mc.displayWidth, mc.displayHeight, depthTextureId, - 0 /*((Blaze3dRenderTargetExt) mainTarget).iris$getDepthBufferVersion()*/, - depthBufferFormat, programs.getPackDirectives().getRenderTargetDirectives().getRenderTargetSettings(), programs.getPackDirectives()); + this.renderTargets = new RenderTargets(mc.displayWidth, mc.displayHeight, ((IRenderTargetExt)mc).iris$getDepthBufferVersion(), + programs.getPackDirectives().getRenderTargetDirectives().getRenderTargetSettings(), programs.getPackDirectives()); this.sunPathRotation = programs.getPackDirectives().getSunPathRotation(); @@ -181,8 +179,7 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { if (shadowDirectives.isDistanceRenderMulExplicit()) { if (shadowDirectives.getDistanceRenderMul() >= 0.0) { // add 15 and then divide by 16 to ensure we're rounding up - forcedShadowRenderDistanceChunks = - OptionalInt.of(((int) (shadowDirectives.getDistance() * shadowDirectives.getDistanceRenderMul()) + 15) / 16); + forcedShadowRenderDistanceChunks = OptionalInt.of(((int) (shadowDirectives.getDistance() * shadowDirectives.getDistanceRenderMul()) + 15) / 16); } else { forcedShadowRenderDistanceChunks = OptionalInt.of(-1); } @@ -248,7 +245,7 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { this.finalPassRenderer = new FinalPassRenderer(programs, renderTargets, customTextureManager.getNoiseTexture(), updateNotifier, flipper.snapshot(), centerDepthSampler, shadowTargetsSupplier, customTextureManager.getCustomTextureIdMap(TextureStage.COMPOSITE_AND_FINAL), - this.compositeRenderer.getFlippedAtLeastOnceFinal()); + this.compositeRenderer.getFlippedAtLeastOnceFinal(), getRenderTargets().getColorTexture().getTextureId()); // [(textured=false,lightmap=false), (textured=true,lightmap=false), (textured=true,lightmap=true)] ProgramId[] ids = new ProgramId[] { @@ -351,15 +348,12 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { this.shadowRenderer = null; } - this.clearPassesFull = ClearPassCreator.createClearPasses(renderTargets, true, - programs.getPackDirectives().getRenderTargetDirectives()); - this.clearPasses = ClearPassCreator.createClearPasses(renderTargets, false, - programs.getPackDirectives().getRenderTargetDirectives()); + this.clearPassesFull = ClearPassCreator.createClearPasses(renderTargets, true, programs.getPackDirectives().getRenderTargetDirectives()); + this.clearPasses = ClearPassCreator.createClearPasses(renderTargets, false, programs.getPackDirectives().getRenderTargetDirectives()); // SodiumTerrainPipeline setup follows. - Supplier> flipped = - () -> isBeforeTranslucent ? flippedAfterPrepare : flippedAfterTranslucent; + Supplier> flipped = () -> isBeforeTranslucent ? flippedAfterPrepare : flippedAfterTranslucent; IntFunction createTerrainSamplers = (programId) -> { ProgramSamplers.Builder builder = ProgramSamplers.builder(programId, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS); @@ -397,8 +391,7 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true, false)); IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture()); - // Only initialize these samplers if the shadow map renderer exists. - // Otherwise, this program shouldn't be used at all? + // Only initialize these samplers if the shadow map renderer exists. Otherwise, this program shouldn't be used at all? if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, Objects.requireNonNull(shadowRenderTargets)); } @@ -507,28 +500,15 @@ private RenderCondition getCondition(WorldRenderingPhase phase) { } switch (phase) { - case NONE: - case OUTLINE: - case DEBUG: - case PARTICLES: + case NONE, OUTLINE, DEBUG, PARTICLES: return RenderCondition.DEFAULT; - case SKY: - case SUNSET: - case CUSTOM_SKY: - case SUN: - case MOON: - case STARS: - case VOID: + case SKY, SUNSET, CUSTOM_SKY, SUN, MOON, STARS, VOID: return RenderCondition.SKY; - case TERRAIN_SOLID: - case TERRAIN_CUTOUT: - case TERRAIN_CUTOUT_MIPPED: + case TERRAIN_SOLID, TERRAIN_CUTOUT, TERRAIN_CUTOUT_MIPPED: return RenderCondition.TERRAIN_OPAQUE; case ENTITIES: - if (true /*GlStateManagerAccessor.getBLEND().srcRgb == GlStateManager.SourceFactor.SRC_ALPHA.value - && GlStateManagerAccessor.getBLEND().dstRgb == GlStateManager.SourceFactor.ONE_MINUS_SRC_ALPHA.value - && GlStateManagerAccessor.getBLEND().srcAlpha == GlStateManager.SourceFactor.ONE.value - && GlStateManagerAccessor.getBLEND().dstAlpha == GlStateManager.SourceFactor.ONE_MINUS_SRC_ALPHA.value*/) { + final Vector4i blendFunc = CapturedRenderingState.INSTANCE.getBlendFunc(); + if (blendFunc.x == SRC_ALPHA && blendFunc.y == ONE_MINUS_SRC_ALPHA && blendFunc.z == ONE && blendFunc.w == ONE_MINUS_SRC_ALPHA) { return RenderCondition.ENTITIES_TRANSLUCENT; } else { return RenderCondition.ENTITIES; @@ -539,8 +519,7 @@ private RenderCondition getCondition(WorldRenderingPhase phase) { return RenderCondition.DESTROY; case HAND_SOLID: return RenderCondition.HAND_OPAQUE; - case TERRAIN_TRANSLUCENT: - case TRIPWIRE: + case TERRAIN_TRANSLUCENT, TRIPWIRE: return RenderCondition.TERRAIN_TRANSLUCENT; case CLOUDS: return RenderCondition.CLOUDS; @@ -872,7 +851,7 @@ private static void destroyPasses(ProgramTable table) { private void prepareRenderTargets() { // Make sure we're using texture unit 0 for this. GL13.glActiveTexture(GL13.GL_TEXTURE0); - Vector4f emptyClearColor = new Vector4f(1.0F); + final Vector4f emptyClearColor = new Vector4f(1.0F); if (shadowRenderTargets != null) { if (packDirectives.getShadowDirectives().isShadowEnabled() == OptionalBoolean.FALSE) { @@ -912,15 +891,10 @@ private void prepareRenderTargets() { } } -// RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); -// Blaze3dRenderTargetExt mainExt = (Blaze3dRenderTargetExt) main; - -// int depthTextureId = main.getDepthTextureId(); -// int internalFormat = TextureInfoCache.INSTANCE.getInfo(depthTextureId).getInternalFormat(); -// DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); + final Minecraft mc = Minecraft.getMinecraft(); - boolean changed = true;//renderTargets.resizeIfNeeded(mainExt.iris$getDepthBufferVersion(), depthTextureId, main.width, -// main.height, depthBufferFormat, packDirectives); + final boolean changed = renderTargets.resizeIfNeeded(((IRenderTargetExt)mc).iris$getDepthBufferVersion(), mc.displayWidth, + mc.displayHeight, packDirectives); if (changed) { prepareRenderer.recalculateSizes(); @@ -931,10 +905,8 @@ private void prepareRenderTargets() { this.clearPassesFull.forEach(clearPass -> renderTargets.destroyFramebuffer(clearPass.getFramebuffer())); this.clearPasses.forEach(clearPass -> renderTargets.destroyFramebuffer(clearPass.getFramebuffer())); - this.clearPassesFull = ClearPassCreator.createClearPasses(renderTargets, true, - packDirectives.getRenderTargetDirectives()); - this.clearPasses = ClearPassCreator.createClearPasses(renderTargets, false, - packDirectives.getRenderTargetDirectives()); + this.clearPassesFull = ClearPassCreator.createClearPasses(renderTargets, true, packDirectives.getRenderTargetDirectives()); + this.clearPasses = ClearPassCreator.createClearPasses(renderTargets, false, packDirectives.getRenderTargetDirectives()); } final ImmutableList passes; @@ -946,11 +918,11 @@ private void prepareRenderTargets() { passes = clearPasses; } - Vector3d fogColor3 = CapturedRenderingState.INSTANCE.getFogColor(); + final Vector3d fogColor3 = CapturedRenderingState.INSTANCE.getFogColor(); // NB: The alpha value must be 1.0 here, or else you will get a bunch of bugs. Sildur's Vibrant Shaders // will give you pink reflections and other weirdness if this is zero. - Vector4f fogColor = new Vector4f((float) fogColor3.x, (float) fogColor3.y, (float) fogColor3.z, 1.0F); + final Vector4f fogColor = new Vector4f((float) fogColor3.x, (float) fogColor3.y, (float) fogColor3.z, 1.0F); for (ClearPass clearPass : passes) { clearPass.execute(fogColor); @@ -985,8 +957,7 @@ private ComputeProgram[] createShadowComputes(ComputeSource[] compute, ProgramSe TextureStage textureStage = TextureStage.GBUFFERS_AND_SHADOW; ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = - ProgramSamplers.customTextureSamplerInterceptor(builder, - customTextureManager.getCustomTextureIdMap(textureStage)); + ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureManager.getCustomTextureIdMap(textureStage)); IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false); IrisImages.addRenderTargetImages(builder, flipped, renderTargets); diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 2a32ab513..76d67845d 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -39,12 +39,14 @@ import org.joml.Vector3d; import org.joml.Vector3f; import org.joml.Vector4f; +import org.lwjgl.BufferUtils; import org.lwjgl.opengl.ARBTextureSwizzle; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL14; import org.lwjgl.opengl.GL30; +import java.nio.IntBuffer; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -207,8 +209,9 @@ private void configureDepthSampler(int glTextureId, PackShadowDirectives.DepthSa // Workaround for issues with old shader packs like Chocapic v4. // They expected the driver to put the depth value in z, but it's supposed to only // be available in r. So we set up the swizzle to fix that. - IrisRenderSystem.texParameteriv(glTextureId, GL11.GL_TEXTURE_2D, ARBTextureSwizzle.GL_TEXTURE_SWIZZLE_RGBA, - new int[] { GL11.GL_RED, GL11.GL_RED, GL11.GL_RED, GL11.GL_ONE }); + IntBuffer swizzleBuf = BufferUtils.createIntBuffer(4); + swizzleBuf.put(new int[] { GL11.GL_RED, GL11.GL_RED, GL11.GL_RED, GL11.GL_ONE }).rewind(); + IrisRenderSystem.texParameteriv(glTextureId, GL11.GL_TEXTURE_2D, ARBTextureSwizzle.GL_TEXTURE_SWIZZLE_RGBA, swizzleBuf); configureSampler(glTextureId, settings); } diff --git a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java index 4957ffbc5..0a76ef607 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java @@ -15,6 +15,7 @@ import net.coderbot.iris.pipeline.PatchedShaderPrinter; import net.coderbot.iris.pipeline.transform.PatchShaderType; import net.coderbot.iris.pipeline.transform.TransformPatcher; +import net.coderbot.iris.rendertarget.IRenderTargetExt; import net.coderbot.iris.rendertarget.RenderTarget; import net.coderbot.iris.rendertarget.RenderTargets; import net.coderbot.iris.samplers.IrisImages; @@ -48,7 +49,7 @@ public class FinalPassRenderer { private final ImmutableList swapPasses; private final GlFramebuffer baseline; private final GlFramebuffer colorHolder; - private int lastColorTextureId; + private int colorTextureId; private int lastColorTextureVersion; private final IntSupplier noiseTexture; private final FrameUpdateNotifier updateNotifier; @@ -61,7 +62,7 @@ public FinalPassRenderer(ProgramSet pack, RenderTargets renderTargets, IntSuppli CenterDepthSampler centerDepthSampler, Supplier shadowTargetsSupplier, Object2ObjectMap customTextureIds, - ImmutableSet flippedAtLeastOnce) { + ImmutableSet flippedAtLeastOnce, int colorTextureId) { this.updateNotifier = updateNotifier; this.centerDepthSampler = centerDepthSampler; this.customTextureIds = customTextureIds; @@ -92,10 +93,9 @@ public FinalPassRenderer(ProgramSet pack, RenderTargets renderTargets, IntSuppli // passes that write to framebuffers). this.baseline = renderTargets.createGbufferFramebuffer(flippedBuffers, new int[] {0}); this.colorHolder = new GlFramebuffer(); - // TODO: Iris - this.lastColorTextureId = 0; //Minecraft.getMinecraft().getMainRenderTarget().getColorTextureId(); - this.lastColorTextureVersion = 0; //((Blaze3dRenderTargetExt) Minecraft.getMinecraft().getMainRenderTarget()).iris$getColorBufferVersion(); - this.colorHolder.addColorAttachment(0, lastColorTextureId); + this.colorTextureId = colorTextureId; + this.lastColorTextureVersion = ((IRenderTargetExt)Minecraft.getMinecraft()).iris$getColorBufferVersion(); + this.colorHolder.addColorAttachment(0, this.colorTextureId); // TODO: We don't actually fully swap the content, we merely copy it from alt to main // This works for the most part, but it's not perfect. A better approach would be creating secondary @@ -169,16 +169,14 @@ public void renderFinalPass() { // This is not a concern for depthtex1 / depthtex2 since the copy call extracts the depth values, and the // shader pack only ever uses them to read the depth values. - // TODO: Iris -// if (((Blaze3dRenderTargetExt) main).iris$getColorBufferVersion() != lastColorTextureVersion || main.getColorTextureId() != lastColorTextureId) { -// lastColorTextureVersion = ((Blaze3dRenderTargetExt) main).iris$getColorBufferVersion(); -// this.lastColorTextureId = main.getColorTextureId(); -// colorHolder.addColorAttachment(0, lastColorTextureId); -// } + if (((IRenderTargetExt)mc).iris$getColorBufferVersion() != lastColorTextureVersion) { + lastColorTextureVersion = ((IRenderTargetExt)mc).iris$getColorBufferVersion(); +// colorHolder.addColorAttachment(0, colorTextureId); + throw new RuntimeException("Color buffer changed during frame!"); + } if (this.finalPass != null) { - // If there is a final pass, we use the shader-based full screen quad rendering pathway instead - // of just copying the color buffer. + // If there is a final pass, we use the shader-based full screen quad rendering pathway instead of just copying the color buffer. colorHolder.bind(); diff --git a/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java b/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java new file mode 100644 index 000000000..415b318a1 --- /dev/null +++ b/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java @@ -0,0 +1,35 @@ +package net.coderbot.iris.rendertarget; + +import net.coderbot.iris.gl.GlResource; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.texture.TextureUploadHelper; +import org.lwjgl.opengl.EXTFramebufferObject; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import java.nio.ByteBuffer; + +public class ColorTexture extends GlResource { + public ColorTexture(int width, int height) { + super(IrisRenderSystem.createTexture(GL11.GL_TEXTURE_2D)); + final int texture = getGlId(); + + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + + TextureUploadHelper.resetTextureUploadState(); + IrisRenderSystem.texImage2D(texture, GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (ByteBuffer) null); + EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, GL11.GL_TEXTURE_2D, texture, 0); + } + + public int getTextureId() { + return getGlId(); + } + + @Override + protected void destroyInternal() { + GL11.glDeleteTextures(getGlId()); + } +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java b/src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java index f4aa02873..d73b75a21 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java @@ -9,7 +9,7 @@ public class DepthTexture extends GlResource { public DepthTexture(int width, int height, DepthBufferFormat format) { super(IrisRenderSystem.createTexture(GL11.GL_TEXTURE_2D)); - int texture = getGlId(); + final int texture = getGlId(); resize(width, height, format); diff --git a/src/main/java/net/coderbot/iris/rendertarget/IRenderTargetExt.java b/src/main/java/net/coderbot/iris/rendertarget/IRenderTargetExt.java new file mode 100644 index 000000000..332cd73fa --- /dev/null +++ b/src/main/java/net/coderbot/iris/rendertarget/IRenderTargetExt.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.rendertarget; + +public interface IRenderTargetExt { + int iris$getDepthBufferVersion(); + + int iris$getColorBufferVersion(); +} diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java index bfd204c47..86142d6f6 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java @@ -1,6 +1,7 @@ package net.coderbot.iris.rendertarget; import com.google.common.collect.ImmutableSet; +import lombok.Getter; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.framebuffer.GlFramebuffer; import net.coderbot.iris.gl.texture.DepthBufferFormat; @@ -8,17 +9,24 @@ import net.coderbot.iris.shaderpack.PackDirectives; import net.coderbot.iris.shaderpack.PackRenderTargetDirectives; import org.joml.Vector2i; +import org.lwjgl.opengl.EXTFramebufferObject; import org.lwjgl.opengl.GL11; import java.util.ArrayList; import java.util.List; import java.util.Map; +import static org.lwjgl.opengl.EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT; +import static org.lwjgl.opengl.EXTFramebufferObject.GL_FRAMEBUFFER_EXT; + public class RenderTargets { private final RenderTarget[] targets; private int currentDepthTexture; private DepthBufferFormat currentDepthFormat; + @Getter + private final ColorTexture colorTexture; + private final DepthTexture depthTexture; private final DepthTexture noTranslucents; private final DepthTexture noHand; private final GlFramebuffer depthSourceFb; @@ -36,7 +44,7 @@ public class RenderTargets { private int cachedDepthBufferVersion; - public RenderTargets(int width, int height, int depthTexture, int depthBufferVersion, DepthBufferFormat depthFormat, Map renderTargets, PackDirectives packDirectives) { + public RenderTargets(int width, int height, int depthBufferVersion, Map renderTargets, PackDirectives packDirectives) { targets = new RenderTarget[renderTargets.size()]; renderTargets.forEach((index, settings) -> { @@ -46,9 +54,16 @@ public RenderTargets(int width, int height, int depthTexture, int depthBufferVer .setInternalFormat(settings.getInternalFormat()) .setPixelFormat(settings.getInternalFormat().getPixelFormat()).build(); }); + // TODO: currentDepthFormat... :hmmm: -- NEED GL_TEXTURE_INTERNAL_FORMAT ?? + this.currentDepthFormat = DepthBufferFormat.DEPTH; + this.depthTexture = new DepthTexture(width, height, currentDepthFormat); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, depthTexture.getTextureId()); + EXTFramebufferObject.glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, depthTexture.getTextureId(), 0); + + this.colorTexture = new ColorTexture(width, height); + - this.currentDepthTexture = depthTexture; - this.currentDepthFormat = depthFormat; + this.currentDepthTexture = depthTexture.getTextureId(); this.copyStrategy = DepthCopyStrategy.fastest(currentDepthFormat.isCombinedStencil()); this.cachedWidth = width; @@ -85,6 +100,7 @@ public void destroy() { target.destroy(); } + depthTexture.destroy(); noTranslucents.destroy(); noHand.destroy(); } @@ -109,48 +125,18 @@ public DepthTexture getDepthTextureNoHand() { return noHand; } - public boolean resizeIfNeeded(int newDepthBufferVersion, int newDepthTextureId, int newWidth, int newHeight, DepthBufferFormat newDepthFormat, PackDirectives packDirectives) { - boolean recreateDepth = false; + public boolean resizeIfNeeded(int newDepthBufferVersion, int newWidth, int newHeight, PackDirectives packDirectives) { if (cachedDepthBufferVersion != newDepthBufferVersion) { - recreateDepth = true; - currentDepthTexture = newDepthTextureId; + this.depthTexture.resize(newWidth, newHeight, currentDepthFormat); cachedDepthBufferVersion = newDepthBufferVersion; } boolean sizeChanged = newWidth != cachedWidth || newHeight != cachedHeight; - boolean depthFormatChanged = newDepthFormat != currentDepthFormat; - - if (depthFormatChanged) { - currentDepthFormat = newDepthFormat; - // Might need a new copy strategy - copyStrategy = DepthCopyStrategy.fastest(currentDepthFormat.isCombinedStencil()); - } - if (recreateDepth) { - // Re-attach the depth textures with the new depth texture ID, since Minecraft re-creates - // the depth texture when resizing its render targets. - // - // I'm not sure if our framebuffers holding on to the old depth texture between frames - // could be a concern, in the case of resizing and similar. I think it should work - // based on what I've seen of the spec, though - it seems like deleting a texture - // automatically detaches it from its framebuffers. - for (GlFramebuffer framebuffer : ownedFramebuffers) { - if (framebuffer == noHandDestFb || framebuffer == noTranslucentsDestFb) { - // NB: Do not change the depth attachment of these framebuffers - // as it is intentionally different - continue; - } - - if (framebuffer.hasDepthAttachment()) { - framebuffer.addDepthAttachment(newDepthTextureId); - } - } - } - - if (depthFormatChanged || sizeChanged) { + if (sizeChanged) { // Reallocate depth buffers - noTranslucents.resize(newWidth, newHeight, newDepthFormat); - noHand.resize(newWidth, newHeight, newDepthFormat); + noTranslucents.resize(newWidth, newHeight, currentDepthFormat); + noHand.resize(newWidth, newHeight, currentDepthFormat); this.translucentDepthDirty = true; this.handDepthDirty = true; } @@ -188,8 +174,7 @@ public void copyPreHandDepth() { depthSourceFb.bindAsReadBuffer(); IrisRenderSystem.copyTexImage2D(GL11.GL_TEXTURE_2D, 0, currentDepthFormat.getGlInternalFormat(), 0, 0, cachedWidth, cachedHeight, 0); } else { - copyStrategy.copy(depthSourceFb, getDepthTexture(), noHandDestFb, noHand.getTextureId(), - getCurrentWidth(), getCurrentHeight()); + copyStrategy.copy(depthSourceFb, getDepthTexture(), noHandDestFb, noHand.getTextureId(), getCurrentWidth(), getCurrentHeight()); } } @@ -235,10 +220,9 @@ private GlFramebuffer createEmptyFramebuffer() { GlFramebuffer framebuffer = new GlFramebuffer(); ownedFramebuffers.add(framebuffer); - framebuffer.addDepthAttachment(currentDepthTexture); +// framebuffer.addDepthAttachment(currentDepthTexture); - // NB: Before OpenGL 3.0, all framebuffers are required to have a color - // attachment no matter what. + // NB: Before OpenGL 3.0, all framebuffers are required to have a color attachment no matter what. framebuffer.addColorAttachment(0, get(0).getMainTexture()); framebuffer.noDrawBuffers(); @@ -254,7 +238,7 @@ public GlFramebuffer createGbufferFramebuffer(ImmutableSet stageWritesT GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); - framebuffer.addDepthAttachment(currentDepthTexture); +// framebuffer.addDepthAttachment(currentDepthTexture); return framebuffer; } @@ -276,7 +260,7 @@ private GlFramebuffer createFullFramebuffer(boolean clearsAlt, int[] drawBuffers public GlFramebuffer createColorFramebufferWithDepth(ImmutableSet stageWritesToMain, int[] drawBuffers) { GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); - framebuffer.addDepthAttachment(currentDepthTexture); +// framebuffer.addDepthAttachment(currentDepthTexture); return framebuffer; } diff --git a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java index 0349baa7b..1d5bdcea1 100644 --- a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java +++ b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java @@ -5,6 +5,8 @@ import java.nio.FloatBuffer; +import static net.coderbot.iris.compat.mojang.Constants.DEGREES_TO_RADIANS; + public class ShadowMatrices { private static final float NEAR = 0.05f; private static final float FAR = 256.0f; @@ -51,11 +53,10 @@ public static void createBaselineModelViewMatrix(PoseStack target, float shadowA target.last().normal().identity(); target.last().pose().identity(); - // TODO: Render -// target.last().pose().multiply(Matrix4f.createTranslateMatrix(0.0f, 0.0f, -100.0f)); -// target.mulPose(Vector3f.XP.rotationDegrees(90.0F)); -// target.mulPose(Vector3f.ZP.rotationDegrees(skyAngle * -360.0f)); -// target.mulPose(Vector3f.XP.rotationDegrees(sunPathRotation)); + target.last().pose().translate(0.0f, 0.0f, -100.0f); + target.rotateX(90F * DEGREES_TO_RADIANS); + target.rotateZ(sunPathRotation * DEGREES_TO_RADIANS); + target.rotateZ(skyAngle * -360.0f * DEGREES_TO_RADIANS); } public static void snapModelViewToGrid(PoseStack target, float shadowIntervalSize, double cameraX, double cameraY, double cameraZ) { @@ -86,8 +87,7 @@ public static void snapModelViewToGrid(PoseStack target, float shadowIntervalSiz offsetY -= halfIntervalSize; offsetZ -= halfIntervalSize; - // TODO: Render -// target.last().pose().multiply(Matrix4f.createTranslateMatrix(offsetX, offsetY, offsetZ)); + target.last().pose().translate(offsetX, offsetY, offsetZ); } public static void createModelViewMatrix(PoseStack target, float shadowAngle, float shadowIntervalSize, @@ -164,9 +164,8 @@ public static void main(String[] args) { } private static float[] toFloatArray(Matrix4f matrix4f) { - FloatBuffer buffer = FloatBuffer.allocate(16); - // TODO: Render -// matrix4f.store(buffer); + final FloatBuffer buffer = FloatBuffer.allocate(16); + matrix4f.get((FloatBuffer) buffer); return buffer.array(); } diff --git a/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java index 0d79dbdd6..a9a2f8c58 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java @@ -1,6 +1,5 @@ package net.coderbot.iris.uniforms; -import com.gtnewhorizons.angelica.client.Shaders; import net.coderbot.iris.gl.uniform.UniformHolder; import net.minecraft.client.Minecraft; import org.joml.Vector3d; @@ -33,8 +32,7 @@ private static int getRenderDistanceInBlocks() { } public static Vector3d getUnshiftedCameraPosition() { - return Shaders.getCameraPosition(); -// return JomlConversions.fromVec3(client.gameRenderer.getMainCamera().getPosition()); + return CapturedRenderingState.INSTANCE.getCameraPosition(); } static class CameraPositionTracker { diff --git a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java index 129e7c715..fde736ea4 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java +++ b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java @@ -1,18 +1,42 @@ package net.coderbot.iris.uniforms; +import lombok.Getter; +import lombok.Setter; import net.coderbot.iris.gl.state.ValueUpdateNotifier; import net.minecraft.client.Minecraft; +import net.minecraft.entity.EntityLivingBase; import org.joml.Matrix4f; import org.joml.Vector3d; +import org.joml.Vector4d; +import org.joml.Vector4i; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; + +import java.nio.FloatBuffer; public class CapturedRenderingState { public static final CapturedRenderingState INSTANCE = new CapturedRenderingState(); private static final Vector3d ZERO_VECTOR_3d = new Vector3d(); + private final FloatBuffer modelViewBuffer = BufferUtils.createFloatBuffer(16); private Matrix4f gbufferModelView; - private Matrix4f gbufferProjection; + private final FloatBuffer shadowModelViewBuffer = BufferUtils.createFloatBuffer(16); + private Matrix4f shadowModelView; + private final FloatBuffer projectionBuffer = BufferUtils.createFloatBuffer(16); + private Matrix4f gbufferProjection; + private final FloatBuffer shadowProjectionBuffer = BufferUtils.createFloatBuffer(16); + private Matrix4f shadowProjection; private Vector3d fogColor; + private Vector4d clearColor; + + @Getter + private Vector3d cameraPosition = new Vector3d(); + + @Getter + @Setter + private boolean blendEnabled; + private Vector4i blendFunc; private float tickDelta; private int currentRenderedBlockEntity; private Runnable blockEntityIdListener = null; @@ -27,18 +51,10 @@ public Matrix4f getGbufferModelView() { return gbufferModelView; } - public void setGbufferModelView(Matrix4f gbufferModelView) { - this.gbufferModelView = new Matrix4f(gbufferModelView); - } - public Matrix4f getGbufferProjection() { return gbufferProjection; } - public void setGbufferProjection(Matrix4f gbufferProjection) { - this.gbufferProjection = new Matrix4f(gbufferProjection); - } - public Vector3d getFogColor() { if (Minecraft.getMinecraft().theWorld == null || fogColor == null) { return ZERO_VECTOR_3d; @@ -51,6 +67,10 @@ public void setFogColor(float red, float green, float blue) { fogColor = new Vector3d(red, green, blue); } + public void setClearColor(float red, float green, float blue, float alpha) { + clearColor = new Vector4d(red, green, blue, alpha); + } + public void setTickDelta(float tickDelta) { this.tickDelta = tickDelta; } @@ -90,4 +110,41 @@ public ValueUpdateNotifier getBlockEntityIdNotifier() { public int getCurrentRenderedEntity() { return currentRenderedEntity; } + + public void setBlendFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { + blendFunc = new Vector4i(srcRgb, dstRgb, srcAlpha, dstAlpha); + } + + public Vector4i getBlendFunc() { + return blendFunc; + } + + public void setCamera(float tickDelta) { + final Minecraft mc = Minecraft.getMinecraft(); + final EntityLivingBase viewEntity = mc.renderViewEntity; + + final double x = viewEntity.lastTickPosX + (viewEntity.posX - viewEntity.lastTickPosX) * tickDelta; + final double y = viewEntity.lastTickPosY + (viewEntity.posY - viewEntity.lastTickPosY) * tickDelta; + final double z = viewEntity.lastTickPosZ + (viewEntity.posZ - viewEntity.lastTickPosZ) * tickDelta; + cameraPosition = new Vector3d(x, y, z); + + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, (FloatBuffer) projectionBuffer.position(0)); + gbufferProjection = new Matrix4f((FloatBuffer)projectionBuffer.position(0)); + + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, (FloatBuffer) modelViewBuffer.position(0)); + gbufferModelView = new Matrix4f((FloatBuffer)modelViewBuffer.position(0)); + } + + public void setCameraShadow(float tickDelta) { + final Minecraft mc = Minecraft.getMinecraft(); + setCamera(tickDelta); + + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, (FloatBuffer) shadowProjectionBuffer.position(0)); + shadowProjection = new Matrix4f((FloatBuffer)shadowProjectionBuffer.position(0)); + + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, (FloatBuffer) shadowModelViewBuffer.position(0)); + shadowModelView = new Matrix4f((FloatBuffer)shadowModelViewBuffer.position(0)); + + + } } diff --git a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java index 4ff69b3da..58cf757d9 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java @@ -1,6 +1,6 @@ package net.coderbot.iris.uniforms; -import net.coderbot.iris.JomlConversions; +import net.coderbot.iris.compat.mojang.Constants; import net.coderbot.iris.gl.uniform.UniformHolder; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; @@ -15,9 +15,8 @@ * @see Uniforms: Celestial bodies */ public final class CelestialUniforms { - final static float DEGREES_TO_RADIANS = (float)Math.PI / 180.0F; - private final float sunPathRotation; + private final float sunPathRotation; public CelestialUniforms(float sunPathRotation) { this.sunPathRotation = sunPathRotation; @@ -78,8 +77,8 @@ private Vector4f getCelestialPositionInWorldSpace(float y) { // This is the same transformation applied by renderSky, however, it's been moved to here. // This is because we need the result of it before it's actually performed in vanilla. - celestial.rotateY(-90.F * DEGREES_TO_RADIANS); - celestial.rotateZ(sunPathRotation * DEGREES_TO_RADIANS); + celestial.rotateY(-90.F * Constants.DEGREES_TO_RADIANS); + celestial.rotateZ(sunPathRotation * Constants.DEGREES_TO_RADIANS); celestial.rotateX(getSkyAngle() * 360.0F); celestial.transform(position); @@ -93,8 +92,8 @@ private Vector4f getCelestialPosition(float y) { Matrix4f celestial = new Matrix4f(CapturedRenderingState.INSTANCE.getGbufferModelView()); // This is the same transformation applied by renderSky, however, it's been moved to here. // This is because we need the result of it before it's actually performed in vanilla. - celestial.rotateY(-90.F * DEGREES_TO_RADIANS); - celestial.rotateZ(sunPathRotation * DEGREES_TO_RADIANS); + celestial.rotateY(-90.F * Constants.DEGREES_TO_RADIANS); + celestial.rotateZ(sunPathRotation * Constants.DEGREES_TO_RADIANS); celestial.rotateX(getSkyAngle() * 360.0F); position = celestial.transform(position); @@ -110,7 +109,7 @@ private static Vector4f getUpPosition() { // Apply the fixed -90.0F degrees rotation to mirror the same transformation in renderSky. // But, notably, skip the rotation by the skyAngle. - preCelestial.rotateY(-90.F * DEGREES_TO_RADIANS); + preCelestial.rotateY(-90.F * Constants.DEGREES_TO_RADIANS); // Use this matrix to transform the vector. upVector = preCelestial.transform(upVector); diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index 40f779965..dc51b4bc6 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -78,15 +78,10 @@ public static void addCommonUniforms(DynamicUniformHolder uniforms, IdMap idMap, // }, StateUpdateNotifiers.bindTextureNotifier); uniforms.uniform4i("blendFunc", () -> { + if(CapturedRenderingState.INSTANCE.isBlendEnabled()) { + return CapturedRenderingState.INSTANCE.getBlendFunc(); + } return ZERO_VECTOR_4i; - // TODO: blendFunc -// GlStateManager.BlendState blend = GlStateManagerAccessor.getBLEND(); -// -// if (((BooleanStateAccessor) blend.mode).isEnabled()) { -// return new Vector4i(blend.srcRgb, blend.dstRgb, blend.srcAlpha, blend.dstAlpha); -// } else { -// return ZERO_VECTOR_4i; -// } }, StateUpdateNotifiers.blendFuncNotifier); uniforms.uniform1i("renderStage", () -> GbufferPrograms.getCurrentPhase().ordinal(), StateUpdateNotifiers.phaseChangeNotifier); diff --git a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java index cf8ce7790..6fb288ef8 100644 --- a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java @@ -20,8 +20,7 @@ public static void addMatrixUniforms(UniformHolder uniforms, PackDirectives dire // TODO: In some cases, gbufferProjectionInverse takes on a value much different than OptiFine... // We need to audit Mojang's linear algebra. addMatrix(uniforms, "Projection", CapturedRenderingState.INSTANCE::getGbufferProjection); - addShadowMatrix(uniforms, "ModelView", () -> - ShadowRenderer.createShadowModelView(directives.getSunPathRotation(), directives.getShadowDirectives().getIntervalSize()).last().pose()); + addShadowMatrix(uniforms, "ModelView", () -> ShadowRenderer.createShadowModelView(directives.getSunPathRotation(), directives.getShadowDirectives().getIntervalSize()).last().pose()); addShadowArrayMatrix(uniforms, "Projection", () -> ShadowMatrices.createOrthoMatrix(directives.getShadowDirectives().getDistance())); } From afb35fe13c3303ecf35cdda129a8a3140c0e0aa5 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Mon, 30 Oct 2023 14:01:31 -0700 Subject: [PATCH 014/301] Add ASM for GLStateManager * ComplementaryShaders_v4.6 now loads --- .../angelica/client/GLStateManager.java | 43 +++++++++ .../angelica/loading/AngelicaTweaker.java | 18 ++-- .../gtnewhorizons/angelica/mixins/Mixins.java | 3 +- .../angelica/transform/ACTEntityRenderer.java | 3 +- .../angelica/transform/IrisTransformer.java | 87 +++++++++++++++++++ .../iris/gl/program/ProgramUniforms.java | 4 + 6 files changed, 148 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/client/GLStateManager.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/IrisTransformer.java diff --git a/src/main/java/com/gtnewhorizons/angelica/client/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/client/GLStateManager.java new file mode 100644 index 000000000..6389a50ff --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/client/GLStateManager.java @@ -0,0 +1,43 @@ +package com.gtnewhorizons.angelica.client; + +import org.lwjgl.opengl.GL11; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +@SuppressWarnings("unused") // Used in ASM +public class GLStateManager { + public static void glBindTexture(int target, int texture) { + net.coderbot.iris.texture.TextureTracker.INSTANCE.onBindTexture(texture); + GL11.glBindTexture(target, texture); + } + + public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, IntBuffer pixels) { + net.coderbot.iris.texture.TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + } + public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, ByteBuffer pixels) { + net.coderbot.iris.texture.TextureInfoCache.INSTANCE.onTexImage2D( + target, level, internalformat, width, height, border, format, type, + pixels != null ? pixels.asIntBuffer() : (IntBuffer) null + ); + GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + } + + public static void glDeleteTextures(int id) { + iris$onDeleteTexture(id); + GL11.glDeleteTextures(id); + } + public static void glDeleteTextures(IntBuffer ids) { + for(int id: ids.array()) { + iris$onDeleteTexture(id); + } + GL11.glDeleteTextures(ids); + } + + private static void iris$onDeleteTexture(int id) { + net.coderbot.iris.texture.TextureTracker.INSTANCE.onDeleteTexture(id); + net.coderbot.iris.texture.TextureInfoCache.INSTANCE.onDeleteTexture(id); + net.coderbot.iris.texture.pbr.PBRTextureManager.INSTANCE.onDeleteTexture(id); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index 4f95c2b0c..0152055c4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -5,6 +5,7 @@ import com.gtnewhorizons.angelica.mixins.ArchaicMixins; import com.gtnewhorizons.angelica.mixins.Mixins; import com.gtnewhorizons.angelica.mixins.TargetedMod; +import com.gtnewhorizons.angelica.transform.IrisTransformer; import cpw.mods.fml.relauncher.IFMLLoadingPlugin; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; @@ -27,14 +28,14 @@ import java.util.stream.Collectors; @IFMLLoadingPlugin.MCVersion("1.7.10") +@IFMLLoadingPlugin.TransformerExclusions({ + "org.lwjglx", "org.lwjgl", "org.lwjgl.input", "org.lwjglx.input", "org.lwjglx.debug", "me.eigenraven.lwjgl3ify", "com.gtnewhorizons.angelica.transform.IrisTransformer", +}) @IFMLLoadingPlugin.SortingIndex(1100) public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader { public static final Logger LOGGER = LogManager.getLogger("Angelica"); -// public static boolean ENABLE_SPAM = false; // Enable for more spam - public static boolean ENABLE_SPAM = true; - static { try { // ArchaicFix Config @@ -51,11 +52,14 @@ public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader { @Override public String[] getASMTransformerClass() { - List tweakClasses = GlobalProperties.get(MixinServiceLaunchWrapper.BLACKBOARD_KEY_TWEAKCLASSES); - if (tweakClasses != null) { - tweakClasses.add(MixinCompatHackTweaker.class.getName()); + // Directly add this to the MixinServiceLaunchWrapper tweaker's list of Tweak Classes + List mixinTweakClasses = GlobalProperties.get(MixinServiceLaunchWrapper.BLACKBOARD_KEY_TWEAKCLASSES); + if (mixinTweakClasses != null) { + mixinTweakClasses.add(MixinCompatHackTweaker.class.getName()); } - return null; + + // Return any others here + return new String[] { IrisTransformer.class.getName() }; } @Override diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index f80a95a4e..2ecdbe602 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -20,7 +20,8 @@ public enum Mixins { IRIS_RENDERING(new Builder("Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( "shaders.MixinEntityRenderer", - "shaders.MixinItem" + "shaders.MixinItem", + "shaders.MixinOpenGlHelper" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java index 451db5bc4..18f5509ab 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java @@ -34,8 +34,7 @@ public CVTransform(ClassVisitor cv) { } @Override - public void visit(int version, int access, String name, String signature, String superName, - String[] interfaces) { + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { classname = name; cv.visit(version, access, name, signature, superName, interfaces); } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/IrisTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/IrisTransformer.java new file mode 100644 index 000000000..b29e9b0c1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/transform/IrisTransformer.java @@ -0,0 +1,87 @@ +package com.gtnewhorizons.angelica.transform; + +import com.google.common.collect.Sets; +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import net.minecraft.launchwrapper.IClassTransformer; +import org.spongepowered.asm.lib.ClassReader; +import org.spongepowered.asm.lib.ClassVisitor; +import org.spongepowered.asm.lib.ClassWriter; +import org.spongepowered.asm.lib.MethodVisitor; +import org.spongepowered.asm.lib.Opcodes; +import org.spongepowered.asm.lib.commons.Method; +import org.spongepowered.asm.lib.commons.Remapper; + +import java.util.HashSet; +import java.util.Set; + +public class IrisTransformer extends Remapper implements IClassTransformer { + /* + * Redirects a subset of GL11 calls to GLStateManager + * NOTE: Still need to verify compatibility with Mixins and Lwjgl3ify + */ + public static final String GLStateTrackerClass = "com.gtnewhorizons.angelica.client.GLStateManager"; + private static final String GLStateTracker = GLStateTrackerClass.replace(".", "/"); + private static final String GL11Class = "org.lwjgl.opengl.GL11"; + private static final String GL11 = GL11Class.replace(".", "/"); + + private static final Set EnabledRedirects = Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures"); + + public static int remaps = 0, calls = 0; + + @Override + public byte[] transform(final String className, String transformedName, byte[] basicClass) { + if (basicClass == null) return null; + + // Ignore the state tracker itself + if (className.equals(GLStateTrackerClass)) return basicClass; + + ClassReader reader = new ClassReader(basicClass); + Set eligibleMethods = findEligibleMethods(reader); + if (eligibleMethods.isEmpty()) { + return basicClass; + } + + ClassWriter writer = new ClassWriter(reader, 0); + reader.accept(new ClassVisitor(Opcodes.ASM5, writer) { + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); + if (!eligibleMethods.contains(new Method(name, desc))) { + return mv; + } + return new MethodVisitor(Opcodes.ASM5, mv) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (owner.equals(GL11) && EnabledRedirects.contains(name)) { + AngelicaTweaker.LOGGER.info("Redirecting call in {} from GL11.{}{} to GLStateManager.{}{}", className, name, desc, name, desc); + owner = GLStateTracker; + remaps++; + } + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + }; + } + }, 0); + return writer.toByteArray(); + } + + + private Set findEligibleMethods(ClassReader reader) { + Set eligibleMethods = new HashSet<>(); + reader.accept(new ClassVisitor(Opcodes.ASM5) { + @Override + public MethodVisitor visitMethod(int access, String methodName, String methodDesc, String signature, String[] exceptions) { + return new MethodVisitor(Opcodes.ASM5) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (owner.equals(GL11) && EnabledRedirects.contains(name)) { + eligibleMethods.add(new Method(methodName, methodDesc)); + } + } + }; + } + }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + return eligibleMethods; + } + +} diff --git a/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java b/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java index 22238f65b..217d146bf 100644 --- a/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java +++ b/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java @@ -271,6 +271,10 @@ public ProgramUniforms buildUniforms() { @Override public Builder addDynamicUniform(Uniform uniform, ValueUpdateNotifier notifier) { Objects.requireNonNull(uniform); + if(notifier == null){ + Iris.logger.info("notifier is null: " + uniform.getLocation()); + } + Objects.requireNonNull(notifier); dynamic.put(locations.get(uniform.getLocation()), uniform); From 8a270eb41ce075f269f4e02472dcae4632816180 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Mon, 30 Oct 2023 15:19:38 -0700 Subject: [PATCH 015/301] Loosen TransformerExclusion Also take a stab at blacklisting via the transformer itself... --- .../angelica/loading/AngelicaTweaker.java | 4 +-- .../angelica/transform/IrisTransformer.java | 26 +++++++++++++------ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index 0152055c4..735921714 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -28,9 +28,7 @@ import java.util.stream.Collectors; @IFMLLoadingPlugin.MCVersion("1.7.10") -@IFMLLoadingPlugin.TransformerExclusions({ - "org.lwjglx", "org.lwjgl", "org.lwjgl.input", "org.lwjglx.input", "org.lwjglx.debug", "me.eigenraven.lwjgl3ify", "com.gtnewhorizons.angelica.transform.IrisTransformer", -}) +@IFMLLoadingPlugin.TransformerExclusions("com.gtnewhorizons.angelica.transform.IrisTransformer") @IFMLLoadingPlugin.SortingIndex(1100) public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader { diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/IrisTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/IrisTransformer.java index b29e9b0c1..af8073c21 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/IrisTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/IrisTransformer.java @@ -9,12 +9,14 @@ import org.spongepowered.asm.lib.MethodVisitor; import org.spongepowered.asm.lib.Opcodes; import org.spongepowered.asm.lib.commons.Method; -import org.spongepowered.asm.lib.commons.Remapper; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Set; -public class IrisTransformer extends Remapper implements IClassTransformer { +public class IrisTransformer implements IClassTransformer { /* * Redirects a subset of GL11 calls to GLStateManager * NOTE: Still need to verify compatibility with Mixins and Lwjgl3ify @@ -26,14 +28,22 @@ public class IrisTransformer extends Remapper implements IClassTransformer { private static final Set EnabledRedirects = Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures"); + private static final List TransformerExclusions = new ArrayList<>(Arrays.asList( + GLStateTrackerClass, "org.lwjgl", "com.gtnewhorizons.angelica.transform", "me.eigenraven.lwjgl3ify") + ); public static int remaps = 0, calls = 0; @Override public byte[] transform(final String className, String transformedName, byte[] basicClass) { if (basicClass == null) return null; - // Ignore the state tracker itself - if (className.equals(GLStateTrackerClass)) return basicClass; + + // Ignore classes that are excluded from transformation - Doesn't seem to fully work without the TransformerExclusions + for (String exclusion : TransformerExclusions) { + if (className.startsWith(exclusion)) { + return basicClass; + } + } ClassReader reader = new ClassReader(basicClass); Set eligibleMethods = findEligibleMethods(reader); @@ -42,14 +52,14 @@ public byte[] transform(final String className, String transformedName, byte[] b } ClassWriter writer = new ClassWriter(reader, 0); - reader.accept(new ClassVisitor(Opcodes.ASM5, writer) { + reader.accept(new ClassVisitor(Opcodes.ASM9, writer) { @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); if (!eligibleMethods.contains(new Method(name, desc))) { return mv; } - return new MethodVisitor(Opcodes.ASM5, mv) { + return new MethodVisitor(Opcodes.ASM9, mv) { @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { if (owner.equals(GL11) && EnabledRedirects.contains(name)) { @@ -68,10 +78,10 @@ public void visitMethodInsn(int opcode, String owner, String name, String desc, private Set findEligibleMethods(ClassReader reader) { Set eligibleMethods = new HashSet<>(); - reader.accept(new ClassVisitor(Opcodes.ASM5) { + reader.accept(new ClassVisitor(Opcodes.ASM9) { @Override public MethodVisitor visitMethod(int access, String methodName, String methodDesc, String signature, String[] exceptions) { - return new MethodVisitor(Opcodes.ASM5) { + return new MethodVisitor(Opcodes.ASM9) { @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { if (owner.equals(GL11) && EnabledRedirects.contains(name)) { From 63185902cba603a042cca5dfe3319211aa27ae0f Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Mon, 30 Oct 2023 21:40:53 -0700 Subject: [PATCH 016/301] Get the Active Texture, not the textire binding --- .../java/net/coderbot/iris/gl/program/ProgramSamplers.java | 2 +- src/main/java/net/coderbot/iris/texture/TextureTracker.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java b/src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java index c55ab046d..b33110a86 100644 --- a/src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java +++ b/src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java @@ -46,7 +46,7 @@ public void update() { // We need to keep the active texture intact, since if we mess it up // in the middle of RenderType setup, bad things will happen. - int activeTexture = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + int activeTexture = GL11.glGetInteger(GL13.GL_ACTIVE_TEXTURE); for (SamplerBinding samplerBinding : samplerBindings) { samplerBinding.update(); diff --git a/src/main/java/net/coderbot/iris/texture/TextureTracker.java b/src/main/java/net/coderbot/iris/texture/TextureTracker.java index e2333ea31..69e1f7e71 100644 --- a/src/main/java/net/coderbot/iris/texture/TextureTracker.java +++ b/src/main/java/net/coderbot/iris/texture/TextureTracker.java @@ -9,6 +9,7 @@ import net.minecraft.client.renderer.texture.AbstractTexture; import org.jetbrains.annotations.Nullable; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; public class TextureTracker { public static final TextureTracker INSTANCE = new TextureTracker(); @@ -39,7 +40,7 @@ public void onBindTexture(int id) { if (lockBindCallback) { return; } - if (GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D) == 0) { + if (GL11.glGetInteger(GL13.GL_ACTIVE_TEXTURE) == 0) { lockBindCallback = true; if (bindTextureListener != null) { bindTextureListener.run(); From 90081973194853c3320bc6d9c7b2bb4f2c83e0ca Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Mon, 30 Oct 2023 22:31:21 -0700 Subject: [PATCH 017/301] More robust GLStateManagerTransformer * Handles non GL11 functions * Now correctly runs after Mixins, but before LWJGL3ify GLStateManager updates: * glEnable/glDisable intercepting * Add BlendState --- .../angelica/client/GLStateManager.java | 43 ------ .../angelica/glsm/BlendState.java | 14 ++ .../angelica/glsm/BooleanState.java | 34 +++++ .../angelica/glsm/GLStateManager.java | 137 ++++++++++++++++++ .../angelica/loading/AngelicaTweaker.java | 7 +- .../loading/MixinCompatHackTweaker.java | 29 +++- .../early/shaders/MixinEntityRenderer.java | 26 ---- ...er.java => GLStateManagerTransformer.java} | 32 ++-- .../DeferredWorldRenderingPipeline.java | 11 +- .../iris/uniforms/CapturedRenderingState.java | 14 -- .../iris/uniforms/CommonUniforms.java | 7 +- 11 files changed, 242 insertions(+), 112 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/GLStateManager.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/BlendState.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/BooleanState.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java rename src/main/java/com/gtnewhorizons/angelica/transform/{IrisTransformer.java => GLStateManagerTransformer.java} (69%) diff --git a/src/main/java/com/gtnewhorizons/angelica/client/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/client/GLStateManager.java deleted file mode 100644 index 6389a50ff..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/GLStateManager.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -import org.lwjgl.opengl.GL11; - -import java.nio.ByteBuffer; -import java.nio.IntBuffer; - -@SuppressWarnings("unused") // Used in ASM -public class GLStateManager { - public static void glBindTexture(int target, int texture) { - net.coderbot.iris.texture.TextureTracker.INSTANCE.onBindTexture(texture); - GL11.glBindTexture(target, texture); - } - - public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, IntBuffer pixels) { - net.coderbot.iris.texture.TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); - GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); - } - public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, ByteBuffer pixels) { - net.coderbot.iris.texture.TextureInfoCache.INSTANCE.onTexImage2D( - target, level, internalformat, width, height, border, format, type, - pixels != null ? pixels.asIntBuffer() : (IntBuffer) null - ); - GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); - } - - public static void glDeleteTextures(int id) { - iris$onDeleteTexture(id); - GL11.glDeleteTextures(id); - } - public static void glDeleteTextures(IntBuffer ids) { - for(int id: ids.array()) { - iris$onDeleteTexture(id); - } - GL11.glDeleteTextures(ids); - } - - private static void iris$onDeleteTexture(int id) { - net.coderbot.iris.texture.TextureTracker.INSTANCE.onDeleteTexture(id); - net.coderbot.iris.texture.TextureInfoCache.INSTANCE.onDeleteTexture(id); - net.coderbot.iris.texture.pbr.PBRTextureManager.INSTANCE.onDeleteTexture(id); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/BlendState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/BlendState.java new file mode 100644 index 000000000..1fa698158 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/BlendState.java @@ -0,0 +1,14 @@ +package com.gtnewhorizons.angelica.glsm; + +import org.lwjgl.opengl.GL11; + +public class BlendState { + + public final BooleanState mode = new BooleanState(GL11.GL_BLEND); + public int srcRgb = GL11.GL_ONE; + public int dstRgb = GL11.GL_ZERO; + public int srcAlpha = GL11.GL_ONE; + public int dstAlpha = GL11.GL_ZERO; + + BlendState() {} +} diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/BooleanState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/BooleanState.java new file mode 100644 index 000000000..f4eebc2b8 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/BooleanState.java @@ -0,0 +1,34 @@ +package com.gtnewhorizons.angelica.glsm; + +import lombok.Getter; +import org.lwjgl.opengl.GL11; + +public class BooleanState { + private final int cap; + + @Getter + private boolean enabled; + + public BooleanState(int cap) { + this.cap = cap; + } + + public void disable() { + this.setEnabled(false); + } + + public void enable() { + this.setEnabled(true); + } + + public void setEnabled(boolean enabled) { + if (enabled != this.enabled) { + this.enabled = enabled; + if (enabled) { + GL11.glEnable(this.cap); + } else { + GL11.glDisable(this.cap); + } + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java new file mode 100644 index 000000000..afe53d0c8 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -0,0 +1,137 @@ +package com.gtnewhorizons.angelica.glsm; + +import lombok.Getter; +import net.coderbot.iris.gl.blending.BlendModeStorage; +import net.coderbot.iris.gl.state.StateUpdateNotifiers; +import net.coderbot.iris.texture.TextureInfoCache; +import net.coderbot.iris.texture.TextureTracker; +import net.coderbot.iris.texture.pbr.PBRTextureManager; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +@SuppressWarnings("unused") // Used in ASM +public class GLStateManager { + // GLStateManager State Trackers + @Getter + private static final BlendState Blend = new BlendState(); + + // Iris Listeners + private static Runnable blendFuncListener; + + static { + StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener; + } + + + // LWJGL Overrides + + public static void glBindTexture(int target, int texture) { + // Iris + TextureTracker.INSTANCE.onBindTexture(texture); + GL11.glBindTexture(target, texture); + } + + public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, IntBuffer pixels) { + // Iris + TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + } + public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, ByteBuffer pixels) { + // Iris + TextureInfoCache.INSTANCE.onTexImage2D( + target, level, internalformat, width, height, border, format, type, + pixels != null ? pixels.asIntBuffer() : (IntBuffer) null + ); + GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + } + + public static void glDeleteTextures(int id) { + // Iris + iris$onDeleteTexture(id); + GL11.glDeleteTextures(id); + } + public static void glDeleteTextures(IntBuffer ids) { + // Iris + for(int id: ids.array()) { + iris$onDeleteTexture(id); + } + GL11.glDeleteTextures(ids); + } + + public static void glEnable(int cap) { + switch(cap) { + case GL11.GL_BLEND -> enableBlend(); + default -> GL11.glEnable(cap); + } + } + + + public static void glDisable(int cap) { + switch (cap) { + case GL11.GL_BLEND -> disableBlend(); + default -> GL11.glDisable(cap); + } + } + + // GLStateManager Functions + + private static void enableBlend() { + // Iris + if(BlendModeStorage.isBlendLocked()) { + BlendModeStorage.deferBlendModeToggle(true); + return; + } + Blend.mode.enable(); + } + + public static void disableBlend() { + // Iris + if (BlendModeStorage.isBlendLocked()) { + BlendModeStorage.deferBlendModeToggle(false); + return; + } + Blend.mode.disable(); + } + + public static void glBlendFunc(int srcFactor, int dstFactor) { + // Iris + if(BlendModeStorage.isBlendLocked()) { + BlendModeStorage.deferBlendFunc(srcFactor, dstFactor, srcFactor, dstFactor); + return; + } + Blend.srcRgb = srcFactor; + Blend.dstRgb = dstFactor; + GL11.glBlendFunc(srcFactor, dstFactor); + + // Iris + if (blendFuncListener != null) blendFuncListener.run(); + } + + public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { + // Iris + if(BlendModeStorage.isBlendLocked()) { + BlendModeStorage.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); + return; + } + Blend.srcRgb = srcRgb; + Blend.dstRgb = dstRgb; + Blend.srcAlpha = srcAlpha; + Blend.dstAlpha = dstAlpha; + GL14.glBlendFuncSeparate(srcRgb, dstRgb, srcAlpha, dstAlpha); + + // Iris + if (blendFuncListener != null) blendFuncListener.run(); + } + + // Iris Functions + + private static void iris$onDeleteTexture(int id) { + TextureTracker.INSTANCE.onDeleteTexture(id); + TextureInfoCache.INSTANCE.onDeleteTexture(id); + PBRTextureManager.INSTANCE.onDeleteTexture(id); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index 735921714..5c82021e1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -5,7 +5,6 @@ import com.gtnewhorizons.angelica.mixins.ArchaicMixins; import com.gtnewhorizons.angelica.mixins.Mixins; import com.gtnewhorizons.angelica.mixins.TargetedMod; -import com.gtnewhorizons.angelica.transform.IrisTransformer; import cpw.mods.fml.relauncher.IFMLLoadingPlugin; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; @@ -28,8 +27,8 @@ import java.util.stream.Collectors; @IFMLLoadingPlugin.MCVersion("1.7.10") -@IFMLLoadingPlugin.TransformerExclusions("com.gtnewhorizons.angelica.transform.IrisTransformer") -@IFMLLoadingPlugin.SortingIndex(1100) +@IFMLLoadingPlugin.TransformerExclusions("com.gtnewhorizons.angelica.transform.GLStateManagerTransformer") +@IFMLLoadingPlugin.SortingIndex(Integer.MAX_VALUE - 5) public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader { public static final Logger LOGGER = LogManager.getLogger("Angelica"); @@ -57,7 +56,7 @@ public String[] getASMTransformerClass() { } // Return any others here - return new String[] { IrisTransformer.class.getName() }; + return null; } @Override diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java index 494307e6a..387cb71ac 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java @@ -1,17 +1,17 @@ package com.gtnewhorizons.angelica.loading; -import java.io.File; -import java.lang.reflect.Field; -import java.util.List; - +import com.gtnewhorizons.angelica.transform.AClassTransformer; +import com.gtnewhorizons.angelica.transform.GLStateManagerTransformer; +import cpw.mods.fml.common.asm.transformers.TerminalTransformer; import net.minecraft.launchwrapper.IClassTransformer; import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; -import com.gtnewhorizons.angelica.transform.AClassTransformer; +import java.io.File; +import java.lang.reflect.Field; +import java.util.List; -import cpw.mods.fml.common.asm.transformers.TerminalTransformer; public class MixinCompatHackTweaker implements ITweaker { @@ -29,8 +29,19 @@ public void acceptOptions(List args, File gameDir, File assetsDir, Strin break; } } - xformers.add(terminalIndex - 1, new AClassTransformer()); - AngelicaTweaker.LOGGER.info("Hacked in asm class transformer in position {}", terminalIndex - 1); + + try { + Class.forName("me.eigenraven.lwjgl3ify.core.LwjglRedirectTransformer"); + AngelicaTweaker.LOGGER.info("LwjglRedirectTransformer found, injecting before it"); + terminalIndex -= 2; + + } catch(Exception ignored) { + AngelicaTweaker.LOGGER.info("LwjglRedirectTransformer not found, injecting near the end"); + terminalIndex -= 1; + } + + xformers.add(terminalIndex, new AClassTransformer()); + AngelicaTweaker.LOGGER.info("Hacked in asm class transformer in position {}", terminalIndex); } catch (Exception e) { throw new RuntimeException(e); } @@ -48,6 +59,8 @@ public String getLaunchTarget() { @Override public String[] getLaunchArguments() { + // Run after Mixins, but hopefully before LWJGl3ify + Launch.classLoader.registerTransformer(GLStateManagerTransformer.class.getName()); return new String[0]; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index b9143cfc9..5f4722734 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -8,7 +8,6 @@ import net.coderbot.iris.uniforms.SystemTimeUniforms; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.EntityRenderer; -import net.minecraft.client.renderer.OpenGlHelper; import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @@ -27,7 +26,6 @@ public class MixinEntityRenderer { @Unique private static Runnable fogStartListener; @Unique private static Runnable fogEndListener; @Unique private static Runnable fogDensityListener; - @Unique private static Runnable blendFuncListener; @Unique private WorldRenderingPipeline pipeline; @@ -86,29 +84,6 @@ private void toggleFog(boolean enable) { pipeline.beginLevelRendering(); } - // Blend - - @Redirect(method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/OpenGlHelper;glBlendFunc(IIII)V")) - private void iris$glBlendFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { - OpenGlHelper.glBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); - CapturedRenderingState.INSTANCE.setBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); - - } - @Redirect(method="renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V")) - private void iris$glEnable(int cap) { - GL11.glEnable(cap); - if (cap == GL11.GL_BLEND) { - CapturedRenderingState.INSTANCE.setBlendEnabled(true); - } - } - - @Redirect(method="renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V")) - private void iris$glDisable(int cap) { - GL11.glDisable(cap); - if (cap == GL11.GL_BLEND) { - CapturedRenderingState.INSTANCE.setBlendEnabled(false); - } - } @Inject(method = "renderWorld(FJ)V", at = @At(value = "RETURN", shift = At.Shift.BEFORE)) private void iris$endLevelRender(float tickDelta, long limitTime, CallbackInfo callback) { @@ -157,7 +132,6 @@ private void toggleFog(boolean enable) { StateUpdateNotifiers.fogStartNotifier = listener -> fogStartListener = listener; StateUpdateNotifiers.fogEndNotifier = listener -> fogEndListener = listener; StateUpdateNotifiers.fogDensityNotifier = listener -> fogDensityListener = listener; - StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/IrisTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java similarity index 69% rename from src/main/java/com/gtnewhorizons/angelica/transform/IrisTransformer.java rename to src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index af8073c21..3c6190bc1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/IrisTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.transform; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.minecraft.launchwrapper.IClassTransformer; @@ -14,22 +15,28 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; -public class IrisTransformer implements IClassTransformer { +public class GLStateManagerTransformer implements IClassTransformer { /* * Redirects a subset of GL11 calls to GLStateManager * NOTE: Still need to verify compatibility with Mixins and Lwjgl3ify */ - public static final String GLStateTrackerClass = "com.gtnewhorizons.angelica.client.GLStateManager"; - private static final String GLStateTracker = GLStateTrackerClass.replace(".", "/"); - private static final String GL11Class = "org.lwjgl.opengl.GL11"; - private static final String GL11 = GL11Class.replace(".", "/"); + public static final String GLStateTracker = "com/gtnewhorizons/angelica/glsm/GLStateManager"; + private static final String GL11 = "org/lwjgl/opengl/GL11"; + private static final String GL14 = "org/lwjgl/opengl/GL14"; + private static final String ExtBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate"; + + public static final Map> EnabledRedirects = ImmutableMap.of( + GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable") + ,GL14, Sets.newHashSet("glBlendFuncSeparate") + ,ExtBlendFunc, Sets.newHashSet("glBlendFuncSeparate") + ); - private static final Set EnabledRedirects = Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures"); private static final List TransformerExclusions = new ArrayList<>(Arrays.asList( - GLStateTrackerClass, "org.lwjgl", "com.gtnewhorizons.angelica.transform", "me.eigenraven.lwjgl3ify") + "org.lwjgl", "com.gtnewhorizons.angelica.glsm.", "com.gtnewhorizons.angelica.transform", "me.eigenraven.lwjgl3ify") ); public static int remaps = 0, calls = 0; @@ -45,7 +52,7 @@ public byte[] transform(final String className, String transformedName, byte[] b } } - ClassReader reader = new ClassReader(basicClass); + final ClassReader reader = new ClassReader(basicClass); Set eligibleMethods = findEligibleMethods(reader); if (eligibleMethods.isEmpty()) { return basicClass; @@ -62,8 +69,10 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si return new MethodVisitor(Opcodes.ASM9, mv) { @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { - if (owner.equals(GL11) && EnabledRedirects.contains(name)) { - AngelicaTweaker.LOGGER.info("Redirecting call in {} from GL11.{}{} to GLStateManager.{}{}", className, name, desc, name, desc); + final Set redirects = EnabledRedirects.get(owner); + if (redirects != null && redirects.contains(name)) { + final String shortOwner = owner.substring(owner.lastIndexOf("/")+1); + AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", className, shortOwner, name, desc, name, desc); owner = GLStateTracker; remaps++; } @@ -84,7 +93,8 @@ public MethodVisitor visitMethod(int access, String methodName, String methodDes return new MethodVisitor(Opcodes.ASM9) { @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { - if (owner.equals(GL11) && EnabledRedirects.contains(name)) { + final Set redirects = EnabledRedirects.get(owner); + if(redirects != null && redirects.contains(name)) { eligibleMethods.add(new Method(methodName, methodDesc)); } } diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index d9f717ad4..c7ac9266d 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -3,7 +3,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Ints; -import net.coderbot.iris.rendertarget.IRenderTargetExt; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.iris.Iris; import net.coderbot.iris.block_rendering.BlockMaterialMapping; import net.coderbot.iris.block_rendering.BlockRenderingSettings; @@ -30,6 +30,7 @@ import net.coderbot.iris.postprocess.CenterDepthSampler; import net.coderbot.iris.postprocess.CompositeRenderer; import net.coderbot.iris.postprocess.FinalPassRenderer; +import net.coderbot.iris.rendertarget.IRenderTargetExt; import net.coderbot.iris.rendertarget.NativeImageBackedSingleColorTexture; import net.coderbot.iris.rendertarget.RenderTargets; import net.coderbot.iris.samplers.IrisImages; @@ -62,7 +63,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3d; import org.joml.Vector4f; -import org.joml.Vector4i; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL30; @@ -507,8 +507,11 @@ private RenderCondition getCondition(WorldRenderingPhase phase) { case TERRAIN_SOLID, TERRAIN_CUTOUT, TERRAIN_CUTOUT_MIPPED: return RenderCondition.TERRAIN_OPAQUE; case ENTITIES: - final Vector4i blendFunc = CapturedRenderingState.INSTANCE.getBlendFunc(); - if (blendFunc.x == SRC_ALPHA && blendFunc.y == ONE_MINUS_SRC_ALPHA && blendFunc.z == ONE && blendFunc.w == ONE_MINUS_SRC_ALPHA) { + if (GLStateManager.getBlend().srcRgb == SRC_ALPHA && + GLStateManager.getBlend().srcAlpha == ONE_MINUS_SRC_ALPHA && + GLStateManager.getBlend().dstRgb == ONE && + GLStateManager.getBlend().dstAlpha == ONE_MINUS_SRC_ALPHA) + { return RenderCondition.ENTITIES_TRANSLUCENT; } else { return RenderCondition.ENTITIES; diff --git a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java index fde736ea4..4ed8bffc8 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java +++ b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java @@ -1,14 +1,12 @@ package net.coderbot.iris.uniforms; import lombok.Getter; -import lombok.Setter; import net.coderbot.iris.gl.state.ValueUpdateNotifier; import net.minecraft.client.Minecraft; import net.minecraft.entity.EntityLivingBase; import org.joml.Matrix4f; import org.joml.Vector3d; import org.joml.Vector4d; -import org.joml.Vector4i; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; @@ -33,10 +31,6 @@ public class CapturedRenderingState { @Getter private Vector3d cameraPosition = new Vector3d(); - @Getter - @Setter - private boolean blendEnabled; - private Vector4i blendFunc; private float tickDelta; private int currentRenderedBlockEntity; private Runnable blockEntityIdListener = null; @@ -111,14 +105,6 @@ public int getCurrentRenderedEntity() { return currentRenderedEntity; } - public void setBlendFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { - blendFunc = new Vector4i(srcRgb, dstRgb, srcAlpha, dstAlpha); - } - - public Vector4i getBlendFunc() { - return blendFunc; - } - public void setCamera(float tickDelta) { final Minecraft mc = Minecraft.getMinecraft(); final EntityLivingBase viewEntity = mc.renderViewEntity; diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index dc51b4bc6..7033b5f76 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -1,6 +1,8 @@ package net.coderbot.iris.uniforms; import com.gtnewhorizons.angelica.client.Shaders; +import com.gtnewhorizons.angelica.glsm.BlendState; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.mixins.early.accessors.EntityRendererAccessor; import net.coderbot.iris.gl.state.StateUpdateNotifiers; import net.coderbot.iris.gl.uniform.DynamicUniformHolder; @@ -78,8 +80,9 @@ public static void addCommonUniforms(DynamicUniformHolder uniforms, IdMap idMap, // }, StateUpdateNotifiers.bindTextureNotifier); uniforms.uniform4i("blendFunc", () -> { - if(CapturedRenderingState.INSTANCE.isBlendEnabled()) { - return CapturedRenderingState.INSTANCE.getBlendFunc(); + final BlendState blend = GLStateManager.getBlend(); + if(blend.mode.isEnabled()) { + return new Vector4i(blend.srcRgb, blend.dstRgb, blend.srcAlpha, blend.dstAlpha); } return ZERO_VECTOR_4i; }, StateUpdateNotifiers.blendFuncNotifier); From 1353075bda516edb32d0fce6659c8d14dd8056a7 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Mon, 30 Oct 2023 23:31:52 -0700 Subject: [PATCH 018/301] More GLStateManager * AlphaState, DepthState, CullState, GLColorMask --- .../angelica/glsm/GLStateManager.java | 87 +++++++++++++++++++ .../angelica/glsm/states/AlphaState.java | 9 ++ .../glsm/{ => states}/BlendState.java | 3 +- .../glsm/{ => states}/BooleanState.java | 2 +- .../angelica/glsm/states/DepthState.java | 10 +++ .../angelica/glsm/states/GLColorMask.java | 9 ++ .../early/shaders/MixinOpenGlHelper.java | 5 +- .../transform/GLStateManagerTransformer.java | 3 +- .../iris/gl/blending/AlphaTestStorage.java | 31 +++---- .../iris/gl/blending/DepthColorStorage.java | 51 +++++------ .../iris/uniforms/CommonUniforms.java | 2 +- 11 files changed, 162 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/states/AlphaState.java rename src/main/java/com/gtnewhorizons/angelica/glsm/{ => states}/BlendState.java (82%) rename src/main/java/com/gtnewhorizons/angelica/glsm/{ => states}/BooleanState.java (92%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/states/DepthState.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/states/GLColorMask.java diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index afe53d0c8..10522fea7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -1,7 +1,14 @@ package com.gtnewhorizons.angelica.glsm; +import com.gtnewhorizons.angelica.glsm.states.AlphaState; +import com.gtnewhorizons.angelica.glsm.states.BlendState; +import com.gtnewhorizons.angelica.glsm.states.BooleanState; +import com.gtnewhorizons.angelica.glsm.states.DepthState; +import com.gtnewhorizons.angelica.glsm.states.GLColorMask; import lombok.Getter; +import net.coderbot.iris.gl.blending.AlphaTestStorage; import net.coderbot.iris.gl.blending.BlendModeStorage; +import net.coderbot.iris.gl.blending.DepthColorStorage; import net.coderbot.iris.gl.state.StateUpdateNotifiers; import net.coderbot.iris.texture.TextureInfoCache; import net.coderbot.iris.texture.TextureTracker; @@ -17,6 +24,14 @@ public class GLStateManager { // GLStateManager State Trackers @Getter private static final BlendState Blend = new BlendState(); + @Getter + private static final DepthState Depth = new DepthState(); + @Getter + private static final GLColorMask ColorMask = new GLColorMask(); + @Getter + private static final BooleanState Cull = new BooleanState(GL11.GL_CULL_FACE); + @Getter + private static final AlphaState Alpha = new AlphaState(); // Iris Listeners private static Runnable blendFuncListener; @@ -63,7 +78,10 @@ public static void glDeleteTextures(IntBuffer ids) { public static void glEnable(int cap) { switch(cap) { + case GL11.GL_ALPHA_TEST -> enableAlphaTest(); case GL11.GL_BLEND -> enableBlend(); + case GL11.GL_DEPTH_TEST -> Depth.mode.enable(); + case GL11.GL_CULL_FACE -> Cull.enable(); default -> GL11.glEnable(cap); } } @@ -71,7 +89,10 @@ public static void glEnable(int cap) { public static void glDisable(int cap) { switch (cap) { + case GL11.GL_ALPHA_TEST -> disableAlphaTest(); case GL11.GL_BLEND -> disableBlend(); + case GL11.GL_DEPTH_TEST -> Depth.mode.disable(); + case GL11.GL_CULL_FACE -> Cull.disable(); default -> GL11.glDisable(cap); } } @@ -126,6 +147,72 @@ public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int if (blendFuncListener != null) blendFuncListener.run(); } + public static void glDepthFunc(int func) { + if(func != Depth.func) { + Depth.func = func; + GL11.glDepthFunc(func); + } + } + + public static void glDepthMask(boolean mask) { + // Iris + if (DepthColorStorage.isDepthColorLocked()) { + DepthColorStorage.deferDepthEnable(mask); + return; + } + + if(mask != Depth.mask) { + Depth.mask = mask; + GL11.glDepthMask(mask); + } + } + + public static void glColorMask(boolean red, boolean green, boolean blue, boolean alpha) { + // Iris + if (DepthColorStorage.isDepthColorLocked()) { + DepthColorStorage.deferColorMask(red, green, blue, alpha); + return; + } + if(red != ColorMask.red || green != ColorMask.green || blue != ColorMask.blue || alpha != ColorMask.alpha) { + ColorMask.red = red; + ColorMask.green = green; + ColorMask.blue = blue; + ColorMask.alpha = alpha; + GL11.glColorMask(red, green, blue, alpha); + } + } + + // ALPHA + public static void enableAlphaTest() { + // Iris + if (AlphaTestStorage.isAlphaTestLocked()) { + AlphaTestStorage.deferAlphaTestToggle(true); + return; + } + Alpha.mode.enable(); + } + + public static void disableAlphaTest() { + // Iris + if (AlphaTestStorage.isAlphaTestLocked()) { + AlphaTestStorage.deferAlphaTestToggle(false); + return; + } + Alpha.mode.disable(); + } + + public static void glAlphaFunc(int function, float reference) { + // Iris + if (AlphaTestStorage.isAlphaTestLocked()) { + AlphaTestStorage.deferAlphaFunc(function, reference); + return; + } + Alpha.function = function; + Alpha.reference = reference; + GL11.glAlphaFunc(function, reference); + } + + // Iris Functions private static void iris$onDeleteTexture(int id) { diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/AlphaState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/AlphaState.java new file mode 100644 index 000000000..40f5cc39f --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/AlphaState.java @@ -0,0 +1,9 @@ +package com.gtnewhorizons.angelica.glsm.states; + +import org.lwjgl.opengl.GL11; + +public class AlphaState { + public final BooleanState mode = new BooleanState(GL11.GL_ALPHA_TEST); + public int function = GL11.GL_ALWAYS; + public float reference = -1.0F; +} diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/BlendState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/BlendState.java similarity index 82% rename from src/main/java/com/gtnewhorizons/angelica/glsm/BlendState.java rename to src/main/java/com/gtnewhorizons/angelica/glsm/states/BlendState.java index 1fa698158..14a17edee 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/BlendState.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/BlendState.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.glsm; +package com.gtnewhorizons.angelica.glsm.states; import org.lwjgl.opengl.GL11; @@ -10,5 +10,4 @@ public class BlendState { public int srcAlpha = GL11.GL_ONE; public int dstAlpha = GL11.GL_ZERO; - BlendState() {} } diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/BooleanState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/BooleanState.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/glsm/BooleanState.java rename to src/main/java/com/gtnewhorizons/angelica/glsm/states/BooleanState.java index f4eebc2b8..1c9057604 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/BooleanState.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/BooleanState.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.glsm; +package com.gtnewhorizons.angelica.glsm.states; import lombok.Getter; import org.lwjgl.opengl.GL11; diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/DepthState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/DepthState.java new file mode 100644 index 000000000..905e9930c --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/DepthState.java @@ -0,0 +1,10 @@ +package com.gtnewhorizons.angelica.glsm.states; + +import org.lwjgl.opengl.GL11; + +public class DepthState { + public final BooleanState mode = new BooleanState(GL11.GL_DEPTH_TEST); + public boolean mask = true; + public int func = GL11.GL_LESS; + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/GLColorMask.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/GLColorMask.java new file mode 100644 index 000000000..b656c775b --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/GLColorMask.java @@ -0,0 +1,9 @@ +package com.gtnewhorizons.angelica.glsm.states; + +public class GLColorMask { + public boolean red = true; + public boolean green = true; + public boolean blue = true; + public boolean alpha = true; + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinOpenGlHelper.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinOpenGlHelper.java index 59e125c7d..aff6ac976 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinOpenGlHelper.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinOpenGlHelper.java @@ -3,14 +3,15 @@ import net.minecraft.client.renderer.OpenGlHelper; import org.lwjgl.opengl.GL30; import org.spongepowered.asm.mixin.Mixin; +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.CallbackInfo; @Mixin(OpenGlHelper.class) public class MixinOpenGlHelper { - private static int iris$drawFramebuffer = 0; - private static int iris$readFramebuffer = 0; + @Unique private static int iris$drawFramebuffer = 0; + @Unique private static int iris$readFramebuffer = 0; @Inject(method="func_153171_g", at=@At("HEAD"), cancellable=true) private static void iris$avoidRedundantBind(int target, int framebuffer, CallbackInfo ci) { diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index 3c6190bc1..59873c9d9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -29,7 +29,8 @@ public class GLStateManagerTransformer implements IClassTransformer { private static final String ExtBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate"; public static final Map> EnabledRedirects = ImmutableMap.of( - GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable") + GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", + "glColorMask", "glAlphaFunc") ,GL14, Sets.newHashSet("glBlendFuncSeparate") ,ExtBlendFunc, Sets.newHashSet("glBlendFuncSeparate") ); diff --git a/src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java b/src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java index 6772de5e1..a4af6a6fd 100644 --- a/src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java +++ b/src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java @@ -1,30 +1,31 @@ package net.coderbot.iris.gl.blending; -import org.lwjgl.opengl.GL11; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.glsm.states.AlphaState; +import lombok.Getter; public class AlphaTestStorage { private static boolean originalAlphaTestEnable; private static AlphaTest originalAlphaTest; - private static boolean alphaTestLocked; + @Getter + private static boolean alphaTestLocked; - public static boolean isAlphaTestLocked() { - return alphaTestLocked; - } - - public static void overrideAlphaTest(AlphaTest override) { + public static void overrideAlphaTest(AlphaTest override) { if (!alphaTestLocked) { + final AlphaState alphaState = GLStateManager.getAlpha(); + // Only save the previous state if the alpha test wasn't already locked - originalAlphaTestEnable = GL11.glGetBoolean(GL11.GL_ALPHA_TEST); - originalAlphaTest = new AlphaTest(AlphaTestFunction.fromGlId(GL11.glGetInteger(GL11.GL_ALPHA_TEST_FUNC)).orElse(AlphaTestFunction.ALWAYS), GL11.glGetInteger(GL11.GL_ALPHA_TEST_REF)); + originalAlphaTestEnable = alphaState.mode.isEnabled(); + originalAlphaTest = new AlphaTest(AlphaTestFunction.fromGlId(alphaState.function).orElse(AlphaTestFunction.ALWAYS), alphaState.reference); } alphaTestLocked = false; if (override == null) { - GL11.glDisable(GL11.GL_ALPHA_TEST); + GLStateManager.disableAlphaTest(); } else { - GL11.glEnable(GL11.GL_ALPHA_TEST); - GL11.glAlphaFunc(override.getFunction().getGlId(), override.getReference()); + GLStateManager.enableAlphaTest(); + GLStateManager.glAlphaFunc(override.getFunction().getGlId(), override.getReference()); } alphaTestLocked = true; @@ -46,11 +47,11 @@ public static void restoreAlphaTest() { alphaTestLocked = false; if (originalAlphaTestEnable) { - GL11.glEnable(GL11.GL_ALPHA_TEST); + GLStateManager.enableAlphaTest(); } else { - GL11.glDisable(GL11.GL_ALPHA_TEST); + GLStateManager.disableAlphaTest(); } - GL11.glAlphaFunc(originalAlphaTest.getFunction().getGlId(), originalAlphaTest.getReference()); + GLStateManager.glAlphaFunc(originalAlphaTest.getFunction().getGlId(), originalAlphaTest.getReference()); } } diff --git a/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java b/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java index f3cbdd7a6..33344874d 100644 --- a/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java +++ b/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java @@ -1,33 +1,32 @@ package net.coderbot.iris.gl.blending; -import org.lwjgl.opengl.GL11; +import com.gtnewhorizons.angelica.glsm.states.DepthState; +import com.gtnewhorizons.angelica.glsm.states.GLColorMask; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import lombok.Getter; public class DepthColorStorage { private static boolean originalDepthEnable; private static ColorMask originalColor; - private static boolean depthColorLocked; + @Getter + private static boolean depthColorLocked; - public static boolean isDepthColorLocked() { - return depthColorLocked; - } + public static void disableDepthColor() { + if (!depthColorLocked) { + // Only save the previous state if the depth and color mask wasn't already locked + GLColorMask colorMask = GLStateManager.getColorMask(); + final DepthState depthState = GLStateManager.getDepth(); + + originalDepthEnable = depthState.mask; + originalColor = new ColorMask(colorMask.red, colorMask.green, colorMask.blue, colorMask.alpha); + } - public static void disableDepthColor() { - throw new RuntimeException("Iris disabled depth color"); -// if (!depthColorLocked) { -// // Only save the previous state if the depth and color mask wasn't already locked -// GlStateManager.ColorMask colorMask = GlStateManagerAccessor.getCOLOR_MASK(); -// GlStateManager.DepthState depthState = GlStateManagerAccessor.getDEPTH(); -// -// originalDepthEnable = depthState.mask; -// originalColor = new ColorMask(colorMask.red, colorMask.green, colorMask.blue, colorMask.alpha); -// } -// -// depthColorLocked = false; -// -// GL11.glDepthMask(false); -// GL11.glColorMask(false, false, false, false); -// -// depthColorLocked = true; + depthColorLocked = false; + + GLStateManager.glDepthMask(false); + GLStateManager.glColorMask(false, false, false, false); + + depthColorLocked = true; } public static void deferDepthEnable(boolean enabled) { @@ -45,12 +44,8 @@ public static void unlockDepthColor() { depthColorLocked = false; - if (originalDepthEnable) { - GL11.glDepthMask(true); - } else { - GL11.glDepthMask(false); - } + GLStateManager.glDepthMask(originalDepthEnable); - GL11.glColorMask(originalColor.isRedMasked(), originalColor.isGreenMasked(), originalColor.isBlueMasked(), originalColor.isAlphaMasked()); + GLStateManager.glColorMask(originalColor.isRedMasked(), originalColor.isGreenMasked(), originalColor.isBlueMasked(), originalColor.isAlphaMasked()); } } diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index 7033b5f76..c816ba014 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -1,7 +1,7 @@ package net.coderbot.iris.uniforms; import com.gtnewhorizons.angelica.client.Shaders; -import com.gtnewhorizons.angelica.glsm.BlendState; +import com.gtnewhorizons.angelica.glsm.states.BlendState; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.mixins.early.accessors.EntityRendererAccessor; import net.coderbot.iris.gl.state.StateUpdateNotifiers; From 17ed2f2c22b1e8d34ee66e9183e7088241315011 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 31 Oct 2023 08:11:18 -0700 Subject: [PATCH 019/301] More GLStateManager * TextureState[] & activeTexture --- .../angelica/glsm/GLStateManager.java | 142 +++++++++++++----- .../angelica/glsm/states/TextureState.java | 8 + .../transform/GLStateManagerTransformer.java | 4 +- .../mojang/AutoClosableAbstractTexture.java | 3 +- .../coderbot/iris/gl/IrisRenderSystem.java | 29 ++-- .../iris/gl/program/ProgramSamplers.java | 6 +- .../iris/gl/program/ProgramUniforms.java | 5 - .../iris/pipeline/CustomTextureManager.java | 5 +- .../DeferredWorldRenderingPipeline.java | 6 +- .../iris/pipeline/PipelineManager.java | 7 +- .../iris/pipeline/ShadowRenderer.java | 9 +- .../iris/postprocess/CenterDepthSampler.java | 7 +- .../iris/postprocess/CompositeRenderer.java | 9 +- .../iris/postprocess/FinalPassRenderer.java | 15 +- .../postprocess/FullScreenQuadRenderer.java | 3 +- .../iris/rendertarget/ColorTexture.java | 3 +- .../iris/rendertarget/DepthTexture.java | 5 +- .../iris/rendertarget/NoiseTexture.java | 7 +- .../iris/rendertarget/RenderTarget.java | 7 +- .../iris/rendertarget/RenderTargets.java | 7 +- .../iris/rendertarget/SingleColorTexture.java | 3 +- .../iris/texture/TextureInfoCache.java | 5 +- .../coderbot/iris/texture/TextureTracker.java | 5 +- .../iris/texture/pbr/PBRTextureManager.java | 3 +- .../iris/texture/util/TextureExporter.java | 3 +- .../texture/util/TextureManipulationUtil.java | 5 +- 26 files changed, 204 insertions(+), 107 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/states/TextureState.java diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 10522fea7..bf50ce76d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -5,23 +5,33 @@ import com.gtnewhorizons.angelica.glsm.states.BooleanState; import com.gtnewhorizons.angelica.glsm.states.DepthState; import com.gtnewhorizons.angelica.glsm.states.GLColorMask; +import com.gtnewhorizons.angelica.glsm.states.TextureState; import lombok.Getter; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gbuffer_overrides.state.StateTracker; import net.coderbot.iris.gl.blending.AlphaTestStorage; import net.coderbot.iris.gl.blending.BlendModeStorage; import net.coderbot.iris.gl.blending.DepthColorStorage; +import net.coderbot.iris.gl.sampler.SamplerLimits; import net.coderbot.iris.gl.state.StateUpdateNotifiers; +import net.coderbot.iris.samplers.IrisSamplers; import net.coderbot.iris.texture.TextureInfoCache; import net.coderbot.iris.texture.TextureTracker; import net.coderbot.iris.texture.pbr.PBRTextureManager; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL14; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.stream.IntStream; @SuppressWarnings("unused") // Used in ASM public class GLStateManager { // GLStateManager State Trackers + @Getter + private static int activeTexture; + @Getter private static final BlendState Blend = new BlendState(); @Getter @@ -32,56 +42,26 @@ public class GLStateManager { private static final BooleanState Cull = new BooleanState(GL11.GL_CULL_FACE); @Getter private static final AlphaState Alpha = new AlphaState(); + @Getter + private static final TextureState[] Textures; // Iris Listeners private static Runnable blendFuncListener; static { StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener; + Textures = (TextureState[]) IntStream.range(0, SamplerLimits.get().getMaxTextureUnits()).mapToObj(i -> new TextureState()).toArray(TextureState[]::new); } // LWJGL Overrides - - public static void glBindTexture(int target, int texture) { - // Iris - TextureTracker.INSTANCE.onBindTexture(texture); - GL11.glBindTexture(target, texture); - } - - public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, IntBuffer pixels) { - // Iris - TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); - GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); - } - public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, ByteBuffer pixels) { - // Iris - TextureInfoCache.INSTANCE.onTexImage2D( - target, level, internalformat, width, height, border, format, type, - pixels != null ? pixels.asIntBuffer() : (IntBuffer) null - ); - GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); - } - - public static void glDeleteTextures(int id) { - // Iris - iris$onDeleteTexture(id); - GL11.glDeleteTextures(id); - } - public static void glDeleteTextures(IntBuffer ids) { - // Iris - for(int id: ids.array()) { - iris$onDeleteTexture(id); - } - GL11.glDeleteTextures(ids); - } - public static void glEnable(int cap) { switch(cap) { case GL11.GL_ALPHA_TEST -> enableAlphaTest(); case GL11.GL_BLEND -> enableBlend(); case GL11.GL_DEPTH_TEST -> Depth.mode.enable(); case GL11.GL_CULL_FACE -> Cull.enable(); + case GL11.GL_TEXTURE_2D -> enableTexture(); default -> GL11.glEnable(cap); } } @@ -93,6 +73,7 @@ public static void glDisable(int cap) { case GL11.GL_BLEND -> disableBlend(); case GL11.GL_DEPTH_TEST -> Depth.mode.disable(); case GL11.GL_CULL_FACE -> Cull.disable(); + case GL11.GL_TEXTURE_2D -> disableTexture(); default -> GL11.glDisable(cap); } } @@ -212,6 +193,99 @@ public static void glAlphaFunc(int function, float reference) { GL11.glAlphaFunc(function, reference); } + // Textures + public static void glActiveTexture(int texture) { + final int newTexture = texture - GL13.GL_TEXTURE0; + if (activeTexture != newTexture) { + activeTexture = newTexture; + GL13.glActiveTexture(texture); + } + } + + public static void glBindTexture(int target, int texture) { + if(Textures[activeTexture].binding != texture) { + Textures[activeTexture].binding = texture; + GL11.glBindTexture(target, texture); + TextureTracker.INSTANCE.onBindTexture(texture); + } + } + + public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, IntBuffer pixels) { + // Iris + TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + } + public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, ByteBuffer pixels) { + // Iris + TextureInfoCache.INSTANCE.onTexImage2D( + target, level, internalformat, width, height, border, format, type, + pixels != null ? pixels.asIntBuffer() : (IntBuffer) null + ); + GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + } + + public static void glDeleteTextures(int id) { + // Iris + iris$onDeleteTexture(id); + GL11.glDeleteTextures(id); + } + public static void glDeleteTextures(IntBuffer ids) { + // Iris + for(int id: ids.array()) { + iris$onDeleteTexture(id); + } + GL11.glDeleteTextures(ids); + } + + public static void enableTexture() { + // Iris + boolean updatePipeline = false; + if (activeTexture == IrisSamplers.ALBEDO_TEXTURE_UNIT) { + StateTracker.INSTANCE.albedoSampler = true; + updatePipeline = true; + } else if (activeTexture == IrisSamplers.LIGHTMAP_TEXTURE_UNIT) { + StateTracker.INSTANCE.lightmapSampler = true; + updatePipeline = true; + } else if (activeTexture == IrisSamplers.OVERLAY_TEXTURE_UNIT) { + StateTracker.INSTANCE.overlaySampler = true; + updatePipeline = true; + } + + if(updatePipeline) { + Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setInputs(StateTracker.INSTANCE.getInputs())); + } + + Textures[activeTexture].mode.enable(); + } + + public static void disableTexture() { + // Iris + boolean updatePipeline = false; + if (activeTexture == IrisSamplers.ALBEDO_TEXTURE_UNIT) { + StateTracker.INSTANCE.albedoSampler = false; + updatePipeline = true; + } else if (activeTexture == IrisSamplers.LIGHTMAP_TEXTURE_UNIT) { + StateTracker.INSTANCE.lightmapSampler = false; + updatePipeline = true; + } else if (activeTexture == IrisSamplers.OVERLAY_TEXTURE_UNIT) { + StateTracker.INSTANCE.overlaySampler = false; + updatePipeline = true; + } + + if(updatePipeline) { + Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setInputs(StateTracker.INSTANCE.getInputs())); + } + + Textures[activeTexture].mode.disable(); + } + + public static void glDrawArrays(int mode, int first, int count) { + // Iris -- TODO: This doesn't seem to work and is related to matchPass() +// Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram); + + GL11.glDrawArrays(mode, first, count); + } + // Iris Functions diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/TextureState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/TextureState.java new file mode 100644 index 000000000..36709a8f2 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/TextureState.java @@ -0,0 +1,8 @@ +package com.gtnewhorizons.angelica.glsm.states; + +import org.lwjgl.opengl.GL11; + +public class TextureState { + public final BooleanState mode = new BooleanState(GL11.GL_TEXTURE_2D); + public int binding; +} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index 59873c9d9..72679a140 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -25,12 +25,14 @@ public class GLStateManagerTransformer implements IClassTransformer { */ public static final String GLStateTracker = "com/gtnewhorizons/angelica/glsm/GLStateManager"; private static final String GL11 = "org/lwjgl/opengl/GL11"; + private static final String GL13 = "org/lwjgl/opengl/GL13"; private static final String GL14 = "org/lwjgl/opengl/GL14"; private static final String ExtBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate"; public static final Map> EnabledRedirects = ImmutableMap.of( GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", - "glColorMask", "glAlphaFunc") + "glColorMask", "glAlphaFunc", "glDrawArrays") + ,GL13, Sets.newHashSet("glActiveTexture") ,GL14, Sets.newHashSet("glBlendFuncSeparate") ,ExtBlendFunc, Sets.newHashSet("glBlendFuncSeparate") ); diff --git a/src/main/java/net/coderbot/iris/compat/mojang/AutoClosableAbstractTexture.java b/src/main/java/net/coderbot/iris/compat/mojang/AutoClosableAbstractTexture.java index 4ffee4a24..3cbcb5952 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/AutoClosableAbstractTexture.java +++ b/src/main/java/net/coderbot/iris/compat/mojang/AutoClosableAbstractTexture.java @@ -1,5 +1,6 @@ package net.coderbot.iris.compat.mojang; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.resources.IResourceManager; import org.lwjgl.opengl.GL11; @@ -15,6 +16,6 @@ public void close() throws Exception {} // TODO: Is this needed? public void bind() { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, getGlTextureId()); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, getGlTextureId()); } } diff --git a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java index e1b04a173..044239dae 100644 --- a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java +++ b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java @@ -1,5 +1,6 @@ package net.coderbot.iris.gl; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.iris.Iris; import net.minecraft.client.renderer.OpenGlHelper; import org.jetbrains.annotations.Nullable; @@ -64,8 +65,8 @@ public static void bindAttributeLocation(int program, int index, CharSequence na } public static void texImage2D(int texture, int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable ByteBuffer pixels) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); - GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GLStateManager.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } public static void uniformMatrix4fv(int location, boolean transpose, FloatBuffer matrix) { @@ -370,25 +371,25 @@ public int createTexture(int target) { public static class DSAUnsupported implements DSAAccess { @Override public void generateMipmaps(int texture, int target) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture); GL30.glGenerateMipmap(target); } @Override public void texParameteri(int texture, int target, int pname, int param) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture); GL11.glTexParameteri(target, pname, param); } @Override public void texParameterf(int texture, int target, int pname, float param) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture); GL11.glTexParameterf(target, pname, param); } @Override public void texParameteriv(int texture, int target, int pname, IntBuffer params) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture); GL11.glTexParameter(target, pname, params); } @@ -406,22 +407,22 @@ public void drawBuffers(int framebuffer, IntBuffer buffers) { @Override public int getTexParameteri(int texture, int target, int pname) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture); return GL11.glGetTexParameteri(target, pname); } @Override public void copyTexSubImage2D(int destTexture, int target, int i, int i1, int i2, int i3, int i4, int width, int height) { int previous = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, destTexture); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, destTexture); GL11.glCopyTexSubImage2D(target, i, i1, i2, i3, i4, width, height); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, previous); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, previous); } @Override public void bindTextureToUnit(int unit, int texture) { - GL13.glActiveTexture(GL13.GL_TEXTURE0 + unit); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + unit); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture); } @Override @@ -457,7 +458,7 @@ public int createFramebuffer() { @Override public int createTexture(int target) { int texture = GL11.glGenTextures(); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture); return texture; } } @@ -473,8 +474,8 @@ public static void bindTextures(int startingTexture, int[] bindings) { } } else { for (int binding : bindings) { - GL13.glActiveTexture(startingTexture); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, binding); + GLStateManager.glActiveTexture(startingTexture); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, binding); startingTexture++; } } diff --git a/src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java b/src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java index b33110a86..e17c8b94f 100644 --- a/src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java +++ b/src/main/java/net/coderbot/iris/gl/program/ProgramSamplers.java @@ -2,6 +2,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.sampler.SamplerBinding; @@ -9,7 +10,6 @@ import net.coderbot.iris.gl.sampler.SamplerLimits; import net.coderbot.iris.gl.state.ValueUpdateNotifier; import net.coderbot.iris.shaderpack.PackRenderTargetDirectives; -import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import java.util.ArrayList; @@ -46,13 +46,13 @@ public void update() { // We need to keep the active texture intact, since if we mess it up // in the middle of RenderType setup, bad things will happen. - int activeTexture = GL11.glGetInteger(GL13.GL_ACTIVE_TEXTURE); + int activeTexture = GLStateManager.getActiveTexture(); for (SamplerBinding samplerBinding : samplerBindings) { samplerBinding.update(); } - GL13.glActiveTexture(GL13.GL_TEXTURE0 + activeTexture); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + activeTexture); } public void removeListeners() { diff --git a/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java b/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java index 217d146bf..92acb183d 100644 --- a/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java +++ b/src/main/java/net/coderbot/iris/gl/program/ProgramUniforms.java @@ -258,11 +258,6 @@ public ProgramUniforms buildUniforms() { dynamic.remove(name); } } - // iterate over perFrame and print each uniform - Iris.logger.info("UNIFORMS"); - for (Map.Entry entry : perFrame.entrySet()) { - Iris.logger.debug("[" + this.name + "] perFrame uniform: " + entry.getKey() + " " + entry.getValue().getLocation()); - } return new ProgramUniforms(ImmutableList.copyOf(once.values()), ImmutableList.copyOf(perTick.values()), ImmutableList.copyOf(perFrame.values()), ImmutableList.copyOf(dynamic.values()), ImmutableList.copyOf(notifiersToReset)); diff --git a/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java b/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java index 5a12861d6..69a9cd0a4 100644 --- a/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java +++ b/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java @@ -1,5 +1,6 @@ package net.coderbot.iris.pipeline; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -145,9 +146,9 @@ else if (textureData instanceof CustomTextureData.ResourceData) { TextureFormat textureFormat = TextureFormatLoader.getFormat(); if (textureFormat != null) { int previousBinding = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, pbrTexture.getGlTextureId()); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, pbrTexture.getGlTextureId()); textureFormat.setupTextureParameters(pbrType, pbrTexture); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, previousBinding); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, previousBinding); } return pbrTexture.getGlTextureId(); diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index c7ac9266d..1cc4a9e47 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -198,13 +198,13 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { BlockRenderingSettings.INSTANCE.setUseExtendedVertexFormat(true); // Don't clobber anything in texture unit 0. It probably won't cause issues, but we're just being cautious here. - GL13.glActiveTexture(GL13.GL_TEXTURE2); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE2); customTextureManager = new CustomTextureManager(programs.getPackDirectives(), programs.getPack().getCustomTextureDataMap(), programs.getPack().getCustomNoiseTexture()); whitePixel = new NativeImageBackedSingleColorTexture(255, 255, 255, 255); - GL13.glActiveTexture(GL13.GL_TEXTURE0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); this.flippedBeforeShadow = ImmutableSet.of(); @@ -853,7 +853,7 @@ private static void destroyPasses(ProgramTable table) { private void prepareRenderTargets() { // Make sure we're using texture unit 0 for this. - GL13.glActiveTexture(GL13.GL_TEXTURE0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); final Vector4f emptyClearColor = new Vector4f(1.0F); if (shadowRenderTargets != null) { diff --git a/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java b/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java index fbacbe020..86f37583b 100644 --- a/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java +++ b/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java @@ -1,5 +1,6 @@ package net.coderbot.iris.pipeline; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.iris.Iris; import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.coderbot.iris.shaderpack.DimensionId; @@ -91,13 +92,13 @@ private void resetTextureState() { // // Without this code, there will be weird issues when reloading certain shaderpacks. for (int i = 0; i < 16; i++) { - GL13.glActiveTexture(GL13.GL_TEXTURE0 + i); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + i); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, 0); } // Set the active texture unit to unit 0 // // This seems to be what most code expects. It's a sane default in any case. - GL13.glActiveTexture(GL13.GL_TEXTURE0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); } } diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 76d67845d..62ece7c85 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -1,6 +1,7 @@ package net.coderbot.iris.pipeline; import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.batchedentityrendering.impl.BatchingDebugMessageHelper; import net.coderbot.batchedentityrendering.impl.DrawCallTrackingRenderBuffers; import net.coderbot.batchedentityrendering.impl.RenderBuffersExt; @@ -185,7 +186,7 @@ private void configureSamplingSettings(PackShadowDirectives shadowDirectives) { final ImmutableList colorSamplingSettings = shadowDirectives.getColorSamplingSettings(); - GL13.glActiveTexture(GL13.GL_TEXTURE4); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE4); configureDepthSampler(targets.getDepthTexture().getTextureId(), depthSamplingSettings.get(0)); @@ -197,7 +198,7 @@ private void configureSamplingSettings(PackShadowDirectives shadowDirectives) { configureSampler(glTextureId, colorSamplingSettings.get(i)); } - GL13.glActiveTexture(GL13.GL_TEXTURE0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); } private void configureDepthSampler(int glTextureId, PackShadowDirectives.DepthSamplingSettings settings) { @@ -233,13 +234,13 @@ private void configureSampler(int glTextureId, PackShadowDirectives.SamplingSett } private void generateMipmaps() { - GL13.glActiveTexture(GL13.GL_TEXTURE4); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE4); for (MipmapPass mipmapPass : mipmapPasses) { setupMipmappingForTexture(mipmapPass.getTexture(), mipmapPass.getTargetFilteringMode()); } - GL13.glActiveTexture(GL13.GL_TEXTURE0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); } private void setupMipmappingForTexture(int texture, int filteringMode) { diff --git a/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java b/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java index 53f0b6de6..65fc3be24 100644 --- a/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java +++ b/src/main/java/net/coderbot/iris/postprocess/CenterDepthSampler.java @@ -1,6 +1,7 @@ package net.coderbot.iris.postprocess; import com.google.common.collect.ImmutableSet; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.iris.Iris; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.framebuffer.GlFramebuffer; @@ -42,7 +43,7 @@ public CenterDepthSampler(IntSupplier depthSupplier, float halfLife) { InternalTextureFormat format = Iris.capabilities.OpenGL32 ? InternalTextureFormat.R32F : InternalTextureFormat.RGB16; setupColorTexture(texture, format); setupColorTexture(altTexture, format); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, 0); this.framebuffer.addColorAttachment(0, texture); ProgramBuilder builder; @@ -114,8 +115,8 @@ public void setUsage(boolean usage) { } public void destroy() { - GL11.glDeleteTextures(texture); - GL11.glDeleteTextures(altTexture); + GLStateManager.glDeleteTextures(texture); + GLStateManager.glDeleteTextures(altTexture); framebuffer.destroy(); program.destroy(); destroyed = true; diff --git a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java index f4c2d00b7..02eccbc32 100644 --- a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java @@ -3,6 +3,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.framebuffer.GlFramebuffer; @@ -233,7 +234,7 @@ public void renderAll() { } if (!renderPass.mipmappedBuffers.isEmpty()) { - GL13.glActiveTexture(GL13.GL_TEXTURE0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); for (int index : renderPass.mipmappedBuffers) { setupMipmapping(CompositeRenderer.this.renderTargets.get(index), renderPass.stageReadsFromAlt.contains(index)); @@ -263,11 +264,11 @@ public void renderAll() { for (int i = 0; i < SamplerLimits.get().getMaxTextureUnits(); i++) { // Unbind all textures that we may have used. // NB: This is necessary for shader pack reloading to work propely - GL13.glActiveTexture(GL13.GL_TEXTURE0 + i); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + i); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, 0); } - GL13.glActiveTexture(GL13.GL_TEXTURE0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); } private static void setupMipmapping(RenderTarget target, boolean readFromAlt) { diff --git a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java index 0a76ef607..c25697f63 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java @@ -2,6 +2,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.coderbot.iris.gl.IrisRenderSystem; @@ -191,7 +192,7 @@ public void renderFinalPass() { IrisRenderSystem.memoryBarrier(40); if (!finalPass.mipmappedBuffers.isEmpty()) { - GL13.glActiveTexture(GL13.GL_TEXTURE0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); for (int index : finalPass.mipmappedBuffers) { setupMipmapping(renderTargets.get(index), finalPass.stageReadsFromAlt.contains(index)); @@ -219,7 +220,7 @@ public void renderFinalPass() { IrisRenderSystem.copyTexSubImage2D(0/*main.getColorTextureId()*/, GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, baseWidth, baseHeight); } - GL13.glActiveTexture(GL13.GL_TEXTURE0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); for (int i = 0; i < renderTargets.getRenderTargetCount(); i++) { // Reset mipmapping states at the end of the frame. @@ -237,7 +238,7 @@ public void renderFinalPass() { // Also note that RenderTargets already calls readBuffer(0) for us. swapPass.from.bind(); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, swapPass.targetTexture); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, swapPass.targetTexture); GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, swapPass.width, swapPass.height); } @@ -252,11 +253,11 @@ public void renderFinalPass() { for (int i = 0; i < SamplerLimits.get().getMaxTextureUnits(); i++) { // Unbind all textures that we may have used. // NB: This is necessary for shader pack reloading to work properly - GL13.glActiveTexture(GL13.GL_TEXTURE0 + i); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + i); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, 0); } - GL13.glActiveTexture(GL13.GL_TEXTURE0); + GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); } public void recalculateSwapPassSize() { @@ -305,7 +306,7 @@ private static void resetRenderTarget(RenderTarget target) { IrisRenderSystem.texParameteri(target.getMainTexture(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); IrisRenderSystem.texParameteri(target.getAltTexture(), GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, 0); } // TODO: Don't just copy this from DeferredWorldRenderingPipeline diff --git a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java index 933f08466..f2f39792b 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java @@ -1,5 +1,6 @@ package net.coderbot.iris.postprocess; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.compat.mojang.DefaultVertexFormat; import org.lwjgl.BufferUtils; @@ -50,7 +51,7 @@ public void begin() { } public void renderQuad() { - GL11.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, 4); + GLStateManager.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, 4); } @SuppressWarnings("deprecation") diff --git a/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java b/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java index 415b318a1..9e0c8d3ac 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java @@ -1,5 +1,6 @@ package net.coderbot.iris.rendertarget; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.iris.gl.GlResource; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.texture.TextureUploadHelper; @@ -30,6 +31,6 @@ public int getTextureId() { @Override protected void destroyInternal() { - GL11.glDeleteTextures(getGlId()); + GLStateManager.glDeleteTextures(getGlId()); } } diff --git a/src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java b/src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java index d73b75a21..9906002d4 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/DepthTexture.java @@ -1,5 +1,6 @@ package net.coderbot.iris.rendertarget; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.iris.gl.GlResource; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.texture.DepthBufferFormat; @@ -18,7 +19,7 @@ public DepthTexture(int width, int height, DepthBufferFormat format) { IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); IrisRenderSystem.texParameteri(texture, GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, 0); } void resize(int width, int height, DepthBufferFormat format) { @@ -32,6 +33,6 @@ public int getTextureId() { @Override protected void destroyInternal() { - GL11.glDeleteTextures(getGlId()); + GLStateManager.glDeleteTextures(getGlId()); } } diff --git a/src/main/java/net/coderbot/iris/rendertarget/NoiseTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NoiseTexture.java index 2ecf25b4f..db1780a4c 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NoiseTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NoiseTexture.java @@ -1,5 +1,6 @@ package net.coderbot.iris.rendertarget; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.iris.gl.GlResource; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.texture.TextureUploadHelper; @@ -33,7 +34,7 @@ public NoiseTexture(int width, int height) { IrisRenderSystem.texParameterf(texture, GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_LOD_BIAS, 0.0F); resize(texture, width, height); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, 0); } void resize(int texture, int width, int height) { @@ -48,7 +49,7 @@ void resize(int texture, int width, int height) { GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1); IrisRenderSystem.texImage2D(texture, GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, width, height, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, pixels); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, 0); } private ByteBuffer generateNoise() { @@ -70,6 +71,6 @@ public int getTextureId() { @Override protected void destroyInternal() { - GL11.glDeleteTextures(getGlId()); + GLStateManager.glDeleteTextures(getGlId()); } } diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java index 43986dbef..c0d8fb0a1 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java @@ -1,5 +1,6 @@ package net.coderbot.iris.rendertarget; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import lombok.Getter; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.texture.InternalTextureFormat; @@ -50,7 +51,7 @@ public RenderTarget(Builder builder) { // Clean up after ourselves // This is strictly defensive to ensure that other buggy code doesn't tamper with our textures - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, 0); } private void setupTexture(int texture, int width, int height, boolean allowsLinear) { @@ -101,8 +102,8 @@ public int getAltTexture() { public void destroy() { requireValid(); isValid = false; - GL11.glDeleteTextures(mainTexture); - GL11.glDeleteTextures(altTexture); + GLStateManager.glDeleteTextures(mainTexture); + GLStateManager.glDeleteTextures(altTexture); } private void requireValid() { diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java index 86142d6f6..7c1b76b3a 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java @@ -1,6 +1,7 @@ package net.coderbot.iris.rendertarget; import com.google.common.collect.ImmutableSet; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import lombok.Getter; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.framebuffer.GlFramebuffer; @@ -57,7 +58,7 @@ public RenderTargets(int width, int height, int depthBufferVersion, Map> 8 & 0xFF) / 255.0f, (rgba & 0xFF) / 255.0f ); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, textureId); for (int level = 0; level <= maxLevel; ++level) { int width = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_WIDTH); int height = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_HEIGHT); @@ -45,7 +46,7 @@ public static void fillWithColor(int textureId, int maxLevel, int rgba) { OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, previousFramebufferId); GL11.glClearColor(previousClearColor[0], previousClearColor[1], previousClearColor[2], previousClearColor[3]); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, previousTextureId); + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, previousTextureId); GL11.glViewport(previousViewport[0], previousViewport[1], previousViewport[2], previousViewport[3]); } } From 098cc39dd5c388c38cf44d37b63f60025bfcb8bc Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 1 Nov 2023 08:39:50 -0700 Subject: [PATCH 020/301] Make NotFine mixins Client only --- .../angelica/loading/AngelicaLateMixins.java | 32 ++++++++++++------- .../angelica/loading/AngelicaTweaker.java | 4 +++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java index bb6ced6f1..cd892a54f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java @@ -1,12 +1,5 @@ package com.gtnewhorizons.angelica.loading; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import com.gtnewhorizon.gtnhmixins.ILateMixinLoader; import com.gtnewhorizon.gtnhmixins.LateMixin; import com.gtnewhorizons.angelica.mixins.ArchaicMixins; @@ -18,12 +11,24 @@ import cpw.mods.fml.common.versioning.DefaultArtifactVersion; import cpw.mods.fml.common.versioning.InvalidVersionSpecificationException; import cpw.mods.fml.common.versioning.VersionRange; +import cpw.mods.fml.relauncher.FMLLaunchHandler; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.coreMods; @LateMixin public class AngelicaLateMixins implements ILateMixinLoader { + public static final String TWILIGHT_FOREST = "TwilightForest"; + public static final String THAUMCRAFT = "Thaumcraft"; + public static final String WITCHERY = "witchery"; + @Override public String getMixinConfig() { return "mixins.angelica.late.json"; @@ -49,21 +54,24 @@ public List getMixins(Set loadedMods) { } private List getNotFineMixins(Set loadedMods) { + if(FMLLaunchHandler.side().isServer()) + return Collections.emptyList(); + final List mixins = new ArrayList<>(); - if(loadedMods.contains("Thaumcraft")) { + if(loadedMods.contains(THAUMCRAFT)) { mixins.add("leaves.thaumcraft.MixinBlockMagicalLeaves"); } - if(loadedMods.contains("TwilightForest")) { + if(loadedMods.contains(TWILIGHT_FOREST)) { mixins.add("leaves.twilightforest.MixinBlockTFLeaves"); mixins.add("leaves.twilightforest.MixinBlockTFLeaves3"); //Non-GTNH Twilight Forest builds will break horribly with this mixin. boolean modernBuild = false; try { - ArtifactVersion accepted = new DefaultArtifactVersion("TwilightForest", VersionRange.createFromVersionSpec("[2.3.8.18,)")); - ModContainer mc = Loader.instance().getIndexedModList().get("TwilightForest"); + ArtifactVersion accepted = new DefaultArtifactVersion(TWILIGHT_FOREST, VersionRange.createFromVersionSpec("[2.3.8.18,)")); + ModContainer mc = Loader.instance().getIndexedModList().get(TWILIGHT_FOREST); if(mc != null) modernBuild = accepted.containsVersion(mc.getProcessedVersion()); } catch (InvalidVersionSpecificationException ignored) {} @@ -72,7 +80,7 @@ private List getNotFineMixins(Set loadedMods) { } } - if(loadedMods.contains("witchery")) { + if(loadedMods.contains(WITCHERY)) { mixins.add("leaves.witchery.MixinBlockWitchLeaves"); } return mixins; diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index 5c82021e1..29bf2662b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -5,6 +5,7 @@ import com.gtnewhorizons.angelica.mixins.ArchaicMixins; import com.gtnewhorizons.angelica.mixins.Mixins; import com.gtnewhorizons.angelica.mixins.TargetedMod; +import cpw.mods.fml.relauncher.FMLLaunchHandler; import cpw.mods.fml.relauncher.IFMLLoadingPlugin; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; @@ -104,6 +105,9 @@ public List getMixins(Set loadedCoreMods) { } private List getNotFineMixins(Set loadedCoreMods) { + if(FMLLaunchHandler.side().isServer()) + return Collections.emptyList(); + final List mixins = new ArrayList<>(); mixins.add("notfine.clouds.MixinEntityRenderer"); mixins.add("notfine.clouds.MixinGameSettings"); From 20e5cf7ee182ed7a5ccb3f9b489325cd278ede2c Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 2 Nov 2023 17:37:51 -0700 Subject: [PATCH 021/301] Progress * Stop running ShaderMod Mixins, but leave them around as reference points for where to inject. Document relations w/ TODOs * Reorganize shaders mixins * Updated GLDebug --- .../angelica/client/Shaders.java | 1 - .../angelica/client/ShadersTess.java | 40 +++-- .../angelica/client/ShadersTex.java | 8 +- .../angelica/glsm/GLStateManager.java | 8 + .../gtnewhorizons/angelica/mixins/Mixins.java | 66 +++----- .../accessors/EntityRendererAccessor.java | 2 +- .../accessors/MinecraftAccessor.java | 2 +- .../accessors/SimpleTextureAccessor.java | 2 +- .../accessors/TextureAtlasSpriteAccessor.java | 2 +- .../{ => startup}/MixinGameSettings.java | 2 +- .../{ => startup}/MixinGuiMainMenu.java | 2 +- .../{ => startup}/MixinInitRenderer.java | 2 +- .../shaders/{ => startup}/MixinMinecraft.java | 11 +- .../{ => shadersmod}/lighting/MixinBlock.java | 2 +- .../lighting/MixinRenderBlocks.java | 2 +- .../renderer/MixinAbstractTexture.java | 2 +- .../renderer/MixinDynamicTexture.java | 11 +- .../renderer/MixinEntityRenderer.java | 7 +- .../renderer/MixinITextureObject.java | 2 +- .../renderer/MixinItemRenderer.java | 4 +- .../renderer/MixinLayeredTexture.java | 12 +- .../renderer/MixinModelRenderer.java | 4 +- .../renderer/MixinOpenGlHelper.java | 2 +- .../renderer/MixinRender.java | 4 +- .../renderer/MixinRenderBlocks.java | 15 +- .../renderer/MixinRenderDragon.java | 4 +- .../renderer/MixinRenderEnderman.java | 4 +- .../renderer/MixinRenderGlobal.java | 15 +- .../renderer/MixinRenderSpider.java | 4 +- .../renderer/MixinRendererLivingEntity.java | 7 +- .../renderer/MixinSimpleTexture.java | 18 +-- .../renderer/MixinTessellator.java | 34 ++--- .../renderer/MixinTextureAtlasSprite.java | 3 +- .../renderer/MixinTextureClock.java | 4 +- .../renderer/MixinTextureCompass.java | 3 +- .../renderer/MixinTextureManager.java | 8 +- .../renderer/MixinTextureMap.java | 30 +--- .../MixinThreadDownloadImageData.java | 4 +- .../settings/MixinGuiVideoSettings.java | 2 +- .../compat/MixinModelRotationRenderer.java | 2 +- .../transform/GLStateManagerTransformer.java | 6 +- src/main/java/net/coderbot/iris/Iris.java | 1 - .../java/net/coderbot/iris/gl/GLDebug.java | 142 +++++++++++++----- .../iris/pipeline/ClearPassCreator.java | 3 +- .../DeferredWorldRenderingPipeline.java | 24 +-- .../iris/postprocess/CompositeRenderer.java | 4 +- .../iris/postprocess/FinalPassRenderer.java | 5 +- .../iris/rendertarget/ColorTexture.java | 2 + .../iris/rendertarget/RenderTargets.java | 26 ++-- .../iris/shadows/ShadowRenderTargets.java | 6 +- .../texture/pbr/loader/SimplePBRLoader.java | 2 +- .../iris/uniforms/CommonUniforms.java | 2 +- 52 files changed, 272 insertions(+), 308 deletions(-) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shaders}/accessors/EntityRendererAccessor.java (84%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shaders}/accessors/MinecraftAccessor.java (80%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shaders}/accessors/SimpleTextureAccessor.java (83%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shaders}/accessors/TextureAtlasSpriteAccessor.java (92%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/{ => startup}/MixinGameSettings.java (92%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/{ => startup}/MixinGuiMainMenu.java (88%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/{ => startup}/MixinInitRenderer.java (91%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/{ => startup}/MixinMinecraft.java (68%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/lighting/MixinBlock.java (87%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/lighting/MixinRenderBlocks.java (98%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinAbstractTexture.java (92%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinDynamicTexture.java (84%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinEntityRenderer.java (98%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinITextureObject.java (79%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinItemRenderer.java (94%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinLayeredTexture.java (90%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinModelRenderer.java (87%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinOpenGlHelper.java (89%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinRender.java (87%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinRenderBlocks.java (82%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinRenderDragon.java (90%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinRenderEnderman.java (90%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinRenderGlobal.java (98%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinRenderSpider.java (90%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinRendererLivingEntity.java (93%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinSimpleTexture.java (83%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinTessellator.java (92%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinTextureAtlasSprite.java (89%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinTextureClock.java (88%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinTextureCompass.java (88%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinTextureManager.java (85%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinTextureMap.java (86%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/renderer/MixinThreadDownloadImageData.java (88%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shadersmod}/settings/MixinGuiVideoSettings.java (95%) diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index 1f5515fb7..b53e71499 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -645,7 +645,6 @@ public static int checkFramebufferStatus(String location) { } public static int checkGLError(String location) { - if (true) return 0; int errorCode = GL11.glGetError(); if (errorCode != GL11.GL_NO_ERROR) { boolean skipPrint = false; diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTess.java b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTess.java index 76c0d96b4..b8fcaeb55 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTess.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTess.java @@ -1,21 +1,19 @@ package com.gtnewhorizons.angelica.client; -import static org.lwjgl.opengl.ARBVertexShader.glDisableVertexAttribArrayARB; -import static org.lwjgl.opengl.ARBVertexShader.glEnableVertexAttribArrayARB; -import static org.lwjgl.opengl.ARBVertexShader.glVertexAttribPointerARB; - -import java.nio.FloatBuffer; -import java.nio.ShortBuffer; -import java.util.Arrays; - +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import com.gtnewhorizons.angelica.mixins.interfaces.TessellatorAccessor; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.Tessellator; - import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; -import com.gtnewhorizons.angelica.mixins.interfaces.TessellatorAccessor; +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; +import java.util.Arrays; + +import static org.lwjgl.opengl.ARBVertexShader.glDisableVertexAttribArrayARB; +import static org.lwjgl.opengl.ARBVertexShader.glEnableVertexAttribArrayARB; +import static org.lwjgl.opengl.ARBVertexShader.glVertexAttribPointerARB; public class ShadersTess { @@ -219,12 +217,12 @@ public static void addVertex(Tessellator tess, double parx, double pary, double tessa.angelica$setNormalX(normalX); tessa.angelica$setNormalY(normalY); tessa.angelica$setNormalZ(normalZ); - rawBuffer[rbi + (9 - vertexStride * 3)] = rawBuffer[rbi + (9 - vertexStride * 2)] = rawBuffer[rbi - + (9 - vertexStride * 1)] = Float.floatToRawIntBits(normalX); - rawBuffer[rbi + (10 - vertexStride * 3)] = rawBuffer[rbi + (10 - vertexStride * 2)] = rawBuffer[rbi - + (10 - vertexStride * 1)] = Float.floatToRawIntBits(normalY); - rawBuffer[rbi + (11 - vertexStride * 3)] = rawBuffer[rbi + (11 - vertexStride * 2)] = rawBuffer[rbi - + (11 - vertexStride * 1)] = Float.floatToRawIntBits(normalZ); + rawBuffer[rbi + (9 - vertexStride * 3)] = rawBuffer[rbi + (9 - vertexStride * 2)] = + rawBuffer[rbi + (9 - vertexStride * 1)] = Float.floatToRawIntBits(normalX); + rawBuffer[rbi + (10 - vertexStride * 3)] = rawBuffer[rbi + (10 - vertexStride * 2)] = + rawBuffer[rbi + (10 - vertexStride * 1)] = Float.floatToRawIntBits(normalY); + rawBuffer[rbi + (11 - vertexStride * 3)] = rawBuffer[rbi + (11 - vertexStride * 2)] = + rawBuffer[rbi + (11 - vertexStride * 1)] = Float.floatToRawIntBits(normalZ); tess.hasNormals = true; // mid UV tessa.angelica$setMidTextureU( @@ -237,10 +235,10 @@ public static void addVertex(Tessellator tess, double parx, double pary, double + Float.intBitsToFloat(rawBuffer[rbi + (4 - vertexStride * 2)]) + Float.intBitsToFloat(rawBuffer[rbi + (4 - vertexStride * 1)]) + (float) tess.textureV) / 4); - rawBuffer[rbi + (12 - vertexStride * 3)] = rawBuffer[rbi + (12 - vertexStride * 2)] = rawBuffer[rbi - + (12 - vertexStride * 1)] = Float.floatToRawIntBits(tessa.angelica$getMidTextureU()); - rawBuffer[rbi + (13 - vertexStride * 3)] = rawBuffer[rbi + (13 - vertexStride * 2)] = rawBuffer[rbi - + (13 - vertexStride * 1)] = Float.floatToRawIntBits(tessa.angelica$getMidTextureV()); + rawBuffer[rbi + (12 - vertexStride * 3)] = rawBuffer[rbi + (12 - vertexStride * 2)] = + rawBuffer[rbi + (12 - vertexStride * 1)] = Float.floatToRawIntBits(tessa.angelica$getMidTextureU()); + rawBuffer[rbi + (13 - vertexStride * 3)] = rawBuffer[rbi + (13 - vertexStride * 2)] = + rawBuffer[rbi + (13 - vertexStride * 1)] = Float.floatToRawIntBits(tessa.angelica$getMidTextureV()); } } // end normal and mid UV calculation diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java index 4074f81dd..34040e0f6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java @@ -223,6 +223,7 @@ public static void allocTexStorage(int width, int height, int maxLevel) { // for Dynamic Texture public static void initDynamicTexture(int texID, int width, int height, DynamicTexture tex) { + // TODO: PBR MultiTexID multiTex = tex.angelica$getMultiTexID(); int[] aint = tex.getTextureData(); int size = width * height; @@ -237,6 +238,7 @@ public static void initDynamicTexture(int texID, int width, int height, DynamicT GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0); + // This seems PBR related... // norm texture GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); allocTexStorage(width, height, 0); @@ -374,8 +376,8 @@ public static int[][] genMipmapsSimple(int maxLevel, int width, int[][] data) { return data; } - public static void uploadTexSub(int[][] data, int width, int height, int xoffset, int yoffset, boolean linear, - boolean clamp) { + public static void uploadTexSub(int[][] data, int width, int height, int xoffset, int yoffset, boolean linear, boolean clamp) { + // TODO: Mipmap TextureUtil.uploadTextureMipmap(data, width, height, xoffset, yoffset, linear, clamp); } @@ -606,6 +608,7 @@ public static void setupTextureMipmap(TextureMap tex) { } public static void updateDynamicTexture(int texID, int[] src, int width, int height, DynamicTexture tex) { + // TODO: PBR MultiTexID multiTex = tex.angelica$getMultiTexID(); GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); updateSubImage1(src, width, height, 0, 0, 1, defNormTexColor); @@ -760,6 +763,7 @@ public static void loadNSMap1(IResourceManager manager, ResourceLocation locatio */ public static int loadSimpleTexture(int textureID, BufferedImage bufferedimage, boolean linear, boolean clamp, IResourceManager resourceManager, ResourceLocation location, MultiTexID multiTex) { + // TODO: PBR int width = bufferedimage.getWidth(); int height = bufferedimage.getHeight(); int size = width * height; diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index bf50ce76d..f707d2ee4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -18,6 +18,7 @@ import net.coderbot.iris.texture.TextureInfoCache; import net.coderbot.iris.texture.TextureTracker; import net.coderbot.iris.texture.pbr.PBRTextureManager; +import org.lwjgl.opengl.ARBMultitexture; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL14; @@ -201,6 +202,13 @@ public static void glActiveTexture(int texture) { GL13.glActiveTexture(texture); } } + public static void glActiveTextureARB(int texture) { + final int newTexture = texture - GL13.GL_TEXTURE0; + if (activeTexture != newTexture) { + activeTexture = newTexture; + ARBMultitexture.glActiveTextureARB(texture); + } + } public static void glBindTexture(int target, int texture) { if(Textures[activeTexture].binding != texture) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 2ecdbe602..bc3c9f61e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -10,14 +10,14 @@ public enum Mixins { - ANGELICA_STARTUP(new Builder("Start Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( - "shaders.MixinMinecraft", - "shaders.MixinGameSettings", - "shaders.MixinGuiMainMenu", - "shaders.MixinInitRenderer") + "shaders.startup.MixinMinecraft", + "shaders.startup.MixinGameSettings", + "shaders.startup.MixinGuiMainMenu", + "shaders.startup.MixinInitRenderer") ), - IRIS_RENDERING(new Builder("Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + IRIS_RENDERING(new Builder("Iris Shaders").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( "shaders.MixinEntityRenderer", "shaders.MixinItem", @@ -25,57 +25,27 @@ public enum Mixins { ) ), - - ANGELICA_ACCESSORS(new Builder("Angelica Accessors").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + IRIS_ACCESSORS(new Builder("Iris Accessors").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( - "accessors.MinecraftAccessor", - "accessors.EntityRendererAccessor", - "accessors.SimpleTextureAccessor", - "accessors.TextureAtlasSpriteAccessor" + "shaders.accessors.MinecraftAccessor", + "shaders.accessors.EntityRendererAccessor", + "shaders.accessors.SimpleTextureAccessor", + "shaders.accessors.TextureAtlasSpriteAccessor" )), - ANGELICA_SHADERS_BUTTON(new Builder("Add Shaders Button").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses("settings.MixinGuiVideoSettings")), - - ANGELICA_LIGHTING(new Builder("Lighting").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses("lighting.MixinBlock", "lighting.MixinRenderBlocks")), - - ANGELICA_RENDERER(new Builder("Renderer").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses( - "renderer.MixinAbstractTexture", - "renderer.MixinDynamicTexture", - "renderer.MixinEntityRenderer", - "renderer.MixinItemRenderer", - "renderer.MixinITextureObject", - "renderer.MixinLayeredTexture", - "renderer.MixinModelRenderer", - "renderer.MixinOpenGlHelper", - "renderer.MixinRender", - "renderer.MixinRenderBlocks", - "renderer.MixinRenderDragon", - "renderer.MixinRenderEnderman", - "renderer.MixinRendererLivingEntity", - "renderer.MixinRenderGlobal", - "renderer.MixinRenderSpider", - "renderer.MixinSimpleTexture", - "renderer.MixinTessellator", - "renderer.MixinTextureAtlasSprite", - "renderer.MixinTextureClock", - "renderer.MixinTextureCompass", - "renderer.MixinTextureManager", - "renderer.MixinTextureMap", - "renderer.MixinThreadDownloadImageData")), ANGELICA_TEXTURE(new Builder("Texture").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( )), - COMPAT_PR_ILLUMINATION( - new Builder("ProjectRed Illumination compat").addTargetedMod(TargetedMod.PROJECTRED_ILLUMINATION) - .setSide(Side.CLIENT).addMixinClasses("compat.MixinRenderHalo")), - COMPAT_SMART_RENDER(new Builder("Smart Render compat").addTargetedMod(TargetedMod.SMART_RENDER).setSide(Side.CLIENT) - .addMixinClasses("compat.MixinModelRotationRenderer")) + // TODO: Iris +// SHADERSMOD_COMPAT_PR_ILLUMINATION( +// new Builder("ProjectRed Illumination compat").addTargetedMod(TargetedMod.PROJECTRED_ILLUMINATION) +// .setSide(Side.CLIENT).addMixinClasses("compat.MixinRenderHalo")), +// +// SHADERSMOD_COMPAT_SMART_RENDER(new Builder("Smart Render compat").addTargetedMod(TargetedMod.SMART_RENDER).setSide(Side.CLIENT) +// .addMixinClasses("compat.MixinModelRotationRenderer")) ; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/EntityRendererAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/EntityRendererAccessor.java similarity index 84% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/EntityRendererAccessor.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/EntityRendererAccessor.java index 11168107b..1dbab0d41 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/EntityRendererAccessor.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/EntityRendererAccessor.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.accessors; +package com.gtnewhorizons.angelica.mixins.early.shaders.accessors; import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.entity.player.EntityPlayer; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/MinecraftAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/MinecraftAccessor.java similarity index 80% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/MinecraftAccessor.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/MinecraftAccessor.java index 83729cb93..767f185af 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/MinecraftAccessor.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/MinecraftAccessor.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.accessors; +package com.gtnewhorizons.angelica.mixins.early.shaders.accessors; import net.minecraft.client.Minecraft; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/SimpleTextureAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/SimpleTextureAccessor.java similarity index 83% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/SimpleTextureAccessor.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/SimpleTextureAccessor.java index 0a361fed0..bc346ff60 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/SimpleTextureAccessor.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/SimpleTextureAccessor.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.accessors; +package com.gtnewhorizons.angelica.mixins.early.shaders.accessors; import net.minecraft.client.renderer.texture.SimpleTexture; import net.minecraft.util.ResourceLocation; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/TextureAtlasSpriteAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureAtlasSpriteAccessor.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/TextureAtlasSpriteAccessor.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureAtlasSpriteAccessor.java index 2e436563c..fc23b9f05 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/accessors/TextureAtlasSpriteAccessor.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureAtlasSpriteAccessor.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.accessors; +package com.gtnewhorizons.angelica.mixins.early.shaders.accessors; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.data.AnimationMetadataSection; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGameSettings.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGameSettings.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGameSettings.java index 24cc82172..83e07781a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGameSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGameSettings.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.shaders; +package com.gtnewhorizons.angelica.mixins.early.shaders.startup; import net.coderbot.iris.Iris; import net.minecraft.client.settings.GameSettings; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGuiMainMenu.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGuiMainMenu.java similarity index 88% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGuiMainMenu.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGuiMainMenu.java index a0a5a6aa1..407bc8f68 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinGuiMainMenu.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGuiMainMenu.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.shaders; +package com.gtnewhorizons.angelica.mixins.early.shaders.startup; import net.coderbot.iris.Iris; import net.minecraft.client.gui.GuiMainMenu; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinInitRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinInitRenderer.java similarity index 91% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinInitRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinInitRenderer.java index fa075e274..629ce6931 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinInitRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinInitRenderer.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.shaders; +package com.gtnewhorizons.angelica.mixins.early.shaders.startup; import net.coderbot.iris.Iris; import net.coderbot.iris.gl.GLDebug; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinMinecraft.java similarity index 68% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinMinecraft.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinMinecraft.java index b559db801..72fb46d0d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinMinecraft.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinMinecraft.java @@ -1,6 +1,5 @@ -package com.gtnewhorizons.angelica.mixins.early.shaders; +package com.gtnewhorizons.angelica.mixins.early.shaders.startup; -import com.gtnewhorizons.angelica.client.Shaders; import net.coderbot.iris.rendertarget.IRenderTargetExt; import net.minecraft.client.Minecraft; import net.minecraft.profiler.IPlayerUsage; @@ -16,14 +15,6 @@ public abstract class MixinMinecraft implements IPlayerUsage, IRenderTargetExt { private int iris$colorBufferVersion; - @Inject(method = "startGame()V", - at = @At(ordinal = 1, shift = At.Shift.AFTER, value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;checkGLError(Ljava/lang/String;)V")) - private void angelica$Startup(CallbackInfo ci) { - // Start the Shaders - Shaders.startup(((Minecraft) ((Object) this))); - } - - @Inject(method = "updateFramebufferSize()V", at = @At("HEAD")) private void iris$onDestroyBuffers(CallbackInfo ci) { iris$depthBufferVersion++; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/lighting/MixinBlock.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinBlock.java similarity index 87% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/lighting/MixinBlock.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinBlock.java index 963b0e5a2..c47dda264 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/lighting/MixinBlock.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinBlock.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.lighting; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.lighting; import net.minecraft.block.Block; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/lighting/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinRenderBlocks.java similarity index 98% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/lighting/MixinRenderBlocks.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinRenderBlocks.java index c2338547f..0077e2def 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/lighting/MixinRenderBlocks.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinRenderBlocks.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.lighting; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.lighting; import net.minecraft.client.renderer.RenderBlocks; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinAbstractTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinAbstractTexture.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinAbstractTexture.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinAbstractTexture.java index eb0abca22..50c275853 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinAbstractTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinAbstractTexture.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.texture.AbstractTexture; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinDynamicTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinDynamicTexture.java similarity index 84% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinDynamicTexture.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinDynamicTexture.java index 38fae2bf5..fc0398e68 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinDynamicTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinDynamicTexture.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.texture.DynamicTexture; @@ -11,7 +11,7 @@ @Mixin(DynamicTexture.class) public class MixinDynamicTexture { - + // TODO: PBR @ModifyVariable(argsOnly = true, at = @At(ordinal = 1, value = "LOAD"), index = 1, method = "(II)V") private int angelica$resizeDynamicTextureData(int p_i1271_2_) { return p_i1271_2_ * 3; @@ -33,12 +33,7 @@ public class MixinDynamicTexture { value = "INVOKE"), method = "updateDynamicTexture()V") private void angelica$updateDynamicTexture(int p_110988_0_, int[] p_110988_1_, int p_110988_2_, int p_110988_3_) { - ShadersTex.updateDynamicTexture( - p_110988_0_, - p_110988_1_, - p_110988_2_, - p_110988_3_, - (DynamicTexture) (Object) this); + ShadersTex.updateDynamicTexture(p_110988_0_, p_110988_1_, p_110988_2_, p_110988_3_, (DynamicTexture) (Object) this); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinEntityRenderer.java similarity index 98% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinEntityRenderer.java index 738d5e89c..bcbe29bf9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinEntityRenderer.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import com.gtnewhorizons.angelica.client.Shaders; import com.gtnewhorizons.angelica.client.ShadersRender; @@ -25,7 +25,7 @@ @Mixin(EntityRenderer.class) public abstract class MixinEntityRenderer { - + // TODO: Rendering @Shadow private Minecraft mc; @@ -77,8 +77,7 @@ public abstract class MixinEntityRenderer { Shaders.beginRender(this.mc, renderPartialTicks, tickDelta); } - @Redirect( - at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glViewport(IIII)V", value = "INVOKE"), + @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glViewport(IIII)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void angelica$setViewport(int x, int y, int width, int height) { Shaders.setViewport(x, y, width, height); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinITextureObject.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinITextureObject.java similarity index 79% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinITextureObject.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinITextureObject.java index 5e54da1b2..0a3b34a4d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinITextureObject.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinITextureObject.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.texture.ITextureObject; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinItemRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinItemRenderer.java similarity index 94% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinItemRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinItemRenderer.java index 11aa5830a..45db1edfb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinItemRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinItemRenderer.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.entity.EntityClientPlayerMP; import net.minecraft.client.renderer.ItemRenderer; @@ -16,7 +16,7 @@ @Mixin(ItemRenderer.class) public class MixinItemRenderer { - + // TODO: Rendering - items @Inject( at = @At( opcode = Opcodes.PUTFIELD, diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinLayeredTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java similarity index 90% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinLayeredTexture.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java index 51759a3ee..3bb04399f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinLayeredTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java @@ -1,21 +1,19 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; - -import java.io.IOException; -import java.util.List; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; +import com.gtnewhorizons.angelica.client.ShadersTex; import net.minecraft.client.renderer.texture.LayeredTexture; import net.minecraft.client.resources.IResourceManager; - import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; -import com.gtnewhorizons.angelica.client.ShadersTex; +import java.io.IOException; +import java.util.List; @Mixin(LayeredTexture.class) public class MixinLayeredTexture { - + // TODO: PBR @Final @Shadow public List layeredTextureNames; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinModelRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinModelRenderer.java similarity index 87% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinModelRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinModelRenderer.java index a71e868e9..543b68d71 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinModelRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinModelRenderer.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.model.ModelRenderer; import net.minecraft.client.renderer.GLAllocation; @@ -10,7 +10,7 @@ @Mixin(ModelRenderer.class) public class MixinModelRenderer implements IModelRenderer { - + // TODO: Rendering @Shadow private boolean compiled; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinOpenGlHelper.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinOpenGlHelper.java similarity index 89% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinOpenGlHelper.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinOpenGlHelper.java index 023c2cd4d..c2fe30cab 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinOpenGlHelper.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinOpenGlHelper.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.OpenGlHelper; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRender.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRender.java similarity index 87% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRender.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRender.java index be2289ff4..eb073ddfb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRender.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRender.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.entity.Render; @@ -11,7 +11,7 @@ @Mixin(Render.class) public class MixinRender { - + // TODO: Rendering @Inject(method = "renderShadow(Lnet/minecraft/entity/Entity;DDDFF)V", at = @At("HEAD"), cancellable = true) private void angelica$checkShouldSkipDefaultShadow(CallbackInfo ci) { if (Shaders.shouldSkipDefaultShadow) ci.cancel(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderBlocks.java similarity index 82% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderBlocks.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderBlocks.java index 114527344..160e6e7fd 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderBlocks.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderBlocks.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.block.Block; import net.minecraft.block.BlockFlowerPot; @@ -30,22 +30,18 @@ public class MixinRenderBlocks { // BlockFlowerPot @Inject(method = "renderBlockFlowerpot(Lnet/minecraft/block/BlockFlowerPot;III)Z", at = @At("HEAD")) - private void angelica$pushEntityBlockFlowerPot(BlockFlowerPot blockFlowerPot, int x, int y, int z, - CallbackInfoReturnable cir) { + private void angelica$pushEntityBlockFlowerPot(BlockFlowerPot blockFlowerPot, int x, int y, int z, CallbackInfoReturnable cir) { Shaders.pushEntity((RenderBlocks) ((Object) this), blockFlowerPot, x, y, z); } @Inject(method = "renderBlockFlowerpot(Lnet/minecraft/block/BlockFlowerPot;III)Z", at = @At("RETURN")) - private void angelica$popEntityBlockFlowerPot(BlockFlowerPot blockFlowerPot, int x, int y, int z, - CallbackInfoReturnable cir) { + private void angelica$popEntityBlockFlowerPot(BlockFlowerPot blockFlowerPot, int x, int y, int z, CallbackInfoReturnable cir) { Shaders.popEntity(); } @WrapOperation( method = "renderBlockFlowerpot(Lnet/minecraft/block/BlockFlowerPot;III)Z", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/block/Block;getBlockFromItem(Lnet/minecraft/item/Item;)Lnet/minecraft/block/Block;")) + at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;getBlockFromItem(Lnet/minecraft/item/Item;)Lnet/minecraft/block/Block;")) private Block angelica$pushEntityFlowerInFlowerPot(Item itemIn, Operation original) { final Block block = original.call(itemIn); Shaders.pushEntity(block); @@ -59,8 +55,7 @@ public class MixinRenderBlocks { target = "Lnet/minecraft/client/renderer/Tessellator;addTranslation(FFF)V", shift = At.Shift.AFTER, ordinal = 1)) - private void angelica$popEntityFlowerInFlowerPot(BlockFlowerPot blockFlowerPot, int x, int y, int z, - CallbackInfoReturnable cir) { + private void angelica$popEntityFlowerInFlowerPot(BlockFlowerPot blockFlowerPot, int x, int y, int z, CallbackInfoReturnable cir) { Shaders.popEntity(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderDragon.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderDragon.java similarity index 90% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderDragon.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderDragon.java index eb795ccee..91b68a223 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderDragon.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderDragon.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.entity.RenderDragon; @@ -11,7 +11,7 @@ @Mixin(RenderDragon.class) public class MixinRenderDragon { - + // TODO: Rendering @Inject( at = @At( remap = false, diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderEnderman.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderEnderman.java similarity index 90% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderEnderman.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderEnderman.java index 903e87d0e..f82692b88 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderEnderman.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderEnderman.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.entity.RenderEnderman; @@ -11,7 +11,7 @@ @Mixin(RenderEnderman.class) public class MixinRenderEnderman { - + // TODO: Rendering @Inject( at = @At( remap = false, diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderGlobal.java similarity index 98% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderGlobal.java index 6ec3feffe..e8d80267f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderGlobal.java @@ -1,29 +1,24 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; -import jss.notfine.core.Settings; -import jss.notfine.render.RenderStars; +import com.gtnewhorizons.angelica.client.Shaders; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.culling.ICamera; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.MovingObjectPosition; - import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.gtnewhorizons.angelica.client.Shaders; - @Mixin(RenderGlobal.class) public class MixinRenderGlobal { - + // TODO: Rendering @Inject( method = "renderEntities(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/client/renderer/culling/ICamera;F)V", at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", args = "ldc=entities")) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderSpider.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderSpider.java similarity index 90% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderSpider.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderSpider.java index 8c26918d8..a8309bb0b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRenderSpider.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderSpider.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.entity.RenderSpider; @@ -11,7 +11,7 @@ @Mixin(RenderSpider.class) public class MixinRenderSpider { - + // TODO: Rendering @Inject( at = @At( remap = false, diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRendererLivingEntity.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRendererLivingEntity.java similarity index 93% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRendererLivingEntity.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRendererLivingEntity.java index 9f891a8de..233b5b93c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinRendererLivingEntity.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRendererLivingEntity.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.entity.RendererLivingEntity; import net.minecraft.entity.EntityLivingBase; @@ -13,13 +13,12 @@ @Mixin(RendererLivingEntity.class) public abstract class MixinRendererLivingEntity { - + // TODO: Rendering @Shadow protected abstract int getColorMultiplier(EntityLivingBase p_77030_1_, float p_77030_2_, float p_77030_3_); @Inject(at = @At("HEAD"), method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V") - private void angelica$setEntityHurtFlash(EntityLivingBase p_76986_1_, double p_76986_2_, double p_76986_4_, - double p_76986_6_, float p_76986_8_, float p_76986_9_, CallbackInfo ci) { + private void angelica$setEntityHurtFlash(EntityLivingBase p_76986_1_, double p_76986_2_, double p_76986_4_, double p_76986_6_, float p_76986_8_, float p_76986_9_, CallbackInfo ci) { if (!Shaders.useEntityHurtFlash) { Shaders.setEntityHurtFlash( p_76986_1_.hurtTime <= 0 && p_76986_1_.deathTime <= 0 ? 0 : 102, diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinSimpleTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinSimpleTexture.java similarity index 83% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinSimpleTexture.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinSimpleTexture.java index ece5431e6..9aecfdf3a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinSimpleTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinSimpleTexture.java @@ -1,12 +1,10 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; - -import java.awt.image.BufferedImage; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; +import com.gtnewhorizons.angelica.client.ShadersTex; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.SimpleTexture; import net.minecraft.client.resources.IResourceManager; import net.minecraft.util.ResourceLocation; - import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -14,10 +12,11 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.gtnewhorizons.angelica.client.ShadersTex; +import java.awt.image.BufferedImage; @Mixin(value = SimpleTexture.class) public abstract class MixinSimpleTexture extends AbstractTexture { + // TODO: PBR private IResourceManager passedResourceManager; @@ -36,14 +35,7 @@ public abstract class MixinSimpleTexture extends AbstractTexture { value = "INVOKE", target = "Lnet/minecraft/client/renderer/texture/TextureUtil;uploadTextureImageAllocate(ILjava/awt/image/BufferedImage;ZZ)I")) private int angelica$loadSimpleTexture(int textureID, BufferedImage bufferedImage, boolean flag, boolean flag1) { - ShadersTex.loadSimpleTexture( - textureID, - bufferedImage, - flag, - flag1, - passedResourceManager, - this.textureLocation, - ShadersTex.getMultiTexID(this)); + ShadersTex.loadSimpleTexture(textureID, bufferedImage, flag, flag1, passedResourceManager, this.textureLocation, ShadersTex.getMultiTexID(this)); return 0; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTessellator.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTessellator.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTessellator.java index 12a36bf44..b792e1017 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTessellator.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTessellator.java @@ -1,16 +1,11 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; - -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; -import java.util.PriorityQueue; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; +import com.gtnewhorizons.angelica.client.ShadersTess; +import com.gtnewhorizons.angelica.mixins.interfaces.TessellatorAccessor; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.shader.TesselatorVertexState; import net.minecraft.client.util.QuadComparator; - import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; @@ -18,11 +13,15 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.gtnewhorizons.angelica.client.ShadersTess; -import com.gtnewhorizons.angelica.mixins.interfaces.TessellatorAccessor; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.PriorityQueue; @Mixin(Tessellator.class) public abstract class MixinTessellator implements TessellatorAccessor { + // TODO: Rendering @Shadow(remap = false) public boolean defaultTexture; @@ -122,11 +121,7 @@ public TesselatorVertexState getVertexState(float x, float y, float z) { @SuppressWarnings("unchecked") PriorityQueue pQueue = new PriorityQueue<>( this.rawBufferIndex, - new QuadComparator( - this.rawBuffer, - x + (float) this.xOffset, - y + (float) this.yOffset, - z + (float) this.zOffset)); + new QuadComparator(this.rawBuffer, x + (float) this.xOffset, y + (float) this.yOffset, z + (float) this.zOffset)); byte batchSize = 64; for (int vidx = 0; vidx < this.rawBufferIndex; vidx += batchSize) { @@ -142,14 +137,7 @@ public TesselatorVertexState getVertexState(float x, float y, float z) { } System.arraycopy(tmpCopyBuffer, 0, this.rawBuffer, 0, tmpCopyBuffer.length); - return new TesselatorVertexState( - tmpCopyBuffer, - this.rawBufferIndex, - this.vertexCount, - this.hasTexture, - this.hasBrightness, - this.hasNormals, - this.hasColor); + return new TesselatorVertexState(tmpCopyBuffer, this.rawBufferIndex, this.vertexCount, this.hasTexture, this.hasBrightness, this.hasNormals, this.hasColor); } @Inject(method = "setNormal(FFF)V", at = @At("HEAD")) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureAtlasSprite.java similarity index 89% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureAtlasSprite.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureAtlasSprite.java index 23f06852c..213edf9cb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureAtlasSprite.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureAtlasSprite.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -10,6 +10,7 @@ @Mixin(TextureAtlasSprite.class) public class MixinTextureAtlasSprite { + // TODO: Mipmap/Rendering/Animation @Redirect( at = @At( diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureClock.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureClock.java similarity index 88% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureClock.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureClock.java index cc91692c2..8e59571f3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureClock.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureClock.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.texture.TextureClock; @@ -10,7 +10,7 @@ @Mixin(value = TextureClock.class) public class MixinTextureClock { - + // TODO: Mipmap/Rendering/Animation @Redirect( method = "updateAnimation()V", at = @At( diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureCompass.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureCompass.java similarity index 88% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureCompass.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureCompass.java index b4a811e07..ac156f51a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureCompass.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureCompass.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.texture.TextureCompass; @@ -10,6 +10,7 @@ @Mixin(value = TextureCompass.class) public class MixinTextureCompass { + // TODO: Mipmap/Rendering/Animation @Redirect( method = "updateCompass(Lnet/minecraft/world/World;DDDZZ)V", diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureManager.java similarity index 85% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureManager.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureManager.java index 1ba1ff0e8..1d65e8a4c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureManager.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.texture.ITextureObject; import net.minecraft.client.renderer.texture.TextureManager; @@ -11,11 +11,9 @@ @Mixin(TextureManager.class) public class MixinTextureManager { - + // TODO: PBR @Redirect( - at = @At( - target = "Lnet/minecraft/client/renderer/texture/ITextureObject;getGlTextureId()I", - value = "INVOKE"), + at = @At(target = "Lnet/minecraft/client/renderer/texture/ITextureObject;getGlTextureId()I", value = "INVOKE"), method = "bindTexture(Lnet/minecraft/util/ResourceLocation;)V") private int angelica$bindTexture(ITextureObject object) { ShadersTex.bindTexture(object); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureMap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureMap.java similarity index 86% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureMap.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureMap.java index c4b4457ca..5cc88d53d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinTextureMap.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureMap.java @@ -1,14 +1,12 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; - -import java.io.IOException; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; +import com.gtnewhorizons.angelica.client.ShadersTex; import net.minecraft.client.renderer.texture.Stitcher; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResourceManager; import net.minecraft.util.ResourceLocation; - import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -18,10 +16,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import com.gtnewhorizons.angelica.client.ShadersTex; +import java.io.IOException; @Mixin(TextureMap.class) public class MixinTextureMap extends MixinAbstractTexture { + // TODO: Textures/Stitcher public int angelica$atlasWidth; public int angelica$atlasHeight; @@ -36,8 +35,7 @@ public class MixinTextureMap extends MixinAbstractTexture { target = "Lnet/minecraft/client/resources/IResourceManager;getResource(Lnet/minecraft/util/ResourceLocation;)Lnet/minecraft/client/resources/IResource;", value = "INVOKE"), method = "loadTextureAtlas(Lnet/minecraft/client/resources/IResourceManager;)V") - private IResource angelica$loadResource(IResourceManager p_110571_1_, ResourceLocation resourcelocation1) - throws IOException { + private IResource angelica$loadResource(IResourceManager p_110571_1_, ResourceLocation resourcelocation1) throws IOException { return ShadersTex.loadResource(p_110571_1_, resourcelocation1); } @@ -57,14 +55,7 @@ public class MixinTextureMap extends MixinAbstractTexture { method = "loadTextureAtlas(Lnet/minecraft/client/resources/IResourceManager;)V") private void angelica$allocateTextureMap(int p_147946_0_, int p_147946_1_, int p_147946_2_, int p_147946_3_, float p_147946_4_) { - ShadersTex.allocateTextureMap( - p_147946_0_, - p_147946_1_, - p_147946_2_, - p_147946_3_, - p_147946_4_, - this.stitcher, - (TextureMap) (Object) this); + ShadersTex.allocateTextureMap(p_147946_0_, p_147946_1_, p_147946_2_, p_147946_3_, p_147946_4_, this.stitcher, (TextureMap) (Object) this); } @Redirect( @@ -89,14 +80,7 @@ public class MixinTextureMap extends MixinAbstractTexture { method = "loadTextureAtlas(Lnet/minecraft/client/resources/IResourceManager;)V") private void angelica$uploadTexSubForLoadAtlas(int[][] p_147955_0_, int p_147955_1_, int p_147955_2_, int p_147955_3_, int p_147955_4_, boolean p_147955_5_, boolean p_147955_6_) { - ShadersTex.uploadTexSubForLoadAtlas( - p_147955_0_, - p_147955_1_, - p_147955_2_, - p_147955_3_, - p_147955_4_, - p_147955_5_, - p_147955_6_); + ShadersTex.uploadTexSubForLoadAtlas(p_147955_0_, p_147955_1_, p_147955_2_, p_147955_3_, p_147955_4_, p_147955_5_, p_147955_6_); } // updateAnimations diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinThreadDownloadImageData.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinThreadDownloadImageData.java similarity index 88% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinThreadDownloadImageData.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinThreadDownloadImageData.java index 812194c1a..16d2f75c8 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/renderer/MixinThreadDownloadImageData.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinThreadDownloadImageData.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.renderer; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import net.minecraft.client.renderer.ThreadDownloadImageData; @@ -10,7 +10,7 @@ @Mixin(ThreadDownloadImageData.class) public abstract class MixinThreadDownloadImageData extends MixinAbstractTexture { - + // TODO: PBR @Shadow private boolean textureUploaded; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/settings/MixinGuiVideoSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/settings/MixinGuiVideoSettings.java similarity index 95% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/settings/MixinGuiVideoSettings.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/settings/MixinGuiVideoSettings.java index 007ce18c4..029aae52e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/settings/MixinGuiVideoSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/settings/MixinGuiVideoSettings.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.settings; +package com.gtnewhorizons.angelica.mixins.early.shadersmod.settings; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinModelRotationRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinModelRotationRenderer.java index 77053b032..ed2fe7aa0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinModelRotationRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinModelRotationRenderer.java @@ -5,7 +5,7 @@ import org.spongepowered.asm.mixin.Mixin; -import com.gtnewhorizons.angelica.mixins.early.renderer.MixinModelRenderer; +import com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer.MixinModelRenderer; @Mixin(ModelRotationRenderer.class) public class MixinModelRotationRenderer extends MixinModelRenderer { diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index 72679a140..aba5a1529 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -27,14 +27,16 @@ public class GLStateManagerTransformer implements IClassTransformer { private static final String GL11 = "org/lwjgl/opengl/GL11"; private static final String GL13 = "org/lwjgl/opengl/GL13"; private static final String GL14 = "org/lwjgl/opengl/GL14"; - private static final String ExtBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate"; + private static final String EXTBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate"; + private static final String ARBMultiTexture = "org/lwjgl/opengl/ARBMultitexture"; public static final Map> EnabledRedirects = ImmutableMap.of( GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", "glColorMask", "glAlphaFunc", "glDrawArrays") ,GL13, Sets.newHashSet("glActiveTexture") ,GL14, Sets.newHashSet("glBlendFuncSeparate") - ,ExtBlendFunc, Sets.newHashSet("glBlendFuncSeparate") + ,EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") + ,ARBMultiTexture, Sets.newHashSet("glActiveTextureARB") ); diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 022d0054f..0bd9b4605 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -390,7 +390,6 @@ private static void setShadersDisabled() { } private static void setDebug(boolean enable) { - if (true) return; int success; if (enable) { success = GLDebug.setupDebugMessageCallback(); diff --git a/src/main/java/net/coderbot/iris/gl/GLDebug.java b/src/main/java/net/coderbot/iris/gl/GLDebug.java index fca204d43..fbb51f9ee 100644 --- a/src/main/java/net/coderbot/iris/gl/GLDebug.java +++ b/src/main/java/net/coderbot/iris/gl/GLDebug.java @@ -22,8 +22,15 @@ import static org.lwjgl.opengl.ARBDebugOutput.glDebugMessageCallbackARB; public final class GLDebug { + /** + * Sets up debug callbacks + * @return 0 for failure, 1 for success, 2 for restart required. + */ + public static int setupDebugMessageCallback() { + return setupDebugMessageCallback(System.err); + } - private static void trace(Consumer output) { + private static void trace(Consumer output) { /* * We can not just use a fixed stacktrace element offset, because some methods * are intercepted and some are not. So, check the package name. @@ -70,47 +77,68 @@ public void accept(String str) { * Sets up debug callbacks * @return 0 for failure, 1 for success, 2 for restart required. */ - public static int setupDebugMessageCallback() { + public static int setupDebugMessageCallback(PrintStream stream) { if (Iris.capabilities.OpenGL43 || Iris.capabilities.GL_KHR_debug) { - Iris.logger.info("[GL] Using KHR_debug for error logging."); - GL11.glEnable(GL43.GL_DEBUG_OUTPUT); - GL11.glEnable(GL43.GL_DEBUG_OUTPUT_SYNCHRONOUS); - - KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); - KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); - KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_LOW, null, false); - KHRDebug.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, null, false); - KHRDebug.glDebugMessageCallback(new KHRDebugCallback()); - - if (Iris.capabilities.OpenGL30 && (GL11.glGetInteger(GL30.GL_CONTEXT_FLAGS) & GL43.GL_CONTEXT_FLAG_DEBUG_BIT) == 0) { - Iris.logger.warn("[GL] Warning: A non-debug context may not produce any debug output."); - GL11.glDisable(GL43.GL_DEBUG_OUTPUT); - return 2; - } - return 1; - } else if (Iris.capabilities.GL_ARB_debug_output) { - Iris.logger.info("[GL] Using ARB_debug_output for error logging."); - - ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); - ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); - ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_LOW, null, false); - ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, null, false); - glDebugMessageCallbackARB(new ARBDebugOutputCallback()); - return 1; - } else if (Iris.capabilities.GL_AMD_debug_output) { - Iris.logger.info("[GL] Using AMD_debug_output for error logging."); - - AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); - AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); - AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_LOW, null, false); - AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, null, false); - AMDDebugOutput.glDebugMessageCallbackAMD(new AMDDebugOutputCallback()); - return 1; - } else { - Iris.logger.info("[GL] No debug output implementation is available, cannot return debug info."); - return 0; - } - } + Iris.logger.info("[GL] Using OpenGL 4.3 for error logging."); + KHRDebugCallback proc = new KHRDebugCallback((source, type, id, severity, message) -> { + stream.println("[LWJGL] OpenGL debug message"); + printDetail(stream, "ID", String.format("0x%X", id)); + printDetail(stream, "Source", getDebugSource(source)); + printDetail(stream, "Type", getDebugType(type)); + printDetail(stream, "Severity", getDebugSeverity(severity)); + printDetail(stream, "Message", message); + printTrace(stream); + }); + GL43.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); + GL43.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); + GL43.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_LOW, null, false); + GL43.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, null, false); + GL43.glDebugMessageCallback(proc); + + if ((GL11.glGetInteger(GL30.GL_CONTEXT_FLAGS) & GL43.GL_CONTEXT_FLAG_DEBUG_BIT) == 0) { + Iris.logger.warn("[GL] Warning: A non-debug context may not produce any debug output."); + GL11.glEnable(GL43.GL_DEBUG_OUTPUT); + return 2; + } + return 1; + } else if (Iris.capabilities.GL_ARB_debug_output) { + Iris.logger.info("[GL] Using ARB_debug_output for error logging."); + ARBDebugOutputCallback proc = new ARBDebugOutputCallback((source, type, id, severity, message) -> { + stream.println("[LWJGL] ARB_debug_output message"); + printDetail(stream, "ID", String.format("0x%X", id)); + printDetail(stream, "Source", getSourceARB(source)); + printDetail(stream, "Type", getTypeARB(type)); + printDetail(stream, "Severity", getSeverityARB(severity)); + printDetail(stream, "Message", message); + printTrace(stream); + }); + ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); + ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); + ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_LOW, null, false); + ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, null, false); + ARBDebugOutput.glDebugMessageCallbackARB(proc); + return 1; + } else if (Iris.capabilities.GL_AMD_debug_output) { + Iris.logger.info("[GL] Using AMD_debug_output for error logging."); + AMDDebugOutputCallback proc = new AMDDebugOutputCallback((id, category, severity, message) -> { + stream.println("[LWJGL] AMD_debug_output message"); + printDetail(stream, "ID", String.format("0x%X", id)); + printDetail(stream, "Category", getCategoryAMD(category)); + printDetail(stream, "Severity", getSeverityAMD(severity)); + printDetail(stream, "Message", message); + printTrace(stream); + }); + AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); + AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); + AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_LOW, null, false); + AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, null, false); + AMDDebugOutput.glDebugMessageCallbackAMD(proc); + return 1; + } else { + Iris.logger.info("[GL] No debug output implementation is available, cannot return debug info."); + return 0; + } + } public static int disableDebugMessages() { if (Iris.capabilities.OpenGL43) { @@ -181,6 +209,38 @@ private static String getDebugSeverity(int severity) { }; } + private static String getSourceARB(int source) { + return switch (source) { + case ARBDebugOutput.GL_DEBUG_SOURCE_API_ARB -> "API"; + case ARBDebugOutput.GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB -> "WINDOW SYSTEM"; + case ARBDebugOutput.GL_DEBUG_SOURCE_SHADER_COMPILER_ARB -> "SHADER COMPILER"; + case ARBDebugOutput.GL_DEBUG_SOURCE_THIRD_PARTY_ARB -> "THIRD PARTY"; + case ARBDebugOutput.GL_DEBUG_SOURCE_APPLICATION_ARB -> "APPLICATION"; + case ARBDebugOutput.GL_DEBUG_SOURCE_OTHER_ARB -> "OTHER"; + default -> String.format("Unknown [0x%X]", source); + }; + } + + private static String getTypeARB(int type) { + return switch (type) { + case ARBDebugOutput.GL_DEBUG_TYPE_ERROR_ARB -> "ERROR"; + case ARBDebugOutput.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB -> "DEPRECATED BEHAVIOR"; + case ARBDebugOutput.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB -> "UNDEFINED BEHAVIOR"; + case ARBDebugOutput.GL_DEBUG_TYPE_PORTABILITY_ARB -> "PORTABILITY"; + case ARBDebugOutput.GL_DEBUG_TYPE_PERFORMANCE_ARB -> "PERFORMANCE"; + case ARBDebugOutput.GL_DEBUG_TYPE_OTHER_ARB -> "OTHER"; + default -> String.format("Unknown [0x%X]", type); + }; + } + + private static String getSeverityARB(int severity) { + return switch (severity) { + case ARBDebugOutput.GL_DEBUG_SEVERITY_HIGH_ARB -> "HIGH"; + case ARBDebugOutput.GL_DEBUG_SEVERITY_MEDIUM_ARB -> "MEDIUM"; + case ARBDebugOutput.GL_DEBUG_SEVERITY_LOW_ARB -> "LOW"; + default -> String.format("Unknown [0x%X]", severity); + }; + } private static String getCategoryAMD(int category) { return switch (category) { diff --git a/src/main/java/net/coderbot/iris/pipeline/ClearPassCreator.java b/src/main/java/net/coderbot/iris/pipeline/ClearPassCreator.java index ef97bf4ed..a8c175703 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ClearPassCreator.java +++ b/src/main/java/net/coderbot/iris/pipeline/ClearPassCreator.java @@ -70,8 +70,7 @@ public static ImmutableList createClearPasses(RenderTargets renderTar // No need to clear the depth buffer, since we're using Minecraft's depth buffer. clearPasses.add(new ClearPass(clearInfo.getColor(), clearInfo::getWidth, clearInfo::getHeight, renderTargets.createClearFramebuffer(true, clearBuffers), GL11.GL_COLOR_BUFFER_BIT)); - - clearPasses.add(new ClearPass(clearInfo.getColor(), clearInfo::getWidth, clearInfo::getHeight, + clearPasses.add(new ClearPass(clearInfo.getColor(), clearInfo::getWidth, clearInfo::getHeight, renderTargets.createClearFramebuffer(false, clearBuffers), GL11.GL_COLOR_BUFFER_BIT)); } }); diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 1cc4a9e47..96405720b 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -325,7 +325,6 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { } }); }); - if (shadowRenderTargets == null && shadowDirectives.isShadowEnabled() == OptionalBoolean.TRUE) { shadowRenderTargets = new ShadowRenderTargets(shadowMapResolution, shadowDirectives); } @@ -398,8 +397,7 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { return builder.build(); }; - - IntFunction createShadowTerrainImages = (programId) -> { + IntFunction createShadowTerrainImages = (programId) -> { ProgramImages.Builder builder = ProgramImages.builder(programId); IrisImages.addRenderTargetImages(builder, () -> flippedAfterPrepare, renderTargets); @@ -410,8 +408,7 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { return builder.build(); }; - - this.sodiumTerrainPipeline = new SodiumTerrainPipeline(this, programs, createTerrainSamplers, + this.sodiumTerrainPipeline = new SodiumTerrainPipeline(this, programs, createTerrainSamplers, shadowRenderer == null ? null : createShadowTerrainSamplers, createTerrainImages, shadowRenderer == null ? null : createShadowTerrainImages); } @@ -569,13 +566,9 @@ public void beginPass(Pass pass) { } private Pass createDefaultPass() { - GlFramebuffer framebufferBeforeTranslucents; - GlFramebuffer framebufferAfterTranslucents; + final GlFramebuffer framebufferBeforeTranslucents = renderTargets.createGbufferFramebuffer(flippedAfterPrepare, new int[] {0}); + final GlFramebuffer framebufferAfterTranslucents = renderTargets.createGbufferFramebuffer(flippedAfterTranslucent, new int[] {0}); - framebufferBeforeTranslucents = - renderTargets.createGbufferFramebuffer(flippedAfterPrepare, new int[] {0}); - framebufferAfterTranslucents = - renderTargets.createGbufferFramebuffer(flippedAfterTranslucent, new int[] {0}); return new Pass(null, framebufferBeforeTranslucents, framebufferAfterTranslucents, null, null, Collections.emptyList(), false); @@ -650,14 +643,11 @@ private Pass createPassInner(ProgramBuilder builder, IdMap map, ProgramDirective if (shadow) { // Always add both draw buffers on the shadow pass. - framebufferBeforeTranslucents = - shadowTargetsSupplier.get().createShadowFramebuffer(shadowRenderTargets.snapshot(), new int[] { 0, 1 }); + framebufferBeforeTranslucents = shadowTargetsSupplier.get().createShadowFramebuffer(shadowRenderTargets.snapshot(), new int[] { 0, 1 }); framebufferAfterTranslucents = framebufferBeforeTranslucents; } else { - framebufferBeforeTranslucents = - renderTargets.createGbufferFramebuffer(flippedAfterPrepare, programDirectives.getDrawBuffers()); - framebufferAfterTranslucents = - renderTargets.createGbufferFramebuffer(flippedAfterTranslucent, programDirectives.getDrawBuffers()); + framebufferBeforeTranslucents = renderTargets.createGbufferFramebuffer(flippedAfterPrepare, programDirectives.getDrawBuffers()); + framebufferAfterTranslucents = renderTargets.createGbufferFramebuffer(flippedAfterTranslucent, programDirectives.getDrawBuffers()); } builder.bindAttributeLocation(11, "mc_Entity"); diff --git a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java index 02eccbc32..bdeba1eb7 100644 --- a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java @@ -165,8 +165,8 @@ public void recalculateSizes() { passHeight = target.getHeight(); } renderTargets.destroyFramebuffer(pass.framebuffer); - pass.framebuffer = renderTargets.createColorFramebuffer(pass.stageReadsFromAlt, pass.drawBuffers); - pass.viewWidth = passWidth; + pass.framebuffer = renderTargets.createColorFramebuffer(pass.stageReadsFromAlt, pass.drawBuffers); + pass.viewWidth = passWidth; pass.viewHeight = passHeight; } } diff --git a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java index c25697f63..3e65d17db 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java @@ -5,6 +5,7 @@ import com.gtnewhorizons.angelica.glsm.GLStateManager; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import net.coderbot.iris.Iris; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.framebuffer.GlFramebuffer; import net.coderbot.iris.gl.program.ComputeProgram; @@ -172,8 +173,8 @@ public void renderFinalPass() { if (((IRenderTargetExt)mc).iris$getColorBufferVersion() != lastColorTextureVersion) { lastColorTextureVersion = ((IRenderTargetExt)mc).iris$getColorBufferVersion(); -// colorHolder.addColorAttachment(0, colorTextureId); - throw new RuntimeException("Color buffer changed during frame!"); + colorHolder.addColorAttachment(0, colorTextureId); + Iris.logger.info("Color buffer changed during frame!"); } if (this.finalPass != null) { diff --git a/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java b/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java index 9e0c8d3ac..da3eac319 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java @@ -22,6 +22,8 @@ public ColorTexture(int width, int height) { TextureUploadHelper.resetTextureUploadState(); IrisRenderSystem.texImage2D(texture, GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (ByteBuffer) null); + + // TODO: Message: GL_INVALID_OPERATION error generated. Cannot modify the default framebuffer object. EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, GL11.GL_TEXTURE_2D, texture, 0); } diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java index 7c1b76b3a..89843898e 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java @@ -46,7 +46,7 @@ public class RenderTargets { private int cachedDepthBufferVersion; public RenderTargets(int width, int height, int depthBufferVersion, Map renderTargets, PackDirectives packDirectives) { - targets = new RenderTarget[renderTargets.size()]; + targets = new RenderTarget[renderTargets.size()]; renderTargets.forEach((index, settings) -> { // TODO: Handle mipmapping? @@ -59,8 +59,9 @@ public RenderTargets(int width, int height, int depthBufferVersion, Map stageWritesT } ImmutableSet stageWritesToMain = invert(stageWritesToAlt, drawBuffers); - - GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); - -// framebuffer.addDepthAttachment(currentDepthTexture); + GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); + framebuffer.addDepthAttachment(currentDepthTexture); return framebuffer; } @@ -259,9 +258,8 @@ private GlFramebuffer createFullFramebuffer(boolean clearsAlt, int[] drawBuffers } public GlFramebuffer createColorFramebufferWithDepth(ImmutableSet stageWritesToMain, int[] drawBuffers) { - GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); - -// framebuffer.addDepthAttachment(currentDepthTexture); + GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); + framebuffer.addDepthAttachment(currentDepthTexture); return framebuffer; } @@ -271,8 +269,8 @@ public GlFramebuffer createColorFramebuffer(ImmutableSet stageWritesToM throw new IllegalArgumentException("Framebuffer must have at least one color buffer"); } - GlFramebuffer framebuffer = new GlFramebuffer(); - ownedFramebuffers.add(framebuffer); + GlFramebuffer framebuffer = new GlFramebuffer(); + ownedFramebuffers.add(framebuffer); int[] actualDrawBuffers = new int[drawBuffers.length]; @@ -290,10 +288,10 @@ public GlFramebuffer createColorFramebuffer(ImmutableSet stageWritesToM int textureId = stageWritesToMain.contains(drawBuffers[i]) ? target.getMainTexture() : target.getAltTexture(); framebuffer.addColorAttachment(i, textureId); - } + } framebuffer.drawBuffers(actualDrawBuffers); - framebuffer.readBuffer(0); + framebuffer.readBuffer(0); if (!framebuffer.isComplete()) { throw new IllegalStateException("Unexpected error while creating framebuffer"); diff --git a/src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java b/src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java index 5f0048d29..767b18cd1 100644 --- a/src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java +++ b/src/main/java/net/coderbot/iris/shadows/ShadowRenderTargets.java @@ -177,10 +177,8 @@ public GlFramebuffer createShadowFramebuffer(ImmutableSet stageWritesTo } ImmutableSet stageWritesToMain = invert(stageWritesToAlt, drawBuffers); - - GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); - - framebuffer.addDepthAttachment(mainDepth.getTextureId()); + GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); + framebuffer.addDepthAttachment(mainDepth.getTextureId()); return framebuffer; } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java index a2613cd33..fed180dcc 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/SimplePBRLoader.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.pbr.loader; -import com.gtnewhorizons.angelica.mixins.early.accessors.SimpleTextureAccessor; +import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.SimpleTextureAccessor; import net.coderbot.iris.texture.pbr.PBRType; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.SimpleTexture; diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index c816ba014..d2169e51f 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -3,7 +3,7 @@ import com.gtnewhorizons.angelica.client.Shaders; import com.gtnewhorizons.angelica.glsm.states.BlendState; import com.gtnewhorizons.angelica.glsm.GLStateManager; -import com.gtnewhorizons.angelica.mixins.early.accessors.EntityRendererAccessor; +import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.EntityRendererAccessor; import net.coderbot.iris.gl.state.StateUpdateNotifiers; import net.coderbot.iris.gl.uniform.DynamicUniformHolder; import net.coderbot.iris.gl.uniform.UniformHolder; From d30a90f40ec793f06e328a15e63c7c9a2c42c99b Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 2 Nov 2023 20:17:53 -0700 Subject: [PATCH 022/301] Progress * Add Common & ClientProxy * Less spammy GLStateManagerTransformer * Get the color texture ID from the main framebuffer --- .../gtnewhorizons/angelica/AngelicaMod.java | 19 ++-- .../gtnewhorizons/angelica/mixins/Mixins.java | 2 +- ...inMinecraft.java => MixinFramebuffer.java} | 9 +- .../angelica/proxy/ClientProxy.java | 19 ++++ .../angelica/proxy/CommonProxy.java | 10 ++ .../transform/GLStateManagerTransformer.java | 7 +- .../DeferredWorldRenderingPipeline.java | 16 ++-- .../iris/postprocess/FinalPassRenderer.java | 47 +++++---- .../iris/rendertarget/ColorTexture.java | 1 - .../iris/rendertarget/RenderTargets.java | 95 +++++++++++-------- 10 files changed, 133 insertions(+), 92 deletions(-) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/{MixinMinecraft.java => MixinFramebuffer.java} (71%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index dad800ef2..e7f4def6f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -1,12 +1,10 @@ package com.gtnewhorizons.angelica; -import com.gtnewhorizons.angelica.client.gui.AngelicaVideoSettings; +import com.gtnewhorizons.angelica.proxy.CommonProxy; import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.SidedProxy; import cpw.mods.fml.common.event.FMLPreInitializationEvent; -import cpw.mods.fml.relauncher.Side; -import jss.notfine.gui.GuiCustomMenu; -import jss.notfine.gui.ISettingsEnum; -import jss.notfine.gui.MenuButtonLists; + @Mod( modid = "angelica", @@ -15,15 +13,12 @@ acceptedMinecraftVersions = "[1.7.10]", acceptableRemoteVersions = "*") public class AngelicaMod { + @SidedProxy(clientSide = "com.gtnewhorizons.angelica.proxy.ClientProxy", serverSide = "com.gtnewhorizons.angelica.proxy.CommonProxy") + public static CommonProxy proxy; + @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { - if (event.getSide() == Side.CLIENT) { - MenuButtonLists.addAdditionalEntry(MenuButtonLists.VIDEO, AngelicaVideoSettings.SHADERS); - GuiCustomMenu.addButtonHandler(AngelicaVideoSettings.class, (xPosition, yPosition, setting) -> { - ISettingsEnum settingsEnum = (ISettingsEnum) setting; - return settingsEnum.createButton(xPosition, yPosition, setting); - }); - } + proxy.preInit(event); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index bc3c9f61e..944a728f5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -12,7 +12,7 @@ public enum Mixins { IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( - "shaders.startup.MixinMinecraft", + "shaders.startup.MixinFramebuffer", "shaders.startup.MixinGameSettings", "shaders.startup.MixinGuiMainMenu", "shaders.startup.MixinInitRenderer") diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinFramebuffer.java similarity index 71% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinMinecraft.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinFramebuffer.java index 72fb46d0d..4a15f7538 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinMinecraft.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinFramebuffer.java @@ -1,21 +1,20 @@ package com.gtnewhorizons.angelica.mixins.early.shaders.startup; import net.coderbot.iris.rendertarget.IRenderTargetExt; -import net.minecraft.client.Minecraft; -import net.minecraft.profiler.IPlayerUsage; +import net.minecraft.client.shader.Framebuffer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(Minecraft.class) -public abstract class MixinMinecraft implements IPlayerUsage, IRenderTargetExt { +@Mixin(Framebuffer.class) +public abstract class MixinFramebuffer implements IRenderTargetExt { private int iris$depthBufferVersion; private int iris$colorBufferVersion; - @Inject(method = "updateFramebufferSize()V", at = @At("HEAD")) + @Inject(method = "deleteFramebuffer()V", at = @At(value="INVOKE", target="Lnet/minecraft/client/shader/Framebuffer;unbindFramebuffer()V", shift = At.Shift.AFTER)) private void iris$onDestroyBuffers(CallbackInfo ci) { iris$depthBufferVersion++; iris$colorBufferVersion++; diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java new file mode 100644 index 000000000..273a43a6a --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -0,0 +1,19 @@ +package com.gtnewhorizons.angelica.proxy; + +import com.gtnewhorizons.angelica.client.gui.AngelicaVideoSettings; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import jss.notfine.gui.GuiCustomMenu; +import jss.notfine.gui.ISettingsEnum; +import jss.notfine.gui.MenuButtonLists; + +public class ClientProxy extends CommonProxy { + + @Override + public void preInit(FMLPreInitializationEvent event) { + MenuButtonLists.addAdditionalEntry(MenuButtonLists.VIDEO, AngelicaVideoSettings.SHADERS); + GuiCustomMenu.addButtonHandler(AngelicaVideoSettings.class, (xPosition, yPosition, setting) -> { + ISettingsEnum settingsEnum = (ISettingsEnum) setting; + return settingsEnum.createButton(xPosition, yPosition, setting); + }); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java new file mode 100644 index 000000000..02ae873da --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java @@ -0,0 +1,10 @@ +package com.gtnewhorizons.angelica.proxy; + +import cpw.mods.fml.common.event.FMLPreInitializationEvent; + +public class CommonProxy { + + public void preInit(FMLPreInitializationEvent event) { + + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index aba5a1529..c6b8d0403 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -3,6 +3,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import net.coderbot.iris.IrisLogging; import net.minecraft.launchwrapper.IClassTransformer; import org.spongepowered.asm.lib.ClassReader; import org.spongepowered.asm.lib.ClassVisitor; @@ -76,8 +77,10 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { final Set redirects = EnabledRedirects.get(owner); if (redirects != null && redirects.contains(name)) { - final String shortOwner = owner.substring(owner.lastIndexOf("/")+1); - AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", className, shortOwner, name, desc, name, desc); + if(IrisLogging.ENABLE_SPAM) { + final String shortOwner = owner.substring(owner.lastIndexOf("/") + 1); + AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", className, shortOwner, name, desc, name, desc); + } owner = GLStateTracker; remaps++; } diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 96405720b..cd3b4a13d 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -23,6 +23,7 @@ import net.coderbot.iris.gl.program.ProgramBuilder; import net.coderbot.iris.gl.program.ProgramImages; import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.texture.DepthBufferFormat; import net.coderbot.iris.layer.GbufferPrograms; import net.coderbot.iris.pipeline.transform.PatchShaderType; import net.coderbot.iris.pipeline.transform.TransformPatcher; @@ -59,6 +60,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.shader.Framebuffer; import org.apache.commons.lang3.tuple.Pair; import org.jetbrains.annotations.Nullable; import org.joml.Vector3d; @@ -167,9 +169,11 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { this.packDirectives = programs.getPackDirectives(); - Minecraft mc = Minecraft.getMinecraft(); + final Framebuffer main = Minecraft.getMinecraft().getFramebuffer(); - this.renderTargets = new RenderTargets(mc.displayWidth, mc.displayHeight, ((IRenderTargetExt)mc).iris$getDepthBufferVersion(), + + this.renderTargets = new RenderTargets(main.framebufferWidth, main.framebufferHeight, main.depthBuffer, + ((IRenderTargetExt)main).iris$getDepthBufferVersion(), programs.getPackDirectives().getRenderTargetDirectives().getRenderTargetSettings(), programs.getPackDirectives()); this.sunPathRotation = programs.getPackDirectives().getSunPathRotation(); @@ -245,7 +249,7 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { this.finalPassRenderer = new FinalPassRenderer(programs, renderTargets, customTextureManager.getNoiseTexture(), updateNotifier, flipper.snapshot(), centerDepthSampler, shadowTargetsSupplier, customTextureManager.getCustomTextureIdMap(TextureStage.COMPOSITE_AND_FINAL), - this.compositeRenderer.getFlippedAtLeastOnceFinal(), getRenderTargets().getColorTexture().getTextureId()); + this.compositeRenderer.getFlippedAtLeastOnceFinal()); // [(textured=false,lightmap=false), (textured=true,lightmap=false), (textured=true,lightmap=true)] ProgramId[] ids = new ProgramId[] { @@ -884,10 +888,10 @@ private void prepareRenderTargets() { } } - final Minecraft mc = Minecraft.getMinecraft(); + final Framebuffer main = Minecraft.getMinecraft().getFramebuffer(); - final boolean changed = renderTargets.resizeIfNeeded(((IRenderTargetExt)mc).iris$getDepthBufferVersion(), mc.displayWidth, - mc.displayHeight, packDirectives); + final boolean changed = renderTargets.resizeIfNeeded(((IRenderTargetExt)main).iris$getDepthBufferVersion(), main.depthBuffer, main.framebufferWidth, + main.framebufferHeight, DepthBufferFormat.DEPTH, packDirectives); if (changed) { prepareRenderer.recalculateSizes(); diff --git a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java index 3e65d17db..4b431bc8b 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java @@ -5,7 +5,6 @@ import com.gtnewhorizons.angelica.glsm.GLStateManager; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import net.coderbot.iris.Iris; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.framebuffer.GlFramebuffer; import net.coderbot.iris.gl.program.ComputeProgram; @@ -32,6 +31,7 @@ import net.coderbot.iris.uniforms.FrameUpdateNotifier; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.shader.Framebuffer; import org.jetbrains.annotations.Nullable; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; @@ -51,27 +51,26 @@ public class FinalPassRenderer { private final ImmutableList swapPasses; private final GlFramebuffer baseline; private final GlFramebuffer colorHolder; - private int colorTextureId; + private int lastColorTextureId; private int lastColorTextureVersion; private final IntSupplier noiseTexture; private final FrameUpdateNotifier updateNotifier; private final CenterDepthSampler centerDepthSampler; private final Object2ObjectMap customTextureIds; - // TODO: The length of this argument list is getting a bit ridiculous + // TODO: The length of this argument list is getting a bit ridiculous public FinalPassRenderer(ProgramSet pack, RenderTargets renderTargets, IntSupplier noiseTexture, FrameUpdateNotifier updateNotifier, ImmutableSet flippedBuffers, CenterDepthSampler centerDepthSampler, Supplier shadowTargetsSupplier, Object2ObjectMap customTextureIds, - ImmutableSet flippedAtLeastOnce, int colorTextureId) { + ImmutableSet flippedAtLeastOnce) { this.updateNotifier = updateNotifier; this.centerDepthSampler = centerDepthSampler; this.customTextureIds = customTextureIds; final PackRenderTargetDirectives renderTargetDirectives = pack.getPackDirectives().getRenderTargetDirectives(); - final Map renderTargetSettings = - renderTargetDirectives.getRenderTargetSettings(); + final Map renderTargetSettings = renderTargetDirectives.getRenderTargetSettings(); this.noiseTexture = noiseTexture; this.renderTargets = renderTargets; @@ -93,18 +92,19 @@ public FinalPassRenderer(ProgramSet pack, RenderTargets renderTargets, IntSuppli // up with whatever was written last (since we're reading from these framebuffers) instead of trying to create // a framebuffer with color attachments different from what was written last (as we do with normal composite // passes that write to framebuffers). + final Framebuffer main = Minecraft.getMinecraft().getFramebuffer(); this.baseline = renderTargets.createGbufferFramebuffer(flippedBuffers, new int[] {0}); this.colorHolder = new GlFramebuffer(); - this.colorTextureId = colorTextureId; - this.lastColorTextureVersion = ((IRenderTargetExt)Minecraft.getMinecraft()).iris$getColorBufferVersion(); - this.colorHolder.addColorAttachment(0, this.colorTextureId); + this.lastColorTextureId = main.framebufferTexture; + this.lastColorTextureVersion = ((IRenderTargetExt)main).iris$getColorBufferVersion(); + this.colorHolder.addColorAttachment(0, lastColorTextureId); // TODO: We don't actually fully swap the content, we merely copy it from alt to main // This works for the most part, but it's not perfect. A better approach would be creating secondary // framebuffers for every other frame, but that would be a lot more complex... ImmutableList.Builder swapPasses = ImmutableList.builder(); - flippedBuffers.forEach((i) -> { + flippedBuffers.forEach(i -> { int target = i; if (buffersToBeCleared.contains(target)) { @@ -149,13 +149,13 @@ private static final class SwapPass { } public void renderFinalPass() { - GL11.glDisable(GL11.GL_BLEND); - GL11.glDisable(GL11.GL_ALPHA_TEST); - GL11.glDepthMask(false); + GLStateManager.disableBlend(); + GLStateManager.disableAlphaTest(); + GLStateManager.glDepthMask(false); - final Minecraft mc = Minecraft.getMinecraft(); - final int baseWidth = mc.displayWidth; - final int baseHeight = mc.displayHeight; + final Framebuffer main = Minecraft.getMinecraft().getFramebuffer(); + final int baseWidth = main.framebufferWidth; + final int baseHeight = main.framebufferHeight; // Note that since DeferredWorldRenderingPipeline uses the depth texture of the main Minecraft framebuffer, // we'll be writing to that depth buffer directly automatically and won't need to futz around with copying @@ -170,11 +170,10 @@ public void renderFinalPass() { // // This is not a concern for depthtex1 / depthtex2 since the copy call extracts the depth values, and the // shader pack only ever uses them to read the depth values. - - if (((IRenderTargetExt)mc).iris$getColorBufferVersion() != lastColorTextureVersion) { - lastColorTextureVersion = ((IRenderTargetExt)mc).iris$getColorBufferVersion(); - colorHolder.addColorAttachment(0, colorTextureId); - Iris.logger.info("Color buffer changed during frame!"); + if (((IRenderTargetExt)main).iris$getColorBufferVersion() != lastColorTextureVersion) { + lastColorTextureVersion = ((IRenderTargetExt)main).iris$getColorBufferVersion(); + this.lastColorTextureId = main.framebufferTexture; + colorHolder.addColorAttachment(0, lastColorTextureId); } if (this.finalPass != null) { @@ -217,8 +216,7 @@ public void renderFinalPass() { // https://stackoverflow.com/a/23994979/18166885 this.baseline.bindAsReadBuffer(); - // TODO: Iris - IrisRenderSystem.copyTexSubImage2D(0/*main.getColorTextureId()*/, GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, baseWidth, baseHeight); + IrisRenderSystem.copyTexSubImage2D(main.framebufferTexture, GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, baseWidth, baseHeight); } GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); @@ -245,8 +243,7 @@ public void renderFinalPass() { // Make sure to reset the viewport to how it was before... Otherwise weird issues could occur. // Also bind the "main" framebuffer if it isn't already bound. - // TODO: Iris -// main.bindWrite(true); + main.bindFramebuffer(true); ProgramUniforms.clearActiveUniforms(); ProgramSamplers.clearActiveSamplers(); GL20.glUseProgram(0); diff --git a/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java b/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java index da3eac319..9680bd4e2 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/ColorTexture.java @@ -23,7 +23,6 @@ public ColorTexture(int width, int height) { TextureUploadHelper.resetTextureUploadState(); IrisRenderSystem.texImage2D(texture, GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (ByteBuffer) null); - // TODO: Message: GL_INVALID_OPERATION error generated. Cannot modify the default framebuffer object. EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, GL11.GL_TEXTURE_2D, texture, 0); } diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java index 89843898e..77e162846 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java @@ -10,24 +10,18 @@ import net.coderbot.iris.shaderpack.PackDirectives; import net.coderbot.iris.shaderpack.PackRenderTargetDirectives; import org.joml.Vector2i; -import org.lwjgl.opengl.EXTFramebufferObject; import org.lwjgl.opengl.GL11; import java.util.ArrayList; import java.util.List; import java.util.Map; -import static org.lwjgl.opengl.EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT; -import static org.lwjgl.opengl.EXTFramebufferObject.GL_FRAMEBUFFER_EXT; - public class RenderTargets { private final RenderTarget[] targets; private int currentDepthTexture; private DepthBufferFormat currentDepthFormat; @Getter - private final ColorTexture colorTexture; - private final DepthTexture depthTexture; private final DepthTexture noTranslucents; private final DepthTexture noHand; private final GlFramebuffer depthSourceFb; @@ -45,7 +39,7 @@ public class RenderTargets { private int cachedDepthBufferVersion; - public RenderTargets(int width, int height, int depthBufferVersion, Map renderTargets, PackDirectives packDirectives) { + public RenderTargets(int width, int height, int depthTexture, int depthBufferVersion, Map renderTargets, PackDirectives packDirectives) { targets = new RenderTarget[renderTargets.size()]; renderTargets.forEach((index, settings) -> { @@ -57,15 +51,7 @@ public RenderTargets(int width, int height, int depthBufferVersion, Map Date: Sat, 4 Nov 2023 10:04:36 -0700 Subject: [PATCH 023/301] formatting --- .../angelica/client/Shaders.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index b53e71499..f39cc3024 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -2082,19 +2082,13 @@ public static void beginRender(Minecraft minecraft, float f, long l) { if (shadowMipmapEnabled[0]) { GL13.glActiveTexture(GL13.GL_TEXTURE4); GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - GL11.glTexParameteri( - GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MIN_FILTER, - shadowFilterNearest[0] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, shadowFilterNearest[0] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); } if (usedShadowDepthBuffers >= 2) { if (shadowMipmapEnabled[1]) { GL13.glActiveTexture(GL13.GL_TEXTURE5); GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - GL11.glTexParameteri( - GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MIN_FILTER, - shadowFilterNearest[1] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, shadowFilterNearest[1] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); } } GL13.glActiveTexture(GL13.GL_TEXTURE0); @@ -2103,19 +2097,13 @@ public static void beginRender(Minecraft minecraft, float f, long l) { if (shadowColorMipmapEnabled[0]) { GL13.glActiveTexture(GL13.GL_TEXTURE13); GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - GL11.glTexParameteri( - GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MIN_FILTER, - shadowColorFilterNearest[0] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, shadowColorFilterNearest[0] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); } if (usedShadowColorBuffers >= 2) { if (shadowColorMipmapEnabled[1]) { GL13.glActiveTexture(GL13.GL_TEXTURE14); GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - GL11.glTexParameteri( - GL11.GL_TEXTURE_2D, - GL11.GL_TEXTURE_MIN_FILTER, - shadowColorFilterNearest[1] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, shadowColorFilterNearest[1] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); } } GL13.glActiveTexture(GL13.GL_TEXTURE0); From b555f3083c1998e56b348cd227d1f41a67f23cb8 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 4 Nov 2023 10:20:33 -0700 Subject: [PATCH 024/301] Move compat --- .../mojang/AutoClosableAbstractTexture.java | 2 +- .../compat/mojang/BufferBuilder.java | 2 +- .../angelica}/compat/mojang/BufferSource.java | 2 +- .../mojang/ByteBufferBackedInputStream.java | 2 +- .../angelica}/compat/mojang/Camera.java | 2 +- .../angelica}/compat/mojang/Constants.java | 2 +- .../compat/mojang/DefaultVertexFormat.java | 6 ++-- .../angelica}/compat/mojang/DrawState.java | 2 +- .../angelica}/compat/mojang/GLHelper.java | 2 +- .../angelica}/compat/mojang/GameRenderer.java | 2 +- .../compat/mojang/InteractionHand.java | 2 +- .../compat/mojang/LevelRenderer.java | 2 +- .../compat/mojang/MultiBufferSource.java | 2 +- .../angelica}/compat/mojang/NativeImage.java | 2 +- .../angelica}/compat/mojang/PoseStack.java | 31 ++++++++++++++++++- .../compat/mojang/RenderBuffers.java | 2 +- .../compat/mojang/RenderStateShard.java | 2 +- .../angelica}/compat/mojang/RenderType.java | 2 +- .../angelica}/compat/mojang/TextureAtlas.java | 2 +- .../angelica}/compat/mojang/VertexBuffer.java | 2 +- .../compat/mojang/VertexConsumer.java | 2 +- .../angelica}/compat/mojang/VertexFormat.java | 2 +- .../compat/mojang/VertexFormatElement.java | 2 +- .../impl/BufferBuilderExt.java | 2 +- .../impl/BufferSegment.java | 4 +-- .../impl/BufferSegmentRenderer.java | 2 +- .../impl/FullyBufferedMultiBufferSource.java | 8 ++--- .../OldFullyBufferedMultiBufferSource.java | 8 ++--- .../impl/RenderTypeUtil.java | 2 +- .../impl/SegmentedBufferBuilder.java | 10 +++--- .../impl/WrappableRenderType.java | 2 +- .../GraphTranslucencyRenderOrderManager.java | 2 +- .../impl/ordering/RenderOrderManager.java | 2 +- .../ordering/SimpleRenderOrderManager.java | 2 +- .../TranslucencyRenderOrderManager.java | 2 +- .../wrappers/TaggingRenderTypeWrapper.java | 2 +- .../block_rendering/BlockMaterialMapping.java | 2 +- .../BlockRenderingSettings.java | 2 +- .../fantastic/WrappingMultiBufferSource.java | 2 +- .../layer/BlockEntityRenderStateShard.java | 2 +- .../iris/layer/EntityRenderStateShard.java | 2 +- .../layer/IsBlockEntityRenderStateShard.java | 2 +- .../iris/layer/IsEntityRenderStateShard.java | 2 +- .../iris/layer/IsOutlineRenderStateShard.java | 2 +- .../iris/layer/OuterWrappedRenderType.java | 4 +-- .../DeferredWorldRenderingPipeline.java | 4 +-- .../FixedFunctionWorldRenderingPipeline.java | 4 +-- .../coderbot/iris/pipeline/HandRenderer.java | 8 ++--- .../iris/pipeline/HorizonRenderer.java | 8 ++--- .../iris/pipeline/ShadowRenderer.java | 12 +++---- .../iris/pipeline/WorldRenderingPhase.java | 2 +- .../iris/pipeline/WorldRenderingPipeline.java | 4 +-- .../postprocess/FullScreenQuadRenderer.java | 2 +- .../NativeImageBackedCustomTexture.java | 2 +- .../NativeImageBackedNoiseTexture.java | 2 +- .../NativeImageBackedSingleColorTexture.java | 2 +- .../coderbot/iris/shadow/ShadowMatrices.java | 4 +-- .../mipmap/AbstractMipmapGenerator.java | 2 +- .../mipmap/ChannelMipmapGenerator.java | 2 +- .../texture/mipmap/CustomMipmapGenerator.java | 2 +- .../iris/texture/pbr/PBRAtlasTexture.java | 4 +-- .../texture/pbr/loader/AtlasPBRLoader.java | 2 +- .../texture/util/ImageManipulationUtil.java | 2 +- .../iris/texture/util/TextureExporter.java | 2 +- .../iris/uniforms/CelestialUniforms.java | 2 +- .../coderbot/iris/uniforms/IdMapUniforms.java | 2 +- .../iris/vertices/ExtendingBufferBuilder.java | 2 +- .../iris/vertices/IrisVertexFormats.java | 6 ++-- 68 files changed, 129 insertions(+), 100 deletions(-) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/AutoClosableAbstractTexture.java (92%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/BufferBuilder.java (98%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/BufferSource.java (86%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/ByteBufferBackedInputStream.java (93%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/Camera.java (74%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/Constants.java (67%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/DefaultVertexFormat.java (85%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/DrawState.java (87%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/GLHelper.java (89%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/GameRenderer.java (86%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/InteractionHand.java (65%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/LevelRenderer.java (76%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/MultiBufferSource.java (83%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/NativeImage.java (98%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/PoseStack.java (70%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/RenderBuffers.java (66%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/RenderStateShard.java (95%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/RenderType.java (95%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/TextureAtlas.java (90%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/VertexBuffer.java (85%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/VertexConsumer.java (70%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/VertexFormat.java (93%) rename src/main/java/{net/coderbot/iris => com/gtnewhorizons/angelica}/compat/mojang/VertexFormatElement.java (98%) diff --git a/src/main/java/net/coderbot/iris/compat/mojang/AutoClosableAbstractTexture.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java similarity index 92% rename from src/main/java/net/coderbot/iris/compat/mojang/AutoClosableAbstractTexture.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java index 3cbcb5952..90f543a1a 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/AutoClosableAbstractTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.minecraft.client.renderer.texture.AbstractTexture; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/BufferBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java similarity index 98% rename from src/main/java/net/coderbot/iris/compat/mojang/BufferBuilder.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java index 57eccbe6b..2945a92cd 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/BufferBuilder.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import net.coderbot.batchedentityrendering.impl.BufferBuilderExt; import org.apache.commons.lang3.tuple.Pair; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/BufferSource.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java similarity index 86% rename from src/main/java/net/coderbot/iris/compat/mojang/BufferSource.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java index d4fd7ba73..260b1615a 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/BufferSource.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import java.util.Map; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/ByteBufferBackedInputStream.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java similarity index 93% rename from src/main/java/net/coderbot/iris/compat/mojang/ByteBufferBackedInputStream.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java index 511321021..11269c996 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/ByteBufferBackedInputStream.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/Camera.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java similarity index 74% rename from src/main/java/net/coderbot/iris/compat/mojang/Camera.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java index a0abb362f..38ac41ea6 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/Camera.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; public class Camera { diff --git a/src/main/java/net/coderbot/iris/compat/mojang/Constants.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Constants.java similarity index 67% rename from src/main/java/net/coderbot/iris/compat/mojang/Constants.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/Constants.java index 6e16f32d8..2f1bd5ec6 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/Constants.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Constants.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; public class Constants { diff --git a/src/main/java/net/coderbot/iris/compat/mojang/DefaultVertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java similarity index 85% rename from src/main/java/net/coderbot/iris/compat/mojang/DefaultVertexFormat.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java index 5c80f7aa4..379988b31 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/DefaultVertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java @@ -1,8 +1,8 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import com.google.common.collect.ImmutableList; -import net.coderbot.iris.compat.mojang.VertexFormatElement.Type; -import net.coderbot.iris.compat.mojang.VertexFormatElement.Usage; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement.Type; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement.Usage; public class DefaultVertexFormat { diff --git a/src/main/java/net/coderbot/iris/compat/mojang/DrawState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DrawState.java similarity index 87% rename from src/main/java/net/coderbot/iris/compat/mojang/DrawState.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/DrawState.java index 6572c19a8..0be23ade7 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/DrawState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DrawState.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import lombok.Getter; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/GLHelper.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GLHelper.java similarity index 89% rename from src/main/java/net/coderbot/iris/compat/mojang/GLHelper.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/GLHelper.java index ac8a130b0..9a90b5c60 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/GLHelper.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GLHelper.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import net.minecraft.client.renderer.OpenGlHelper; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/GameRenderer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java similarity index 86% rename from src/main/java/net/coderbot/iris/compat/mojang/GameRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java index 48359fcbb..9552d1531 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/GameRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; public class GameRenderer { diff --git a/src/main/java/net/coderbot/iris/compat/mojang/InteractionHand.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/InteractionHand.java similarity index 65% rename from src/main/java/net/coderbot/iris/compat/mojang/InteractionHand.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/InteractionHand.java index 560312a37..75af559a5 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/InteractionHand.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/InteractionHand.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; public enum InteractionHand { MAIN_HAND, diff --git a/src/main/java/net/coderbot/iris/compat/mojang/LevelRenderer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LevelRenderer.java similarity index 76% rename from src/main/java/net/coderbot/iris/compat/mojang/LevelRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/LevelRenderer.java index fe4a77d78..87f38bd5f 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/LevelRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LevelRenderer.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; public class LevelRenderer { diff --git a/src/main/java/net/coderbot/iris/compat/mojang/MultiBufferSource.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java similarity index 83% rename from src/main/java/net/coderbot/iris/compat/mojang/MultiBufferSource.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java index 018427031..67d192e76 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/MultiBufferSource.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import java.util.Map; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/NativeImage.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java similarity index 98% rename from src/main/java/net/coderbot/iris/compat/mojang/NativeImage.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java index 83b22b63d..237d84993 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/NativeImage.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import lombok.Getter; import net.coderbot.iris.Iris; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/PoseStack.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PoseStack.java similarity index 70% rename from src/main/java/net/coderbot/iris/compat/mojang/PoseStack.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/PoseStack.java index 4c16e56d9..a6e0d42cd 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/PoseStack.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PoseStack.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import com.google.common.collect.Queues; import org.joml.Matrix3f; @@ -53,6 +53,35 @@ public void rotateZ(float f) { } + public void scale(float f, float g, float h) { + final Pose lv = (Pose)this.poseStack.getLast(); + lv.pose.scale(f, g, h); + + if (f == g && g == h) { + if (f > 0.0F) { + return; + } + + lv.normal.scale(-1.0F); + } + float i = 1.0F / f; + float j = 1.0F / g; + float k = 1.0F / h; + float l = invSqrt(i * j * k); + lv.normal.scale(l * i, l * j, l * k); + + } + + + private static float invSqrt(float x) { + float xhalf = 0.5f * x; + int i = Float.floatToIntBits(x); + i = 0x5f3759df - (i >> 1); + x = Float.intBitsToFloat(i); + x *= (1.5f - xhalf * x * x); + return x; + } + public static final class Pose { private final Matrix4f pose; private final Matrix3f normal; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/RenderBuffers.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderBuffers.java similarity index 66% rename from src/main/java/net/coderbot/iris/compat/mojang/RenderBuffers.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderBuffers.java index 34f31181a..721da4902 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/RenderBuffers.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderBuffers.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; public class RenderBuffers { diff --git a/src/main/java/net/coderbot/iris/compat/mojang/RenderStateShard.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderStateShard.java similarity index 95% rename from src/main/java/net/coderbot/iris/compat/mojang/RenderStateShard.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderStateShard.java index c1b271e70..e48aacbfe 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/RenderStateShard.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderStateShard.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import javax.annotation.Nullable; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/RenderType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderType.java similarity index 95% rename from src/main/java/net/coderbot/iris/compat/mojang/RenderType.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderType.java index 300c0d405..ab2609a0e 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/RenderType.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderType.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import java.util.Optional; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/TextureAtlas.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java similarity index 90% rename from src/main/java/net/coderbot/iris/compat/mojang/TextureAtlas.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java index 6be3dcb64..1c7ecacd6 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/TextureAtlas.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.ITickable; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/VertexBuffer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java similarity index 85% rename from src/main/java/net/coderbot/iris/compat/mojang/VertexBuffer.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java index 6697e2cca..1819196f2 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/VertexBuffer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import org.joml.Matrix4f; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/VertexConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java similarity index 70% rename from src/main/java/net/coderbot/iris/compat/mojang/VertexConsumer.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java index c0e938963..156ef1286 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/VertexConsumer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; public interface VertexConsumer { diff --git a/src/main/java/net/coderbot/iris/compat/mojang/VertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java similarity index 93% rename from src/main/java/net/coderbot/iris/compat/mojang/VertexFormat.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java index 9884e1cc8..a48e0042c 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/VertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import com.google.common.collect.ImmutableList; import it.unimi.dsi.fastutil.ints.IntArrayList; diff --git a/src/main/java/net/coderbot/iris/compat/mojang/VertexFormatElement.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java similarity index 98% rename from src/main/java/net/coderbot/iris/compat/mojang/VertexFormatElement.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java index b7c3593c8..a7561e989 100644 --- a/src/main/java/net/coderbot/iris/compat/mojang/VertexFormatElement.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.compat.mojang; +package com.gtnewhorizons.angelica.compat.mojang; import lombok.Getter; import org.lwjgl.opengl.GL11; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java index e70df8d28..2eeec5207 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl; -import net.coderbot.iris.compat.mojang.DrawState; +import com.gtnewhorizons.angelica.compat.mojang.DrawState; import java.nio.ByteBuffer; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java index 503d685eb..6bf1b01d5 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java @@ -1,7 +1,7 @@ package net.coderbot.batchedentityrendering.impl; -import net.coderbot.iris.compat.mojang.DrawState; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.DrawState; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; import java.nio.ByteBuffer; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java index fa52f06fd..b10e99510 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl; -import net.coderbot.iris.compat.mojang.BufferBuilder; +import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; public class BufferSegmentRenderer { private final BufferBuilder fakeBufferBuilder; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java index 034ff7dbd..b512068c1 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java @@ -2,10 +2,10 @@ import net.coderbot.batchedentityrendering.impl.ordering.GraphTranslucencyRenderOrderManager; import net.coderbot.batchedentityrendering.impl.ordering.RenderOrderManager; -import net.coderbot.iris.compat.mojang.BufferBuilder; -import net.coderbot.iris.compat.mojang.BufferSource; -import net.coderbot.iris.compat.mojang.RenderType; -import net.coderbot.iris.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; +import com.gtnewhorizons.angelica.compat.mojang.BufferSource; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import net.coderbot.iris.fantastic.WrappingMultiBufferSource; import net.minecraft.client.Minecraft; import net.minecraft.profiler.Profiler; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java index 6faf177f4..1a1a5ba6f 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java @@ -2,10 +2,10 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import net.coderbot.iris.compat.mojang.BufferBuilder; -import net.coderbot.iris.compat.mojang.BufferSource; -import net.coderbot.iris.compat.mojang.RenderType; -import net.coderbot.iris.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; +import com.gtnewhorizons.angelica.compat.mojang.BufferSource; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java index d30d9ebe3..1897d2d58 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; import org.lwjgl.opengl.GL11; public class RenderTypeUtil { diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java b/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java index 0164977e5..b7084412f 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java @@ -1,10 +1,10 @@ package net.coderbot.batchedentityrendering.impl; -import net.coderbot.iris.compat.mojang.BufferBuilder; -import net.coderbot.iris.compat.mojang.DrawState; -import net.coderbot.iris.compat.mojang.MultiBufferSource; -import net.coderbot.iris.compat.mojang.RenderType; -import net.coderbot.iris.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; +import com.gtnewhorizons.angelica.compat.mojang.DrawState; +import com.gtnewhorizons.angelica.compat.mojang.MultiBufferSource; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import org.apache.commons.lang3.tuple.Pair; import java.nio.ByteBuffer; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java b/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java index d33e69c4e..b4054de23 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; public interface WrappableRenderType { /** diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java index b8ea53e31..82b52e1ba 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java @@ -10,7 +10,7 @@ import net.coderbot.batchedentityrendering.impl.BlendingStateHolder; import net.coderbot.batchedentityrendering.impl.TransparencyType; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; import java.util.ArrayList; import java.util.EnumMap; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java index 590bdd40a..cd75ad501 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl.ordering; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; public interface RenderOrderManager { void begin(RenderType type); diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java index 25f18c4c7..ddbeddc24 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl.ordering; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; import java.util.LinkedHashSet; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java index 75ac1f2d2..f320be937 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java @@ -3,7 +3,7 @@ import net.coderbot.batchedentityrendering.impl.BlendingStateHolder; import net.coderbot.batchedentityrendering.impl.TransparencyType; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; import java.util.ArrayList; import java.util.EnumMap; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java index 89677eea7..0da70a272 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java @@ -1,7 +1,7 @@ package net.coderbot.batchedentityrendering.impl.wrappers; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; import org.jetbrains.annotations.Nullable; import java.util.Objects; diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java index 9b04c5a86..d8678a9d1 100644 --- a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java @@ -4,7 +4,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; import net.coderbot.iris.shaderpack.materialmap.BlockEntry; import net.coderbot.iris.shaderpack.materialmap.BlockRenderType; import net.coderbot.iris.shaderpack.materialmap.NamespacedId; diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java index 0f91ee52b..784aca6bc 100644 --- a/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java @@ -2,7 +2,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntFunction; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; import net.coderbot.iris.shaderpack.materialmap.NamespacedId; import net.minecraft.block.Block; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java b/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java index 08bd06128..00a8067bd 100644 --- a/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java +++ b/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java @@ -1,6 +1,6 @@ package net.coderbot.iris.fantastic; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; import java.util.function.Function; public interface WrappingMultiBufferSource { diff --git a/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java index f14e19251..d93393004 100644 --- a/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java @@ -1,6 +1,6 @@ package net.coderbot.iris.layer; -import net.coderbot.iris.compat.mojang.RenderStateShard; +import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; import net.coderbot.iris.uniforms.CapturedRenderingState; public final class BlockEntityRenderStateShard extends RenderStateShard { diff --git a/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java index 91c0d31c4..32f1b9905 100644 --- a/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java @@ -1,6 +1,6 @@ package net.coderbot.iris.layer; -import net.coderbot.iris.compat.mojang.RenderStateShard; +import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; import net.coderbot.iris.uniforms.CapturedRenderingState; public final class EntityRenderStateShard extends RenderStateShard { diff --git a/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java index 3b7247f8b..78b5ef68a 100644 --- a/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java @@ -1,6 +1,6 @@ package net.coderbot.iris.layer; -import net.coderbot.iris.compat.mojang.RenderStateShard; +import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; public class IsBlockEntityRenderStateShard extends RenderStateShard { public static final IsBlockEntityRenderStateShard INSTANCE = new IsBlockEntityRenderStateShard(); diff --git a/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java index c032f8bf2..d3a435b43 100644 --- a/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java @@ -1,6 +1,6 @@ package net.coderbot.iris.layer; -import net.coderbot.iris.compat.mojang.RenderStateShard; +import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; public class IsEntityRenderStateShard extends RenderStateShard { public static final IsEntityRenderStateShard INSTANCE = new IsEntityRenderStateShard(); diff --git a/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java index c6f29b64e..ba0799752 100644 --- a/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java @@ -1,6 +1,6 @@ package net.coderbot.iris.layer; -import net.coderbot.iris.compat.mojang.RenderStateShard; +import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; public class IsOutlineRenderStateShard extends RenderStateShard { public static final IsOutlineRenderStateShard INSTANCE = new IsOutlineRenderStateShard(); diff --git a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java index 5e9daff4d..f842825ad 100644 --- a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java +++ b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java @@ -1,8 +1,8 @@ package net.coderbot.iris.layer; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import net.coderbot.iris.compat.mojang.RenderStateShard; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; import org.jetbrains.annotations.Nullable; import java.util.Objects; diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index cd3b4a13d..ce0712ac4 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -7,8 +7,8 @@ import net.coderbot.iris.Iris; import net.coderbot.iris.block_rendering.BlockMaterialMapping; import net.coderbot.iris.block_rendering.BlockRenderingSettings; -import net.coderbot.iris.compat.mojang.Camera; -import net.coderbot.iris.compat.mojang.LevelRenderer; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.LevelRenderer; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.ProgramTable; import net.coderbot.iris.gbuffer_overrides.matching.RenderCondition; diff --git a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java index 38ca8bb83..62cd5e51d 100644 --- a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java @@ -1,8 +1,8 @@ package net.coderbot.iris.pipeline; import net.coderbot.iris.block_rendering.BlockRenderingSettings; -import net.coderbot.iris.compat.mojang.Camera; -import net.coderbot.iris.compat.mojang.LevelRenderer; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.LevelRenderer; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; diff --git a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java index d5d8c5fd6..49a5ddea2 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java @@ -1,10 +1,10 @@ package net.coderbot.iris.pipeline; import net.coderbot.batchedentityrendering.impl.FullyBufferedMultiBufferSource; -import net.coderbot.iris.compat.mojang.Camera; -import net.coderbot.iris.compat.mojang.GameRenderer; -import net.coderbot.iris.compat.mojang.InteractionHand; -import net.coderbot.iris.compat.mojang.PoseStack; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.GameRenderer; +import com.gtnewhorizons.angelica.compat.mojang.InteractionHand; +import com.gtnewhorizons.angelica.compat.mojang.PoseStack; import net.irisshaders.iris.api.v0.IrisApi; import net.minecraft.client.Minecraft; import net.minecraft.entity.EntityLiving; diff --git a/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java index 8fa1ee876..afb1c14ce 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java @@ -1,9 +1,9 @@ package net.coderbot.iris.pipeline; -import net.coderbot.iris.compat.mojang.BufferBuilder; -import net.coderbot.iris.compat.mojang.DefaultVertexFormat; -import net.coderbot.iris.compat.mojang.VertexBuffer; -import net.coderbot.iris.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; +import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.VertexBuffer; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import net.minecraft.client.Minecraft; import org.joml.Matrix4f; import org.lwjgl.opengl.GL11; diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 62ece7c85..6440e6e7f 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -6,12 +6,12 @@ import net.coderbot.batchedentityrendering.impl.DrawCallTrackingRenderBuffers; import net.coderbot.batchedentityrendering.impl.RenderBuffersExt; import net.coderbot.iris.Iris; -import net.coderbot.iris.compat.mojang.BufferSource; -import net.coderbot.iris.compat.mojang.Camera; -import net.coderbot.iris.compat.mojang.LevelRenderer; -import net.coderbot.iris.compat.mojang.PoseStack; -import net.coderbot.iris.compat.mojang.RenderBuffers; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.BufferSource; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.LevelRenderer; +import com.gtnewhorizons.angelica.compat.mojang.PoseStack; +import com.gtnewhorizons.angelica.compat.mojang.RenderBuffers; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.shaderpack.OptionalBoolean; import net.coderbot.iris.shaderpack.PackDirectives; diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java index 0bfda9ed9..de0bf5e75 100644 --- a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java @@ -1,6 +1,6 @@ package net.coderbot.iris.pipeline; -import net.coderbot.iris.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderType; public enum WorldRenderingPhase { NONE, diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java index 2bdc1ff4e..a1d72f76a 100644 --- a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java @@ -1,7 +1,7 @@ package net.coderbot.iris.pipeline; -import net.coderbot.iris.compat.mojang.Camera; -import net.coderbot.iris.compat.mojang.LevelRenderer; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.LevelRenderer; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; diff --git a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java index f2f39792b..383ae8ccc 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java @@ -2,7 +2,7 @@ import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.iris.gl.IrisRenderSystem; -import net.coderbot.iris.compat.mojang.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java index 3a809e10a..22d6e7f6d 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java @@ -1,6 +1,6 @@ package net.coderbot.iris.rendertarget; -import net.coderbot.iris.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.shaderpack.texture.CustomTextureData; import net.minecraft.client.renderer.texture.DynamicTexture; diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java index 68b15b375..fbb7c232c 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java @@ -1,6 +1,6 @@ package net.coderbot.iris.rendertarget; -import net.coderbot.iris.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; import net.minecraft.client.renderer.texture.DynamicTexture; import org.lwjgl.opengl.GL11; diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java index 162c14285..2671804d8 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java @@ -1,6 +1,6 @@ package net.coderbot.iris.rendertarget; -import net.coderbot.iris.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; import net.minecraft.client.renderer.texture.DynamicTexture; public class NativeImageBackedSingleColorTexture extends DynamicTexture { diff --git a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java index 1d5bdcea1..4ef230d26 100644 --- a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java +++ b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java @@ -1,11 +1,11 @@ package net.coderbot.iris.shadow; -import net.coderbot.iris.compat.mojang.PoseStack; +import com.gtnewhorizons.angelica.compat.mojang.PoseStack; import org.joml.Matrix4f; import java.nio.FloatBuffer; -import static net.coderbot.iris.compat.mojang.Constants.DEGREES_TO_RADIANS; +import static com.gtnewhorizons.angelica.compat.mojang.Constants.DEGREES_TO_RADIANS; public class ShadowMatrices { private static final float NEAR = 0.05f; diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java index 4217b23d1..81d1e4ba8 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.mipmap; -import net.coderbot.iris.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; public abstract class AbstractMipmapGenerator implements CustomMipmapGenerator { @Override diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java index 2a51d977e..dd92ad317 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java @@ -1,5 +1,5 @@ package net.coderbot.iris.texture.mipmap; -import net.coderbot.iris.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; public class ChannelMipmapGenerator extends AbstractMipmapGenerator { protected final BlendFunction redFunc; diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java index 8059c3046..ace0d2aa2 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.mipmap; -import net.coderbot.iris.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; public interface CustomMipmapGenerator { NativeImage[] generateMipLevels(NativeImage image, int mipLevel); diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java index 8673ec9cb..e1e3a8ef9 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java @@ -1,8 +1,8 @@ package net.coderbot.iris.texture.pbr; import com.gtnewhorizons.angelica.mixins.early.textures.MixinTextureAtlasSprite; -import net.coderbot.iris.compat.mojang.AutoClosableAbstractTexture; -import net.coderbot.iris.compat.mojang.TextureAtlas; +import com.gtnewhorizons.angelica.compat.mojang.AutoClosableAbstractTexture; +import com.gtnewhorizons.angelica.compat.mojang.TextureAtlas; import net.coderbot.iris.texture.util.TextureExporter; import net.coderbot.iris.texture.util.TextureManipulationUtil; import net.minecraft.client.renderer.texture.TextureAtlasSprite; diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java index 9dd146600..4b118859a 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.pbr.loader; -import net.coderbot.iris.compat.mojang.TextureAtlas; +import com.gtnewhorizons.angelica.compat.mojang.TextureAtlas; import net.coderbot.iris.texture.mipmap.ChannelMipmapGenerator; import net.coderbot.iris.texture.mipmap.LinearBlendFunction; import net.minecraft.client.resources.IResourceManager; diff --git a/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java b/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java index 1c27c5049..365c56355 100644 --- a/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java +++ b/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.util; -import net.coderbot.iris.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; public class ImageManipulationUtil { public static NativeImage scaleNearestNeighbor(NativeImage image, int newWidth, int newHeight) { diff --git a/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java b/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java index a626aea1f..4a89d9583 100644 --- a/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java +++ b/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java @@ -1,7 +1,7 @@ package net.coderbot.iris.texture.util; import com.gtnewhorizons.angelica.glsm.GLStateManager; -import net.coderbot.iris.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; import net.minecraft.client.Minecraft; import org.apache.commons.io.FilenameUtils; import org.lwjgl.opengl.GL11; diff --git a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java index 58cf757d9..e3ed628d3 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java @@ -1,6 +1,6 @@ package net.coderbot.iris.uniforms; -import net.coderbot.iris.compat.mojang.Constants; +import com.gtnewhorizons.angelica.compat.mojang.Constants; import net.coderbot.iris.gl.uniform.UniformHolder; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; diff --git a/src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java b/src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java index d6a1808ce..430e20d95 100644 --- a/src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/IdMapUniforms.java @@ -1,7 +1,7 @@ package net.coderbot.iris.uniforms; import it.unimi.dsi.fastutil.objects.Object2IntFunction; -import net.coderbot.iris.compat.mojang.InteractionHand; +import com.gtnewhorizons.angelica.compat.mojang.InteractionHand; import net.coderbot.iris.gl.uniform.DynamicUniformHolder; import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; import net.coderbot.iris.shaderpack.IdMap; diff --git a/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java b/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java index 2ebd2b6b8..15cab7a6a 100644 --- a/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java +++ b/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java @@ -1,6 +1,6 @@ package net.coderbot.iris.vertices; -import net.coderbot.iris.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; public interface ExtendingBufferBuilder { void iris$beginWithoutExtending(int drawMode, VertexFormat vertexFormat); diff --git a/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java b/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java index 6dc2f44f8..e531c0297 100644 --- a/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java +++ b/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java @@ -1,9 +1,9 @@ package net.coderbot.iris.vertices; import com.google.common.collect.ImmutableList; -import net.coderbot.iris.compat.mojang.DefaultVertexFormat; -import net.coderbot.iris.compat.mojang.VertexFormat; -import net.coderbot.iris.compat.mojang.VertexFormatElement; +import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement; public class IrisVertexFormats { public static final VertexFormatElement ENTITY_ELEMENT; From 382fd329a3214a9b48427de002827ee5a63a0209 Mon Sep 17 00:00:00 2001 From: glowredman <35727266+glowredman@users.noreply.github.com> Date: Sun, 5 Nov 2023 16:02:22 +0100 Subject: [PATCH 025/301] Update buildscript --- build.gradle | 6 +++--- dependencies.gradle | 8 ++++---- repositories.gradle | 5 ++++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index c090c03ac..5c5ffe63e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -//version: 1695474595 +//version: 1698936026 /* DO NOT CHANGE THIS FILE! Also, you may replace this file at any time if there is an update available. @@ -646,7 +646,7 @@ repositories { def mixinProviderGroup = "io.github.legacymoddingmc" def mixinProviderModule = "unimixins" -def mixinProviderVersion = "0.1.7.1" +def mixinProviderVersion = "0.1.13" def mixinProviderSpecNoClassifer = "${mixinProviderGroup}:${mixinProviderModule}:${mixinProviderVersion}" def mixinProviderSpec = "${mixinProviderSpecNoClassifer}:dev" ext.mixinProviderSpec = mixinProviderSpec @@ -798,7 +798,7 @@ dependencies { java17Dependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}") } if (modId != 'hodgepodge') { - java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.3.5') + java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.3.17') } java17PatchDependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}:forgePatches") {transitive = false} diff --git a/dependencies.gradle b/dependencies.gradle index f8c6a0efe..e7a47bc18 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -51,21 +51,21 @@ dependencies { compileOnly(files("dependencies/SmartRender-1.7.10-2.1-dev.jar")) // Because who doesn't want NEI - compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.3.55-GTNH:dev') + compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.4.9-GTNH:dev') // Notfine Deps compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev") runtimeOnly("com.github.GTNewHorizons:Baubles:1.0.1.16:dev") - compileOnly("com.github.GTNewHorizons:twilightforest:2.3.8.18:dev") {transitive = false } + compileOnly("com.github.GTNewHorizons:twilightforest:2.5.1:dev") {transitive = false } devOnlyNonPublishable(rfg.deobf('curse.maven:witchery-69673:2234410')) // ArchaicFix Deps implementation("com.github.Speiger:Primitive-Collections:0.9.0") - compileOnly("curse.maven:chickenchunks-229316:2233250") + compileOnly("codechicken:ChickenChunks:1.7.10-1.3.4.19:dev") compileOnly "thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev" compileOnly('curse.maven:cofh-core-69162:2388751') - compileOnly('com.github.GTNewHorizons:Botania:1.9.19-GTNH:dev') {transitive = false } + compileOnly('com.github.GTNewHorizons:Botania:1.10.2-GTNH:dev') {transitive = false } compileOnly("org.projectlombok:lombok:1.18.22") {transitive = false } annotationProcessor("org.projectlombok:lombok:1.18.22") diff --git a/repositories.gradle b/repositories.gradle index c8843905d..ee596465b 100644 --- a/repositories.gradle +++ b/repositories.gradle @@ -1,5 +1,8 @@ // Add any additional repositories for your dependencies here repositories { - + maven { + name = 'covers1624 maven' + url = 'https://nexus.covers1624.net/repository/maven-hosted/' + } } From 3d9a7d21e8808bc4c33027b81205d2da2b51d752 Mon Sep 17 00:00:00 2001 From: glowredman <35727266+glowredman@users.noreply.github.com> Date: Sun, 5 Nov 2023 16:03:53 +0100 Subject: [PATCH 026/301] Make required mixin ctors private --- .../mixins/early/archaic/client/core/MixinBlockFence.java | 2 +- .../mixins/early/archaic/common/core/MixinEmbeddedChannel.java | 2 +- .../mixins/early/archaic/common/core/MixinEntityLiving.java | 2 +- .../mixins/early/archaic/common/core/MixinEntityPlayerMP.java | 2 +- .../mixins/early/archaic/common/core/MixinMaterialLiquid.java | 2 +- .../mixins/early/archaic/common/core/MixinWorldServer.java | 2 +- .../angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java | 2 +- .../mixins/early/notfine/leaves/MixinBlockLeavesBase.java | 2 +- .../early/notfine/particles/MixinBlockEnchantmentTable.java | 2 +- .../late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java | 2 +- .../late/notfine/leaves/witchery/MixinBlockWitchLeaves.java | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinBlockFence.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinBlockFence.java index 452d83efd..7d0fde598 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinBlockFence.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinBlockFence.java @@ -10,7 +10,7 @@ @Mixin(BlockFence.class) public abstract class MixinBlockFence extends Block { - protected MixinBlockFence(Material p_i45394_1_) { + private MixinBlockFence(Material p_i45394_1_) { super(p_i45394_1_); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEmbeddedChannel.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEmbeddedChannel.java index 5c9150cc7..94ff96b6a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEmbeddedChannel.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEmbeddedChannel.java @@ -21,7 +21,7 @@ @Mixin(EmbeddedChannel.class) public abstract class MixinEmbeddedChannel extends AbstractChannel { - protected MixinEmbeddedChannel(Channel parent) { + private MixinEmbeddedChannel(Channel parent) { super(parent); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java index 5b9e32ff4..5a2d6b075 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java @@ -11,7 +11,7 @@ @Mixin(EntityLiving.class) public abstract class MixinEntityLiving extends EntityLivingBase { - public MixinEntityLiving(World p_i1594_1_) { + private MixinEntityLiving(World p_i1594_1_) { super(p_i1594_1_); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityPlayerMP.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityPlayerMP.java index 94f09e4c6..0ba6051ee 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityPlayerMP.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityPlayerMP.java @@ -15,7 +15,7 @@ @Mixin(EntityPlayerMP.class) public abstract class MixinEntityPlayerMP extends EntityPlayer { - public MixinEntityPlayerMP(World worldIn, GameProfile gameProfileIn) {super(worldIn, gameProfileIn);} + private MixinEntityPlayerMP(World worldIn, GameProfile gameProfileIn) {super(worldIn, gameProfileIn);} /** * @reason This is incorrectly set to 1, but not noticable in vanilla since the move logic diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMaterialLiquid.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMaterialLiquid.java index 5bb6564b1..1ca4eaef1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMaterialLiquid.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMaterialLiquid.java @@ -7,7 +7,7 @@ @Mixin(MaterialLiquid.class) public abstract class MixinMaterialLiquid extends Material { - public MixinMaterialLiquid(MapColor p_i2116_1_) { + private MixinMaterialLiquid(MapColor p_i2116_1_) { super(p_i2116_1_); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldServer.java index c2dde92bc..af0e9a274 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldServer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldServer.java @@ -20,7 +20,7 @@ public abstract class MixinWorldServer extends World { @Shadow public ChunkProviderServer theChunkProviderServer; - public MixinWorldServer(ISaveHandler p_i45368_1_, String p_i45368_2_, WorldProvider p_i45368_3_, WorldSettings p_i45368_4_, Profiler p_i45368_5_) { + private MixinWorldServer(ISaveHandler p_i45368_1_, String p_i45368_2_, WorldProvider p_i45368_3_, WorldSettings p_i45368_4_, Profiler p_i45368_5_) { super(p_i45368_1_, p_i45368_2_, p_i45368_3_, p_i45368_4_, p_i45368_5_); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java index 2eb5a00e3..b21fdaa47 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java @@ -53,7 +53,7 @@ public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { @Shadow protected IIcon[][] field_150129_M; - protected MixinBlockLeaves(Material material, boolean overridden) { + private MixinBlockLeaves(Material material, boolean overridden) { super(material, overridden); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java index 555c0591b..8583e3c4f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java @@ -16,7 +16,7 @@ public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int return LeafRenderUtil.shouldSideBeRendered(world, x, y, z, side); } - protected MixinBlockLeavesBase(Material material) { + private MixinBlockLeavesBase(Material material) { super(material); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinBlockEnchantmentTable.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinBlockEnchantmentTable.java index 1741ffd36..dc8f38bb6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinBlockEnchantmentTable.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinBlockEnchantmentTable.java @@ -15,7 +15,7 @@ @Mixin(value = BlockEnchantmentTable.class) public abstract class MixinBlockEnchantmentTable extends BlockContainer { - protected MixinBlockEnchantmentTable(Material material) { + private MixinBlockEnchantmentTable(Material material) { super(material); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java index d20299cac..6a7427e2d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java @@ -49,7 +49,7 @@ public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int return LeafRenderUtil.shouldSideBeRendered(world, x, y, z, side); } - protected MixinBlockMagicalLeaves(Material material) { + private MixinBlockMagicalLeaves(Material material) { super(material); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java index 5dcb9cbd9..213ab7509 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java @@ -44,7 +44,7 @@ public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { @Shadow(remap = false) private IIcon[][] iconsForModes; - protected MixinBlockWitchLeaves(Material material, boolean unused) { + private MixinBlockWitchLeaves(Material material, boolean unused) { super(material, unused); } From cb797d13f2258036ae80dc5ef02711001284109a Mon Sep 17 00:00:00 2001 From: glowredman <35727266+glowredman@users.noreply.github.com> Date: Sun, 5 Nov 2023 16:05:42 +0100 Subject: [PATCH 027/301] Remove dead code --- .../archaic/client/lighting/MixinWorld.java | 13 ------- .../client/occlusion/MixinWorldRenderer.java | 1 - .../common/core/MixinAxisAlignedBB.java | 1 - .../early/archaic/common/core/MixinBlock.java | 39 +------------------ .../early/archaic/common/core/MixinChunk.java | 3 -- .../early/shaders/MixinEntityRenderer.java | 6 --- 6 files changed, 1 insertion(+), 62 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java index 90c3892e7..5dc615303 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java @@ -1,28 +1,15 @@ package com.gtnewhorizons.angelica.mixins.early.archaic.client.lighting; -import net.minecraft.block.Block; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; -import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngine; import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(World.class) public abstract class MixinWorld { - @Shadow public abstract Block getBlock(int p_147439_1_, int p_147439_2_, int p_147439_3_); - - private LightingEngine lightingEngine; - - @Inject(method = "finishSetup", at = @At("RETURN"), remap = false) - private void onConstructed(CallbackInfo ci) { - this.lightingEngine = new LightingEngine((World) (Object) this); - } @Redirect(method = { "getSkyBlockTypeBrightness", "getSavedLightValue" }, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;getSavedLightValue(Lnet/minecraft/world/EnumSkyBlock;III)I")) private int useBlockIntrinsicBrightness(Chunk instance, EnumSkyBlock type, int x, int y, int z) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java index da44b48fa..a9afccd7a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java @@ -40,7 +40,6 @@ public class MixinWorldRenderer implements IWorldRenderer { @Shadow private TesselatorVertexState vertexState; @Unique private boolean arch$isInUpdateList; - @Unique private boolean arch$isFrustumCheckPending; @Unique private OcclusionWorker.CullInfo arch$cullInfo; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinAxisAlignedBB.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinAxisAlignedBB.java index 22420f75e..f2f1c31f2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinAxisAlignedBB.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinAxisAlignedBB.java @@ -8,7 +8,6 @@ @Mixin(AxisAlignedBB.class) public class MixinAxisAlignedBB { private final double XZ_MARGIN = 1E-6; - private final double Y_MARGIN = 0.000000001; @ModifyVariable(method = "calculateXOffset", at = @At(value = "STORE", ordinal = 0), index = 2, argsOnly = true) private double subXMargin(double old) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinBlock.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinBlock.java index a8d2dd1f8..96ccbb95d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinBlock.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinBlock.java @@ -1,56 +1,19 @@ package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; -import cpw.mods.fml.common.FMLCommonHandler; -import cpw.mods.fml.relauncher.Side; import net.minecraft.block.Block; -import net.minecraft.server.MinecraftServer; -import org.embeddedt.archaicfix.block.ThreadedBlockData; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import java.lang.ref.WeakReference; - @Mixin(Block.class) public class MixinBlock { - @Shadow public Block.SoundType stepSound; - private WeakReference lastServer = new WeakReference<>(null); - private ThreadedBlockData arch$serverThreadedData = null; - private ThreadedBlockData arch$clientThreadedData = new ThreadedBlockData(); - private final ThreadLocal arch$threadBlockData = new ThreadLocal<>(); + @Shadow public Block.SoundType stepSound; @Redirect(method = "", at = @At(opcode = Opcodes.PUTFIELD, value = "FIELD", target = "Lnet/minecraft/block/Block;stepSound:Lnet/minecraft/block/Block$SoundType;", ordinal = 0)) private void onConstruct(Block block, Block.SoundType sound) { stepSound = sound; } - - private ThreadedBlockData arch$calculateThreadedData() { - FMLCommonHandler inst = FMLCommonHandler.instance(); - Side trueSide; - if(inst.getSidedDelegate() == null) { - trueSide = inst.getEffectiveSide(); - } else { - trueSide = inst.getSide(); - } - if(trueSide == Side.SERVER || inst.getEffectiveSide() == Side.SERVER) { - if(lastServer.get() != inst.getMinecraftServerInstance()) { - lastServer = new WeakReference<>(inst.getMinecraftServerInstance()); - arch$serverThreadedData = new ThreadedBlockData(arch$clientThreadedData); - } - return arch$serverThreadedData; - } - return arch$clientThreadedData; - } - - public ThreadedBlockData arch$getThreadedData() { - ThreadedBlockData calculated = arch$threadBlockData.get(); - if(calculated == null) { - calculated = arch$calculateThreadedData(); - arch$threadBlockData.set(calculated); - } - return calculated; - } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java index 4a949b5e6..3d8c088db 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; -import java.util.Map; @Mixin(value = Chunk.class, priority = 1100) public class MixinChunk { @@ -35,8 +34,6 @@ public class MixinChunk { @Shadow @Final public int zPosition; - @Shadow public Map chunkTileEntityMap; - @Inject(method = "onChunkUnload", at = @At("HEAD")) public void handlePlayerChunkUnload(CallbackInfo ci) { final List players = new ArrayList<>(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index 5f4722734..15d9afb28 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -59,12 +59,6 @@ private void sglFogi(int pname, int param) { } } - private void toggleFog(boolean enable) { - if (fogToggleListener != null) { - fogToggleListener.run(); - } - } - @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/EntityRenderer;setupCameraTransform(FI)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void iris$setCamera(float tickDelta, long startTime, CallbackInfo ci) { From fab77e8c7e8d961376a36fb621c20e5e438e5362 Mon Sep 17 00:00:00 2001 From: glowredman <35727266+glowredman@users.noreply.github.com> Date: Sun, 5 Nov 2023 16:06:52 +0100 Subject: [PATCH 028/301] Add generics --- .../early/archaic/client/occlusion/MixinRenderGlobal.java | 5 ++--- .../early/archaic/client/occlusion/MixinWorldRenderer.java | 5 +++-- .../client/threadedupdates/MixinTessellator_Debug.java | 2 +- .../archaic/client/threadedupdates/MixinWorldRenderer.java | 3 ++- .../early/archaic/common/core/MixinEntityTrackerEntry.java | 3 ++- .../early/archaic/common/core/MixinMapGenStructure.java | 4 +++- .../archaic/common/core/MixinObjectIntIdentityMap.java | 7 +++---- .../early/archaic/common/core/MixinSpawnerAnimals.java | 3 ++- .../mixins/early/archaic/common/core/MixinWorld.java | 2 +- .../archaic/common/extrautils/MixinEventHandlerSiege.java | 3 +-- .../archaic/common/lighting/MixinChunkProviderServer.java | 2 +- .../early/archaic/common/lighting/MixinWorld_Lighting.java | 3 ++- .../early/notfine/particles/MixinEffectRenderer.java | 2 +- .../late/archaic/common/mrtjp/MixinBlockUpdateHandler.java | 4 ++-- 14 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinRenderGlobal.java index 0d7ce3f16..7cef7b010 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinRenderGlobal.java @@ -54,12 +54,12 @@ private void initBetterLists(Minecraft p_i1249_1_, CallbackInfo ci) { } @Redirect(method = "loadRenderers", at = @At(value = "INVOKE", target = "Ljava/util/List;clear()V", ordinal = 0)) - private void clearRendererUpdateQueue(List instance) { + private void clearRendererUpdateQueue(List instance) { OcclusionHelpers.renderer.clearRendererUpdateQueue(instance); } @Redirect(method = { "loadRenderers", "markRenderersForNewPosition" }, at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", ordinal = 0)) - private boolean sortAndAddRendererUpdateQueue(List instance, Object renderer) { + private boolean sortAndAddRendererUpdateQueue(List instance, Object renderer) { return OcclusionHelpers.renderer.sortAndAddRendererUpdateQueue(instance, renderer); } @@ -123,7 +123,6 @@ public int sortAndRender(EntityLivingBase view, int pass, double tick) { * @reason occlusion culling */ @Overwrite - @SuppressWarnings("unchecked") public int renderSortedRenderers(int start, int end, int pass, double tick) { return OcclusionHelpers.renderer.sortAndRender(start, end, pass, tick); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java index a9afccd7a..b61799bb1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java @@ -3,6 +3,7 @@ import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.shader.TesselatorVertexState; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; import net.minecraft.world.chunk.EmptyChunk; import org.embeddedt.archaicfix.occlusion.interfaces.IWorldRenderer; @@ -27,9 +28,9 @@ public class MixinWorldRenderer implements IWorldRenderer { @Shadow public int posZ; - @Shadow public List tileEntityRenderers; + @Shadow public List tileEntityRenderers; - @Shadow private List tileEntities; + @Shadow private List tileEntities; @Shadow public boolean needsUpdate; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator_Debug.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator_Debug.java index 9004d08aa..b6f37933d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator_Debug.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator_Debug.java @@ -18,7 +18,7 @@ private void verifyThreadIsCorrect(CallbackInfo ci) { } @Inject(method = {"getVertexState", "draw"}, at = @At("HEAD")) - private void verifyThreadIsCorrect(CallbackInfoReturnable cir) { + private void verifyThreadIsCorrect(CallbackInfoReturnable cir) { verifyThreadIsCorrect(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinWorldRenderer.java index 344b81ff5..62ab94486 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinWorldRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinWorldRenderer.java @@ -5,6 +5,7 @@ import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.tileentity.TileEntity; import net.minecraft.world.ChunkCache; import org.embeddedt.archaicfix.threadedupdates.ICapturableTessellator; import org.embeddedt.archaicfix.threadedupdates.IRendererUpdateResultHolder; @@ -28,7 +29,7 @@ private void setLastWorldRendererSingleton(CallbackInfo ci) { } @Inject(method = "updateRenderer", at = @At(value="INVOKE", target = "Lnet/minecraft/client/renderer/WorldRenderer;postRenderBlocks(ILnet/minecraft/entity/EntityLivingBase;)V"), locals=LocalCapture.CAPTURE_FAILHARD) - private void loadTessellationResult(EntityLivingBase cameraEntity, CallbackInfo ci, int i, int j, int k, int l, int i1, int j1, HashSet hashset, Minecraft minecraft, EntityLivingBase entitylivingbase1, int l1, int i2, int j2, byte b0, ChunkCache chunkcache, RenderBlocks renderblocks, int k2) { + private void loadTessellationResult(EntityLivingBase cameraEntity, CallbackInfo ci, int i, int j, int k, int l, int i1, int j1, HashSet hashset, Minecraft minecraft, EntityLivingBase entitylivingbase1, int l1, int i2, int j2, byte b0, ChunkCache chunkcache, RenderBlocks renderblocks, int k2) { int pass = k2; if(!arch$getRendererUpdateTask().cancelled) { ((ICapturableTessellator) Tessellator.instance).arch$addTessellatorVertexState(arch$getRendererUpdateTask().result[pass].renderedQuads); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityTrackerEntry.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityTrackerEntry.java index 31969e627..84a3b329b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityTrackerEntry.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityTrackerEntry.java @@ -4,6 +4,7 @@ import net.minecraft.entity.EntityLeashKnot; import net.minecraft.entity.EntityTrackerEntry; import net.minecraft.entity.item.EntityItemFrame; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.projectile.EntityArrow; import net.minecraft.network.Packet; import net.minecraft.network.play.server.S0CPacketSpawnPlayer; @@ -34,7 +35,7 @@ public class MixinEntityTrackerEntry { @Shadow public int ticks; @Inject(method = "sendLocationToAllClients", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/EntityTrackerEntry;sendMetadataToAllAssociatedPlayers()V", ordinal = 1, shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD) - private void saveIfTeleported(List clientList, CallbackInfo ci, int i, int j, int k, int l, int i1, int j1, int k1, int l1, Object object) { + private void saveIfTeleported(List clientList, CallbackInfo ci, int i, int j, int k, int l, int i1, int j1, int k1, int l1, Object object) { if(object instanceof S18PacketEntityTeleport) { this.lastScaledXPosition = i; this.lastScaledYPosition = j; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMapGenStructure.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMapGenStructure.java index 6013317b7..316ed69be 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMapGenStructure.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMapGenStructure.java @@ -2,6 +2,8 @@ import com.google.common.collect.ImmutableList; import net.minecraft.world.gen.structure.MapGenStructure; +import net.minecraft.world.gen.structure.StructureStart; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -13,7 +15,7 @@ public abstract class MixinMapGenStructure { @Redirect(method = { "func_143028_c", "func_142038_b", "func_151545_a", "generateStructuresInChunk" }, at = @At(value = "INVOKE", target = "Ljava/util/Map;values()Ljava/util/Collection;")) - private Collection getStructureMapValues(Map structureMap) { + private Collection getStructureMapValues(Map structureMap) { return ImmutableList.copyOf(structureMap.values()); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinObjectIntIdentityMap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinObjectIntIdentityMap.java index 29448a5b9..72c1faca0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinObjectIntIdentityMap.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinObjectIntIdentityMap.java @@ -11,15 +11,14 @@ import java.util.List; -@SuppressWarnings("rawtypes") @Mixin(ObjectIntIdentityMap.class) public class MixinObjectIntIdentityMap { - @Shadow protected List field_148748_b; + @Shadow protected List field_148748_b; @Inject(method = "", at = @At("RETURN")) private void initIdArray(CallbackInfo ci) { - this.field_148748_b = new UnexpectionalObjectArrayList(); + this.field_148748_b = new UnexpectionalObjectArrayList<>(); } /** @@ -30,6 +29,6 @@ private void initIdArray(CallbackInfo ci) { */ @Overwrite public Object func_148745_a(int id) { - return ((UnexpectionalObjectArrayList)field_148748_b).getOrNull(id); + return ((UnexpectionalObjectArrayList)field_148748_b).getOrNull(id); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinSpawnerAnimals.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinSpawnerAnimals.java index da4df4f0b..ebd7dc67c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinSpawnerAnimals.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinSpawnerAnimals.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; import net.minecraft.entity.Entity; +import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.SpawnerAnimals; import net.minecraft.world.World; import org.embeddedt.archaicfix.config.ArchaicConfig; @@ -15,7 +16,7 @@ @Mixin(SpawnerAnimals.class) public class MixinSpawnerAnimals { - @Shadow private HashMap eligibleChunksForSpawning; + @Shadow private HashMap eligibleChunksForSpawning; @ModifyConstant(method = "findChunksForSpawning", constant = @Constant(doubleValue = 24.0D)) private double lowerSpawnRange(double old) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorld.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorld.java index 2595d5701..20c45572b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorld.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorld.java @@ -30,7 +30,7 @@ public abstract class MixinWorld { @Shadow public boolean isRemote; - @Shadow public List playerEntities; + @Shadow public List playerEntities; @Shadow protected IChunkProvider chunkProvider; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerSiege.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerSiege.java index 2b2edcc7b..8780a9966 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerSiege.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerSiege.java @@ -1,7 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.archaic.common.extrautils; import com.rwtema.extrautils.EventHandlerSiege; -import net.minecraft.tileentity.TileEntityBeacon; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -10,6 +9,6 @@ public class MixinEventHandlerSiege { @Redirect(method = "golemDeath", at = @At(value = "INVOKE", target = "Ljava/lang/Object;equals(Ljava/lang/Object;)Z")) private boolean checkSubclassofBeacon(Object subject, Object teBeaconClass) { - return ((Class)teBeaconClass).isAssignableFrom((Class)subject); + return ((Class)teBeaconClass).isAssignableFrom((Class)subject); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkProviderServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkProviderServer.java index 6ac270127..f88d58fa1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkProviderServer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkProviderServer.java @@ -14,7 +14,7 @@ @Mixin(ChunkProviderServer.class) public abstract class MixinChunkProviderServer { - @Shadow private Set chunksToUnload; + @Shadow private Set chunksToUnload; @Shadow public WorldServer worldObj; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinWorld_Lighting.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinWorld_Lighting.java index 75197bcba..1a481ad2b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinWorld_Lighting.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinWorld_Lighting.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; +import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; import net.minecraft.world.chunk.IChunkProvider; @@ -17,7 +18,7 @@ @Mixin(value = World.class, priority = 999) public abstract class MixinWorld_Lighting implements ILightingEngineProvider { - @Shadow protected Set activeChunkSet; + @Shadow protected Set activeChunkSet; @Shadow public abstract IChunkProvider getChunkProvider(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java index c2b7f176a..acea5f6e9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java @@ -88,7 +88,7 @@ public void renderParticles(Entity entity, float p_78874_2_) { @Shadow @Final private static ResourceLocation particleTextures; - @Shadow private List[] fxLayers; + @Shadow private List[] fxLayers; @Shadow private TextureManager renderer; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/mrtjp/MixinBlockUpdateHandler.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/mrtjp/MixinBlockUpdateHandler.java index 484de7740..9e66a5c19 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/mrtjp/MixinBlockUpdateHandler.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/mrtjp/MixinBlockUpdateHandler.java @@ -12,10 +12,10 @@ @Mixin(BlockUpdateHandler$.class) public class MixinBlockUpdateHandler { @Redirect(method = "getActiveChunkSet", at = @At(value = "INVOKE", target = "Ljava/util/HashSet;add(Ljava/lang/Object;)Z"), remap = false) - private boolean addChunkIfLoaded(HashSet chunkSet, Object o, World world) { + private boolean addChunkIfLoaded(HashSet chunkSet, Object o, World world) { ChunkCoordIntPair pair = (ChunkCoordIntPair)o; if(world.getChunkProvider().chunkExists(pair.chunkXPos, pair.chunkZPos)) - return chunkSet.add(o); + return chunkSet.add(pair); return false; } } From 4ee5adee4e8facf52e8c07a08a8bdae0f020098e Mon Sep 17 00:00:00 2001 From: glowredman <35727266+glowredman@users.noreply.github.com> Date: Sun, 5 Nov 2023 16:07:39 +0100 Subject: [PATCH 029/301] Use `@Share` / `@Local` --- .../MixinPlayerChunkViewerManager.java | 30 ++++++++----------- .../early/archaic/common/core/MixinChunk.java | 25 +++++++++------- .../early/shaders/MixinEntityRenderer.java | 16 +++++----- .../renderer/MixinSimpleTexture.java | 16 +++------- .../shadersmod/renderer/MixinTextureMap.java | 20 +++---------- 5 files changed, 44 insertions(+), 63 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/chickenchunks/MixinPlayerChunkViewerManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/chickenchunks/MixinPlayerChunkViewerManager.java index c17ce3cd8..9ea474e34 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/chickenchunks/MixinPlayerChunkViewerManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/chickenchunks/MixinPlayerChunkViewerManager.java @@ -6,34 +6,28 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; + import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; @Mixin(PlayerChunkViewerManager.class) public class MixinPlayerChunkViewerManager { @Shadow(remap = false) public LinkedList ticketChanges; - private ArrayList oldTicketChanges; - - @Redirect(method = "update", at = @At(value = "INVOKE", target = "Ljava/util/LinkedList;iterator()Ljava/util/Iterator;"), remap = false) - private Iterator getSafeIterator(LinkedList list) { - if(list == this.ticketChanges) { - oldTicketChanges = new ArrayList<>((LinkedList)list); - return oldTicketChanges.iterator(); - } else { - return list.iterator(); - } + @Redirect(method = "update", at = @At(ordinal = 7, value = "INVOKE", target = "Ljava/util/LinkedList;iterator()Ljava/util/Iterator;"), remap = false) + private Iterator getSafeIterator(LinkedList list, @Share("oldTicketChanges") LocalRef> oldTicketChanges) { + oldTicketChanges.set(new ArrayList<>(list)); + return oldTicketChanges.get().iterator(); } - @Redirect(method = "update", at = @At(value = "INVOKE", target = "Ljava/util/LinkedList;clear()V"), remap = false) - private void clearListSafely(LinkedList list) { - if(list == this.ticketChanges) { - this.ticketChanges.removeAll(oldTicketChanges); - oldTicketChanges = null; - } else { - list.clear(); - } + @Redirect(method = "update", at = @At(ordinal = 4, value = "INVOKE", target = "Ljava/util/LinkedList;clear()V"), remap = false) + private void clearListSafely(LinkedList list, @Share("oldTicketChanges") LocalRef> oldTicketChanges) { + this.ticketChanges.removeAll(oldTicketChanges.get()); + oldTicketChanges.set(null); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java index 3d8c088db..327e602e6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java @@ -15,12 +15,17 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +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.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; + import java.util.ArrayList; +import java.util.Deque; import java.util.LinkedList; import java.util.List; @@ -54,18 +59,17 @@ private void avoidBiomeGenOnClient(int p_76591_1_, int p_76591_2_, WorldChunkMan } } - private static LinkedList arch$populatingChunk = new LinkedList<>(); // keep track of cascading chunk generation during chunk population - - private void logCascadingWorldGeneration() { + @Unique + private void logCascadingWorldGeneration(Deque populatingChunk) { ModContainer activeModContainer = Loader.instance().activeModContainer(); String format = "{} loaded a new chunk {} in dimension {} ({}) while populating chunk {}, causing cascading worldgen lag."; ChunkCoordIntPair pos = new ChunkCoordIntPair(this.xPosition, this.zPosition); if (activeModContainer == null) { - ArchaicLogger.LOGGER.warn(format, "Minecraft", pos, this.worldObj.provider.dimensionId, this.worldObj.provider.getDimensionName(), arch$populatingChunk.peek()); + ArchaicLogger.LOGGER.warn(format, "Minecraft", pos, this.worldObj.provider.dimensionId, this.worldObj.provider.getDimensionName(), populatingChunk.peek()); } else { - ArchaicLogger.LOGGER.warn(format, activeModContainer.getName(), pos, this.worldObj.provider.dimensionId, this.worldObj.provider.getDimensionName(), arch$populatingChunk.peek()); + ArchaicLogger.LOGGER.warn(format, activeModContainer.getName(), pos, this.worldObj.provider.dimensionId, this.worldObj.provider.getDimensionName(), populatingChunk.peek()); ArchaicLogger.LOGGER.warn("Please report this to the mod's issue tracker. This log can be disabled in the ArchaicFix config."); } @@ -75,14 +79,15 @@ private void logCascadingWorldGeneration() { } @Inject(method = "populateChunk", at = @At("HEAD")) - private void savePopulatingChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int x, int z, CallbackInfo ci) { - if (arch$populatingChunk.size() > 0 && ArchaicConfig.logCascadingWorldgen) logCascadingWorldGeneration(); - arch$populatingChunk.push(new ChunkCoordIntPair(x, z)); + private void savePopulatingChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int x, int z, CallbackInfo ci, @Share("populatingChunk") LocalRef> populatingChunk) { + if(populatingChunk.get() == null) populatingChunk.set(new LinkedList<>()); + if (populatingChunk.get().size() > 0 && ArchaicConfig.logCascadingWorldgen) logCascadingWorldGeneration(populatingChunk.get()); + populatingChunk.get().push(new ChunkCoordIntPair(x, z)); } @Inject(method = "populateChunk", at = @At("TAIL")) - private void restorePopulatingChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int p_76624_3_, int p_76624_4_, CallbackInfo ci) { - arch$populatingChunk.pop(); + private void restorePopulatingChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int p_76624_3_, int p_76624_4_, CallbackInfo ci, @Share("populatingChunk") LocalRef> populatingChunk) { + populatingChunk.get().pop(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index 15d9afb28..22bd9d07e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -17,6 +17,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; + import java.nio.FloatBuffer; @Mixin(EntityRenderer.class) @@ -26,7 +29,6 @@ public class MixinEntityRenderer { @Unique private static Runnable fogStartListener; @Unique private static Runnable fogEndListener; @Unique private static Runnable fogDensityListener; - @Unique private WorldRenderingPipeline pipeline; private void sglFogf(int pname, float param) { @@ -67,25 +69,25 @@ private void sglFogi(int pname, int param) { @Inject(at = @At("HEAD"), method = "renderWorld(FJ)V") - private void iris$beginRender(float tickDelta, long startTime, CallbackInfo ci) { + private void iris$beginRender(float tickDelta, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { CapturedRenderingState.INSTANCE.setTickDelta(tickDelta); SystemTimeUniforms.COUNTER.beginFrame(); SystemTimeUniforms.TIMER.beginFrame(startTime); Program.unbind(); - pipeline = Iris.getPipelineManager().preparePipeline(Iris.getCurrentDimension()); + pipeline.set(Iris.getPipelineManager().preparePipeline(Iris.getCurrentDimension())); - pipeline.beginLevelRendering(); + pipeline.get().beginLevelRendering(); } @Inject(method = "renderWorld(FJ)V", at = @At(value = "RETURN", shift = At.Shift.BEFORE)) - private void iris$endLevelRender(float tickDelta, long limitTime, CallbackInfo callback) { + private void iris$endLevelRender(float tickDelta, long limitTime, CallbackInfo callback, @Share("pipeline") LocalRef pipeline) { // TODO: Iris // HandRenderer.INSTANCE.renderTranslucent(poseStack, tickDelta, camera, gameRenderer, pipeline); Minecraft.getMinecraft().mcProfiler.endStartSection("iris_final"); - pipeline.finalizeLevelRendering(); - pipeline = null; + pipeline.get().finalizeLevelRendering(); + pipeline.set(null); Program.unbind(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinSimpleTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinSimpleTexture.java index 9aecfdf3a..02ebf4618 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinSimpleTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinSimpleTexture.java @@ -1,6 +1,8 @@ package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import com.gtnewhorizons.angelica.client.ShadersTex; +import com.llamalad7.mixinextras.sugar.Local; + import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.SimpleTexture; import net.minecraft.client.resources.IResourceManager; @@ -8,9 +10,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.awt.image.BufferedImage; @@ -18,24 +18,16 @@ public abstract class MixinSimpleTexture extends AbstractTexture { // TODO: PBR - private IResourceManager passedResourceManager; - @Shadow protected ResourceLocation textureLocation; - // TODO: Use @Local as soon as it exists in a stable version of MixinExtras - @Inject(method = "loadTexture(Lnet/minecraft/client/resources/IResourceManager;)V", at = @At("HEAD")) - private void angelica$getResourceManager(IResourceManager p_110551_1_, CallbackInfo cbi) { - passedResourceManager = p_110551_1_; - } - @Redirect( method = "loadTexture(Lnet/minecraft/client/resources/IResourceManager;)V", at = @At( value = "INVOKE", target = "Lnet/minecraft/client/renderer/texture/TextureUtil;uploadTextureImageAllocate(ILjava/awt/image/BufferedImage;ZZ)I")) - private int angelica$loadSimpleTexture(int textureID, BufferedImage bufferedImage, boolean flag, boolean flag1) { - ShadersTex.loadSimpleTexture(textureID, bufferedImage, flag, flag1, passedResourceManager, this.textureLocation, ShadersTex.getMultiTexID(this)); + private int angelica$loadSimpleTexture(int textureID, BufferedImage bufferedImage, boolean flag, boolean flag1, @Local IResourceManager p_110551_1_) { + ShadersTex.loadSimpleTexture(textureID, bufferedImage, flag, flag1, p_110551_1_, this.textureLocation, ShadersTex.getMultiTexID(this)); return 0; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureMap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureMap.java index 5cc88d53d..41341f052 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureMap.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureMap.java @@ -1,6 +1,8 @@ package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; import com.gtnewhorizons.angelica.client.ShadersTex; +import com.llamalad7.mixinextras.sugar.Local; + import net.minecraft.client.renderer.texture.Stitcher; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; @@ -8,13 +10,11 @@ import net.minecraft.client.resources.IResourceManager; import net.minecraft.util.ResourceLocation; import org.spongepowered.asm.mixin.Mixin; -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.Redirect; import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.io.IOException; @@ -25,9 +25,6 @@ public class MixinTextureMap extends MixinAbstractTexture { public int angelica$atlasWidth; public int angelica$atlasHeight; - @Unique - private Stitcher stitcher; - // loadTextureAtlas @Redirect( @@ -39,23 +36,14 @@ public class MixinTextureMap extends MixinAbstractTexture { return ShadersTex.loadResource(p_110571_1_, resourcelocation1); } - // TODO: Use @Local as soon as it is in a stable version of MixinExtras - @Inject( - at = @At(ordinal = 0, remap = false, target = "Ljava/util/Map;clear()V", value = "INVOKE"), - locals = LocalCapture.CAPTURE_FAILEXCEPTION, - method = "loadTextureAtlas(Lnet/minecraft/client/resources/IResourceManager;)V") - private void angelica$captureStitcher(IResourceManager p_110571_1_, CallbackInfo ci, int i, Stitcher stitcher) { - this.stitcher = stitcher; - } - @Redirect( at = @At( target = "Lnet/minecraft/client/renderer/texture/TextureUtil;allocateTextureImpl(IIIIF)V", value = "INVOKE"), method = "loadTextureAtlas(Lnet/minecraft/client/resources/IResourceManager;)V") private void angelica$allocateTextureMap(int p_147946_0_, int p_147946_1_, int p_147946_2_, int p_147946_3_, - float p_147946_4_) { - ShadersTex.allocateTextureMap(p_147946_0_, p_147946_1_, p_147946_2_, p_147946_3_, p_147946_4_, this.stitcher, (TextureMap) (Object) this); + float p_147946_4_, @Local Stitcher stitcher) { + ShadersTex.allocateTextureMap(p_147946_0_, p_147946_1_, p_147946_2_, p_147946_3_, p_147946_4_, stitcher, (TextureMap) (Object) this); } @Redirect( From 0478e2b10cb9eabbb93e71824ea1e1c49cb09e48 Mon Sep 17 00:00:00 2001 From: glowredman <35727266+glowredman@users.noreply.github.com> Date: Sun, 5 Nov 2023 16:20:58 +0100 Subject: [PATCH 030/301] Misc cleanup --- repositories.gradle | 4 ++++ .../com/gtnewhorizons/angelica/client/Shaders.java | 2 +- .../archaic/client/core/AccessorSplashProgress.java | 8 +++++--- .../early/archaic/client/core/MixinSplashProgress.java | 1 + .../early/archaic/common/lighting/MixinChunk.java | 10 ++++------ .../early/notfine/settings/MixinGameSettings.java | 4 ++++ .../early/shadersmod/renderer/MixinRenderDragon.java | 2 +- .../early/shadersmod/renderer/MixinRenderEnderman.java | 2 +- .../early/shadersmod/renderer/MixinRenderSpider.java | 2 +- .../late/client/journeymap/MixinTileDrawStep.java | 2 +- 10 files changed, 23 insertions(+), 14 deletions(-) diff --git a/repositories.gradle b/repositories.gradle index ee596465b..4333d1d9a 100644 --- a/repositories.gradle +++ b/repositories.gradle @@ -4,5 +4,9 @@ repositories { maven { name = 'covers1624 maven' url = 'https://nexus.covers1624.net/repository/maven-hosted/' + metadataSources { + mavenPom() + artifact() + } } } diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index f39cc3024..9ee5355c9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -2828,7 +2828,7 @@ public static void nextEntity() { } } - public static void beginSpiderEyes() { + public static void beginGlowingEyes() { if (true) return; if (isRenderingWorld) { useProgram(ProgramSpiderEyes); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/AccessorSplashProgress.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/AccessorSplashProgress.java index 5c2fd7d08..efb45d0ca 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/AccessorSplashProgress.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/AccessorSplashProgress.java @@ -4,17 +4,19 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; +@SuppressWarnings("deprecation") @Mixin(SplashProgress.class) public interface AccessorSplashProgress { - @Accessor(value="barBorderColor", remap = false) + + @Accessor(remap = false) static int getBarBorderColor() { throw new AssertionError(); } - @Accessor(value="barBackgroundColor", remap = false) + @Accessor(remap = false) static int getBarBackgroundColor() { throw new AssertionError(); } - @Accessor(value="fontColor", remap = false) + @Accessor(remap = false) static int getFontColor() { throw new AssertionError(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSplashProgress.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSplashProgress.java index 55c7059c7..bff59c450 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSplashProgress.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSplashProgress.java @@ -27,6 +27,7 @@ import static org.lwjgl.opengl.GL11.glScalef; import static org.lwjgl.opengl.GL11.glTranslatef; +@SuppressWarnings("deprecation") @Mixin(targets = { "cpw/mods/fml/client/SplashProgress$3" }) public class MixinSplashProgress { private static final int memoryGoodColor = 0x78CB34; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunk.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunk.java index 39fbd7874..7546c85dc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunk.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunk.java @@ -23,10 +23,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@SuppressWarnings("UnnecessaryQualifiedMemberReference") @Mixin(value = Chunk.class) public abstract class MixinChunk implements IChunkLighting, IChunkLightingData, ILightingEngineProvider { - private static final EnumFacing[] HORIZONTAL = LightingHooks.HORIZONTAL_FACINGS; /** * Callback injected to the head of getLightSubtracted(BlockPos, int) to force deferred light updates to be processed. @@ -76,7 +74,7 @@ private int getBlockLightOpacity(int x, int y, int z) { * @author Angeline */ @Overwrite - public void relightBlock(int x, int y, int z) { + private void relightBlock(int x, int y, int z) { int i = this.heightMap[z << 4 | x] & 255; int j = Math.max(y, i); @@ -131,7 +129,7 @@ public void func_150809_p() { * @author Angeline */ @Overwrite - public void recheckGaps(boolean onlyOne) { + private void recheckGaps(boolean onlyOne) { this.worldObj.theProfiler.startSection("recheckGaps"); WorldChunkSlice slice = new WorldChunkSlice(this.worldObj, this.xPosition, this.zPosition); @@ -179,7 +177,7 @@ private boolean recheckGapsForColumn(WorldChunkSlice slice, int x, int z) { private int recheckGapsGetLowestHeight(WorldChunkSlice slice, int x, int z) { int max = Integer.MAX_VALUE; - for (EnumFacing facing : HORIZONTAL) { + for (EnumFacing facing : LightingHooks.HORIZONTAL_FACINGS) { int j = x + facing.getFrontOffsetX(); int k = z + facing.getFrontOffsetZ(); @@ -192,7 +190,7 @@ private int recheckGapsGetLowestHeight(WorldChunkSlice slice, int x, int z) { private void recheckGapsSkylightNeighborHeight(WorldChunkSlice slice, int x, int z, int height, int max) { this.checkSkylightNeighborHeight(slice, x, z, max); - for (EnumFacing facing : HORIZONTAL) { + for (EnumFacing facing : LightingHooks.HORIZONTAL_FACINGS) { int j = x + facing.getFrontOffsetX(); int k = z + facing.getFrontOffsetZ(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java index eee19a73f..39e89d25b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java @@ -96,6 +96,8 @@ public void setOptionFloatValue(GameSettings.Options option, float value) { case STREAM_FPS: field_152404_N = value; break; + default: + break; } } @@ -194,6 +196,8 @@ public void setOptionValue(GameSettings.Options option, int value) { enableVsync = !enableVsync; Display.setVSyncEnabled(enableVsync); break; + default: + break; } saveOptions(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderDragon.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderDragon.java index 91b68a223..5ce485649 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderDragon.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderDragon.java @@ -20,7 +20,7 @@ public class MixinRenderDragon { value = "INVOKE"), method = "shouldRenderPass(Lnet/minecraft/entity/boss/EntityDragon;IF)I") private void angelica$beginSpiderEyes(CallbackInfoReturnable cir) { - Shaders.beginSpiderEyes(); + Shaders.beginGlowingEyes(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderEnderman.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderEnderman.java index f82692b88..8e1bcb564 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderEnderman.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderEnderman.java @@ -20,7 +20,7 @@ public class MixinRenderEnderman { value = "INVOKE"), method = "shouldRenderPass(Lnet/minecraft/entity/monster/EntityEnderman;IF)I") private void angelica$beginSpiderEyes(CallbackInfoReturnable cir) { - Shaders.beginSpiderEyes(); + Shaders.beginGlowingEyes(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderSpider.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderSpider.java index a8309bb0b..7186cb367 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderSpider.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderSpider.java @@ -20,7 +20,7 @@ public class MixinRenderSpider { value = "INVOKE"), method = "shouldRenderPass(Lnet/minecraft/entity/monster/EntitySpider;IF)I") private void angelica$beginSpiderEyes(CallbackInfoReturnable cir) { - Shaders.beginSpiderEyes(); + Shaders.beginGlowingEyes(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/client/journeymap/MixinTileDrawStep.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/client/journeymap/MixinTileDrawStep.java index 7225991e2..6bd156dbd 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/client/journeymap/MixinTileDrawStep.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/client/journeymap/MixinTileDrawStep.java @@ -8,7 +8,7 @@ @Mixin(TileDrawStep.class) public class MixinTileDrawStep { - @Redirect(method = "*", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Ljourneymap/client/render/map/TileDrawStep;debug:Z")) + @Redirect(method = "*", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Ljourneymap/client/render/map/TileDrawStep;debug:Z", remap = false)) private boolean getDebug(TileDrawStep instance) { return false; } From 3016a23b851824f7d58fb2846470207b55a0fa12 Mon Sep 17 00:00:00 2001 From: glowredman <35727266+glowredman@users.noreply.github.com> Date: Sun, 5 Nov 2023 17:15:38 +0100 Subject: [PATCH 031/301] Re-add undead code --- .../archaic/client/lighting/MixinWorld.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java index 5dc615303..85ffad2c5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java @@ -1,16 +1,28 @@ package com.gtnewhorizons.angelica.mixins.early.archaic.client.lighting; -import net.minecraft.world.EnumSkyBlock; -import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; +import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngine; import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; @Mixin(World.class) public abstract class MixinWorld { + @SuppressWarnings("unused") + private LightingEngine lightingEngine; + + @Inject(method = "finishSetup", at = @At("RETURN"), remap = false) + private void onConstructed(CallbackInfo ci) { + this.lightingEngine = new LightingEngine((World) (Object) this); + } + @Redirect(method = { "getSkyBlockTypeBrightness", "getSavedLightValue" }, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;getSavedLightValue(Lnet/minecraft/world/EnumSkyBlock;III)I")) private int useBlockIntrinsicBrightness(Chunk instance, EnumSkyBlock type, int x, int y, int z) { if(type == EnumSkyBlock.Block) From 5f5fbd97442b6554dc608f283eac970bbf34aa7d Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 4 Nov 2023 10:28:20 -0700 Subject: [PATCH 032/301] Add Embeddium - https://github.com/embeddedt/embeddium/commit/dc59ca357c25beefd6288f0d1d40b4cd8e670ab8 --- README.MD | 2 +- .../mods/sodium/client/RubidiumStub.java | 14 + .../mods/sodium/client/SodiumClientMod.java | 76 +++ .../client/buffer/ExtendedVertexFormat.java | 19 + .../sodium/client/compat/FlywheelCompat.java | 32 + .../sodium/client/compat/ccl/CCLCompat.java | 84 +++ .../compat/ccl/SinkingVertexBuilder.java | 191 ++++++ .../compat/forge/ForgeBlockRenderer.java | 111 ++++ .../compat/modernui/MuiGuiScaleHook.java | 45 ++ .../mods/sodium/client/gl/GlObject.java | 48 ++ .../sodium/client/gl/arena/GlBufferArena.java | 134 ++++ .../client/gl/arena/GlBufferSegment.java | 25 + .../sodium/client/gl/array/GlVertexArray.java | 22 + .../gl/attribute/BufferVertexFormat.java | 11 + .../gl/attribute/GlVertexAttribute.java | 55 ++ .../attribute/GlVertexAttributeBinding.java | 17 + .../gl/attribute/GlVertexAttributeFormat.java | 28 + .../client/gl/attribute/GlVertexFormat.java | 123 ++++ .../sodium/client/gl/buffer/GlBuffer.java | 23 + .../client/gl/buffer/GlBufferTarget.java | 31 + .../client/gl/buffer/GlBufferUsage.java | 25 + .../client/gl/buffer/GlMutableBuffer.java | 23 + .../sodium/client/gl/buffer/VertexData.java | 18 + .../sodium/client/gl/compat/FogHelper.java | 63 ++ .../sodium/client/gl/device/CommandList.java | 56 ++ .../client/gl/device/DrawCommandList.java | 18 + .../client/gl/device/GLRenderDevice.java | 217 ++++++ .../sodium/client/gl/device/RenderDevice.java | 18 + .../client/gl/func/GlBufferCopyFunctions.java | 41 ++ .../sodium/client/gl/func/GlFunctions.java | 29 + .../gl/func/GlIndirectMultiDrawFunctions.java | 38 ++ .../gl/func/GlInstancedArrayFunctions.java | 38 ++ .../gl/func/GlVertexArrayFunctions.java | 75 +++ .../sodium/client/gl/shader/GlProgram.java | 116 ++++ .../sodium/client/gl/shader/GlShader.java | 91 +++ .../client/gl/shader/ShaderBindingPoint.java | 13 + .../client/gl/shader/ShaderConstants.java | 74 +++ .../sodium/client/gl/shader/ShaderLoader.java | 52 ++ .../sodium/client/gl/shader/ShaderType.java | 17 + .../client/gl/shader/ShaderWorkarounds.java | 53 ++ .../client/gl/state/GlStateTracker.java | 77 +++ .../tessellation/GlAbstractTessellation.java | 38 ++ .../tessellation/GlFallbackTessellation.java | 30 + .../gl/tessellation/GlPrimitiveType.java | 19 + .../gl/tessellation/GlTessellation.java | 13 + .../GlVertexArrayTessellation.java | 40 ++ .../gl/tessellation/TessellationBinding.java | 28 + .../sodium/client/gl/util/BufferSlice.java | 22 + .../client/gl/util/GlMultiDrawBatch.java | 64 ++ .../client/gl/util/MemoryUtilHelper.java | 28 + .../client/gui/SodiumGameOptionPages.java | 366 ++++++++++ .../sodium/client/gui/SodiumGameOptions.java | 149 +++++ .../sodium/client/gui/SodiumOptionsGUI.java | 316 +++++++++ .../gui/options/FormattedTextProvider.java | 7 + .../sodium/client/gui/options/Option.java | 35 + .../sodium/client/gui/options/OptionFlag.java | 7 + .../client/gui/options/OptionGroup.java | 39 ++ .../client/gui/options/OptionImpact.java | 24 + .../sodium/client/gui/options/OptionImpl.java | 217 ++++++ .../sodium/client/gui/options/OptionPage.java | 45 ++ .../client/gui/options/TextProvider.java | 5 + .../gui/options/binding/GenericBinding.java | 24 + .../gui/options/binding/OptionBinding.java | 7 + .../compat/VanillaBooleanOptionBinding.java | 23 + .../client/gui/options/control/Control.java | 12 + .../gui/options/control/ControlElement.java | 58 ++ .../control/ControlValueFormatter.java | 47 ++ .../gui/options/control/CyclingControl.java | 121 ++++ .../gui/options/control/SliderControl.java | 164 +++++ .../gui/options/control/TickBoxControl.java | 94 +++ .../storage/MinecraftOptionsStorage.java | 25 + .../gui/options/storage/OptionStorage.java | 7 + .../options/storage/SodiumOptionsStorage.java | 30 + .../client/gui/widgets/AbstractWidget.java | 77 +++ .../client/gui/widgets/FlatButtonWidget.java | 76 +++ .../client/model/ModelCuboidAccessor.java | 7 + .../client/model/light/EntityLighter.java | 97 +++ .../sodium/client/model/light/LightMode.java | 6 + .../client/model/light/LightPipeline.java | 22 + .../model/light/LightPipelineProvider.java | 26 + .../light/cache/ArrayLightDataCache.java | 57 ++ .../model/light/cache/HashLightDataCache.java | 37 ++ .../model/light/data/LightDataAccess.java | 127 ++++ .../model/light/data/QuadLightData.java | 17 + .../model/light/flat/FlatLightPipeline.java | 69 ++ .../model/light/smooth/AoCompletionFlags.java | 16 + .../client/model/light/smooth/AoFaceData.java | 227 +++++++ .../model/light/smooth/AoNeighborInfo.java | 249 +++++++ .../light/smooth/SmoothLightPipeline.java | 270 ++++++++ .../sodium/client/model/quad/ModelQuad.java | 139 ++++ .../client/model/quad/ModelQuadView.java | 85 +++ .../model/quad/ModelQuadViewMutable.java | 64 ++ .../model/quad/blender/BiomeColorBlender.java | 29 + .../quad/blender/BlockColorSettings.java | 26 + .../blender/ConfigurableColorBlender.java | 37 ++ .../blender/DefaultBlockColorSettings.java | 19 + .../quad/blender/FlatBiomeColorBlender.java | 25 + .../quad/blender/SmoothBiomeColorBlender.java | 117 ++++ .../quad/properties/ModelQuadFacing.java | 54 ++ .../model/quad/properties/ModelQuadFlags.java | 130 ++++ .../quad/properties/ModelQuadOrientation.java | 35 + .../model/vertex/VanillaVertexTypes.java | 21 + .../client/model/vertex/VertexDrain.java | 29 + .../client/model/vertex/VertexSink.java | 36 + .../vertex/buffer/VertexBufferBuilder.java | 97 +++ .../model/vertex/buffer/VertexBufferView.java | 43 ++ .../vertex/buffer/VertexBufferWriter.java | 53 ++ .../vertex/buffer/VertexBufferWriterNio.java | 32 + .../buffer/VertexBufferWriterUnsafe.java | 34 + .../vertex/fallback/VertexWriterFallback.java | 30 + .../vertex/formats/glyph/GlyphVertexSink.java | 41 ++ .../vertex/formats/glyph/GlyphVertexType.java | 32 + .../writer/GlyphVertexBufferWriterNio.java | 30 + .../writer/GlyphVertexBufferWriterUnsafe.java | 29 + .../writer/GlyphVertexWriterFallback.java | 22 + .../vertex/formats/line/LineVertexSink.java | 37 ++ .../vertex/formats/line/LineVertexType.java | 32 + .../writer/LineVertexBufferWriterNio.java | 27 + .../writer/LineVertexBufferWriterUnsafe.java | 25 + .../line/writer/LineVertexWriterFallback.java | 20 + .../formats/particle/ParticleVertexSink.java | 20 + .../formats/particle/ParticleVertexType.java | 32 + .../writer/ParticleVertexBufferWriterNio.java | 30 + .../ParticleVertexBufferWriterUnsafe.java | 28 + .../writer/ParticleVertexWriterFallback.java | 22 + .../vertex/formats/quad/QuadVertexSink.java | 44 ++ .../vertex/formats/quad/QuadVertexType.java | 32 + .../writer/QuadVertexBufferWriterNio.java | 32 + .../writer/QuadVertexBufferWriterUnsafe.java | 30 + .../quad/writer/QuadVertexWriterFallback.java | 25 + .../BasicScreenQuadVertexSink.java | 37 ++ .../BasicScreenQuadVertexType.java | 32 + .../BasicScreenQuadVertexBufferWriterNio.java | 27 + ...sicScreenQuadVertexBufferWriterUnsafe.java | 25 + .../BasicScreenQuadVertexWriterFallback.java | 20 + .../AbstractVertexTransformer.java | 26 + .../SpriteTexturedVertexTransformer.java | 80 +++ .../vertex/type/BlittableVertexType.java | 15 + .../model/vertex/type/BufferVertexType.java | 14 + .../model/vertex/type/ChunkVertexType.java | 16 + .../model/vertex/type/CustomVertexType.java | 17 + .../model/vertex/type/VanillaVertexType.java | 13 + .../client/model/vertex/type/VertexType.java | 27 + .../client/render/GameRendererContext.java | 38 ++ .../client/render/SodiumWorldRenderer.java | 452 +++++++++++++ .../render/chunk/ChunkCameraContext.java | 21 + .../render/chunk/ChunkGraphicsState.java | 39 ++ .../render/chunk/ChunkRenderBackend.java | 59 ++ .../render/chunk/ChunkRenderColumn.java | 81 +++ .../render/chunk/ChunkRenderContainer.java | 323 +++++++++ .../render/chunk/ChunkRenderManager.java | 623 ++++++++++++++++++ .../multidraw/ChunkDrawCallBatcher.java | 125 ++++ .../multidraw/ChunkDrawParamsVector.java | 106 +++ .../IndirectCommandBufferVector.java | 35 + .../MultidrawChunkRenderBackend.java | 454 +++++++++++++ .../multidraw/MultidrawGraphicsState.java | 53 ++ .../backends/multidraw/StructBuffer.java | 29 + .../oneshot/ChunkOneshotGraphicsState.java | 89 +++ .../oneshot/ChunkRenderBackendOneshot.java | 142 ++++ .../chunk/compile/ChunkBufferSorter.java | 187 ++++++ .../chunk/compile/ChunkBuildBuffers.java | 133 ++++ .../chunk/compile/ChunkBuildResult.java | 23 + .../render/chunk/compile/ChunkBuilder.java | 404 ++++++++++++ .../buffers/BakedChunkModelBuffers.java | 25 + .../compile/buffers/ChunkModelBuffers.java | 12 + .../buffers/ChunkModelVertexTransformer.java | 23 + .../buffers/FallbackChunkModelBuffers.java | 21 + .../client/render/chunk/cull/ChunkCuller.java | 16 + .../render/chunk/cull/ChunkFaceFlags.java | 29 + .../chunk/cull/graph/ChunkGraphCuller.java | 219 ++++++ .../cull/graph/ChunkGraphIterationQueue.java | 58 ++ .../chunk/cull/graph/ChunkGraphNode.java | 184 ++++++ .../render/chunk/data/ChunkMeshData.java | 51 ++ .../render/chunk/data/ChunkRenderBounds.java | 81 +++ .../render/chunk/data/ChunkRenderData.java | 211 ++++++ .../chunk/format/ChunkMeshAttribute.java | 8 + .../render/chunk/format/ChunkModelOffset.java | 11 + .../format/DefaultModelVertexFormats.java | 9 + .../render/chunk/format/ModelVertexSink.java | 17 + .../render/chunk/format/ModelVertexUtil.java | 46 ++ .../hfp/HFPModelVertexBufferWriterNio.java | 43 ++ .../hfp/HFPModelVertexBufferWriterUnsafe.java | 42 ++ .../chunk/format/hfp/HFPModelVertexType.java | 59 ++ .../sfp/SFPModelVertexBufferWriterNio.java | 52 ++ .../sfp/SFPModelVertexBufferWriterUnsafe.java | 50 ++ .../chunk/format/sfp/SFPModelVertexType.java | 57 ++ .../render/chunk/lists/ChunkRenderList.java | 118 ++++ .../chunk/lists/ChunkRenderListIterator.java | 9 + .../render/chunk/passes/BlockRenderPass.java | 35 + .../chunk/passes/BlockRenderPassManager.java | 54 ++ .../render/chunk/region/ChunkRegion.java | 78 +++ .../chunk/region/ChunkRegionManager.java | 78 +++ .../render/chunk/shader/ChunkFogMode.java | 28 + .../render/chunk/shader/ChunkProgram.java | 55 ++ .../shader/ChunkRenderShaderBackend.java | 87 +++ .../shader/ChunkShaderBindingPoints.java | 12 + .../chunk/shader/ChunkShaderFogComponent.java | 69 ++ .../chunk/tasks/ChunkRenderBuildTask.java | 40 ++ .../tasks/ChunkRenderEmptyBuildTask.java | 33 + .../chunk/tasks/ChunkRenderRebuildTask.java | 193 ++++++ .../ChunkRenderTranslucencySortTask.java | 92 +++ .../render/entity/EntityLightSampler.java | 10 + .../render/occlusion/BlockOcclusionCache.java | 136 ++++ .../client/render/pipeline/BlockRenderer.java | 207 ++++++ .../render/pipeline/ChunkRenderCache.java | 10 + .../client/render/pipeline/FluidRenderer.java | 449 +++++++++++++ .../context/ChunkRenderCacheLocal.java | 66 ++ .../context/ChunkRenderCacheShared.java | 68 ++ .../client/render/texture/SpriteExtended.java | 5 + .../client/render/texture/SpriteUtil.java | 11 + .../mods/sodium/client/util/Dim2i.java | 51 ++ .../mods/sodium/client/util/MathUtil.java | 10 + .../sodium/client/util/ModelQuadUtil.java | 79 +++ .../mods/sodium/client/util/Norm3b.java | 82 +++ .../sodium/client/util/color/ColorABGR.java | 84 +++ .../sodium/client/util/color/ColorARGB.java | 66 ++ .../sodium/client/util/color/ColorMixer.java | 40 ++ .../sodium/client/util/color/ColorU8.java | 21 + .../client/util/color/FastCubicSampler.java | 88 +++ .../client/util/math/FrustumExtended.java | 5 + .../client/util/math/Matrix3fExtended.java | 34 + .../client/util/math/Matrix4fExtended.java | 51 ++ .../sodium/client/util/math/MatrixUtil.java | 34 + .../client/util/rand/SplitMixRandom.java | 99 +++ .../client/util/rand/XoRoShiRoRandom.java | 150 +++++ .../client/util/task/CancellationSource.java | 5 + .../client/world/ChunkStatusListener.java | 20 + .../world/ChunkStatusListenerManager.java | 6 + .../client/world/ClientWorldExtended.java | 8 + .../mods/sodium/client/world/WorldSlice.java | 371 +++++++++++ .../sodium/client/world/WorldSliceLocal.java | 126 ++++ .../sodium/client/world/biome/BiomeCache.java | 39 ++ .../client/world/biome/BiomeColorCache.java | 112 ++++ .../world/biome/BlockColorsExtended.java | 8 + .../world/biome/ItemColorsExtended.java | 8 + .../world/cloned/ChunkRenderContext.java | 37 ++ .../world/cloned/ClonedChunkSection.java | 193 ++++++ .../world/cloned/ClonedChunkSectionCache.java | 73 ++ .../cloned/PackedIntegerArrayExtended.java | 7 + .../cloned/PalettedContainerExtended.java | 20 + .../world/cloned/palette/ClonedPalette.java | 5 + .../cloned/palette/ClonedPaletteFallback.java | 16 + .../cloned/palette/ClonedPalleteArray.java | 22 + .../mods/sodium/common/config/Option.java | 63 ++ .../sodium/common/config/SodiumConfig.java | 219 ++++++ .../sodium/common/util/DirectionUtil.java | 15 + .../mods/sodium/common/util/IdTable.java | 60 ++ .../mods/sodium/common/util/ListUtil.java | 16 + .../common/util/collections/DequeDrain.java | 22 + .../util/collections/FutureDequeDrain.java | 52 ++ .../mods/sodium/mixin/SodiumMixinPlugin.java | 95 +++ .../sodium/mixin/core/MixinDirection.java | 66 ++ .../mixin/core/frustum/MixinFrustum.java | 115 ++++ .../mixin/core/matrix/MixinGameRenderer.java | 17 + .../mixin/core/matrix/MixinMatrix3f.java | 229 +++++++ .../mixin/core/matrix/MixinMatrix4f.java | 313 +++++++++ .../mixin/core/model/MixinBlockColors.java | 39 ++ .../mixin/core/model/MixinItemColors.java | 40 ++ .../mixin/core/pipeline/MixinBakedQuad.java | 102 +++ .../core/pipeline/MixinBufferBuilder.java | 117 ++++ .../core/pipeline/MixinVertexConsumer.java | 15 + .../core/pipeline/MixinVertexFormat.java | 17 + .../block/MixinBlockModelRenderer.java | 105 +++ .../features/block/MixinWorldRenderer.java | 27 + .../fast_advance/MixinBufferBuilder.java | 56 ++ .../fast_advance/MixinVertexFormat.java | 55 ++ .../fast_sort/MixinBufferBuilder.java | 180 +++++ .../intrinsics/MixinBufferBuilder.java | 94 +++ .../MixinSpriteTexturedVertexConsumer.java | 41 ++ .../intrinsics/MixinWorldRenderer.java | 114 ++++ .../chunk_rendering/MixinChunkBuilder.java | 15 + .../MixinClientChunkManager.java | 143 ++++ .../chunk_rendering/MixinClientWorld.java | 34 + .../MixinPackedIntegerArray.java | 49 ++ .../MixinPalettedContainer.java | 45 ++ .../chunk_rendering/MixinRenderLayer.java | 24 + .../chunk_rendering/MixinWorldRenderer.java | 171 +++++ .../mixin/features/debug/MixinDebugHud.java | 79 +++ .../entity/fast_render/MixinCuboid.java | 19 + .../entity/fast_render/MixinModelPart.java | 70 ++ .../smooth_lighting/MixinEntityRenderer.java | 51 ++ .../MixinPaintingEntityRenderer.java | 59 ++ .../MixinBackgroundRenderer.java | 24 + .../fast_biome_colors/MixinBlock.java | 17 + .../fast_biome_colors/MixinFluid.java | 16 + .../mixin/features/gui/MixinDebugHud.java | 133 ++++ .../fast_fps_pie/MixinMinecraftClient.java | 43 ++ .../MixinLevelLoadingScreen.java | 132 ++++ .../gui/fast_status_bars/MixinInGameHud.java | 60 ++ .../features/gui/font/MixinGlyphRenderer.java | 75 +++ .../features/item/MixinItemRenderer.java | 124 ++++ .../matrix_stack/MixinMatrixStack.java | 47 ++ .../matrix_stack/MixinVertexConsumer.java | 48 ++ .../model/MixinMultipartBakedModel.java | 82 +++ .../model/MixinWeightedBakedModel.java | 60 ++ .../optimized_bamboo/MixinBambooBlock.java | 22 + .../features/options/MixinGameOptions.java | 34 + .../features/options/MixinInGameHud.java | 15 + .../options/MixinMinecraftClient.java | 19 + .../features/options/MixinOptionsScreen.java | 27 + .../features/options/MixinWorldRenderer.java | 16 + .../fast_render/MixinBillboardParticle.java | 120 ++++ .../MixinTexturedRenderLayers.java | 34 + .../render_layer/leaves/MixinLeavesBlock.java | 27 + .../leaves/MixinRenderLayers.java | 54 ++ .../features/sky/MixinWorldRenderer.java | 57 ++ .../texture_tracking/MixinSprite.java | 84 +++ .../MixinSpriteAtlasTexture.java | 21 + .../MixinSpriteBillboardParticle.java | 40 ++ .../world_ticking/MixinClientWorld.java | 111 ++++ src/main/resources/META-INF/sodium_at.cfg | 18 + .../resources/assets/sodium/lang/en_us.json | 82 +++ .../resources/assets/sodium/lang/es_ar.json | 66 ++ .../resources/assets/sodium/lang/es_es.json | 66 ++ .../resources/assets/sodium/lang/es_mx.json | 66 ++ .../resources/assets/sodium/lang/ko_kr.json | 68 ++ .../resources/assets/sodium/lang/pt_br.json | 66 ++ .../resources/assets/sodium/lang/ru_ru.json | 66 ++ .../resources/assets/sodium/lang/zh_cn.json | 82 +++ .../assets/sodium/shaders/chunk_gl20.f.glsl | 54 ++ .../assets/sodium/shaders/chunk_gl20.v.glsl | 40 ++ .../assets/sodium/textures/gui/arrows.png | Bin 0 -> 119 bytes src/main/resources/mcmod.info | 11 + src/main/resources/rubidium.mixins.json | 75 +++ 324 files changed, 21798 insertions(+), 1 deletion(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/RubidiumStub.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/compat/FlywheelCompat.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/CCLCompat.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/SinkingVertexBuilder.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/compat/forge/ForgeBlockRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/compat/modernui/MuiGuiScaleHook.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/GlObject.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferArena.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferSegment.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/array/GlVertexArray.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttribute.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexFormat.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBuffer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferTarget.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferUsage.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlMutableBuffer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/VertexData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/device/CommandList.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/device/RenderDevice.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlBufferCopyFunctions.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlFunctions.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlInstancedArrayFunctions.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlVertexArrayFunctions.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderBindingPoint.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderConstants.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderWorkarounds.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlFallbackTessellation.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlPrimitiveType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlTessellation.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/TessellationBinding.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/util/BufferSlice.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/util/GlMultiDrawBatch.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/util/MemoryUtilHelper.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/FormattedTextProvider.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/LightMode.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipelineProvider.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/data/QuadLightData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoCompletionFlags.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VanillaVertexTypes.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferView.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriter.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterNio.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterNio.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterNio.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterNio.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterNio.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterNio.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/AbstractVertexTransformer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/SpriteTexturedVertexTransformer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/BlittableVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/BufferVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/ChunkVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/CustomVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkCameraContext.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkGraphicsState.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderColumn.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawGraphicsState.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkOneshotGraphicsState.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkRenderBackendOneshot.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBufferSorter.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildResult.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuffers.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuffers.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelVertexTransformer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/FallbackChunkModelBuffers.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkFaceFlags.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphIterationQueue.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphNode.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkMeshData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkMeshAttribute.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkModelOffset.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/DefaultModelVertexFormats.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ModelVertexSink.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ModelVertexUtil.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterNio.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterNio.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderList.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderListIterator.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegion.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkFogMode.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderBuildTask.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderEmptyBuildTask.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/entity/EntityLightSampler.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteExtended.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/Dim2i.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorABGR.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorARGB.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorMixer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorU8.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/math/FrustumExtended.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix3fExtended.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix4fExtended.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/math/MatrixUtil.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/rand/SplitMixRandom.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/rand/XoRoShiRoRandom.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/task/CancellationSource.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/ChunkStatusListener.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/ChunkStatusListenerManager.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/ClientWorldExtended.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PackedIntegerArrayExtended.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalette.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalleteArray.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/common/config/Option.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/common/util/IdTable.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/common/util/ListUtil.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/common/util/collections/DequeDrain.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/SodiumMixinPlugin.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/MixinDirection.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/frustum/MixinFrustum.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinGameRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix3f.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix4f.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinBlockColors.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinItemColors.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBufferBuilder.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexConsumer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexFormat.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinBlockModelRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinBufferBuilder.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinVertexFormat.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_sort/MixinBufferBuilder.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinBufferBuilder.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinSpriteTexturedVertexConsumer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinWorldRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinChunkBuilder.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientChunkManager.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientWorld.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPackedIntegerArray.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPalettedContainer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinRenderLayer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinCuboid.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinModelPart.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinEntityRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinPaintingEntityRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBackgroundRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBlock.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinFluid.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/MixinDebugHud.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_fps_pie/MixinMinecraftClient.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_loading_screen/MixinLevelLoadingScreen.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_status_bars/MixinInGameHud.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/font/MixinGlyphRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/item/MixinItemRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinMatrixStack.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinVertexConsumer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinMultipartBakedModel.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinWeightedBakedModel.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/optimized_bamboo/MixinBambooBlock.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinGameOptions.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinInGameHud.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinMinecraftClient.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinOptionsScreen.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinWorldRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/particle/fast_render/MixinBillboardParticle.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/MixinTexturedRenderLayers.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinLeavesBlock.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinRenderLayers.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/sky/MixinWorldRenderer.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSprite.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteAtlasTexture.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteBillboardParticle.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/world_ticking/MixinClientWorld.java create mode 100644 src/main/resources/META-INF/sodium_at.cfg create mode 100644 src/main/resources/assets/sodium/lang/en_us.json create mode 100644 src/main/resources/assets/sodium/lang/es_ar.json create mode 100644 src/main/resources/assets/sodium/lang/es_es.json create mode 100644 src/main/resources/assets/sodium/lang/es_mx.json create mode 100644 src/main/resources/assets/sodium/lang/ko_kr.json create mode 100644 src/main/resources/assets/sodium/lang/pt_br.json create mode 100644 src/main/resources/assets/sodium/lang/ru_ru.json create mode 100644 src/main/resources/assets/sodium/lang/zh_cn.json create mode 100644 src/main/resources/assets/sodium/shaders/chunk_gl20.f.glsl create mode 100644 src/main/resources/assets/sodium/shaders/chunk_gl20.v.glsl create mode 100644 src/main/resources/assets/sodium/textures/gui/arrows.png create mode 100644 src/main/resources/rubidium.mixins.json diff --git a/README.MD b/README.MD index 3bdba195d..d3ca9e77d 100644 --- a/README.MD +++ b/README.MD @@ -10,4 +10,4 @@ Not yet in an usable state * Includes backported code from [Occulus](https://github.com/Asek3/Oculus) and [Iris](https://github.com/IrisShaders/Iris) under the LGPL * eigenraven and vlaetansky for getting the original ShaderMod compiling again * eigenraven, Caedis, glowredman, and mitchej123 for the conversion of ASM to Mixin - +* JellySquid & the CaffeineMC team, for making Sodium in the first place and embeddedt for [Embeddium](https://github.com/embeddedt/embeddium/commit/dc59ca357c25beefd6288f0d1d40b4cd8e670ab8) under the [LGPL 3.0](https://github.com/embeddedt/embeddium/blob/16.x/forge/LICENSE) and select files under the LGPL-2.1 diff --git a/src/main/java/me/jellysquid/mods/sodium/client/RubidiumStub.java b/src/main/java/me/jellysquid/mods/sodium/client/RubidiumStub.java new file mode 100644 index 000000000..1900bc2fa --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/RubidiumStub.java @@ -0,0 +1,14 @@ +package me.jellysquid.mods.sodium.client; + +import net.minecraftforge.fml.ExtensionPoint; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.network.FMLNetworkConstants; +import org.apache.commons.lang3.tuple.Pair; + +@Mod("rubidium") +public class RubidiumStub { + public RubidiumStub() { + ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java new file mode 100644 index 000000000..e6b609587 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -0,0 +1,76 @@ +package me.jellysquid.mods.sodium.client; + +import me.jellysquid.mods.sodium.client.compat.ccl.CCLCompat; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import net.minecraftforge.fml.ExtensionPoint; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.fml.loading.FMLPaths; +import net.minecraftforge.fml.network.FMLNetworkConstants; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Mod(SodiumClientMod.MODID) +public class SodiumClientMod { + private static SodiumGameOptions CONFIG; + public static Logger LOGGER = LogManager.getLogger("Embeddium"); + + private static String MOD_VERSION; + + public static final String MODID = "embeddium"; + + public static boolean flywheelLoaded; + public static boolean cclLoaded; + + public SodiumClientMod() { + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onInitializeClient); + + ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); + } + + public void onInitializeClient(final FMLClientSetupEvent event) { + flywheelLoaded = ModList.get().isLoaded("flywheel"); + cclLoaded = ModList.get().isLoaded("codechickenlib"); + MOD_VERSION = ModList.get().getModContainerById(MODID).get().getModInfo().getVersion().toString(); + + if(cclLoaded) { + CCLCompat.init(); + } + } + + public static SodiumGameOptions options() { + if (CONFIG == null) { + CONFIG = loadConfig(); + } + + return CONFIG; + } + + public static Logger logger() { + if (LOGGER == null) { + LOGGER = LogManager.getLogger("Embeddium"); + } + + return LOGGER; + } + + private static SodiumGameOptions loadConfig() { + return SodiumGameOptions.load(FMLPaths.CONFIGDIR.get().resolve("rubidium-options.json")); + } + + public static String getVersion() { + if (MOD_VERSION == null) { + throw new NullPointerException("Mod version hasn't been populated yet"); + } + + return MOD_VERSION; + } + + public static boolean isDirectMemoryAccessEnabled() { + return options().advanced.allowDirectMemoryAccess; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java new file mode 100644 index 000000000..92812e043 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java @@ -0,0 +1,19 @@ +package me.jellysquid.mods.sodium.client.buffer; + +import net.minecraft.client.render.VertexFormatElement; + +public interface ExtendedVertexFormat { + Element[] embeddium$getExtendedElements(); + + class Element { + public final VertexFormatElement actual; + public final int increment; + public final int byteLength; + + public Element(VertexFormatElement actual, int increment, int byteLength) { + this.actual = actual; + this.increment = increment; + this.byteLength = byteLength; + } + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compat/FlywheelCompat.java b/src/main/java/me/jellysquid/mods/sodium/client/compat/FlywheelCompat.java new file mode 100644 index 000000000..9f631cbae --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/compat/FlywheelCompat.java @@ -0,0 +1,32 @@ +package me.jellysquid.mods.sodium.client.compat; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.block.entity.BlockEntity; + +import java.util.Collection; + +public class FlywheelCompat { + + /** + * Filters a collection of TileEntities to avoid rendering conflicts with Flywheel. + * + * @param blockEntities The collection to be filtered. + */ + public static void filterBlockEntityList(Collection blockEntities) { + if (SodiumClientMod.flywheelLoaded && Backend.getInstance().canUseInstancing()) { + InstancedRenderRegistry r = InstancedRenderRegistry.getInstance(); + blockEntities.removeIf(r::shouldSkipRender); + } + } + + public static boolean isSkipped(BlockEntity be) { + if(!SodiumClientMod.flywheelLoaded) + return false; + if(!Backend.getInstance().canUseInstancing()) + return false; + return InstancedRenderRegistry.getInstance().shouldSkipRender(be); + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/CCLCompat.java b/src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/CCLCompat.java new file mode 100644 index 000000000..ad275a559 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/CCLCompat.java @@ -0,0 +1,84 @@ +package me.jellysquid.mods.sodium.client.compat.ccl; + +import codechicken.lib.render.block.BlockRenderingRegistry; +import codechicken.lib.render.block.ICCBlockRenderer; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.FluidState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; +import net.minecraftforge.registries.IRegistryDelegate; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class CCLCompat { + + public static Map, ICCBlockRenderer> customBlockRenderers; + public static Map, ICCBlockRenderer> customFluidRenderers; + public static List customGlobalRenderers; + + public static @NotNull List getCustomRenderers(final @NotNull BlockRenderView world, final @NotNull BlockPos pos) { + final BlockState state = world.getBlockState(pos); + final Block block = state.getBlock(); + + final FluidState fluidState = state.getFluidState(); + final Fluid fluid = fluidState.getFluid(); + + if(customGlobalRenderers == null) + return new ArrayList<>(); + + final ArrayList renderers = new ArrayList<>(customGlobalRenderers); + + if(customBlockRenderers != null) + for (final Map.Entry, ICCBlockRenderer> entry : customBlockRenderers.entrySet()) { + final Block entryBlock = entry.getKey().get(); + + if (entryBlock.is(block)) { + renderers.add(entry.getValue()); + } + } + + if(customFluidRenderers != null) + for (final Map.Entry, ICCBlockRenderer> entry : customFluidRenderers.entrySet()) { + final Fluid entryFluid = entry.getKey().get(); + + if (entryFluid.matchesType(fluid)) { + renderers.add(entry.getValue()); + } + } + + return renderers; + } + + + @SuppressWarnings("unchecked") + public static void init() { + try { + SodiumClientMod.LOGGER.info("Retrieving block renderers"); + final Field blockRenderersField = BlockRenderingRegistry.class.getDeclaredField("blockRenderers"); + blockRenderersField.setAccessible(true); + customBlockRenderers = (Map, ICCBlockRenderer>) blockRenderersField.get(null); + + SodiumClientMod.LOGGER.info("Retrieving fluid renderers"); + final Field fluidRenderersField = BlockRenderingRegistry.class.getDeclaredField("fluidRenderers"); + fluidRenderersField.setAccessible(true); + customFluidRenderers = (Map, ICCBlockRenderer>) fluidRenderersField.get(null); + + SodiumClientMod.LOGGER.info("Retrieving global renderers"); + final Field globalRenderersField = BlockRenderingRegistry.class.getDeclaredField("globalRenderers"); + globalRenderersField.setAccessible(true); + customGlobalRenderers = (List) globalRenderersField.get(null); + } + catch (final @NotNull Throwable t) { + SodiumClientMod.LOGGER.error("Could not retrieve custom renderers"); + } + + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/SinkingVertexBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/SinkingVertexBuilder.java new file mode 100644 index 000000000..f873714b8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/SinkingVertexBuilder.java @@ -0,0 +1,191 @@ +package me.jellysquid.mods.sodium.client.compat.ccl; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.util.math.Direction; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import javax.annotation.Nonnull; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + +/** + * A allocation-free {@link IVertexBuilder} implementation + * which pipes vertices into a {@link ModelVertexSink}. + * + * @author KitsuneAlex + */ +@OnlyIn(Dist.CLIENT) +public final class SinkingVertexBuilder implements VertexConsumer { + private final ByteBuffer buffer = ByteBuffer.allocateDirect(2097152).order(ByteOrder.nativeOrder()); + private final int[] sideCount = new int[ModelQuadFacing.VALUES.length]; + private int currentVertex; + + private float x; + private float y; + private float z; + private float nx; + private float ny; + private float nz; + private float u; + private float v; + private int color; + private int light; + + private static final ThreadLocal instance = ThreadLocal.withInitial(SinkingVertexBuilder::new); + + @Nonnull + public static SinkingVertexBuilder getInstance() { + return instance.get(); + } + + @Nonnull + @Override + public VertexConsumer vertex(double x, double y, double z) { + this.x = (float) x; + this.y = (float) y; + this.z = (float) z; + return this; + } + + @Nonnull + @Override + public VertexConsumer color(int r, int g, int b, int a) { + color = ((a & 255) << 24) | ((b & 255) << 16) | ((g & 255) << 8) | (r & 255); + // Colour.flipABGR(Colour.packRGBA(r, g, b, a)); // We need ABGR so we compose it on the fly + return this; + } + + @Nonnull + @Override + public VertexConsumer texture(float u, float v) { + this.u = u; + this.v = v; + return this; + } + + @Nonnull + @Override + public VertexConsumer overlay(int u, int v) { + return this; + } + + @Nonnull + @Override + public VertexConsumer light(int u, int v) { + light = (v << 16) | u; // Compose lightmap coords into raw light value 0xVVVV_UUUU + return this; + } + + @Nonnull + @Override + public VertexConsumer normal(float x, float y, float z) { + nx = x; + ny = y; + nz = z; + return this; + } + + @Override + public void next() { + final Direction dir = Direction.fromVector((int) nx, (int) ny, (int) nz); + final int normal = dir != null ? dir.ordinal() : -1; + + // Write the current quad vertex's normal, position, UVs, color and raw light values + buffer.putInt(normal); + buffer.putFloat(x); + buffer.putFloat(y); + buffer.putFloat(z); + buffer.putFloat(u); + buffer.putFloat(v); + buffer.putInt(color); + buffer.putInt(light); + // We store 32 bytes per vertex + + resetCurrentVertex(); // Reset the current vertex values + currentVertex++; + } + + public void reset() { + buffer.rewind(); + currentVertex = 0; + Arrays.fill(sideCount, 0); + resetCurrentVertex(); + } + + public void flush(@Nonnull ChunkModelBuffers buffers) { + final int numQuads = currentVertex >> 2; + + for (int quadIdx = 0; quadIdx < numQuads; quadIdx++) { + final int normal = buffer.getInt((quadIdx << 2) << 5); + final Direction dir = normal != -1 ? DirectionUtil.ALL_DIRECTIONS[normal] : null; + final ModelQuadFacing facing = dir != null ? ModelQuadFacing.fromDirection(dir) : ModelQuadFacing.UNASSIGNED; + sideCount[facing.ordinal()]++; + } + + for (final ModelQuadFacing facing : ModelQuadFacing.VALUES) { + final int count = sideCount[facing.ordinal()]; + if (count == 0) { + continue; + } + buffers.getSink(facing).ensureCapacity(count << 2); + } + + final int byteSize = currentVertex << 5; + byte sideMask = 0; + + buffer.rewind(); + + while (buffer.position() < byteSize) { + final int normal = buffer.getInt(); // Fetch first normal for pre-selecting the vertex sink + final Direction dir = normal != -1 ? DirectionUtil.ALL_DIRECTIONS[normal] : null; + final ModelQuadFacing facing = dir != null ? ModelQuadFacing.fromDirection(dir) : ModelQuadFacing.UNASSIGNED; + final int facingIdx = facing.ordinal(); + + final ModelVertexSink sink = buffers.getSink(facing); + + writeQuadVertex(sink); + buffer.getInt(); + writeQuadVertex(sink); + buffer.getInt(); + writeQuadVertex(sink); + buffer.getInt(); + writeQuadVertex(sink); + + sideMask |= 1 << facingIdx; + } + + for (final ModelQuadFacing facing : ModelQuadFacing.VALUES) { + if (((sideMask >> facing.ordinal()) & 1) == 0) { + continue; + } + + buffers.getSink(facing).flush(); + } + } + + private void writeQuadVertex(@Nonnull ModelVertexSink sink) { + final float x = buffer.getFloat(); + final float y = buffer.getFloat(); + final float z = buffer.getFloat(); + final float u = buffer.getFloat(); + final float v = buffer.getFloat(); + final int color = buffer.getInt(); + final int light = buffer.getInt(); + + sink.writeQuad(x, y, z, color, u, v, light); + } + + private void resetCurrentVertex() { + x = y = z = 0F; + nx = ny = nz = 0F; + u = v = 0F; + color = 0xFFFF_FFFF; + light = 0; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compat/forge/ForgeBlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/compat/forge/ForgeBlockRenderer.java new file mode 100644 index 000000000..71538df9f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/compat/forge/ForgeBlockRenderer.java @@ -0,0 +1,111 @@ +package me.jellysquid.mods.sodium.client.compat.forge; + +import me.jellysquid.mods.sodium.client.model.light.LightMode; +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.occlusion.BlockOcclusionCache; +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockRenderView; +import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.pipeline.VertexBufferConsumer; +import net.minecraftforge.client.model.pipeline.VertexLighterFlat; +import net.minecraftforge.client.model.pipeline.VertexLighterSmoothAo; +import net.minecraftforge.common.ForgeConfig; + +import java.util.List; +import java.util.Random; + +/** + * Utility class for BlockRenderer, that uses the Forge lighting pipeline. + * + * This class is derived from Forge's renderer, and is licensed under LGPL-2.1. As the class is a standalone class file, + * it may be replaced in an existing copy of Embeddium with an alternate LGPL-2.1 implementation. + */ +public class ForgeBlockRenderer { + private final BlockColors colors = MinecraftClient.getInstance().getBlockColors(); + private final ThreadLocal lighterFlat = ThreadLocal.withInitial(() -> new VertexLighterFlat(colors)); + private final ThreadLocal lighterSmooth = ThreadLocal.withInitial(() -> new VertexLighterSmoothAo(colors)); + private final ThreadLocal consumerFlat = ThreadLocal.withInitial(VertexBufferConsumer::new); + private final ThreadLocal consumerSmooth = ThreadLocal.withInitial(VertexBufferConsumer::new); + + + private static boolean useForgeLightingPipeline = false; + + public static void init() { + useForgeLightingPipeline = ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.get(); + } + + public static boolean useForgeLightingPipeline() { + return useForgeLightingPipeline; + } + + private void processQuad(ChunkRenderData.Builder renderData, BakedQuad quad) { + ModelQuadView src = (ModelQuadView)quad; + Sprite sprite = src.rubidium$getSprite(); + + if (sprite != null) { + renderData.addSprite(sprite); + } + } + + public boolean renderBlock(LightMode mode, BlockState state, BlockPos pos, BlockRenderView world, BakedModel model, MatrixStack stack, + VertexConsumer buffer, Random random, long seed, IModelData data, boolean checkSides, BlockOcclusionCache sideCache, + ChunkRenderData.Builder renderData) { + VertexBufferConsumer consumer = mode == LightMode.FLAT ? this.consumerFlat.get() : this.consumerSmooth.get(); + consumer.setBuffer(buffer); + VertexLighterFlat lighter = mode == LightMode.FLAT ? this.lighterFlat.get() : this.lighterSmooth.get(); + lighter.setParent(consumer); + lighter.setTransform(stack.peek()); + + // render + lighter.setWorld(world); + lighter.setState(state); + lighter.setBlockPos(pos); + boolean empty = true; + random.setSeed(seed); + + List quads = model.getQuads(state, null, random, data); + if(!quads.isEmpty()) { + lighter.updateBlockInfo(); + empty = false; + // noinspection ForLoopReplaceableByForEach + for(int i = 0; i < quads.size(); i++) { + BakedQuad quad = quads.get(i); + quad.pipe(lighter); + processQuad(renderData, quad); + } + } + + for(Direction side : DirectionUtil.ALL_DIRECTIONS) + { + random.setSeed(seed); + quads = model.getQuads(state, side, random, data); + if(!quads.isEmpty()) + { + if(!checkSides || sideCache.shouldDrawSide(state, world, pos, side)) + { + if(empty) lighter.updateBlockInfo(); + empty = false; + // noinspection ForLoopReplaceableByForEach + for(int i = 0; i < quads.size(); i++) { + BakedQuad quad = quads.get(i); + quad.pipe(lighter); + processQuad(renderData, quad); + } + } + } + } + lighter.resetBlockInfo(); + return !empty; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compat/modernui/MuiGuiScaleHook.java b/src/main/java/me/jellysquid/mods/sodium/client/compat/modernui/MuiGuiScaleHook.java new file mode 100644 index 000000000..4c8c9d551 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/compat/modernui/MuiGuiScaleHook.java @@ -0,0 +1,45 @@ +package me.jellysquid.mods.sodium.client.compat.modernui; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.client.MinecraftClient; + +import java.lang.reflect.Method; +import java.util.stream.Stream; + +/** + * Ugly hack to get around Modern UI overwriting calculateScaleFactor and not conforming to vanilla standards + * by returning the max size when scale = 0. + */ +public class MuiGuiScaleHook { + private static final Method calcGuiScalesMethod; + static { + calcGuiScalesMethod = Stream.of("icyllis.modernui.forge.MForgeCompat", "icyllis.modernui.forge.MuiForgeApi").flatMap(clzName -> { + try { + return Stream.of(Class.forName(clzName)); + } catch(Throwable e) { + return Stream.of(); + } + }).flatMap(clz -> { + try { + Method m = clz.getDeclaredMethod("calcGuiScales"); + m.setAccessible(true); + return Stream.of(m); + } catch(Throwable e) { + return Stream.of(); + } + }).findFirst().orElse(null); + if(calcGuiScalesMethod != null) + SodiumClientMod.logger().info("Found ModernUI GUI scale hook"); + } + public static int getMaxGuiScale() { + if(calcGuiScalesMethod != null) { + try { + return ((int)calcGuiScalesMethod.invoke(null)) & 0xf; + } catch(Throwable e) { + e.printStackTrace(); + } + } + // default vanilla logic + return MinecraftClient.getInstance().getWindow().calculateScaleFactor(0, MinecraftClient.getInstance().forcesUnicodeFont()); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/GlObject.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/GlObject.java new file mode 100644 index 000000000..d75f94ece --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/GlObject.java @@ -0,0 +1,48 @@ +package me.jellysquid.mods.sodium.client.gl; + +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; + +/** + * An abstract object used to represent objects in OpenGL code safely. This class hides the direct handle to a OpenGL + * object, requiring that it first be checked by all callers to prevent null pointer de-referencing. However, this will + * not stop code from cloning the handle and trying to use it after it has been deleted and as such should not be + * relied on too heavily. + */ +public class GlObject { + private static final int INVALID_HANDLE = Integer.MIN_VALUE; + + protected final RenderDevice device; + private int handle = INVALID_HANDLE; + + public GlObject(RenderDevice owner) { + this.device = owner; + } + + protected final void setHandle(int handle) { + this.handle = handle; + } + + public final int handle() { + this.checkHandle(); + + return this.handle; + } + + protected final void checkHandle() { + if (!this.isHandleValid()) { + throw new IllegalStateException("Handle is not valid"); + } + } + + protected final boolean isHandleValid() { + return this.handle != INVALID_HANDLE; + } + + public final void invalidateHandle() { + this.handle = INVALID_HANDLE; + } + + public RenderDevice getDevice() { + return this.device; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferArena.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferArena.java new file mode 100644 index 000000000..3b4a7b707 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferArena.java @@ -0,0 +1,134 @@ +package me.jellysquid.mods.sodium.client.gl.arena; + +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferUsage; +import me.jellysquid.mods.sodium.client.gl.buffer.GlMutableBuffer; +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; + +import java.util.Set; + +public class GlBufferArena { + private static final GlBufferUsage BUFFER_USAGE = GlBufferUsage.GL_DYNAMIC_DRAW; + + private final RenderDevice device; + private final int resizeIncrement; + + private final Set freeRegions = new ObjectLinkedOpenHashSet<>(); + + private GlMutableBuffer vertexBuffer; + + private int position; + private int capacity; + private int allocCount; + + public GlBufferArena(RenderDevice device, int initialSize, int resizeIncrement) { + this.device = device; + + try (CommandList commands = device.createCommandList()) { + this.vertexBuffer = commands.createMutableBuffer(BUFFER_USAGE); + commands.allocateBuffer(GlBufferTarget.COPY_WRITE_BUFFER, this.vertexBuffer, initialSize); + } + + this.resizeIncrement = resizeIncrement; + this.capacity = initialSize; + } + + private void resize(CommandList commandList, int newCapacity) { + GlMutableBuffer src = this.vertexBuffer; + GlMutableBuffer dst = commandList.createMutableBuffer(BUFFER_USAGE); + + commandList.allocateBuffer(GlBufferTarget.COPY_WRITE_BUFFER, dst, newCapacity); + commandList.copyBufferSubData(src, dst, 0, 0, this.position); + commandList.deleteBuffer(src); + + this.vertexBuffer = dst; + this.capacity = newCapacity; + } + + public void prepareBuffer(CommandList commandList, int bytes) { + if (this.position + bytes >= this.capacity) { + this.resize(commandList, this.getNextSize(bytes)); + } + } + + public GlBufferSegment uploadBuffer(CommandList commandList, GlBuffer readBuffer, int readOffset, int byteCount) { + this.prepareBuffer(commandList, byteCount); + + GlBufferSegment segment = this.alloc(byteCount); + + commandList.copyBufferSubData(readBuffer, this.vertexBuffer, readOffset, segment.getStart(), byteCount); + + return segment; + } + + private int getNextSize(int len) { + return Math.max(this.capacity + this.resizeIncrement, this.capacity + len); + } + + public void free(GlBufferSegment segment) { + if (!this.freeRegions.add(segment)) { + throw new IllegalArgumentException("Segment already freed"); + } + + this.allocCount--; + } + + private GlBufferSegment alloc(int len) { + GlBufferSegment segment = this.allocReuse(len); + + if (segment == null) { + segment = new GlBufferSegment(this, this.position, len); + + this.position += len; + } + + this.allocCount++; + + return segment; + } + + private GlBufferSegment allocReuse(int len) { + GlBufferSegment bestSegment = null; + + for (GlBufferSegment segment : this.freeRegions) { + if (segment.getLength() < len) { + continue; + } + + if (bestSegment == null || bestSegment.getLength() > segment.getLength()) { + bestSegment = segment; + } + } + + if (bestSegment == null) { + return null; + } + + this.freeRegions.remove(bestSegment); + + int excess = bestSegment.getLength() - len; + + if (excess > 0) { + this.freeRegions.add(new GlBufferSegment(this, bestSegment.getStart() + len, excess)); + } + + return new GlBufferSegment(this, bestSegment.getStart(), len); + } + + public void delete() { + try (CommandList commands = this.device.createCommandList()) { + commands.deleteBuffer(this.vertexBuffer); + } + } + + public boolean isEmpty() { + return this.allocCount <= 0; + } + + public GlBuffer getBuffer() { + return this.vertexBuffer; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferSegment.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferSegment.java new file mode 100644 index 000000000..295d5bff2 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferSegment.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.sodium.client.gl.arena; + +public class GlBufferSegment { + private final GlBufferArena arena; + private final int start; + private final int len; + + GlBufferSegment(GlBufferArena arena, int start, int len) { + this.arena = arena; + this.start = start; + this.len = len; + } + + public int getStart() { + return this.start; + } + + public int getLength() { + return this.len; + } + + public void delete() { + this.arena.free(this); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/array/GlVertexArray.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/array/GlVertexArray.java new file mode 100644 index 000000000..d72612acc --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/array/GlVertexArray.java @@ -0,0 +1,22 @@ +package me.jellysquid.mods.sodium.client.gl.array; + +import me.jellysquid.mods.sodium.client.gl.GlObject; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gl.func.GlFunctions; + +/** + * Provides Vertex Array functionality on supported platforms. + */ +public class GlVertexArray extends GlObject { + public static final int NULL_ARRAY_ID = 0; + + public GlVertexArray(RenderDevice owner) { + super(owner); + + if (!GlFunctions.isVertexArraySupported()) { + throw new UnsupportedOperationException("Vertex arrays are unsupported on this platform"); + } + + this.setHandle(GlFunctions.VERTEX_ARRAY.glGenVertexArrays()); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java new file mode 100644 index 000000000..344656465 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java @@ -0,0 +1,11 @@ +package me.jellysquid.mods.sodium.client.gl.attribute; + +import net.minecraft.client.render.VertexFormat; + +public interface BufferVertexFormat { + static BufferVertexFormat from(VertexFormat format) { + return (BufferVertexFormat) format; + } + + int getStride(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttribute.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttribute.java new file mode 100644 index 000000000..0cadb2432 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttribute.java @@ -0,0 +1,55 @@ +package me.jellysquid.mods.sodium.client.gl.attribute; + +public class GlVertexAttribute { + private final int format; + private final int count; + private final int pointer; + private final int size; + private final int stride; + + private final boolean normalized; + + /** + * @param format The format used + * @param count The number of components in the vertex attribute + * @param normalized Specifies whether or not fixed-point data values should be normalized (true) or used directly + * as fixed-point values (false) + * @param pointer The offset to the first component in the attribute + */ + public GlVertexAttribute(GlVertexAttributeFormat format, int count, boolean normalized, int pointer, int stride) { + this(format.getGlFormat(), format.getSize() * count, count, normalized, pointer, stride); + } + + protected GlVertexAttribute(int format, int size, int count, boolean normalized, int pointer, int stride) { + this.format = format; + this.size = size; + this.count = count; + this.normalized = normalized; + this.pointer = pointer; + this.stride = stride; + } + + public int getSize() { + return this.size; + } + + public int getPointer() { + return this.pointer; + } + + public int getCount() { + return this.count; + } + + public int getFormat() { + return this.format; + } + + public boolean isNormalized() { + return this.normalized; + } + + public int getStride() { + return this.stride; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java new file mode 100644 index 000000000..233808eaa --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java @@ -0,0 +1,17 @@ +package me.jellysquid.mods.sodium.client.gl.attribute; + +import me.jellysquid.mods.sodium.client.gl.shader.ShaderBindingPoint; + +public class GlVertexAttributeBinding extends GlVertexAttribute { + private final int index; + + public GlVertexAttributeBinding(ShaderBindingPoint bindingPoint, GlVertexAttribute attribute) { + super(attribute.getFormat(), attribute.getSize(), attribute.getCount(), attribute.isNormalized(), attribute.getPointer(), attribute.getStride()); + + this.index = bindingPoint.getGenericAttributeIndex(); + } + + public int getIndex() { + return this.index; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java new file mode 100644 index 000000000..09e5b5e67 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java @@ -0,0 +1,28 @@ +package me.jellysquid.mods.sodium.client.gl.attribute; + +import org.lwjgl.opengl.GL20C; + +/** + * An enumeration over the supported data types that can be used for vertex attributes. + */ +public class GlVertexAttributeFormat { + public static final GlVertexAttributeFormat FLOAT = new GlVertexAttributeFormat(GL20C.GL_FLOAT, 4); + public static final GlVertexAttributeFormat UNSIGNED_SHORT = new GlVertexAttributeFormat(GL20C.GL_UNSIGNED_SHORT, 2); + public static final GlVertexAttributeFormat UNSIGNED_BYTE = new GlVertexAttributeFormat(GL20C.GL_UNSIGNED_BYTE, 1); + + private final int glId; + private final int size; + + private GlVertexAttributeFormat(int glId, int size) { + this.glId = glId; + this.size = size; + } + + public int getSize() { + return this.size; + } + + public int getGlFormat() { + return this.glId; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexFormat.java new file mode 100644 index 000000000..55b1d1028 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexFormat.java @@ -0,0 +1,123 @@ +package me.jellysquid.mods.sodium.client.gl.attribute; + +import java.util.EnumMap; + +/** + * Provides a generic vertex format which contains the attributes defined by {@param T}. Other code can then retrieve + * the attributes and work with encoded data in a generic manner without needing to rely on a specific format. + * + * @param The enumeration over the vertex attributes + */ +public class GlVertexFormat> implements BufferVertexFormat { + private final Class attributeEnum; + private final EnumMap attributesKeyed; + private final GlVertexAttribute[] attributesArray; + + private final int stride; + + public GlVertexFormat(Class attributeEnum, EnumMap attributesKeyed, int stride) { + this.attributeEnum = attributeEnum; + this.attributesKeyed = attributesKeyed; + this.attributesArray = attributesKeyed.values().toArray(new GlVertexAttribute[0]); + this.stride = stride; + } + + public static > Builder builder(Class type, int stride) { + return new Builder<>(type, stride); + } + + /** + * Returns the {@link GlVertexAttribute} of this vertex format bound to the type {@param name}. + * @throws NullPointerException If the attribute does not exist in this format + */ + public GlVertexAttribute getAttribute(T name) { + GlVertexAttribute attr = this.attributesKeyed.get(name); + + if (attr == null) { + throw new NullPointerException("No attribute exists for " + name.toString()); + } + + return attr; + } + + /** + * @return The stride (or the size of) the vertex format in bytes + */ + public int getStride() { + return this.stride; + } + + @Override + public String toString() { + return String.format("GlVertexFormat<%s>{attributes=%d,stride=%d}", this.attributeEnum.getName(), + this.attributesKeyed.size(), this.stride); + } + + public GlVertexAttribute[] getAttributesArray() { + return this.attributesArray; + } + + public static class Builder> { + private final EnumMap attributes; + private final Class type; + private final int stride; + + public Builder(Class type, int stride) { + this.type = type; + this.attributes = new EnumMap<>(type); + this.stride = stride; + } + + public Builder addElement(T type, int pointer, GlVertexAttributeFormat format, int count, boolean normalized) { + return this.addElement(type, new GlVertexAttribute(format, count, normalized, pointer, this.stride)); + } + + /** + * Adds an vertex attribute which will be bound to the given generic attribute type. + * + * @param type The generic attribute type + * @param attribute The attribute to bind + * @throws IllegalStateException If an attribute is already bound to the generic type + */ + private Builder addElement(T type, GlVertexAttribute attribute) { + if ((attribute.getPointer() >= this.stride)) { + throw new IllegalArgumentException("Element starts outside vertex format"); + } + + if ((attribute.getPointer() + attribute.getSize() > this.stride)) { + throw new IllegalArgumentException("Element extends outside vertex format"); + } + + if (this.attributes.put(type, attribute) != null) { + throw new IllegalStateException("Generic attribute " + type.name() + " already defined in vertex format"); + } + + return this; + } + + /** + * Creates a {@link GlVertexFormat} from the current builder. + */ + public GlVertexFormat build() { + int size = 0; + + for (T key : this.type.getEnumConstants()) { + GlVertexAttribute attribute = this.attributes.get(key); + + if (attribute == null) { + throw new NullPointerException("Generic attribute not assigned to enumeration " + key.name()); + } + + size = Math.max(size, attribute.getPointer() + attribute.getSize()); + } + + // The stride must be large enough to cover all attributes. This still allows for additional padding + // to be added to the end of the vertex to accommodate alignment restrictions. + if (this.stride < size) { + throw new IllegalArgumentException("Stride is too small"); + } + + return new GlVertexFormat<>(this.type, this.attributes, this.stride); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBuffer.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBuffer.java new file mode 100644 index 000000000..96bf38c9f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBuffer.java @@ -0,0 +1,23 @@ +package me.jellysquid.mods.sodium.client.gl.buffer; + +import com.mojang.blaze3d.platform.GlStateManager; +import me.jellysquid.mods.sodium.client.gl.GlObject; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; + +public abstract class GlBuffer extends GlObject { + public static final int NULL_BUFFER_ID = 0; + + protected final GlBufferUsage usage; + + protected GlBuffer(RenderDevice owner, GlBufferUsage usage) { + super(owner); + + this.setHandle(GlStateManager.genBuffers()); + + this.usage = usage; + } + + public GlBufferUsage getUsageHint() { + return this.usage; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferTarget.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferTarget.java new file mode 100644 index 000000000..265e222d9 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferTarget.java @@ -0,0 +1,31 @@ +package me.jellysquid.mods.sodium.client.gl.buffer; + +import org.lwjgl.opengl.GL20C; +import org.lwjgl.opengl.GL31C; +import org.lwjgl.opengl.GL40C; + +public enum GlBufferTarget { + ARRAY_BUFFER(GL20C.GL_ARRAY_BUFFER, GL20C.GL_ARRAY_BUFFER_BINDING), + COPY_READ_BUFFER(GL31C.GL_COPY_READ_BUFFER, GL31C.GL_COPY_READ_BUFFER), + COPY_WRITE_BUFFER(GL31C.GL_COPY_WRITE_BUFFER, GL31C.GL_COPY_WRITE_BUFFER), + DRAW_INDIRECT_BUFFER(GL40C.GL_DRAW_INDIRECT_BUFFER, GL40C.GL_DRAW_INDIRECT_BUFFER_BINDING); + + public static final GlBufferTarget[] VALUES = GlBufferTarget.values(); + public static final int COUNT = VALUES.length; + + private final int target; + private final int binding; + + GlBufferTarget(int target, int binding) { + this.target = target; + this.binding = binding; + } + + public int getTargetParameter() { + return this.target; + } + + public int getBindingParameter() { + return this.binding; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferUsage.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferUsage.java new file mode 100644 index 000000000..d7acb91d3 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferUsage.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.sodium.client.gl.buffer; + +import org.lwjgl.opengl.GL20C; + +public enum GlBufferUsage { + GL_STREAM_DRAW(GL20C.GL_STREAM_DRAW), + GL_STREAM_READ(GL20C.GL_STREAM_READ), + GL_STREAM_COPY(GL20C.GL_STREAM_COPY), + GL_STATIC_DRAW(GL20C.GL_STATIC_DRAW), + GL_STATIC_READ(GL20C.GL_STATIC_READ), + GL_STATIC_COPY(GL20C.GL_STATIC_COPY), + GL_DYNAMIC_DRAW(GL20C.GL_DYNAMIC_DRAW), + GL_DYNAMIC_READ(GL20C.GL_DYNAMIC_READ), + GL_DYNAMIC_COPY(GL20C.GL_DYNAMIC_COPY); + + private final int id; + + GlBufferUsage(int id) { + this.id = id; + } + + public int getId() { + return this.id; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlMutableBuffer.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlMutableBuffer.java new file mode 100644 index 000000000..7f1ec5bb2 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlMutableBuffer.java @@ -0,0 +1,23 @@ +package me.jellysquid.mods.sodium.client.gl.buffer; + +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; + +/** + * A mutable buffer type which is supported with OpenGL 1.5+. The buffer's storage can be reallocated at any time + * without needing to re-create the buffer itself. + */ +public class GlMutableBuffer extends GlBuffer { + private long size = 0L; + + public GlMutableBuffer(RenderDevice owner, GlBufferUsage usage) { + super(owner, usage); + } + + public void setSize(long size) { + this.size = size; + } + + public long getSize() { + return this.size; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/VertexData.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/VertexData.java new file mode 100644 index 000000000..d27aba592 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/VertexData.java @@ -0,0 +1,18 @@ +package me.jellysquid.mods.sodium.client.gl.buffer; + +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; + +import java.nio.ByteBuffer; + +/** + * Helper type for tagging the vertex format alongside the raw buffer data. + */ +public class VertexData { + public final GlVertexFormat format; + public final ByteBuffer buffer; + + public VertexData(ByteBuffer buffer, GlVertexFormat format) { + this.format = format; + this.buffer = buffer; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java new file mode 100644 index 000000000..dba0f1cc5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java @@ -0,0 +1,63 @@ +package me.jellysquid.mods.sodium.client.gl.compat; + +import com.mojang.blaze3d.platform.GlStateManager; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkFogMode; +import net.minecraft.client.render.BackgroundRenderer; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.opengl.GL20; + +public class FogHelper { + private static final float FAR_PLANE_THRESHOLD_EXP = (float) Math.log(1.0f / 0.0019f); + private static final float FAR_PLANE_THRESHOLD_EXP2 = MathHelper.sqrt(FAR_PLANE_THRESHOLD_EXP); + + public static float getFogEnd() { + return GlStateManager.FOG.end; + } + + public static float getFogStart() { + return GlStateManager.FOG.start; + } + + public static float getFogDensity() { + return GlStateManager.FOG.density; + } + + /** + * Retrieves the current fog mode from the fixed-function pipeline. + */ + public static ChunkFogMode getFogMode() { + int mode = GlStateManager.FOG.mode; + + if(mode == 0 || !GlStateManager.FOG.capState.state) + return ChunkFogMode.NONE; + + switch (mode) { + case GL20.GL_EXP2: + case GL20.GL_EXP: + return ChunkFogMode.EXP2; + case GL20.GL_LINEAR: + return ChunkFogMode.LINEAR; + default: + throw new UnsupportedOperationException("Unknown fog mode: " + mode); + } + } + + public static float getFogCutoff() { + int mode = GlStateManager.FOG.mode; + + switch (mode) { + case GL20.GL_LINEAR: + return getFogEnd(); + case GL20.GL_EXP: + return FAR_PLANE_THRESHOLD_EXP / getFogDensity(); + case GL20.GL_EXP2: + return FAR_PLANE_THRESHOLD_EXP2 / getFogDensity(); + default: + return 0.0f; + } + } + + public static float[] getFogColor() { + return new float[]{BackgroundRenderer.red, BackgroundRenderer.green, BackgroundRenderer.blue, 1.0F}; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/CommandList.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/CommandList.java new file mode 100644 index 000000000..f1678c6f7 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/CommandList.java @@ -0,0 +1,56 @@ +package me.jellysquid.mods.sodium.client.gl.device; + +import me.jellysquid.mods.sodium.client.gl.array.GlVertexArray; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferUsage; +import me.jellysquid.mods.sodium.client.gl.buffer.GlMutableBuffer; +import me.jellysquid.mods.sodium.client.gl.buffer.VertexData; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlPrimitiveType; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; +import me.jellysquid.mods.sodium.client.gl.tessellation.TessellationBinding; + +import java.nio.ByteBuffer; + +public interface CommandList extends AutoCloseable { + GlVertexArray createVertexArray(); + + GlMutableBuffer createMutableBuffer(GlBufferUsage usage); + + GlTessellation createTessellation(GlPrimitiveType primitiveType, TessellationBinding[] bindings); + + void bindVertexArray(GlVertexArray array); + + default void uploadData(GlMutableBuffer glBuffer, VertexData data) { + this.uploadData(glBuffer, data.buffer); + } + + void uploadData(GlMutableBuffer glBuffer, ByteBuffer byteBuffer); + + void copyBufferSubData(GlBuffer src, GlMutableBuffer dst, long readOffset, long writeOffset, long bytes); + + void bindBuffer(GlBufferTarget target, GlBuffer buffer); + + void unbindBuffer(GlBufferTarget target); + + void unbindVertexArray(); + + void invalidateBuffer(GlMutableBuffer glBuffer); + + void allocateBuffer(GlBufferTarget target, GlMutableBuffer buffer, long bufferSize); + + void deleteBuffer(GlBuffer buffer); + + void deleteVertexArray(GlVertexArray vertexArray); + + void flush(); + + DrawCommandList beginTessellating(GlTessellation tessellation); + + void deleteTessellation(GlTessellation tessellation); + + @Override + default void close() { + this.flush(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java new file mode 100644 index 000000000..cc6b2e7bc --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java @@ -0,0 +1,18 @@ +package me.jellysquid.mods.sodium.client.gl.device; + +import java.nio.IntBuffer; + +public interface DrawCommandList extends AutoCloseable { + void multiDrawArrays(IntBuffer first, IntBuffer count); + + void multiDrawArraysIndirect(long pointer, int count, int stride); + + void endTessellating(); + + void flush(); + + @Override + default void close() { + this.flush(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java new file mode 100644 index 000000000..c55633e9a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java @@ -0,0 +1,217 @@ +package me.jellysquid.mods.sodium.client.gl.device; + +import com.mojang.blaze3d.platform.GlStateManager; +import me.jellysquid.mods.sodium.client.gl.array.GlVertexArray; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferUsage; +import me.jellysquid.mods.sodium.client.gl.buffer.GlMutableBuffer; +import me.jellysquid.mods.sodium.client.gl.func.GlFunctions; +import me.jellysquid.mods.sodium.client.gl.state.GlStateTracker; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlFallbackTessellation; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlPrimitiveType; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlVertexArrayTessellation; +import me.jellysquid.mods.sodium.client.gl.tessellation.TessellationBinding; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +public class GLRenderDevice implements RenderDevice { + private final GlStateTracker stateTracker = new GlStateTracker(); + private final CommandList commandList = new ImmediateCommandList(this.stateTracker); + private final DrawCommandList drawCommandList = new ImmediateDrawCommandList(); + + private boolean isActive; + private GlTessellation activeTessellation; + + @Override + public CommandList createCommandList() { + GLRenderDevice.this.checkDeviceActive(); + + return this.commandList; + } + + @Override + public void makeActive() { + if (this.isActive) { + return; + } + + this.stateTracker.clearRestoreState(); + this.isActive = true; + } + + @Override + public void makeInactive() { + if (!this.isActive) { + return; + } + + this.stateTracker.applyRestoreState(); + this.isActive = false; + } + + private void checkDeviceActive() { + if (!this.isActive) { + throw new IllegalStateException("Tried to access device from unmanaged context"); + } + } + + private class ImmediateCommandList implements CommandList { + private final GlStateTracker stateTracker; + + private ImmediateCommandList(GlStateTracker stateTracker) { + this.stateTracker = stateTracker; + } + + @Override + public void bindVertexArray(GlVertexArray array) { + if (this.stateTracker.makeVertexArrayActive(array)) { + GlFunctions.VERTEX_ARRAY.glBindVertexArray(array.handle()); + } + } + + @Override + public void uploadData(GlMutableBuffer glBuffer, ByteBuffer byteBuffer) { + this.bindBuffer(GlBufferTarget.ARRAY_BUFFER, glBuffer); + + GlStateManager.bufferData(GlBufferTarget.ARRAY_BUFFER.getTargetParameter(), byteBuffer, glBuffer.getUsageHint().getId()); + + glBuffer.setSize(byteBuffer.limit()); + } + + @Override + public void copyBufferSubData(GlBuffer src, GlMutableBuffer dst, long readOffset, long writeOffset, long bytes) { + if (writeOffset + bytes > dst.getSize()) { + throw new IllegalArgumentException("Not enough space in destination buffer (writeOffset + bytes > bufferSize)"); + } + + this.bindBuffer(GlBufferTarget.COPY_READ_BUFFER, src); + this.bindBuffer(GlBufferTarget.COPY_WRITE_BUFFER, dst); + + GlFunctions.BUFFER_COPY.glCopyBufferSubData(GL31C.GL_COPY_READ_BUFFER, GL31C.GL_COPY_WRITE_BUFFER, readOffset, writeOffset, bytes); + } + + @Override + public void bindBuffer(GlBufferTarget target, GlBuffer buffer) { + if (this.stateTracker.makeBufferActive(target, buffer)) { + GlStateManager.bindBuffers(target.getTargetParameter(), buffer.handle()); + } + } + + @Override + public void unbindBuffer(GlBufferTarget target) { + if (this.stateTracker.makeBufferActive(target, null)) { + GlStateManager.bindBuffers(target.getTargetParameter(), GlBuffer.NULL_BUFFER_ID); + } + } + + @Override + public void unbindVertexArray() { + if (this.stateTracker.makeVertexArrayActive(null)) { + GlFunctions.VERTEX_ARRAY.glBindVertexArray(GlVertexArray.NULL_ARRAY_ID); + } + } + + @Override + public void invalidateBuffer(GlMutableBuffer glBuffer) { + this.allocateBuffer(GlBufferTarget.ARRAY_BUFFER, glBuffer, 0L); + } + + @Override + public void allocateBuffer(GlBufferTarget target, GlMutableBuffer buffer, long bufferSize) { + this.bindBuffer(target, buffer); + + GL20C.glBufferData(target.getTargetParameter(), bufferSize, buffer.getUsageHint().getId()); + buffer.setSize(bufferSize); + } + + @Override + public void deleteBuffer(GlBuffer buffer) { + int handle = buffer.handle(); + buffer.invalidateHandle(); + + GlStateManager.deleteBuffers(handle); + } + + @Override + public void deleteVertexArray(GlVertexArray array) { + int handle = array.handle(); + array.invalidateHandle(); + + GlFunctions.VERTEX_ARRAY.glDeleteVertexArrays(handle); + } + + @Override + public void flush() { + // NO-OP + } + + @Override + public DrawCommandList beginTessellating(GlTessellation tessellation) { + GLRenderDevice.this.activeTessellation = tessellation; + GLRenderDevice.this.activeTessellation.bind(GLRenderDevice.this.commandList); + + return GLRenderDevice.this.drawCommandList; + } + + @Override + public void deleteTessellation(GlTessellation tessellation) { + tessellation.delete(this); + } + + @Override + public GlVertexArray createVertexArray() { + return new GlVertexArray(GLRenderDevice.this); + } + + @Override + public GlMutableBuffer createMutableBuffer(GlBufferUsage usage) { + return new GlMutableBuffer(GLRenderDevice.this, usage); + } + + @Override + public GlTessellation createTessellation(GlPrimitiveType primitiveType, TessellationBinding[] bindings) { + if (GlVertexArrayTessellation.isSupported()) { + GlVertexArrayTessellation tessellation = new GlVertexArrayTessellation(new GlVertexArray(GLRenderDevice.this), primitiveType, bindings); + tessellation.init(this); + + return tessellation; + } else { + return new GlFallbackTessellation(primitiveType, bindings); + } + } + } + + private class ImmediateDrawCommandList implements DrawCommandList { + public ImmediateDrawCommandList() { + + } + + @Override + public void multiDrawArrays(IntBuffer first, IntBuffer count) { + GlPrimitiveType primitiveType = GLRenderDevice.this.activeTessellation.getPrimitiveType(); + GL20C.glMultiDrawArrays(primitiveType.getId(), first, count); + } + + @Override + public void multiDrawArraysIndirect(long pointer, int count, int stride) { + GlPrimitiveType primitiveType = GLRenderDevice.this.activeTessellation.getPrimitiveType(); + GlFunctions.INDIRECT_DRAW.glMultiDrawArraysIndirect(primitiveType.getId(), pointer, count, stride); + } + + @Override + public void endTessellating() { + GLRenderDevice.this.activeTessellation.unbind(GLRenderDevice.this.commandList); + GLRenderDevice.this.activeTessellation = null; + } + + @Override + public void flush() { + if (GLRenderDevice.this.activeTessellation != null) { + this.endTessellating(); + } + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/RenderDevice.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/RenderDevice.java new file mode 100644 index 000000000..ffbf2a8e5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/RenderDevice.java @@ -0,0 +1,18 @@ +package me.jellysquid.mods.sodium.client.gl.device; + +public interface RenderDevice { + RenderDevice INSTANCE = new GLRenderDevice(); + + CommandList createCommandList(); + + static void enterManagedCode() { + RenderDevice.INSTANCE.makeActive(); + } + + static void exitManagedCode() { + RenderDevice.INSTANCE.makeInactive(); + } + + void makeActive(); + void makeInactive(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlBufferCopyFunctions.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlBufferCopyFunctions.java new file mode 100644 index 000000000..c55d0c577 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlBufferCopyFunctions.java @@ -0,0 +1,41 @@ +package me.jellysquid.mods.sodium.client.gl.func; + +import org.lwjgl.opengl.ARBCopyBuffer; +import org.lwjgl.opengl.GL31C; +import org.lwjgl.opengl.GLCapabilities; + +/** + * Requires OpenGL 3.1+ or the ARB_copy_buffer extension. + */ +public enum GlBufferCopyFunctions { + CORE { + @Override + public void glCopyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size) { + GL31C.glCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); + } + }, + ARB { + @Override + public void glCopyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size) { + ARBCopyBuffer.glCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); + } + }, + UNSUPPORTED { + @Override + public void glCopyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size) { + throw new UnsupportedOperationException(); + } + }; + + static GlBufferCopyFunctions load(GLCapabilities capabilities) { + if (capabilities.OpenGL31) { + return GlBufferCopyFunctions.CORE; + } else if (capabilities.GL_ARB_copy_buffer) { + return GlBufferCopyFunctions.ARB; + } else { + return GlBufferCopyFunctions.UNSUPPORTED; + } + } + + public abstract void glCopyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlFunctions.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlFunctions.java new file mode 100644 index 000000000..fdf59f22a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlFunctions.java @@ -0,0 +1,29 @@ +package me.jellysquid.mods.sodium.client.gl.func; + +import org.lwjgl.opengl.GL; +import org.lwjgl.opengl.GLCapabilities; + +public class GlFunctions { + private static final GLCapabilities capabilities = GL.getCapabilities(); + + public static final GlVertexArrayFunctions VERTEX_ARRAY = GlVertexArrayFunctions.load(capabilities); + public static final GlBufferCopyFunctions BUFFER_COPY = GlBufferCopyFunctions.load(capabilities); + public static final GlIndirectMultiDrawFunctions INDIRECT_DRAW = GlIndirectMultiDrawFunctions.load(capabilities); + public static final GlInstancedArrayFunctions INSTANCED_ARRAY = GlInstancedArrayFunctions.load(capabilities); + + public static boolean isVertexArraySupported() { + return VERTEX_ARRAY != GlVertexArrayFunctions.UNSUPPORTED; + } + + public static boolean isBufferCopySupported() { + return BUFFER_COPY != GlBufferCopyFunctions.UNSUPPORTED; + } + + public static boolean isIndirectMultiDrawSupported() { + return INDIRECT_DRAW != GlIndirectMultiDrawFunctions.UNSUPPORTED; + } + + public static boolean isInstancedArraySupported() { + return INSTANCED_ARRAY != GlInstancedArrayFunctions.UNSUPPORTED; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java new file mode 100644 index 000000000..a13e294d2 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java @@ -0,0 +1,38 @@ +package me.jellysquid.mods.sodium.client.gl.func; + +import org.lwjgl.opengl.ARBMultiDrawIndirect; +import org.lwjgl.opengl.GL43C; +import org.lwjgl.opengl.GLCapabilities; + +public enum GlIndirectMultiDrawFunctions { + CORE { + @Override + public void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride) { + GL43C.glMultiDrawArraysIndirect(mode, indirect, primcount, stride); + } + }, + ARB { + @Override + public void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride) { + ARBMultiDrawIndirect.glMultiDrawArraysIndirect(mode, indirect, primcount, stride); + } + }, + UNSUPPORTED { + @Override + public void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride) { + throw new UnsupportedOperationException(); + } + }; + + public static GlIndirectMultiDrawFunctions load(GLCapabilities capabilities) { + if (capabilities.OpenGL43) { + return CORE; + } else if (capabilities.GL_ARB_multi_draw_indirect && capabilities.GL_ARB_draw_indirect) { + return ARB; + } else { + return UNSUPPORTED; + } + } + + public abstract void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlInstancedArrayFunctions.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlInstancedArrayFunctions.java new file mode 100644 index 000000000..95f575beb --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlInstancedArrayFunctions.java @@ -0,0 +1,38 @@ +package me.jellysquid.mods.sodium.client.gl.func; + +import org.lwjgl.opengl.ARBInstancedArrays; +import org.lwjgl.opengl.GL33C; +import org.lwjgl.opengl.GLCapabilities; + +public enum GlInstancedArrayFunctions { + CORE { + @Override + public void glVertexAttribDivisor(int index, int divisor) { + GL33C.glVertexAttribDivisor(index, divisor); + } + }, + ARB { + @Override + public void glVertexAttribDivisor(int index, int divisor) { + ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor); + } + }, + UNSUPPORTED { + @Override + public void glVertexAttribDivisor(int index, int divisor) { + throw new UnsupportedOperationException(); + } + }; + + public static GlInstancedArrayFunctions load(GLCapabilities capabilities) { + if (capabilities.OpenGL33) { + return CORE; + } else if (capabilities.GL_ARB_instanced_arrays) { + return ARB; + } else { + return UNSUPPORTED; + } + } + + public abstract void glVertexAttribDivisor(int index, int divisor); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlVertexArrayFunctions.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlVertexArrayFunctions.java new file mode 100644 index 000000000..8b639bb85 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlVertexArrayFunctions.java @@ -0,0 +1,75 @@ +package me.jellysquid.mods.sodium.client.gl.func; + +import org.lwjgl.opengl.ARBVertexArrayObject; +import org.lwjgl.opengl.GL30C; +import org.lwjgl.opengl.GLCapabilities; + +/** + * Requires OpenGL 3.0+ or the ARB_vertex_array_object extension. + */ +public enum GlVertexArrayFunctions { + BASE { + @Override + public void glBindVertexArray(int id) { + GL30C.glBindVertexArray(id); + } + + @Override + public int glGenVertexArrays() { + return GL30C.glGenVertexArrays(); + } + + @Override + public void glDeleteVertexArrays(int id) { + GL30C.glDeleteVertexArrays(id); + } + }, + ARB { + @Override + public void glBindVertexArray(int id) { + ARBVertexArrayObject.glBindVertexArray(id); + } + + @Override + public int glGenVertexArrays() { + return ARBVertexArrayObject.glGenVertexArrays(); + } + + @Override + public void glDeleteVertexArrays(int id) { + ARBVertexArrayObject.glDeleteVertexArrays(id); + } + }, + UNSUPPORTED { + @Override + public void glBindVertexArray(int id) { + throw new UnsupportedOperationException(); + } + + @Override + public int glGenVertexArrays() { + throw new UnsupportedOperationException(); + } + + @Override + public void glDeleteVertexArrays(int id) { + throw new UnsupportedOperationException(); + } + }; + + static GlVertexArrayFunctions load(GLCapabilities capabilities) { + if (capabilities.OpenGL30) { + return BASE; + } else if (capabilities.GL_ARB_vertex_array_object) { + return ARB; + } + + return UNSUPPORTED; + } + + public abstract void glBindVertexArray(int id); + + public abstract int glGenVertexArrays(); + + public abstract void glDeleteVertexArrays(int id); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java new file mode 100644 index 000000000..8891f1ebf --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java @@ -0,0 +1,116 @@ +package me.jellysquid.mods.sodium.client.gl.shader; + +import com.mojang.blaze3d.platform.GlStateManager; +import me.jellysquid.mods.sodium.client.gl.GlObject; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import net.minecraft.util.Identifier; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.lwjgl.opengl.GL20C; + +/** + * An OpenGL shader program. + */ +public abstract class GlProgram extends GlObject { + private static final Logger LOGGER = LogManager.getLogger(GlProgram.class); + + private final Identifier name; + + protected GlProgram(RenderDevice owner, Identifier name, int program) { + super(owner); + + this.name = name; + this.setHandle(program); + } + + public static Builder builder(Identifier identifier) { + return new Builder(identifier); + } + + public void bind() { + GlStateManager.useProgram(this.handle()); + } + + public void unbind() { + GlStateManager.useProgram(0); + } + + public Identifier getName() { + return this.name; + } + + /** + * Retrieves the index of the uniform with the given name. + * @param name The name of the uniform to find the index of + * @return The uniform's index + * @throws NullPointerException If no uniform exists with the given name + */ + public int getUniformLocation(String name) { + int index = GlStateManager.getUniformLocation(this.handle(), name); + + if (index < 0) { + throw new NullPointerException("No uniform exists with name: " + name); + } + + return index; + } + + public void delete() { + GlStateManager.deleteProgram(this.handle()); + + this.invalidateHandle(); + } + + public static class Builder { + private final Identifier name; + private final int program; + + public Builder(Identifier name) { + this.name = name; + this.program = GlStateManager.createProgram(); + } + + public Builder attachShader(GlShader shader) { + GlStateManager.attachShader(this.program, shader.handle()); + + return this; + } + + /** + * Links the attached shaders to this program and returns a user-defined container which wraps the shader + * program. This container can, for example, provide methods for updating the specific uniforms of that shader + * set. + * + * @param factory The factory which will create the shader program's container + * @param

The type which should be instantiated with the new program's handle + * @return An instantiated shader container as provided by the factory + */ + public

P build(ProgramFactory

factory) { + GlStateManager.linkProgram(this.program); + + String log = GL20C.glGetProgramInfoLog(this.program); + + if (!log.isEmpty()) { + LOGGER.warn("Program link log for " + this.name + ": " + log); + } + + int result = GlStateManager.getProgram(this.program, GL20C.GL_LINK_STATUS); + + if (result != GL20C.GL_TRUE) { + throw new RuntimeException("Shader program linking failed, see log for details"); + } + + return factory.create(this.name, this.program); + } + + public Builder bindAttribute(String name, ShaderBindingPoint binding) { + GL20C.glBindAttribLocation(this.program, binding.getGenericAttributeIndex(), name); + + return this; + } + } + + public interface ProgramFactory

{ + P create(Identifier name, int handle); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java new file mode 100644 index 000000000..6fe345e95 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java @@ -0,0 +1,91 @@ +package me.jellysquid.mods.sodium.client.gl.shader; + +import com.mojang.blaze3d.platform.GlStateManager; +import me.jellysquid.mods.sodium.client.gl.GlObject; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import net.minecraft.util.Identifier; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.lwjgl.opengl.GL20C; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; + +/** + * A compiled OpenGL shader object. + */ +public class GlShader extends GlObject { + private static final Logger LOGGER = LogManager.getLogger(GlShader.class); + + private final Identifier name; + + public GlShader(RenderDevice owner, ShaderType type, Identifier name, String src, ShaderConstants constants) { + super(owner); + + this.name = name; + + src = processShader(src, constants); + + int handle = GlStateManager.createShader(type.id); + ShaderWorkarounds.safeShaderSource(handle, src); + GlStateManager.compileShader(handle); + + String log = GL20C.glGetShaderInfoLog(handle); + + if (!log.isEmpty()) { + LOGGER.warn("Shader compilation log for " + this.name + ": " + log); + } + + int result = GlStateManager.getShader(handle, GL20C.GL_COMPILE_STATUS); + + if (result != GL20C.GL_TRUE) { + throw new RuntimeException("Shader compilation failed, see log for details"); + } + + this.setHandle(handle); + } + + /** + * Adds an additional list of defines to the top of a GLSL shader file just after the version declaration. This + * allows for ghetto shader specialization. + */ + private static String processShader(String src, ShaderConstants constants) { + StringBuilder builder = new StringBuilder(src.length()); + boolean patched = false; + + try (BufferedReader reader = new BufferedReader(new StringReader(src))) { + String line; + + while ((line = reader.readLine()) != null) { + // Write the line out to the patched GLSL code string + builder.append(line).append("\n"); + + // Now, see if the line we just wrote declares the version + // If we haven't already added our define declarations, add them just after the version declaration + if (!patched && line.startsWith("#version")) { + for (String macro : constants.getDefineStrings()) { + builder.append(macro).append('\n'); + } + + // We did our work, don't add them again + patched = true; + } + } + } catch (IOException e) { + throw new RuntimeException("Could not process shader source", e); + } + + return builder.toString(); + } + + public Identifier getName() { + return this.name; + } + + public void delete() { + GlStateManager.deleteShader(this.handle()); + + this.invalidateHandle(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderBindingPoint.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderBindingPoint.java new file mode 100644 index 000000000..4da44924f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderBindingPoint.java @@ -0,0 +1,13 @@ +package me.jellysquid.mods.sodium.client.gl.shader; + +public class ShaderBindingPoint { + private final int genericAttributeIndex; + + public ShaderBindingPoint(int genericAttributeIndex) { + this.genericAttributeIndex = genericAttributeIndex; + } + + public int getGenericAttributeIndex() { + return genericAttributeIndex; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderConstants.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderConstants.java new file mode 100644 index 000000000..c8ba2caef --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderConstants.java @@ -0,0 +1,74 @@ +package me.jellysquid.mods.sodium.client.gl.shader; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ShaderConstants { + private final List defines; + + private ShaderConstants(List defines) { + this.defines = defines; + } + + public List getDefineStrings() { + return this.defines; + } + + public static ShaderConstants fromStringList(List defines) { + Builder builder = new Builder(); + + for (String define : defines) { + builder.define(define); + } + + return builder.build(); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private static final String EMPTY_VALUE = ""; + + private final HashMap constants = new HashMap<>(); + + private Builder() { + + } + + public void define(String name) { + this.define(name, EMPTY_VALUE); + } + + public void define(String name, String value) { + String prev = this.constants.get(name); + + if (prev != null) { + throw new IllegalArgumentException("Constant " + name + " is already defined with value " + prev); + } + + this.constants.put(name, value); + } + + public ShaderConstants build() { + List defines = new ArrayList<>(this.constants.size()); + + for (Map.Entry entry : this.constants.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + + if (value.length() <= 0) { + defines.add("#define " + key); + } else { + defines.add("#define " + key + " " + value); + } + } + + return new ShaderConstants(Collections.unmodifiableList(defines)); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java new file mode 100644 index 000000000..33acceac1 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java @@ -0,0 +1,52 @@ +package me.jellysquid.mods.sodium.client.gl.shader; + +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import net.minecraft.util.Identifier; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +public class ShaderLoader { + /** + * Creates an OpenGL shader from GLSL sources. The GLSL source file should be made available on the classpath at the + * path of `/assets/{namespace}/shaders/{path}`. User defines can be used to declare variables in the shader source + * after the version header, allowing for conditional compilation with macro code. + * + * + * @param device + * @param type The type of shader to create + * @param name The identifier used to locate the shader source file + * @param constants A list of constants for shader specialization + * @return An OpenGL shader object compiled with the given user defines + */ + public static GlShader loadShader(RenderDevice device, ShaderType type, Identifier name, ShaderConstants constants) { + return new GlShader(device, type, name, getShaderSource(getShaderPath(name)), constants); + } + + /** + * Use {@link ShaderLoader#loadShader(RenderDevice, ShaderType, Identifier, ShaderConstants)} instead. This will be removed. + */ + @Deprecated + public static GlShader loadShader(RenderDevice device, ShaderType type, Identifier name, List constants) { + return new GlShader(device, type, name, getShaderSource(getShaderPath(name)), ShaderConstants.fromStringList(constants)); + } + + private static String getShaderPath(Identifier name) { + return String.format("/assets/%s/shaders/%s", name.getNamespace(), name.getPath()); + } + + private static String getShaderSource(String path) { + try (InputStream in = ShaderLoader.class.getResourceAsStream(path)) { + if (in == null) { + throw new RuntimeException("Shader not found: " + path); + } + + return IOUtils.toString(in, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Could not read shader sources", e); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java new file mode 100644 index 000000000..4791e3dc8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java @@ -0,0 +1,17 @@ +package me.jellysquid.mods.sodium.client.gl.shader; + +import org.lwjgl.opengl.GL20C; + +/** + * An enumeration over the supported OpenGL shader types. + */ +public enum ShaderType { + VERTEX(GL20C.GL_VERTEX_SHADER), + FRAGMENT(GL20C.GL_FRAGMENT_SHADER); + + public final int id; + + ShaderType(int id) { + this.id = id; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderWorkarounds.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderWorkarounds.java new file mode 100644 index 000000000..d13bbfaee --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderWorkarounds.java @@ -0,0 +1,53 @@ +// Copyright 2020 Grondag +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package me.jellysquid.mods.sodium.client.gl.shader; + +import org.lwjgl.PointerBuffer; +import org.lwjgl.opengl.GL20C; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; + +/** + * Contains a workaround for a crash in nglShaderSource on some AMD drivers. Copied from the following Canvas commit: + * https://github.com/grondag/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96 + */ +class ShaderWorkarounds { + /** + * Identical in function to {@link GL20C#glShaderSource(int, CharSequence)} but + * passes a null pointer for string length to force the driver to rely on the null + * terminator for string length. This is a workaround for an apparent flaw with some + * AMD drivers that don't receive or interpret the length correctly, resulting in + * an access violation when the driver tries to read past the string memory. + * + *

Hat tip to fewizz for the find and the fix. + */ + static void safeShaderSource(int glId, CharSequence source) { + final MemoryStack stack = MemoryStack.stackGet(); + final int stackPointer = stack.getPointer(); + + try { + final ByteBuffer sourceBuffer = MemoryUtil.memUTF8(source, true); + final PointerBuffer pointers = stack.mallocPointer(1); + pointers.put(sourceBuffer); + + GL20C.nglShaderSource(glId, 1, pointers.address0(), 0); + org.lwjgl.system.APIUtil.apiArrayFree(pointers.address0(), 1); + } finally { + stack.setPointer(stackPointer); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java new file mode 100644 index 000000000..94f51b355 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java @@ -0,0 +1,77 @@ +package me.jellysquid.mods.sodium.client.gl.state; + +import com.mojang.blaze3d.platform.GlStateManager; +import me.jellysquid.mods.sodium.client.gl.array.GlVertexArray; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; +import org.lwjgl.opengl.GL30C; + +import java.util.Arrays; + +public class GlStateTracker { + private static final int UNASSIGNED_HANDLE = -1; + + private final int[] bufferState = new int[GlBufferTarget.COUNT]; + private final int[] bufferRestoreState = new int[GlBufferTarget.COUNT]; + + private int vertexArrayState; + private int vertexArrayRestoreState; + + public GlStateTracker() { + this.clearRestoreState(); + } + + public boolean makeBufferActive(GlBufferTarget target, GlBuffer buffer) { + return this.makeBufferActive(target, buffer == null ? GlBuffer.NULL_BUFFER_ID : buffer.handle()); + } + + private boolean makeBufferActive(GlBufferTarget target, int buffer) { + int prevBuffer = this.bufferState[target.ordinal()]; + + if (prevBuffer == UNASSIGNED_HANDLE) { + this.bufferRestoreState[target.ordinal()] = GlStateManager.getInteger(target.getBindingParameter()); + } + + this.bufferState[target.ordinal()] = buffer; + + return prevBuffer != buffer; + } + + public boolean makeVertexArrayActive(GlVertexArray array) { + return this.makeVertexArrayActive(array == null ? GlVertexArray.NULL_ARRAY_ID : array.handle()); + } + + private boolean makeVertexArrayActive(int array) { + int prevArray = this.vertexArrayState; + + if (prevArray == UNASSIGNED_HANDLE) { + this.vertexArrayRestoreState = GlStateManager.getInteger(GL30C.GL_VERTEX_ARRAY_BINDING); + } + + this.vertexArrayState = array; + + return prevArray != array; + } + + public void applyRestoreState() { + for (int i = 0; i < GlBufferTarget.COUNT; i++) { + if (this.bufferState[i] != this.bufferRestoreState[i] && + this.bufferRestoreState[i] != UNASSIGNED_HANDLE) { + GlStateManager.bindBuffers(GlBufferTarget.VALUES[i].getTargetParameter(), this.bufferRestoreState[i]); + } + } + + if (this.vertexArrayState != this.vertexArrayRestoreState && + this.vertexArrayRestoreState != UNASSIGNED_HANDLE) { + GL30C.glBindVertexArray(this.vertexArrayRestoreState); + } + } + + public void clearRestoreState() { + Arrays.fill(this.bufferState, UNASSIGNED_HANDLE); + Arrays.fill(this.bufferRestoreState, UNASSIGNED_HANDLE); + + this.vertexArrayState = UNASSIGNED_HANDLE; + this.vertexArrayRestoreState = UNASSIGNED_HANDLE; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java new file mode 100644 index 000000000..ab6c790d3 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java @@ -0,0 +1,38 @@ +package me.jellysquid.mods.sodium.client.gl.tessellation; + +import com.mojang.blaze3d.platform.GlStateManager; +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import me.jellysquid.mods.sodium.client.gl.func.GlFunctions; + +public abstract class GlAbstractTessellation implements GlTessellation { + protected final GlPrimitiveType primitiveType; + protected final TessellationBinding[] bindings; + + protected GlAbstractTessellation(GlPrimitiveType primitiveType, TessellationBinding[] bindings) { + this.primitiveType = primitiveType; + this.bindings = bindings; + } + + @Override + public GlPrimitiveType getPrimitiveType() { + return this.primitiveType; + } + + protected void bindAttributes(CommandList commandList) { + for (TessellationBinding binding : this.bindings) { + commandList.bindBuffer(GlBufferTarget.ARRAY_BUFFER, binding.getBuffer()); + + for (GlVertexAttributeBinding attrib : binding.getAttributeBindings()) { + GlStateManager.vertexAttribPointer(attrib.getIndex(), attrib.getCount(), attrib.getFormat(), attrib.isNormalized(), + attrib.getStride(), attrib.getPointer()); + GlStateManager.enableVertexAttribArray(attrib.getIndex()); + + if (binding.isInstanced()) { + GlFunctions.INSTANCED_ARRAY.glVertexAttribDivisor(attrib.getIndex(), 1); + } + } + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlFallbackTessellation.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlFallbackTessellation.java new file mode 100644 index 000000000..7cb4eb937 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlFallbackTessellation.java @@ -0,0 +1,30 @@ +package me.jellysquid.mods.sodium.client.gl.tessellation; + +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import org.lwjgl.opengl.GL20C; + +public class GlFallbackTessellation extends GlAbstractTessellation { + public GlFallbackTessellation(GlPrimitiveType primitiveType, TessellationBinding[] bindings) { + super(primitiveType, bindings); + } + + @Override + public void delete(CommandList commandList) { + + } + + @Override + public void bind(CommandList commandList) { + this.bindAttributes(commandList); + } + + @Override + public void unbind(CommandList commandList) { + for (TessellationBinding binding : this.bindings) { + for (GlVertexAttributeBinding attrib : binding.getAttributeBindings()) { + GL20C.glDisableVertexAttribArray(attrib.getIndex()); + } + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlPrimitiveType.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlPrimitiveType.java new file mode 100644 index 000000000..fb8f0297c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlPrimitiveType.java @@ -0,0 +1,19 @@ +package me.jellysquid.mods.sodium.client.gl.tessellation; + +import org.lwjgl.opengl.GL20C; + +public enum GlPrimitiveType { + LINES(GL20C.GL_LINES), + TRIANGLES(GL20C.GL_TRIANGLES), + QUADS(GL20C.GL_QUADS); + + private final int id; + + GlPrimitiveType(int id) { + this.id = id; + } + + public int getId() { + return this.id; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlTessellation.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlTessellation.java new file mode 100644 index 000000000..cf7aeb70a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlTessellation.java @@ -0,0 +1,13 @@ +package me.jellysquid.mods.sodium.client.gl.tessellation; + +import me.jellysquid.mods.sodium.client.gl.device.CommandList; + +public interface GlTessellation { + void delete(CommandList commandList); + + void bind(CommandList commandList); + + void unbind(CommandList commandList); + + GlPrimitiveType getPrimitiveType(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java new file mode 100644 index 000000000..f09f3bfef --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java @@ -0,0 +1,40 @@ +package me.jellysquid.mods.sodium.client.gl.tessellation; + +import me.jellysquid.mods.sodium.client.gl.array.GlVertexArray; +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import me.jellysquid.mods.sodium.client.gl.func.GlFunctions; + +public class GlVertexArrayTessellation extends GlAbstractTessellation { + private final GlVertexArray array; + + public GlVertexArrayTessellation(GlVertexArray array, GlPrimitiveType primitiveType, TessellationBinding[] bindings) { + super(primitiveType, bindings); + + this.array = array; + } + + public static boolean isSupported() { + return GlFunctions.isVertexArraySupported(); + } + + public void init(CommandList commandList) { + this.bind(commandList); + this.bindAttributes(commandList); + this.unbind(commandList); + } + + @Override + public void delete(CommandList commandList) { + commandList.deleteVertexArray(this.array); + } + + @Override + public void bind(CommandList commandList) { + commandList.bindVertexArray(this.array); + } + + @Override + public void unbind(CommandList commandList) { + commandList.unbindVertexArray(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/TessellationBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/TessellationBinding.java new file mode 100644 index 000000000..b383d74e6 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/TessellationBinding.java @@ -0,0 +1,28 @@ +package me.jellysquid.mods.sodium.client.gl.tessellation; + +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; + +public class TessellationBinding { + private final GlBuffer buffer; + private final GlVertexAttributeBinding[] bindings; + private final boolean instanced; + + public TessellationBinding(GlBuffer buffer, GlVertexAttributeBinding[] bindings, boolean instanced) { + this.buffer = buffer; + this.bindings = bindings; + this.instanced = instanced; + } + + public GlBuffer getBuffer() { + return this.buffer; + } + + public GlVertexAttributeBinding[] getAttributeBindings() { + return this.bindings; + } + + public boolean isInstanced() { + return this.instanced; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/BufferSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/util/BufferSlice.java new file mode 100644 index 000000000..898d3f9ca --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/util/BufferSlice.java @@ -0,0 +1,22 @@ +package me.jellysquid.mods.sodium.client.gl.util; + +public class BufferSlice { + public final int start, len; + + public BufferSlice(int start, int len) { + this.start = start; + this.len = len; + } + + public static long pack(int start, int len) { + return (long) start & 0xffffffffL | ((long) len & 0xffffffffL) << 32; + } + + public static int unpackStart(long slice) { + return (int) (slice & 0xffffffffL); + } + + public static int unpackLength(long slice) { + return (int) (slice >>> 32 & 0xffffffffL); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/GlMultiDrawBatch.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/util/GlMultiDrawBatch.java new file mode 100644 index 000000000..a069a484d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/util/GlMultiDrawBatch.java @@ -0,0 +1,64 @@ +package me.jellysquid.mods.sodium.client.gl.util; + +import org.lwjgl.opengl.GL20; +import org.lwjgl.system.MemoryUtil; + +import java.nio.IntBuffer; + +/** + * Provides a fixed-size queue for batching draw calls for vertex data in the same buffer. This internally + * uses {@link GL20#glMultiDrawArrays(int, IntBuffer, IntBuffer)} and should be compatible on any relevant platform. + */ +public class GlMultiDrawBatch { + private final IntBuffer bufIndices; + private final IntBuffer bufLen; + private int count; + private boolean isBuilding; + + public GlMultiDrawBatch(int capacity) { + this.bufIndices = MemoryUtil.memAllocInt(capacity); + this.bufLen = MemoryUtil.memAllocInt(capacity); + } + + public IntBuffer getIndicesBuffer() { + return this.bufIndices; + } + + public IntBuffer getLengthBuffer() { + return this.bufLen; + } + + public void begin() { + this.bufIndices.clear(); + this.bufLen.clear(); + this.count = 0; + + this.isBuilding = true; + } + + public void end() { + this.bufIndices.limit(this.count); + this.bufLen.limit(this.count); + + this.isBuilding = false; + } + + public boolean isEmpty() { + return this.count <= 0; + } + + public void addChunkRender(int first, int count) { + int i = this.count++; + this.bufIndices.put(i, first); + this.bufLen.put(i, count); + } + + public boolean isBuilding() { + return this.isBuilding; + } + + public void delete() { + MemoryUtilHelper.memFree(this.bufIndices); + MemoryUtilHelper.memFree(this.bufLen); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/MemoryUtilHelper.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/util/MemoryUtilHelper.java new file mode 100644 index 000000000..851b73f7f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/util/MemoryUtilHelper.java @@ -0,0 +1,28 @@ +package me.jellysquid.mods.sodium.client.gl.util; + +import org.jetbrains.annotations.Nullable; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryUtil; + +import java.nio.Buffer; + +/** + * Contains versions of MemoryUtil#memFree that hopefully work on all versions of LWJGL 3 released + * in the past few years. + * + * LWJGL 3.2.3 made breaking changes to memFree, which is why this class is needed: + * https://github.com/LWJGL/lwjgl3/releases/tag/3.2.3 + */ +public class MemoryUtilHelper { + // memFree for custom / pointer buffers *was* changed. + public static void memFree(@Nullable PointerBuffer ptr) { + if (ptr != null) { + MemoryUtil.nmemFree(ptr.address0()); + } + } + + // memFree for normal buffers was not changed. + public static void memFree(@Nullable Buffer ptr) { + MemoryUtil.memFree(ptr); + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java new file mode 100644 index 000000000..1f06ddff5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -0,0 +1,366 @@ +package me.jellysquid.mods.sodium.client.gui; + +import com.google.common.collect.ImmutableList; +import me.jellysquid.mods.sodium.client.compat.modernui.MuiGuiScaleHook; +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; +import me.jellysquid.mods.sodium.client.gui.options.OptionGroup; +import me.jellysquid.mods.sodium.client.gui.options.OptionImpact; +import me.jellysquid.mods.sodium.client.gui.options.OptionImpl; +import me.jellysquid.mods.sodium.client.gui.options.OptionPage; +import me.jellysquid.mods.sodium.client.gui.options.binding.compat.VanillaBooleanOptionBinding; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; +import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl; +import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl; +import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl; +import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; +import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage; +import me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw.MultidrawChunkRenderBackend; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gl.Framebuffer; +import net.minecraft.client.option.AttackIndicator; +import net.minecraft.client.option.GraphicsMode; +import net.minecraft.client.option.ParticlesMode; +import net.minecraft.client.util.Window; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; + +import java.util.ArrayList; +import java.util.List; + +public class SodiumGameOptionPages { + private static final SodiumOptionsStorage sodiumOpts = new SodiumOptionsStorage(); + private static final MinecraftOptionsStorage vanillaOpts = new MinecraftOptionsStorage(); + + public static OptionPage general() { + List groups = new ArrayList<>(); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(new TranslatableText("options.renderDistance")) + .setTooltip(new TranslatableText("sodium.options.view_distance.tooltip")) + .setControl(option -> new SliderControl(option, 2, 32, 1, ControlValueFormatter.quantity("options.chunks"))) + .setBinding((options, value) -> options.viewDistance = value, options -> options.viewDistance) + .setImpact(OptionImpact.HIGH) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(new TranslatableText("options.gamma")) + .setTooltip(new TranslatableText("sodium.options.brightness.tooltip")) + .setControl(opt -> new SliderControl(opt, 0, 100, 1, ControlValueFormatter.brightness())) + .setBinding((opts, value) -> opts.gamma = value * 0.01D, (opts) -> (int) (opts.gamma / 0.01D)) + .build()) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.clouds.name")) + .setTooltip(new TranslatableText("sodium.options.clouds.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> { + opts.quality.enableClouds = value; + + if (MinecraftClient.isFabulousGraphicsOrBetter()) { + Framebuffer framebuffer = MinecraftClient.getInstance().worldRenderer.getCloudsFramebuffer(); + if (framebuffer != null) { + framebuffer.clear(MinecraftClient.IS_SYSTEM_MAC); + } + } + }, (opts) -> opts.quality.enableClouds) + .setImpact(OptionImpact.LOW) + .build()) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(new TranslatableText("options.guiScale")) + .setTooltip(new TranslatableText("sodium.options.gui_scale.tooltip")) + .setControl(option -> new SliderControl(option, 0, MuiGuiScaleHook.getMaxGuiScale(), 1, ControlValueFormatter.guiScale())) + .setBinding((opts, value) -> { + opts.guiScale = value; + + MinecraftClient client = MinecraftClient.getInstance(); + client.onResolutionChanged(); + }, opts -> opts.guiScale) + .build()) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(new TranslatableText("options.fullscreen")) + .setTooltip(new TranslatableText("sodium.options.fullscreen.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> { + opts.fullscreen = value; + + MinecraftClient client = MinecraftClient.getInstance(); + Window window = client.getWindow(); + + if (window != null && window.isFullscreen() != opts.fullscreen) { + window.toggleFullscreen(); + + // The client might not be able to enter full-screen mode + opts.fullscreen = window.isFullscreen(); + } + }, (opts) -> opts.fullscreen) + .build()) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(new TranslatableText("options.vsync")) + .setTooltip(new TranslatableText("sodium.options.v_sync.tooltip")) + .setControl(TickBoxControl::new) + .setBinding(new VanillaBooleanOptionBinding(Option.VSYNC)) + .setImpact(OptionImpact.VARIES) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(new TranslatableText("options.framerateLimit")) + .setTooltip(new TranslatableText("sodium.options.fps_limit.tooltip")) + .setControl(option -> new SliderControl(option, 5, 260, 5, ControlValueFormatter.fpsLimit())) + .setBinding((opts, value) -> { + opts.maxFps = value; + MinecraftClient.getInstance().getWindow().setFramerateLimit(value); + }, opts -> opts.maxFps) + .build()) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(new TranslatableText("options.viewBobbing")) + .setTooltip(new TranslatableText("sodium.options.view_bobbing.tooltip")) + .setControl(TickBoxControl::new) + .setBinding(new VanillaBooleanOptionBinding(Option.VIEW_BOBBING)) + .build()) + .add(OptionImpl.createBuilder(AttackIndicator.class, vanillaOpts) + .setName(new TranslatableText("options.attackIndicator")) + .setTooltip(new TranslatableText("sodium.options.attack_indicator.tooltip")) + .setControl(opts -> new CyclingControl<>(opts, AttackIndicator.class, new Text[] { new TranslatableText("options.off"), new TranslatableText("options.attack.crosshair"), new TranslatableText("options.attack.hotbar") })) + .setBinding((opts, value) -> opts.attackIndicator = value, (opts) -> opts.attackIndicator) + .build()) + .build()); + + return new OptionPage(new TranslatableText("stat.generalButton"), ImmutableList.copyOf(groups)); + } + + public static OptionPage quality() { + List groups = new ArrayList<>(); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(GraphicsMode.class, vanillaOpts) + .setName(new TranslatableText("options.graphics")) + .setTooltip(new TranslatableText("sodium.options.graphics_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, GraphicsMode.class, new Text[] { new TranslatableText("options.graphics.fast"), new TranslatableText("options.graphics.fancy"), new TranslatableText("options.graphics.fabulous") })) + .setBinding( + (opts, value) -> opts.graphicsMode = value, + opts -> opts.graphicsMode) + .setImpact(OptionImpact.HIGH) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .setName(new TranslatableText("options.renderClouds")) + .setTooltip(new TranslatableText("sodium.options.clouds_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setBinding((opts, value) -> opts.quality.cloudQuality = value, opts -> opts.quality.cloudQuality) + .setImpact(OptionImpact.LOW) + .build()) + .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .setName(new TranslatableText("soundCategory.weather")) + .setTooltip(new TranslatableText("sodium.options.weather_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setBinding((opts, value) -> opts.quality.weatherQuality = value, opts -> opts.quality.weatherQuality) + .setImpact(OptionImpact.MEDIUM) + .build()) + .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.leaves_quality.name")) + .setTooltip(new TranslatableText("sodium.options.leaves_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setBinding((opts, value) -> opts.quality.leavesQuality = value, opts -> opts.quality.leavesQuality) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .add(OptionImpl.createBuilder(ParticlesMode.class, vanillaOpts) + .setName(new TranslatableText("options.particles")) + .setTooltip(new TranslatableText("sodium.options.particle_quality.tooltip")) + .setControl(opt -> new CyclingControl<>(opt, ParticlesMode.class, new Text[] { new TranslatableText("options.particles.all"), new TranslatableText("options.particles.decreased"), new TranslatableText("options.particles.minimal") })) + .setBinding((opts, value) -> opts.particles = value, (opts) -> opts.particles) + .setImpact(OptionImpact.MEDIUM) + .build()) + .add(OptionImpl.createBuilder(SodiumGameOptions.LightingQuality.class, sodiumOpts) + .setName(new TranslatableText("options.ao")) + .setTooltip(new TranslatableText("sodium.options.smooth_lighting.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.LightingQuality.class)) + .setBinding((opts, value) -> opts.quality.smoothLighting = value, opts -> opts.quality.smoothLighting) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(new TranslatableText("options.biomeBlendRadius")) + .setTooltip(new TranslatableText("sodium.options.biome_blend.tooltip")) + .setControl(option -> new SliderControl(option, 0, 7, 1, ControlValueFormatter.quantityOrDisabled("sodium.options.biome_blend.value", "gui.none"))) + .setBinding((opts, value) -> opts.biomeBlendRadius = value, opts -> opts.biomeBlendRadius) + .setImpact(OptionImpact.LOW) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(new TranslatableText("options.entityDistanceScaling")) + .setTooltip(new TranslatableText("sodium.options.entity_distance.tooltip")) + .setControl(option -> new SliderControl(option, 50, 500, 25, ControlValueFormatter.percentage())) + .setBinding((opts, value) -> opts.entityDistanceScaling = value / 100.0F, opts -> Math.round(opts.entityDistanceScaling * 100.0F)) + .setImpact(OptionImpact.MEDIUM) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(new TranslatableText("options.entityShadows")) + .setTooltip(new TranslatableText("sodium.options.entity_shadows.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.entityShadows = value, opts -> opts.entityShadows) + .setImpact(OptionImpact.LOW) + .build()) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.vignette.name")) + .setTooltip(new TranslatableText("sodium.options.vignette.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.quality.enableVignette = value, opts -> opts.quality.enableVignette) + .setImpact(OptionImpact.LOW) + .build()) + .build()); + + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(new TranslatableText("options.mipmapLevels")) + .setTooltip(new TranslatableText("sodium.options.mipmap_levels.tooltip")) + .setControl(option -> new SliderControl(option, 0, 4, 1, ControlValueFormatter.multiplier())) + .setBinding((opts, value) -> opts.mipmapLevels = value, opts -> opts.mipmapLevels) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_ASSET_RELOAD) + .build()) + .build()); + + + return new OptionPage(new TranslatableText("sodium.options.pages.quality"), ImmutableList.copyOf(groups)); + } + + public static OptionPage advanced() { + List groups = new ArrayList<>(); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.use_chunk_multidraw.name")) + .setTooltip(new TranslatableText("sodium.options.use_chunk_multidraw.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.advanced.useChunkMultidraw = value, opts -> opts.advanced.useChunkMultidraw) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .setImpact(OptionImpact.EXTREME) + .setEnabled(MultidrawChunkRenderBackend.isSupported(sodiumOpts.getData().advanced.ignoreDriverBlacklist)) + .build()) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.use_vertex_objects.name")) + .setTooltip(new TranslatableText("sodium.options.use_vertex_objects.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.advanced.useVertexArrayObjects = value, opts -> opts.advanced.useVertexArrayObjects) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .setImpact(OptionImpact.LOW) + .build()) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.use_block_face_culling.name")) + .setTooltip(new TranslatableText("sodium.options.use_block_face_culling.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.MEDIUM) + .setBinding((opts, value) -> opts.advanced.useBlockFaceCulling = value, opts -> opts.advanced.useBlockFaceCulling) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.use_compact_vertex_format.name")) + .setTooltip(new TranslatableText("sodium.options.use_compact_vertex_format.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.MEDIUM) + .setBinding((opts, value) -> opts.advanced.useCompactVertexFormat = value, opts -> opts.advanced.useCompactVertexFormat) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.use_fog_occlusion.name")) + .setTooltip(new TranslatableText("sodium.options.use_fog_occlusion.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.advanced.useFogOcclusion = value, opts -> opts.advanced.useFogOcclusion) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.translucency_sorting.name")) + .setTooltip(new TranslatableText("sodium.options.translucency_sorting.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.advanced.translucencySorting = value, opts -> opts.advanced.translucencySorting) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.use_entity_culling.name")) + .setTooltip(new TranslatableText("sodium.options.use_entity_culling.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.MEDIUM) + .setBinding((opts, value) -> opts.advanced.useEntityCulling = value, opts -> opts.advanced.useEntityCulling) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.animate_only_visible_textures.name")) + .setTooltip(new TranslatableText("sodium.options.animate_only_visible_textures.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.HIGH) + .setBinding((opts, value) -> opts.advanced.animateOnlyVisibleTextures = value, opts -> opts.advanced.animateOnlyVisibleTextures) + .build() + ) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.allow_direct_memory_access.name")) + .setTooltip(new TranslatableText("sodium.options.allow_direct_memory_access.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.HIGH) + .setBinding((opts, value) -> opts.advanced.allowDirectMemoryAccess = value, opts -> opts.advanced.allowDirectMemoryAccess) + .build() + ) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.ignore_driver_blacklist.name")) + .setTooltip(new TranslatableText("sodium.options.ignore_driver_blacklist.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.advanced.ignoreDriverBlacklist = value, opts -> opts.advanced.ignoreDriverBlacklist) + .build() + ) + .build()); + + return new OptionPage(new TranslatableText("sodium.options.pages.advanced"), ImmutableList.copyOf(groups)); + } + + public static OptionPage performance() { + List groups = new ArrayList<>(); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(int.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.chunk_update_threads.name")) + .setTooltip(new TranslatableText("sodium.options.chunk_update_threads.tooltip")) + .setControl(o -> new SliderControl(o, 0, Runtime.getRuntime().availableProcessors(), 1, ControlValueFormatter.quantityOrDisabled("sodium.options.threads.value", "sodium.options.default"))) + .setImpact(OptionImpact.HIGH) + .setBinding((opts, value) -> opts.performance.chunkBuilderThreads = value, opts -> opts.performance.chunkBuilderThreads) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.always_defer_chunk_updates.name")) + .setTooltip(new TranslatableText("sodium.options.always_defer_chunk_updates.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.HIGH) + .setBinding((opts, value) -> opts.performance.alwaysDeferChunkUpdates = value, opts -> opts.performance.alwaysDeferChunkUpdates) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .build()); + + return new OptionPage(new TranslatableText("sodium.options.pages.performance"), ImmutableList.copyOf(groups)); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java new file mode 100644 index 000000000..82cb38980 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -0,0 +1,149 @@ +package me.jellysquid.mods.sodium.client.gui; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.options.FormattedTextProvider; +import net.minecraft.client.option.GraphicsMode; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; + +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +public class SodiumGameOptions { + public final QualitySettings quality = new QualitySettings(); + public final AdvancedSettings advanced = new AdvancedSettings(); + public final PerformanceSettings performance = new PerformanceSettings(); + public final NotificationSettings notifications = new NotificationSettings(); + + private Path configPath; + + public static class AdvancedSettings { + public boolean useVertexArrayObjects = true; + public boolean useChunkMultidraw = true; + + public boolean animateOnlyVisibleTextures = true; + public boolean useEntityCulling = true; + public boolean useParticleCulling = true; + public boolean useFogOcclusion = true; + public boolean useCompactVertexFormat = true; + public boolean useBlockFaceCulling = true; + public boolean allowDirectMemoryAccess = true; + public boolean ignoreDriverBlacklist = false; + public boolean translucencySorting = false; + } + + public static class PerformanceSettings { + public int chunkBuilderThreads = 0; + public boolean alwaysDeferChunkUpdates = false; + } + + public static class QualitySettings { + public GraphicsQuality cloudQuality = GraphicsQuality.DEFAULT; + public GraphicsQuality weatherQuality = GraphicsQuality.DEFAULT; + public GraphicsQuality leavesQuality = GraphicsQuality.DEFAULT; + + public boolean enableVignette = true; + public boolean enableClouds = true; + + public LightingQuality smoothLighting = LightingQuality.HIGH; + } + + public static class NotificationSettings { + public boolean hideDonationButton = false; + } + + public enum GraphicsQuality implements FormattedTextProvider { + DEFAULT(new TranslatableText("generator.default")), + FANCY(new TranslatableText("options.clouds.fancy")), + FAST(new TranslatableText("options.clouds.fast")); + + private final Text name; + + GraphicsQuality(Text name) { + this.name = name; + } + + @Override + public Text getLocalizedName() { + return this.name; + } + + public boolean isFancy(GraphicsMode graphicsMode) { + return (this == FANCY) || (this == DEFAULT && (graphicsMode == GraphicsMode.FANCY || graphicsMode == GraphicsMode.FABULOUS)); + } + } + + public enum LightingQuality implements FormattedTextProvider { + HIGH(new TranslatableText("options.ao.max")), + LOW(new TranslatableText("options.ao.min")), + OFF(new TranslatableText("options.ao.off")); + + private final Text name; + + LightingQuality(Text name) { + this.name = name; + } + + @Override + public Text getLocalizedName() { + return this.name; + } + } + + private static final Gson GSON = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .setPrettyPrinting() + .excludeFieldsWithModifiers(Modifier.PRIVATE) + .create(); + + public static SodiumGameOptions load(Path path) { + SodiumGameOptions config; + boolean resaveConfig = true; + + if (Files.exists(path)) { + try (FileReader reader = new FileReader(path.toFile())) { + config = GSON.fromJson(reader, SodiumGameOptions.class); + } catch (IOException e) { + throw new RuntimeException("Could not parse config", e); + } catch (JsonSyntaxException e) { + SodiumClientMod.logger().error("Could not parse config, will fallback to default settings", e); + config = new SodiumGameOptions(); + resaveConfig = false; + } + } else { + config = new SodiumGameOptions(); + } + + config.configPath = path; + + try { + if(resaveConfig) + config.writeChanges(); + } catch (IOException e) { + throw new RuntimeException("Couldn't update config file", e); + } + + return config; + } + + public void writeChanges() throws IOException { + Path dir = this.configPath.getParent(); + + if (!Files.exists(dir)) { + Files.createDirectories(dir); + } else if (!Files.isDirectory(dir)) { + throw new IOException("Not a directory: " + dir); + } + + Files.write(this.configPath, GSON.toJson(this) + .getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java new file mode 100644 index 000000000..597e306e7 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java @@ -0,0 +1,316 @@ +package me.jellysquid.mods.sodium.client.gui; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; +import me.jellysquid.mods.sodium.client.gui.options.OptionGroup; +import me.jellysquid.mods.sodium.client.gui.options.OptionImpact; +import me.jellysquid.mods.sodium.client.gui.options.OptionPage; +import me.jellysquid.mods.sodium.client.gui.options.control.Control; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; +import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; +import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.Drawable; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.option.VideoOptionsScreen; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.OrderedText; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.Formatting; +import net.minecraft.util.Language; +import net.minecraft.util.Util; +import org.lwjgl.glfw.GLFW; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Stream; + +public class SodiumOptionsGUI extends Screen { + private final List pages = new ArrayList<>(); + + private final List> controls = new ArrayList<>(); + private final List drawable = new ArrayList<>(); + + private final Screen prevScreen; + + private OptionPage currentPage; + + private FlatButtonWidget applyButton, closeButton, undoButton; + private FlatButtonWidget donateButton, hideDonateButton; + + private boolean hasPendingChanges; + private ControlElement hoveredElement; + + public SodiumOptionsGUI(Screen prevScreen) { + super(new TranslatableText("Rubidium Options")); + + this.prevScreen = prevScreen; + + this.pages.add(SodiumGameOptionPages.general()); + this.pages.add(SodiumGameOptionPages.quality()); + this.pages.add(SodiumGameOptionPages.advanced()); + this.pages.add(SodiumGameOptionPages.performance()); + } + + public void setPage(OptionPage page) { + this.currentPage = page; + + this.rebuildGUI(); + } + + @Override + protected void init() { + super.init(); + + this.rebuildGUI(); + } + + private void rebuildGUI() { + this.controls.clear(); + this.children.clear(); + this.drawable.clear(); + + if (this.currentPage == null) { + if (this.pages.isEmpty()) { + throw new IllegalStateException("No pages are available?!"); + } + + // Just use the first page for now + this.currentPage = this.pages.get(0); + } + + this.rebuildGUIPages(); + this.rebuildGUIOptions(); + + this.undoButton = new FlatButtonWidget(new Dim2i(this.width - 211, this.height - 26, 65, 20), new TranslatableText("sodium.options.buttons.undo").getString(), this::undoChanges); + this.applyButton = new FlatButtonWidget(new Dim2i(this.width - 142, this.height - 26, 65, 20), new TranslatableText("sodium.options.buttons.apply").getString(), this::applyChanges); + this.closeButton = new FlatButtonWidget(new Dim2i(this.width - 73, this.height - 26, 65, 20), new TranslatableText("gui.done").getString(), this::onClose); + this.donateButton = new FlatButtonWidget(new Dim2i(this.width - 128, 6, 100, 20), new TranslatableText("sodium.options.buttons.donate").getString(), this::openDonationPage); + this.hideDonateButton = new FlatButtonWidget(new Dim2i(this.width - 26, 6, 20, 20), "x", this::hideDonationButton); + + if (SodiumClientMod.options().notifications.hideDonationButton) { + this.setDonationButtonVisibility(false); + } + + this.children.add(this.undoButton); + this.children.add(this.applyButton); + this.children.add(this.closeButton); + this.children.add(this.donateButton); + this.children.add(this.hideDonateButton); + + for (Element element : this.children) { + if (element instanceof Drawable) { + this.drawable.add((Drawable) element); + } + } + } + + private void setDonationButtonVisibility(boolean value) { + this.donateButton.setVisible(value); + this.hideDonateButton.setVisible(value); + } + + private void hideDonationButton() { + SodiumGameOptions options = SodiumClientMod.options(); + options.notifications.hideDonationButton = true; + + try { + options.writeChanges(); + } catch (IOException e) { + throw new RuntimeException("Failed to save configuration", e); + } + + this.setDonationButtonVisibility(false); + } + + private void rebuildGUIPages() { + int x = 6; + int y = 6; + + for (OptionPage page : this.pages) { + int width = 12 + this.textRenderer.getWidth(page.getNewName()); + + FlatButtonWidget button = new FlatButtonWidget(new Dim2i(x, y, width, 18), page.getNewName(), () -> this.setPage(page)); + button.setSelected(this.currentPage == page); + + x += width + 6; + + this.children.add(button); + } + } + + private void rebuildGUIOptions() { + int x = 6; + int y = 28; + + for (OptionGroup group : this.currentPage.getGroups()) { + // Add each option's control element + for (Option option : group.getOptions()) { + Control control = option.getControl(); + ControlElement element = control.createElement(new Dim2i(x, y, 200, 18)); + + this.controls.add(element); + this.children.add(element); + + // Move down to the next option + y += 18; + } + + // Add padding beneath each option group + y += 4; + } + } + + @Override + public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { + super.renderBackground(matrixStack); + + this.updateControls(); + + for (Drawable drawable : this.drawable) { + drawable.render(matrixStack, mouseX, mouseY, delta); + } + + if (this.hoveredElement != null) { + this.renderOptionTooltip(matrixStack, this.hoveredElement); + } + } + + private void updateControls() { + ControlElement hovered = this.getActiveControls() + .filter(ControlElement::isHovered) + .findFirst() + .orElse(null); + + boolean hasChanges = this.getAllOptions() + .anyMatch(Option::hasChanged); + + for (OptionPage page : this.pages) { + for (Option option : page.getOptions()) { + if (option.hasChanged()) { + hasChanges = true; + } + } + } + + this.applyButton.setEnabled(hasChanges); + this.undoButton.setVisible(hasChanges); + this.closeButton.setEnabled(!hasChanges); + + this.hasPendingChanges = hasChanges; + this.hoveredElement = hovered; + } + + private Stream> getAllOptions() { + return this.pages.stream() + .flatMap(s -> s.getOptions().stream()); + } + + private Stream> getActiveControls() { + return this.controls.stream(); + } + + private void renderOptionTooltip(MatrixStack matrixStack, ControlElement element) { + Dim2i dim = element.getDimensions(); + + int textPadding = 3; + int boxPadding = 3; + + int boxWidth = 200; + + int boxY = dim.getOriginY(); + int boxX = dim.getLimitX() + boxPadding; + + Option option = element.getOption(); + List tooltip = new ArrayList<>(this.textRenderer.wrapLines(option.getTooltip(), boxWidth - (textPadding * 2))); + + OptionImpact impact = option.getImpact(); + + if (impact != null) { + tooltip.add(Language.getInstance().reorder(new TranslatableText("sodium.options.performance_impact_string", impact.toDisplayString()).formatted(Formatting.GRAY))); + } + + int boxHeight = (tooltip.size() * 12) + boxPadding; + int boxYLimit = boxY + boxHeight; + int boxYCutoff = this.height - 40; + + // If the box is going to be cutoff on the Y-axis, move it back up the difference + if (boxYLimit > boxYCutoff) { + boxY -= boxYLimit - boxYCutoff; + } + + this.fillGradient(matrixStack, boxX, boxY, boxX + boxWidth, boxY + boxHeight, 0xE0000000, 0xE0000000); + + for (int i = 0; i < tooltip.size(); i++) { + this.textRenderer.draw(matrixStack, tooltip.get(i), boxX + textPadding, boxY + textPadding + (i * 12), 0xFFFFFFFF); + } + } + + private void applyChanges() { + final HashSet> dirtyStorages = new HashSet<>(); + final EnumSet flags = EnumSet.noneOf(OptionFlag.class); + + this.getAllOptions().forEach((option -> { + if (!option.hasChanged()) { + return; + } + + option.applyChanges(); + + flags.addAll(option.getFlags()); + dirtyStorages.add(option.getStorage()); + })); + + MinecraftClient client = MinecraftClient.getInstance(); + + if (flags.contains(OptionFlag.REQUIRES_RENDERER_RELOAD)) { + client.worldRenderer.reload(); + } + + if (flags.contains(OptionFlag.REQUIRES_ASSET_RELOAD)) { + client.setMipmapLevels(client.options.mipmapLevels); + client.reloadResourcesConcurrently(); + } + + for (OptionStorage storage : dirtyStorages) { + storage.save(); + } + } + + private void undoChanges() { + this.getAllOptions() + .forEach(Option::reset); + } + + private void openDonationPage() { + Util.getOperatingSystem() + .open("https://caffeinemc.net/donate"); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (keyCode == GLFW.GLFW_KEY_P && (modifiers & GLFW.GLFW_MOD_SHIFT) != 0) { + MinecraftClient.getInstance().openScreen(new VideoOptionsScreen(this.prevScreen, MinecraftClient.getInstance().options)); + + return true; + } + + return super.keyPressed(keyCode, scanCode, modifiers); + } + + @Override + public boolean shouldCloseOnEsc() { + return !this.hasPendingChanges; + } + + @Override + public void onClose() { + this.client.openScreen(this.prevScreen); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/FormattedTextProvider.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/FormattedTextProvider.java new file mode 100644 index 000000000..0f3a79209 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/FormattedTextProvider.java @@ -0,0 +1,7 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +import net.minecraft.text.Text; + +public interface FormattedTextProvider { + Text getLocalizedName(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java new file mode 100644 index 000000000..55477f48c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java @@ -0,0 +1,35 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +import me.jellysquid.mods.sodium.client.gui.options.control.Control; +import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; +import net.minecraft.text.Text; + +import java.util.Collection; + +public interface Option { + Text getNewName(); + + String getName(); + + Text getTooltip(); + + OptionImpact getImpact(); + + Control getControl(); + + T getValue(); + + void setValue(T value); + + void reset(); + + OptionStorage getStorage(); + + boolean isAvailable(); + + boolean hasChanged(); + + void applyChanges(); + + Collection getFlags(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java new file mode 100644 index 000000000..d7ac00621 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java @@ -0,0 +1,7 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +public enum OptionFlag { + REQUIRES_RENDERER_RELOAD, + REQUIRES_ASSET_RELOAD, + REQUIRES_GAME_RESTART +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java new file mode 100644 index 000000000..97426724a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java @@ -0,0 +1,39 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +import com.google.common.collect.ImmutableList; +import org.apache.commons.lang3.Validate; + +import java.util.ArrayList; +import java.util.List; + +public class OptionGroup { + private final ImmutableList> options; + + private OptionGroup(ImmutableList> options) { + this.options = options; + } + + public static Builder createBuilder() { + return new Builder(); + } + + public ImmutableList> getOptions() { + return this.options; + } + + public static class Builder { + private final List> options = new ArrayList<>(); + + public Builder add(Option option) { + this.options.add(option); + + return this; + } + + public OptionGroup build() { + Validate.notEmpty(this.options, "At least one option must be specified"); + + return new OptionGroup(ImmutableList.copyOf(this.options)); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java new file mode 100644 index 000000000..e5ab58cd9 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java @@ -0,0 +1,24 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +import net.minecraft.text.TranslatableText; +import net.minecraft.util.Formatting; + +public enum OptionImpact { + LOW(Formatting.GREEN, new TranslatableText("sodium.option_impact.low").getString()), + MEDIUM(Formatting.YELLOW, new TranslatableText("sodium.option_impact.medium").getString()), + HIGH(Formatting.GOLD, new TranslatableText("sodium.option_impact.high").getString()), + EXTREME(Formatting.RED, new TranslatableText("sodium.option_impact.extreme").getString()), + VARIES(Formatting.WHITE, new TranslatableText("sodium.option_impact.varies").getString()); + + private final Formatting color; + private final String text; + + OptionImpact(Formatting color, String text) { + this.color = color; + this.text = text; + } + + public String toDisplayString() { + return this.color + this.text; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java new file mode 100644 index 000000000..10518748e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java @@ -0,0 +1,217 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +import me.jellysquid.mods.sodium.client.gui.options.binding.GenericBinding; +import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding; +import me.jellysquid.mods.sodium.client.gui.options.control.Control; +import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import org.apache.commons.lang3.Validate; + +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class OptionImpl implements Option { + private final OptionStorage storage; + + private final OptionBinding binding; + private final Control control; + + private final EnumSet flags; + + private final Text name; + private final Text tooltip; + + private final OptionImpact impact; + + private T value; + private T modifiedValue; + + private final boolean enabled; + + private OptionImpl(OptionStorage storage, + Text name, + Text tooltip, + OptionBinding binding, + Function, Control> control, + EnumSet flags, + OptionImpact impact, + boolean enabled) { + this.storage = storage; + this.name = name; + this.tooltip = tooltip; + this.binding = binding; + this.impact = impact; + this.flags = flags; + this.control = control.apply(this); + this.enabled = enabled; + + this.reset(); + } + + @Override + public Text getNewName() { + return this.name; + } + + @Override + public String getName() { + return this.getNewName().getString(); + } + + @Override + public Text getTooltip() { + return this.tooltip; + } + + @Override + public OptionImpact getImpact() { + return this.impact; + } + + @Override + public Control getControl() { + return this.control; + } + + @Override + public T getValue() { + return this.modifiedValue; + } + + @Override + public void setValue(T value) { + this.modifiedValue = value; + } + + @Override + public void reset() { + this.value = this.binding.getValue(this.storage.getData()); + this.modifiedValue = this.value; + } + + @Override + public OptionStorage getStorage() { + return this.storage; + } + + @Override + public boolean isAvailable() { + return this.enabled; + } + + @Override + public boolean hasChanged() { + return !this.value.equals(this.modifiedValue); + } + + @Override + public void applyChanges() { + this.binding.setValue(this.storage.getData(), this.modifiedValue); + this.value = this.modifiedValue; + } + + @Override + public Collection getFlags() { + return this.flags; + } + + public static Builder createBuilder(Class type, OptionStorage storage) { + return new Builder<>(storage); + } + + public static class Builder { + private final OptionStorage storage; + private Text name; + private Text tooltip; + private OptionBinding binding; + private Function, Control> control; + private OptionImpact impact; + private final EnumSet flags = EnumSet.noneOf(OptionFlag.class); + private boolean enabled = true; + + private Builder(OptionStorage storage) { + this.storage = storage; + } + + public Builder setName(Text name) { + Validate.notNull(name, "Argument must not be null"); + + this.name = name; + + return this; + } + + public Builder setName(String name) { + return setName(new LiteralText(name)); + } + + public Builder setTooltip(Text tooltip) { + Validate.notNull(tooltip, "Argument must not be null"); + + this.tooltip = tooltip; + + return this; + } + + public Builder setTooltip(String tooltip) { + return setTooltip(new LiteralText(tooltip)); + } + + public Builder setBinding(BiConsumer setter, Function getter) { + Validate.notNull(setter, "Setter must not be null"); + Validate.notNull(getter, "Getter must not be null"); + + this.binding = new GenericBinding<>(setter, getter); + + return this; + } + + + public Builder setBinding(OptionBinding binding) { + Validate.notNull(binding, "Argument must not be null"); + + this.binding = binding; + + return this; + } + + public Builder setControl(Function, Control> control) { + Validate.notNull(control, "Argument must not be null"); + + this.control = control; + + return this; + } + + public Builder setImpact(OptionImpact impact) { + this.impact = impact; + + return this; + } + + public Builder setEnabled(boolean value) { + this.enabled = value; + + return this; + } + + public Builder setFlags(OptionFlag... flags) { + Collections.addAll(this.flags, flags); + + return this; + } + + public OptionImpl build() { + Validate.notNull(this.name, "Name must be specified"); + Validate.notNull(this.tooltip, "Tooltip must be specified"); + Validate.notNull(this.binding, "Option binding must be specified"); + Validate.notNull(this.control, "Control must be specified"); + + return new OptionImpl<>(this.storage, this.name, this.tooltip, this.binding, this.control, this.flags, this.impact, this.enabled); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java new file mode 100644 index 000000000..5d4cd852b --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java @@ -0,0 +1,45 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +import com.google.common.collect.ImmutableList; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; + +public class OptionPage { + private final Text name; + private final ImmutableList groups; + private final ImmutableList> options; + + public OptionPage(String name, ImmutableList groups) { + this(new LiteralText(name), groups); + } + + public OptionPage(Text name, ImmutableList groups) { + this.name = name; + this.groups = groups; + + ImmutableList.Builder> builder = ImmutableList.builder(); + + for (OptionGroup group : groups) { + builder.addAll(group.getOptions()); + } + + this.options = builder.build(); + } + + public ImmutableList getGroups() { + return this.groups; + } + + public ImmutableList> getOptions() { + return this.options; + } + + public Text getNewName() { + return this.name; + } + + public String getName() { + return this.getNewName().getString(); + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java new file mode 100644 index 000000000..a7ace2ef5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java @@ -0,0 +1,5 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +public interface TextProvider { + String getLocalizedName(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java new file mode 100644 index 000000000..9e166c93e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java @@ -0,0 +1,24 @@ +package me.jellysquid.mods.sodium.client.gui.options.binding; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class GenericBinding implements OptionBinding { + private final BiConsumer setter; + private final Function getter; + + public GenericBinding(BiConsumer setter, Function getter) { + this.setter = setter; + this.getter = getter; + } + + @Override + public void setValue(S storage, T value) { + this.setter.accept(storage, value); + } + + @Override + public T getValue(S storage) { + return this.getter.apply(storage); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java new file mode 100644 index 000000000..5e597a679 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java @@ -0,0 +1,7 @@ +package me.jellysquid.mods.sodium.client.gui.options.binding; + +public interface OptionBinding { + void setValue(S storage, T value); + + T getValue(S storage); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java new file mode 100644 index 000000000..97fb26305 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java @@ -0,0 +1,23 @@ +package me.jellysquid.mods.sodium.client.gui.options.binding.compat; + +import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding; +import net.minecraft.client.option.BooleanOption; +import net.minecraft.client.option.GameOptions; + +public class VanillaBooleanOptionBinding implements OptionBinding { + private final BooleanOption option; + + public VanillaBooleanOptionBinding(BooleanOption option) { + this.option = option; + } + + @Override + public void setValue(GameOptions storage, Boolean value) { + this.option.set(storage, value.toString()); + } + + @Override + public Boolean getValue(GameOptions storage) { + return this.option.get(storage); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java new file mode 100644 index 000000000..28931db82 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java @@ -0,0 +1,12 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.util.Dim2i; + +public interface Control { + Option getOption(); + + ControlElement createElement(Dim2i dim); + + int getMaxWidth(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java new file mode 100644 index 000000000..380b2a145 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java @@ -0,0 +1,58 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.widgets.AbstractWidget; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Formatting; + +public class ControlElement extends AbstractWidget { + protected final Option option; + + protected final Dim2i dim; + + protected boolean hovered; + + public ControlElement(Option option, Dim2i dim) { + this.option = option; + this.dim = dim; + } + + public boolean isHovered() { + return this.hovered; + } + + @Override + public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { + String name = this.option.getName(); + String label; + + if (this.hovered && this.font.getWidth(name) > (this.dim.getWidth() - this.option.getControl().getMaxWidth())) { + name = name.substring(0, Math.min(name.length(), 10)) + "..."; + } + + if (this.option.isAvailable()) { + if (this.option.hasChanged()) { + label = Formatting.ITALIC + name + " *"; + } else { + label = Formatting.WHITE + name; + } + } else { + label = String.valueOf(Formatting.GRAY) + Formatting.STRIKETHROUGH + name; + } + + this.hovered = this.dim.containsCursor(mouseX, mouseY); + + + this.drawRect(this.dim.getOriginX(), this.dim.getOriginY(), this.dim.getLimitX(), this.dim.getLimitY(), this.hovered ? 0xE0000000 : 0x90000000); + this.drawString(matrixStack, label, this.dim.getOriginX() + 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); + } + + public Option getOption() { + return this.option; + } + + public Dim2i getDimensions() { + return this.dim; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java new file mode 100644 index 000000000..1220b2975 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java @@ -0,0 +1,47 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import net.minecraft.text.TranslatableText; + +public interface ControlValueFormatter { + static ControlValueFormatter guiScale() { + return (v) -> (v == 0) ? new TranslatableText("options.guiScale.auto").getString() : new TranslatableText(v + "x").getString(); + } + + static ControlValueFormatter fpsLimit() { + return (v) -> (v == 260) ? new TranslatableText("options.framerateLimit.max").getString() : new TranslatableText("options.framerate", v).getString(); + } + + static ControlValueFormatter brightness() { + return (v) -> { + if (v == 0) { + return new TranslatableText("options.gamma.min").getString(); + } else if (v == 100) { + return new TranslatableText("options.gamma.max").getString(); + } else { + return new TranslatableText(v + "%").getString(); + } + }; + } + + String format(int value); + + static ControlValueFormatter percentage() { + return (v) -> new TranslatableText(v + "%").getString(); + } + + static ControlValueFormatter multiplier() { + return (v) -> new TranslatableText(v + "x").getString(); + } + + static ControlValueFormatter quantity(String name) { + return (v) -> new TranslatableText(name, v).getString(); + } + + static ControlValueFormatter quantityOrDisabled(String name, String disableText) { + return (v) -> new TranslatableText(v == 0 ? disableText : name, v).getString(); + } + + static ControlValueFormatter number() { + return String::valueOf; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java new file mode 100644 index 000000000..d8e778cfd --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java @@ -0,0 +1,121 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import me.jellysquid.mods.sodium.client.gui.options.FormattedTextProvider; +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.TextProvider; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import org.apache.commons.lang3.Validate; + +import java.util.Arrays; + +public class CyclingControl> implements Control { + private final Option option; + private final T[] allowedValues; + private final Text[] names; + + public CyclingControl(Option option, Class enumType) { + this(option, enumType, enumType.getEnumConstants()); + } + + public CyclingControl(Option option, Class enumType, Text[] names) { + T[] universe = enumType.getEnumConstants(); + + Validate.isTrue(universe.length == names.length, "Mismatch between universe length and names array length"); + Validate.notEmpty(universe, "The enum universe must contain at least one item"); + + this.option = option; + this.allowedValues = universe; + this.names = names; + } + + @Deprecated + public CyclingControl(Option option, Class enumType, String[] names) { + this(option, enumType, Arrays.stream(names).map(LiteralText::new).toArray(Text[]::new)); + } + + public CyclingControl(Option option, Class enumType, T[] allowedValues) { + T[] universe = enumType.getEnumConstants(); + + this.option = option; + this.allowedValues = allowedValues; + this.names = new Text[universe.length]; + + for (int i = 0; i < this.names.length; i++) { + Text name; + T value = universe[i]; + + if (value instanceof TextProvider) { + name = new LiteralText(((TextProvider)value).getLocalizedName()); + } else if(value instanceof FormattedTextProvider) { + name = ((FormattedTextProvider)value).getLocalizedName(); + } else { + name = new LiteralText(value.name()); + } + + this.names[i] = name; + } + } + + @Override + public Option getOption() { + return this.option; + } + + @Override + public ControlElement createElement(Dim2i dim) { + return new CyclingControlElement<>(this.option, dim, this.allowedValues, this.names); + } + + @Override + public int getMaxWidth() { + return 70; + } + + private static class CyclingControlElement> extends ControlElement { + private final T[] allowedValues; + private final Text[] names; + private int currentIndex; + + public CyclingControlElement(Option option, Dim2i dim, T[] allowedValues, Text[] names) { + super(option, dim); + + this.allowedValues = allowedValues; + this.names = names; + this.currentIndex = 0; + + for (int i = 0; i < allowedValues.length; i++) { + if (allowedValues[i] == option.getValue()) { + this.currentIndex = i; + break; + } + } + } + + @Override + public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { + super.render(matrixStack, mouseX, mouseY, delta); + + Enum value = this.option.getValue(); + Text name = this.names[value.ordinal()]; + + int strWidth = this.getTextWidth(name); + this.drawText(matrixStack, name, this.dim.getLimitX() - strWidth - 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { + this.currentIndex = (this.option.getValue().ordinal() + 1) % this.allowedValues.length; + this.option.setValue(this.allowedValues[this.currentIndex]); + this.playClickSound(); + + return true; + } + + return false; + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java new file mode 100644 index 000000000..0eca60523 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java @@ -0,0 +1,164 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.util.math.Rect2i; +import net.minecraft.util.math.MathHelper; +import org.apache.commons.lang3.Validate; + +public class SliderControl implements Control { + private final Option option; + + private final int min, max, interval; + + private final ControlValueFormatter mode; + + public SliderControl(Option option, int min, int max, int interval, ControlValueFormatter mode) { + Validate.isTrue(max > min, "The maximum value must be greater than the minimum value"); + Validate.isTrue(interval > 0, "The slider interval must be greater than zero"); + Validate.isTrue(((max - min) % interval) == 0, "The maximum value must be divisable by the interval"); + Validate.notNull(mode, "The slider mode must not be null"); + + this.option = option; + this.min = min; + this.max = max; + this.interval = interval; + this.mode = mode; + } + + @Override + public ControlElement createElement(Dim2i dim) { + return new Button(this.option, dim, this.min, this.max, this.interval, this.mode); + } + + @Override + public Option getOption() { + return this.option; + } + + @Override + public int getMaxWidth() { + return 130; + } + + private static class Button extends ControlElement { + private static final int THUMB_WIDTH = 2, TRACK_HEIGHT = 1; + + private final Rect2i sliderBounds; + private final ControlValueFormatter formatter; + + private final int min; + private final int range; + private final int interval; + + private double thumbPosition; + + public Button(Option option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter) { + super(option, dim); + + this.min = min; + this.range = max - min; + this.interval = interval; + this.thumbPosition = this.getThumbPositionForValue(option.getValue()); + this.formatter = formatter; + + this.sliderBounds = new Rect2i(dim.getLimitX() - 96, dim.getCenterY() - 5, 90, 10); + } + + @Override + public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { + super.render(matrixStack, mouseX, mouseY, delta); + + if (this.option.isAvailable() && this.hovered) { + this.renderSlider(matrixStack); + } else { + this.renderStandaloneValue(matrixStack); + } + } + + private void renderStandaloneValue(MatrixStack matrixStack) { + int sliderX = this.sliderBounds.getX(); + int sliderY = this.sliderBounds.getY(); + int sliderWidth = this.sliderBounds.getWidth(); + int sliderHeight = this.sliderBounds.getHeight(); + + String label = this.formatter.format(this.option.getValue()); + int labelWidth = this.font.getWidth(label); + + this.drawString(matrixStack, label, sliderX + sliderWidth - labelWidth, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); + } + + private void renderSlider(MatrixStack matrixStack) { + int sliderX = this.sliderBounds.getX(); + int sliderY = this.sliderBounds.getY(); + int sliderWidth = this.sliderBounds.getWidth(); + int sliderHeight = this.sliderBounds.getHeight(); + + this.thumbPosition = this.getThumbPositionForValue(option.getValue()); + + double thumbOffset = MathHelper.clamp((double) (this.getIntValue() - this.min) / this.range * sliderWidth, 0, sliderWidth); + + double thumbX = sliderX + thumbOffset - THUMB_WIDTH; + double trackY = sliderY + (sliderHeight / 2) - ((double) TRACK_HEIGHT / 2); + + this.drawRect(thumbX, sliderY, thumbX + (THUMB_WIDTH * 2), sliderY + sliderHeight, 0xFFFFFFFF); + this.drawRect(sliderX, trackY, sliderX + sliderWidth, trackY + TRACK_HEIGHT, 0xFFFFFFFF); + + String label = String.valueOf(this.getIntValue()); + + int labelWidth = this.font.getWidth(label); + + this.drawString(matrixStack, label, sliderX - labelWidth - 6, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); + } + + public int getIntValue() { + return this.min + (this.interval * (int) Math.round(this.getSnappedThumbPosition() / this.interval)); + } + + public double getSnappedThumbPosition() { + return this.thumbPosition / (1.0D / this.range); + } + + public double getThumbPositionForValue(int value) { + return (value - this.min) * (1.0D / this.range); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (this.option.isAvailable() && button == 0 && this.sliderBounds.contains((int) mouseX, (int) mouseY)) { + this.setValueFromMouse(mouseX); + + return true; + } + + return false; + } + + private void setValueFromMouse(double d) { + this.setValue((d - (double) this.sliderBounds.getX()) / (double) this.sliderBounds.getWidth()); + } + + private void setValue(double d) { + this.thumbPosition = MathHelper.clamp(d, 0.0D, 1.0D); + + int value = this.getIntValue(); + + if (this.option.getValue() != value) { + this.option.setValue(value); + } + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if (this.option.isAvailable() && button == 0) { + this.setValueFromMouse(mouseX); + + return true; + } + + return false; + } + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java new file mode 100644 index 000000000..63bc41c12 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java @@ -0,0 +1,94 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.util.math.Rect2i; + +public class TickBoxControl implements Control { + private final Option option; + + public TickBoxControl(Option option) { + this.option = option; + } + + @Override + public ControlElement createElement(Dim2i dim) { + return new TickBoxControlElement(this.option, dim); + } + + @Override + public int getMaxWidth() { + return 30; + } + + @Override + public Option getOption() { + return this.option; + } + + private static class TickBoxControlElement extends ControlElement { + private final Rect2i button; + + public TickBoxControlElement(Option option, Dim2i dim) { + super(option, dim); + + this.button = new Rect2i(dim.getLimitX() - 16, dim.getCenterY() - 5, 10, 10); + } + + @Override + public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { + super.render(matrixStack, mouseX, mouseY, delta); + + final int x = this.button.getX(); + final int y = this.button.getY(); + final int w = x + this.button.getWidth(); + final int h = y + this.button.getHeight(); + + final boolean enabled = this.option.isAvailable(); + final boolean ticked = enabled && this.option.getValue(); + + final int color; + + if (enabled) { + color = ticked ? 0xFF94E4D3 : 0xFFFFFFFF; + } else { + color = 0xFFAAAAAA; + } + + if (ticked) { + this.drawRect(x + 2, y + 2, w - 2, h - 2, color); + } + + this.drawRectOutline(x, y, w, h, color); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { + this.option.setValue(!this.option.getValue()); + this.playClickSound(); + + return true; + } + + return false; + } + + protected void drawRectOutline(int x, int y, int w, int h, int color) { + final float a = (float) (color >> 24 & 255) / 255.0F; + final float r = (float) (color >> 16 & 255) / 255.0F; + final float g = (float) (color >> 8 & 255) / 255.0F; + final float b = (float) (color & 255) / 255.0F; + + this.drawQuads(vertices -> { + addQuad(vertices, x, y, w, y + 1, a, r, g, b); + addQuad(vertices, x, h - 1, w, h, a, r, g, b); + addQuad(vertices, x, y, x + 1, h, a, r, g, b); + addQuad(vertices, w - 1, y, w, h, a, r, g, b); + }); + } + } + + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java new file mode 100644 index 000000000..30663f78d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.sodium.client.gui.options.storage; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.option.GameOptions; + +public class MinecraftOptionsStorage implements OptionStorage { + private final MinecraftClient client; + + public MinecraftOptionsStorage() { + this.client = MinecraftClient.getInstance(); + } + + @Override + public GameOptions getData() { + return this.client.options; + } + + @Override + public void save() { + this.getData().write(); + + SodiumClientMod.logger().info("Flushed changes to Minecraft configuration"); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java new file mode 100644 index 000000000..a2e4966da --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java @@ -0,0 +1,7 @@ +package me.jellysquid.mods.sodium.client.gui.options.storage; + +public interface OptionStorage { + T getData(); + + void save(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java new file mode 100644 index 000000000..c8b3372b5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java @@ -0,0 +1,30 @@ +package me.jellysquid.mods.sodium.client.gui.options.storage; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; + +import java.io.IOException; + +public class SodiumOptionsStorage implements OptionStorage { + private final SodiumGameOptions options; + + public SodiumOptionsStorage() { + this.options = SodiumClientMod.options(); + } + + @Override + public SodiumGameOptions getData() { + return this.options; + } + + @Override + public void save() { + try { + this.options.writeChanges(); + } catch (IOException e) { + throw new RuntimeException("Couldn't save configuration changes", e); + } + + SodiumClientMod.logger().info("Flushed changes to Rubidium configuration"); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java new file mode 100644 index 000000000..cb7b292db --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java @@ -0,0 +1,77 @@ +package me.jellysquid.mods.sodium.client.gui.widgets; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.Drawable; +import net.minecraft.client.gui.Element; +import net.minecraft.client.render.*; +import net.minecraft.client.sound.PositionedSoundInstance; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import org.lwjgl.opengl.GL20C; + +import java.util.function.Consumer; + +public abstract class AbstractWidget implements Drawable, Element { + protected final TextRenderer font; + + protected AbstractWidget() { + this.font = MinecraftClient.getInstance().textRenderer; + } + + protected void drawString(MatrixStack matrixStack, String str, int x, int y, int color) { + this.font.draw(matrixStack, str, x, y, color); + } + + protected void drawText(MatrixStack matrixStack, Text text, int x, int y, int color) { + this.font.draw(matrixStack, text, x, y, color); + } + + protected void drawRect(double x1, double y1, double x2, double y2, int color) { + float a = (float) (color >> 24 & 255) / 255.0F; + float r = (float) (color >> 16 & 255) / 255.0F; + float g = (float) (color >> 8 & 255) / 255.0F; + float b = (float) (color & 255) / 255.0F; + + this.drawQuads(vertices -> addQuad(vertices, x1, y1, x2, y2, a, r, g, b)); + } + + protected void drawQuads(Consumer consumer) { + RenderSystem.enableBlend(); + RenderSystem.disableTexture(); + RenderSystem.defaultBlendFunc(); + + BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); + bufferBuilder.begin(GL20C.GL_QUADS, VertexFormats.POSITION_COLOR); + + consumer.accept(bufferBuilder); + + bufferBuilder.end(); + + BufferRenderer.draw(bufferBuilder); + RenderSystem.enableTexture(); + RenderSystem.disableBlend(); + } + + protected static void addQuad(VertexConsumer consumer, double x1, double y1, double x2, double y2, float a, float r, float g, float b) { + consumer.vertex(x2, y1, 0.0D).color(r, g, b, a).next(); + consumer.vertex(x1, y1, 0.0D).color(r, g, b, a).next(); + consumer.vertex(x1, y2, 0.0D).color(r, g, b, a).next(); + consumer.vertex(x2, y2, 0.0D).color(r, g, b, a).next(); + } + + protected void playClickSound() { + MinecraftClient.getInstance().getSoundManager() + .play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + } + + protected int getStringWidth(String text) { + return this.font.getWidth(text); + } + + protected int getTextWidth(Text text) { + return this.font.getWidth(text); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java new file mode 100644 index 000000000..f697aa8c9 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java @@ -0,0 +1,76 @@ +package me.jellysquid.mods.sodium.client.gui.widgets; + +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.gui.Drawable; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; + +public class FlatButtonWidget extends AbstractWidget implements Drawable { + private final Dim2i dim; + private final Text label; + private final Runnable action; + + private boolean selected; + private boolean enabled = true; + private boolean visible = true; + + public FlatButtonWidget(Dim2i dim, String label, Runnable action) { + this(dim, new LiteralText(label), action); + } + + public FlatButtonWidget(Dim2i dim, Text label, Runnable action) { + this.dim = dim; + this.label = label; + this.action = action; + } + + @Override + public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { + if (!this.visible) { + return; + } + + boolean hovered = this.dim.containsCursor(mouseX, mouseY); + + int backgroundColor = this.enabled ? (hovered ? 0xE0000000 : 0x90000000) : 0x60000000; + int textColor = this.enabled ? 0xFFFFFFFF : 0x90FFFFFF; + + int strWidth = this.font.getWidth(this.label); + + this.drawRect(this.dim.getOriginX(), this.dim.getOriginY(), this.dim.getLimitX(), this.dim.getLimitY(), backgroundColor); + this.drawString(matrixStack, this.label.getString(), this.dim.getCenterX() - (strWidth / 2), this.dim.getCenterY() - 4, textColor); + + if (this.enabled && this.selected) { + this.drawRect(this.dim.getOriginX(), this.dim.getLimitY() - 1, this.dim.getLimitX(), this.dim.getLimitY(), 0xFF94E4D3); + } + } + + public void setSelected(boolean selected) { + this.selected = selected; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (!this.enabled || !this.visible) { + return false; + } + + if (button == 0 && this.dim.containsCursor(mouseX, mouseY)) { + this.action.run(); + this.playClickSound(); + + return true; + } + + return false; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public void setVisible(boolean visible) { + this.visible = visible; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java b/src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java new file mode 100644 index 000000000..c252815ae --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java @@ -0,0 +1,7 @@ +package me.jellysquid.mods.sodium.client.model; + +import net.minecraft.client.model.ModelPart; + +public interface ModelCuboidAccessor { + ModelPart.Quad[] getQuads(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java new file mode 100644 index 000000000..18999c0f2 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java @@ -0,0 +1,97 @@ +package me.jellysquid.mods.sodium.client.model.light; + +import me.jellysquid.mods.sodium.client.render.entity.EntityLightSampler; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; + +public class EntityLighter { + private static final double MIN_BOX_SIZE = 0.001D; + + private static final double MAX_LIGHT_VAL = 15.0; + private static final double MAX_LIGHTMAP_COORD = 240.0D; + + public static int getBlendedLight(EntityLightSampler lighter, T entity, float tickDelta) { + boolean calcBlockLight = !entity.isOnFire(); + + // Find the interpolated position of the entity + double x1 = MathHelper.lerp(tickDelta, entity.prevX, entity.getX()); + double y1 = MathHelper.lerp(tickDelta, entity.prevY, entity.getY()); + double z1 = MathHelper.lerp(tickDelta, entity.prevZ, entity.getZ()); + + // Bounding boxes with no volume cause issues, ensure they're non-zero + // Notably, armor stands in "Marker" mode decide this is a cute thing to do + // https://github.com/jellysquid3/sodium-fabric/issues/60 + double width = Math.max(entity.getWidth(), MIN_BOX_SIZE); + double height = Math.max(entity.getHeight(), MIN_BOX_SIZE); + + double x2 = x1 + width; + double y2 = y1 + height; + double z2 = z1 + width; + + // The sampling volume of blocks which could possibly contribute light to this entity + int bMinX = MathHelper.floor(x1); + int bMinY = MathHelper.floor(y1); + int bMinZ = MathHelper.floor(z1); + int bMaxX = MathHelper.ceil(x2); + int bMaxY = MathHelper.ceil(y2); + int bMaxZ = MathHelper.ceil(z2); + + // The maximum amount of light that could be contributed + double max = 0.0D; + + // The sampled light values contributed by all sources + double sl = 0; + double bl = 0; + + BlockPos.Mutable pos = new BlockPos.Mutable(); + + // Iterate over every block in the sampling volume + for (int bX = bMinX; bX < bMaxX; bX++) { + double ix1 = Math.max(bX, x1); + double ix2 = Math.min(bX + 1, x2); + + for (int bY = bMinY; bY < bMaxY; bY++) { + double iy1 = Math.max(bY, y1); + double iy2 = Math.min(bY + 1, y2); + + for (int bZ = bMinZ; bZ < bMaxZ; bZ++) { + pos.set(bX, bY, bZ); + + BlockState blockState = entity.world.getBlockState(pos); + + // Do not consider light-blocking volumes + if (blockState.isOpaqueFullCube(entity.world, pos) && blockState.getLightValue(entity.world, pos) <= 0) { + continue; + } + + // Find the intersecting volume between the entity box and the block's bounding box + double iz1 = Math.max(bZ, z1); + double iz2 = Math.min(bZ + 1, z2); + + // The amount of light this block can contribute is the volume of the intersecting box + double weight = (ix2 - ix1) * (iy2 - iy1) * (iz2 - iz1); + + // Keep count of how much light could've been contributed + max += weight; + + // Sum the light actually contributed by this volume + sl += weight * (lighter.bridge$getSkyLight(entity, pos) / MAX_LIGHT_VAL); + + if (calcBlockLight) { + bl += weight * (lighter.bridge$getBlockLight(entity, pos) / MAX_LIGHT_VAL); + } else { + bl += weight; + } + } + } + } + + // The final light value is calculated from the percentage of light contributed out of the total maximum + int bli = MathHelper.floor((bl / max) * MAX_LIGHTMAP_COORD); + int sli = MathHelper.floor((sl / max) * MAX_LIGHTMAP_COORD); + + return ((sli & 0xFFFF) << 16) | (bli & 0xFFFF); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightMode.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightMode.java new file mode 100644 index 000000000..90133268c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightMode.java @@ -0,0 +1,6 @@ +package me.jellysquid.mods.sodium.client.model.light; + +public enum LightMode { + SMOOTH, + FLAT +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java new file mode 100644 index 000000000..f431e2b4a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java @@ -0,0 +1,22 @@ +package me.jellysquid.mods.sodium.client.model.light; + +import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; + +/** + * Light pipelines allow model quads for any location in the world to be lit using various backends, including fluids + * and block entities. + */ +public interface LightPipeline { + /** + * Calculates the light data for a given block model quad, storing the result in {@param out}. + * @param quad The block model quad + * @param pos The block position of the model this quad belongs to + * @param out The data arrays which will store the calculated light data results + * @param face The pre-computed facing vector of the quad + * @param shade True if the block is shaded by ambient occlusion + */ + void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction face, boolean shade); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipelineProvider.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipelineProvider.java new file mode 100644 index 000000000..49fb74188 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipelineProvider.java @@ -0,0 +1,26 @@ +package me.jellysquid.mods.sodium.client.model.light; + +import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; +import me.jellysquid.mods.sodium.client.model.light.flat.FlatLightPipeline; +import me.jellysquid.mods.sodium.client.model.light.smooth.SmoothLightPipeline; + +import java.util.EnumMap; + +public class LightPipelineProvider { + private final EnumMap lighters = new EnumMap<>(LightMode.class); + + public LightPipelineProvider(LightDataAccess cache) { + this.lighters.put(LightMode.SMOOTH, new SmoothLightPipeline(cache)); + this.lighters.put(LightMode.FLAT, new FlatLightPipeline(cache)); + } + + public LightPipeline getLighter(LightMode type) { + LightPipeline pipeline = this.lighters.get(type); + + if (pipeline == null) { + throw new NullPointerException("No lighter exists for mode: " + type.name()); + } + + return pipeline; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java new file mode 100644 index 000000000..ce9503fdf --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java @@ -0,0 +1,57 @@ +package me.jellysquid.mods.sodium.client.model.light.cache; + +import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; +import me.jellysquid.mods.sodium.client.world.WorldSlice; +import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.world.BlockRenderView; + +import java.util.Arrays; + +/** + * A light data cache which uses a flat-array to store the light data for the blocks in a given chunk and its direct + * neighbors. This is considerably faster than using a hash table to lookup values for a given block position and + * can be re-used by {@link WorldSlice} to avoid allocations. + */ +public class ArrayLightDataCache extends LightDataAccess { + private static final int NEIGHBOR_BLOCK_RADIUS = 2; + private static final int BLOCK_LENGTH = 16 + (NEIGHBOR_BLOCK_RADIUS * 2); + + private final long[] light; + + private int xOffset, yOffset, zOffset; + + public ArrayLightDataCache(BlockRenderView world) { + this.world = world; + this.light = new long[BLOCK_LENGTH * BLOCK_LENGTH * BLOCK_LENGTH]; + } + + public void reset(ChunkSectionPos origin) { + this.xOffset = origin.getMinX() - NEIGHBOR_BLOCK_RADIUS; + this.yOffset = origin.getMinY() - NEIGHBOR_BLOCK_RADIUS; + this.zOffset = origin.getMinZ() - NEIGHBOR_BLOCK_RADIUS; + + Arrays.fill(this.light, 0L); + } + + private int index(int x, int y, int z) { + int x2 = x - this.xOffset; + int y2 = y - this.yOffset; + int z2 = z - this.zOffset; + + return (z2 * BLOCK_LENGTH * BLOCK_LENGTH) + (y2 * BLOCK_LENGTH) + x2; + } + + @Override + public long get(int x, int y, int z) { + int l = this.index(x, y, z); + + long word = this.light[l]; + + if (word != 0) { + return word; + } + + return this.light[l] = this.compute(x, y, z); + } + +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java new file mode 100644 index 000000000..ffbc58b33 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java @@ -0,0 +1,37 @@ +package me.jellysquid.mods.sodium.client.model.light.cache; + +import it.unimi.dsi.fastutil.longs.Long2LongLinkedOpenHashMap; +import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; + +/** + * A light data cache which uses a hash table to store previously accessed values. + */ +public class HashLightDataCache extends LightDataAccess { + private final Long2LongLinkedOpenHashMap map = new Long2LongLinkedOpenHashMap(1024, 0.50f); + + public HashLightDataCache(BlockRenderView world) { + this.world = world; + } + + @Override + public long get(int x, int y, int z) { + long key = BlockPos.asLong(x, y, z); + long word = this.map.getAndMoveToFirst(key); + + if (word == 0) { + if (this.map.size() > 1024) { + this.map.removeLastLong(); + } + + this.map.put(key, word = this.compute(x, y, z)); + } + + return word; + } + + public void clearCache() { + this.map.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java new file mode 100644 index 000000000..02e774bef --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java @@ -0,0 +1,127 @@ +package me.jellysquid.mods.sodium.client.model.light.data; + +import net.minecraft.block.BlockState; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockRenderView; + +/** + * The light data cache is used to make accessing the light data and occlusion properties of blocks cheaper. The data + * for each block is stored as a long integer with packed fields in order to work around the lack of value types in Java. + * + * This code is not very pretty, but it does perform significantly faster than the vanilla implementation and has + * good cache locality. + * + * Each long integer contains the following fields: + * - OP: Block opacity test, true if opaque + * - FO: Full block opaque test, true if opaque + * - AO: Ambient occlusion, floating point value in the range of 0.0..1.0 encoded as an 12-bit unsigned integer + * - LM: Light map texture coordinates, two packed UV shorts in an integer + * + * You can use the various static pack/unpack methods to extract these values in a usable format. + */ +public abstract class LightDataAccess { + private final BlockPos.Mutable pos = new BlockPos.Mutable(); + protected BlockRenderView world; + + public long get(int x, int y, int z, Direction d1, Direction d2) { + return this.get(x + d1.getOffsetX() + d2.getOffsetX(), + y + d1.getOffsetY() + d2.getOffsetY(), + z + d1.getOffsetZ() + d2.getOffsetZ()); + } + + public long get(int x, int y, int z, Direction dir) { + return this.get(x + dir.getOffsetX(), + y + dir.getOffsetY(), + z + dir.getOffsetZ()); + } + + public long get(BlockPos pos, Direction dir) { + return this.get(pos.getX(), pos.getY(), pos.getZ(), dir); + } + + public long get(BlockPos pos) { + return this.get(pos.getX(), pos.getY(), pos.getZ()); + } + + /** + * Returns the light data for the block at the given position. The property fields can then be accessed using + * the various unpack methods below. + */ + public abstract long get(int x, int y, int z); + + protected long compute(int x, int y, int z) { + BlockPos pos = this.pos.set(x, y, z); + BlockRenderView world = this.world; + + BlockState state = world.getBlockState(pos); + + float ao; + boolean em; + + if (state.getLightValue(world, pos) == 0) { + ao = state.getAmbientOcclusionLightLevel(world, pos); + em = state.hasEmissiveLighting(world, pos); + } else { + ao = 1.0f; + em = true; + } + + boolean op = !state.shouldBlockVision(world, pos) || state.getOpacity(world, pos) == 0; + boolean fo = state.isOpaqueFullCube(world, pos); + boolean fc = state.isFullCube(world, pos); + + // OPTIMIZE: Do not calculate lightmap data if the block is full and opaque. + // FIX: Calculate lightmap data for light-emitting or emissive blocks, even though they are full and opaque. + int lm = (fo && !em) ? 0 : WorldRenderer.getLightmapCoordinates(world, state, pos); + + return packAO(ao) | packLM(lm) | packOP(op) | packFO(fo) | packFC(fc) | (1L << 60); + } + + public static long packOP(boolean opaque) { + return (opaque ? 1L : 0L) << 56; + } + + public static boolean unpackOP(long word) { + return ((word >>> 56) & 0b1) != 0; + } + + public static long packFO(boolean opaque) { + return (opaque ? 1L : 0L) << 57; + } + + public static boolean unpackFO(long word) { + return ((word >>> 57) & 0b1) != 0; + } + + public static long packFC(boolean fullCube) { + return (fullCube ? 1L : 0L) << 58; + } + + public static boolean unpackFC(long word) { + return ((word >>> 58) & 0b1) != 0; + } + + public static long packLM(int lm) { + return (long) lm & 0xFFFFFFFFL; + } + + public static int unpackLM(long word) { + return (int) (word & 0xFFFFFFFFL); + } + + public static long packAO(float ao) { + int aoi = (int) (ao * 4096.0f); + return ((long) aoi & 0xFFFFL) << 32; + } + + public static float unpackAO(long word) { + int aoi = (int) (word >>> 32 & 0xFFFFL); + return aoi * (1.0f / 4096.0f); + } + + public BlockRenderView getWorld() { + return this.world; + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/QuadLightData.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/QuadLightData.java new file mode 100644 index 000000000..1342e1dcf --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/QuadLightData.java @@ -0,0 +1,17 @@ +package me.jellysquid.mods.sodium.client.model.light.data; + +/** + * Stores the computed light data for a block model quad. The vertex order of each array is defined as that of the + * quad's vertex order. + */ +public class QuadLightData { + /** + * The brightness of each vertex in the quad as normalized floats. + */ + public final float[] br = new float[4]; + + /** + * The lightmap texture coordinates for each vertex in the quad. + */ + public final int[] lm = new int[4]; +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java new file mode 100644 index 000000000..d0a893e62 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java @@ -0,0 +1,69 @@ +package me.jellysquid.mods.sodium.client.model.light.flat; + +import me.jellysquid.mods.sodium.client.model.light.LightPipeline; +import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; +import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockRenderView; + +import java.util.Arrays; + +/** + * A light pipeline which implements "classic-style" lighting through simply using the light value of the adjacent + * block to a face. + */ +public class FlatLightPipeline implements LightPipeline { + /** + * The cache which light data will be accessed from. + */ + private final LightDataAccess lightCache; + + public FlatLightPipeline(LightDataAccess lightCache) { + this.lightCache = lightCache; + } + + @Override + public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction face, boolean shade) { + int lightmap; + + // To match vanilla behavior, use the cull face if it exists/is available + if (cullFace != null) { + lightmap = getOffsetLightmap(pos, cullFace); + } else { + int flags = quad.getFlags(); + // If the face is aligned, use the light data above it + // To match vanilla behavior, also treat the face as aligned if it is parallel and the block state is a full cube + if ((flags & ModelQuadFlags.IS_ALIGNED) != 0 || ((flags & ModelQuadFlags.IS_PARALLEL) != 0 && LightDataAccess.unpackFC(this.lightCache.get(pos)))) { + lightmap = getOffsetLightmap(pos, face); + } else { + lightmap = LightDataAccess.unpackLM(this.lightCache.get(pos)); + } + } + + Arrays.fill(out.lm, lightmap); + Arrays.fill(out.br, this.lightCache.getWorld().getBrightness(face, shade)); + } + + /** + * When vanilla computes an offset lightmap with flat lighting, it passes the original BlockState but the + * offset BlockPos to {@link WorldRenderer#getLightmapCoordinates(BlockRenderView, BlockState, BlockPos)}. + * This does not make much sense but fixes certain issues, primarily dark quads on light-emitting blocks + * behind tinted glass. {@link LightDataAccess} cannot efficiently store lightmaps computed with + * inconsistent values so this method exists to mirror vanilla behavior as closely as possible. + */ + private int getOffsetLightmap(BlockPos pos, Direction face) { + int lightmap = LightDataAccess.unpackLM(this.lightCache.get(pos, face)); + // If the block light is not 15 (max)... + if ((lightmap & 0xF0) != 0xF0) { + int originLightmap = LightDataAccess.unpackLM(this.lightCache.get(pos)); + // ...take the maximum combined block light at the origin and offset positions + lightmap = (lightmap & ~0xFF) | Math.max(lightmap & 0xFF, originLightmap & 0xFF); + } + return lightmap; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoCompletionFlags.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoCompletionFlags.java new file mode 100644 index 000000000..4dd78bcc4 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoCompletionFlags.java @@ -0,0 +1,16 @@ +package me.jellysquid.mods.sodium.client.model.light.smooth; + +/** + * Bit flags to indicate which light properties have been computed for a given face. + */ +class AoCompletionFlags { + /** + * The light data has been retrieved from the cache. + */ + public static final int HAS_LIGHT_DATA = 0b01; + + /** + * The light data has been unpacked into normalized floating point values. + */ + public static final int HAS_UNPACKED_LIGHT_DATA = 0b10; +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java new file mode 100644 index 000000000..7833dc21d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java @@ -0,0 +1,227 @@ +package me.jellysquid.mods.sodium.client.model.light.smooth; + +import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; + +import static me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache.unpackAO; +import static me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache.unpackFO; +import static me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache.unpackLM; +import static me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache.unpackOP; + +class AoFaceData { + public final int[] lm = new int[4]; + + public final float[] ao = new float[4]; + public final float[] bl = new float[4]; + public final float[] sl = new float[4]; + + private int flags; + + public void initLightData(LightDataAccess cache, BlockPos pos, Direction direction, boolean offset) { + final int x = pos.getX(); + final int y = pos.getY(); + final int z = pos.getZ(); + + final int adjX; + final int adjY; + final int adjZ; + + if (offset) { + adjX = x + direction.getOffsetX(); + adjY = y + direction.getOffsetY(); + adjZ = z + direction.getOffsetZ(); + } else { + adjX = x; + adjY = y; + adjZ = z; + } + + long adjWord = cache.get(adjX, adjY, adjZ); + + final int calm; + + // Use the origin block's light values if the adjacent one is opaque + if (offset && unpackFO(adjWord)) { + calm = unpackLM(cache.get(x, y, z)); + } else { + calm = unpackLM(adjWord); + } + + final float caao = unpackAO(adjWord); + + Direction[] faces = AoNeighborInfo.get(direction).faces; + + final long e0 = cache.get(adjX, adjY, adjZ, faces[0]); + final int e0lm = unpackLM(e0); + final float e0ao = unpackAO(e0); + final boolean e0op = unpackOP(e0); + + final long e1 = cache.get(adjX, adjY, adjZ, faces[1]); + final int e1lm = unpackLM(e1); + final float e1ao = unpackAO(e1); + final boolean e1op = unpackOP(e1); + + final long e2 = cache.get(adjX, adjY, adjZ, faces[2]); + final int e2lm = unpackLM(e2); + final float e2ao = unpackAO(e2); + final boolean e2op = unpackOP(e2); + + final long e3 = cache.get(adjX, adjY, adjZ, faces[3]); + final int e3lm = unpackLM(e3); + final float e3ao = unpackAO(e3); + final boolean e3op = unpackOP(e3); + + // If neither edge of a corner is occluded, then use the light + final int c0lm; + final float c0ao; + + if (!e2op && !e0op) { + c0lm = e0lm; + c0ao = e0ao; + } else { + long d0 = cache.get(adjX, adjY, adjZ, faces[0], faces[2]); + c0lm = unpackLM(d0); + c0ao = unpackAO(d0); + } + + final int c1lm; + final float c1ao; + + if (!e3op && !e0op) { + c1lm = e0lm; + c1ao = e0ao; + } else { + long d1 = cache.get(adjX, adjY, adjZ, faces[0], faces[3]); + c1lm = unpackLM(d1); + c1ao = unpackAO(d1); + } + + final int c2lm; + final float c2ao; + + if (!e2op && !e1op) { + // FIX: Use e1 instead of c0 to fix lighting errors in some directions + c2lm = e1lm; + c2ao = e1ao; + } else { + long d2 = cache.get(adjX, adjY, adjZ, faces[1], faces[2]); + c2lm = unpackLM(d2); + c2ao = unpackAO(d2); + } + + final int c3lm; + final float c3ao; + + if (!e3op && !e1op) { + // FIX: Use e1 instead of c0 to fix lighting errors in some directions + c3lm = e1lm; + c3ao = e1ao; + } else { + long d3 = cache.get(adjX, adjY, adjZ, faces[1], faces[3]); + c3lm = unpackLM(d3); + c3ao = unpackAO(d3); + } + + float[] ao = this.ao; + ao[0] = (e3ao + e0ao + c1ao + caao) * 0.25f; + ao[1] = (e2ao + e0ao + c0ao + caao) * 0.25f; + ao[2] = (e2ao + e1ao + c2ao + caao) * 0.25f; + ao[3] = (e3ao + e1ao + c3ao + caao) * 0.25f; + + int[] cb = this.lm; + cb[0] = calculateCornerBrightness(e3lm, e0lm, c1lm, calm); + cb[1] = calculateCornerBrightness(e2lm, e0lm, c0lm, calm); + cb[2] = calculateCornerBrightness(e2lm, e1lm, c2lm, calm); + cb[3] = calculateCornerBrightness(e3lm, e1lm, c3lm, calm); + + this.flags |= AoCompletionFlags.HAS_LIGHT_DATA; + } + + public void unpackLightData() { + int[] lm = this.lm; + + float[] bl = this.bl; + float[] sl = this.sl; + + bl[0] = unpackBlockLight(lm[0]); + bl[1] = unpackBlockLight(lm[1]); + bl[2] = unpackBlockLight(lm[2]); + bl[3] = unpackBlockLight(lm[3]); + + sl[0] = unpackSkyLight(lm[0]); + sl[1] = unpackSkyLight(lm[1]); + sl[2] = unpackSkyLight(lm[2]); + sl[3] = unpackSkyLight(lm[3]); + + this.flags |= AoCompletionFlags.HAS_UNPACKED_LIGHT_DATA; + } + + public float getBlendedSkyLight(float[] w) { + return weightedSum(this.sl, w); + } + + public float getBlendedBlockLight(float[] w) { + return weightedSum(this.bl, w); + } + + public float getBlendedShade(float[] w) { + return weightedSum(this.ao, w); + } + + private static float weightedSum(float[] v, float[] w) { + float t0 = v[0] * w[0]; + float t1 = v[1] * w[1]; + float t2 = v[2] * w[2]; + float t3 = v[3] * w[3]; + + return t0 + t1 + t2 + t3; + } + + private static float unpackSkyLight(int i) { + return (i >> 16) & 0xFF; + } + + private static float unpackBlockLight(int i) { + return i & 0xFF; + } + + private static int calculateCornerBrightness(int a, int b, int c, int d) { + // FIX: Normalize corner vectors correctly to the minimum non-zero value between each one to prevent + // strange issues + if ((a == 0) || (b == 0) || (c == 0) || (d == 0)) { + // Find the minimum value between all corners + final int min = minNonZero(minNonZero(a, b), minNonZero(c, d)); + + // Normalize the corner values + a = Math.max(a, min); + b = Math.max(b, min); + c = Math.max(c, min); + d = Math.max(d, min); + } + + return ((a + b + c + d) >> 2) & 0xFF00FF; + } + + private static int minNonZero(int a, int b) { + if (a == 0) { + return b; + } else if (b == 0) { + return a; + } + + return Math.min(a, b); + } + + public boolean hasLightData() { + return (this.flags & AoCompletionFlags.HAS_LIGHT_DATA) != 0; + } + + public boolean hasUnpackedLightData() { + return (this.flags & AoCompletionFlags.HAS_UNPACKED_LIGHT_DATA) != 0; + } + + public void reset() { + this.flags = 0; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java new file mode 100644 index 000000000..660e588c5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java @@ -0,0 +1,249 @@ +package me.jellysquid.mods.sodium.client.model.light.smooth; + +import net.minecraft.util.math.Direction; + +/** + * The neighbor information for each face of a block, used when performing smooth lighting in order to calculate + * the occlusion of each corner. + */ +enum AoNeighborInfo { + DOWN(new Direction[] { Direction.WEST, Direction.EAST, Direction.NORTH, Direction.SOUTH }, 0.5F) { + @Override + public void calculateCornerWeights(float x, float y, float z, float[] out) { + final float u = z; + final float v = 1.0f - x; + + out[0] = v * u; + out[1] = v * (1.0f - u); + out[2] = (1.0f - v) * (1.0f - u); + out[3] = (1.0f - v) * u; + } + + @Override + public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) { + lm1[0] = lm0[0]; + lm1[1] = lm0[1]; + lm1[2] = lm0[2]; + lm1[3] = lm0[3]; + + ao1[0] = ao0[0]; + ao1[1] = ao0[1]; + ao1[2] = ao0[2]; + ao1[3] = ao0[3]; + } + + @Override + public float getDepth(float x, float y, float z) { + return y; + } + }, + UP(new Direction[] { Direction.EAST, Direction.WEST, Direction.NORTH, Direction.SOUTH }, 1.0F) { + @Override + public void calculateCornerWeights(float x, float y, float z, float[] out) { + final float u = z; + final float v = x; + + out[0] = v * u; + out[1] = v * (1.0f - u); + out[2] = (1.0f - v) * (1.0f - u); + out[3] = (1.0f - v) * u; + } + + @Override + public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) { + lm1[2] = lm0[0]; + lm1[3] = lm0[1]; + lm1[0] = lm0[2]; + lm1[1] = lm0[3]; + + ao1[2] = ao0[0]; + ao1[3] = ao0[1]; + ao1[0] = ao0[2]; + ao1[1] = ao0[3]; + } + + @Override + public float getDepth(float x, float y, float z) { + return 1.0f - y; + } + }, + NORTH(new Direction[] { Direction.UP, Direction.DOWN, Direction.EAST, Direction.WEST }, 0.8F) { + @Override + public void calculateCornerWeights(float x, float y, float z, float[] out) { + final float u = 1.0f - x; + final float v = y; + + out[0] = v * u; + out[1] = v * (1.0f - u); + out[2] = (1.0f - v) * (1.0f - u); + out[3] = (1.0f - v) * u; + } + + @Override + public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) { + lm1[3] = lm0[0]; + lm1[0] = lm0[1]; + lm1[1] = lm0[2]; + lm1[2] = lm0[3]; + + ao1[3] = ao0[0]; + ao1[0] = ao0[1]; + ao1[1] = ao0[2]; + ao1[2] = ao0[3]; + } + + @Override + public float getDepth(float x, float y, float z) { + return z; + } + }, + SOUTH(new Direction[] { Direction.WEST, Direction.EAST, Direction.DOWN, Direction.UP }, 0.8F) { + @Override + public void calculateCornerWeights(float x, float y, float z, float[] out) { + final float u = y; + final float v = 1.0f - x; + + out[0] = u * v; + out[1] = (1.0f - u) * v; + out[2] = (1.0f - u) * (1.0f - v); + out[3] = u * (1.0f - v); + } + + @Override + public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) { + lm1[0] = lm0[0]; + lm1[1] = lm0[1]; + lm1[2] = lm0[2]; + lm1[3] = lm0[3]; + + ao1[0] = ao0[0]; + ao1[1] = ao0[1]; + ao1[2] = ao0[2]; + ao1[3] = ao0[3]; + } + + @Override + public float getDepth(float x, float y, float z) { + return 1.0f - z; + } + }, + WEST(new Direction[] { Direction.UP, Direction.DOWN, Direction.NORTH, Direction.SOUTH }, 0.6F) { + @Override + public void calculateCornerWeights(float x, float y, float z, float[] out) { + final float u = z; + final float v = y; + + out[0] = v * u; + out[1] = v * (1.0f - u); + out[2] = (1.0f - v) * (1.0f - u); + out[3] = (1.0f - v) * u; + } + + @Override + public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) { + lm1[3] = lm0[0]; + lm1[0] = lm0[1]; + lm1[1] = lm0[2]; + lm1[2] = lm0[3]; + + ao1[3] = ao0[0]; + ao1[0] = ao0[1]; + ao1[1] = ao0[2]; + ao1[2] = ao0[3]; + } + + @Override + public float getDepth(float x, float y, float z) { + return x; + } + }, + EAST(new Direction[] { Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH }, 0.6F) { + @Override + public void calculateCornerWeights(float x, float y, float z, float[] out) { + final float u = z; + final float v = 1.0f - y; + + out[0] = v * u; + out[1] = v * (1.0f - u); + out[2] = (1.0f - v) * (1.0f - u); + out[3] = (1.0f - v) * u; + } + + @Override + public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) { + lm1[1] = lm0[0]; + lm1[2] = lm0[1]; + lm1[3] = lm0[2]; + lm1[0] = lm0[3]; + + ao1[1] = ao0[0]; + ao1[2] = ao0[1]; + ao1[3] = ao0[2]; + ao1[0] = ao0[3]; + } + + @Override + public float getDepth(float x, float y, float z) { + return 1.0f - x; + } + }; + + /** + * The direction of each corner block from this face, which can be retrieved by offsetting the position of the origin + * block by the direction vector. + */ + public final Direction[] faces; + + /** + * The constant brightness modifier for this face. This data exists to emulate the results of the OpenGL lighting + * model which gives a faux directional light appearance to blocks in the game. Not currently used. + */ + public final float strength; + + AoNeighborInfo(Direction[] directions, float strength) { + this.faces = directions; + this.strength = strength; + } + + /** + * Calculates how much each corner contributes to the final "darkening" of the vertex at the specified position. The + * weight is a function of the distance from the vertex's position to the corner block's position. + * + * @param x The x-position of the vertex + * @param y The y-position of the vertex + * @param z The z-position of the vertex + * @param out The weight values for each corner + */ + public abstract void calculateCornerWeights(float x, float y, float z, float[] out); + + /** + * Maps the light map and occlusion value arrays {@param lm0} and {@param ao0} from {@link AoFaceData} to the + * correct corners for this facing. + * + * @param lm0 The input light map texture coordinates array + * @param ao0 The input ambient occlusion color array + * @param lm1 The re-orientated output light map texture coordinates array + * @param ao1 The re-orientated output ambient occlusion color array + */ + public abstract void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1); + + /** + * Calculates the depth (or inset) of the vertex into this facing of the block. Used to determine + * how much shadow is contributed by the direct neighbors of a block. + * + * @param x The x-position of the vertex + * @param y The y-position of the vertex + * @param z The z-position of the vertex + * @return The depth of the vertex into this face + */ + public abstract float getDepth(float x, float y, float z); + + private static final AoNeighborInfo[] VALUES = AoNeighborInfo.values(); + + /** + * @return Returns the {@link AoNeighborInfo} which corresponds with the specified direction + */ + public static AoNeighborInfo get(Direction direction) { + return VALUES[direction.getId()]; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java new file mode 100644 index 000000000..265f22996 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java @@ -0,0 +1,270 @@ +package me.jellysquid.mods.sodium.client.model.light.smooth; + +import me.jellysquid.mods.sodium.client.model.light.LightPipeline; +import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; +import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; + +/** + * A light pipeline which produces smooth interpolated lighting and ambient occlusion for model quads. This + * implementation makes a number of improvements over vanilla's own "smooth lighting" option. In no particular order: + * + * - Ambient occlusion of block slopes underwater no longer produces broken results (fixes MC-149211) + * - Smooth lighting now works when underwater (fixes MC-68129) + * - Corner blocks are now selected from the correct set of neighbors above block faces (fixes MC-148689 and MC-12558) + * - Shading issues caused by anisotropy are fixed by re-orientating quads to a consistent ordering (fixes MC-136302) + * - Inset block faces are correctly shaded by their neighbors, fixing a number of problems with non-full blocks such as + * grass paths (fixes MC-11783 and MC-108621) + * - Synchronization issues between the main render thread's light engine and chunk build worker threads are corrected + * by copying light data alongside block states, fixing a number of inconsistencies in baked chunks (no open issue) + * + * This implementation also includes a significant number of optimizations: + * + * - Computed light data for a given block face is cached and re-used again when multiple quads exist for a given + * facing, making complex block models less expensive to render + * - The light data cache encodes as much information as possible into integer words to improve cache locality and + * to eliminate the multiple array lookups that would otherwise be needed, significantly speeding up this section + * - Block faces aligned to the block grid use a fast-path for mapping corner light values to vertices without expensive + * interpolation or blending, speeding up most block renders + * - Some critical code paths have been re-written to hit the JVM's happy path, allowing it to perform auto-vectorization + * of the blend functions + * - Information about a given model quad is cached to enable the light pipeline to make certain assumptions and skip + * unnecessary computation + */ +public class SmoothLightPipeline implements LightPipeline { + /** + * The cache which light data will be accessed from. + */ + private final LightDataAccess lightCache; + + /** + * The cached face data for each side of a block, both inset and outset. + */ + private final AoFaceData[] cachedFaceData = new AoFaceData[6 * 2]; + + /** + * The position at which the cached face data was taken at. + */ + private long cachedPos = Long.MIN_VALUE; + + /** + * A temporary array for storing the intermediary results of weight data for non-aligned face blending. + */ + private final float[] weights = new float[4]; + + public SmoothLightPipeline(LightDataAccess cache) { + this.lightCache = cache; + + for (int i = 0; i < this.cachedFaceData.length; i++) { + this.cachedFaceData[i] = new AoFaceData(); + } + } + + @Override + public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction face, boolean shade) { + this.updateCachedData(pos.asLong()); + + int flags = quad.getFlags(); + + final AoNeighborInfo neighborInfo = AoNeighborInfo.get(face); + + // If the model quad is aligned to the block's face and covers it entirely, we can take a fast path and directly + // map the corner values onto this quad's vertices. This covers most situations during rendering and provides + // a modest speed-up. + // To match vanilla behavior, also treat the face as aligned if it is parallel and the block state is a full cube + if ((flags & ModelQuadFlags.IS_ALIGNED) != 0 || ((flags & ModelQuadFlags.IS_PARALLEL) != 0 && LightDataAccess.unpackFC(this.lightCache.get(pos)))) { + if ((flags & ModelQuadFlags.IS_PARTIAL) == 0) { + this.applyAlignedFullFace(neighborInfo, pos, face, out); + } else { + this.applyAlignedPartialFace(neighborInfo, quad, pos, face, out); + } + } else if ((flags & ModelQuadFlags.IS_PARALLEL) != 0) { + this.applyParallelFace(neighborInfo, quad, pos, face, out); + } else { + this.applyNonParallelFace(neighborInfo, quad, pos, face, out); + } + + this.applySidedBrightness(out, face, shade); + } + + /** + * Quickly calculates the light data for a full grid-aligned quad. This represents the most common case (outward + * facing quads on a full-block model) and avoids interpolation between neighbors as each corner will only ever + * have two contributing sides. + * Flags: IS_ALIGNED, !IS_PARTIAL + */ + private void applyAlignedFullFace(AoNeighborInfo neighborInfo, BlockPos pos, Direction dir, QuadLightData out) { + AoFaceData faceData = this.getCachedFaceData(pos, dir, true); + neighborInfo.mapCorners(faceData.lm, faceData.ao, out.lm, out.br); + } + + /** + * Calculates the light data for a grid-aligned quad that does not cover the entire block volume's face. + * Flags: IS_ALIGNED, IS_PARTIAL + */ + private void applyAlignedPartialFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out) { + for (int i = 0; i < 4; i++) { + // Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting + float cx = clamp(quad.getX(i)); + float cy = clamp(quad.getY(i)); + float cz = clamp(quad.getZ(i)); + + float[] weights = this.weights; + neighborInfo.calculateCornerWeights(cx, cy, cz, weights); + this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, true); + } + } + + /** + * This method is the same as {@link #applyNonParallelFace(AoNeighborInfo, ModelQuadView, BlockPos, Direction, + * QuadLightData)} but with the check for a depth of approximately 0 removed. If the quad is parallel but not + * aligned, all of its vertices will have the same depth and this depth must be approximately greater than 0, + * meaning the check for 0 will always return false. + * Flags: !IS_ALIGNED, IS_PARALLEL + */ + private void applyParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out) { + for (int i = 0; i < 4; i++) { + // Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting + float cx = clamp(quad.getX(i)); + float cy = clamp(quad.getY(i)); + float cz = clamp(quad.getZ(i)); + + float[] weights = this.weights; + neighborInfo.calculateCornerWeights(cx, cy, cz, weights); + + float depth = neighborInfo.getDepth(cx, cy, cz); + + // If the quad is approximately grid-aligned (not inset) to the other side of the block, avoid unnecessary + // computation by treating it is as aligned + if (MathHelper.approximatelyEquals(depth, 1.0F)) { + this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, false); + } else { + // Blend the occlusion factor between the blocks directly beside this face and the blocks above it + // based on how inset the face is. This fixes a few issues with blocks such as farmland and paths. + this.applyInsetPartialFaceVertex(pos, dir, depth, 1.0f - depth, weights, i, out); + } + } + } + + /** + * Flags: !IS_ALIGNED, !IS_PARALLEL + */ + private void applyNonParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out) { + for (int i = 0; i < 4; i++) { + // Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting + float cx = clamp(quad.getX(i)); + float cy = clamp(quad.getY(i)); + float cz = clamp(quad.getZ(i)); + + float[] weights = this.weights; + neighborInfo.calculateCornerWeights(cx, cy, cz, weights); + + float depth = neighborInfo.getDepth(cx, cy, cz); + + // If the quad is approximately grid-aligned (not inset), avoid unnecessary computation by treating it is as aligned + if (MathHelper.approximatelyEquals(depth, 0.0F)) { + this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, true); + } else if (MathHelper.approximatelyEquals(depth, 1.0F)) { + this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, false); + } else { + // Blend the occlusion factor between the blocks directly beside this face and the blocks above it + // based on how inset the face is. This fixes a few issues with blocks such as farmland and paths. + this.applyInsetPartialFaceVertex(pos, dir, depth, 1.0f - depth, weights, i, out); + } + } + } + + private void applyAlignedPartialFaceVertex(BlockPos pos, Direction dir, float[] w, int i, QuadLightData out, boolean offset) { + AoFaceData faceData = this.getCachedFaceData(pos, dir, offset); + + if (!faceData.hasUnpackedLightData()) { + faceData.unpackLightData(); + } + + float sl = faceData.getBlendedSkyLight(w); + float bl = faceData.getBlendedBlockLight(w); + float ao = faceData.getBlendedShade(w); + + out.br[i] = ao; + out.lm[i] = getLightMapCoord(sl, bl); + } + + private void applyInsetPartialFaceVertex(BlockPos pos, Direction dir, float n1d, float n2d, float[] w, int i, QuadLightData out) { + AoFaceData n1 = this.getCachedFaceData(pos, dir, false); + + if (!n1.hasUnpackedLightData()) { + n1.unpackLightData(); + } + + AoFaceData n2 = this.getCachedFaceData(pos, dir, true); + + if (!n2.hasUnpackedLightData()) { + n2.unpackLightData(); + } + + // Blend between the direct neighbors and above based on the passed weights + float ao = (n1.getBlendedShade(w) * n1d) + (n2.getBlendedShade(w) * n2d); + float sl = (n1.getBlendedSkyLight(w) * n1d) + (n2.getBlendedSkyLight(w) * n2d); + float bl = (n1.getBlendedBlockLight(w) * n1d) + (n2.getBlendedBlockLight(w) * n2d); + + out.br[i] = ao; + out.lm[i] = getLightMapCoord(sl, bl); + } + + private void applySidedBrightness(QuadLightData out, Direction face, boolean shade) { + float brightness = this.lightCache.getWorld().getBrightness(face, shade); + float[] br = out.br; + + for (int i = 0; i < br.length; i++) { + br[i] *= brightness; + } + } + + /** + * Returns the cached data for a given facing or calculates it if it hasn't been cached. + */ + private AoFaceData getCachedFaceData(BlockPos pos, Direction face, boolean offset) { + AoFaceData data = this.cachedFaceData[offset ? face.ordinal() : face.ordinal() + 6]; + + if (!data.hasLightData()) { + data.initLightData(this.lightCache, pos, face, offset); + } + + return data; + } + + private void updateCachedData(long key) { + if (this.cachedPos != key) { + for (AoFaceData data : this.cachedFaceData) { + data.reset(); + } + + this.cachedPos = key; + } + } + + /** + * Clamps the given float to the range [0.0, 1.0]. + */ + private static float clamp(float v) { + if (v < 0.0f) { + return 0.0f; + } else if (v > 1.0f) { + return 1.0f; + } + + return v; + } + + /** + * Returns a texture coordinate on the light map texture for the given block and sky light values. + */ + private static int getLightMapCoord(float sl, float bl) { + return (((int) sl & 0xFF) << 16) | ((int) bl & 0xFF); + } + +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java new file mode 100644 index 000000000..feb2f3d73 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java @@ -0,0 +1,139 @@ +package me.jellysquid.mods.sodium.client.model.quad; + +import net.minecraft.client.texture.Sprite; + +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.COLOR_INDEX; +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.LIGHT_INDEX; +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.NORMAL_INDEX; +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.POSITION_INDEX; +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.TEXTURE_INDEX; +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.VERTEX_SIZE; +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.vertexOffset; + +/** + * A simple implementation of the {@link ModelQuadViewMutable} interface which can provide an on-heap scratch area + * for storing quad vertex data. + */ +public class ModelQuad implements ModelQuadViewMutable { + private final int[] data = new int[VERTEX_SIZE * 4]; + private int flags; + + private Sprite sprite; + private int colorIdx; + + @Override + public void setX(int idx, float x) { + this.data[vertexOffset(idx) + POSITION_INDEX] = Float.floatToRawIntBits(x); + } + + @Override + public void setY(int idx, float y) { + this.data[vertexOffset(idx) + POSITION_INDEX + 1] = Float.floatToRawIntBits(y); + } + + @Override + public void setZ(int idx, float z) { + this.data[vertexOffset(idx) + POSITION_INDEX + 2] = Float.floatToRawIntBits(z); + } + + @Override + public void setColor(int idx, int color) { + this.data[vertexOffset(idx) + COLOR_INDEX] = color; + } + + @Override + public void setTexU(int idx, float u) { + this.data[vertexOffset(idx) + TEXTURE_INDEX] = Float.floatToRawIntBits(u); + } + + @Override + public void setTexV(int idx, float v) { + this.data[vertexOffset(idx) + TEXTURE_INDEX + 1] = Float.floatToRawIntBits(v); + } + + @Override + public void setLight(int idx, int light) { + this.data[vertexOffset(idx) + LIGHT_INDEX] = light; + } + + @Override + public void setNormal(int idx, int norm) { + this.data[vertexOffset(idx) + NORMAL_INDEX] = norm; + } + + @Override + public void setFlags(int flags) { + this.flags = flags; + } + + @Override + public void setSprite(Sprite sprite) { + this.sprite = sprite; + } + + @Override + public void setColorIndex(int index) { + this.colorIdx = index; + } + + @Override + public int getLight(int idx) { + return this.data[vertexOffset(idx) + LIGHT_INDEX]; + } + + @Override + public int getNormal(int idx) { + return this.data[vertexOffset(idx) + NORMAL_INDEX]; + } + + @Override + public int getColorIndex() { + return this.colorIdx; + } + + @Override + public float getX(int idx) { + return Float.intBitsToFloat(this.data[vertexOffset(idx) + POSITION_INDEX]); + } + + @Override + public float getY(int idx) { + return Float.intBitsToFloat(this.data[vertexOffset(idx) + POSITION_INDEX + 1]); + } + + @Override + public float getZ(int idx) { + return Float.intBitsToFloat(this.data[vertexOffset(idx) + POSITION_INDEX + 2]); + } + + @Override + public int getColor(int idx) { + if(vertexOffset(idx) + COLOR_INDEX < data.length) { + return this.data[vertexOffset(idx) + COLOR_INDEX]; + } + else { + return data.length; + } + } + + @Override + public float getTexU(int idx) { + return Float.intBitsToFloat(this.data[vertexOffset(idx) + TEXTURE_INDEX]); + } + + @Override + public float getTexV(int idx) { + return Float.intBitsToFloat(this.data[vertexOffset(idx) + TEXTURE_INDEX + 1]); + } + + @Override + public int getFlags() { + return this.flags; + } + + @Override + public Sprite rubidium$getSprite() { + return this.sprite; + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java new file mode 100644 index 000000000..f230df5f8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -0,0 +1,85 @@ +package me.jellysquid.mods.sodium.client.model.quad; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.minecraft.client.texture.Sprite; + +import java.nio.ByteBuffer; + +/** + * Provides a read-only view of a model quad. For mutable access to a model quad, see {@link ModelQuadViewMutable}. + */ +public interface ModelQuadView { + /** + * @return The x-position of the vertex at index {@param idx} + */ + float getX(int idx); + + /** + * @return The y-position of the vertex at index {@param idx} + */ + float getY(int idx); + + /** + * @return The z-position of the vertex at index {@param idx} + */ + float getZ(int idx); + + /** + * @return The integer-encoded color of the vertex at index {@param idx} + */ + int getColor(int idx); + + /** + * @return The texture x-coordinate for the vertex at index {@param idx} + */ + float getTexU(int idx); + + /** + * @return The texture y-coordinate for the vertex at index {@param idx} + */ + float getTexV(int idx); + + /** + * @return The integer bit flags containing the {@link ModelQuadFlags} for this quad + */ + int getFlags(); + + /** + * @return The lightmap texture coordinates for the vertex at index {@param idx} + */ + int getLight(int idx); + + /** + * @return The integer-encoded normal vector for the vertex at index {@param idx} + */ + int getNormal(int idx); + + /** + * @return The color index of this quad. + */ + int getColorIndex(); + + /** + * Copies this quad's data into the specified buffer starting at the given position. + * @param buf The buffer to write this quad's data to + * @param position The starting byte index to write to + */ + default void copyInto(ByteBuffer buf, int position) { + for (int i = 0; i < 4; i++) { + buf.putFloat(position, this.getX(i)); + buf.putFloat(position + 4, this.getY(i)); + buf.putFloat(position + 8, this.getZ(i)); + buf.putInt(position + 12, this.getColor(i)); + buf.putFloat(position + 16, this.getTexU(i)); + buf.putFloat(position + 20, this.getTexV(i)); + buf.putInt(position + 24, this.getLight(i)); + + position += 28; + } + } + + /** + * @return The sprite texture used by this quad, or null if none is attached + */ + Sprite rubidium$getSprite(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java new file mode 100644 index 000000000..01579a64d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java @@ -0,0 +1,64 @@ +package me.jellysquid.mods.sodium.client.model.quad; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.minecraft.client.texture.Sprite; + +/** + * Provides a mutable view to a model quad. + */ +public interface ModelQuadViewMutable extends ModelQuadView { + /** + * Sets the x-position of the vertex at index {@param idx} to the value {@param x} + */ + void setX(int idx, float x); + + /** + * Sets the y-position of the vertex at index {@param idx} to the value {@param y} + */ + void setY(int idx, float y); + + /** + * Sets the z-position of the vertex at index {@param idx} to the value {@param z} + */ + void setZ(int idx, float z); + + /** + * Sets the integer-encoded color of the vertex at index {@param idx} to the value {@param color} + */ + void setColor(int idx, int color); + + /** + * Sets the texture x-coordinate of the vertex at index {@param idx} to the value {@param u} + */ + void setTexU(int idx, float u); + + /** + * Sets the texture y-coordinate of the vertex at index {@param idx} to the value {@param v} + */ + void setTexV(int idx, float v); + + /** + * Sets the light map texture coordinate of the vertex at index {@param idx} to the value {@param light} + */ + void setLight(int idx, int light); + + /** + * Sets the integer-encoded normal vector of the vertex at index {@param idx} to the value {@param light} + */ + void setNormal(int idx, int norm); + + /** + * Sets the bit-flag field which contains the {@link ModelQuadFlags} for this quad + */ + void setFlags(int flags); + + /** + * Sets the sprite used by this quad + */ + void setSprite(Sprite sprite); + + /** + * Sets the color index used by this quad + */ + void setColorIndex(int index); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java new file mode 100644 index 000000000..8994f6d70 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java @@ -0,0 +1,29 @@ +package me.jellysquid.mods.sodium.client.model.quad.blender; + +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.color.block.BlockColorProvider; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; + +public interface BiomeColorBlender { + /** + * Computes the blended biome colors and returns an an array containing the integer-encoded colors for each vertex. + * The array returned by this method may be re-used in subsequent calls in order to reduce memory allocations, and + * as such, the contents of an array returned by this method is undefined after a subsequent call. + * + * @param colorizer The color sampling source + * @param world The world to sample biomes (and as a result, colors) from + * @param state The block state being rendered + * @param origin The position of the block being rendered + * @param quad The quad which will be colorized + * @return An array of integer colors in ABGR format + */ + int[] getColors(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, + ModelQuadView quad); + + static BiomeColorBlender create(MinecraftClient client) { + return new ConfigurableColorBlender(client); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java new file mode 100644 index 000000000..b7c6cad13 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java @@ -0,0 +1,26 @@ +package me.jellysquid.mods.sodium.client.model.quad.blender; + +import net.minecraft.state.State; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; + +public interface BlockColorSettings { + /** + * Configures whether biome colors from a color provider will be interpolated for this block. You should only + * enable this functionality if your color provider returns values based upon a pair of coordinates in the world, + * and not if it needs access to the block state itself. + * + * @return True if interpolation should be used, otherwise false. + */ + boolean useSmoothColorBlending(BlockRenderView view, T state, BlockPos pos); + + @SuppressWarnings("unchecked") + static boolean isSmoothBlendingEnabled(BlockRenderView world, State state, BlockPos pos) { + if (state.owner instanceof BlockColorSettings) { + BlockColorSettings> settings = (BlockColorSettings>) state.owner; + return settings.useSmoothColorBlending(world, state, pos); + } + + return false; + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java new file mode 100644 index 000000000..42d52817e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java @@ -0,0 +1,37 @@ +package me.jellysquid.mods.sodium.client.model.quad.blender; + +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.color.block.BlockColorProvider; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; + +class ConfigurableColorBlender implements BiomeColorBlender { + private final BiomeColorBlender defaultBlender; + private final BiomeColorBlender smoothBlender; + + public ConfigurableColorBlender(MinecraftClient client) { + this.defaultBlender = new FlatBiomeColorBlender(); + this.smoothBlender = isSmoothBlendingEnabled(client) ? new SmoothBiomeColorBlender() : this.defaultBlender; + } + + private static boolean isSmoothBlendingEnabled(MinecraftClient client) { + return client.options.biomeBlendRadius > 0; + } + + @Override + public int[] getColors(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, + ModelQuadView quad) { + BiomeColorBlender blender; + + if (BlockColorSettings.isSmoothBlendingEnabled(world, state, origin)) { + blender = this.smoothBlender; + } else { + blender = this.defaultBlender; + } + + return blender.getColors(colorizer, world, state, origin, quad); + } + +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java new file mode 100644 index 000000000..7a2cd3be0 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java @@ -0,0 +1,19 @@ +package me.jellysquid.mods.sodium.client.model.quad.blender; + +import com.google.common.collect.Sets; +import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; + +import java.util.Set; + +public class DefaultBlockColorSettings { + private static final Set BLENDED_BLOCKS = new ReferenceOpenHashSet<>(Sets.newHashSet( + Blocks.FERN, Blocks.LARGE_FERN, Blocks.POTTED_FERN, Blocks.GRASS, Blocks.TALL_GRASS, + Blocks.GRASS_BLOCK, Blocks.OAK_LEAVES, Blocks.JUNGLE_LEAVES, Blocks.ACACIA_LEAVES, Blocks.DARK_OAK_LEAVES, + Blocks.VINE, Blocks.WATER, Blocks.BUBBLE_COLUMN, Blocks.CAULDRON, Blocks.SUGAR_CANE)); + + public static boolean isSmoothBlendingAvailable(Block block) { + return BLENDED_BLOCKS.contains(block); + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java new file mode 100644 index 000000000..c134c4917 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.sodium.client.model.quad.blender; + +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.util.color.ColorARGB; +import net.minecraft.block.BlockState; +import net.minecraft.client.color.block.BlockColorProvider; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; + +import java.util.Arrays; + +/** + * A simple colorizer which performs no blending between adjacent blocks. + */ +public class FlatBiomeColorBlender implements BiomeColorBlender { + private final int[] cachedRet = new int[4]; + + @Override + public int[] getColors(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, + ModelQuadView quad) { + Arrays.fill(this.cachedRet, ColorARGB.toABGR(colorizer.getColor(state, world, origin, quad.getColorIndex()))); + + return this.cachedRet; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java new file mode 100644 index 000000000..1b00ef1b7 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java @@ -0,0 +1,117 @@ +package me.jellysquid.mods.sodium.client.model.quad.blender; + +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import me.jellysquid.mods.sodium.client.util.color.ColorARGB; +import me.jellysquid.mods.sodium.client.util.color.ColorU8; +import net.minecraft.block.BlockState; +import net.minecraft.client.color.block.BlockColorProvider; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; + +public class SmoothBiomeColorBlender implements BiomeColorBlender { + private final int[] cachedRet = new int[4]; + + private final BlockPos.Mutable mpos = new BlockPos.Mutable(); + + @Override + public int[] getColors(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, + ModelQuadView quad) { + final int[] colors = this.cachedRet; + + boolean aligned = ModelQuadFlags.contains(quad.getFlags(), ModelQuadFlags.IS_ALIGNED); + + for (int i = 0; i < 4; i++) { + // If the vertex is aligned to the block grid, we do not need to interpolate + if (aligned) { + colors[i] = this.getVertexColor(colorizer, world, state, origin, quad, i); + } else { + colors[i] = this.getInterpolatedVertexColor(colorizer, world, state, origin, quad, i); + } + } + + return colors; + } + + private int getVertexColor(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, + ModelQuadView quad, int vertexIdx) { + final int x = origin.getX() + (int) quad.getX(vertexIdx); + final int z = origin.getZ() + (int) quad.getZ(vertexIdx); + + final int color = this.getBlockColor(colorizer, world, state, origin, x, z, quad.getColorIndex()); + + return ColorARGB.toABGR(color); + } + + private int getBlockColor(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, + int x, int z, int colorIdx) { + return colorizer.getColor(state, world, this.mpos.set(x, origin.getY(), z), colorIdx); + } + + private int getInterpolatedVertexColor(BlockColorProvider colorizer, BlockRenderView world, BlockState state, + BlockPos origin, ModelQuadView quad, int vertexIdx) { + final float x = quad.getX(vertexIdx); + final float z = quad.getZ(vertexIdx); + + final int intX = (int) x; + final int intZ = (int) z; + + // Integer component of position vector + final int originX = origin.getX() + intX; + final int originZ = origin.getZ() + intZ; + + // Fraction component of position vector + final float fracX = x - intX; + final float fracZ = z - intZ; + + // Retrieve the color values for each neighbor + final int c1 = this.getBlockColor(colorizer, world, state, origin, originX, originZ, quad.getColorIndex()); + final int c2 = this.getBlockColor(colorizer, world, state, origin, originX, originZ + 1, quad.getColorIndex()); + final int c3 = this.getBlockColor(colorizer, world, state, origin, originX + 1, originZ, quad.getColorIndex()); + final int c4 = this.getBlockColor(colorizer, world, state, origin, originX + 1, originZ + 1, quad.getColorIndex()); + + final float fr, fg, fb; + + // All the colors are the same, so the results of interpolation will be useless. + if (c1 == c2 && c2 == c3 && c3 == c4) { + fr = ColorARGB.unpackRed(c1); + fg = ColorARGB.unpackGreen(c1); + fb = ColorARGB.unpackBlue(c1); + } else { + // TODO: avoid float conversions here + // RGB components for each corner's color + final float c1r = ColorARGB.unpackRed(c1); + final float c1g = ColorARGB.unpackGreen(c1); + final float c1b = ColorARGB.unpackBlue(c1); + + final float c2r = ColorARGB.unpackRed(c2); + final float c2g = ColorARGB.unpackGreen(c2); + final float c2b = ColorARGB.unpackBlue(c2); + + final float c3r = ColorARGB.unpackRed(c3); + final float c3g = ColorARGB.unpackGreen(c3); + final float c3b = ColorARGB.unpackBlue(c3); + + final float c4r = ColorARGB.unpackRed(c4); + final float c4g = ColorARGB.unpackGreen(c4); + final float c4b = ColorARGB.unpackBlue(c4); + + // Compute the final color values across the Z axis + final float r1r = c1r + ((c2r - c1r) * fracZ); + final float r1g = c1g + ((c2g - c1g) * fracZ); + final float r1b = c1b + ((c2b - c1b) * fracZ); + + final float r2r = c3r + ((c4r - c3r) * fracZ); + final float r2g = c3g + ((c4g - c3g) * fracZ); + final float r2b = c3b + ((c4b - c3b) * fracZ); + + // Compute the final color values across the X axis + fr = r1r + ((r2r - r1r) * fracX); + fg = r1g + ((r2g - r1g) * fracX); + fb = r1b + ((r2b - r1b) * fracX); + } + + return ColorABGR.pack(ColorU8.normalize(fr), ColorU8.normalize(fg), ColorU8.normalize(fb)); + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java new file mode 100644 index 000000000..933b286f3 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -0,0 +1,54 @@ +package me.jellysquid.mods.sodium.client.model.quad.properties; + +import net.minecraft.util.math.Direction; + +public enum ModelQuadFacing { + UP, + DOWN, + EAST, + WEST, + SOUTH, + NORTH, + UNASSIGNED; + + public static final ModelQuadFacing[] VALUES = ModelQuadFacing.values(); + public static final int COUNT = VALUES.length; + + public static ModelQuadFacing fromDirection(Direction dir) { + switch (dir) { + case DOWN: + return DOWN; + case UP: + return UP; + case NORTH: + return NORTH; + case SOUTH: + return SOUTH; + case WEST: + return WEST; + case EAST: + return EAST; + default: + return UNASSIGNED; + } + } + + public ModelQuadFacing getOpposite() { + switch (this) { + case UP: + return DOWN; + case DOWN: + return UP; + case EAST: + return WEST; + case WEST: + return EAST; + case SOUTH: + return NORTH; + case NORTH: + return SOUTH; + default: + return UNASSIGNED; + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java new file mode 100644 index 000000000..bccce149e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java @@ -0,0 +1,130 @@ +package me.jellysquid.mods.sodium.client.model.quad.properties; + +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.util.math.Direction; + +public class ModelQuadFlags { + /** + * Indicates that the quad does not fully cover the given face for the model. + */ + public static final int IS_PARTIAL = 0b001; + + /** + * Indicates that the quad is parallel to its light face. + */ + public static final int IS_PARALLEL = 0b010; + + /** + * Indicates that the quad is aligned to the block grid. + * This flag is only set if {@link #IS_PARALLEL} is set. + */ + public static final int IS_ALIGNED = 0b100; + + /** + * @return True if the bit-flag of {@link ModelQuadFlags} contains the given flag + */ + public static boolean contains(int flags, int mask) { + return (flags & mask) != 0; + } + + /** + * Calculates the properties of the given quad. This data is used later by the light pipeline in order to make + * certain optimizations. + */ + public static int getQuadFlags(BakedQuad bakedQuad) { + ModelQuadView quad = (ModelQuadView) bakedQuad; + Direction face = bakedQuad.getFace(); + + float minX = 32.0F; + float minY = 32.0F; + float minZ = 32.0F; + + float maxX = -32.0F; + float maxY = -32.0F; + float maxZ = -32.0F; + + for (int i = 0; i < 4; ++i) { + float x = quad.getX(i); + float y = quad.getY(i); + float z = quad.getZ(i); + + minX = Math.min(minX, x); + minY = Math.min(minY, y); + minZ = Math.min(minZ, z); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + maxZ = Math.max(maxZ, z); + } + + boolean partial = false; + + switch (face.getAxis()) { + case X : + partial = minY >= 0.0001f || minZ >= 0.0001f || maxY <= 0.9999F || maxZ <= 0.9999F; + break; + case Y : + partial = minX >= 0.0001f || minZ >= 0.0001f || maxX <= 0.9999F || maxZ <= 0.9999F; + break; + case Z : + partial = minX >= 0.0001f || minY >= 0.0001f || maxX <= 0.9999F || maxY <= 0.9999F; + break; + }; + + boolean parallel = false; + + switch(face.getAxis()) { + case X : + parallel = minX == maxX; + break; + case Y : + parallel = minY == maxY; + break; + case Z : + parallel = minZ == maxZ; + break; + }; + + boolean aligned = false; + boolean flag = false; + + switch (face) { + case DOWN : + flag = minY < 0.0001f; + break; + case UP : + flag = maxY > 0.9999F; + break; + case NORTH : + flag = minZ < 0.0001f; + break; + case SOUTH : + flag = maxZ > 0.9999F; + break; + case WEST : + flag = minX < 0.0001f; + break; + case EAST : + flag = maxX > 0.9999F; + break; + }; + + aligned = parallel && flag; + + int flags = 0; + + if (partial) { + flags |= IS_PARTIAL; + } + + if (parallel) { + flags |= IS_PARALLEL; + } + + if (aligned) { + flags |= IS_ALIGNED; + } + + return flags; + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java new file mode 100644 index 000000000..662ce4aaf --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java @@ -0,0 +1,35 @@ +package me.jellysquid.mods.sodium.client.model.quad.properties; + +/** + * Defines the orientation of vertices in a model quad. This information be used to re-orient the quad's vertices to a + * consistent order, eliminating a number of shading issues caused by anisotropy problems. + */ +public enum ModelQuadOrientation { + NORMAL(new int[] { 0, 1, 2, 3 }), + FLIP(new int[] { 1, 2, 3, 0 }); + + private final int[] indices; + + ModelQuadOrientation(int[] indices) { + this.indices = indices; + } + + /** + * @return The re-oriented index of the vertex {@param idx} + */ + public int getVertexIndex(int idx) { + return this.indices[idx]; + } + + /** + * Determines the orientation of the vertices in the quad. + */ + public static ModelQuadOrientation orient(float[] brightnesses) { + // If one side of the quad is brighter, flip the sides + if (brightnesses[0] + brightnesses[2] > brightnesses[1] + brightnesses[3]) { + return NORMAL; + } else { + return FLIP; + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VanillaVertexTypes.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VanillaVertexTypes.java new file mode 100644 index 000000000..4d2ab7857 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VanillaVertexTypes.java @@ -0,0 +1,21 @@ +package me.jellysquid.mods.sodium.client.model.vertex; + +import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.formats.line.LineVertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.formats.line.LineVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.ParticleVertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.ParticleVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.BasicScreenQuadVertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.BasicScreenQuadVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; + +public class VanillaVertexTypes { + public static final VanillaVertexType QUADS = new QuadVertexType(); + public static final VanillaVertexType LINES = new LineVertexType(); + public static final VanillaVertexType GLYPHS = new GlyphVertexType(); + public static final VanillaVertexType PARTICLES = new ParticleVertexType(); + public static final VanillaVertexType BASIC_SCREEN_QUADS = new BasicScreenQuadVertexType(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java new file mode 100644 index 000000000..decfdc3d0 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java @@ -0,0 +1,29 @@ +package me.jellysquid.mods.sodium.client.model.vertex; + +import me.jellysquid.mods.sodium.client.model.vertex.type.VertexType; +import net.minecraft.client.render.VertexConsumer; + +/** + * A drain allows the instantiation of {@link VertexSink} and is implemented on outputs which take vertex data. + */ +public interface VertexDrain { + /** + * Returns a {@link VertexDrain} implementation on the provided {@link VertexConsumer}. Since the interface + * is always implemented on a given VertexConsumer, this is simply implemented as a cast internally. + * @param consumer The {@link VertexConsumer} + * @return A {@link VertexDrain} + */ + static VertexDrain of(VertexConsumer consumer) { + return (VertexDrain) consumer; + } + + /** + * Returns a {@link VertexSink} of type {@link T}, created from {@param factory}, which transforms and writes + * vertices through this vertex drain. + * + * @param factory The factory to create a vertex sink using + * @param The vertex sink's type + * @return A new {@link VertexSink} of type {@link T} + */ + T createSink(VertexType factory); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java new file mode 100644 index 000000000..4d932b365 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java @@ -0,0 +1,36 @@ +package me.jellysquid.mods.sodium.client.model.vertex; + +/** + * Vertex sinks allow vertex data to be quickly written out to a {@link VertexDrain} while providing + * compile-time data format contracts. Generally, you will want a format-specific vertex sink, such as + * {@link me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink} in order to write + * vertex data. + */ +public interface VertexSink { + /** + * Ensures the backing storage to this sink has enough space for the given number of vertices to be written. This + * should be called with the number of vertices you expect to write before you make calls to write vertices. + * + * If the caller tries to write vertices without calling this method, or writes more vertices than they ensured + * there was capacity for, an {@link java.nio.BufferUnderflowException} may occur. + * + * When writing batches of vertices (such as those belonging to a primitive or a large model), it is best practice + * to simply call this method once at the start with the number of vertices you plan to write. This ensures the + * backing storage will only be resized once (if necessary) to fit the incoming vertex data. + * + * @param count The number of vertices + */ + void ensureCapacity(int count); + + /** + * Flushes any written vertex data to the {@link VertexDrain} this sink is connected to, ensuring it is actually + * written to the backing storage. This should be called after vertex data has been written to this sink. + * + * It is valid to flush a sink at any time. Only vertices that have been written since the last flush will be + * flushed when calling this method. If no vertices need to be flushed, this method does nothing. + * + * For optimal performance, callers should wait until they have written out as much vertex data as possible before + * flushing, in effect batching their writes. + */ + void flush(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java new file mode 100644 index 000000000..ff79f8a03 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java @@ -0,0 +1,97 @@ +package me.jellysquid.mods.sodium.client.model.vertex.buffer; + +import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; +import net.minecraft.client.util.GlAllocationUtils; + +import java.nio.ByteBuffer; + +public class VertexBufferBuilder implements VertexBufferView { + private final BufferVertexFormat vertexFormat; + + private ByteBuffer buffer; + private int writerOffset; + private int capacity; + + public VertexBufferBuilder(BufferVertexFormat vertexFormat, int initialCapacity) { + this.vertexFormat = vertexFormat; + + this.buffer = GlAllocationUtils.allocateByteBuffer(initialCapacity); + this.capacity = initialCapacity; + this.writerOffset = 0; + } + + private void grow(int len) { + // The new capacity will at least as large as the write it needs to service + int cap = Math.max(this.capacity * 2, this.capacity + len); + + // Allocate a new buffer and copy the old buffer's contents into it + ByteBuffer buffer = GlAllocationUtils.allocateByteBuffer(cap); + buffer.put(this.buffer); + buffer.position(0); + + // Update the buffer and capacity now + this.buffer = buffer; + this.capacity = cap; + } + + @Override + public boolean ensureBufferCapacity(int bytes) { + if (this.writerOffset + bytes <= this.capacity) { + return false; + } + + this.grow(bytes); + + return true; + } + + @Override + public ByteBuffer getDirectBuffer() { + return this.buffer; + } + + @Override + public int getWriterPosition() { + return this.writerOffset; + } + + @Override + public void flush(int vertexCount, BufferVertexFormat format) { + if (this.vertexFormat != format) { + throw new IllegalStateException("Mis-matched vertex format (expected: [" + format + "], currently using: [" + this.vertexFormat + "])"); + } + + this.writerOffset += vertexCount * format.getStride(); + } + + @Override + public BufferVertexFormat getVertexFormat() { + return this.vertexFormat; + } + + public boolean isEmpty() { + return this.writerOffset == 0; + } + + public int getSize() { + return this.writerOffset; + } + + /** + * Ends the stream of written data and makes a copy of it to be passed around. + */ + public void copyInto(ByteBuffer dst) { + // Mark the slice of memory that needs to be copied + this.buffer.position(0); + this.buffer.limit(this.writerOffset); + + // Allocate a new buffer which is just large enough to contain the slice of vertex data + // The buffer is then flipped after the operation so the callee sees a range of bytes from (0,len] which can + // then be immediately passed to native libraries or the graphics driver + dst.put(this.buffer.slice()); + + // Reset the position and limit set earlier of the backing scratch buffer + this.buffer.clear(); + this.writerOffset = 0; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferView.java new file mode 100644 index 000000000..0ae537fc1 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferView.java @@ -0,0 +1,43 @@ +package me.jellysquid.mods.sodium.client.model.vertex.buffer; + +import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; + +import java.nio.ByteBuffer; + +/** + * Provides a view into {@link net.minecraft.client.render.BufferBuilder} and similar types. + */ +public interface VertexBufferView { + /** + * Ensures there is capacity in the buffer for the given number of bytes. + * @param bytes The number of bytes to allocate space for + * @return True if the buffer was resized, otherwise false + */ + boolean ensureBufferCapacity(int bytes); + + /** + * Returns a handle to the internal storage of this buffer. The buffer can be directly written into at the + * base address provided by {@link VertexBufferView#getWriterPosition()}. + * + * @return A {@link ByteBuffer} in off-heap space + */ + ByteBuffer getDirectBuffer(); + + /** + * @return The position at which new data should be written to, in bytes + */ + int getWriterPosition(); + + /** + * Flushes the given number of vertices to this buffer. This ensures that all constraints are still valid, and if + * so, advances the vertex counter and writer pointer to the end of the data that was written by the caller. + * @param vertexCount The number of vertices to flush + * @param format The format of each vertex + */ + void flush(int vertexCount, BufferVertexFormat format); + + /** + * @return The current vertex format of the buffer + */ + BufferVertexFormat getVertexFormat(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriter.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriter.java new file mode 100644 index 000000000..48e7727c4 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriter.java @@ -0,0 +1,53 @@ +package me.jellysquid.mods.sodium.client.model.vertex.buffer; + +import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.type.BufferVertexType; + +/** + * Base implementation of a {@link VertexSink} which writes into a {@link VertexBufferView} directly. + */ +public abstract class VertexBufferWriter implements VertexSink { + protected final VertexBufferView backingBuffer; + + protected final BufferVertexFormat vertexFormat; + protected final int vertexStride; + + private int vertexCount; + + protected VertexBufferWriter(VertexBufferView backingBuffer, BufferVertexType vertexType) { + this.backingBuffer = backingBuffer; + + this.vertexFormat = vertexType.getBufferVertexFormat(); + this.vertexStride = this.vertexFormat.getStride(); + + this.onBufferStorageChanged(); + } + + @Override + public void ensureCapacity(int count) { + if (this.backingBuffer.ensureBufferCapacity((this.vertexCount + count) * this.vertexStride)) { + this.onBufferStorageChanged(); + } + } + + @Override + public void flush() { + this.backingBuffer.flush(this.vertexCount, this.vertexFormat); + this.vertexCount = 0; + } + + /** + * Advances the write pointer forward by the stride of one vertex. This should always be called after a + * vertex is written. Implementations which override this should always call invoke the super implementation. + */ + protected void advance() { + this.vertexCount++; + } + + /** + * Called when the underlying memory buffer to the backing storage changes. When this is called, the implementation + * should update any pointers + */ + protected abstract void onBufferStorageChanged(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterNio.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterNio.java new file mode 100644 index 000000000..c444c4714 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterNio.java @@ -0,0 +1,32 @@ +package me.jellysquid.mods.sodium.client.model.vertex.buffer; + +import me.jellysquid.mods.sodium.client.model.vertex.type.BufferVertexType; + +import java.nio.ByteBuffer; + +/** + * A safe {@link VertexBufferWriter} implementation which uses Java's NIO library to write into memory buffers. All + * write operations are checked and will throw an exception if an invalid memory access is detected. Supported on all + * platforms. + */ +public abstract class VertexBufferWriterNio extends VertexBufferWriter { + protected ByteBuffer byteBuffer; + protected int writeOffset; + + protected VertexBufferWriterNio(VertexBufferView backingBuffer, BufferVertexType vertexType) { + super(backingBuffer, vertexType); + } + + @Override + protected void onBufferStorageChanged() { + this.byteBuffer = this.backingBuffer.getDirectBuffer(); + this.writeOffset = this.backingBuffer.getWriterPosition(); + } + + @Override + protected void advance() { + this.writeOffset += this.vertexStride; + + super.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java new file mode 100644 index 000000000..405d9c767 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java @@ -0,0 +1,34 @@ +package me.jellysquid.mods.sodium.client.model.vertex.buffer; + +import me.jellysquid.mods.sodium.client.model.vertex.type.BufferVertexType; +import org.lwjgl.system.MemoryUtil; + +/** + * An unsafe {@link VertexBufferWriter} implementation which uses direct memory operations to enable fast blitting of + * data into memory buffers. Only available on JVMs which support {@link sun.misc.Unsafe}, but generally produces much + * better optimized code than other implementations. The implementation does not check for invalid memory accesses, + * meaning that errors can corrupt process memory. + */ +public abstract class VertexBufferWriterUnsafe extends VertexBufferWriter { + /** + * The write pointer into the buffer storage. This is advanced by the vertex stride every time + * {@link VertexBufferWriterUnsafe#advance()} is called. + */ + protected long writePointer; + + protected VertexBufferWriterUnsafe(VertexBufferView backingBuffer, BufferVertexType vertexType) { + super(backingBuffer, vertexType); + } + + @Override + protected void onBufferStorageChanged() { + this.writePointer = MemoryUtil.memAddress(this.backingBuffer.getDirectBuffer(), this.backingBuffer.getWriterPosition()); + } + + @Override + protected void advance() { + this.writePointer += this.vertexStride; + + super.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java new file mode 100644 index 000000000..a1af0e689 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java @@ -0,0 +1,30 @@ +package me.jellysquid.mods.sodium.client.model.vertex.fallback; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import net.minecraft.client.render.VertexConsumer; + +/** + * The base implementation for a {@link VertexSink} which writes to a black-boxed {@link VertexConsumer}. This is the + * fallback path used when direct-writing optimizations cannot be used because the drain has no accessible backing + * memory. This implementation is very slow and should be avoided where possible. + * + * This sink does not support explicit batching/flushing and as such, all written vertices are immediately flushed + * to the backing implementation. + */ +public abstract class VertexWriterFallback implements VertexSink { + protected final VertexConsumer consumer; + + protected VertexWriterFallback(VertexConsumer consumer) { + this.consumer = consumer; + } + + @Override + public void ensureCapacity(int count) { + // NO-OP + } + + @Override + public void flush() { + // NO-OP + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java new file mode 100644 index 000000000..cd3e3cafc --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java @@ -0,0 +1,41 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; +import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.VertexFormats; +import net.minecraft.util.math.Matrix4f; + +public interface GlyphVertexSink extends VertexSink { + VertexFormat VERTEX_FORMAT = VertexFormats.POSITION_COLOR_TEXTURE_LIGHT; + + /** + * Writes a glyph vertex to the sink. + * + * @param matrix The transformation matrix to apply to the vertex's position + * @see GlyphVertexSink#writeGlyph(float, float, float, int, float, float, int) + */ + default void writeGlyph(Matrix4f matrix, float x, float y, float z, int color, float u, float v, int light) { + Matrix4fExtended matrixExt = MatrixUtil.getExtendedMatrix(matrix); + + float x2 = matrixExt.transformVecX(x, y, z); + float y2 = matrixExt.transformVecY(x, y, z); + float z2 = matrixExt.transformVecZ(x, y, z); + + this.writeGlyph(x2, y2, z2, color, u, v, light); + } + + /** + * Writes a glyph vertex to the sink. + * + * @param x The x-position of the vertex + * @param y The y-position of the vertex + * @param z The z-position of the vertex + * @param color The ABGR-packed color of the vertex + * @param u The u-texture of the vertex + * @param v The v-texture of the vertex + * @param light The packed light map texture coordinates of the vertex + */ + void writeGlyph(float x, float y, float z, int color, float u, float v, int light); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java new file mode 100644 index 000000000..22da53544 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java @@ -0,0 +1,32 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph; + +import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; +import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer.GlyphVertexBufferWriterNio; +import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer.GlyphVertexBufferWriterUnsafe; +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.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexFormat; + +public class GlyphVertexType implements VanillaVertexType, BlittableVertexType { + @Override + public GlyphVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { + return direct ? new GlyphVertexBufferWriterUnsafe(buffer) : new GlyphVertexBufferWriterNio(buffer); + } + + @Override + public GlyphVertexSink createFallbackWriter(VertexConsumer consumer) { + return new GlyphVertexWriterFallback(consumer); + } + + @Override + public VertexFormat getVertexFormat() { + return GlyphVertexSink.VERTEX_FORMAT; + } + + @Override + public BlittableVertexType asBlittable() { + return this; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterNio.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterNio.java new file mode 100644 index 000000000..ab8384b3a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterNio.java @@ -0,0 +1,30 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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 java.nio.ByteBuffer; + +public class GlyphVertexBufferWriterNio extends VertexBufferWriterNio implements GlyphVertexSink { + public GlyphVertexBufferWriterNio(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.GLYPHS); + } + + @Override + public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) { + int i = this.writeOffset; + + ByteBuffer buffer = this.byteBuffer; + 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); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..748fa87f9 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java @@ -0,0 +1,29 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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 org.lwjgl.system.MemoryUtil; + +public class GlyphVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements GlyphVertexSink { + public GlyphVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.GLYPHS); + } + + @Override + public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) { + long i = this.writePointer; + + MemoryUtil.memPutFloat(i, x); + MemoryUtil.memPutFloat(i + 4, y); + MemoryUtil.memPutFloat(i + 8, z); + MemoryUtil.memPutInt(i + 12, color); + MemoryUtil.memPutFloat(i + 16, u); + MemoryUtil.memPutFloat(i + 20, v); + MemoryUtil.memPutInt(i + 24, light); + + this.advance(); + + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java new file mode 100644 index 000000000..cd7313c9f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java @@ -0,0 +1,22 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; +import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import net.minecraft.client.render.VertexConsumer; + +public class GlyphVertexWriterFallback extends VertexWriterFallback implements GlyphVertexSink { + public GlyphVertexWriterFallback(VertexConsumer consumer) { + super(consumer); + } + + @Override + public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) { + VertexConsumer consumer = this.consumer; + consumer.vertex(x, y, z); + consumer.color(ColorABGR.unpackRed(color), ColorABGR.unpackGreen(color), ColorABGR.unpackBlue(color), ColorABGR.unpackAlpha(color)); + consumer.texture(u, v); + consumer.light(light); + consumer.next(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java new file mode 100644 index 000000000..4ec8e06a0 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java @@ -0,0 +1,37 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.line; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.VertexFormats; + +public interface LineVertexSink extends VertexSink { + VertexFormat VERTEX_FORMAT = VertexFormats.POSITION_COLOR; + + /** + * Writes a line vertex to the sink. + * + * @param x The x-position of the vertex + * @param y The y-position of the vertex + * @param z The z-position of the vertex + * @param color The ABGR-packed color of the vertex + */ + void vertexLine(float x, float y, float z, int color); + + /** + * Writes a line vertex to the sink using unpacked normalized colors. This is slower than + * {@link LineVertexSink#vertexLine(float, float, float, int)} as it needs to pack the colors + * each call. + * + * @param x The x-position of the vertex + * @param y The y-position of the vertex + * @param z The z-position of the vertex + * @param r The normalized red component of the vertex's color + * @param g The normalized green component of the vertex's color + * @param b The normalized blue component of the vertex's color + * @param a The normalized alpha component of the vertex's color + */ + default void vertexLine(float x, float y, float z, float r, float g, float b, float a) { + this.vertexLine(x, y, z, ColorABGR.pack(r, g, b, a)); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java new file mode 100644 index 000000000..5b4be974f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java @@ -0,0 +1,32 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.line; + +import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; +import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexBufferWriterNio; +import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexBufferWriterUnsafe; +import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexWriterFallback; +import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexFormat; + +public class LineVertexType implements VanillaVertexType, BlittableVertexType { + @Override + public LineVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { + return direct ? new LineVertexBufferWriterUnsafe(buffer) : new LineVertexBufferWriterNio(buffer); + } + + @Override + public LineVertexSink createFallbackWriter(VertexConsumer consumer) { + return new LineVertexWriterFallback(consumer); + } + + @Override + public VertexFormat getVertexFormat() { + return LineVertexSink.VERTEX_FORMAT; + } + + @Override + public BlittableVertexType asBlittable() { + return this; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterNio.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterNio.java new file mode 100644 index 000000000..ab7c89a1e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterNio.java @@ -0,0 +1,27 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.line.LineVertexSink; + +import java.nio.ByteBuffer; + +public class LineVertexBufferWriterNio extends VertexBufferWriterNio implements LineVertexSink { + public LineVertexBufferWriterNio(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.LINES); + } + + @Override + public void vertexLine(float x, float y, float z, int color) { + int i = this.writeOffset; + + ByteBuffer buffer = this.byteBuffer; + buffer.putFloat(i, x); + buffer.putFloat(i + 4, y); + buffer.putFloat(i + 8, z); + buffer.putInt(i + 12, color); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..952b27b99 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.line.LineVertexSink; +import org.lwjgl.system.MemoryUtil; + +public class LineVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements LineVertexSink { + public LineVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.LINES); + } + + @Override + public void vertexLine(float x, float y, float z, int color) { + long i = this.writePointer; + + MemoryUtil.memPutFloat(i, x); + MemoryUtil.memPutFloat(i + 4, y); + MemoryUtil.memPutFloat(i + 8, z); + MemoryUtil.memPutInt(i + 12, color); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java new file mode 100644 index 000000000..8c99564ae --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java @@ -0,0 +1,20 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; +import me.jellysquid.mods.sodium.client.model.vertex.formats.line.LineVertexSink; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import net.minecraft.client.render.VertexConsumer; + +public class LineVertexWriterFallback extends VertexWriterFallback implements LineVertexSink { + public LineVertexWriterFallback(VertexConsumer consumer) { + super(consumer); + } + + @Override + public void vertexLine(float x, float y, float z, int color) { + VertexConsumer consumer = this.consumer; + consumer.vertex(x, y, z); + consumer.color(ColorABGR.unpackRed(color), ColorABGR.unpackGreen(color), ColorABGR.unpackBlue(color), ColorABGR.unpackAlpha(color)); + consumer.next(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java new file mode 100644 index 000000000..854114757 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java @@ -0,0 +1,20 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.particle; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.VertexFormats; + +public interface ParticleVertexSink extends VertexSink { + VertexFormat VERTEX_FORMAT = VertexFormats.POSITION_TEXTURE_COLOR_LIGHT; + + /** + * @param x The x-position of the vertex + * @param y The y-position of the vertex + * @param z The z-position of the vertex + * @param u The u-texture of the vertex + * @param v The v-texture of the vertex + * @param color The ABGR-packed color of the vertex + * @param light The packed light map texture coordinates of the vertex + */ + void writeParticle(float x, float y, float z, float u, float v, int color, int light); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java new file mode 100644 index 000000000..41fbfcfd2 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java @@ -0,0 +1,32 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.particle; + +import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; +import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexBufferWriterNio; +import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexBufferWriterUnsafe; +import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexWriterFallback; +import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexFormat; + +public class ParticleVertexType implements VanillaVertexType, BlittableVertexType { + @Override + public ParticleVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { + return direct ? new ParticleVertexBufferWriterUnsafe(buffer) : new ParticleVertexBufferWriterNio(buffer); + } + + @Override + public ParticleVertexSink createFallbackWriter(VertexConsumer consumer) { + return new ParticleVertexWriterFallback(consumer); + } + + @Override + public BlittableVertexType asBlittable() { + return this; + } + + @Override + public VertexFormat getVertexFormat() { + return ParticleVertexSink.VERTEX_FORMAT; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterNio.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterNio.java new file mode 100644 index 000000000..72a6db372 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterNio.java @@ -0,0 +1,30 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.particle.ParticleVertexSink; + +import java.nio.ByteBuffer; + +public class ParticleVertexBufferWriterNio extends VertexBufferWriterNio implements ParticleVertexSink { + public ParticleVertexBufferWriterNio(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.PARTICLES); + } + + @Override + public void writeParticle(float x, float y, float z, float u, float v, int color, int light) { + int i = this.writeOffset; + + ByteBuffer buffer = this.byteBuffer; + buffer.putFloat(i, x); + buffer.putFloat(i + 4, y); + buffer.putFloat(i + 8, z); + buffer.putFloat(i + 12, u); + buffer.putFloat(i + 16, v); + buffer.putInt(i + 20, color); + buffer.putInt(i + 24, light); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..7cb08d8c6 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java @@ -0,0 +1,28 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.particle.ParticleVertexSink; +import org.lwjgl.system.MemoryUtil; + +public class ParticleVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ParticleVertexSink { + public ParticleVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.PARTICLES); + } + + @Override + public void writeParticle(float x, float y, float z, float u, float v, int color, int light) { + long i = this.writePointer; + + MemoryUtil.memPutFloat(i, x); + MemoryUtil.memPutFloat(i + 4, y); + MemoryUtil.memPutFloat(i + 8, z); + MemoryUtil.memPutFloat(i + 12, u); + MemoryUtil.memPutFloat(i + 16, v); + MemoryUtil.memPutInt(i + 20, color); + MemoryUtil.memPutInt(i + 24, light); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java new file mode 100644 index 000000000..e9f683250 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java @@ -0,0 +1,22 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; +import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.ParticleVertexSink; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import net.minecraft.client.render.VertexConsumer; + +public class ParticleVertexWriterFallback extends VertexWriterFallback implements ParticleVertexSink { + public ParticleVertexWriterFallback(VertexConsumer consumer) { + super(consumer); + } + + @Override + public void writeParticle(float x, float y, float z, float u, float v, int color, int light) { + VertexConsumer consumer = this.consumer; + consumer.vertex(x, y, z); + consumer.texture(u, v); + consumer.color(ColorABGR.unpackRed(color), ColorABGR.unpackGreen(color), ColorABGR.unpackBlue(color), ColorABGR.unpackAlpha(color)); + consumer.light(light); + consumer.next(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java new file mode 100644 index 000000000..9b622b6b9 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java @@ -0,0 +1,44 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.quad; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; +import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.VertexFormats; +import net.minecraft.client.util.math.MatrixStack; + +public interface QuadVertexSink extends VertexSink { + VertexFormat VERTEX_FORMAT = VertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL; + + /** + * Writes a quad vertex to this sink. + * + * @param x The x-position of the vertex + * @param y The y-position of the vertex + * @param z The z-position of the vertex + * @param color The ABGR-packed color of the vertex + * @param u The u-texture of the vertex + * @param v The y-texture of the vertex + * @param light The packed light-map coordinates of the vertex + * @param overlay The packed overlay-map coordinates of the vertex + * @param normal The 3-byte packed normal vector of the vertex + */ + void writeQuad(float x, float y, float z, int color, float u, float v, int light, int overlay, int normal); + + /** + * Writes a quad vertex to the sink, transformed by the given matrices. + * + * @param matrices The matrices to transform the vertex's position and normal vectors by + */ + default void writeQuad(MatrixStack.Entry matrices, float x, float y, float z, int color, float u, float v, int light, int overlay, int normal) { + Matrix4fExtended modelMatrix = MatrixUtil.getExtendedMatrix(matrices.getModel()); + + float x2 = modelMatrix.transformVecX(x, y, z); + float y2 = modelMatrix.transformVecY(x, y, z); + float z2 = modelMatrix.transformVecZ(x, y, z); + + int norm = MatrixUtil.transformPackedNormal(normal, matrices.getNormal()); + + this.writeQuad(x2, y2, z2, color, u, v, light, overlay, norm); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java new file mode 100644 index 000000000..eefb6e907 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java @@ -0,0 +1,32 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.quad; + +import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; +import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer.QuadVertexBufferWriterNio; +import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer.QuadVertexBufferWriterUnsafe; +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.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexFormat; + +public class QuadVertexType implements VanillaVertexType, BlittableVertexType { + @Override + public QuadVertexSink createFallbackWriter(VertexConsumer consumer) { + return new QuadVertexWriterFallback(consumer); + } + + @Override + public QuadVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { + return direct ? new QuadVertexBufferWriterUnsafe(buffer) : new QuadVertexBufferWriterNio(buffer); + } + + @Override + public VertexFormat getVertexFormat() { + return QuadVertexSink.VERTEX_FORMAT; + } + + @Override + public BlittableVertexType asBlittable() { + return this; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterNio.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterNio.java new file mode 100644 index 000000000..ef26488a4 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterNio.java @@ -0,0 +1,32 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.quad.QuadVertexSink; + +import java.nio.ByteBuffer; + +public class QuadVertexBufferWriterNio extends VertexBufferWriterNio implements QuadVertexSink { + public QuadVertexBufferWriterNio(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.QUADS); + } + + @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 buf = this.byteBuffer; + buf.putFloat(i, x); + buf.putFloat(i + 4, y); + buf.putFloat(i + 8, z); + buf.putInt(i + 12, color); + buf.putFloat(i + 16, u); + buf.putFloat(i + 20, v); + buf.putInt(i + 24, overlay); + buf.putInt(i + 28, light); + buf.putInt(i + 32, normal); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..58c0a500e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java @@ -0,0 +1,30 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.quad.QuadVertexSink; +import org.lwjgl.system.MemoryUtil; + +public class QuadVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements QuadVertexSink { + public QuadVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.QUADS); + } + + @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; + + MemoryUtil.memPutFloat(i, x); + MemoryUtil.memPutFloat(i + 4, y); + MemoryUtil.memPutFloat(i + 8, z); + MemoryUtil.memPutInt(i + 12, color); + MemoryUtil.memPutFloat(i + 16, u); + MemoryUtil.memPutFloat(i + 20, v); + MemoryUtil.memPutInt(i + 24, overlay); + MemoryUtil.memPutInt(i + 28, light); + MemoryUtil.memPutInt(i + 32, normal); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java new file mode 100644 index 000000000..994c7a4a8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; +import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; +import me.jellysquid.mods.sodium.client.util.Norm3b; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import net.minecraft.client.render.VertexConsumer; + +public class QuadVertexWriterFallback extends VertexWriterFallback implements QuadVertexSink { + public QuadVertexWriterFallback(VertexConsumer consumer) { + super(consumer); + } + + @Override + public void writeQuad(float x, float y, float z, int color, float u, float v, int light, int overlay, int normal) { + VertexConsumer consumer = this.consumer; + consumer.vertex(x, y, z); + consumer.color(ColorABGR.unpackRed(color), ColorABGR.unpackGreen(color), ColorABGR.unpackBlue(color), ColorABGR.unpackAlpha(color)); + consumer.texture(u, v); + consumer.overlay(overlay); + consumer.light(light); + consumer.normal(Norm3b.unpackX(normal), Norm3b.unpackY(normal), Norm3b.unpackZ(normal)); + consumer.next(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java new file mode 100644 index 000000000..c65081338 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java @@ -0,0 +1,37 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; +import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.VertexFormats; +import net.minecraft.util.math.Matrix4f; + +public interface BasicScreenQuadVertexSink extends VertexSink { + VertexFormat VERTEX_FORMAT = VertexFormats.POSITION_COLOR; + + /** + * Writes a quad vertex to this sink. + * + * @param x The x-position of the vertex + * @param y The y-position of the vertex + * @param z The z-position of the vertex + * @param color The ABGR-packed color of the vertex + */ + void writeQuad(float x, float y, float z, int color); + + /** + * Writes a quad vertex to the sink, transformed by the given matrix. + * + * @param matrix The matrix to transform the vertex's position by + */ + default void writeQuad(Matrix4f matrix, float x, float y, float z, int color) { + Matrix4fExtended modelMatrix = MatrixUtil.getExtendedMatrix(matrix); + + float x2 = modelMatrix.transformVecX(x, y, z); + float y2 = modelMatrix.transformVecY(x, y, z); + float z2 = modelMatrix.transformVecZ(x, y, z); + + this.writeQuad(x2, y2, z2, color); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java new file mode 100644 index 000000000..1cd287fa8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java @@ -0,0 +1,32 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad; + +import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; +import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexBufferWriterNio; +import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexBufferWriterUnsafe; +import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexWriterFallback; +import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexFormat; + +public class BasicScreenQuadVertexType implements VanillaVertexType, BlittableVertexType { + @Override + public BasicScreenQuadVertexSink createFallbackWriter(VertexConsumer consumer) { + return new BasicScreenQuadVertexWriterFallback(consumer); + } + + @Override + public BasicScreenQuadVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { + return direct ? new BasicScreenQuadVertexBufferWriterUnsafe(buffer) : new BasicScreenQuadVertexBufferWriterNio(buffer); + } + + @Override + public VertexFormat getVertexFormat() { + return BasicScreenQuadVertexSink.VERTEX_FORMAT; + } + + @Override + public BlittableVertexType asBlittable() { + return this; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterNio.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterNio.java new file mode 100644 index 000000000..9de639cb2 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterNio.java @@ -0,0 +1,27 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.screen_quad.BasicScreenQuadVertexSink; + +import java.nio.ByteBuffer; + +public class BasicScreenQuadVertexBufferWriterNio extends VertexBufferWriterNio implements BasicScreenQuadVertexSink { + public BasicScreenQuadVertexBufferWriterNio(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.BASIC_SCREEN_QUADS); + } + + @Override + public void writeQuad(float x, float y, float z, int color) { + int i = this.writeOffset; + + ByteBuffer buf = this.byteBuffer; + buf.putFloat(i, x); + buf.putFloat(i + 4, y); + buf.putFloat(i + 8, z); + buf.putInt(i + 12, color); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..4606f8181 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.screen_quad.BasicScreenQuadVertexSink; +import org.lwjgl.system.MemoryUtil; + +public class BasicScreenQuadVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements BasicScreenQuadVertexSink { + public BasicScreenQuadVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.BASIC_SCREEN_QUADS); + } + + @Override + public void writeQuad(float x, float y, float z, int color) { + long i = this.writePointer; + + MemoryUtil.memPutFloat(i, x); + MemoryUtil.memPutFloat(i + 4, y); + MemoryUtil.memPutFloat(i + 8, z); + MemoryUtil.memPutInt(i + 12, color); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java new file mode 100644 index 000000000..9b85637b6 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java @@ -0,0 +1,20 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer; + +import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; +import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.BasicScreenQuadVertexSink; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import net.minecraft.client.render.VertexConsumer; + +public class BasicScreenQuadVertexWriterFallback extends VertexWriterFallback implements BasicScreenQuadVertexSink { + public BasicScreenQuadVertexWriterFallback(VertexConsumer consumer) { + super(consumer); + } + + @Override + public void writeQuad(float x, float y, float z, int color) { + VertexConsumer consumer = this.consumer; + consumer.vertex(x, y, z); + consumer.color(ColorABGR.unpackRed(color), ColorABGR.unpackGreen(color), ColorABGR.unpackBlue(color), ColorABGR.unpackAlpha(color)); + consumer.next(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/AbstractVertexTransformer.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/AbstractVertexTransformer.java new file mode 100644 index 000000000..bb616beab --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/AbstractVertexTransformer.java @@ -0,0 +1,26 @@ +package me.jellysquid.mods.sodium.client.model.vertex.transformers; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; + +/** + * A vertex transformer wraps an {@link VertexSink} interface to modify incoming vertex data, delegating any + * actual logic to the inner sink. + * @param The {@link VertexSink} interface this transformer wraps + */ +public abstract class AbstractVertexTransformer implements VertexSink { + protected final T delegate; + + protected AbstractVertexTransformer(T delegate) { + this.delegate = delegate; + } + + @Override + public void ensureCapacity(int count) { + this.delegate.ensureCapacity(count); + } + + @Override + public void flush() { + this.delegate.flush(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/SpriteTexturedVertexTransformer.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/SpriteTexturedVertexTransformer.java new file mode 100644 index 000000000..ce9408617 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/SpriteTexturedVertexTransformer.java @@ -0,0 +1,80 @@ +package me.jellysquid.mods.sodium.client.model.vertex.transformers; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.ParticleVertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; +import net.minecraft.client.texture.Sprite; + +/** + * Base implementation for a {@link VertexSink} which transforms texture coordinates relative to a sprite's bounds. + * + * @param The {@link VertexSink} interface this transformer wraps + */ +public abstract class SpriteTexturedVertexTransformer extends AbstractVertexTransformer { + private final float uMin; + private final float vMin; + + private final float uMaxMin; + private final float vMaxMin; + + public SpriteTexturedVertexTransformer(T delegate, Sprite sprite) { + super(delegate); + + this.uMin = sprite.getMinU(); + this.vMin = sprite.getMinV(); + + this.uMaxMin = sprite.getMaxU() - this.uMin; + this.vMaxMin = sprite.getMaxV() - this.vMin; + } + + protected float transformTextureU(float u) { + return (this.uMaxMin * u) + this.uMin; + } + + protected float transformTextureV(float v) { + return (this.vMaxMin * v) + this.vMin; + } + + public static class Quad extends SpriteTexturedVertexTransformer implements QuadVertexSink { + public Quad(QuadVertexSink delegate, Sprite sprite) { + super(delegate, sprite); + } + + @Override + public void writeQuad(float x, float y, float z, int color, float u, float v, int light, int overlay, int normal) { + u = this.transformTextureU(u); + v = this.transformTextureV(v); + + this.delegate.writeQuad(x, y, z, color, u, v, light, overlay, normal); + } + } + + public static class Particle extends SpriteTexturedVertexTransformer implements ParticleVertexSink { + public Particle(ParticleVertexSink delegate, Sprite sprite) { + super(delegate, sprite); + } + + @Override + public void writeParticle(float x, float y, float z, float u, float v, int color, int light) { + u = this.transformTextureU(u); + v = this.transformTextureV(v); + + this.delegate.writeParticle(x, y, z, u, v, color, light); + } + } + + public static class Glyph extends SpriteTexturedVertexTransformer implements GlyphVertexSink { + public Glyph(GlyphVertexSink delegate, Sprite sprite) { + super(delegate, sprite); + } + + @Override + public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) { + u = this.transformTextureU(u); + v = this.transformTextureV(v); + + this.delegate.writeGlyph(x, y, z, color, u, v, light); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/BlittableVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/BlittableVertexType.java new file mode 100644 index 000000000..8ac1a1977 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/BlittableVertexType.java @@ -0,0 +1,15 @@ +package me.jellysquid.mods.sodium.client.model.vertex.type; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; + +public interface BlittableVertexType extends BufferVertexType { + /** + * Creates a {@link VertexSink} which writes into a {@link VertexBufferView}. This allows for specialization + * when the memory storage is known. + * + * @param buffer The backing vertex buffer + * @param direct True if direct memory access is allowed, otherwise false + */ + T createBufferWriter(VertexBufferView buffer, boolean direct); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/BufferVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/BufferVertexType.java new file mode 100644 index 000000000..2a4cdaa65 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/BufferVertexType.java @@ -0,0 +1,14 @@ +package me.jellysquid.mods.sodium.client.model.vertex.type; + +import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; + +/** + * A blittable {@link VertexType} which supports direct copying into a {@link net.minecraft.client.render.BufferBuilder} + * provided the buffer's vertex format matches that required by the {@link VertexSink}. + * + * @param The {@link VertexSink} type this factory produces + */ +public interface BufferVertexType extends VertexType { + BufferVertexFormat getBufferVertexFormat(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/ChunkVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/ChunkVertexType.java new file mode 100644 index 000000000..ad7aaee1b --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/ChunkVertexType.java @@ -0,0 +1,16 @@ +package me.jellysquid.mods.sodium.client.model.vertex.type; + +import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; + +public interface ChunkVertexType extends BlittableVertexType, CustomVertexType { + /** + * @return The scale to be applied to vertex coordinates + */ + float getModelScale(); + + /** + * @return The scale to be applied to texture coordinates + */ + float getTextureScale(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/CustomVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/CustomVertexType.java new file mode 100644 index 000000000..980c01015 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/CustomVertexType.java @@ -0,0 +1,17 @@ +package me.jellysquid.mods.sodium.client.model.vertex.type; + +import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; + +public interface CustomVertexType> extends BufferVertexType { + /** + * @return The {@link GlVertexFormat} required for blitting (direct writing into buffers) + */ + GlVertexFormat getCustomVertexFormat(); + + @Override + default BufferVertexFormat getBufferVertexFormat() { + return this.getCustomVertexFormat(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java new file mode 100644 index 000000000..b69fb2061 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java @@ -0,0 +1,13 @@ +package me.jellysquid.mods.sodium.client.model.vertex.type; + +import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import net.minecraft.client.render.VertexFormat; + +public interface VanillaVertexType extends BufferVertexType { + default BufferVertexFormat getBufferVertexFormat() { + return BufferVertexFormat.from(this.getVertexFormat()); + } + + VertexFormat getVertexFormat(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java new file mode 100644 index 000000000..c742a6c50 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java @@ -0,0 +1,27 @@ +package me.jellysquid.mods.sodium.client.model.vertex.type; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import net.minecraft.client.render.VertexConsumer; + +/** + * Provides factories which create a {@link VertexSink} for the given vertex format. + * + * @param The {@link VertexSink} type this factory produces + */ +public interface VertexType { + /** + * Creates a {@link VertexSink} which can write into any {@link VertexConsumer}. This is generally used when + * a special implementation of {@link VertexConsumer} is used that cannot be optimized for, or when + * complex/unsupported transformations need to be performed using vanilla code paths. + * @param consumer The {@link VertexConsumer} to write into + */ + T createFallbackWriter(VertexConsumer consumer); + + /** + * If this vertex type supports {@link BufferVertexType}, then this method returns this vertex type as a + * blittable type, performing a safe cast. + */ + default BlittableVertexType asBlittable() { + return null; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java new file mode 100644 index 000000000..a3312807c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java @@ -0,0 +1,38 @@ +package me.jellysquid.mods.sodium.client.render; + +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Matrix4f; +import org.lwjgl.system.MemoryStack; + +import java.nio.FloatBuffer; + +public class GameRendererContext { + private static Matrix4f PROJECTION_MATRIX; + + public static void captureProjectionMatrix(Matrix4f matrix) { + PROJECTION_MATRIX = matrix.copy(); + } + + /** + * Obtains a model-view-projection matrix by multiplying the projection matrix with the model-view matrix + * from {@param matrices}. + * + * The returned buffer is only valid for the lifetime of {@param stack}. + * + * @return A float-buffer on the stack containing the model-view-projection matrix in a format suitable for + * uploading as uniform state + */ + public static FloatBuffer getModelViewProjectionMatrix(MatrixStack.Entry matrices, MemoryStack memoryStack) { + if (PROJECTION_MATRIX == null) { + throw new IllegalStateException("Projection matrix has not been captured"); + } + + FloatBuffer bufModelViewProjection = memoryStack.mallocFloat(16); + + Matrix4f matrix = PROJECTION_MATRIX.copy(); + matrix.multiply(matrices.getModel()); + matrix.writeRowFirst(bufModelViewProjection); + + return bufModelViewProjection; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java new file mode 100644 index 000000000..e8491cd31 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -0,0 +1,452 @@ +package me.jellysquid.mods.sodium.client.render; + +import com.mojang.blaze3d.systems.RenderSystem; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongSet; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderBackend; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderManager; +import me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw.MultidrawChunkRenderBackend; +import me.jellysquid.mods.sodium.client.render.chunk.backends.oneshot.ChunkRenderBackendOneshot; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.format.DefaultModelVertexFormats; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPassManager; +import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheShared; +import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; +import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; +import me.jellysquid.mods.sodium.client.world.ChunkStatusListenerManager; +import me.jellysquid.mods.sodium.common.util.ListUtil; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.render.*; +import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; +import net.minecraft.client.render.model.ModelLoader; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.*; +import net.minecraft.util.profiler.Profiler; + +import java.util.Set; +import java.util.SortedSet; + +/** + * Provides an extension to vanilla's {@link WorldRenderer}. + */ +public class SodiumWorldRenderer implements ChunkStatusListener { + private static SodiumWorldRenderer instance; + + private final MinecraftClient client; + + private ClientWorld world; + private int renderDistance; + + private double lastCameraX, lastCameraY, lastCameraZ; + private double lastCameraPitch, lastCameraYaw; + + private boolean useEntityCulling; + + private final LongSet loadedChunkPositions = new LongOpenHashSet(); + private final Set globalBlockEntities = new ObjectOpenHashSet<>(); + + private Frustum frustum; + private ChunkRenderManager chunkRenderManager; + private BlockRenderPassManager renderPassManager; + private ChunkRenderBackend chunkRenderBackend; + + /** + * Instantiates Sodium's world renderer. This should be called at the time of the world renderer initialization. + */ + public static SodiumWorldRenderer create() { + if (instance == null) { + instance = new SodiumWorldRenderer(MinecraftClient.getInstance()); + } + + return instance; + } + + /** + * @throws IllegalStateException If the renderer has not yet been created + * @return The current instance of this type + */ + public static SodiumWorldRenderer getInstance() { + if (instance == null) { + throw new IllegalStateException("Renderer not initialized"); + } + + return instance; + } + + private SodiumWorldRenderer(MinecraftClient client) { + this.client = client; + } + + public void setWorld(ClientWorld world) { + // Check that the world is actually changing + if (this.world == world) { + return; + } + + // If we have a world is already loaded, unload the renderer + if (this.world != null) { + this.unloadWorld(); + } + + // If we're loading a new world, load the renderer + if (world != null) { + this.loadWorld(world); + } + } + + private void loadWorld(ClientWorld world) { + this.world = world; + + ChunkRenderCacheShared.createRenderContext(this.world); + + this.initRenderer(); + + ((ChunkStatusListenerManager) world.getChunkManager()).setListener(this); + } + + private void unloadWorld() { + ChunkRenderCacheShared.destroyRenderContext(this.world); + + if (this.chunkRenderManager != null) { + this.chunkRenderManager.destroy(); + this.chunkRenderManager = null; + } + + if (this.chunkRenderBackend != null) { + this.chunkRenderBackend.delete(); + this.chunkRenderBackend = null; + } + + this.loadedChunkPositions.clear(); + this.globalBlockEntities.clear(); + + this.world = null; + } + + /** + * @return The number of chunk renders which are visible in the current camera's frustum + */ + public int getVisibleChunkCount() { + return this.chunkRenderManager.getVisibleChunkCount(); + } + + /** + * Notifies the chunk renderer that the graph scene has changed and should be re-computed. + */ + public void scheduleTerrainUpdate() { + // BUG: seems to be called before init + if (this.chunkRenderManager != null) { + this.chunkRenderManager.markDirty(); + } + } + + /** + * @return True if no chunks are pending rebuilds + */ + public boolean isTerrainRenderComplete() { + return this.chunkRenderManager.isBuildComplete(); + } + + // We'll keep it to have compatibility with Oculus' older versions + public static boolean hasChanges = false; + + /** + * Called prior to any chunk rendering in order to update necessary state. + */ + public void updateChunks(Camera camera, Frustum frustum, boolean hasForcedFrustum, int frame, boolean spectator) { + this.frustum = frustum; + + this.useEntityCulling = SodiumClientMod.options().advanced.useEntityCulling; + + Profiler profiler = this.client.getProfiler(); + profiler.push("camera_setup"); + + ClientPlayerEntity player = this.client.player; + + if (player == null) { + throw new IllegalStateException("Client instance has no active player entity"); + } + + Vec3d pos = camera.getPos(); + + this.chunkRenderManager.setCameraPosition(pos.x, pos.y, pos.z); + + float pitch = camera.getPitch(); + float yaw = camera.getYaw(); + + boolean dirty = pos.x != this.lastCameraX || pos.y != this.lastCameraY || pos.z != this.lastCameraZ || + pitch != this.lastCameraPitch || yaw != this.lastCameraYaw; + + if (dirty) { + this.chunkRenderManager.markDirty(); + } + + this.lastCameraX = pos.x; + this.lastCameraY = pos.y; + this.lastCameraZ = pos.z; + this.lastCameraPitch = pitch; + this.lastCameraYaw = yaw; + + profiler.swap("chunk_update"); + + this.chunkRenderManager.updateChunks(); + + if (!hasForcedFrustum && this.chunkRenderManager.isDirty()) { + profiler.swap("chunk_graph_rebuild"); + + this.chunkRenderManager.update(camera, (FrustumExtended) frustum, frame, spectator); + } + + profiler.swap("visible_chunk_tick"); + + this.chunkRenderManager.tickVisibleRenders(); + + profiler.pop(); + + Entity.setRenderDistanceMultiplier(MathHelper.clamp((double) this.client.options.viewDistance / 8.0D, 1.0D, 2.5D) * (double) this.client.options.entityDistanceScaling); + } + + /** + * Performs a render pass for the given {@link RenderLayer} and draws all visible chunks for it. + */ + public void drawChunkLayer(RenderLayer renderLayer, MatrixStack matrixStack, double x, double y, double z) { + BlockRenderPass pass = this.renderPassManager.getRenderPassForLayer(renderLayer); + pass.startDrawing(); + + this.chunkRenderManager.renderLayer(matrixStack, pass, x, y, z); + + pass.endDrawing(); + + RenderSystem.clearCurrentColor(); + } + + public void reload() { + if (this.world == null) { + return; + } + + this.initRenderer(); + } + + private void initRenderer() { + if (this.chunkRenderManager != null) { + this.chunkRenderManager.destroy(); + this.chunkRenderManager = null; + } + + if (this.chunkRenderBackend != null) { + this.chunkRenderBackend.delete(); + this.chunkRenderBackend = null; + } + + RenderDevice device = RenderDevice.INSTANCE; + + SodiumGameOptions opts = SodiumClientMod.options(); + + this.renderPassManager = BlockRenderPassManager.createDefaultMappings(); + + final ChunkVertexType vertexFormat; + + if (opts.advanced.useCompactVertexFormat) { + vertexFormat = DefaultModelVertexFormats.MODEL_VERTEX_HFP; + } else { + vertexFormat = DefaultModelVertexFormats.MODEL_VERTEX_SFP; + } + + this.chunkRenderBackend = createChunkRenderBackend(device, opts, vertexFormat); + this.chunkRenderBackend.createShaders(device); + + this.chunkRenderManager = new ChunkRenderManager<>(this, this.chunkRenderBackend, this.renderPassManager, this.world, this.client.options.viewDistance); + this.chunkRenderManager.restoreChunks(this.loadedChunkPositions); + } + + private static ChunkRenderBackend createChunkRenderBackend(RenderDevice device, + SodiumGameOptions options, + ChunkVertexType vertexFormat) { + boolean disableBlacklist = SodiumClientMod.options().advanced.ignoreDriverBlacklist; + + if (options.advanced.useChunkMultidraw && MultidrawChunkRenderBackend.isSupported(disableBlacklist)) { + return new MultidrawChunkRenderBackend(device, vertexFormat); + } else { + return new ChunkRenderBackendOneshot(vertexFormat); + } + } + + private boolean checkBEVisibility(BlockEntity entity) { + return frustum.isVisible(entity.getRenderBoundingBox()); + } + + public void renderTileEntities(MatrixStack matrices, BufferBuilderStorage bufferBuilders, Long2ObjectMap> blockBreakingProgressions, + Camera camera, float tickDelta) { + VertexConsumerProvider.Immediate immediate = bufferBuilders.getEntityVertexConsumers(); + + Vec3d cameraPos = camera.getPos(); + double x = cameraPos.getX(); + double y = cameraPos.getY(); + double z = cameraPos.getZ(); + + for (BlockEntity blockEntity : this.chunkRenderManager.getVisibleBlockEntities()) { + if(blockEntity.isRemoved() || !checkBEVisibility(blockEntity)) + continue; + BlockPos pos = blockEntity.getPos(); + + matrices.push(); + matrices.translate((double) pos.getX() - x, (double) pos.getY() - y, (double) pos.getZ() - z); + + VertexConsumerProvider consumer = immediate; + SortedSet breakingInfos = blockBreakingProgressions.get(pos.asLong()); + + if (breakingInfos != null && !breakingInfos.isEmpty()) { + int stage = breakingInfos.last().getStage(); + + if (stage >= 0) { + MatrixStack.Entry entry = matrices.peek(); + VertexConsumer transformer = new OverlayVertexConsumer(bufferBuilders.getEffectVertexConsumers().getBuffer(ModelLoader.BLOCK_DESTRUCTION_RENDER_LAYERS.get(stage)), entry.getModel(), entry.getNormal()); + consumer = (layer) -> layer.hasCrumbling() ? VertexConsumers.union(transformer, immediate.getBuffer(layer)) : immediate.getBuffer(layer); + } + } + + BlockEntityRenderDispatcher.INSTANCE.render(blockEntity, tickDelta, matrices, consumer); + + matrices.pop(); + } + + for (BlockEntity blockEntity : this.globalBlockEntities) { + if(!checkBEVisibility(blockEntity)) + continue; + BlockPos pos = blockEntity.getPos(); + + matrices.push(); + matrices.translate((double) pos.getX() - x, (double) pos.getY() - y, (double) pos.getZ() - z); + + BlockEntityRenderDispatcher.INSTANCE.render(blockEntity, tickDelta, matrices, immediate); + + matrices.pop(); + } + } + + @Override + public void onChunkAdded(int x, int z) { + this.loadedChunkPositions.add(ChunkPos.toLong(x, z)); + this.chunkRenderManager.onChunkAdded(x, z); + } + + @Override + public void onChunkRemoved(int x, int z) { + this.loadedChunkPositions.remove(ChunkPos.toLong(x, z)); + this.chunkRenderManager.onChunkRemoved(x, z); + } + + public void onChunkRenderUpdated(int x, int y, int z, ChunkRenderData meshBefore, ChunkRenderData meshAfter) { + ListUtil.updateList(this.globalBlockEntities, meshBefore.getGlobalBlockEntities(), meshAfter.getGlobalBlockEntities()); + + this.chunkRenderManager.onChunkRenderUpdates(x, y, z, meshAfter); + } + + private static boolean isInfiniteExtentsBox(Box box) { + return Double.isInfinite(box.minX) || Double.isInfinite(box.minY) || Double.isInfinite(box.minZ) + || Double.isInfinite(box.maxX) || Double.isInfinite(box.maxY) || Double.isInfinite(box.maxZ); + } + + /** + * Returns whether or not the entity intersects with any visible chunks in the graph. + * @return True if the entity is visible, otherwise false + */ + public boolean isEntityVisible(Entity entity) { + if (!this.useEntityCulling) { + return true; + } + + Box box = entity.getVisibilityBoundingBox(); + + // Entities outside the valid world height will never map to a rendered chunk + // Always render these entities or they'll be culled incorrectly! + if (box.maxY < 0.5D || box.minY > 255.5D) { + return true; + } + + if (isInfiniteExtentsBox(box)) { + return true; + } + + // Ensure entities with outlines or nametags are always visible + if (this.client.hasOutline(entity) || entity.shouldRenderName()) { + return true; + } + + int minX = MathHelper.floor(box.minX - 0.5D) >> 4; + int minY = MathHelper.floor(box.minY - 0.5D) >> 4; + int minZ = MathHelper.floor(box.minZ - 0.5D) >> 4; + + int maxX = MathHelper.floor(box.maxX + 0.5D) >> 4; + int maxY = MathHelper.floor(box.maxY + 0.5D) >> 4; + int maxZ = MathHelper.floor(box.maxZ + 0.5D) >> 4; + + for (int x = minX; x <= maxX; x++) { + for (int z = minZ; z <= maxZ; z++) { + for (int y = minY; y <= maxY; y++) { + if (this.chunkRenderManager.isChunkVisible(x, y, z)) { + return true; + } + } + } + } + + return false; + } + + /** + * @return The frustum of the current player's camera used to cull chunks + */ + public Frustum getFrustum() { + return this.frustum; + } + + public String getChunksDebugString() { + // C: visible/total + // TODO: add dirty and queued counts + return String.format("C: %s/%s", this.chunkRenderManager.getVisibleChunkCount(), this.chunkRenderManager.getTotalSections()); + } + + /** + * Schedules chunk rebuilds for all chunks in the specified block region. + */ + public void scheduleRebuildForBlockArea(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, boolean important) { + this.scheduleRebuildForChunks(minX >> 4, minY >> 4, minZ >> 4, maxX >> 4, maxY >> 4, maxZ >> 4, important); + } + + /** + * Schedules chunk rebuilds for all chunks in the specified chunk region. + */ + public void scheduleRebuildForChunks(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, boolean important) { + for (int chunkX = minX; chunkX <= maxX; chunkX++) { + for (int chunkY = minY; chunkY <= maxY; chunkY++) { + for (int chunkZ = minZ; chunkZ <= maxZ; chunkZ++) { + this.scheduleRebuildForChunk(chunkX, chunkY, chunkZ, important); + } + } + } + } + + /** + * Schedules a chunk rebuild for the render belonging to the given chunk section position. + */ + public void scheduleRebuildForChunk(int x, int y, int z, boolean important) { + this.chunkRenderManager.scheduleRebuild(x, y, z, important); + } + + public ChunkRenderBackend getChunkRenderer() { + return this.chunkRenderBackend; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkCameraContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkCameraContext.java new file mode 100644 index 000000000..3610c382e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkCameraContext.java @@ -0,0 +1,21 @@ +package me.jellysquid.mods.sodium.client.render.chunk; + +public class ChunkCameraContext { + public final int blockOriginX, blockOriginY, blockOriginZ; + public final float originX, originY, originZ; + + public ChunkCameraContext(double x, double y, double z) { + this.blockOriginX = (int) x; + this.blockOriginY = (int) y; + this.blockOriginZ = (int) z; + + this.originX = (float) (x - this.blockOriginX); + this.originY = (float) (y - this.blockOriginY); + this.originZ = (float) (z - this.blockOriginZ); + } + + public float getChunkModelOffset(int chunkBlockPos, int cameraBlockPos, float cameraPos) { + int t = chunkBlockPos - cameraBlockPos; + return t - cameraPos; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkGraphicsState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkGraphicsState.java new file mode 100644 index 000000000..0c74e0c4b --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkGraphicsState.java @@ -0,0 +1,39 @@ +package me.jellysquid.mods.sodium.client.render.chunk; + +import me.jellysquid.mods.sodium.client.gl.device.CommandList; + +import java.nio.ByteBuffer; + +public abstract class ChunkGraphicsState { + private final int x, y, z; + + private ByteBuffer translucencyData; + + protected ChunkGraphicsState(ChunkRenderContainer container) { + this.x = container.getRenderX(); + this.y = container.getRenderY(); + this.z = container.getRenderZ(); + } + + public abstract void delete(CommandList commandList); + + public int getX() { + return this.x; + } + + public int getY() { + return this.y; + } + + public int getZ() { + return this.z; + } + + public ByteBuffer getTranslucencyData() { + return this.translucencyData; + } + + public void setTranslucencyData(ByteBuffer data) { + this.translucencyData = data; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java new file mode 100644 index 000000000..a845d6856 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java @@ -0,0 +1,59 @@ +package me.jellysquid.mods.sodium.client.render.chunk; + +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; +import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterator; +import net.minecraft.client.util.math.MatrixStack; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * The chunk render backend takes care of managing the graphics resource state of chunk render containers. This includes + * the handling of uploading their data to the graphics card and rendering responsibilities. + * @param The type of graphics state to be used in chunk render containers + */ +public interface ChunkRenderBackend { + /** + * Drains the iterator of items and processes each build task's result serially. After this method returns, all + * drained results should be processed. + */ + void upload(CommandList commandList, Iterator> queue); + + /** + * Renders the given chunk render list to the active framebuffer. + * @param commandList The command list which OpenGL commands should be serialized to + * @param renders An iterator over the list of chunks to be rendered + * @param camera The camera context containing chunk offsets for the current render + */ + void render(CommandList commandList, ChunkRenderListIterator renders, ChunkCameraContext camera); + + void createShaders(RenderDevice device); + + void begin(MatrixStack matrixStack); + + void end(MatrixStack matrixStack); + + /** + * Deletes this render backend and any resources attached to it. + */ + void delete(); + + /** + * Returns the vertex format used by this chunk render backend for rendering meshes. + */ + ChunkVertexType getVertexType(); + + Class getGraphicsStateType(); + + default String getRendererName() { + return this.getClass().getSimpleName(); + } + + default List getDebugStrings() { + return Collections.emptyList(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderColumn.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderColumn.java new file mode 100644 index 000000000..1995bb692 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderColumn.java @@ -0,0 +1,81 @@ +package me.jellysquid.mods.sodium.client.render.chunk; + +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.util.math.Direction; + +public class ChunkRenderColumn { + @SuppressWarnings("unchecked") + private final ChunkRenderContainer[] renders = new ChunkRenderContainer[16]; + + @SuppressWarnings("unchecked") + private final ChunkRenderColumn[] adjacent = new ChunkRenderColumn[6]; + + private final int x, z; + + public ChunkRenderColumn(int x, int z) { + this.x = x; + this.z = z; + + this.setAdjacentColumn(Direction.UP, this); + this.setAdjacentColumn(Direction.DOWN, this); + } + + public void setAdjacentColumn(Direction dir, ChunkRenderColumn column) { + this.adjacent[dir.ordinal()] = column; + } + + public ChunkRenderColumn getAdjacentColumn(Direction dir) { + return this.adjacent[dir.ordinal()]; + } + + public void setRender(int y, ChunkRenderContainer render) { + this.renders[y] = render; + } + + public ChunkRenderContainer getRender(int y) { + if (y < 0 || y >= this.renders.length) { + return null; + } + return this.renders[y]; + } + + public int getX() { + return this.x; + } + + public int getZ() { + return this.z; + } + + public boolean areNeighborsPresent() { + for (Direction dir : DirectionUtil.HORIZONTAL_DIRECTIONS) { + ChunkRenderColumn adj = this.adjacent[dir.ordinal()]; + + if (adj == null) { + return false; + } + + Direction corner; + + // Access the adjacent corner chunk from the neighbor in this direction + if (dir == Direction.NORTH) { + corner = Direction.EAST; + } else if (dir == Direction.SOUTH) { + corner = Direction.WEST; + } else if (dir == Direction.WEST) { + corner = Direction.NORTH; + } else if (dir == Direction.EAST) { + corner = Direction.SOUTH; + } else { + continue; + } + + // If no neighbor has been attached, the chunk is not present + if (adj.getAdjacentColumn(corner) == null) { + return false; + } + } + + return true; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java new file mode 100644 index 000000000..8f2a564a8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java @@ -0,0 +1,323 @@ +package me.jellysquid.mods.sodium.client.render.chunk; + +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderBounds; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; +import net.minecraft.client.texture.Sprite; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkSectionPos; + +import java.lang.reflect.Array; +import java.util.concurrent.CompletableFuture; + +/** + * The render state object for a chunk section. This contains all the graphics state for each render pass along with + * data about the render in the chunk visibility graph. + */ +public class ChunkRenderContainer { + private final SodiumWorldRenderer worldRenderer; + private final int chunkX, chunkY, chunkZ; + + private final T[] graphicsStates; + private final ChunkRenderColumn column; + + private ChunkRenderData data = ChunkRenderData.ABSENT; + private CompletableFuture rebuildTask = null; + + private boolean needsRebuild; + private boolean needsImportantRebuild; + + private boolean needsSort; + + private boolean tickable; + private int id; + + private boolean rebuildableForTranslucents; + + public ChunkRenderContainer(ChunkRenderBackend backend, SodiumWorldRenderer worldRenderer, int chunkX, int chunkY, int chunkZ, ChunkRenderColumn column) { + this.worldRenderer = worldRenderer; + + this.chunkX = chunkX; + this.chunkY = chunkY; + this.chunkZ = chunkZ; + + //noinspection unchecked + this.graphicsStates = (T[]) Array.newInstance(backend.getGraphicsStateType(), BlockRenderPass.COUNT); + this.rebuildableForTranslucents = false; + this.column = column; + } + + /** + * Cancels any pending tasks to rebuild the chunk. If the result of any pending tasks has not been processed yet, + * those will also be discarded when processing finally happens. + */ + public void cancelRebuildTask() { + this.needsRebuild = false; + this.needsImportantRebuild = false; + this.needsSort = false; + + if (this.rebuildTask != null) { + this.rebuildTask.cancel(false); + this.rebuildTask = null; + } + } + + public ChunkRenderData getData() { + return this.data; + } + + /** + * @return True if the render's state is out of date with the world state + */ + public boolean needsRebuild() { + return this.needsRebuild; + } + + /** + * @return True if the render's rebuild should be performed as blocking + */ + public boolean needsImportantRebuild() { + return this.needsImportantRebuild; + } + + public boolean needsSort() { + return this.needsSort; + } + + /** + * Deletes all data attached to this render and drops any pending tasks. This should be used when the render falls + * out of view or otherwise needs to be destroyed. After the render has been destroyed, the object can no longer + * be used. + */ + public void delete() { + this.cancelRebuildTask(); + this.setData(ChunkRenderData.ABSENT); + this.deleteGraphicsState(); + } + + private void deleteGraphicsState() { + T[] states = this.graphicsStates; + + for (int i = 0; i < states.length; i++) { + T state = states[i]; + + if (state != null) { + state.delete(RenderDevice.INSTANCE.createCommandList()); + states[i] = null; + } + } + } + + public boolean shouldRebuildForTranslucents() { + return this.rebuildableForTranslucents; + } + + public void setRebuildForTranslucents(boolean flag) { + this.rebuildableForTranslucents = flag; + } + + + public void setData(ChunkRenderData info) { + if (info == null) { + throw new NullPointerException("Mesh information must not be null"); + } + + this.worldRenderer.onChunkRenderUpdated(this.chunkX, this.chunkY, this.chunkZ, this.data, info); + this.data = info; + + this.tickable = !info.getAnimatedSprites().isEmpty(); + } + + /** + * Marks this render as needing an update. Important updates are scheduled as "blocking" and will prevent the next + * frame from being rendered until the update is performed. + * @param important True if the update is blocking, otherwise false + */ + public boolean scheduleRebuild(boolean important) { + boolean changed = !this.needsRebuild || (!this.needsImportantRebuild && important); + + this.needsImportantRebuild = important; + this.needsRebuild = true; + this.needsSort = false; + + return changed; + } + + public boolean scheduleSort(boolean important) { + if (this.needsRebuild) + return false; + + boolean changed = !this.needsSort; + this.needsSort = true; + + return changed; + } + + /** + * @return True if the chunk render contains no data, otherwise false + */ + public boolean isEmpty() { + return this.data.isEmpty(); + } + + /** + * Returns the chunk section position which this render refers to in the world. + */ + public ChunkSectionPos getChunkPos() { + return ChunkSectionPos.from(this.chunkX, this.chunkY, this.chunkZ); + } + + /** + * Tests if the given chunk render is visible within the provided frustum. + * @param frustum The frustum to test against + * @return True if visible, otherwise false + */ + public boolean isOutsideFrustum(FrustumExtended frustum) { + float x = this.getOriginX(); + float y = this.getOriginY(); + float z = this.getOriginZ(); + + return !frustum.fastAabbTest(x, y, z, x + 16.0f, y + 16.0f, z + 16.0f); + } + + /** + * Ensures that all resources attached to the given chunk render are "ticked" forward. This should be called every + * time before this render is drawn if {@link ChunkRenderContainer#isTickable()} is true. + */ + public void tick() { + for (Sprite sprite : this.data.getAnimatedSprites()) { + SpriteUtil.markSpriteActive(sprite); + } + } + + /** + * @return The x-coordinate of the origin position of this chunk render + */ + public int getOriginX() { + return this.chunkX << 4; + } + + /** + * @return The y-coordinate of the origin position of this chunk render + */ + public int getOriginY() { + return this.chunkY << 4; + } + + /** + * @return The z-coordinate of the origin position of this chunk render + */ + public int getOriginZ() { + return this.chunkZ << 4; + } + + public int getRenderX() { + return this.getOriginX() - 8; + } + + public int getRenderY() { + return this.getOriginY() - 8; + } + + public int getRenderZ() { + return this.getOriginZ() - 8; + } + + /** + * @return The squared distance from the center of this chunk in the world to the given position + */ + public double getSquaredDistance(double x, double y, double z) { + double xDist = x - this.getCenterX(); + double yDist = y - this.getCenterY(); + double zDist = z - this.getCenterZ(); + + return (xDist * xDist) + (yDist * yDist) + (zDist * zDist); + } + + /** + * @return The x-coordinate of the center position of this chunk render + */ + private double getCenterX() { + return this.getOriginX() + 8.0D; + } + + /** + * @return The y-coordinate of the center position of this chunk render + */ + private double getCenterY() { + return this.getOriginY() + 8.0D; + } + + /** + * @return The z-coordinate of the center position of this chunk render + */ + private double getCenterZ() { + return this.getOriginZ() + 8.0D; + } + + public BlockPos getRenderOrigin() { + return new BlockPos(this.getRenderX(), this.getRenderY(), this.getRenderZ()); + } + + public T[] getGraphicsStates() { + return this.graphicsStates; + } + + public void setGraphicsState(BlockRenderPass pass, T state) { + this.graphicsStates[pass.ordinal()] = state; + } + + /** + * @return The squared distance from the center of this chunk in the world to the given position + */ + public double getSquaredDistanceXZ(double x, double z) { + double xDist = x - this.getCenterX(); + double zDist = z - this.getCenterZ(); + + return (xDist * xDist) + (zDist * zDist); + } + + public int getChunkX() { + return this.chunkX; + } + + public int getChunkY() { + return this.chunkY; + } + + public int getChunkZ() { + return this.chunkZ; + } + + public ChunkRenderBounds getBounds() { + return this.data.getBounds(); + } + + public T getGraphicsState(BlockRenderPass pass) { + return this.graphicsStates[pass.ordinal()]; + } + + public boolean isTickable() { + return this.tickable; + } + + public int getFacesWithData() { + return this.data.getFacesWithData(); + } + + public boolean canRebuild() { + return this.column.areNeighborsPresent(); + } + + public void setId(int id) { + this.id = id; + } + + public int getId() { + return this.id; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java new file mode 100644 index 000000000..79dcd8e7d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -0,0 +1,623 @@ +package me.jellysquid.mods.sodium.client.render.chunk; + +import it.unimi.dsi.fastutil.ints.IntIterator; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.LongCollection; +import it.unimi.dsi.fastutil.longs.LongIterator; +import it.unimi.dsi.fastutil.objects.ObjectArrayFIFOQueue; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectList; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gl.compat.FogHelper; +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw.MultidrawChunkRenderBackend; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuilder; +import me.jellysquid.mods.sodium.client.render.chunk.cull.ChunkCuller; +import me.jellysquid.mods.sodium.client.render.chunk.cull.ChunkFaceFlags; +import me.jellysquid.mods.sodium.client.render.chunk.cull.graph.ChunkGraphCuller; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderBounds; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; +import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterator; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPassManager; +import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; +import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import me.jellysquid.mods.sodium.common.util.IdTable; +import me.jellysquid.mods.sodium.common.util.collections.FutureDequeDrain; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.Camera; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.chunk.ChunkSection; + +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Deque; +import java.util.concurrent.CompletableFuture; + +public class ChunkRenderManager implements ChunkStatusListener { + /** + * The maximum distance a chunk can be from the player's camera in order to be eligible for blocking updates. + */ + private static final double NEARBY_CHUNK_DISTANCE = Math.pow(48, 2.0); + + /** + * The minimum distance the culling plane can be from the player's camera. This helps to prevent mathematical + * errors that occur when the fog distance is less than 8 blocks in width, such as when using a blindness potion. + */ + private static final float FOG_PLANE_MIN_DISTANCE = (float) Math.pow(8.0f, 2.0); + + /** + * The distance past the fog's far plane at which to begin culling. Distance calculations use the center of each + * chunk from the camera's position, and as such, special care is needed to ensure that the culling plane is pushed + * back far enough. I'm sure there's a mathematical formula that should be used here in place of the constant, + * but this value works fine in testing. + */ + private static final float FOG_PLANE_OFFSET = 12.0f; + + private final ChunkBuilder builder; + private final ChunkRenderBackend backend; + + private final Thread renderThread = Thread.currentThread(); + + private final Long2ObjectOpenHashMap> columns = new Long2ObjectOpenHashMap<>(); + private final IdTable> renders = new IdTable<>(16384); + + private final ObjectArrayFIFOQueue> importantRebuildQueue = new ObjectArrayFIFOQueue<>(); + private final ObjectArrayFIFOQueue> rebuildQueue = new ObjectArrayFIFOQueue<>(); + private final ObjectArrayFIFOQueue> sortQueue = new ObjectArrayFIFOQueue<>(); + private final ObjectArrayFIFOQueue> unloadQueue = new ObjectArrayFIFOQueue<>(); + + @SuppressWarnings("unchecked") + private final ChunkRenderList[] chunkRenderLists = new ChunkRenderList[BlockRenderPass.COUNT]; + private final ObjectList> tickableChunks = new ObjectArrayList<>(); + + private final ObjectList visibleBlockEntities = new ObjectArrayList<>(); + + private final SodiumWorldRenderer renderer; + private final ClientWorld world; + + private final ChunkCuller culler; + private final boolean useBlockFaceCulling; + + private float cameraX, cameraY, cameraZ; + private boolean dirty; + + private final boolean translucencySorting; + + private int visibleChunkCount; + + private boolean useFogCulling; + private double fogRenderCutoff; + + private final int translucencyBlockRenderDistance; + + private boolean alwaysDeferChunkUpdates; + + public ChunkRenderManager(SodiumWorldRenderer renderer, ChunkRenderBackend backend, BlockRenderPassManager renderPassManager, ClientWorld world, int renderDistance) { + this.backend = backend; + this.renderer = renderer; + this.world = world; + + this.builder = new ChunkBuilder<>(backend.getVertexType(), this.backend); + this.builder.init(world, renderPassManager); + + this.dirty = true; + + for (int i = 0; i < this.chunkRenderLists.length; i++) { + this.chunkRenderLists[i] = new ChunkRenderList<>(); + } + + this.culler = new ChunkGraphCuller(world, renderDistance); + this.translucencySorting = SodiumClientMod.options().advanced.translucencySorting; + this.translucencyBlockRenderDistance = Math.min(9216, (renderDistance << 4) * (renderDistance << 4)); + + this.useBlockFaceCulling = SodiumClientMod.options().advanced.useBlockFaceCulling; + } + + public void update(Camera camera, FrustumExtended frustum, int frame, boolean spectator) { + this.reset(); + this.unloadPending(); + + this.setup(camera); + this.iterateChunks(camera, frustum, frame, spectator); + + this.dirty = false; + } + + private void setup(Camera camera) { + Vec3d cameraPos = camera.getPos(); + + this.cameraX = (float) cameraPos.x; + this.cameraY = (float) cameraPos.y; + this.cameraZ = (float) cameraPos.z; + + this.useFogCulling = false; + this.alwaysDeferChunkUpdates = SodiumClientMod.options().performance.alwaysDeferChunkUpdates; + + if (SodiumClientMod.options().advanced.useFogOcclusion) { + float dist = FogHelper.getFogCutoff() + FOG_PLANE_OFFSET; + + if (dist != 0.0f) { + this.useFogCulling = true; + this.fogRenderCutoff = Math.max(FOG_PLANE_MIN_DISTANCE, dist * dist); + } + } + } + + private void iterateChunks(Camera camera, FrustumExtended frustum, int frame, boolean spectator) { + // Schedule new translucency sorting tasks if the camera has moved + if(this.translucencySorting) { + this.checkTranslucencyCameraMoved(); + if(this.hasCameraMovedTranslucent) { + for(Object o : this.renders.getElements()) { + if(o == null) + continue; + ChunkRenderContainer render = (ChunkRenderContainer)o; + if(render.getData().isEmpty()) + continue; + if(!render.needsRebuild() && render.canRebuild() && render.shouldRebuildForTranslucents() && render.getSquaredDistance(cameraX, cameraY, cameraZ) < translucencyBlockRenderDistance) { + // put it at the end of the queue, after any "real" rebuild tasks + render.scheduleSort(false); + } + } + } + } + + IntList list = this.culler.computeVisible(camera, frustum, frame, spectator); + IntIterator it = list.iterator(); + + while (it.hasNext()) { + ChunkRenderContainer render = this.renders.get(it.nextInt()); + + this.addChunk(render); + } + } + + private float lastCameraTranslucentX, lastCameraTranslucentY, lastCameraTranslucentZ; + private boolean hasCameraMovedTranslucent; + + private void checkTranslucencyCameraMoved() { + float dx = (cameraX - lastCameraTranslucentX); + float dy = (cameraY - lastCameraTranslucentY); + float dz = (cameraZ - lastCameraTranslucentZ); + if((dx * dx + dy * dy + dz * dz) > 1.0) { + lastCameraTranslucentX = cameraX; + lastCameraTranslucentY = cameraY; + lastCameraTranslucentZ = cameraZ; + hasCameraMovedTranslucent = true; + } else + hasCameraMovedTranslucent = false; + } + + private void addChunk(ChunkRenderContainer render) { + if (render.needsRebuild() && render.canRebuild()) { + if (!this.alwaysDeferChunkUpdates && render.needsImportantRebuild()) { + this.importantRebuildQueue.enqueue(render); + } else { + this.rebuildQueue.enqueue(render); + } + } else if (render.canRebuild() && !render.getData().isEmpty() && render.needsSort()) { + this.sortQueue.enqueue(render); + } + + if (this.useFogCulling && render.getSquaredDistanceXZ(this.cameraX, this.cameraZ) >= this.fogRenderCutoff) { + return; + } + + if (!render.isEmpty()) { + this.addChunkToRenderLists(render); + this.addEntitiesToRenderLists(render); + } + } + + private void addChunkToRenderLists(ChunkRenderContainer render) { + int visibleFaces = this.computeVisibleFaces(render) & render.getFacesWithData(); + + if (visibleFaces == 0) { + return; + } + + boolean added = false; + T[] states = render.getGraphicsStates(); + + for (int i = 0; i < states.length; i++) { + T state = states[i]; + + if (state != null) { + ChunkRenderList list = this.chunkRenderLists[i]; + list.add(state, (this.translucencySorting && BlockRenderPass.VALUES[i].isTranslucent()) ? (ChunkFaceFlags.ALL & render.getFacesWithData()) : visibleFaces); + + added = true; + } + } + + if (added) { + if (render.isTickable()) { + this.tickableChunks.add(render); + } + + this.visibleChunkCount++; + } + } + + private int computeVisibleFaces(ChunkRenderContainer render) { + // If chunk face culling is disabled, render all faces + if (!this.useBlockFaceCulling) { + return ChunkFaceFlags.ALL; + } + + ChunkRenderBounds bounds = render.getBounds(); + + // Always render groups of vertices not belonging to any given face + int visibleFaces = ChunkFaceFlags.UNASSIGNED; + + if (this.cameraY > bounds.y1) { + visibleFaces |= ChunkFaceFlags.UP; + } + + if (this.cameraY < bounds.y2) { + visibleFaces |= ChunkFaceFlags.DOWN; + } + + if (this.cameraX > bounds.x1) { + visibleFaces |= ChunkFaceFlags.EAST; + } + + if (this.cameraX < bounds.x2) { + visibleFaces |= ChunkFaceFlags.WEST; + } + + if (this.cameraZ > bounds.z1) { + visibleFaces |= ChunkFaceFlags.SOUTH; + } + + if (this.cameraZ < bounds.z2) { + visibleFaces |= ChunkFaceFlags.NORTH; + } + + return visibleFaces; + } + + private void addEntitiesToRenderLists(ChunkRenderContainer render) { + Collection blockEntities = render.getData().getBlockEntities(); + + if (!blockEntities.isEmpty()) { + this.visibleBlockEntities.addAll(blockEntities); + } + } + + public ChunkRenderContainer getRender(int x, int y, int z) { + ChunkRenderColumn column = this.columns.get(ChunkPos.toLong(x, z)); + + if (column == null) { + return null; + } + + return column.getRender(y); + } + + private void reset() { + this.rebuildQueue.clear(); + this.importantRebuildQueue.clear(); + this.sortQueue.clear(); + + this.visibleBlockEntities.clear(); + + for (ChunkRenderList list : this.chunkRenderLists) { + list.reset(); + } + + this.tickableChunks.clear(); + + this.visibleChunkCount = 0; + } + + private void unloadPending() { + while (!this.unloadQueue.isEmpty()) { + this.unloadQueue.dequeue() + .delete(); + } + } + + public Collection getVisibleBlockEntities() { + return this.visibleBlockEntities; + } + + @Override + public void onChunkAdded(int x, int z) { + this.loadChunk(x, z); + } + + @Override + public void onChunkRemoved(int x, int z) { + this.unloadChunk(x, z); + } + + private void loadChunk(int x, int z) { + ChunkRenderColumn column = new ChunkRenderColumn<>(x, z); + ChunkRenderColumn prev; + + if ((prev = this.columns.put(ChunkPos.toLong(x, z), column)) != null) { + this.unloadSections(prev); + } + + this.connectNeighborColumns(column); + this.loadSections(column); + + this.dirty = true; + } + + private void unloadChunk(int x, int z) { + ChunkRenderColumn column = this.columns.remove(ChunkPos.toLong(x, z)); + + if (column == null) { + return; + } + + this.disconnectNeighborColumns(column); + this.unloadSections(column); + + this.dirty = true; + } + + private void loadSections(ChunkRenderColumn column) { + int x = column.getX(); + int z = column.getZ(); + + for (int y = 0; y < 16; y++) { + ChunkRenderContainer render = this.createChunkRender(column, x, y, z); + column.setRender(y, render); + + this.culler.onSectionLoaded(x, y, z, render.getId()); + } + } + + private void unloadSections(ChunkRenderColumn column) { + int x = column.getX(); + int z = column.getZ(); + + for (int y = 0; y < 16; y++) { + ChunkRenderContainer render = column.getRender(y); + + if (render != null) { + this.unloadQueue.enqueue(render); + this.renders.remove(render.getId()); + } + + this.culler.onSectionUnloaded(x, y, z); + } + } + + private void connectNeighborColumns(ChunkRenderColumn column) { + for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + ChunkRenderColumn adj = this.getAdjacentColumn(column, dir); + + if (adj != null) { + adj.setAdjacentColumn(dir.getOpposite(), column); + } + + column.setAdjacentColumn(dir, adj); + } + } + + private void disconnectNeighborColumns(ChunkRenderColumn column) { + for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + ChunkRenderColumn adj = column.getAdjacentColumn(dir); + + if (adj != null) { + adj.setAdjacentColumn(dir.getOpposite(), null); + } + + column.setAdjacentColumn(dir, null); + } + } + + private ChunkRenderColumn getAdjacentColumn(ChunkRenderColumn column, Direction dir) { + return this.getColumn(column.getX() + dir.getOffsetX(), column.getZ() + dir.getOffsetZ()); + } + + private ChunkRenderColumn getColumn(int x, int z) { + return this.columns.get(ChunkPos.toLong(x, z)); + } + + private ChunkRenderContainer createChunkRender(ChunkRenderColumn column, int x, int y, int z) { + ChunkRenderContainer render = new ChunkRenderContainer<>(this.backend, this.renderer, x, y, z, column); + + if (ChunkSection.isEmpty(this.world.getChunk(x, z).getSectionArray()[y])) { + render.setData(ChunkRenderData.EMPTY); + } else { + render.scheduleRebuild(false); + } + + render.setId(this.renders.add(render)); + + return render; + } + + public void renderLayer(MatrixStack matrixStack, BlockRenderPass pass, double x, double y, double z) { + ChunkRenderList chunkRenderList = this.chunkRenderLists[pass.ordinal()]; + ChunkRenderListIterator iterator = chunkRenderList.iterator(pass.isTranslucent()); + + RenderDevice device = RenderDevice.INSTANCE; + CommandList commandList = device.createCommandList(); + + this.backend.begin(matrixStack); + // Ensure multidraw regions are ordered appropriately + if(this.backend instanceof MultidrawChunkRenderBackend) { + ((MultidrawChunkRenderBackend) this.backend).setReverseRegions(pass.isTranslucent()); + } + this.backend.render(commandList, iterator, new ChunkCameraContext(x, y, z)); + this.backend.end(matrixStack); + + commandList.flush(); + } + + public void tickVisibleRenders() { + for (ChunkRenderContainer render : this.tickableChunks) { + render.tick(); + } + } + + public boolean isChunkVisible(int x, int y, int z) { + return this.culler.isSectionVisible(x, y, z); + } + + public void updateChunks() { + this.builder.cleanupSectionCache(); + + Deque>> futures = new ArrayDeque<>(); + + int budget = this.builder.getSchedulingBudget(); + int submitted = 0; + + while (!this.importantRebuildQueue.isEmpty()) { + ChunkRenderContainer render = this.importantRebuildQueue.dequeue(); + + if (render == null) { + 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)); + } + + this.dirty = true; + submitted++; + // Limit quantity of updates submitted if we are deferring all important builds + if (this.alwaysDeferChunkUpdates && submitted >= budget) + break; + } + + while (submitted < budget && !this.rebuildQueue.isEmpty()) { + ChunkRenderContainer render = this.rebuildQueue.dequeue(); + + this.builder.deferRebuild(render); + submitted++; + } + + // always do at least one sort + boolean sortedAnything = false; + while ((!sortedAnything || submitted < budget) && !this.sortQueue.isEmpty()) { + ChunkRenderContainer render = this.sortQueue.dequeue(); + + this.builder.deferSort(render); + sortedAnything = true; + submitted++; + } + + this.dirty |= submitted > 0; + + // Try to complete some other work on the main thread while we wait for rebuilds to complete + this.dirty |= this.builder.performPendingUploads(); + + if (!futures.isEmpty()) { + this.backend.upload(RenderDevice.INSTANCE.createCommandList(), new FutureDequeDrain<>(futures)); + } + } + + public void markDirty() { + this.dirty = true; + } + + public boolean isDirty() { + return this.dirty; + } + + public void restoreChunks(LongCollection chunks) { + LongIterator it = chunks.iterator(); + + while (it.hasNext()) { + long pos = it.nextLong(); + + this.loadChunk(ChunkPos.getPackedX(pos), ChunkPos.getPackedZ(pos)); + } + } + + public boolean isBuildComplete() { + return this.builder.isBuildQueueEmpty(); + } + + public void setCameraPosition(double x, double y, double z) { + this.builder.setCameraPosition(x, y, z); + } + + public void destroy() { + this.reset(); + + for (ChunkRenderColumn column : this.columns.values()) { + this.unloadSections(column); + } + + this.columns.clear(); + + this.builder.stopWorkers(); + } + + public int getTotalSections() { + return this.columns.size() * 16; + } + + private void scheduleRebuildOffThread(int x, int y, int z, boolean important) { + MinecraftClient.getInstance().submit(() -> this.scheduleRebuild(x, y, z, important)); + } + + public void scheduleRebuild(int x, int y, int z, boolean important) { + // Some mods try to schedule rebuilds off the main thread. This is dangerous, + // but the vanilla renderer seems to tolerate it. Our hashmaps are not thread-safe + // so the best solution is to do what the server chunk system does and handle this + // on the main thread. + if (Thread.currentThread() != renderThread) { + this.scheduleRebuildOffThread(x, y, z, important); + return; + } + + ChunkRenderContainer render = this.getRender(x, y, z); + + if (render != null) { + // Nearby chunks are always rendered immediately + important = important || this.isChunkPrioritized(render); + + // Only enqueue chunks for updates if they aren't already enqueued for an update + // + // We should avoid rebuilding chunks that aren't visible by using data from the occlusion culler, however + // that is not currently feasible because occlusion culling data is only ever updated when chunks are + // rebuilt. Computation of occlusion data needs to be isolated from chunk rebuilds for that to be feasible. + // + // TODO: Avoid rebuilding chunks that aren't visible to the player + if (render.scheduleRebuild(important)) { + (render.needsImportantRebuild() ? this.importantRebuildQueue : this.rebuildQueue) + .enqueue(render); + } + + this.dirty = true; + } + + this.builder.onChunkDataChanged(x, y, z); + } + + public boolean isChunkPrioritized(ChunkRenderContainer render) { + return render != null ? render.getSquaredDistance(this.cameraX, this.cameraY, this.cameraZ) <= NEARBY_CHUNK_DISTANCE : false; + } + + public int getVisibleChunkCount() { + return this.visibleChunkCount; + } + + public void onChunkRenderUpdates(int x, int y, int z, ChunkRenderData data) { + this.culler.onSectionStateChanged(x, y, z, data.getOcclusionData()); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java new file mode 100644 index 000000000..fc2ad3aca --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java @@ -0,0 +1,125 @@ +package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.system.MemoryUtil; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; + +/** + * Provides a fixed-size buffer which can be used to batch chunk section draw calls. + */ +public abstract class ChunkDrawCallBatcher extends StructBuffer { + protected final int capacity; + + protected boolean isBuilding; + protected int count; + + protected int arrayLength; + + protected ChunkDrawCallBatcher(int capacity) { + super(MathHelper.smallestEncompassingPowerOfTwo(capacity), 16); + + this.capacity = capacity; + } + + public static ChunkDrawCallBatcher create(int capacity) { + return SodiumClientMod.isDirectMemoryAccessEnabled() ? new UnsafeChunkDrawCallBatcher(capacity) : new NioChunkDrawCallBatcher(capacity); + } + + public void begin() { + this.isBuilding = true; + this.count = 0; + this.arrayLength = 0; + + this.buffer.limit(this.buffer.capacity()); + } + + public void end() { + this.isBuilding = false; + + this.arrayLength = this.count * this.stride; + this.buffer.limit(this.arrayLength); + this.buffer.position(0); + } + + public boolean isBuilding() { + return this.isBuilding; + } + + public abstract void addIndirectDrawCall(int first, int count, int baseInstance, int instanceCount); + + public int getCount() { + return this.count; + } + + public boolean isEmpty() { + return this.count <= 0; + } + + public static class UnsafeChunkDrawCallBatcher extends ChunkDrawCallBatcher { + + private final long basePointer; + private long writePointer; + + public UnsafeChunkDrawCallBatcher(int capacity) { + super(capacity); + + this.basePointer = MemoryUtil.memAddress(this.buffer); + } + + @Override + public void begin() { + super.begin(); + + this.writePointer = this.basePointer; + } + + @Override + public void addIndirectDrawCall(int first, int count, int baseInstance, int instanceCount) { + if (this.count++ >= this.capacity) { + throw new BufferUnderflowException(); + } + + MemoryUtil.memPutInt(this.writePointer , count); // Vertex Count + MemoryUtil.memPutInt(this.writePointer + 4, instanceCount); // Instance Count + MemoryUtil.memPutInt(this.writePointer + 8, first); // Vertex Start + MemoryUtil.memPutInt(this.writePointer + 12, baseInstance); // Base Instance + + this.writePointer += this.stride; + } + } + + public static class NioChunkDrawCallBatcher extends ChunkDrawCallBatcher { + private int writeOffset; + + public NioChunkDrawCallBatcher(int capacity) { + super(capacity); + } + + @Override + public void begin() { + super.begin(); + + this.writeOffset = 0; + } + + @Override + public void addIndirectDrawCall(int first, int count, int baseInstance, int instanceCount) { + ByteBuffer buf = this.buffer; + buf.putInt(this.writeOffset , count); // Vertex Count + buf.putInt(this.writeOffset + 4, instanceCount); // Instance Count + buf.putInt(this.writeOffset + 8, first); // Vertex Start + buf.putInt(this.writeOffset + 12, baseInstance); // Base Instance + + this.writeOffset += this.stride; + this.count++; + } + } + + public int getArrayLength() { + return this.arrayLength; + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java new file mode 100644 index 000000000..03e17f304 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java @@ -0,0 +1,106 @@ +package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; + +/** + * Provides a resizeable vector backed by native memory that can be used to build an array of chunk draw call + * parameters. + */ +public abstract class ChunkDrawParamsVector extends StructBuffer { + protected int capacity; + protected int count; + + protected ChunkDrawParamsVector(int capacity) { + super(capacity, 16); + + this.capacity = capacity; + } + + public static ChunkDrawParamsVector create(int capacity) { + return SodiumClientMod.isDirectMemoryAccessEnabled() ? new UnsafeChunkDrawCallVector(capacity) : new NioChunkDrawCallVector(capacity); + } + + public abstract void pushChunkDrawParams(float x, float y, float z); + + public void reset() { + this.count = 0; + } + + protected void growBuffer() { + this.capacity = this.capacity * 2; + this.buffer = MemoryUtil.memRealloc(this.buffer, this.capacity * this.stride); + } + + public static class UnsafeChunkDrawCallVector extends ChunkDrawParamsVector { + private long basePointer; + private long writePointer; + + public UnsafeChunkDrawCallVector(int capacity) { + super(capacity); + + this.basePointer = MemoryUtil.memAddress(this.buffer); + } + + @Override + public void pushChunkDrawParams(float x, float y, float z) { + if (this.count++ >= this.capacity) { + this.growBuffer(); + } + + MemoryUtil.memPutFloat(this.writePointer , x); + MemoryUtil.memPutFloat(this.writePointer + 4, y); + MemoryUtil.memPutFloat(this.writePointer + 8, z); + + this.writePointer += this.stride; + } + + @Override + protected void growBuffer() { + super.growBuffer(); + + long offset = this.writePointer - this.basePointer; + + this.basePointer = MemoryUtil.memAddress(this.buffer); + this.writePointer = this.basePointer + offset; + } + + @Override + public void reset() { + super.reset(); + + this.writePointer = this.basePointer; + } + } + + public static class NioChunkDrawCallVector extends ChunkDrawParamsVector { + private int writeOffset; + + public NioChunkDrawCallVector(int capacity) { + super(capacity); + } + + @Override + public void pushChunkDrawParams(float x, float y, float z) { + if (this.count++ >= this.capacity) { + this.growBuffer(); + } + + ByteBuffer buf = this.buffer; + buf.putFloat(this.writeOffset , x); + buf.putFloat(this.writeOffset + 4, y); + buf.putFloat(this.writeOffset + 8, z); + + this.writeOffset += this.stride; + } + + @Override + public void reset() { + super.reset(); + + this.writeOffset = 0; + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java new file mode 100644 index 000000000..e1b4a4fa5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java @@ -0,0 +1,35 @@ +package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; + +import org.lwjgl.system.MemoryUtil; + +public class IndirectCommandBufferVector extends StructBuffer { + protected IndirectCommandBufferVector(int capacity) { + super(capacity, 16); + } + + public static IndirectCommandBufferVector create(int capacity) { + return new IndirectCommandBufferVector(capacity); + } + + public void begin() { + this.buffer.clear(); + } + + public void end() { + this.buffer.flip(); + } + + public void pushCommandBuffer(ChunkDrawCallBatcher batcher) { + int len = batcher.getArrayLength(); + + if (this.buffer.remaining() < len) { + this.growBuffer(len); + } + + this.buffer.put(batcher.getBuffer()); + } + + protected void growBuffer(int n) { + this.buffer = MemoryUtil.memRealloc(this.buffer, Math.max(this.buffer.capacity() * 2, this.buffer.capacity() + n)); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java new file mode 100644 index 000000000..1b78d8913 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java @@ -0,0 +1,454 @@ +package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; + +import com.mojang.blaze3d.platform.GlStateManager; +import it.unimi.dsi.fastutil.objects.ObjectArrayFIFOQueue; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import me.jellysquid.mods.sodium.client.gl.arena.GlBufferArena; +import me.jellysquid.mods.sodium.client.gl.arena.GlBufferSegment; +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttribute; +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferUsage; +import me.jellysquid.mods.sodium.client.gl.buffer.GlMutableBuffer; +import me.jellysquid.mods.sodium.client.gl.buffer.VertexData; +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import me.jellysquid.mods.sodium.client.gl.device.DrawCommandList; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gl.func.GlFunctions; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlPrimitiveType; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; +import me.jellysquid.mods.sodium.client.gl.tessellation.TessellationBinding; +import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkCameraContext; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkMeshData; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; +import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterator; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.region.ChunkRegion; +import me.jellysquid.mods.sodium.client.render.chunk.region.ChunkRegionManager; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkRenderShaderBackend; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; +import net.minecraft.util.Formatting; +import net.minecraft.util.Util; +import org.lwjgl.opengl.GL20C; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Shader-based chunk renderer which makes use of a custom memory allocator on top of large buffer objects to allow + * for draw call batching without buffer switching. + * + * The biggest bottleneck after setting up vertex attribute state is the sheer number of buffer switches and draw calls + * being performed. In vanilla, the game uses one buffer for every chunk section, which means we need to bind, setup, + * and draw every chunk individually. + * + * In order to reduce the number of these calls, we need to firstly reduce the number of buffer switches. We do this + * through sub-dividing the world into larger "chunk regions" which then have one large buffer object in OpenGL. From + * here, we can allocate slices of this buffer to each individual chunk and then only bind it once before drawing. Then, + * our draw calls can simply point to individual sections within the buffer by manipulating the offset and count + * parameters. + * + * However, an unfortunate consequence is that if we run out of space in a buffer, we need to re-allocate the entire + * storage, which can take a ton of time! With old OpenGL 2.1 code, the only way to do this would be to copy the buffer's + * memory from the graphics card over the host bus into CPU memory, allocate a new buffer, and then copy it back over + * the bus and into graphics card. For reasons that should be obvious, this is extremely inefficient and requires the + * CPU and GPU to be synchronized. + * + * If we make use of more modern OpenGL 3.0 features, we can avoid this transfer over the memory bus and instead just + * perform the copy between buffers in GPU memory with the aptly named "copy buffer" function. It's still not blazing + * fast, but it's much better than what we're stuck with in older versions. We can help prevent these re-allocations by + * sizing our buffers to be a bit larger than what we expect all the chunk data to be, but this wastes memory. + * + * In the initial implementation, this solution worked fine enough, but the amount of time being spent on uploading + * chunks to the large buffers was now a magnitude more than what it was before all of this and it made chunk updates + * *very* slow. It took some tinkering to figure out what was going wrong here, but at least on the NVIDIA drivers, it + * seems that updating sub-regions of buffer memory hits some kind of slow path. A workaround for this problem is to + * create a scratch buffer object and upload the chunk data there *first*, re-allocating the storage each time. Then, + * you can copy the contents of the scratch buffer into the chunk region buffer, rise and repeat. I'm not happy with + * this solution, but it performs surprisingly well across all hardware I tried. + * + * With both of these changes, the amount of CPU time taken by rendering chunks linearly decreases with the reduction + * in buffer bind/setup/draw calls. Using the default settings of 4x2x4 chunk region buffers, the number of calls can be + * reduced up to a factor of ~32x. + */ +public class MultidrawChunkRenderBackend extends ChunkRenderShaderBackend { + private final ChunkRegionManager bufferManager; + + private final ObjectArrayList> pendingBatches = new ObjectArrayList<>(); + private final ObjectArrayFIFOQueue> pendingUploads = new ObjectArrayFIFOQueue<>(); + + private final GlMutableBuffer uploadBuffer; + private final GlMutableBuffer uniformBuffer; + private final GlMutableBuffer commandBuffer; + + private final ChunkDrawParamsVector uniformBufferBuilder; + private final IndirectCommandBufferVector commandClientBufferBuilder; + + public MultidrawChunkRenderBackend(RenderDevice device, ChunkVertexType vertexType) { + super(vertexType); + + this.bufferManager = new ChunkRegionManager<>(device); + + try (CommandList commands = device.createCommandList()) { + this.uploadBuffer = commands.createMutableBuffer(GlBufferUsage.GL_STREAM_DRAW); + this.uniformBuffer = commands.createMutableBuffer(GlBufferUsage.GL_STATIC_DRAW); + this.commandBuffer = isWindowsIntelDriver() ? null : commands.createMutableBuffer(GlBufferUsage.GL_STREAM_DRAW); + } + + this.uniformBufferBuilder = ChunkDrawParamsVector.create(2048); + this.commandClientBufferBuilder = IndirectCommandBufferVector.create(2048); + } + + @Override + public void upload(CommandList commandList, Iterator> queue) { + if(queue != null) { + this.setupUploadBatches(queue); + } + + commandList.bindBuffer(GlBufferTarget.ARRAY_BUFFER, this.uploadBuffer); + + while (!this.pendingUploads.isEmpty()) { + ChunkRegion region = this.pendingUploads.dequeue(); + + GlBufferArena arena = region.getBufferArena(); + GlBuffer buffer = arena.getBuffer(); + + ObjectArrayList> uploadQueue = region.getUploadQueue(); + arena.prepareBuffer(commandList, getUploadQueuePayloadSize(uploadQueue)); + + for (ChunkBuildResult result : uploadQueue) { + ChunkRenderContainer render = result.render; + ChunkRenderData data = result.data; + + for (BlockRenderPass pass : result.passesToUpload) { + MultidrawGraphicsState graphics = render.getGraphicsState(pass); + + // De-allocate the existing buffer arena for this render + // This will allow it to be cheaply re-allocated just below + if (graphics != null) { + graphics.delete(commandList); + } + + ChunkMeshData meshData = data.getMesh(pass); + + if (meshData.hasVertexData()) { + VertexData upload = meshData.takeVertexData(); + + commandList.uploadData(this.uploadBuffer, upload.buffer); + + GlBufferSegment segment = arena.uploadBuffer(commandList, this.uploadBuffer, 0, upload.buffer.capacity()); + + MultidrawGraphicsState graphicsState = new MultidrawGraphicsState(render, region, segment, meshData, this.vertexFormat); + if(pass.isTranslucent()) { + upload.buffer.limit(upload.buffer.capacity()); + upload.buffer.position(0); + + graphicsState.setTranslucencyData(upload.buffer); + } + render.setGraphicsState(pass, graphicsState); + } else { + render.setGraphicsState(pass, null); + } + } + + render.setData(data); + } + + // Check if the tessellation needs to be updated + // This happens whenever the backing buffer object for the arena changes, or if it hasn't already been created + if (region.getTessellation() == null || buffer != arena.getBuffer()) { + if (region.getTessellation() != null) { + commandList.deleteTessellation(region.getTessellation()); + } + + region.setTessellation(this.createRegionTessellation(commandList, arena.getBuffer())); + } + + uploadQueue.clear(); + } + + commandList.invalidateBuffer(this.uploadBuffer); + } + + private GlTessellation createRegionTessellation(CommandList commandList, GlBuffer buffer) { + return commandList.createTessellation(GlPrimitiveType.QUADS, new TessellationBinding[] { + new TessellationBinding(buffer, new GlVertexAttributeBinding[] { + new GlVertexAttributeBinding(ChunkShaderBindingPoints.POSITION, + this.vertexFormat.getAttribute(ChunkMeshAttribute.POSITION)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.COLOR, + this.vertexFormat.getAttribute(ChunkMeshAttribute.COLOR)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.TEX_COORD, + this.vertexFormat.getAttribute(ChunkMeshAttribute.TEXTURE)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.LIGHT_COORD, + this.vertexFormat.getAttribute(ChunkMeshAttribute.LIGHT)) + }, false), + new TessellationBinding(this.uniformBuffer, new GlVertexAttributeBinding[] { + new GlVertexAttributeBinding(ChunkShaderBindingPoints.MODEL_OFFSET, + new GlVertexAttribute(GlVertexAttributeFormat.FLOAT, 4, false, 0, 0)) + }, true) + }); + } + + private boolean reverseRegions = false; + private ChunkCameraContext regionCamera; + + /** + * Sets whether to reverse the order in which regions are drawn (fixes + */ + public void setReverseRegions(boolean flag) { + this.reverseRegions = flag; + } + + @Override + public void render(CommandList commandList, ChunkRenderListIterator renders, ChunkCameraContext camera) { + this.bufferManager.cleanup(); + + this.setupDrawBatches(commandList, renders, camera); + this.buildCommandBuffer(); + + if (this.commandBuffer != null) { + commandList.bindBuffer(GlBufferTarget.DRAW_INDIRECT_BUFFER, this.commandBuffer); + commandList.uploadData(this.commandBuffer, this.commandClientBufferBuilder.getBuffer()); + } + + long pointer = this.commandBuffer == null ? this.commandClientBufferBuilder.getBufferAddress() : 0L; + + for (ChunkRegion region : this.pendingBatches) { + ChunkDrawCallBatcher batch = region.getDrawBatcher(); + + if (!batch.isEmpty()) { + try (DrawCommandList drawCommandList = commandList.beginTessellating(region.getTessellation())) { + drawCommandList.multiDrawArraysIndirect(pointer, batch.getCount(), 0 /* tightly packed */); + } + } + + pointer += batch.getArrayLength(); + } + + this.pendingBatches.clear(); + } + + private static final Comparator> REGION_REVERSER = Comparator.>comparingDouble(r -> r.camDistance).reversed(); + + private void buildCommandBuffer() { + this.commandClientBufferBuilder.begin(); + + if(this.reverseRegions) { + ChunkCameraContext camera = this.regionCamera; + for (ChunkRegion region : this.pendingBatches) { + float x = camera.getChunkModelOffset(region.x * 16, camera.blockOriginX, camera.originX); + float y = camera.getChunkModelOffset(region.y * 16, camera.blockOriginY, camera.originY); + float z = camera.getChunkModelOffset(region.z * 16, camera.blockOriginZ, camera.originZ); + region.camDistance = x * x + y * y + z * z; + } + + this.pendingBatches.sort(REGION_REVERSER); + } + + for (ChunkRegion region : this.pendingBatches) { + ChunkDrawCallBatcher batcher = region.getDrawBatcher(); + batcher.end(); + + this.commandClientBufferBuilder.pushCommandBuffer(batcher); + } + + this.commandClientBufferBuilder.end(); + } + + private void setupUploadBatches(Iterator> renders) { + while (renders.hasNext()) { + ChunkBuildResult result = renders.next(); + + if(result == null) { + continue; + } + + ChunkRenderContainer render = result.render; + + ChunkRegion region = this.bufferManager.getRegion(render.getChunkX(), render.getChunkY(), render.getChunkZ()); + + if (region == null) { + if (result.data.getMeshSize() <= 0) { + render.setData(result.data); + continue; + } + + region = this.bufferManager.getOrCreateRegion(render.getChunkX(), render.getChunkY(), render.getChunkZ()); + } + + ObjectArrayList> uploadQueue = region.getUploadQueue(); + + if (uploadQueue.isEmpty()) { + this.pendingUploads.enqueue(region); + } + + uploadQueue.add(result); + } + } + + private void setupDrawBatches(CommandList commandList, ChunkRenderListIterator it, ChunkCameraContext camera) { + this.uniformBufferBuilder.reset(); + this.regionCamera = camera; + + int drawCount = 0; + + while (it.hasNext()) { + MultidrawGraphicsState state = it.getGraphicsState(); + int visible = it.getVisibleFaces(); + + int index = drawCount++; + float x = camera.getChunkModelOffset(state.getX(), camera.blockOriginX, camera.originX); + float y = camera.getChunkModelOffset(state.getY(), camera.blockOriginY, camera.originY); + float z = camera.getChunkModelOffset(state.getZ(), camera.blockOriginZ, camera.originZ); + + this.uniformBufferBuilder.pushChunkDrawParams(x, y, z); + + ChunkRegion region = state.getRegion(); + ChunkDrawCallBatcher batch = region.getDrawBatcher(); + + if (!batch.isBuilding()) { + batch.begin(); + + this.pendingBatches.add(region); + } + + int mask = 0b1; + + for (int i = 0; i < ModelQuadFacing.COUNT; i++) { + if ((visible & mask) != 0) { + long part = state.getModelPart(i); + + batch.addIndirectDrawCall(BufferSlice.unpackStart(part), BufferSlice.unpackLength(part), index, 1); + } + + mask <<= 1; + } + + it.advance(); + } + + commandList.uploadData(this.uniformBuffer, this.uniformBufferBuilder.getBuffer()); + } + + private static int getUploadQueuePayloadSize(List> queue) { + int size = 0; + + for (ChunkBuildResult result : queue) { + size += result.data.getMeshSize(); + } + + return size; + } + + @Override + public void delete() { + super.delete(); + + try (CommandList commands = RenderDevice.INSTANCE.createCommandList()) { + commands.deleteBuffer(this.uploadBuffer); + commands.deleteBuffer(this.uniformBuffer); + + if (this.commandBuffer != null) { + commands.deleteBuffer(this.commandBuffer); + } + } + + this.bufferManager.delete(); + + this.commandClientBufferBuilder.delete(); + this.uniformBufferBuilder.delete(); + } + + @Override + public Class getGraphicsStateType() { + return MultidrawGraphicsState.class; + } + + public static boolean isSupported(boolean disableDriverBlacklist) { + if (!disableDriverBlacklist && isKnownBrokenIntelDriver()) { + return false; + } + + return GlFunctions.isVertexArraySupported() && + GlFunctions.isBufferCopySupported() && + GlFunctions.isIndirectMultiDrawSupported() && + GlFunctions.isInstancedArraySupported(); + } + + // https://www.intel.com/content/www/us/en/support/articles/000005654/graphics.html + private static final Pattern INTEL_BUILD_MATCHER = Pattern.compile("(\\d.\\d.\\d) - Build (\\d+).(\\d+).(\\d+).(\\d+)"); + + private static final String INTEL_VENDOR_NAME = "Intel"; + + /** + * Determines whether or not the current OpenGL renderer is an integrated Intel GPU on Windows. + * These drivers on Windows are known to fail when using command buffers. + */ + private static boolean isWindowsIntelDriver() { + // We only care about Windows + // The open-source drivers on Linux are not known to have driver bugs with indirect command buffers + if (Util.getOperatingSystem() != Util.OperatingSystem.WINDOWS) { + return false; + } + + // Check to see if the GPU vendor is Intel + return Objects.equals(GlStateManager.getString(GL20C.GL_VENDOR), INTEL_VENDOR_NAME); + } + + /** + * Determines whether or not the current OpenGL renderer is an old integrated Intel GPU (prior to Skylake/Gen8) on + * Windows. These drivers on Windows are unsupported and known to create significant trouble with the multi-draw + * renderer. + */ + private static boolean isKnownBrokenIntelDriver() { + if (!isWindowsIntelDriver()) { + return false; + } + + String version = GlStateManager.getString(GL20C.GL_VERSION); + + // The returned version string may be null in the case of an error + if (version == null) { + return false; + } + + Matcher matcher = INTEL_BUILD_MATCHER.matcher(version); + + // If the version pattern doesn't match, assume we're dealing with something special + if (!matcher.matches()) { + return false; + } + + // Anything with a major build of >=100 is GPU Gen8 or newer + // The fourth group is the major build number + return Integer.parseInt(matcher.group(4)) < 100; + } + + @Override + public String getRendererName() { + return "Multidraw"; + } + + @Override + public List getDebugStrings() { + List list = new ArrayList<>(); + list.add(String.format("Active Buffers: %s", this.bufferManager.getAllocatedRegionCount())); + list.add(String.format("Submission Mode: %s", this.commandBuffer != null ? + Formatting.AQUA + "Buffer" : Formatting.LIGHT_PURPLE + "Client Memory")); + + return list; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawGraphicsState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawGraphicsState.java new file mode 100644 index 000000000..e4ebbdb2c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawGraphicsState.java @@ -0,0 +1,53 @@ +package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; + +import me.jellysquid.mods.sodium.client.gl.arena.GlBufferSegment; +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +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.data.ChunkMeshData; +import me.jellysquid.mods.sodium.client.render.chunk.region.ChunkRegion; + +import java.util.Map; + +public class MultidrawGraphicsState extends ChunkGraphicsState { + private final ChunkRegion region; + + private final GlBufferSegment segment; + private final long[] parts; + + public MultidrawGraphicsState(ChunkRenderContainer container, ChunkRegion region, GlBufferSegment segment, ChunkMeshData meshData, GlVertexFormat vertexFormat) { + super(container); + + this.region = region; + this.segment = segment; + + this.parts = new long[ModelQuadFacing.COUNT]; + + for (Map.Entry entry : meshData.getSlices()) { + ModelQuadFacing facing = entry.getKey(); + BufferSlice slice = entry.getValue(); + + int start = (segment.getStart() + slice.start) / vertexFormat.getStride(); + int count = slice.len / vertexFormat.getStride(); + + this.parts[facing.ordinal()] = BufferSlice.pack(start, count); + } + } + + @Override + public void delete(CommandList commandList) { + this.segment.delete(); + } + + public ChunkRegion getRegion() { + return this.region; + } + + public long getModelPart(int facing) { + return this.parts[facing]; + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java new file mode 100644 index 000000000..a0c84f711 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java @@ -0,0 +1,29 @@ +package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; + +import me.jellysquid.mods.sodium.client.gl.util.MemoryUtilHelper; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; + +public abstract class StructBuffer { + protected ByteBuffer buffer; + + protected final int stride; + + protected StructBuffer(int bytes, int stride) { + this.buffer = MemoryUtil.memAlloc(bytes * stride); + this.stride = stride; + } + + public ByteBuffer getBuffer() { + return this.buffer; + } + + public void delete() { + MemoryUtilHelper.memFree(this.buffer); + } + + public long getBufferAddress() { + return MemoryUtil.memAddress(this.buffer); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkOneshotGraphicsState.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkOneshotGraphicsState.java new file mode 100644 index 000000000..7501aedd8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkOneshotGraphicsState.java @@ -0,0 +1,89 @@ +package me.jellysquid.mods.sodium.client.render.chunk.backends.oneshot; + +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; +import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferUsage; +import me.jellysquid.mods.sodium.client.gl.buffer.GlMutableBuffer; +import me.jellysquid.mods.sodium.client.gl.buffer.VertexData; +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlPrimitiveType; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; +import me.jellysquid.mods.sodium.client.gl.tessellation.TessellationBinding; +import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +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.data.ChunkMeshData; +import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; + +import java.util.Arrays; +import java.util.Map; + +public class ChunkOneshotGraphicsState extends ChunkGraphicsState { + private final GlMutableBuffer vertexBuffer; + + protected GlTessellation tessellation; + + private final long[] parts; + + protected ChunkOneshotGraphicsState(RenderDevice device, ChunkRenderContainer container) { + super(container); + + this.parts = new long[ModelQuadFacing.COUNT]; + + try (CommandList commands = device.createCommandList()) { + this.vertexBuffer = commands.createMutableBuffer(GlBufferUsage.GL_STATIC_DRAW); + } + } + + public long getModelPart(int facing) { + return this.parts[facing]; + } + + protected void setModelPart(ModelQuadFacing facing, long slice) { + this.parts[facing.ordinal()] = slice; + } + + protected void setupModelParts(ChunkMeshData meshData, GlVertexFormat vertexFormat) { + int stride = vertexFormat.getStride(); + + Arrays.fill(this.parts, 0L); + + for (Map.Entry entry : meshData.getSlices()) { + ModelQuadFacing facing = entry.getKey(); + BufferSlice slice = entry.getValue(); + + this.setModelPart(facing, BufferSlice.pack(slice.start / stride, slice.len / stride)); + } + } + + @Override + public void delete(CommandList commandList) { + commandList.deleteBuffer(this.vertexBuffer); + } + + public void upload(CommandList commandList, ChunkMeshData meshData) { + VertexData vertexData = meshData.takeVertexData(); + + commandList.uploadData(this.vertexBuffer, vertexData); + + GlVertexFormat vertexFormat = (GlVertexFormat) vertexData.format; + + this.tessellation = commandList.createTessellation(GlPrimitiveType.QUADS, new TessellationBinding[] { + new TessellationBinding(this.vertexBuffer, new GlVertexAttributeBinding[] { + new GlVertexAttributeBinding(ChunkShaderBindingPoints.POSITION, vertexFormat.getAttribute(ChunkMeshAttribute.POSITION)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.COLOR, vertexFormat.getAttribute(ChunkMeshAttribute.COLOR)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.TEX_COORD, vertexFormat.getAttribute(ChunkMeshAttribute.TEXTURE)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.LIGHT_COORD, vertexFormat.getAttribute(ChunkMeshAttribute.LIGHT)) + }, false) + }); + + this.setupModelParts(meshData, vertexData.format); + + vertexData.buffer.limit(vertexData.buffer.capacity()); + vertexData.buffer.position(0); + this.setTranslucencyData(vertexData.buffer); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkRenderBackendOneshot.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkRenderBackendOneshot.java new file mode 100644 index 000000000..1d94bee1a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkRenderBackendOneshot.java @@ -0,0 +1,142 @@ +package me.jellysquid.mods.sodium.client.render.chunk.backends.oneshot; + +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import me.jellysquid.mods.sodium.client.gl.device.DrawCommandList; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; +import me.jellysquid.mods.sodium.client.gl.util.GlMultiDrawBatch; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkCameraContext; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkMeshData; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterator; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkRenderShaderBackend; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; +import org.lwjgl.opengl.GL20C; +import org.lwjgl.system.MemoryStack; + +import java.nio.FloatBuffer; +import java.util.Iterator; + +public class ChunkRenderBackendOneshot extends ChunkRenderShaderBackend { + private final GlMultiDrawBatch batch = new GlMultiDrawBatch(ModelQuadFacing.COUNT); + + public ChunkRenderBackendOneshot(ChunkVertexType vertexType) { + super(vertexType); + } + + @Override + public void upload(CommandList commandList, Iterator> queue) { + while (queue.hasNext()) { + ChunkBuildResult result = queue.next(); + + ChunkRenderContainer render = result.render; + ChunkRenderData data = result.data; + + for (BlockRenderPass pass : result.passesToUpload) { + ChunkOneshotGraphicsState state = render.getGraphicsState(pass); + ChunkMeshData mesh = data.getMesh(pass); + + if (mesh.hasVertexData()) { + if (state == null) { + state = new ChunkOneshotGraphicsState(RenderDevice.INSTANCE, render); + } + + state.upload(commandList, mesh); + // For code simplicity, ChunkOneshotGraphicsState stores the buffer unconditionally + // Reset it here if the pass isn't translucent, as we don't want to store useless + // buffers + if(!pass.isTranslucent()) + state.setTranslucencyData(null); + } else { + if (state != null) { + state.delete(commandList); + } + + state = null; + } + + render.setGraphicsState(pass, state); + } + + render.setData(data); + } + } + + @Override + public void render(CommandList commandList, ChunkRenderListIterator it, ChunkCameraContext camera) { + while (it.hasNext()) { + ChunkOneshotGraphicsState state = it.getGraphicsState(); + int visibleFaces = it.getVisibleFaces(); + + this.buildBatch(state, visibleFaces); + + if (this.batch.isBuilding()) { + this.prepareDrawBatch(camera, state); + this.drawBatch(commandList, state); + } + + it.advance(); + } + } + + protected void prepareDrawBatch(ChunkCameraContext camera, ChunkOneshotGraphicsState state) { + float modelX = camera.getChunkModelOffset(state.getX(), camera.blockOriginX, camera.originX); + float modelY = camera.getChunkModelOffset(state.getY(), camera.blockOriginY, camera.originY); + float modelZ = camera.getChunkModelOffset(state.getZ(), camera.blockOriginZ, camera.originZ); + + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer fb = stack.mallocFloat(4); + fb.put(0, modelX); + fb.put(1, modelY); + fb.put(2, modelZ); + + GL20C.glVertexAttrib4fv(ChunkShaderBindingPoints.MODEL_OFFSET.getGenericAttributeIndex(), fb); + } + } + + protected void buildBatch(ChunkOneshotGraphicsState state, int visibleFaces) { + GlMultiDrawBatch batch = this.batch; + batch.begin(); + + for (int i = 0; i < ModelQuadFacing.COUNT; i++) { + if ((visibleFaces & (1 << i)) == 0) { + continue; + } + + long part = state.getModelPart(i); + batch.addChunkRender(BufferSlice.unpackStart(part), BufferSlice.unpackLength(part)); + } + } + + protected void drawBatch(CommandList commandList, ChunkOneshotGraphicsState state) { + this.batch.end(); + + if (!batch.isEmpty()) { + try (DrawCommandList drawCommandList = commandList.beginTessellating(state.tessellation)) { + drawCommandList.multiDrawArrays(this.batch.getIndicesBuffer(), this.batch.getLengthBuffer()); + } + } + } + + @Override + public void delete() { + super.delete(); + + this.batch.delete(); + } + + @Override + public Class getGraphicsStateType() { + return ChunkOneshotGraphicsState.class; + } + + @Override + public String getRendererName() { + return "Oneshot"; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBufferSorter.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBufferSorter.java new file mode 100644 index 000000000..3a1e4615c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBufferSorter.java @@ -0,0 +1,187 @@ +package me.jellysquid.mods.sodium.client.render.chunk.compile; + +import com.google.common.primitives.Floats; +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 org.lwjgl.system.MemoryStack; + +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; +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) { + isCompact = true; + } else if(vertexType.getClass() == SFPModelVertexType.class) { + isCompact = false; + } else + return; // ignore unsupported vertex types to avoid corruption + + // Quad stride by Float size + int quadStride = vertexType.getBufferVertexFormat().getStride(); + + int quadStart = ((Buffer)buffer).position(); + int quadCount = bufferLen/quadStride/4; + + float[] distanceArray = new float[quadCount]; + int[] indicesArray = new int[quadCount]; + + if(isCompact) { + ShortBuffer shortBuffer = buffer.asShortBuffer(); + int vertexSizeShort = quadStride / 2; + for (int quadIdx = 0; quadIdx < quadCount; ++quadIdx) { + distanceArray[quadIdx] = getDistanceSqHFP(shortBuffer, x, y, z, vertexSizeShort, quadStart + (quadIdx * quadStride * 2)); + indicesArray[quadIdx] = quadIdx; + } + } else { + FloatBuffer floatBuffer = buffer.asFloatBuffer(); + int vertexSizeInteger = quadStride / 4; + for (int quadIdx = 0; quadIdx < quadCount; ++quadIdx) { + distanceArray[quadIdx] = getDistanceSqSFP(floatBuffer, x, y, z, vertexSizeInteger, quadStart + (quadIdx * quadStride)); + indicesArray[quadIdx] = quadIdx; + } + } + + IntArrays.mergeSort(indicesArray, (a, b) -> Floats.compare(distanceArray[b], distanceArray[a])); + + rearrangeQuads(buffer, indicesArray, quadStride, quadStart); + } + + private static void rearrangeQuads(ByteBuffer quadBuffer, int[] indicesArray, int quadStride, int quadStart) { + FloatBuffer floatBuffer = quadBuffer.asFloatBuffer(); + BitSet bits = new BitSet(); + + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer tmp = stack.mallocFloat(quadStride); + + for (int l = bits.nextClearBit(0); l < indicesArray.length; l = bits.nextClearBit(l + 1)) { + int m = indicesArray[l]; + + if (m != l) { + sliceQuad(floatBuffer, m, quadStride, quadStart); + ((Buffer)tmp).clear(); + tmp.put(floatBuffer); + + int n = m; + + for (int o = indicesArray[m]; n != l; o = indicesArray[o]) { + sliceQuad(floatBuffer, o, quadStride, quadStart); + FloatBuffer floatBuffer3 = floatBuffer.slice(); + + sliceQuad(floatBuffer, n, quadStride, quadStart); + floatBuffer.put(floatBuffer3); + + bits.set(n); + n = o; + } + + sliceQuad(floatBuffer, l, quadStride, quadStart); + ((Buffer)tmp).flip(); + + floatBuffer.put(tmp); + } + + bits.set(l); + } + } + } + + private static void sliceQuad(FloatBuffer floatBuffer, int quadIdx, int quadStride, int quadStart) { + int base = quadStart + (quadIdx * quadStride); + + ((Buffer)floatBuffer).limit(base + quadStride); + ((Buffer)floatBuffer).position(base); + } + + private static float getDistanceSqSFP(FloatBuffer buffer, float xCenter, float yCenter, float zCenter, int stride, int start) { + int vertexBase = start; + float x1 = buffer.get(vertexBase); + float y1 = buffer.get(vertexBase + 1); + float z1 = buffer.get(vertexBase + 2); + + //System.out.println("camera: " + xCenter + "," + yCenter + "," + zCenter); + //System.out.println("buffer1: " + x1 + "," + y1 + "," + z1); + + vertexBase += stride; + float x2 = buffer.get(vertexBase); + float y2 = buffer.get(vertexBase + 1); + float z2 = buffer.get(vertexBase + 2); + //System.out.println("buffer2: " + x2 + "," + y2 + "," + z2); + + vertexBase += stride; + float x3 = buffer.get(vertexBase); + float y3 = buffer.get(vertexBase + 1); + float z3 = buffer.get(vertexBase + 2); + //System.out.println("buffer3: " + x3 + "," + y3 + "," + z3); + + vertexBase += stride; + float x4 = buffer.get(vertexBase); + float y4 = buffer.get(vertexBase + 1); + float z4 = buffer.get(vertexBase + 2); + //System.out.println("buffer4: " + x4 + "," + y4 + "," + z4); + + float xDist = ((x1 + x2 + x3 + x4) * 0.25F) - xCenter; + float yDist = ((y1 + y2 + y3 + y4) * 0.25F) - yCenter; + float zDist = ((z1 + z2 + z3 + z4) * 0.25F) - zCenter; + + return (xDist * xDist) + (yDist * yDist) + (zDist * zDist); + } + + private static float normalizeShort(short s) { + return (float)Short.toUnsignedInt(s) / 2048.0f; + } + + private static float getDistanceSqHFP(ShortBuffer buffer, float xCenter, float yCenter, float zCenter, int stride, int start) { + int vertexBase = start; + float x1 = normalizeShort(buffer.get(vertexBase)); + float y1 = normalizeShort(buffer.get(vertexBase + 1)); + float z1 = normalizeShort(buffer.get(vertexBase + 2)); + + //System.out.println("camera: " + xCenter + "," + yCenter + "," + zCenter); + //System.out.println("buffer1: " + x1 + "," + y1 + "," + z1); + + vertexBase += stride; + float x2 = normalizeShort(buffer.get(vertexBase)); + float y2 = normalizeShort(buffer.get(vertexBase + 1)); + float z2 = normalizeShort(buffer.get(vertexBase + 2)); + //System.out.println("buffer2: " + x2 + "," + y2 + "," + z2); + + vertexBase += stride; + float x3 = normalizeShort(buffer.get(vertexBase)); + float y3 = normalizeShort(buffer.get(vertexBase + 1)); + float z3 = normalizeShort(buffer.get(vertexBase + 2)); + //System.out.println("buffer3: " + x3 + "," + y3 + "," + z3); + + vertexBase += stride; + float x4 = normalizeShort(buffer.get(vertexBase)); + float y4 = normalizeShort(buffer.get(vertexBase + 1)); + float z4 = normalizeShort(buffer.get(vertexBase + 2)); + //System.out.println("buffer4: " + x4 + "," + y4 + "," + z4); + + float xDist = ((x1 + x2 + x3 + x4) * 0.25F) - xCenter; + float yDist = ((y1 + y2 + y3 + y4) * 0.25F) - yCenter; + float zDist = ((z1 + z2 + z3 + z4) * 0.25F) - zCenter; + + return (xDist * xDist) + (yDist * yDist) + (zDist * zDist); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java new file mode 100644 index 000000000..47aaf0241 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java @@ -0,0 +1,133 @@ +package me.jellysquid.mods.sodium.client.render.chunk.compile; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gl.buffer.VertexData; +import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferBuilder; +import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; +import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.BakedChunkModelBuffers; +import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; +import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelVertexTransformer; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkMeshData; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkModelOffset; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPassManager; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.util.GlAllocationUtils; + +import java.nio.ByteBuffer; +import java.util.Map; + +/** + * A collection of temporary buffers for each worker thread which will be used to build chunk meshes for given render + * passes. This makes a best-effort attempt to pick a suitable size for each scratch buffer, but will never try to + * shrink a buffer. + */ +public class ChunkBuildBuffers { + private final ChunkModelBuffers[] delegates; + private final VertexBufferBuilder[][] buffersByLayer; + private final ChunkVertexType vertexType; + + private final BlockRenderPassManager renderPassManager; + private final ChunkModelOffset offset; + + public ChunkBuildBuffers(ChunkVertexType vertexType, BlockRenderPassManager renderPassManager) { + this.vertexType = vertexType; + this.renderPassManager = renderPassManager; + + this.delegates = new ChunkModelBuffers[BlockRenderPass.COUNT]; + this.buffersByLayer = new VertexBufferBuilder[BlockRenderPass.COUNT][ModelQuadFacing.COUNT]; + + this.offset = new ChunkModelOffset(); + + for (RenderLayer layer : RenderLayer.getBlockLayers()) { + int passId = this.renderPassManager.getRenderPassId(layer); + + VertexBufferBuilder[] buffers = this.buffersByLayer[passId]; + + for (ModelQuadFacing facing : ModelQuadFacing.VALUES) { + buffers[facing.ordinal()] = new VertexBufferBuilder(vertexType.getBufferVertexFormat(), layer.getExpectedBufferSize() / ModelQuadFacing.COUNT); + } + } + } + + public void init(ChunkRenderData.Builder renderData) { + for (int i = 0; i < this.buffersByLayer.length; i++) { + ChunkModelVertexTransformer[] writers = new ChunkModelVertexTransformer[ModelQuadFacing.COUNT]; + + for (ModelQuadFacing facing : ModelQuadFacing.VALUES) { + writers[facing.ordinal()] = new ChunkModelVertexTransformer(this.vertexType.createBufferWriter(this.buffersByLayer[i][facing.ordinal()], SodiumClientMod.isDirectMemoryAccessEnabled()), this.offset); + } + + this.delegates[i] = new BakedChunkModelBuffers(writers, renderData); + } + } + + /** + * Return the {@link ChunkModelVertexTransformer} for the given {@link RenderLayer} as mapped by the + * {@link BlockRenderPassManager} for this render context. + */ + public ChunkModelBuffers get(RenderLayer layer) { + return this.delegates[this.renderPassManager.getRenderPassId(layer)]; + } + + /** + * Creates immutable baked chunk meshes from all non-empty scratch buffers and resets the state of all mesh + * builders. This is used after all blocks have been rendered to pass the finished meshes over to the graphics card. + */ + public ChunkMeshData createMesh(BlockRenderPass pass, float x, float y, float z, boolean sortTranslucent) { + VertexBufferBuilder[] builders = this.buffersByLayer[pass.ordinal()]; + + ChunkMeshData meshData = new ChunkMeshData(); + int bufferLen = 0; + + for (int facingId = 0; facingId < builders.length; facingId++) { + VertexBufferBuilder builder = builders[facingId]; + + if (builder == null || builder.isEmpty()) { + continue; + } + + int start = bufferLen; + int size = builder.getSize(); + + meshData.setModelSlice(ModelQuadFacing.VALUES[facingId], new BufferSlice(start, size)); + + bufferLen += size; + } + + if (bufferLen <= 0) { + return null; + } + + ByteBuffer buffer = GlAllocationUtils.allocateByteBuffer(bufferLen); + + for (Map.Entry entry : meshData.getSlices()) { + BufferSlice slice = entry.getValue(); + buffer.position(slice.start); + + VertexBufferBuilder builder = this.buffersByLayer[pass.ordinal()][entry.getKey().ordinal()]; + builder.copyInto(buffer); + } + + buffer.flip(); + + if (sortTranslucent && pass.isTranslucent()) { + ChunkBufferSorter.sortStandardFormat(vertexType, buffer, bufferLen, x, y, z); + } + + meshData.setVertexData(new VertexData(buffer, this.vertexType.getCustomVertexFormat())); + + return meshData; + } + + public void setRenderOffset(int x, int y, int z) { + this.offset.set(x, y, z); + } + + public ChunkVertexType getVertexType() { + return this.vertexType; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildResult.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildResult.java new file mode 100644 index 000000000..bdccb56d0 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildResult.java @@ -0,0 +1,23 @@ +package me.jellysquid.mods.sodium.client.render.chunk.compile; + +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.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; + +/** + * The result of a chunk rebuild task which contains any and all data that needs to be processed or uploaded on + * the main thread. If a task is cancelled after finishing its work and not before the result is processed, the result + * will instead be discarded. + */ +public class ChunkBuildResult { + public final ChunkRenderContainer render; + public final ChunkRenderData data; + public BlockRenderPass[] passesToUpload; + + public ChunkBuildResult(ChunkRenderContainer render, ChunkRenderData data) { + this.render = render; + this.data = data; + this.passesToUpload = BlockRenderPass.VALUES; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java new file mode 100644 index 000000000..64e059f2a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java @@ -0,0 +1,404 @@ +package me.jellysquid.mods.sodium.client.render.chunk.compile; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.compat.forge.ForgeBlockRenderer; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; +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.passes.BlockRenderPassManager; +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; +import me.jellysquid.mods.sodium.client.util.task.CancellationSource; +import me.jellysquid.mods.sodium.client.world.WorldSlice; +import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; +import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSectionCache; +import me.jellysquid.mods.sodium.common.util.collections.DequeDrain; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.atomic.AtomicBoolean; + +public class ChunkBuilder { + /** + * The maximum number of jobs that can be queued for a given worker thread. + */ + private static final int TASK_QUEUE_LIMIT_PER_WORKER = 2; + + private static final Logger LOGGER = LogManager.getLogger("ChunkBuilder"); + + private final Deque> buildQueue = new ConcurrentLinkedDeque<>(); + private final Deque> uploadQueue = new ConcurrentLinkedDeque<>(); + + private final Object jobNotifier = new Object(); + + private final AtomicBoolean running = new AtomicBoolean(false); + private final List threads = new ArrayList<>(); + + private ClonedChunkSectionCache sectionCache; + + private World world; + private Vec3d cameraPosition = Vec3d.ZERO; + private BlockRenderPassManager renderPassManager; + + private final int limitThreads; + private final ChunkVertexType vertexType; + private final ChunkRenderBackend backend; + + public ChunkBuilder(ChunkVertexType vertexType, ChunkRenderBackend backend) { + this.vertexType = vertexType; + this.backend = backend; + this.limitThreads = getThreadCount(); + } + + /** + * Returns the remaining number of build tasks which should be scheduled this frame. If an attempt is made to + * spawn more tasks than the budget allows, it will block until resources become available. + */ + public int getSchedulingBudget() { + return Math.max(0, (this.limitThreads * TASK_QUEUE_LIMIT_PER_WORKER) - this.buildQueue.size()); + } + + /** + * Spawns a number of work-stealing threads to process results in the build queue. If the builder is already + * running, this method does nothing and exits. + */ + public void startWorkers() { + if (this.running.getAndSet(true)) { + return; + } + + if (!this.threads.isEmpty()) { + throw new IllegalStateException("Threads are still alive while in the STOPPED state"); + } + + MinecraftClient client = MinecraftClient.getInstance(); + + for (int i = 0; i < this.limitThreads; i++) { + ChunkBuildBuffers buffers = new ChunkBuildBuffers(this.vertexType, this.renderPassManager); + ChunkRenderCacheLocal pipeline = new ChunkRenderCacheLocal(client, this.world); + + WorkerRunnable worker = new WorkerRunnable(buffers, pipeline); + + Thread thread = new Thread(worker, "Chunk Render Task Executor #" + i); + thread.setPriority(Math.max(0, Thread.NORM_PRIORITY - 2)); + thread.start(); + + this.threads.add(thread); + } + + LOGGER.info("Started {} worker threads", this.threads.size()); + } + + /** + * Notifies all worker threads to stop and blocks until all workers terminate. After the workers have been shut + * down, all tasks are cancelled and the pending queues are cleared. If the builder is already stopped, this + * method does nothing and exits. + */ + public void stopWorkers() { + if (!this.running.getAndSet(false)) { + return; + } + + if (this.threads.isEmpty()) { + throw new IllegalStateException("No threads are alive but the executor is in the RUNNING state"); + } + + LOGGER.info("Stopping worker threads"); + + // Notify all worker threads to wake up, where they will then terminate + synchronized (this.jobNotifier) { + this.jobNotifier.notifyAll(); + } + + // Wait for every remaining thread to terminate + for (Thread thread : this.threads) { + try { + thread.join(); + } catch (InterruptedException ignored) { + } + } + + this.threads.clear(); + + // Drop any pending work queues and cancel futures + this.uploadQueue.clear(); + + for (WrappedTask job : this.buildQueue) { + job.future.cancel(true); + } + + this.buildQueue.clear(); + + this.world = null; + this.sectionCache = null; + } + + public void cleanupSectionCache() { + this.sectionCache.cleanup(); + } + + /** + * Processes all pending build task uploads using the chunk render backend. + */ + // TODO: Limit the amount of time this can take per frame + public boolean performPendingUploads() { + if (this.uploadQueue.isEmpty()) { + return false; + } + + this.backend.upload(RenderDevice.INSTANCE.createCommandList(), new DequeDrain<>(this.uploadQueue)); + + return true; + } + + public CompletableFuture> schedule(ChunkRenderBuildTask task) { + if (!this.running.get()) { + throw new IllegalStateException("Executor is stopped"); + } + + WrappedTask job = new WrappedTask<>(task); + + this.buildQueue.add(job); + + synchronized (this.jobNotifier) { + this.jobNotifier.notify(); + } + + return job.future; + } + + /** + * Sets the current camera position of the player used for task prioritization. + */ + public void setCameraPosition(double x, double y, double z) { + this.cameraPosition = new Vec3d(x, y, z); + } + + /** + * Returns the current camera position of the player used for task prioritization. + */ + public Vec3d getCameraPosition() { + return this.cameraPosition; + } + + /** + * @return True if the build queue is empty + */ + public boolean isBuildQueueEmpty() { + return this.buildQueue.isEmpty(); + } + + /** + * Initializes this chunk builder for the given world. If the builder is already running (which can happen during + * a world teleportation event), the worker threads will first be stopped and all pending tasks will be discarded + * before being started again. + * @param world The world instance + * @param renderPassManager The render pass manager used for the world + */ + public void init(ClientWorld world, BlockRenderPassManager renderPassManager) { + if (world == null) { + throw new NullPointerException("World is null"); + } + + this.stopWorkers(); + + this.world = world; + this.renderPassManager = renderPassManager; + this.sectionCache = new ClonedChunkSectionCache(this.world); + + ForgeBlockRenderer.init(); + + this.startWorkers(); + } + + /** + * Returns the "optimal" number of threads to be used for chunk build tasks. This is always at least one thread, + * but can be up to the number of available processor threads on the system. + */ + private static int getOptimalThreadCount() { + return MathHelper.clamp(Math.max(getMaxThreadCount() / 3, getMaxThreadCount() - 6), 1, 10); + } + + private static int getThreadCount() { + int requested = SodiumClientMod.options().performance.chunkBuilderThreads; + return requested == 0 ? getOptimalThreadCount() : Math.min(requested, getMaxThreadCount()); + } + + private static int getMaxThreadCount() { + return Runtime.getRuntime().availableProcessors(); + } + + /** + * 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 render) { + this.scheduleRebuildTaskAsync(render) + .thenAccept(this::enqueueUpload); + } + + /** + * 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 deferSort(ChunkRenderContainer render) { + this.scheduleSortTaskAsync(render) + .thenAccept(this::enqueueUpload); + } + + + /** + * Enqueues the build task result to the pending result queue to be later processed during the next available + * synchronization point on the main thread. + * @param result The build task's result + */ + private void enqueueUpload(ChunkBuildResult 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 + */ + public CompletableFuture> scheduleRebuildTaskAsync(ChunkRenderContainer render) { + return this.schedule(this.createRebuildTask(render)); + } + + /** + * Schedules the rebuild task asynchronously on the worker pool, returning a future wrapping the task. + * @param render The render to rebuild + */ + public CompletableFuture> scheduleSortTaskAsync(ChunkRenderContainer render) { + return this.schedule(this.createSortTask(render)); + } + + /** + * Creates a task to rebuild the geometry of a {@link ChunkRenderContainer}. + * @param render The render to rebuild + */ + private ChunkRenderBuildTask createRebuildTask(ChunkRenderContainer render) { + render.cancelRebuildTask(); + + ChunkRenderContext context = WorldSlice.prepare(this.world, render.getChunkPos(), this.sectionCache); + + if (context == null) { + return new ChunkRenderEmptyBuildTask<>(render); + } else { + return new ChunkRenderRebuildTask<>(render, context, render.getRenderOrigin()).withCameraPosition(this.cameraPosition); + } + } + + private ChunkRenderBuildTask createSortTask(ChunkRenderContainer render) { + render.cancelRebuildTask(); + + return new ChunkRenderTranslucencySortTask<>(render, render.getRenderOrigin(), this.cameraPosition); + } + + public void onChunkDataChanged(int x, int y, int z) { + this.sectionCache.invalidate(x, y, z); + } + + private class WorkerRunnable implements Runnable { + private final AtomicBoolean running = ChunkBuilder.this.running; + + // The re-useable build buffers used by this worker for building chunk meshes + private final ChunkBuildBuffers bufferCache; + + // Making this thread-local provides a small boost to performance by avoiding the overhead in synchronizing + // caches between different CPU cores + private final ChunkRenderCacheLocal cache; + + public WorkerRunnable(ChunkBuildBuffers bufferCache, ChunkRenderCacheLocal cache) { + this.bufferCache = bufferCache; + this.cache = cache; + } + + @Override + public void run() { + // Run until the chunk builder shuts down + while (this.running.get()) { + WrappedTask job = this.getNextJob(); + + // If the job is null or no longer valid, keep searching for a task + if (job == null || job.isCancelled()) { + continue; + } + + ChunkBuildResult result; + + try { + // Perform the build task with this worker's local resources and obtain the result + result = job.task.performBuild(this.cache, this.bufferCache, job); + } catch (Exception e) { + // Propagate any exception from chunk building + job.future.completeExceptionally(e); + continue; + } finally { + job.task.releaseResources(); + } + + // The result can be null if the task is cancelled + if (result != null) { + // Notify the future that the result is now available + job.future.complete(result); + } else if (!job.isCancelled()) { + // If the job wasn't cancelled and no result was produced, we've hit a bug + job.future.completeExceptionally(new RuntimeException("No result was produced by the task")); + } + } + } + + /** + * Returns the next task which this worker can work on or blocks until one becomes available. If no tasks are + * currently available, it will wait on {@link ChunkBuilder#jobNotifier} field until notified. + */ + private WrappedTask getNextJob() { + WrappedTask job = ChunkBuilder.this.buildQueue.poll(); + + if (job == null) { + synchronized (ChunkBuilder.this.jobNotifier) { + try { + ChunkBuilder.this.jobNotifier.wait(); + } catch (InterruptedException ignored) { + } + } + } + + return job; + } + } + + private static class WrappedTask implements CancellationSource { + private final ChunkRenderBuildTask task; + private final CompletableFuture> future; + + private WrappedTask(ChunkRenderBuildTask task) { + this.task = task; + this.future = new CompletableFuture<>(); + } + + @Override + public boolean isCancelled() { + return this.future.isCancelled(); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuffers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuffers.java new file mode 100644 index 000000000..7b2e52cfc --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuffers.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.sodium.client.render.chunk.compile.buffers; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; + +public class BakedChunkModelBuffers implements ChunkModelBuffers { + private final ModelVertexSink[] builders; + private final ChunkRenderData.Builder renderData; + + public BakedChunkModelBuffers(ModelVertexSink[] builders, ChunkRenderData.Builder renderData) { + this.builders = builders; + this.renderData = renderData; + } + + @Override + public ModelVertexSink getSink(ModelQuadFacing facing) { + return this.builders[facing.ordinal()]; + } + + @Override + public ChunkRenderData.Builder getRenderData() { + return this.renderData; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuffers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuffers.java new file mode 100644 index 000000000..a886d88c2 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuffers.java @@ -0,0 +1,12 @@ +package me.jellysquid.mods.sodium.client.render.chunk.compile.buffers; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; + +public interface ChunkModelBuffers { + ModelVertexSink getSink(ModelQuadFacing facing); + + @Deprecated + ChunkRenderData.Builder getRenderData(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelVertexTransformer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelVertexTransformer.java new file mode 100644 index 000000000..73fa02ed4 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/ChunkModelVertexTransformer.java @@ -0,0 +1,23 @@ +package me.jellysquid.mods.sodium.client.render.chunk.compile.buffers; + +import me.jellysquid.mods.sodium.client.model.vertex.transformers.AbstractVertexTransformer; +import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkModelOffset; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; + +public class ChunkModelVertexTransformer extends AbstractVertexTransformer implements ModelVertexSink { + /** + * The translation to be applied to all quads written into this mesh builder. + */ + private final ChunkModelOffset offset; + + public ChunkModelVertexTransformer(ModelVertexSink delegate, ChunkModelOffset offset) { + super(delegate); + + this.offset = offset; + } + + @Override + public void writeQuad(float x, float y, float z, int color, float u, float v, int light) { + this.delegate.writeQuad(x + this.offset.x, y + this.offset.y, z + this.offset.z, color, u, v, light); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/FallbackChunkModelBuffers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/FallbackChunkModelBuffers.java new file mode 100644 index 000000000..2b3397d5e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/buffers/FallbackChunkModelBuffers.java @@ -0,0 +1,21 @@ +package me.jellysquid.mods.sodium.client.render.chunk.compile.buffers; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; + +public class FallbackChunkModelBuffers implements ChunkModelBuffers { + public FallbackChunkModelBuffers() { + + } + + @Override + public ModelVertexSink getSink(ModelQuadFacing facing) { + return null; + } + + @Override + public ChunkRenderData.Builder getRenderData() { + return null; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java new file mode 100644 index 000000000..da48d7e64 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java @@ -0,0 +1,16 @@ +package me.jellysquid.mods.sodium.client.render.chunk.cull; + +import it.unimi.dsi.fastutil.ints.IntArrayList; +import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.chunk.ChunkOcclusionData; + +public interface ChunkCuller { + IntArrayList computeVisible(Camera camera, FrustumExtended frustum, int frame, boolean spectator); + + void onSectionStateChanged(int x, int y, int z, ChunkOcclusionData occlusionData); + void onSectionLoaded(int x, int y, int z, int id); + void onSectionUnloaded(int x, int y, int z); + + boolean isSectionVisible(int x, int y, int z); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkFaceFlags.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkFaceFlags.java new file mode 100644 index 000000000..6ea6b5c5c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkFaceFlags.java @@ -0,0 +1,29 @@ +package me.jellysquid.mods.sodium.client.render.chunk.cull; + +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; + +public class ChunkFaceFlags { + public static final int UP = of(ModelQuadFacing.UP); + public static final int DOWN = of(ModelQuadFacing.DOWN); + public static final int WEST = of(ModelQuadFacing.WEST); + public static final int EAST = of(ModelQuadFacing.EAST); + public static final int NORTH = of(ModelQuadFacing.NORTH); + public static final int SOUTH = of(ModelQuadFacing.SOUTH); + public static final int UNASSIGNED = of(ModelQuadFacing.UNASSIGNED); + + public static final int ALL = all(); + + public static int of(ModelQuadFacing facing) { + return 1 << facing.ordinal(); + } + + private static int all() { + int v = 0; + + for (ModelQuadFacing facing : ModelQuadFacing.VALUES) { + v |= of(facing); + } + + return v; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java new file mode 100644 index 000000000..cc05f88cb --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java @@ -0,0 +1,219 @@ +package me.jellysquid.mods.sodium.client.render.chunk.cull.graph; + +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import me.jellysquid.mods.sodium.client.render.chunk.cull.ChunkCuller; +import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.chunk.ChunkOcclusionData; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public class ChunkGraphCuller implements ChunkCuller { + private final Long2ObjectMap nodes = new Long2ObjectOpenHashMap<>(); + + private final ChunkGraphIterationQueue visible = new ChunkGraphIterationQueue(); + private final World world; + private final int renderDistance; + + private FrustumExtended frustum; + private boolean useOcclusionCulling; + + private int activeFrame = 0; + private int centerChunkX, centerChunkY, centerChunkZ; + + public ChunkGraphCuller(World world, int renderDistance) { + this.world = world; + this.renderDistance = renderDistance; + } + + @Override + public IntArrayList computeVisible(Camera camera, FrustumExtended frustum, int frame, boolean spectator) { + this.initSearch(camera, frustum, frame, spectator); + + ChunkGraphIterationQueue queue = this.visible; + + for (int i = 0; i < queue.size(); i++) { + ChunkGraphNode node = queue.getNode(i); + short cullData = node.computeQueuePop(); + + for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + if (useOcclusionCulling && (cullData & (1 << dir.ordinal())) == 0) { + continue; + } + + ChunkGraphNode adj = node.getConnectedNode(dir); + + if (adj != null && this.isWithinRenderDistance(adj)) { + this.bfsEnqueue(node, adj, dir.getOpposite(), cullData); + } + } + } + + return this.visible.getOrderedIdList(); + } + + private boolean isWithinRenderDistance(ChunkGraphNode adj) { + int x = Math.abs(adj.getChunkX() - this.centerChunkX); + int z = Math.abs(adj.getChunkZ() - this.centerChunkZ); + + return x <= this.renderDistance && z <= this.renderDistance; + } + + private void initSearch(Camera camera, FrustumExtended frustum, int frame, boolean spectator) { + this.activeFrame = frame; + this.frustum = frustum; + this.useOcclusionCulling = MinecraftClient.getInstance().chunkCullingEnabled; + + this.visible.clear(); + + BlockPos origin = camera.getBlockPos(); + + int chunkX = origin.getX() >> 4; + int chunkY = origin.getY() >> 4; + int chunkZ = origin.getZ() >> 4; + + this.centerChunkX = chunkX; + this.centerChunkY = chunkY; + this.centerChunkZ = chunkZ; + + ChunkGraphNode rootNode = this.getNode(chunkX, chunkY, chunkZ); + + if (rootNode != null) { + rootNode.resetCullingState(); + rootNode.setLastVisibleFrame(frame); + + if (spectator && this.world.getBlockState(origin).isOpaqueFullCube(this.world, origin)) { + this.useOcclusionCulling = false; + } + + this.visible.add(rootNode); + } else { + chunkY = MathHelper.clamp(origin.getY() >> 4, 0, 15); + + List bestNodes = new ArrayList<>(); + + for (int x2 = -this.renderDistance; x2 <= this.renderDistance; ++x2) { + for (int z2 = -this.renderDistance; z2 <= this.renderDistance; ++z2) { + ChunkGraphNode node = this.getNode(chunkX + x2, chunkY, chunkZ + z2); + + if (node == null || node.isCulledByFrustum(frustum)) { + continue; + } + + node.resetCullingState(); + node.setLastVisibleFrame(frame); + + bestNodes.add(node); + } + } + + bestNodes.sort(Comparator.comparingDouble(node -> node.getSquaredDistance(origin))); + + for (ChunkGraphNode node : bestNodes) { + this.visible.add(node); + } + } + } + + + private void bfsEnqueue(ChunkGraphNode parent, ChunkGraphNode node, Direction flow, short parentalData) { + if (node.getLastVisibleFrame() == this.activeFrame) { + node.updateCullingState(flow, parentalData); + return; + } + node.setLastVisibleFrame(this.activeFrame); + + if (node.isCulledByFrustum(this.frustum)) { + return; + } + + node.setCullingState(parentalData); + node.updateCullingState(flow, parentalData); + + this.visible.add(node); + } + + private void connectNeighborNodes(ChunkGraphNode node) { + for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + ChunkGraphNode adj = this.findAdjacentNode(node, dir); + + if (adj != null) { + adj.setAdjacentNode(dir.getOpposite(), node); + } + + node.setAdjacentNode(dir, adj); + } + } + + private void disconnectNeighborNodes(ChunkGraphNode node) { + for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + ChunkGraphNode adj = node.getConnectedNode(dir); + + if (adj != null) { + adj.setAdjacentNode(dir.getOpposite(), null); + } + + node.setAdjacentNode(dir, null); + } + } + + private ChunkGraphNode findAdjacentNode(ChunkGraphNode node, Direction dir) { + return this.getNode(node.getChunkX() + dir.getOffsetX(), node.getChunkY() + dir.getOffsetY(), node.getChunkZ() + dir.getOffsetZ()); + } + + private ChunkGraphNode getNode(int x, int y, int z) { + return this.nodes.get(ChunkSectionPos.asLong(x, y, z)); + } + + @Override + public void onSectionStateChanged(int x, int y, int z, ChunkOcclusionData occlusionData) { + ChunkGraphNode node = this.getNode(x, y, z); + + if (node != null) { + node.setOcclusionData(occlusionData); + } + } + + @Override + public void onSectionLoaded(int x, int y, int z, int id) { + ChunkGraphNode node = new ChunkGraphNode(x, y, z, id); + ChunkGraphNode prev; + + if ((prev = this.nodes.put(ChunkSectionPos.asLong(x, y, z), node)) != null) { + this.disconnectNeighborNodes(prev); + } + + this.connectNeighborNodes(node); + } + + @Override + public void onSectionUnloaded(int x, int y, int z) { + ChunkGraphNode node = this.nodes.remove(ChunkSectionPos.asLong(x, y, z)); + + if (node != null) { + this.disconnectNeighborNodes(node); + } + } + + @Override + public boolean isSectionVisible(int x, int y, int z) { + ChunkGraphNode render = this.getNode(x, y, z); + + if (render == null) { + return false; + } + + return render.getLastVisibleFrame() == this.activeFrame; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphIterationQueue.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphIterationQueue.java new file mode 100644 index 000000000..981464e11 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphIterationQueue.java @@ -0,0 +1,58 @@ +package me.jellysquid.mods.sodium.client.render.chunk.cull.graph; + +import it.unimi.dsi.fastutil.ints.IntArrayList; + +import java.util.Arrays; + +public class ChunkGraphIterationQueue { + private int[] positions; + private ChunkGraphNode[] nodes; + + private int pos; + private int capacity; + + public ChunkGraphIterationQueue() { + this(4096); + } + + public ChunkGraphIterationQueue(int capacity) { + this.positions = new int[capacity]; + this.nodes = new ChunkGraphNode[capacity]; + + this.capacity = capacity; + } + + public void add(ChunkGraphNode node) { + int i = this.pos++; + + if (i == this.capacity) { + this.resize(); + } + + this.positions[i] = node.getId(); + this.nodes[i] = node; + } + + private void resize() { + this.capacity *= 2; + + this.positions = Arrays.copyOf(this.positions, this.capacity); + this.nodes = Arrays.copyOf(this.nodes, this.capacity); + } + + public ChunkGraphNode getNode(int i) { + return this.nodes[i]; + } + + public void clear() { + this.pos = 0; + } + + public int size() { + return this.pos; + } + + public IntArrayList getOrderedIdList() { + return IntArrayList.wrap(this.positions, this.pos); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphNode.java new file mode 100644 index 000000000..a8057f926 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphNode.java @@ -0,0 +1,184 @@ +package me.jellysquid.mods.sodium.client.render.chunk.cull.graph; + +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.client.render.chunk.ChunkOcclusionData; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; + +public class ChunkGraphNode { + private static final long DEFAULT_VISIBILITY_DATA = calculateVisibilityData(ChunkRenderData.EMPTY.getOcclusionData()); + private static final float FRUSTUM_EPSILON = 1.0f /* block model margin */ + 0.125f /* epsilon */; + + private final ChunkGraphNode[] nodes = new ChunkGraphNode[DirectionUtil.ALL_DIRECTIONS.length]; + + private final int id; + private final int chunkX, chunkY, chunkZ; + + private int lastVisibleFrame = -1; + + private long visibilityData; + private short cullingState; + + public ChunkGraphNode(int chunkX, int chunkY, int chunkZ, int id) { + this.chunkX = chunkX; + this.chunkY = chunkY; + this.chunkZ = chunkZ; + this.id = id; + + this.visibilityData = DEFAULT_VISIBILITY_DATA; + } + + public ChunkGraphNode getConnectedNode(Direction dir) { + return this.nodes[dir.ordinal()]; + } + + public void setLastVisibleFrame(int frame) { + this.lastVisibleFrame = frame; + } + + public int getLastVisibleFrame() { + return this.lastVisibleFrame; + } + + public int getChunkX() { + return this.chunkX; + } + + public int getChunkY() { + return this.chunkY; + } + + public int getChunkZ() { + return this.chunkZ; + } + + public void setAdjacentNode(Direction dir, ChunkGraphNode node) { + this.nodes[dir.ordinal()] = node; + } + + public void setOcclusionData(ChunkOcclusionData occlusionData) { + this.visibilityData = calculateVisibilityData(occlusionData); + } + + private static long calculateVisibilityData(ChunkOcclusionData occlusionData) { + long visibilityData = 0; + + for (Direction from : DirectionUtil.ALL_DIRECTIONS) { + for (Direction to : DirectionUtil.ALL_DIRECTIONS) { + if (occlusionData == null || occlusionData.isVisibleThrough(from, to)) { + visibilityData |= (1L << ((from.ordinal() << 3) + to.ordinal())); + } + } + } + + return visibilityData; + } + + //The way this works now is that the culling state contains 2 inner states + // visited directions mask, and visitable direction mask + //On graph start, the root node(s) have the visit and visitable masks set to all visible + // when a chunk section is popped off the queue, the visited direction mask is anded with the + // visitable direction mask to return a bitfield containing what directions the graph can flow too + //When a chunk is visited in the graph the inbound direction is masked off from the visited direction mask + // and the visitable direction mask is updated (ored) with the visibilityData of the inbound direction + //When a chunk hasnt been visited before, it uses the parents data as the initial visited direction mask + + public short computeQueuePop() { + short retVal = (short) (cullingState & (((cullingState >> 8) & 0xFF) | 0xFF00)); + cullingState = 0; + return retVal; + } + + public void updateCullingState(Direction flow, short parent) { + int inbound = flow.ordinal(); + this.cullingState |= (visibilityData >> (inbound<<3)) & 0xFF; + this.cullingState &= ~(1 << (inbound + 8)); + //NOTE: this isnt strictly needed, due to the properties provided from the bfs search (never backtracking), + // but just incase/better readability/understandability + this.cullingState &= parent|0x00FF; + } + + public void setCullingState(short parent) { + this.cullingState = (short) (parent & 0xFF00); + } + + public void resetCullingState() { + this.cullingState = -1; + } + + public int getId() { + return this.id; + } + + public boolean isCulledByFrustum(FrustumExtended frustum) { + float x = this.getOriginX(); + float y = this.getOriginY(); + float z = this.getOriginZ(); + + return !frustum.fastAabbTest(x - FRUSTUM_EPSILON, y - FRUSTUM_EPSILON, z - FRUSTUM_EPSILON, + x + 16.0f + FRUSTUM_EPSILON, y + 16.0f + FRUSTUM_EPSILON, z + 16.0f + FRUSTUM_EPSILON); + } + + /** + * @return The x-coordinate of the origin position of this chunk render + */ + public int getOriginX() { + return this.chunkX << 4; + } + + /** + * @return The y-coordinate of the origin position of this chunk render + */ + public int getOriginY() { + return this.chunkY << 4; + } + + /** + * @return The z-coordinate of the origin position of this chunk render + */ + public int getOriginZ() { + return this.chunkZ << 4; + } + + /** + * @return The squared distance from the center of this chunk in the world to the center of the block position + * given by {@param pos} + */ + public double getSquaredDistance(BlockPos pos) { + return this.getSquaredDistance(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D); + } + + /** + * @return The x-coordinate of the center position of this chunk render + */ + private double getCenterX() { + return this.getOriginX() + 8.0D; + } + + /** + * @return The y-coordinate of the center position of this chunk render + */ + private double getCenterY() { + return this.getOriginY() + 8.0D; + } + + /** + * @return The z-coordinate of the center position of this chunk render + */ + private double getCenterZ() { + return this.getOriginZ() + 8.0D; + } + + /** + * @return The squared distance from the center of this chunk in the world to the given position + */ + public double getSquaredDistance(double x, double y, double z) { + double xDist = x - this.getCenterX(); + double yDist = y - this.getCenterY(); + double zDist = z - this.getCenterZ(); + + return (xDist * xDist) + (yDist * yDist) + (zDist * zDist); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkMeshData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkMeshData.java new file mode 100644 index 000000000..fe2e04031 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkMeshData.java @@ -0,0 +1,51 @@ +package me.jellysquid.mods.sodium.client.render.chunk.data; + +import me.jellysquid.mods.sodium.client.gl.buffer.VertexData; +import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; + +import java.util.EnumMap; +import java.util.Map; + +public class ChunkMeshData { + public static final ChunkMeshData EMPTY = new ChunkMeshData(); + + private final EnumMap parts = new EnumMap<>(ModelQuadFacing.class); + private VertexData vertexData; + + public void setVertexData(VertexData vertexData) { + this.vertexData = vertexData; + } + + public void setModelSlice(ModelQuadFacing facing, BufferSlice slice) { + this.parts.put(facing, slice); + } + + public VertexData takeVertexData() { + VertexData data = this.vertexData; + + if (data == null) { + throw new NullPointerException("No pending data to upload"); + } + + this.vertexData = null; + + return data; + } + + public boolean hasVertexData() { + return this.vertexData != null; + } + + public int getVertexDataSize() { + if (this.vertexData != null) { + return this.vertexData.buffer.capacity(); + } + + return 0; + } + + public Iterable> getSlices() { + return this.parts.entrySet(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java new file mode 100644 index 000000000..9e933dfa9 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java @@ -0,0 +1,81 @@ +package me.jellysquid.mods.sodium.client.render.chunk.data; + +import net.minecraft.util.math.ChunkSectionPos; + +public class ChunkRenderBounds { + public static final ChunkRenderBounds ALWAYS_FALSE = new ChunkRenderBounds(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, + Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); + + public final float x1, y1, z1; + public final float x2, y2, z2; + + public ChunkRenderBounds(float x1, float y1, float z1, float x2, float y2, float z2) { + this.x1 = x1; + this.y1 = y1; + this.z1 = z1; + + this.x2 = x2; + this.y2 = y2; + this.z2 = z2; + } + + public ChunkRenderBounds(ChunkSectionPos origin) { + this.x1 = origin.getMinX(); + this.y1 = origin.getMinY(); + this.z1 = origin.getMinZ(); + + this.x2 = origin.getMaxX() + 1; + this.y2 = origin.getMaxY() + 1; + this.z2 = origin.getMaxZ() + 1; + } + + public static class Builder { + // Bit-mask of the blocks set on each axis + private int x = 0, y = 0, z = 0; + + public void addBlock(int x, int y, int z) { + // Accumulate bits on each axis for the given block position. This avoids needing to + // branch multiple times trying to determine if the bounds need to grow. The min/max + // value of each axis can later be extracted by counting the trailing/leading zeroes. + this.x |= 1 << x; + this.y |= 1 << y; + this.z |= 1 << z; + } + + public ChunkRenderBounds build(ChunkSectionPos origin) { + // If no bits were set on any axis, return the default bounds + if ((this.x | this.y | this.z) == 0) { + return new ChunkRenderBounds(origin); + } + + int x1 = origin.getMinX() + leftBound(this.x); + int x2 = origin.getMinX() + rightBound(this.x); + + int y1 = origin.getMinY() + leftBound(this.y); + int y2 = origin.getMinY() + rightBound(this.y); + + int z1 = origin.getMinZ() + leftBound(this.z); + int z2 = origin.getMinZ() + rightBound(this.z); + + return new ChunkRenderBounds( + Math.max(x1, origin.getMinX()) - 0.5f, + Math.max(y1, origin.getMinY()) - 0.5f, + Math.max(z1, origin.getMinZ()) - 0.5f, + + Math.min(x2, origin.getMaxX()) + 0.5f, + Math.min(y2, origin.getMaxY()) + 0.5f, + Math.min(z2, origin.getMaxZ()) + 0.5f + ); + } + + // Return the left-bound of the bit-masked axis + private static int leftBound(int i) { + return Integer.numberOfTrailingZeros(i); + } + + // Return the right-bound of the bit-masked axis + private static int rightBound(int i) { + return 32 - Integer.numberOfLeadingZeros(i); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java new file mode 100644 index 000000000..79208602d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java @@ -0,0 +1,211 @@ +package me.jellysquid.mods.sodium.client.render.chunk.data; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.render.chunk.ChunkOcclusionData; +import net.minecraft.client.texture.Sprite; +import net.minecraft.util.math.Direction; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * The render data for a chunk render container containing all the information about which meshes are attached, the + * block entities contained by it, and any data used for occlusion testing. + */ +public class ChunkRenderData { + public static final ChunkRenderData ABSENT = new Builder() + .build(); + public static final ChunkRenderData EMPTY = createEmptyData(); + + private List globalBlockEntities; + private List blockEntities; + + private EnumMap meshes; + + private ChunkOcclusionData occlusionData; + private ChunkRenderBounds bounds; + + private List animatedSprites; + + private boolean isEmpty; + private int meshByteSize; + private int facesWithData; + + /** + * @return True if the chunk has no renderables, otherwise false + */ + public boolean isEmpty() { + return this.isEmpty; + } + + public ChunkRenderBounds getBounds() { + return this.bounds; + } + + public ChunkOcclusionData getOcclusionData() { + return this.occlusionData; + } + + public List getAnimatedSprites() { + return this.animatedSprites; + } + + /** + * The collection of block entities contained by this rendered chunk. + */ + public Collection getBlockEntities() { + return this.blockEntities; + } + + /** + * The collection of block entities contained by this rendered chunk section which are not part of its culling + * volume. These entities should always be rendered regardless of the render being visible in the frustum. + */ + public Collection getGlobalBlockEntities() { + return this.globalBlockEntities; + } + + /** + * The collection of chunk meshes belonging to this render. + */ + public ChunkMeshData getMesh(BlockRenderPass pass) { + return this.meshes.get(pass); + } + + public void setMesh(BlockRenderPass pass, ChunkMeshData data) { + if (this.meshes.get(pass) == null) + throw new IllegalStateException("No mesh found"); + this.meshes.put(pass, data); + } + + public int getMeshSize() { + return this.meshByteSize; + } + + public int getFacesWithData() { + return this.facesWithData; + } + + public ChunkRenderData copyAndReplaceMesh(Map replacements) { + ChunkRenderData data = new ChunkRenderData(); + data.globalBlockEntities = this.globalBlockEntities; + data.blockEntities = this.blockEntities; + data.occlusionData = this.occlusionData; + data.meshes = new EnumMap<>(this.meshes); + data.bounds = this.bounds; + data.animatedSprites = new ObjectArrayList<>(this.animatedSprites); + data.meshes.putAll(replacements); + + int facesWithData = 0; + int size = 0; + + for (ChunkMeshData meshData : this.meshes.values()) { + size += meshData.getVertexDataSize(); + + for (Map.Entry entry : meshData.getSlices()) { + facesWithData |= 1 << entry.getKey().ordinal(); + } + } + + data.isEmpty = this.globalBlockEntities.isEmpty() && this.blockEntities.isEmpty() && facesWithData == 0; + data.meshByteSize = size; + data.facesWithData = facesWithData; + return data; + } + + public static class Builder { + private final List globalBlockEntities = new ArrayList<>(); + private final List blockEntities = new ArrayList<>(); + private final Set animatedSprites = new ObjectOpenHashSet<>(); + + private final EnumMap meshes = new EnumMap<>(BlockRenderPass.class); + + private ChunkOcclusionData occlusionData; + private ChunkRenderBounds bounds = ChunkRenderBounds.ALWAYS_FALSE; + + public Builder() { + for (BlockRenderPass pass : BlockRenderPass.VALUES) { + this.setMesh(pass, ChunkMeshData.EMPTY); + } + } + + public void setBounds(ChunkRenderBounds bounds) { + this.bounds = bounds; + } + + public void setOcclusionData(ChunkOcclusionData data) { + this.occlusionData = data; + } + + /** + * Adds a sprite to this data container for tracking. If the sprite is tickable, it will be ticked every frame + * before rendering as necessary. + * @param sprite The sprite + */ + public void addSprite(Sprite sprite) { + if (sprite.isAnimated()) { + this.animatedSprites.add(sprite); + } + } + + public void setMesh(BlockRenderPass pass, ChunkMeshData data) { + this.meshes.put(pass, data); + } + + /** + * Adds a block entity to the data container. + * @param entity The block entity itself + * @param cull True if the block entity can be culled to this chunk render's volume, otherwise false + */ + public void addBlockEntity(BlockEntity entity, boolean cull) { + (cull ? this.blockEntities : this.globalBlockEntities).add(entity); + } + + public ChunkRenderData build() { + ChunkRenderData data = new ChunkRenderData(); + data.globalBlockEntities = this.globalBlockEntities; + data.blockEntities = this.blockEntities; + data.occlusionData = this.occlusionData; + data.meshes = this.meshes; + data.bounds = this.bounds; + data.animatedSprites = new ObjectArrayList<>(this.animatedSprites); + + int facesWithData = 0; + int size = 0; + + for (ChunkMeshData meshData : this.meshes.values()) { + size += meshData.getVertexDataSize(); + + for (Map.Entry entry : meshData.getSlices()) { + facesWithData |= 1 << entry.getKey().ordinal(); + } + } + + data.isEmpty = this.globalBlockEntities.isEmpty() && this.blockEntities.isEmpty() && facesWithData == 0; + data.meshByteSize = size; + data.facesWithData = facesWithData; + + return data; + } + } + + private static ChunkRenderData createEmptyData() { + ChunkOcclusionData occlusionData = new ChunkOcclusionData(); + occlusionData.addOpenEdgeFaces(EnumSet.allOf(Direction.class)); + + Builder meshInfo = new Builder(); + meshInfo.setOcclusionData(occlusionData); + + return meshInfo.build(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkMeshAttribute.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkMeshAttribute.java new file mode 100644 index 000000000..75df244b8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkMeshAttribute.java @@ -0,0 +1,8 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format; + +public enum ChunkMeshAttribute { + POSITION, + COLOR, + TEXTURE, + LIGHT +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkModelOffset.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkModelOffset.java new file mode 100644 index 000000000..64b441a08 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkModelOffset.java @@ -0,0 +1,11 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format; + +public class ChunkModelOffset { + public float x, y, z; + + public void set(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/DefaultModelVertexFormats.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/DefaultModelVertexFormats.java new file mode 100644 index 000000000..03e523dda --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/DefaultModelVertexFormats.java @@ -0,0 +1,9 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format; + +import me.jellysquid.mods.sodium.client.render.chunk.format.hfp.HFPModelVertexType; +import me.jellysquid.mods.sodium.client.render.chunk.format.sfp.SFPModelVertexType; + +public class DefaultModelVertexFormats { + public static final HFPModelVertexType MODEL_VERTEX_HFP = new HFPModelVertexType(); + public static final SFPModelVertexType MODEL_VERTEX_SFP = new SFPModelVertexType(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ModelVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ModelVertexSink.java new file mode 100644 index 000000000..91d56ec8a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ModelVertexSink.java @@ -0,0 +1,17 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; + +public interface ModelVertexSink extends VertexSink { + /** + * Writes a quad vertex to this sink. + * @param x The x-position of the vertex + * @param y The y-position of the vertex + * @param z The z-position of the vertex + * @param color The ABGR-packed color of the vertex + * @param u The u-texture of the vertex + * @param v The y-texture of the vertex + * @param light The packed light-map coordinates of the vertex + */ + void writeQuad(float x, float y, float z, int color, float u, float v, int light); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ModelVertexUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ModelVertexUtil.java new file mode 100644 index 000000000..4d05c9ed9 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ModelVertexUtil.java @@ -0,0 +1,46 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format; + +public class ModelVertexUtil { + /** + * Converts a floating point vertex position in range 0..32 to a de-normalized unsigned short. + * @param value The float in range 0..32 + * @return The resulting de-normalized unsigned short + */ + public static short denormalizeVertexPositionFloatAsShort(float value) { + // Since we're skipping the scaling formerly done in ChunkModelVertexTransformer to preserve precision, this + // method actually takes input unnormalized within the range 0..32, and expands that to 0..65536. + // TODO: Restructure things to be less arbitrary here + return (short) (value * 2048.0f); + } + + /** + * Converts a normalized floating point texture coordinate to a de-normalized unsigned short. + * @param value The normalized float + * @return The resulting de-normalized unsigned short + */ + public static short denormalizeVertexTextureFloatAsShort(float value) { + return (short) (Math.min(0.99999997F, value) * 32768.0f); + } + + /** + * This moves some work out the shader code and simplifies things a bit. In vanilla, the game encodes light map + * texture coordinates as two un-normalized unsigned shorts in the range 0..255. Using the fixed-function pipeline, + * it then applies a matrix transformation which normalizes these coordinates and applies a centering offset. This + * operation has non-zero overhead and complicates shader code a bit. + * + * To work around the problem, this function instead normalizes these light map texture coordinates and applies the + * centering offset, allowing it to be baked into the vertex data itself. + * + * @param light The light map value + * @return The light map texture coordinates as two unsigned shorts with a center offset applied + */ + public static int encodeLightMapTexCoord(int light) { + int sl = (light >> 16) & 255; + sl = (sl << 8) + 2048; + + int bl = light & 255; + bl = (bl << 8) + 2048; + + return (sl << 16) | bl; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterNio.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterNio.java new file mode 100644 index 000000000..b06868e28 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterNio.java @@ -0,0 +1,43 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format.hfp; + +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.render.chunk.format.DefaultModelVertexFormats; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexUtil; + +import java.nio.ByteBuffer; + +public class HFPModelVertexBufferWriterNio extends VertexBufferWriterNio implements ModelVertexSink { + public HFPModelVertexBufferWriterNio(VertexBufferView backingBuffer) { + super(backingBuffer, DefaultModelVertexFormats.MODEL_VERTEX_HFP); + } + + @Override + public void writeQuad(float x, float y, float z, int color, float u, float v, int light) { + this.writeQuadInternal( + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(x), + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(y), + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(z), + color, + ModelVertexUtil.denormalizeVertexTextureFloatAsShort(u), + ModelVertexUtil.denormalizeVertexTextureFloatAsShort(v), + ModelVertexUtil.encodeLightMapTexCoord(light) + ); + } + + private void writeQuadInternal(short x, short y, short z, int color, short u, short v, int light) { + int i = this.writeOffset; + + ByteBuffer buffer = this.byteBuffer; + buffer.putShort(i, x); + buffer.putShort(i + 2, y); + buffer.putShort(i + 4, z); + buffer.putInt(i + 8, color); + buffer.putShort(i + 12, u); + buffer.putShort(i + 14, v); + buffer.putInt(i + 16, light); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..1766b3d01 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java @@ -0,0 +1,42 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format.hfp; + +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.render.chunk.format.DefaultModelVertexFormats; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexUtil; +import org.lwjgl.system.MemoryUtil; + +public class HFPModelVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ModelVertexSink { + public HFPModelVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, DefaultModelVertexFormats.MODEL_VERTEX_HFP); + } + + @Override + public void writeQuad(float x, float y, float z, int color, float u, float v, int light) { + this.writeQuadInternal( + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(x), + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(y), + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(z), + color, + ModelVertexUtil.denormalizeVertexTextureFloatAsShort(u), + ModelVertexUtil.denormalizeVertexTextureFloatAsShort(v), + ModelVertexUtil.encodeLightMapTexCoord(light) + ); + } + + private void writeQuadInternal(short x, short y, short z, int color, short u, short v, int light) { + long i = this.writePointer; + + MemoryUtil.memPutShort(i, x); + MemoryUtil.memPutShort(i + 2, y); + MemoryUtil.memPutShort(i + 4, z); + MemoryUtil.memPutInt(i + 8, color); + MemoryUtil.memPutShort(i + 12, u); + MemoryUtil.memPutShort(i + 14, v); + MemoryUtil.memPutInt(i + 16, light); + + this.advance(); + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java new file mode 100644 index 000000000..884b0b370 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java @@ -0,0 +1,59 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format.hfp; + +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; +import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; +import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; +import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; +import net.minecraft.client.render.VertexConsumer; + +/** + * Uses half-precision floating point numbers to represent position coordinates and normalized unsigned shorts for + * texture coordinates. All texel positions in the block diffuse texture atlas can be exactly mapped (including + * their centering offset), as the + */ +public class HFPModelVertexType implements ChunkVertexType { + public static final GlVertexFormat VERTEX_FORMAT = + GlVertexFormat.builder(ChunkMeshAttribute.class, 20) + .addElement(ChunkMeshAttribute.POSITION, 0, GlVertexAttributeFormat.UNSIGNED_SHORT, 3, false) + .addElement(ChunkMeshAttribute.COLOR, 8, GlVertexAttributeFormat.UNSIGNED_BYTE, 4, true) + .addElement(ChunkMeshAttribute.TEXTURE, 12, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, false) + .addElement(ChunkMeshAttribute.LIGHT, 16, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, true) + .build(); + + + public static final float MODEL_SCALE = (32.0f / 65536.0f); + public static final float TEXTURE_SCALE = (1.0f / 32768.0f); + + @Override + public ModelVertexSink createFallbackWriter(VertexConsumer consumer) { + throw new UnsupportedOperationException(); + } + + @Override + public ModelVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { + return direct ? new HFPModelVertexBufferWriterUnsafe(buffer) : new HFPModelVertexBufferWriterNio(buffer); + } + + @Override + public BlittableVertexType asBlittable() { + return this; + } + + @Override + public GlVertexFormat getCustomVertexFormat() { + return VERTEX_FORMAT; + } + + @Override + public float getModelScale() { + return MODEL_SCALE; + } + + @Override + public float getTextureScale() { + return TEXTURE_SCALE; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterNio.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterNio.java new file mode 100644 index 000000000..9e32a9188 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterNio.java @@ -0,0 +1,52 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format.sfp; + +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.render.chunk.format.DefaultModelVertexFormats; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; + +import java.nio.ByteBuffer; + +public class SFPModelVertexBufferWriterNio extends VertexBufferWriterNio implements ModelVertexSink { + public SFPModelVertexBufferWriterNio(VertexBufferView backingBuffer) { + super(backingBuffer, DefaultModelVertexFormats.MODEL_VERTEX_SFP); + } + + @Override + public void writeQuad(float x, float y, float z, int color, float u, float v, int light) { + int i = this.writeOffset; + + ByteBuffer buffer = this.byteBuffer; + 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, encodeLightMapTexCoord(light)); + + this.advance(); + } + + /** + * This moves some work out the shader code and simplifies things a bit. In vanilla, the game encodes light map + * texture coordinates as two un-normalized unsigned shorts in the range 0..255. Using the fixed-function pipeline, + * it then applies a matrix transformation which normalizes these coordinates and applies a centering offset. This + * operation has non-zero overhead and complicates shader code a bit. + * + * To work around the problem, this function instead normalizes these light map texture coordinates and applies the + * centering offset, allowing it to be baked into the vertex data itself. + * + * @param light The light map value + * @return The light map texture coordinates as two unsigned shorts with a center offset applied + */ + private static int encodeLightMapTexCoord(int light) { + int sl = (light >> 16) & 255; + sl = (sl << 8) + 2048; + + int bl = light & 255; + bl = (bl << 8) + 2048; + + return (sl << 16) | bl; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..510b244f3 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java @@ -0,0 +1,50 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format.sfp; + +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.render.chunk.format.DefaultModelVertexFormats; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; +import org.lwjgl.system.MemoryUtil; + +public class SFPModelVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ModelVertexSink { + public SFPModelVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, DefaultModelVertexFormats.MODEL_VERTEX_SFP); + } + + @Override + public void writeQuad(float x, float y, float z, int color, float u, float v, int light) { + long i = this.writePointer; + + MemoryUtil.memPutFloat(i, x); + MemoryUtil.memPutFloat(i + 4, y); + MemoryUtil.memPutFloat(i + 8, z); + MemoryUtil.memPutInt(i + 12, color); + MemoryUtil.memPutFloat(i + 16, u); + MemoryUtil.memPutFloat(i + 20, v); + MemoryUtil.memPutInt(i + 24, encodeLightMapTexCoord(light)); + + this.advance(); + } + + /** + * This moves some work out the shader code and simplifies things a bit. In vanilla, the game encodes light map + * texture coordinates as two un-normalized unsigned shorts in the range 0..255. Using the fixed-function pipeline, + * it then applies a matrix transformation which normalizes these coordinates and applies a centering offset. This + * operation has non-zero overhead and complicates shader code a bit. + * + * To work around the problem, this function instead normalizes these light map texture coordinates and applies the + * centering offset, allowing it to be baked into the vertex data itself. + * + * @param light The light map value + * @return The light map texture coordinates as two unsigned shorts with a center offset applied + */ + private static int encodeLightMapTexCoord(int light) { + int sl = (light >> 16) & 255; + sl = (sl << 8) + 2048; + + int bl = light & 255; + bl = (bl << 8) + 2048; + + return (sl << 16) | bl; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java new file mode 100644 index 000000000..ddcc12f04 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java @@ -0,0 +1,57 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format.sfp; + +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; +import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; +import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; +import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; +import net.minecraft.client.render.VertexConsumer; + +/** + * Simple vertex format which uses single-precision floating point numbers to represent position and texture + * coordinates. + */ +public class SFPModelVertexType implements ChunkVertexType { + public static final GlVertexFormat VERTEX_FORMAT = + GlVertexFormat.builder(ChunkMeshAttribute.class, 32) + .addElement(ChunkMeshAttribute.POSITION, 0, GlVertexAttributeFormat.FLOAT, 3, false) + .addElement(ChunkMeshAttribute.COLOR, 12, GlVertexAttributeFormat.UNSIGNED_BYTE, 4, true) + .addElement(ChunkMeshAttribute.TEXTURE, 16, GlVertexAttributeFormat.FLOAT, 2, false) + .addElement(ChunkMeshAttribute.LIGHT, 24, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, true) + .build(); + + public static final float MODEL_SCALE = 1.0f; + public static final float TEXTURE_SCALE = 1.0f; + + @Override + public ModelVertexSink createFallbackWriter(VertexConsumer consumer) { + throw new UnsupportedOperationException(); + } + + @Override + public ModelVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { + return direct ? new SFPModelVertexBufferWriterUnsafe(buffer) : new SFPModelVertexBufferWriterNio(buffer); + } + + @Override + public BlittableVertexType asBlittable() { + return this; + } + + @Override + public GlVertexFormat getCustomVertexFormat() { + return VERTEX_FORMAT; + } + + @Override + public float getModelScale() { + return MODEL_SCALE; + } + + @Override + public float getTextureScale() { + return TEXTURE_SCALE; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderList.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderList.java new file mode 100644 index 000000000..bfdaa6f80 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderList.java @@ -0,0 +1,118 @@ +package me.jellysquid.mods.sodium.client.render.chunk.lists; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +import java.util.Arrays; + +/** + * A simple extension over {@link ObjectArrayList} which provides iterator methods in either FIFO or LIFO ordering. + */ +public class ChunkRenderList { + private T[] stateArray; + private int[] cullArray; + private int size, capacity; + + public ChunkRenderList() { + this(1024); + } + + @SuppressWarnings("unchecked") + public ChunkRenderList(int capacity) { + this.size = 0; + this.capacity = capacity; + + this.stateArray = (T[]) new Object[capacity]; + this.cullArray = new int[capacity]; + } + + private void resize() { + this.capacity = this.capacity * 2; + + this.stateArray = Arrays.copyOf(this.stateArray, this.capacity); + this.cullArray = Arrays.copyOf(this.cullArray, this.capacity); + } + + public void add(T state, int cull) { + int idx = this.size++; + + if (idx >= this.capacity) { + this.resize(); + } + + this.stateArray[idx] = state; + this.cullArray[idx] = cull; + } + + public void reset() { + if (this.size == 0) { + return; + } + + for (int i = 0; i < this.size; i++) { + this.stateArray[i] = null; + } + + for (int i = 0; i < this.size; i++) { + this.cullArray[i] = 0; + } + + this.size = 0; + } + + /** + * @return An iterator which returns elements in FIFO order or LIFO order if {@param backwards} is set + */ + public ChunkRenderListIterator iterator(boolean backwards) { + if (backwards) { + return new ChunkRenderListIterator() { + private int pos = ChunkRenderList.this.size - 1; + + @Override + public T getGraphicsState() { + return ChunkRenderList.this.stateArray[this.pos]; + } + + @Override + public int getVisibleFaces() { + return ChunkRenderList.this.cullArray[this.pos]; + } + + @Override + public boolean hasNext() { + return this.pos >= 0; + } + + @Override + public void advance() { + this.pos--; + } + }; + } else { + return new ChunkRenderListIterator() { + private final int lim = ChunkRenderList.this.size; + + private int pos = 0; + + @Override + public T getGraphicsState() { + return ChunkRenderList.this.stateArray[this.pos]; + } + + @Override + public int getVisibleFaces() { + return ChunkRenderList.this.cullArray[this.pos]; + } + + @Override + public boolean hasNext() { + return this.pos < this.lim; + } + + @Override + public void advance() { + this.pos++; + } + }; + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderListIterator.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderListIterator.java new file mode 100644 index 000000000..9dc21f066 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/lists/ChunkRenderListIterator.java @@ -0,0 +1,9 @@ +package me.jellysquid.mods.sodium.client.render.chunk.lists; + +public interface ChunkRenderListIterator { + T getGraphicsState(); + int getVisibleFaces(); + + boolean hasNext(); + void advance(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java new file mode 100644 index 000000000..7531055a0 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java @@ -0,0 +1,35 @@ +package me.jellysquid.mods.sodium.client.render.chunk.passes; + +import net.minecraft.client.render.RenderLayer; + +// TODO: Move away from using an enum, make this extensible +public enum BlockRenderPass { + SOLID(RenderLayer.getSolid(), false), + CUTOUT(RenderLayer.getCutout(), false), + CUTOUT_MIPPED(RenderLayer.getCutoutMipped(), false), + TRANSLUCENT(RenderLayer.getTranslucent(), true), + TRIPWIRE(RenderLayer.getTripwire(), true); + + public static final BlockRenderPass[] VALUES = BlockRenderPass.values(); + public static final int COUNT = VALUES.length; + + private final RenderLayer layer; + private final boolean translucent; + + BlockRenderPass(RenderLayer layer, boolean translucent) { + this.layer = layer; + this.translucent = translucent; + } + + public boolean isTranslucent() { + return this.translucent; + } + + public void endDrawing() { + this.layer.endDrawing(); + } + + public void startDrawing() { + this.layer.startDrawing(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java new file mode 100644 index 000000000..6207e2cb1 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java @@ -0,0 +1,54 @@ +package me.jellysquid.mods.sodium.client.render.chunk.passes; + +import it.unimi.dsi.fastutil.objects.Reference2IntArrayMap; +import net.minecraft.client.render.RenderLayer; + +/** + * Maps vanilla render layers to render passes used by Sodium. This provides compatibility with the render layers already + * used by the base game. + */ +public class BlockRenderPassManager { + private final Reference2IntArrayMap mappingsId = new Reference2IntArrayMap<>(); + + public BlockRenderPassManager() { + this.mappingsId.defaultReturnValue(-1); + } + + public int getRenderPassId(RenderLayer layer) { + int pass = this.mappingsId.getInt(layer); + + if (pass < 0) { + throw new NullPointerException("No render pass exists for layer: " + layer); + } + + return pass; + } + + private void addMapping(RenderLayer layer, BlockRenderPass type) { + if (this.mappingsId.put(layer, type.ordinal()) >= 0) { + throw new IllegalArgumentException("Layer target already defined for " + layer); + } + } + + /** + * Creates a set of render pass mappings to vanilla render layers which closely mirrors the rendering + * behavior of vanilla. + */ + public static BlockRenderPassManager createDefaultMappings() { + BlockRenderPassManager mapper = new BlockRenderPassManager(); + mapper.addMapping(RenderLayer.getSolid(), BlockRenderPass.SOLID); + mapper.addMapping(RenderLayer.getCutoutMipped(), BlockRenderPass.CUTOUT_MIPPED); + mapper.addMapping(RenderLayer.getCutout(), BlockRenderPass.CUTOUT); + mapper.addMapping(RenderLayer.getTranslucent(), BlockRenderPass.TRANSLUCENT); + mapper.addMapping(RenderLayer.getTripwire(), BlockRenderPass.TRIPWIRE); + + return mapper; + } + public BlockRenderPass getRenderPassForLayer(RenderLayer layer) { + return this.getRenderPass(this.getRenderPassId(layer)); + } + + public BlockRenderPass getRenderPass(int i) { + return BlockRenderPass.VALUES[i]; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegion.java new file mode 100644 index 000000000..8e73b037f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegion.java @@ -0,0 +1,78 @@ +package me.jellysquid.mods.sodium.client.render.chunk.region; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import me.jellysquid.mods.sodium.client.gl.arena.GlBufferArena; +import me.jellysquid.mods.sodium.client.gl.device.CommandList; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; +import me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw.ChunkDrawCallBatcher; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; + +public class ChunkRegion { + private static final int EXPECTED_CHUNK_SIZE = 4 * 1024; + + private final GlBufferArena arena; + private final ChunkDrawCallBatcher batch; + private final RenderDevice device; + + private final ObjectArrayList> uploadQueue; + + private GlTessellation tessellation; + + public final int x, y, z; + + public float camDistance; + + public ChunkRegion(RenderDevice device, int size, int x, int y, int z) { + int arenaSize = EXPECTED_CHUNK_SIZE * size; + + this.device = device; + this.arena = new GlBufferArena(device, arenaSize, arenaSize); + this.uploadQueue = new ObjectArrayList<>(); + + this.batch = ChunkDrawCallBatcher.create(size * ModelQuadFacing.COUNT); + + this.x = x; + this.y = y; + this.z = z; + } + + public GlBufferArena getBufferArena() { + return this.arena; + } + + public boolean isArenaEmpty() { + return this.arena.isEmpty(); + } + + public void deleteResources() { + if (this.tessellation != null) { + try (CommandList commands = this.device.createCommandList()) { + commands.deleteTessellation(this.tessellation); + } + + this.tessellation = null; + } + + this.arena.delete(); + this.batch.delete(); + } + + public ObjectArrayList> getUploadQueue() { + return this.uploadQueue; + } + + public ChunkDrawCallBatcher getDrawBatcher() { + return this.batch; + } + + public GlTessellation getTessellation() { + return this.tessellation; + } + + public void setTessellation(GlTessellation tessellation) { + this.tessellation = tessellation; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java new file mode 100644 index 000000000..72ae14f5f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java @@ -0,0 +1,78 @@ +package me.jellysquid.mods.sodium.client.render.chunk.region; + +import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; +import me.jellysquid.mods.sodium.client.util.MathUtil; +import net.minecraft.util.math.ChunkSectionPos; +import org.apache.commons.lang3.Validate; + +public class ChunkRegionManager { + public static final int BUFFER_WIDTH = 8; + public static final int BUFFER_HEIGHT = 4; + public static final int BUFFER_LENGTH = 8; + + public static final int BUFFER_SIZE = BUFFER_WIDTH * BUFFER_HEIGHT * BUFFER_LENGTH; + + private static final int BUFFER_WIDTH_SH = Integer.bitCount(BUFFER_WIDTH - 1); + private static final int BUFFER_HEIGHT_SH = Integer.bitCount(BUFFER_HEIGHT - 1); + private static final int BUFFER_LENGTH_SH = Integer.bitCount(BUFFER_LENGTH - 1); + + static { + Validate.isTrue(MathUtil.isPowerOfTwo(BUFFER_WIDTH)); + Validate.isTrue(MathUtil.isPowerOfTwo(BUFFER_LENGTH)); + Validate.isTrue(MathUtil.isPowerOfTwo(BUFFER_HEIGHT)); + } + + private final Long2ReferenceOpenHashMap> regions = new Long2ReferenceOpenHashMap<>(); + private final RenderDevice device; + + public ChunkRegionManager(RenderDevice device) { + this.device = device; + } + + public ChunkRegion getRegion(int x, int y, int z) { + return this.regions.get(getRegionKey(x, y, z)); + } + + public ChunkRegion getOrCreateRegion(int x, int y, int z) { + long key = getRegionKey(x, y, z); + + ChunkRegion region = this.regions.get(key); + + if (region == null) { + this.regions.put(key, region = new ChunkRegion<>(this.device, BUFFER_SIZE, x, y, z)); + } + + return region; + } + + public static long getRegionKey(int x, int y, int z) { + return ChunkSectionPos.asLong(x >> BUFFER_WIDTH_SH, y >> BUFFER_HEIGHT_SH, z >> BUFFER_LENGTH_SH); + } + + public void delete() { + for (ChunkRegion region : this.regions.values()) { + region.deleteResources(); + } + + this.regions.clear(); + } + + public void cleanup() { + for (ObjectIterator> iterator = this.regions.values().iterator(); iterator.hasNext(); ) { + ChunkRegion region = iterator.next(); + + if (region.isArenaEmpty()) { + region.deleteResources(); + + iterator.remove(); + } + } + } + + public int getAllocatedRegionCount() { + return this.regions.size(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkFogMode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkFogMode.java new file mode 100644 index 000000000..1e81e0444 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkFogMode.java @@ -0,0 +1,28 @@ +package me.jellysquid.mods.sodium.client.render.chunk.shader; + +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.function.Function; + +public enum ChunkFogMode { + NONE(ChunkShaderFogComponent.None::new, ImmutableList.of()), + LINEAR(ChunkShaderFogComponent.Linear::new, ImmutableList.of("USE_FOG", "USE_FOG_LINEAR")), + EXP2(ChunkShaderFogComponent.Exp2::new, ImmutableList.of("USE_FOG", "USE_FOG_EXP2")); + + private final Function factory; + private final List defines; + + ChunkFogMode(Function factory, List defines) { + this.factory = factory; + this.defines = defines; + } + + public Function getFactory() { + return this.factory; + } + + public List getDefines() { + return this.defines; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java new file mode 100644 index 000000000..18c81eb39 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java @@ -0,0 +1,55 @@ +package me.jellysquid.mods.sodium.client.render.chunk.shader; + +import com.mojang.blaze3d.platform.GlStateManager; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; +import me.jellysquid.mods.sodium.client.render.GameRendererContext; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Identifier; +import org.lwjgl.opengl.GL20C; +import org.lwjgl.system.MemoryStack; + +import java.util.function.Function; + +/** + * A forward-rendering shader program for chunks. + */ +public class ChunkProgram extends GlProgram { + // Uniform variable binding indexes + private final int uModelViewProjectionMatrix; + private final int uModelScale; + private final int uTextureScale; + private final int uBlockTex; + private final int uLightTex; + + // The fog shader component used by this program in order to setup the appropriate GL state + private final ChunkShaderFogComponent fogShader; + + protected ChunkProgram(RenderDevice owner, Identifier name, int handle, Function fogShaderFunction) { + super(owner, name, handle); + + this.uModelViewProjectionMatrix = this.getUniformLocation("u_ModelViewProjectionMatrix"); + + this.uBlockTex = this.getUniformLocation("u_BlockTex"); + this.uLightTex = this.getUniformLocation("u_LightTex"); + this.uModelScale = this.getUniformLocation("u_ModelScale"); + this.uTextureScale = this.getUniformLocation("u_TextureScale"); + + this.fogShader = fogShaderFunction.apply(this); + } + + public void setup(MatrixStack matrixStack, float modelScale, float textureScale) { + GlStateManager.uniform1(this.uBlockTex, 0); + GlStateManager.uniform1(this.uLightTex, 2); + + GL20C.glUniform3f(this.uModelScale, modelScale, modelScale, modelScale); + GL20C.glUniform2f(this.uTextureScale, textureScale, textureScale); + + this.fogShader.setup(); + + try (MemoryStack memoryStack = MemoryStack.stackPush()) { + GlStateManager.uniformMatrix4(this.uModelViewProjectionMatrix, false, + GameRendererContext.getModelViewProjectionMatrix(matrixStack.peek(), memoryStack)); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java new file mode 100644 index 000000000..92762ae07 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java @@ -0,0 +1,87 @@ +package me.jellysquid.mods.sodium.client.render.chunk.shader; + +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; +import me.jellysquid.mods.sodium.client.gl.compat.FogHelper; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; +import me.jellysquid.mods.sodium.client.gl.shader.GlShader; +import me.jellysquid.mods.sodium.client.gl.shader.ShaderLoader; +import me.jellysquid.mods.sodium.client.gl.shader.ShaderType; +import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; +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.format.ChunkMeshAttribute; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Identifier; + +import java.util.EnumMap; + +public abstract class ChunkRenderShaderBackend + implements ChunkRenderBackend { + private final EnumMap programs = new EnumMap<>(ChunkFogMode.class); + + protected final ChunkVertexType vertexType; + protected final GlVertexFormat vertexFormat; + + protected ChunkProgram activeProgram; + + public ChunkRenderShaderBackend(ChunkVertexType vertexType) { + this.vertexType = vertexType; + this.vertexFormat = vertexType.getCustomVertexFormat(); + } + + private ChunkProgram createShader(RenderDevice device, ChunkFogMode fogMode, GlVertexFormat vertexFormat) { + GlShader vertShader = ShaderLoader.loadShader(device, ShaderType.VERTEX, + new Identifier("sodium", "chunk_gl20.v.glsl"), fogMode.getDefines()); + + GlShader fragShader = ShaderLoader.loadShader(device, ShaderType.FRAGMENT, + new Identifier("sodium", "chunk_gl20.f.glsl"), fogMode.getDefines()); + + try { + return GlProgram.builder(new Identifier("sodium", "chunk_shader")) + .attachShader(vertShader) + .attachShader(fragShader) + .bindAttribute("a_Pos", ChunkShaderBindingPoints.POSITION) + .bindAttribute("a_Color", ChunkShaderBindingPoints.COLOR) + .bindAttribute("a_TexCoord", ChunkShaderBindingPoints.TEX_COORD) + .bindAttribute("a_LightCoord", ChunkShaderBindingPoints.LIGHT_COORD) + .bindAttribute("d_ModelOffset", ChunkShaderBindingPoints.MODEL_OFFSET) + .build((program, name) -> new ChunkProgram(device, program, name, fogMode.getFactory())); + } finally { + vertShader.delete(); + fragShader.delete(); + } + } + + @Override + public final void createShaders(RenderDevice device) { + this.programs.put(ChunkFogMode.NONE, this.createShader(device, ChunkFogMode.NONE, this.vertexFormat)); + this.programs.put(ChunkFogMode.LINEAR, this.createShader(device, ChunkFogMode.LINEAR, this.vertexFormat)); + this.programs.put(ChunkFogMode.EXP2, this.createShader(device, ChunkFogMode.EXP2, this.vertexFormat)); + } + + @Override + public void begin(MatrixStack matrixStack) { + this.activeProgram = this.programs.get(FogHelper.getFogMode()); + this.activeProgram.bind(); + this.activeProgram.setup(matrixStack, this.vertexType.getModelScale(), this.vertexType.getTextureScale()); + } + + @Override + public void end(MatrixStack matrixStack) { + this.activeProgram.unbind(); + this.activeProgram = null; + } + + @Override + public void delete() { + for (ChunkProgram shader : this.programs.values()) { + shader.delete(); + } + } + + @Override + public ChunkVertexType getVertexType() { + return this.vertexType; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java new file mode 100644 index 000000000..9b1b6d3d6 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java @@ -0,0 +1,12 @@ +package me.jellysquid.mods.sodium.client.render.chunk.shader; + +import me.jellysquid.mods.sodium.client.gl.shader.ShaderBindingPoint; + +public class ChunkShaderBindingPoints { + public static final ShaderBindingPoint POSITION = new ShaderBindingPoint(0); + public static final ShaderBindingPoint COLOR = new ShaderBindingPoint(1); + public static final ShaderBindingPoint TEX_COORD = new ShaderBindingPoint(2); + public static final ShaderBindingPoint LIGHT_COORD = new ShaderBindingPoint(3); + + public static final ShaderBindingPoint MODEL_OFFSET = new ShaderBindingPoint(4); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java new file mode 100644 index 000000000..bc9c1392d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java @@ -0,0 +1,69 @@ +package me.jellysquid.mods.sodium.client.render.chunk.shader; + +import me.jellysquid.mods.sodium.client.gl.compat.FogHelper; +import org.lwjgl.opengl.GL20C; + +/** + * These shader implementations try to remain compatible with the deprecated fixed function pipeline by manually + * copying the state into each shader's uniforms. The shader code itself is a straight-forward implementation of the + * fog functions themselves from the fixed-function pipeline, except that they use the distance from the camera + * rather than the z-buffer to produce better looking fog that doesn't move with the player's view angle. + * + * Minecraft itself will actually try to enable distance-based fog by using the proprietary NV_fog_distance extension, + * but as the name implies, this only works on graphics cards produced by NVIDIA. The shader implementation however does + * not depend on any vendor-specific extensions and is written using very simple GLSL code. + */ +public abstract class ChunkShaderFogComponent { + public abstract void setup(); + + public static class None extends ChunkShaderFogComponent { + public None(ChunkProgram program) { + + } + + @Override + public void setup() { + + } + } + + public static class Exp2 extends ChunkShaderFogComponent { + private final int uFogColor; + private final int uFogDensity; + + public Exp2(ChunkProgram program) { + this.uFogColor = program.getUniformLocation("u_FogColor"); + this.uFogDensity = program.getUniformLocation("u_FogDensity"); + } + + @Override + public void setup() { + GL20C.glUniform4fv(this.uFogColor, FogHelper.getFogColor()); + GL20C.glUniform1f(this.uFogDensity, FogHelper.getFogDensity()); + } + } + + public static class Linear extends ChunkShaderFogComponent { + private final int uFogColor; + private final int uFogLength; + private final int uFogEnd; + + public Linear(ChunkProgram program) { + this.uFogColor = program.getUniformLocation("u_FogColor"); + this.uFogLength = program.getUniformLocation("u_FogLength"); + this.uFogEnd = program.getUniformLocation("u_FogEnd"); + } + + @Override + public void setup() { + float end = FogHelper.getFogEnd(); + float start = FogHelper.getFogStart(); + float[] color = FogHelper.getFogColor(); + + GL20C.glUniform4fv(this.uFogColor, color); + GL20C.glUniform1f(this.uFogLength, end - start); + GL20C.glUniform1f(this.uFogEnd, end); + } + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderBuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderBuildTask.java new file mode 100644 index 000000000..3bd799cdb --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderBuildTask.java @@ -0,0 +1,40 @@ +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.compile.ChunkBuildBuffers; +import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; +import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheLocal; +import me.jellysquid.mods.sodium.client.util.task.CancellationSource; + +/** + * Build tasks are immutable jobs (with optional prioritization) which contain all the necessary state to perform + * chunk mesh updates or quad sorting off the main thread. + * + * When a task is constructed on the main thread, it should copy all the state it requires in order to complete the task + * without further synchronization. The task will then be scheduled for async execution on a thread pool. + * + * After the task completes, it returns a "build result" which contains any computed data that needs to be handled + * on the main thread. + * + * @param The graphics state of the chunk render + */ +public abstract class ChunkRenderBuildTask { + /** + * Executes the given build task asynchronously from the calling thread. The implementation should be careful not + * to access or modify global mutable state. + * + * @param cache The render cache to use for building this chunk + * @param buffers The temporary scratch buffers for rendering block data + * @param cancellationSource The cancellation source which can be used to query if the task is cancelled + * @return The build result of this task, containing any data which needs to be uploaded on the main-thread, or null + * if the task was cancelled. + */ + public abstract ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildBuffers buffers, + CancellationSource cancellationSource); + + /** + * Called on the main render thread when the task's execution returns. The implementation should release any + * resources it's still holding onto at this point. + */ + public abstract void releaseResources(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderEmptyBuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderEmptyBuildTask.java new file mode 100644 index 000000000..b91532f62 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderEmptyBuildTask.java @@ -0,0 +1,33 @@ +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 extends ChunkRenderBuildTask { + private final ChunkRenderContainer render; + + public ChunkRenderEmptyBuildTask(ChunkRenderContainer render) { + this.render = render; + } + + @Override + public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildBuffers buffers, CancellationSource cancellationSource) { + return new ChunkBuildResult<>(this.render, ChunkRenderData.EMPTY); + } + + @Override + public void releaseResources() { + + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java new file mode 100644 index 000000000..1ae270cbc --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -0,0 +1,193 @@ +package me.jellysquid.mods.sodium.client.render.chunk.tasks; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.compat.FlywheelCompat; +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.ChunkMeshData; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderBounds; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheLocal; +import me.jellysquid.mods.sodium.client.util.task.CancellationSource; +import me.jellysquid.mods.sodium.client.world.WorldSlice; +import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.RenderLayers; +import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; +import net.minecraft.client.render.block.entity.BlockEntityRenderer; +import net.minecraft.client.render.chunk.ChunkOcclusionDataBuilder; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.fluid.FluidState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.ModelDataManager; +import net.minecraftforge.client.model.data.EmptyModelData; +import net.minecraftforge.client.model.data.IModelData; + +import java.util.Map; + +/** + * Rebuilds all the meshes of a chunk for each given render pass with non-occluded blocks. The result is then uploaded + * to graphics memory on the main thread. + * + * This task takes a slice of the world from the thread it is created on. Since these slices require rather large + * array allocations, they are pooled to ensure that the garbage collector doesn't become overloaded. + */ +public class ChunkRenderRebuildTask extends ChunkRenderBuildTask { + private final ChunkRenderContainer render; + + private final BlockPos offset; + + private final ChunkRenderContext context; + + private final Map modelDataMap; + + private Vec3d camera; + + private final boolean translucencySorting; + + public ChunkRenderRebuildTask(ChunkRenderContainer render, ChunkRenderContext context, BlockPos offset) { + this.render = render; + this.offset = offset; + this.context = context; + this.camera = Vec3d.ZERO; + this.translucencySorting = SodiumClientMod.options().advanced.translucencySorting; + + this.modelDataMap = ModelDataManager.getModelData(MinecraftClient.getInstance().world, new ChunkPos(ChunkSectionPos.getSectionCoord(this.render.getOriginX()), ChunkSectionPos.getSectionCoord(this.render.getOriginZ()))); + } + + public ChunkRenderRebuildTask withCameraPosition(Vec3d camera) { + this.camera = camera; + return this; + } + + @Override + public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildBuffers buffers, CancellationSource cancellationSource) { + // COMPATIBLITY NOTE: Oculus relies on the LVT of this method being unchanged, at least in 16.5 + ChunkRenderData.Builder renderData = new ChunkRenderData.Builder(); + ChunkOcclusionDataBuilder occluder = new ChunkOcclusionDataBuilder(); + ChunkRenderBounds.Builder bounds = new ChunkRenderBounds.Builder(); + + buffers.init(renderData); + + cache.init(this.context); + + WorldSlice slice = cache.getWorldSlice(); + + int baseX = this.render.getOriginX(); + int baseY = this.render.getOriginY(); + int baseZ = this.render.getOriginZ(); + + BlockPos.Mutable pos = new BlockPos.Mutable(); + BlockPos renderOffset = this.offset; + + for (int relY = 0; relY < 16; relY++) { + if (cancellationSource.isCancelled()) { + return null; + } + + for (int relZ = 0; relZ < 16; relZ++) { + for (int relX = 0; relX < 16; relX++) { + BlockState blockState = slice.getBlockStateRelative(relX + 16, relY + 16, relZ + 16); + + if (blockState.isAir()) { + continue; + } + + // TODO: commit this separately + pos.set(baseX + relX, baseY + relY, baseZ + relZ); + buffers.setRenderOffset(pos.getX() - renderOffset.getX(), pos.getY() - renderOffset.getY(), pos.getZ() - renderOffset.getZ()); + + if (blockState.getRenderType() == BlockRenderType.MODEL) { + for (RenderLayer layer : RenderLayer.getBlockLayers()) { + if (!RenderLayers.canRenderInLayer(blockState, layer)) { + continue; + } + + ForgeHooksClient.setRenderLayer(layer); + IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); + + BakedModel model = cache.getBlockModels() + .getModel(blockState); + + long seed = blockState.getRenderingSeed(pos); + + if (cache.getBlockRenderer().renderModel(cache.getLocalSlice(), blockState, pos, model, buffers.get(layer), true, seed, modelData)) { + bounds.addBlock(relX, relY, relZ); + } + + } + } + + FluidState fluidState = blockState.getFluidState(); + + if (!fluidState.isEmpty()) { + for (RenderLayer layer : RenderLayer.getBlockLayers()) { + if (!RenderLayers.canRenderInLayer(fluidState, layer)) { + continue; + } + + ForgeHooksClient.setRenderLayer(layer); + + if (cache.getFluidRenderer().render(cache.getLocalSlice(), fluidState, pos, buffers.get(layer))) { + bounds.addBlock(relX, relY, relZ); + } + } + } + + if (blockState.hasTileEntity()) { + BlockEntity entity = slice.getBlockEntity(pos); + + if (entity != null) { + BlockEntityRenderer renderer = BlockEntityRenderDispatcher.INSTANCE.get(entity); + + if (renderer != null) { + if (!FlywheelCompat.isSkipped(entity)) + renderData.addBlockEntity(entity, !renderer.rendersOutsideBoundingBox(entity)); + + bounds.addBlock(relX, relY, relZ); + } + } + } + + if (blockState.isOpaqueFullCube(slice, pos)) { + occluder.markClosed(pos); + } + } + } + } + + ForgeHooksClient.setRenderLayer(null); + + render.setRebuildForTranslucents(false); + for (BlockRenderPass pass : BlockRenderPass.VALUES) { + ChunkMeshData mesh = buffers.createMesh(pass, (float)camera.x - offset.getX(), (float)camera.y - offset.getY(), (float)camera.z - offset.getZ(), this.translucencySorting); + + if (mesh != null) { + renderData.setMesh(pass, mesh); + if(this.translucencySorting && pass.isTranslucent()) + render.setRebuildForTranslucents(true); + } + } + + renderData.setOcclusionData(occluder.build()); + renderData.setBounds(bounds.build(this.render.getChunkPos())); + + return new ChunkBuildResult<>(this.render, renderData.build()); + } + + @Override + public void releaseResources() { + this.context.releaseResources(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java new file mode 100644 index 000000000..13f7fad63 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java @@ -0,0 +1,92 @@ +package me.jellysquid.mods.sodium.client.render.chunk.tasks; + +import me.jellysquid.mods.sodium.client.gl.buffer.VertexData; +import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +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.ChunkBufferSorter; +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.ChunkMeshData; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheLocal; +import me.jellysquid.mods.sodium.client.util.task.CancellationSource; +import net.minecraft.client.util.GlAllocationUtils; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * Handles sorting translucency data in built chunks. + */ +public class ChunkRenderTranslucencySortTask extends ChunkRenderBuildTask { + private static final BlockRenderPass[] TRANSLUCENT_PASSES = Arrays.stream(BlockRenderPass.VALUES).filter(BlockRenderPass::isTranslucent).toArray(BlockRenderPass[]::new); + + private final ChunkRenderContainer render; + private final BlockPos offset; + private final Vec3d camera; + + public ChunkRenderTranslucencySortTask(ChunkRenderContainer render, BlockPos offset, Vec3d camera) { + this.render = render; + this.offset = offset; + this.camera = camera; + + } + + + @Override + public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildBuffers buffers, CancellationSource cancellationSource) { + ChunkRenderData data = this.render.getData(); + if(data.isEmpty()) + return null; + + Map replacementMeshes = new HashMap<>(); + for(BlockRenderPass pass : TRANSLUCENT_PASSES) { + ChunkGraphicsState state = this.render.getGraphicsState(pass); + if(state == null) + continue; + ByteBuffer translucencyData = state.getTranslucencyData(); + if(translucencyData == null) + continue; + ChunkMeshData translucentMesh = data.getMesh(pass); + if(translucentMesh == null) + continue; + + // Make a snapshot of the translucency data to sort + ByteBuffer sortedData = GlAllocationUtils.allocateByteBuffer(translucencyData.capacity()); + synchronized (translucencyData) { + sortedData.put(translucencyData); + translucencyData.position(0); + translucencyData.limit(translucencyData.capacity()); + } + + sortedData.flip(); + // Sort it and create the new mesh + ChunkBufferSorter.sortStandardFormat(buffers.getVertexType(), sortedData, sortedData.capacity(), (float) camera.x - offset.getX(), (float)camera.y - offset.getY(), (float)camera.z - offset.getZ()); + ChunkMeshData newMesh = new ChunkMeshData(); + newMesh.setVertexData(new VertexData(sortedData, buffers.getVertexType().getCustomVertexFormat())); + for(Map.Entry entry : translucentMesh.getSlices()) { + newMesh.setModelSlice(entry.getKey(), entry.getValue()); + } + replacementMeshes.put(pass, newMesh); + } + + if(replacementMeshes.isEmpty()) + return null; + + ChunkBuildResult result = new ChunkBuildResult<>(this.render, data.copyAndReplaceMesh(replacementMeshes)); + result.passesToUpload = replacementMeshes.keySet().toArray(new BlockRenderPass[0]); + return result; + } + + @Override + public void releaseResources() { + + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/entity/EntityLightSampler.java b/src/main/java/me/jellysquid/mods/sodium/client/render/entity/EntityLightSampler.java new file mode 100644 index 000000000..34b6de495 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/entity/EntityLightSampler.java @@ -0,0 +1,10 @@ +package me.jellysquid.mods.sodium.client.render.entity; + +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; + +public interface EntityLightSampler { + int bridge$getBlockLight(T entity, BlockPos pos); + + int bridge$getSkyLight(T entity, BlockPos pos); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java b/src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java new file mode 100644 index 000000000..31c53e720 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java @@ -0,0 +1,136 @@ +package me.jellysquid.mods.sodium.client.render.occlusion; + +import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap; +import net.minecraft.block.BlockState; +import net.minecraft.util.function.BooleanBiFunction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; +import net.minecraft.world.BlockView; + +public class BlockOcclusionCache { + private static final byte UNCACHED_VALUE = (byte) 127; + + private final Object2ByteLinkedOpenHashMap map; + private final CachedOcclusionShapeTest cachedTest = new CachedOcclusionShapeTest(); + private final BlockPos.Mutable cpos = new BlockPos.Mutable(); + + public BlockOcclusionCache() { + this.map = new Object2ByteLinkedOpenHashMap<>(2048, 0.5F); + this.map.defaultReturnValue(UNCACHED_VALUE); + } + + /** + * @param selfState The state of the block in the world + * @param view The world view for this render context + * @param pos The position of the block + * @param facing The facing direction of the side to check + * @return True if the block side facing {@param dir} is not occluded, otherwise false + */ + public boolean shouldDrawSide(BlockState selfState, BlockView view, BlockPos pos, Direction facing) { + BlockPos.Mutable adjPos = this.cpos; + adjPos.set(pos.getX() + facing.getOffsetX(), pos.getY() + facing.getOffsetY(), pos.getZ() + facing.getOffsetZ()); + + BlockState adjState = view.getBlockState(adjPos); + + if (selfState.isSideInvisible(adjState, facing)) { + return false; + } else if (adjState.isOpaque()) { + VoxelShape selfShape = selfState.getCullingFace(view, pos, facing); + VoxelShape adjShape = adjState.getCullingFace(view, adjPos, facing.getOpposite()); + + if (selfShape == VoxelShapes.fullCube() && adjShape == VoxelShapes.fullCube()) { + return false; + } + + if (selfShape.isEmpty()) { + // Upstream Sodium only returns true under stricter conditions than this, in order to cull faces in + // unusual block arrangements like a potted cacti under a solid block. + // However, that fix has the side effect of causing block models with improperly specified cullfaces + // to not render sometimes, and also breaks powder snow culling on 1.17+. + // It's not clear that the stricter check provides a significant performance uplift, so we err + // on the side of compatibility and use the same weaker check as vanilla. + return true; + /* + if (adjShape.isEmpty()){ + return true; //example: top face of potted plants if top slab is placed above + } + else if (!adjState.isSideSolid(view,adjPos,facing.getOpposite(), SideShapeType.FULL)){ + return true; //example: face of potted plants rendered if top stair placed above + } + */ + } + + return this.calculate(selfShape, adjShape); + } else { + return true; + } + } + + private boolean calculate(VoxelShape selfShape, VoxelShape adjShape) { + CachedOcclusionShapeTest cache = this.cachedTest; + cache.a = selfShape; + cache.b = adjShape; + cache.updateHash(); + + byte cached = this.map.getByte(cache); + + if (cached != UNCACHED_VALUE) { + return cached == 1; + } + + boolean ret = VoxelShapes.matchesAnywhere(selfShape, adjShape, BooleanBiFunction.ONLY_FIRST); + + this.map.put(cache.copy(), (byte) (ret ? 1 : 0)); + + if (this.map.size() > 2048) { + this.map.removeLastByte(); + } + + return ret; + } + + private static final class CachedOcclusionShapeTest { + private VoxelShape a, b; + private int hashCode; + + private CachedOcclusionShapeTest() { + + } + + private CachedOcclusionShapeTest(VoxelShape a, VoxelShape b, int hashCode) { + this.a = a; + this.b = b; + this.hashCode = hashCode; + } + + public void updateHash() { + int result = System.identityHashCode(this.a); + result = 31 * result + System.identityHashCode(this.b); + + this.hashCode = result; + } + + public CachedOcclusionShapeTest copy() { + return new CachedOcclusionShapeTest(this.a, this.b, this.hashCode); + } + + @Override + public boolean equals(Object o) { + if (o instanceof CachedOcclusionShapeTest) { + CachedOcclusionShapeTest that = (CachedOcclusionShapeTest) o; + + return this.a == that.a && + this.b == that.b; + } + + return false; + } + + @Override + public int hashCode() { + return this.hashCode; + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java new file mode 100644 index 000000000..a63fb8227 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -0,0 +1,207 @@ +package me.jellysquid.mods.sodium.client.render.pipeline; + +import codechicken.lib.render.block.ICCBlockRenderer; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.compat.ccl.CCLCompat; +import me.jellysquid.mods.sodium.client.compat.ccl.SinkingVertexBuilder; +import me.jellysquid.mods.sodium.client.compat.forge.ForgeBlockRenderer; +import me.jellysquid.mods.sodium.client.model.light.LightMode; +import me.jellysquid.mods.sodium.client.model.light.LightPipeline; +import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; +import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadOrientation; +import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; +import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; +import me.jellysquid.mods.sodium.client.render.occlusion.BlockOcclusionCache; +import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; +import me.jellysquid.mods.sodium.client.world.biome.BlockColorsExtended; +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.color.block.BlockColorProvider; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.BlockRenderView; +import net.minecraftforge.client.model.data.IModelData; + +import java.util.List; +import java.util.Random; + +public class BlockRenderer { + private static final MatrixStack EMPTY_STACK = new MatrixStack(); + + private final Random random = new XoRoShiRoRandom(); + + private final BlockColorsExtended blockColors; + private final BlockOcclusionCache occlusionCache; + + private final QuadLightData cachedQuadLightData = new QuadLightData(); + + private final ForgeBlockRenderer forgeBlockRenderer = new ForgeBlockRenderer(); + + private final BiomeColorBlender biomeColorBlender; + private final LightPipelineProvider lighters; + + private final boolean useAmbientOcclusion; + + public BlockRenderer(MinecraftClient client, LightPipelineProvider lighters, BiomeColorBlender biomeColorBlender) { + this.blockColors = (BlockColorsExtended) client.getBlockColors(); + this.biomeColorBlender = biomeColorBlender; + + this.lighters = lighters; + + this.occlusionCache = new BlockOcclusionCache(); + this.useAmbientOcclusion = MinecraftClient.isAmbientOcclusionEnabled(); + } + + public boolean renderModel(BlockRenderView world, BlockState state, BlockPos pos, BakedModel model, ChunkModelBuffers buffers, boolean cull, long seed, IModelData modelData) { + LightMode mode = this.getLightingMode(state, model, world, pos); + LightPipeline lighter = this.lighters.getLighter(mode); + Vec3d offset = state.getModelOffset(world, pos); + + boolean rendered = false; + + modelData = model.getModelData(world, pos, state, modelData); + + if(SodiumClientMod.cclLoaded) { + final MatrixStack mStack = new MatrixStack(); + final SinkingVertexBuilder builder = SinkingVertexBuilder.getInstance(); + for (final ICCBlockRenderer renderer : CCLCompat.getCustomRenderers(world, pos)) { + if (renderer.canHandleBlock(world, pos, state)) { + mStack.isEmpty(); + + builder.reset(); + rendered = renderer.renderBlock(state, pos, world, mStack, builder, random, modelData); + builder.flush(buffers); + + return rendered; + } + } + } + + if(ForgeBlockRenderer.useForgeLightingPipeline()) { + MatrixStack mStack; + if(offset != Vec3d.ZERO) { + mStack = new MatrixStack(); + mStack.translate(offset.x, offset.y, offset.z); + } else + mStack = EMPTY_STACK; + final SinkingVertexBuilder builder = SinkingVertexBuilder.getInstance(); + builder.reset(); + rendered = forgeBlockRenderer.renderBlock(mode, state, pos, world, model, mStack, builder, random, seed, modelData, cull, this.occlusionCache, buffers.getRenderData()); + builder.flush(buffers); + return rendered; + } + + for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + this.random.setSeed(seed); + + List sided = model.getQuads(state, dir, this.random, modelData); + + if (sided.isEmpty()) { + continue; + } + + if (!cull || this.occlusionCache.shouldDrawSide(state, world, pos, dir)) { + this.renderQuadList(world, state, pos, lighter, offset, buffers, sided, dir); + + rendered = true; + } + } + + this.random.setSeed(seed); + + List all = model.getQuads(state, null, this.random, modelData); + + if (!all.isEmpty()) { + this.renderQuadList(world, state, pos, lighter, offset, buffers, all, null); + + rendered = true; + } + + return rendered; + } + + private void renderQuadList(BlockRenderView world, BlockState state, BlockPos pos, LightPipeline lighter, Vec3d offset, + ChunkModelBuffers buffers, List quads, Direction cullFace) { + ModelQuadFacing facing = cullFace == null ? ModelQuadFacing.UNASSIGNED : ModelQuadFacing.fromDirection(cullFace); + BlockColorProvider colorizer = null; + + ModelVertexSink sink = buffers.getSink(facing); + sink.ensureCapacity(quads.size() * 4); + + ChunkRenderData.Builder renderData = buffers.getRenderData(); + + // This is a very hot allocation, iterate over it manually + // noinspection ForLoopReplaceableByForEach + for (int i = 0, quadsSize = quads.size(); i < quadsSize; i++) { + BakedQuad quad = quads.get(i); + + QuadLightData light = this.cachedQuadLightData; + lighter.calculate((ModelQuadView) quad, pos, light, cullFace, quad.getFace(), quad.hasShade()); + + if (quad.hasColor() && colorizer == null) { + colorizer = this.blockColors.getColorProvider(state); + } + + this.renderQuad(world, state, pos, sink, offset, colorizer, quad, light, renderData); + } + + sink.flush(); + } + + private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, ModelVertexSink sink, Vec3d offset, + BlockColorProvider colorProvider, BakedQuad bakedQuad, QuadLightData light, ChunkRenderData.Builder renderData) { + ModelQuadView src = (ModelQuadView) bakedQuad; + + ModelQuadOrientation order = ModelQuadOrientation.orient(light.br); + + int[] colors = null; + + if (bakedQuad.hasColor()) { + colors = this.biomeColorBlender.getColors(colorProvider, world, state, pos, src); + } + + for (int dstIndex = 0; dstIndex < 4; dstIndex++) { + int srcIndex = order.getVertexIndex(dstIndex); + + float x = src.getX(srcIndex) + (float) offset.getX(); + float y = src.getY(srcIndex) + (float) offset.getY(); + float z = src.getZ(srcIndex) + (float) offset.getZ(); + + int color = ColorABGR.mul(colors != null ? colors[srcIndex] : src.getColor(srcIndex), light.br[srcIndex]); + + float u = src.getTexU(srcIndex); + float v = src.getTexV(srcIndex); + + int lm = ModelQuadUtil.mergeBakedLight(src.getLight(srcIndex), light.lm[srcIndex]); + + sink.writeQuad(x, y, z, color, u, v, lm); + } + + Sprite sprite = src.rubidium$getSprite(); + + if (sprite != null) { + renderData.addSprite(sprite); + } + } + + private LightMode getLightingMode(BlockState state, BakedModel model, BlockRenderView world, BlockPos pos) { + if (this.useAmbientOcclusion && model.isAmbientOcclusion(state) && state.getLightValue(world, pos) == 0) { + return LightMode.SMOOTH; + } else { + return LightMode.FLAT; + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java new file mode 100644 index 000000000..3d713c45a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java @@ -0,0 +1,10 @@ +package me.jellysquid.mods.sodium.client.render.pipeline; + +import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; +import net.minecraft.client.MinecraftClient; + +public class ChunkRenderCache { + protected BiomeColorBlender createBiomeColorBlender() { + return BiomeColorBlender.create(MinecraftClient.getInstance()); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java new file mode 100644 index 000000000..bdd4f78cd --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java @@ -0,0 +1,449 @@ +package me.jellysquid.mods.sodium.client.render.pipeline; + +import me.jellysquid.mods.sodium.client.model.light.LightMode; +import me.jellysquid.mods.sodium.client.model.light.LightPipeline; +import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; +import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; +import me.jellysquid.mods.sodium.client.model.quad.ModelQuad; +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadViewMutable; +import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; +import me.jellysquid.mods.sodium.client.util.Norm3b; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.block.BlockState; +import net.minecraft.block.SideShapeType; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.color.block.BlockColorProvider; +import net.minecraft.client.texture.Sprite; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.FluidState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; +import net.minecraft.world.BlockRenderView; +import net.minecraftforge.client.ForgeHooksClient; + +public class FluidRenderer { + + private static final float EPSILON = 0.001f; + + private static final BlockColorProvider FLUID_COLOR_PROVIDER = (state, world, pos, tintIndex) -> { + if (world == null) return 0xFFFFFFFF; + return state.getFluidState().getFluid().getAttributes().getColor(world, pos); + }; + + private final BlockPos.Mutable scratchPos = new BlockPos.Mutable(); + + private final ModelQuadViewMutable quad = new ModelQuad(); + + private final LightPipelineProvider lighters; + private final BiomeColorBlender biomeColorBlender; + + private final QuadLightData quadLightData = new QuadLightData(); + private final int[] quadColors = new int[4]; + + public FluidRenderer(MinecraftClient client, LightPipelineProvider lighters, BiomeColorBlender biomeColorBlender) { + int normal = Norm3b.pack(0.0f, 1.0f, 0.0f); + + for (int i = 0; i < 4; i++) { + this.quad.setNormal(i, normal); + } + + this.lighters = lighters; + this.biomeColorBlender = biomeColorBlender; + } + + private boolean isFluidOccluded(BlockRenderView world, int x, int y, int z, Direction dir, Fluid fluid) { + BlockPos pos = this.scratchPos.set(x, y, z); + BlockState blockState = world.getBlockState(pos); + BlockPos adjPos = this.scratchPos.set(x + dir.getOffsetX(), y + dir.getOffsetY(), z + dir.getOffsetZ()); + + if (blockState.isOpaque()) { + return world.getFluidState(adjPos).getFluid().matchesType(fluid) || blockState.isSideSolid(world,pos,dir, SideShapeType.FULL); + // fluidlogged or next to water, occlude sides that are solid or the same liquid + } + return world.getFluidState(adjPos).getFluid().matchesType(fluid); + } + + private boolean isSideExposed(BlockRenderView world, int x, int y, int z, Direction dir, float height) { + BlockPos pos = this.scratchPos.set(x + dir.getOffsetX(), y + dir.getOffsetY(), z + dir.getOffsetZ()); + BlockState blockState = world.getBlockState(pos); + + if (blockState.isOpaque()) { + VoxelShape shape = blockState.getCullingShape(world, pos); + + // Hoist these checks to avoid allocating the shape below + if (shape == VoxelShapes.fullCube()) { + // The top face always be inset, so if the shape above is a full cube it can't possibly occlude + return dir == Direction.UP; + } else if (shape.isEmpty()) { + return true; + } + + VoxelShape threshold = VoxelShapes.cuboid(0.0D, 0.0D, 0.0D, 1.0D, height, 1.0D); + + return !VoxelShapes.isSideCovered(threshold, shape, dir); + } + + return true; + } + + public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos, ChunkModelBuffers buffers) { + int posX = pos.getX(); + int posY = pos.getY(); + int posZ = pos.getZ(); + + Fluid fluid = fluidState.getFluid(); + + boolean sfUp = this.isFluidOccluded(world, posX, posY, posZ, Direction.UP, fluid); + boolean sfDown = this.isFluidOccluded(world, posX, posY, posZ, Direction.DOWN, fluid) || + !this.isSideExposed(world, posX, posY, posZ, Direction.DOWN, 0.8888889F); + boolean sfNorth = this.isFluidOccluded(world, posX, posY, posZ, Direction.NORTH, fluid); + boolean sfSouth = this.isFluidOccluded(world, posX, posY, posZ, Direction.SOUTH, fluid); + boolean sfWest = this.isFluidOccluded(world, posX, posY, posZ, Direction.WEST, fluid); + boolean sfEast = this.isFluidOccluded(world, posX, posY, posZ, Direction.EAST, fluid); + + if (sfUp && sfDown && sfEast && sfWest && sfNorth && sfSouth) { + return false; + } + + Sprite[] sprites = ForgeHooksClient.getFluidSprites(world, pos, fluidState); + boolean hc = fluidState.getFluid().getAttributes().getColor() != 0xffffffff; + + boolean rendered = false; + + float h1 = this.getCornerHeight(world, posX, posY, posZ, fluidState.getFluid()); + float h2 = this.getCornerHeight(world, posX, posY, posZ + 1, fluidState.getFluid()); + float h3 = this.getCornerHeight(world, posX + 1, posY, posZ + 1, fluidState.getFluid()); + float h4 = this.getCornerHeight(world, posX + 1, posY, posZ, fluidState.getFluid()); + + float yOffset = sfDown ? 0.0F : EPSILON; + + final ModelQuadViewMutable quad = this.quad; + + LightMode lightMode = hc && MinecraftClient.isAmbientOcclusionEnabled() ? LightMode.SMOOTH : LightMode.FLAT; + LightPipeline lighter = this.lighters.getLighter(lightMode); + + quad.setFlags(0); + + if (!sfUp && this.isSideExposed(world, posX, posY, posZ, Direction.UP, Math.min(Math.min(h1, h2), Math.min(h3, h4)))) { + h1 -= 0.001F; + h2 -= 0.001F; + h3 -= 0.001F; + h4 -= 0.001F; + + Vec3d velocity = fluidState.getVelocity(world, pos); + + Sprite sprite; + ModelQuadFacing facing; + float u1, u2, u3, u4; + float v1, v2, v3, v4; + + if (velocity.x == 0.0D && velocity.z == 0.0D) { + sprite = sprites[0]; + facing = ModelQuadFacing.UP; + u1 = sprite.getFrameU(0.0D); + v1 = sprite.getFrameV(0.0D); + u2 = u1; + v2 = sprite.getFrameV(16.0D); + u3 = sprite.getFrameU(16.0D); + v3 = v2; + u4 = u3; + v4 = v1; + } else { + sprite = sprites[1]; + facing = ModelQuadFacing.UNASSIGNED; + float dir = (float) MathHelper.atan2(velocity.z, velocity.x) - (1.5707964f); + float sin = MathHelper.sin(dir) * 0.25F; + float cos = MathHelper.cos(dir) * 0.25F; + u1 = sprite.getFrameU(8.0F + (-cos - sin) * 16.0F); + v1 = sprite.getFrameV(8.0F + (-cos + sin) * 16.0F); + u2 = sprite.getFrameU(8.0F + (-cos + sin) * 16.0F); + v2 = sprite.getFrameV(8.0F + (cos + sin) * 16.0F); + u3 = sprite.getFrameU(8.0F + (cos + sin) * 16.0F); + v3 = sprite.getFrameV(8.0F + (cos - sin) * 16.0F); + u4 = sprite.getFrameU(8.0F + (cos - sin) * 16.0F); + v4 = sprite.getFrameV(8.0F + (-cos - sin) * 16.0F); + } + + float uAvg = (u1 + u2 + u3 + u4) / 4.0F; + float vAvg = (v1 + v2 + v3 + v4) / 4.0F; + float s1 = (float) sprites[0].getWidth() / (sprites[0].getMaxU() - sprites[0].getMinU()); + float s2 = (float) sprites[0].getHeight() / (sprites[0].getMaxV() - sprites[0].getMinV()); + float s3 = 4.0F / Math.max(s2, s1); + + u1 = MathHelper.lerp(s3, u1, uAvg); + u2 = MathHelper.lerp(s3, u2, uAvg); + u3 = MathHelper.lerp(s3, u3, uAvg); + u4 = MathHelper.lerp(s3, u4, uAvg); + v1 = MathHelper.lerp(s3, v1, vAvg); + v2 = MathHelper.lerp(s3, v2, vAvg); + v3 = MathHelper.lerp(s3, v3, vAvg); + v4 = MathHelper.lerp(s3, v4, vAvg); + + quad.setSprite(sprite); + + this.setVertex(quad, 0, 0.0f, h1, 0.0f, u1, v1); + this.setVertex(quad, 1, 0.0f, h2, 1.0F, u2, v2); + this.setVertex(quad, 2, 1.0F, h3, 1.0F, u3, v3); + this.setVertex(quad, 3, 1.0F, h4, 0.0f, u4, v4); + + this.calculateQuadColors(quad, world, pos, lighter, Direction.UP, 1.0F, hc); + this.flushQuad(buffers, quad, facing, false); + + if (fluidState.method_15756(world, this.scratchPos.set(posX, posY + 1, posZ))) { + this.setVertex(quad, 3, 0.0f, h1, 0.0f, u1, v1); + this.setVertex(quad, 2, 0.0f, h2, 1.0F, u2, v2); + this.setVertex(quad, 1, 1.0F, h3, 1.0F, u3, v3); + this.setVertex(quad, 0, 1.0F, h4, 0.0f, u4, v4); + + this.flushQuad(buffers, quad, ModelQuadFacing.DOWN, true); + } + + rendered = true; + } + + if (!sfDown) { + Sprite sprite = sprites[0]; + + float minU = sprite.getMinU(); + float maxU = sprite.getMaxU(); + float minV = sprite.getMinV(); + float maxV = sprite.getMaxV(); + quad.setSprite(sprite); + + this.setVertex(quad, 0, 0.0f, yOffset, 1.0F, minU, maxV); + this.setVertex(quad, 1, 0.0f, yOffset, 0.0f, minU, minV); + this.setVertex(quad, 2, 1.0F, yOffset, 0.0f, maxU, minV); + this.setVertex(quad, 3, 1.0F, yOffset, 1.0F, maxU, maxV); + + this.calculateQuadColors(quad, world, pos, lighter, Direction.DOWN, 1.0F, hc); + this.flushQuad(buffers, quad, ModelQuadFacing.DOWN, false); + + rendered = true; + } + + quad.setFlags(ModelQuadFlags.IS_ALIGNED); + + for (Direction dir : DirectionUtil.HORIZONTAL_DIRECTIONS) { + float c1; + float c2; + float x1; + float z1; + float x2; + float z2; + + switch (dir) { + case NORTH: + if (sfNorth) { + continue; + } + + c1 = h1; + c2 = h4; + x1 = 0.0f; + x2 = 1.0F; + z1 = 0.001f; + z2 = z1; + break; + case SOUTH: + if (sfSouth) { + continue; + } + + c1 = h3; + c2 = h2; + x1 = 1.0F; + x2 = 0.0f; + z1 = 0.999f; + z2 = z1; + break; + case WEST: + if (sfWest) { + continue; + } + + c1 = h2; + c2 = h1; + x1 = 0.001f; + x2 = x1; + z1 = 1.0F; + z2 = 0.0f; + break; + case EAST: + if (sfEast) { + continue; + } + + c1 = h4; + c2 = h3; + x1 = 0.999f; + x2 = x1; + z1 = 0.0f; + z2 = 1.0F; + break; + default: + continue; + } + + if (this.isSideExposed(world, posX, posY, posZ, dir, Math.max(c1, c2))) { + int adjX = posX + dir.getOffsetX(); + int adjY = posY + dir.getOffsetY(); + int adjZ = posZ + dir.getOffsetZ(); + + Sprite sprite = sprites[1]; + Sprite oSprite = sprites[2]; + + if (oSprite != null) { + BlockPos adjPos = this.scratchPos.set(adjX, adjY, adjZ); + BlockState adjBlock = world.getBlockState(adjPos); + + if (adjBlock.shouldDisplayFluidOverlay(world, adjPos, fluidState)) { + // should ignore invisible blocks, barriers, light blocks + // use static water when adjacent block is ice, glass, stained glass, tinted glass + sprite = oSprite; + } + } + + float u1 = sprite.getFrameU(0.0D); + float u2 = sprite.getFrameU(8.0D); + float v1 = sprite.getFrameV((1.0F - c1) * 16.0F * 0.5F); + float v2 = sprite.getFrameV((1.0F - c2) * 16.0F * 0.5F); + float v3 = sprite.getFrameV(8.0D); + + quad.setSprite(sprite); + + this.setVertex(quad, 0, x2, c2, z2, u2, v2); + this.setVertex(quad, 1, x2, yOffset, z2, u2, v3); + this.setVertex(quad, 2, x1, yOffset, z1, u1, v3); + this.setVertex(quad, 3, x1, c1, z1, u1, v1); + + float br = dir.getAxis() == Direction.Axis.Z ? 0.8F : 0.6F; + + ModelQuadFacing facing = ModelQuadFacing.fromDirection(dir); + + this.calculateQuadColors(quad, world, pos, lighter, dir, br, hc); + this.flushQuad(buffers, quad, facing, false); + + if (sprite != oSprite) { + this.setVertex(quad, 0, x1, c1, z1, u1, v1); + this.setVertex(quad, 1, x1, yOffset, z1, u1, v3); + this.setVertex(quad, 2, x2, yOffset, z2, u2, v3); + this.setVertex(quad, 3, x2, c2, z2, u2, v2); + + this.flushQuad(buffers, quad, facing.getOpposite(), true); + } + + rendered = true; + } + } + + return rendered; + } + + private void calculateQuadColors(ModelQuadView quad, BlockRenderView world, BlockPos pos, LightPipeline lighter, Direction dir, float brightness, boolean colorized) { + QuadLightData light = this.quadLightData; + lighter.calculate(quad, pos, light, null, dir, false); + + int[] biomeColors = null; + + if (colorized) { + biomeColors = this.biomeColorBlender.getColors(FLUID_COLOR_PROVIDER, world, world.getBlockState(pos), pos, quad); + } + + for (int i = 0; i < 4; i++) { + this.quadColors[i] = ColorABGR.mul(biomeColors != null ? biomeColors[i] : 0xFFFFFFFF, light.br[i] * brightness); + } + } + + private void flushQuad(ChunkModelBuffers buffers, ModelQuadView quad, ModelQuadFacing facing, boolean flip) { + int vertexIdx, lightOrder; + + if (flip) { + vertexIdx = 3; + lightOrder = -1; + } else { + vertexIdx = 0; + lightOrder = 1; + } + + ModelVertexSink sink = buffers.getSink(facing); + sink.ensureCapacity(4); + + for (int i = 0; i < 4; i++) { + float x = quad.getX(i); + float y = quad.getY(i); + float z = quad.getZ(i); + + int color = this.quadColors[vertexIdx]; + + float u = quad.getTexU(i); + float v = quad.getTexV(i); + + int light = this.quadLightData.lm[vertexIdx]; + + sink.writeQuad(x, y, z, color, u, v, light); + + vertexIdx += lightOrder; + } + + Sprite sprite = quad.rubidium$getSprite(); + + if (sprite != null) { + buffers.getRenderData().addSprite(sprite); + } + + sink.flush(); + } + + private void setVertex(ModelQuadViewMutable quad, int i, float x, float y, float z, float u, float v) { + quad.setX(i, x); + quad.setY(i, y); + quad.setZ(i, z); + quad.setTexU(i, u); + quad.setTexV(i, v); + } + + private float getCornerHeight(BlockRenderView world, int x, int y, int z, Fluid fluid) { + int samples = 0; + float totalHeight = 0.0F; + + for (int i = 0; i < 4; ++i) { + int x2 = x - (i & 1); + int z2 = z - (i >> 1 & 1); + + if (world.getFluidState(this.scratchPos.set(x2, y + 1, z2)).getFluid().matchesType(fluid)) { + return 1.0F; + } + + BlockPos pos = this.scratchPos.set(x2, y, z2); + + BlockState blockState = world.getBlockState(pos); + FluidState fluidState = blockState.getFluidState(); + + if (fluidState.getFluid().matchesType(fluid)) { + float height = fluidState.getHeight(world, pos); + + if (height >= 0.8F) { + totalHeight += height * 10.0F; + samples += 10; + } else { + totalHeight += height; + ++samples; + } + } else if (!blockState.getMaterial().isSolid()) { + ++samples; + } + } + + return totalHeight / (float) samples; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java new file mode 100644 index 000000000..cdabe32b8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java @@ -0,0 +1,66 @@ +package me.jellysquid.mods.sodium.client.render.pipeline.context; + +import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; +import me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache; +import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; +import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; +import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; +import me.jellysquid.mods.sodium.client.render.pipeline.FluidRenderer; +import me.jellysquid.mods.sodium.client.world.WorldSlice; +import me.jellysquid.mods.sodium.client.world.WorldSliceLocal; +import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.block.BlockModels; +import net.minecraft.world.World; + +public class ChunkRenderCacheLocal extends ChunkRenderCache { + private final ArrayLightDataCache lightDataCache; + + private final BlockRenderer blockRenderer; + private final FluidRenderer fluidRenderer; + + private final BlockModels blockModels; + private final WorldSlice worldSlice; + private WorldSliceLocal localSlice; + + public ChunkRenderCacheLocal(MinecraftClient client, World world) { + this.worldSlice = new WorldSlice(world); + this.lightDataCache = new ArrayLightDataCache(this.worldSlice); + + LightPipelineProvider lightPipelineProvider = new LightPipelineProvider(this.lightDataCache); + BiomeColorBlender biomeColorBlender = this.createBiomeColorBlender(); + + this.blockRenderer = new BlockRenderer(client, lightPipelineProvider, biomeColorBlender); + this.fluidRenderer = new FluidRenderer(client, lightPipelineProvider, biomeColorBlender); + + this.blockModels = client.getBakedModelManager().getBlockModels(); + } + + public BlockModels getBlockModels() { + return this.blockModels; + } + + public BlockRenderer getBlockRenderer() { + return this.blockRenderer; + } + + public FluidRenderer getFluidRenderer() { + return this.fluidRenderer; + } + + public void init(ChunkRenderContext context) { + this.lightDataCache.reset(context.getOrigin()); + this.worldSlice.copyData(context); + // create the new local slice here so that it's unique whenever we copy new data + // this is passed into mod code, since some depend on the provided BlockRenderView object being unique each time + this.localSlice = new WorldSliceLocal(this.worldSlice); + } + + public WorldSlice getWorldSlice() { + return this.worldSlice; + } + + public WorldSliceLocal getLocalSlice() { + return this.localSlice; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java new file mode 100644 index 000000000..0a8c6f253 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java @@ -0,0 +1,68 @@ +package me.jellysquid.mods.sodium.client.render.pipeline.context; + +import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; +import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; +import me.jellysquid.mods.sodium.client.model.light.cache.HashLightDataCache; +import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; +import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; +import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; +import net.minecraft.client.MinecraftClient; +import net.minecraft.world.BlockRenderView; + +import java.util.Map; + +public class ChunkRenderCacheShared extends ChunkRenderCache { + private static final Map INSTANCES = new Reference2ObjectOpenHashMap<>(); + + private final BlockRenderer blockRenderer; + private final HashLightDataCache lightCache; + + private ChunkRenderCacheShared(BlockRenderView world) { + MinecraftClient client = MinecraftClient.getInstance(); + + this.lightCache = new HashLightDataCache(world); + + BiomeColorBlender biomeColorBlender = this.createBiomeColorBlender(); + LightPipelineProvider lightPipelineProvider = new LightPipelineProvider(this.lightCache); + + this.blockRenderer = new BlockRenderer(client, lightPipelineProvider, biomeColorBlender); + } + + public BlockRenderer getBlockRenderer() { + return this.blockRenderer; + } + + private void resetCache() { + this.lightCache.clearCache(); + } + + public static ChunkRenderCacheShared getInstance(BlockRenderView world) { + ChunkRenderCacheShared instance = INSTANCES.get(world); + + if (instance == null) { + throw new IllegalStateException("No global renderer exists"); + } + + return instance; + } + + public static void destroyRenderContext(BlockRenderView world) { + if (INSTANCES.remove(world) == null) { + throw new IllegalStateException("No render context exists for world: " + world); + } + } + + public static void createRenderContext(BlockRenderView world) { + if (INSTANCES.containsKey(world)) { + throw new IllegalStateException("Render context already exists for world: " + world); + } + + INSTANCES.put(world, new ChunkRenderCacheShared(world)); + } + + public static void resetCaches() { + for (ChunkRenderCacheShared context : INSTANCES.values()) { + context.resetCache(); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteExtended.java new file mode 100644 index 000000000..570f83b13 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteExtended.java @@ -0,0 +1,5 @@ +package me.jellysquid.mods.sodium.client.render.texture; + +public interface SpriteExtended { + void markActive(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java new file mode 100644 index 000000000..5f06c319d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java @@ -0,0 +1,11 @@ +package me.jellysquid.mods.sodium.client.render.texture; + +import net.minecraft.client.texture.Sprite; + +public class SpriteUtil { + public static void markSpriteActive(Sprite sprite) { + if (sprite instanceof SpriteExtended) { + ((SpriteExtended) sprite).markActive(); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/Dim2i.java b/src/main/java/me/jellysquid/mods/sodium/client/util/Dim2i.java new file mode 100644 index 000000000..d8e6458d6 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/Dim2i.java @@ -0,0 +1,51 @@ +package me.jellysquid.mods.sodium.client.util; + +public class Dim2i { + private final int x; + private final int y; + private final int width; + private final int height; + + public Dim2i(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public int getOriginX() { + return this.x; + } + + public int getOriginY() { + return this.y; + } + + public int getWidth() { + return this.width; + } + + public int getHeight() { + return this.height; + } + + public int getLimitX() { + return this.x + this.width; + } + + public int getLimitY() { + return this.y + this.height; + } + + public boolean containsCursor(double x, double y) { + return x >= this.x && x < this.getLimitX() && y >= this.y && y < this.getLimitY(); + } + + public int getCenterX() { + return this.x + (this.width / 2); + } + + public int getCenterY() { + return this.y + (this.height / 2); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java new file mode 100644 index 000000000..49056712e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java @@ -0,0 +1,10 @@ +package me.jellysquid.mods.sodium.client.util; + +public class MathUtil { + /** + * @return True if the specified number is greater than zero and is a power of two, otherwise false + */ + public static boolean isPowerOfTwo(int n) { + return ((n & (n - 1)) == 0); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java new file mode 100644 index 000000000..e81efc582 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java @@ -0,0 +1,79 @@ +package me.jellysquid.mods.sodium.client.util; + +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.util.math.Direction; + +/** + * Provides some utilities and constants for interacting with vanilla's model quad vertex format. + * + * This is the current vertex format used by Minecraft for chunk meshes and model quads. Internally, it uses integer + * arrays for store baked quad data, and as such the following table provides both the byte and int indices. + * + * Byte Index Integer Index Name Format Fields + * 0 ..11 0..2 Position 3 floats x, y, z + * 12..15 3 Color 4 unsigned bytes a, r, g, b + * 16..23 4..5 Block Texture 2 floats u, v + * 24..27 6 Light Texture 2 shorts u, v + * 28..30 7 Normal 3 unsigned bytes x, y, z + * 31 Padding 1 byte + */ +public class ModelQuadUtil { + // Integer indices for vertex attributes, useful for accessing baked quad data + public static final int POSITION_INDEX = 0, + COLOR_INDEX = 3, + TEXTURE_INDEX = 4, + LIGHT_INDEX = 6, + NORMAL_INDEX = 7; + + // Size of vertex format in 4-byte integers + public static final int VERTEX_SIZE = 8; + public static final int VERTEX_SIZE_BYTES = VERTEX_SIZE * 4; + + // Cached array of normals for every facing to avoid expensive computation + static final int[] NORMALS = new int[DirectionUtil.ALL_DIRECTIONS.length]; + + static { + for (int i = 0; i < NORMALS.length; i++) { + NORMALS[i] = Norm3b.pack(DirectionUtil.ALL_DIRECTIONS[i].getVector()); + } + } + + /** + * Returns the normal vector for a model quad with the given {@param facing}. + */ + public static int getFacingNormal(Direction facing) { + return NORMALS[facing.ordinal()]; + } + + public static int getFacingNormal(Direction facing, int bakedNormal) { + if(!hasNormal(bakedNormal)) + return NORMALS[facing.ordinal()]; + return bakedNormal; + } + + public static boolean hasNormal(int n) { + return (n & 0xFFFFFF) != 0; + } + + /** + * @param vertexIndex The index of the vertex to access + * @return The starting offset of the vertex's attributes + */ + public static int vertexOffset(int vertexIndex) { + return vertexIndex * VERTEX_SIZE; + } + + public static int mergeBakedLight(int packedLight, int calcLight) { + // bail early in most cases + if (packedLight == 0) + return calcLight; + + int psl = (packedLight >> 16) & 0xFF; + int csl = (calcLight >> 16) & 0xFF; + int pbl = (packedLight) & 0xFF; + int cbl = (calcLight) & 0xFF; + int bl = Math.max(pbl, cbl); + int sl = Math.max(psl, csl); + return (sl << 16) | bl; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java b/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java new file mode 100644 index 000000000..5df3e52c5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java @@ -0,0 +1,82 @@ +package me.jellysquid.mods.sodium.client.util; + +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3f; +import net.minecraft.util.math.Vec3i; + +/** + * Provides some utilities for working with packed normal vectors. Each normal component provides 8 bits of + * precision in the range of [-1.0,1.0]. + * + * | 32 | 24 | 16 | 8 | + * | 0000 0000 | 0110 1100 | 0110 1100 | 0110 1100 | + * | Padding | X | Y | Z | + */ +public class Norm3b { + /** + * The maximum value of a normal's vector component. + */ + private static final float COMPONENT_RANGE = 127.0f; + + /** + * Constant value which can be multiplied with a floating-point vector component to get the normalized value. The + * multiplication is slightly faster than a floating point division, and this code is a hot path which justifies it. + */ + private static final float NORM = 1.0f / COMPONENT_RANGE; + + static int pack(Vec3i norm) { + return pack(norm.getX(), norm.getY(), norm.getZ()); + } + + public static int pack(Vec3f dir) { + return pack(dir.getX(), dir.getY(), dir.getZ()); + } + + /** + * Packs the specified vector components into a 32-bit integer in XYZ ordering with the 8 bits of padding at the + * end. + * @param x The x component of the normal's vector + * @param y The y component of the normal's vector + * @param z The z component of the normal's vector + */ + public static int pack(float x, float y, float z) { + int normX = encode(x); + int normY = encode(y); + int normZ = encode(z); + + return (normZ << 16) | (normY << 8) | normX; + } + + /** + * Encodes a float in the range of -1.0..1.0 to a normalized unsigned integer in the range of 0..255 which can then + * be passed to graphics memory. + */ + private static int encode(float comp) { + // TODO: is the clamp necessary here? our inputs should always be normalized vector components + return ((int) (MathHelper.clamp(comp, -1.0F, 1.0F) * COMPONENT_RANGE) & 255); + } + + /** + * Unpacks the x-component of the packed normal, denormalizing it to a float in the range of -1.0..1.0. + * @param norm The packed normal + */ + public static float unpackX(int norm) { + return ((byte) (norm & 0xFF)) * NORM; + } + + /** + * Unpacks the y-component of the packed normal, denormalizing it to a float in the range of -1.0..1.0. + * @param norm The packed normal + */ + public static float unpackY(int norm) { + return ((byte) ((norm >> 8) & 0xFF)) * NORM; + } + + /** + * Unpacks the z-component of the packed normal, denormalizing it to a float in the range of -1.0..1.0. + * @param norm The packed normal + */ + public static float unpackZ(int norm) { + return ((byte) ((norm >> 16) & 0xFF)) * NORM; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorABGR.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorABGR.java new file mode 100644 index 000000000..55a8dda91 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorABGR.java @@ -0,0 +1,84 @@ +package me.jellysquid.mods.sodium.client.util.color; + +/** + * Provides some utilities for packing and unpacking color components from packed integer colors in ABGR format, which + * is used by OpenGL for color vectors. + * + * | 32 | 24 | 16 | 8 | + * | 0110 1100 | 0110 1100 | 0110 1100 | 0110 1100 | + * | Alpha | Blue | Green | Red | + */ +public class ColorABGR implements ColorU8 { + /** + * Packs the specified color components into ABGR format. + * @param r The red component of the color + * @param g The green component of the color + * @param b The blue component of the color + * @param a The alpha component of the color + */ + public static int pack(int r, int g, int b, int a) { + return (a & 0xFF) << 24 | (b & 0xFF) << 16 | (g & 0xFF) << 8 | (r & 0xFF); + } + + /** + * @see ColorABGR#pack(int, int, int, int) + */ + public static int pack(float r, float g, float b, float a) { + return pack((int) (r * COMPONENT_RANGE), (int) (g * COMPONENT_RANGE), (int) (b * COMPONENT_RANGE), (int) (a * COMPONENT_RANGE)); + } + + /** + * Multiplies the RGB components of the packed ABGR color using the given scale factors. + * @param color The ABGR packed color to be multiplied + * @param rw The red component scale factor + * @param gw The green component scale factor + * @param bw The blue component scale factor + */ + public static int mul(int color, float rw, float gw, float bw) { + float r = unpackRed(color) * rw; + float g = unpackGreen(color) * gw; + float b = unpackBlue(color) * bw; + + return pack((int) r, (int) g, (int) b, 0xFF); + } + + public static int mul(int color, float w) { + return mul(color, w, w, w); + } + + /** + * @param color The packed 32-bit ABGR color to unpack + * @return The red color component in the range of 0..255 + */ + public static int unpackRed(int color) { + return color & 0xFF; + } + + /** + * @param color The packed 32-bit ABGR color to unpack + * @return The green color component in the range of 0..255 + */ + public static int unpackGreen(int color) { + return color >> 8 & 0xFF; + } + + /** + * @param color The packed 32-bit ABGR color to unpack + * @return The blue color component in the range of 0..255 + */ + public static int unpackBlue(int color) { + return color >> 16 & 0xFF; + } + + /** + * @param color The packed 32-bit ABGR color to unpack + * @return The red color component in the range of 0..255 + */ + public static int unpackAlpha(int color) { + return color >> 24 & 0xFF; + } + + public static int pack(float r, float g, float b) { + return pack(r, g, b, 255); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorARGB.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorARGB.java new file mode 100644 index 000000000..3790e17fb --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorARGB.java @@ -0,0 +1,66 @@ +package me.jellysquid.mods.sodium.client.util.color; + +/** + * Provides some utilities for packing and unpacking color components from packed integer colors in ARGB format. This + * packed format is used by most of Minecraft, but special care must be taken to pack it into ABGR format before passing + * it to OpenGL attributes. + * + * | 32 | 24 | 16 | 8 | + * | 0110 1100 | 0110 1100 | 0110 1100 | 0110 1100 | + * | Alpha | Red | Green | Blue | + */ +public class ColorARGB implements ColorU8 { + /** + * Packs the specified color components into big-endian format for consumption by OpenGL. + * @param r The red component of the color + * @param g The green component of the color + * @param b The blue component of the color + * @param a The alpha component of the color + */ + public static int pack(int r, int g, int b, int a) { + return (a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF); + } + + /** + * @param color The packed 32-bit ARGB color to unpack + * @return The red color component in the range of 0..255 + */ + public static int unpackAlpha(int color) { + return color >> 24 & 0xFF; + } + + /** + * @param color The packed 32-bit ARGB color to unpack + * @return The red color component in the range of 0..255 + */ + public static int unpackRed(int color) { + return color >> 16 & 0xFF; + } + + /** + * @param color The packed 32-bit ARGB color to unpack + * @return The green color component in the range of 0..255 + */ + public static int unpackGreen(int color) { + return color >> 8 & 0xFF; + } + + /** + * @param color The packed 32-bit ARGB color to unpack + * @return The blue color component in the range of 0..255 + */ + public static int unpackBlue(int color) { + return color & 0xFF; + } + + /** + * Re-packs the ARGB color into a aBGR color with the specified alpha component. + */ + public static int toABGR(int color, int alpha) { + return Integer.reverseBytes(color << 8 | alpha); + } + + public static int toABGR(int color) { + return Integer.reverseBytes(color << 8); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorMixer.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorMixer.java new file mode 100644 index 000000000..c0b33ae57 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorMixer.java @@ -0,0 +1,40 @@ +package me.jellysquid.mods.sodium.client.util.color; + +public class ColorMixer { + private static final long MASK1 = 0x00FF00FF; + private static final long MASK2 = 0xFF00FF00; + + /** + * Mixes two ARGB colors using the given ratios. Use {@link ColorMixer#getStartRatio(float)} and + * {@link ColorMixer#getEndRatio(float)} to convert a floating-point ratio into a integer ratio. + * + * This method takes 64-bit inputs to avoid overflows when mixing the alpha channel. The helper method + * {@link ColorMixer#mixARGB(int, int, int, int)} can be used with 32-bit inputs. + * + * @param c1 The first (starting) color to blend with in ARGB format + * @param c2 The second (ending) color to blend with in ARGB format + * @param f1 The ratio of the color {@param c1} as calculated by {@link ColorMixer#getStartRatio(float)} + * @param f2 The ratio of the color {@param c2} as calculated by {@link ColorMixer#getEndRatio(float)} + * @return The result of ((c1 * f1) + (c2 * f2) as an ARGB-encoded color + */ + public static long mixARGB(long c1, long c2, int f1, int f2) { + return ((((((c1 & MASK1) * f1) + ((c2 & MASK1) * f2)) >> 8) & MASK1) | + (((((c1 & MASK2) * f1) + ((c2 & MASK2) * f2)) >> 8) & MASK2)); + } + + /** + * Helper method to convert 32-bit integers to 64-bit integers and back. + * @see ColorMixer#mixARGB(long, long, int, int) + */ + public static int mixARGB(int c1, int c2, int f1, int f2) { + return (int) mixARGB(Integer.toUnsignedLong(c1), Integer.toUnsignedLong(c2), f1, f2); + } + + public static int getStartRatio(float frac) { + return (int) (256 * frac); + } + + public static int getEndRatio(float frac) { + return 256 - getStartRatio(frac); + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorU8.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorU8.java new file mode 100644 index 000000000..779e28d50 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/ColorU8.java @@ -0,0 +1,21 @@ +package me.jellysquid.mods.sodium.client.util.color; + +public interface ColorU8 { + /** + * The maximum value of a color component. + */ + float COMPONENT_RANGE = 255.0f; + + /** + * Constant value which can be multiplied with a floating-point color component to get the normalized value. The + * multiplication is slightly faster than a floating point division, and this code is a hot path which justifies it. + */ + float NORM = 1.0f / COMPONENT_RANGE; + + /** + * Normalizes a color component to the range of 0..1. + */ + static float normalize(float v) { + return v * NORM; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java new file mode 100644 index 000000000..244c1034e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java @@ -0,0 +1,88 @@ +package me.jellysquid.mods.sodium.client.util.color; + +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +import java.util.function.Function; + +public class FastCubicSampler { + private static final double[] DENSITY_CURVE = new double[] { 0.0D, 1.0D, 4.0D, 6.0D, 4.0D, 1.0D, 0.0D }; + private static final int DIAMETER = 6; + + public static Vec3d sampleColor(Vec3d pos, ColorFetcher colorFetcher, Function transformer) { + int intX = MathHelper.floor(pos.getX()); + int intY = MathHelper.floor(pos.getY()); + int intZ = MathHelper.floor(pos.getZ()); + + int[] values = new int[DIAMETER * DIAMETER * DIAMETER]; + + for(int x = 0; x < DIAMETER; ++x) { + int blockX = (intX - 2) + x; + + for(int y = 0; y < DIAMETER; ++y) { + int blockY = (intY - 2) + y; + + for(int z = 0; z < DIAMETER; ++z) { + int blockZ = (intZ - 2) + z; + + values[index(x, y, z)] = colorFetcher.fetch(blockX, blockY, blockZ); + } + } + } + + // Fast path! Skip blending the colors if all inputs are the same + if (isHomogenousArray(values)) { + // Take the first color if it's homogenous (all elements are the same...) + return transformer.apply(Vec3d.unpackRgb(values[0])); + } + + double deltaX = pos.getX() - (double)intX; + double deltaY = pos.getY() - (double)intY; + double deltaZ = pos.getZ() - (double)intZ; + + Vec3d sum = Vec3d.ZERO; + double totalFactor = 0.0D; + + for(int x = 0; x < DIAMETER; ++x) { + double densityX = MathHelper.lerp(deltaX, DENSITY_CURVE[x + 1], DENSITY_CURVE[x]); + + for(int y = 0; y < DIAMETER; ++y) { + double densityY = MathHelper.lerp(deltaY, DENSITY_CURVE[y + 1], DENSITY_CURVE[y]); + + for(int z = 0; z < DIAMETER; ++z) { + double densityZ = MathHelper.lerp(deltaZ, DENSITY_CURVE[z + 1], DENSITY_CURVE[z]); + + double factor = densityX * densityY * densityZ; + totalFactor += factor; + + Vec3d color = transformer.apply(Vec3d.unpackRgb(values[index(x, y, z)])); + sum = sum.add(color.multiply(factor)); + } + } + } + + sum = sum.multiply(1.0D / totalFactor); + + return sum; + } + + private static int index(int x, int y, int z) { + return (DIAMETER * DIAMETER * z) + (DIAMETER * y) + x; + } + + public interface ColorFetcher { + int fetch(int x, int y, int z); + } + + private static boolean isHomogenousArray(int[] arr) { + int val = arr[0]; + + for (int i = 1; i < arr.length; i++) { + if (arr[i] != val) { + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/math/FrustumExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/util/math/FrustumExtended.java new file mode 100644 index 000000000..e78fd526c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/math/FrustumExtended.java @@ -0,0 +1,5 @@ +package me.jellysquid.mods.sodium.client.util.math; + +public interface FrustumExtended { + boolean fastAabbTest(float minX, float minY, float minZ, float maxX, float maxY, float maxZ); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix3fExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix3fExtended.java new file mode 100644 index 000000000..cda3552b7 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix3fExtended.java @@ -0,0 +1,34 @@ +package me.jellysquid.mods.sodium.client.util.math; + +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Quaternion; +import net.minecraft.util.math.Vec3f; + +public interface Matrix3fExtended { + /** + * Applies the specified rotation to this matrix in-place. + * + * @param quaternion The quaternion to rotate this matrix by + */ + void rotate(Quaternion quaternion); + + int computeNormal(Direction dir); + + float transformVecX(float x, float y, float z); + + float transformVecY(float x, float y, float z); + + float transformVecZ(float x, float y, float z); + + default float transformVecX(Vec3f dir) { + return this.transformVecX(dir.getX(), dir.getY(), dir.getZ()); + } + + default float transformVecY(Vec3f dir) { + return this.transformVecY(dir.getX(), dir.getY(), dir.getZ()); + } + + default float transformVecZ(Vec3f dir) { + return this.transformVecZ(dir.getX(), dir.getY(), dir.getZ()); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix4fExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix4fExtended.java new file mode 100644 index 000000000..af0dfbd4c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix4fExtended.java @@ -0,0 +1,51 @@ +package me.jellysquid.mods.sodium.client.util.math; + +import net.minecraft.util.math.Quaternion; + +public interface Matrix4fExtended { + /** + * Applies the specified rotation to this matrix in-place. + * + * @param quaternion The quaternion to rotate this matrix by + */ + void rotate(Quaternion quaternion); + + /** + * Applies the specified translation to this matrix in-place. + * + * @param x The x-component of the translation + * @param y The y-component of the translation + * @param z The z-component of the translation + */ + void translate(float x, float y, float z); + + /** + * Applies this matrix transformation to the given input vector, returning the x-component. Avoids the lack of + * struct types in Java and allows for allocation-free return. + * @param x The x-component of the vector + * @param y The y-component of the vector + * @param z The z-component of the vector + * @return The x-component of the transformed input vector + */ + float transformVecX(float x, float y, float z); + + /** + * Applies this matrix transformation to the given input vector, returning the y-component. Avoids the lack of + * struct types in Java and allows for allocation-free return. + * @param x The x-component of the vector + * @param y The y-component of the vector + * @param z The z-component of the vector + * @return The y-component of the transformed input vector + */ + float transformVecY(float x, float y, float z); + + /** + * Applies this matrix transformation to the given input vector, returning the z-component. Avoids the lack of + * struct types in Java and allows for allocation-free return. + * @param x The x-component of the vector + * @param y The y-component of the vector + * @param z The z-component of the vector + * @return The z-component of the transformed input vector + */ + float transformVecZ(float x, float y, float z); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/math/MatrixUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/math/MatrixUtil.java new file mode 100644 index 000000000..9928dec03 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/math/MatrixUtil.java @@ -0,0 +1,34 @@ +package me.jellysquid.mods.sodium.client.util.math; + +import me.jellysquid.mods.sodium.client.util.Norm3b; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Matrix3f; +import net.minecraft.util.math.Matrix4f; + +public class MatrixUtil { + public static int computeNormal(Matrix3f normalMatrix, Direction facing) { + return ((Matrix3fExtended) (Object) normalMatrix).computeNormal(facing); + } + + public static Matrix4fExtended getExtendedMatrix(Matrix4f matrix) { + return (Matrix4fExtended) (Object) matrix; + } + + public static Matrix3fExtended getExtendedMatrix(Matrix3f matrix) { + return (Matrix3fExtended) (Object) matrix; + } + + public static int transformPackedNormal(int norm, Matrix3f matrix) { + Matrix3fExtended mat = MatrixUtil.getExtendedMatrix(matrix); + + float normX1 = Norm3b.unpackX(norm); + float normY1 = Norm3b.unpackY(norm); + float normZ1 = Norm3b.unpackZ(norm); + + float normX2 = mat.transformVecX(normX1, normY1, normZ1); + float normY2 = mat.transformVecY(normX1, normY1, normZ1); + float normZ2 = mat.transformVecZ(normX1, normY1, normZ1); + + return Norm3b.pack(normX2, normY2, normZ2); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/rand/SplitMixRandom.java b/src/main/java/me/jellysquid/mods/sodium/client/util/rand/SplitMixRandom.java new file mode 100644 index 000000000..5b79bfbb5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/rand/SplitMixRandom.java @@ -0,0 +1,99 @@ +package me.jellysquid.mods.sodium.client.util.rand; + +import it.unimi.dsi.fastutil.HashCommon; + +// SplitMixRandom implementation from DSI Utilities, adopted in a minimal implementation to not +// import Apache Commons. +// +// http://xoshiro.di.unimi.it/ +public class SplitMixRandom { + private static final long PHI = 0x9E3779B97F4A7C15L; + + private long x; + + public SplitMixRandom() { + this(XoRoShiRoRandom.randomSeed()); + } + + public SplitMixRandom(final long seed) { + this.setSeed(seed); + } + + private static long staffordMix13(long z) { + z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L; + z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL; + + return z ^ (z >>> 31); + } + + private static int staffordMix4Upper32(long z) { + z = (z ^ (z >>> 33)) * 0x62A9D9ED799705F5L; + + return (int) (((z ^ (z >>> 28)) * 0xCB24D0A5C88C35B3L) >>> 32); + } + + public long nextLong() { + return staffordMix13(this.x += PHI); + } + + public int nextInt() { + return staffordMix4Upper32(this.x += PHI); + } + + public int nextInt(final int n) { + return (int) this.nextLong(n); + } + + public long nextLong(final long n) { + if (n <= 0) { + throw new IllegalArgumentException("illegal bound " + n + " (must be positive)"); + } + + long t = staffordMix13(this.x += PHI); + + final long nMinus1 = n - 1; + + if ((n & nMinus1) == 0) { + return t & nMinus1; + } + + long u = t >>> 1; + + while (u + nMinus1 - (t = u % n) < 0) { + u = staffordMix13(this.x += PHI) >>> 1; + } + + return t; + } + + public double nextDouble() { + return (staffordMix13(this.x += PHI) >>> 11) * 0x1.0p-53; + } + + public float nextFloat() { + return (staffordMix4Upper32(this.x += PHI) >>> 8) * 0x1.0p-24f; + } + + public boolean nextBoolean() { + return staffordMix4Upper32(this.x += PHI) < 0; + } + + public void nextBytes(final byte[] bytes) { + int i = bytes.length, n; + + while (i != 0) { + n = Math.min(i, 8); + for (long bits = staffordMix13(this.x += PHI); n-- != 0; bits >>= 8) { + bytes[--i] = (byte) bits; + } + } + } + + public void setSeed(final long seed) { + this.x = HashCommon.murmurHash3(seed); + } + + public void setState(final long state) { + this.x = state; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/rand/XoRoShiRoRandom.java b/src/main/java/me/jellysquid/mods/sodium/client/util/rand/XoRoShiRoRandom.java new file mode 100644 index 000000000..ec6d04f46 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/rand/XoRoShiRoRandom.java @@ -0,0 +1,150 @@ +package me.jellysquid.mods.sodium.client.util.rand; + +import java.util.Random; + +// XoRoShiRo128** implementation from DSI Utilities, adopted in a minimal implementation to not +// import Apache Commons. +// +// http://xoshiro.di.unimi.it/ +public class XoRoShiRoRandom extends Random { + private static final long serialVersionUID = 1L; + + private SplitMixRandom mixer; + private long seed = Long.MIN_VALUE; + private long p0, p1; // The initialization words for the current seed + private long s0, s1; // The current random words + private boolean hasSavedState; // True if we can be quickly reseed by using resetting the words + + private static final SplitMixRandom seedUniquifier = new SplitMixRandom(System.nanoTime()); + + public static long randomSeed() { + final long x; + + synchronized (XoRoShiRoRandom.seedUniquifier) { + x = XoRoShiRoRandom.seedUniquifier.nextLong(); + } + + return x ^ System.nanoTime(); + } + + public XoRoShiRoRandom() { + this(XoRoShiRoRandom.randomSeed()); + } + + public XoRoShiRoRandom(final long seed) { + this.setSeed(seed); + } + + @Override + public long nextLong() { + final long s0 = this.s0; + + long s1 = this.s1; + + final long result = s0 + s1; + + s1 ^= s0; + + this.s0 = Long.rotateLeft(s0, 24) ^ s1 ^ s1 << 16; + this.s1 = Long.rotateLeft(s1, 37); + + return result; + } + + @Override + public int nextInt() { + return (int) this.nextLong(); + } + + @Override + public int nextInt(final int n) { + return (int) this.nextLong(n); + } + + private long nextLong(final long n) { + if (n <= 0) { + throw new IllegalArgumentException("illegal bound " + n + " (must be positive)"); + } + + long t = this.nextLong(); + + final long nMinus1 = n - 1; + + // Shortcut for powers of two--high bits + if ((n & nMinus1) == 0) { + return (t >>> Long.numberOfLeadingZeros(nMinus1)) & nMinus1; + } + + // Rejection-based algorithm to get uniform integers in the general case + long u = t >>> 1; + + while (u + nMinus1 - (t = u % n) < 0) { + u = this.nextLong() >>> 1; + } + + return t; + + } + + @Override + public double nextDouble() { + return Double.longBitsToDouble(0x3FFL << 52 | this.nextLong() >>> 12) - 1.0; + } + + @Override + public float nextFloat() { + return (this.nextLong() >>> 40) * 0x1.0p-24f; + } + + @Override + public boolean nextBoolean() { + return this.nextLong() < 0; + } + + @Override + public void nextBytes(final byte[] bytes) { + int i = bytes.length, n; + + while (i != 0) { + n = Math.min(i, 8); + + for (long bits = this.nextLong(); n-- != 0; bits >>= 8) { + bytes[--i] = (byte) bits; + } + } + } + + @Override + public void setSeed(final long seed) { + // Restore the previous initial state if the seed hasn't changed + // Setting and mixing the seed is expensive, so this saves some CPU cycles + if (this.hasSavedState && this.seed == seed) { + this.s0 = this.p0; + this.s1 = this.p1; + } else { + SplitMixRandom mixer = this.mixer; + + // Avoid allocations of SplitMixRandom + if (mixer == null) { + mixer = this.mixer = new SplitMixRandom(seed); + } else { + mixer.setSeed(seed); + } + + this.s0 = mixer.nextLong(); + this.s1 = mixer.nextLong(); + + this.p0 = this.s0; + this.p1 = this.s1; + + this.seed = seed; + this.hasSavedState = true; + } + } + + public XoRoShiRoRandom setSeedAndReturn(final long seed) { + this.setSeed(seed); + + return this; + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/task/CancellationSource.java b/src/main/java/me/jellysquid/mods/sodium/client/util/task/CancellationSource.java new file mode 100644 index 000000000..00dff1481 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/task/CancellationSource.java @@ -0,0 +1,5 @@ +package me.jellysquid.mods.sodium.client.util.task; + +public interface CancellationSource { + boolean isCancelled(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/ChunkStatusListener.java b/src/main/java/me/jellysquid/mods/sodium/client/world/ChunkStatusListener.java new file mode 100644 index 000000000..7cdbbc4c3 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/ChunkStatusListener.java @@ -0,0 +1,20 @@ +package me.jellysquid.mods.sodium.client.world; + +/** + * Defines a listener that can be attached to a world's chunk manager to receive chunk load and unload events. + */ +public interface ChunkStatusListener { + /** + * Called after a chunk is added to the world and loaded. + * @param x The x-coordinate of the loaded chunk + * @param z The z-coordinate of the loaded chunk + */ + void onChunkAdded(int x, int z); + + /** + * Called after a chunk is removed from the world and unloaded. + * @param x The x-coordiante of the unloaded chunk + * @param z The z-coordinate of the unloaded chunk + */ + void onChunkRemoved(int x, int z); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/ChunkStatusListenerManager.java b/src/main/java/me/jellysquid/mods/sodium/client/world/ChunkStatusListenerManager.java new file mode 100644 index 000000000..826e4ecc5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/ChunkStatusListenerManager.java @@ -0,0 +1,6 @@ +package me.jellysquid.mods.sodium.client.world; + +public interface ChunkStatusListenerManager { + // TODO: allow multiple listeners to be added? + void setListener(ChunkStatusListener listener); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/ClientWorldExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/ClientWorldExtended.java new file mode 100644 index 000000000..47b7fd8af --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/ClientWorldExtended.java @@ -0,0 +1,8 @@ +package me.jellysquid.mods.sodium.client.world; + +public interface ClientWorldExtended { + /** + * @return The world seed used for generating biome data on the client + */ + long getBiomeSeed(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java new file mode 100644 index 000000000..d4e38e79c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -0,0 +1,371 @@ +package me.jellysquid.mods.sodium.client.world; + +import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; +import me.jellysquid.mods.sodium.client.world.biome.BiomeCache; +import me.jellysquid.mods.sodium.client.world.biome.BiomeColorCache; +import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; +import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSection; +import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSectionCache; +import me.jellysquid.mods.sodium.client.world.cloned.PackedIntegerArrayExtended; +import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.fluid.FluidState; +import net.minecraft.util.collection.PackedIntegerArray; +import net.minecraft.util.math.*; +import net.minecraft.world.BlockRenderView; +import net.minecraft.world.LightType; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.source.BiomeAccess; +import net.minecraft.world.chunk.light.LightingProvider; +import net.minecraft.world.level.ColorResolver; + +import java.util.Map; + +/** + * Takes a slice of world state (block states, biome and light data arrays) and copies the data for use in off-thread + * operations. This allows chunk build tasks to see a consistent snapshot of chunk data at the exact moment the task was + * created. + * + * World slices are not safe to use from multiple threads at once, but the data they contain is safe from modification + * by the main client thread. + * + * Object pooling should be used to avoid huge allocations as this class contains many large arrays. + */ +public class WorldSlice implements BlockRenderView, BiomeAccess.Storage { + // The number of blocks on each axis in a section. + private static final int SECTION_BLOCK_LENGTH = 16; + + // The number of blocks in a section. + private static final int SECTION_BLOCK_COUNT = SECTION_BLOCK_LENGTH * SECTION_BLOCK_LENGTH * SECTION_BLOCK_LENGTH; + + // The radius of blocks around the origin chunk that should be copied. + private static final int NEIGHBOR_BLOCK_RADIUS = 2; + + // The radius of chunks around the origin chunk that should be copied. + private static final int NEIGHBOR_CHUNK_RADIUS = MathHelper.roundUpToMultiple(NEIGHBOR_BLOCK_RADIUS, 16) >> 4; + + // The number of sections on each axis of this slice. + private static final int SECTION_LENGTH = 1 + (NEIGHBOR_CHUNK_RADIUS * 2); + + // The size of the lookup tables used for mapping values to coordinate int pairs. The lookup table size is always + // a power of two so that multiplications can be replaced with simple bit shifts in hot code paths. + private static final int TABLE_LENGTH = MathHelper.smallestEncompassingPowerOfTwo(SECTION_LENGTH); + + // The number of bits needed for each X/Y/Z component in a lookup table. + private static final int TABLE_BITS = Integer.bitCount(TABLE_LENGTH - 1); + + // The array size for the section lookup table. + private static final int SECTION_TABLE_ARRAY_SIZE = TABLE_LENGTH * TABLE_LENGTH * TABLE_LENGTH; + + // Fallback BlockState to use if none were available in the array + private static final BlockState NULL_BLOCK_STATE = Blocks.AIR.getDefaultState(); + + // The world this slice has copied data from + private final World world; + + // Local Section->BlockState table. + private final BlockState[][] blockStatesArrays; + + // Local section copies. Read-only. + private ClonedChunkSection[] sections; + + // Biome caches for each chunk section + private BiomeCache[] biomeCaches; + + // The biome blend caches for each color resolver type + // This map is always re-initialized, but the caches themselves are taken from an object pool + private final Map biomeColorCaches = new Reference2ObjectOpenHashMap<>(); + + // The previously accessed and cached color resolver, used in conjunction with the cached color cache field + private ColorResolver prevColorResolver; + + // The cached lookup result for the previously accessed color resolver to avoid excess hash table accesses + // for vertex color blending + private BiomeColorCache prevColorCache; + + // The starting point from which this slice captures blocks + private int baseX, baseY, baseZ; + + // The chunk origin of this slice + private ChunkSectionPos origin; + + public static ChunkRenderContext prepare(World world, ChunkSectionPos origin, ClonedChunkSectionCache sectionCache) { + WorldChunk chunk = world.getChunk(origin.getX(), origin.getZ()); + ChunkSection section = chunk.getSectionArray()[origin.getY()]; + + // If the chunk section is absent or empty, simply terminate now. There will never be anything in this chunk + // section to render, so we need to signal that a chunk render task shouldn't created. This saves a considerable + // amount of time in queueing instant build tasks and greatly accelerates how quickly the world can be loaded. + if (ChunkSection.isEmpty(section)) { + return null; + } + + BlockBox volume = new BlockBox(origin.getMinX() - NEIGHBOR_BLOCK_RADIUS, + origin.getMinY() - NEIGHBOR_BLOCK_RADIUS, + origin.getMinZ() - NEIGHBOR_BLOCK_RADIUS, + origin.getMaxX() + NEIGHBOR_BLOCK_RADIUS, + origin.getMaxY() + NEIGHBOR_BLOCK_RADIUS, + origin.getMaxZ() + NEIGHBOR_BLOCK_RADIUS); + + // The min/max bounds of the chunks copied by this slice + final int minChunkX = origin.getX() - NEIGHBOR_CHUNK_RADIUS; + final int minChunkY = origin.getY() - NEIGHBOR_CHUNK_RADIUS; + final int minChunkZ = origin.getZ() - NEIGHBOR_CHUNK_RADIUS; + + final int maxChunkX = origin.getX() + NEIGHBOR_CHUNK_RADIUS; + final int maxChunkY = origin.getY() + NEIGHBOR_CHUNK_RADIUS; + final int maxChunkZ = origin.getZ() + NEIGHBOR_CHUNK_RADIUS; + + ClonedChunkSection[] sections = new ClonedChunkSection[SECTION_TABLE_ARRAY_SIZE]; + + for (int chunkX = minChunkX; chunkX <= maxChunkX; chunkX++) { + for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; chunkZ++) { + for (int chunkY = minChunkY; chunkY <= maxChunkY; chunkY++) { + sections[getLocalSectionIndex(chunkX - minChunkX, chunkY - minChunkY, chunkZ - minChunkZ)] = + sectionCache.acquire(chunkX, chunkY, chunkZ); + } + } + } + + return new ChunkRenderContext(origin, sections, volume); + } + + public WorldSlice(World world) { + this.world = world; + + this.sections = new ClonedChunkSection[SECTION_TABLE_ARRAY_SIZE]; + this.blockStatesArrays = new BlockState[SECTION_TABLE_ARRAY_SIZE][]; + this.biomeCaches = new BiomeCache[SECTION_TABLE_ARRAY_SIZE]; + + for (int x = 0; x < SECTION_LENGTH; x++) { + for (int y = 0; y < SECTION_LENGTH; y++) { + for (int z = 0; z < SECTION_LENGTH; z++) { + int i = getLocalSectionIndex(x, y, z); + + this.blockStatesArrays[i] = new BlockState[SECTION_BLOCK_COUNT]; + this.biomeCaches[i] = new BiomeCache(this.world); + } + } + } + } + + public void copyData(ChunkRenderContext context) { + this.origin = context.getOrigin(); + this.sections = context.getSections(); + + this.prevColorCache = null; + this.prevColorResolver = null; + + this.biomeColorCaches.clear(); + + this.baseX = (this.origin.getX() - NEIGHBOR_CHUNK_RADIUS) << 4; + this.baseY = (this.origin.getY() - NEIGHBOR_CHUNK_RADIUS) << 4; + this.baseZ = (this.origin.getZ() - NEIGHBOR_CHUNK_RADIUS) << 4; + + for (int x = 0; x < SECTION_LENGTH; x++) { + for (int y = 0; y < SECTION_LENGTH; y++) { + for (int z = 0; z < SECTION_LENGTH; z++) { + int idx = getLocalSectionIndex(x, y, z); + + this.biomeCaches[idx].reset(); + + this.unpackBlockData(this.blockStatesArrays[idx], this.sections[idx], context.getVolume()); + } + } + } + } + + private void unpackBlockData(BlockState[] states, ClonedChunkSection section, BlockBox box) { + if (this.origin.equals(section.getPosition())) { + this.unpackBlockDataZ(states, section); + } else { + this.unpackBlockDataR(states, section, box); + } + } + + private void unpackBlockDataR(BlockState[] states, ClonedChunkSection section, BlockBox box) { + PackedIntegerArray intArray = section.getBlockData(); + ClonedPalette palette = section.getBlockPalette(); + + ChunkSectionPos pos = section.getPosition(); + + int minBlockX = Math.max(box.minX, pos.getMinX()); + int maxBlockX = Math.min(box.maxX, pos.getMaxX()); + + int minBlockY = Math.max(box.minY, pos.getMinY()); + int maxBlockY = Math.min(box.maxY, pos.getMaxY()); + + int minBlockZ = Math.max(box.minZ, pos.getMinZ()); + int maxBlockZ = Math.min(box.maxZ, pos.getMaxZ()); + + for (int y = minBlockY; y <= maxBlockY; y++) { + for (int z = minBlockZ; z <= maxBlockZ; z++) { + for (int x = minBlockX; x <= maxBlockX; x++) { + int blockIdx = getLocalBlockIndex(x & 15, y & 15, z & 15); + int value = intArray.get(blockIdx); + + states[blockIdx] = palette.get(value); + } + } + } + } + + private void unpackBlockDataZ(BlockState[] states, ClonedChunkSection section) { + ((PackedIntegerArrayExtended) section.getBlockData()) + .copyUsingPalette(states, section.getBlockPalette()); + } + + /** + * Helper function to ensure a valid BlockState is always returned (air is returned + * in place of null). + */ + private static BlockState nullableState(BlockState state) { + if(state != null) { + return state; + } else + return NULL_BLOCK_STATE; + } + + @Override + public BlockState getBlockState(BlockPos pos) { + return this.getBlockState(pos.getX(), pos.getY(), pos.getZ()); + } + + public BlockState getBlockState(int x, int y, int z) { + int relX = x - this.baseX; + int relY = y - this.baseY; + int relZ = z - this.baseZ; + + return nullableState(this.blockStatesArrays[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] + [getLocalBlockIndex(relX & 15, relY & 15, relZ & 15)]); + } + + public BlockState getBlockStateRelative(int x, int y, int z) { + return nullableState(this.blockStatesArrays[getLocalSectionIndex(x >> 4, y >> 4, z >> 4)] + [getLocalBlockIndex(x & 15, y & 15, z & 15)]); + } + + @Override + public FluidState getFluidState(BlockPos pos) { + return this.getBlockState(pos) + .getFluidState(); + } + + @Override + public float getBrightness(Direction direction, boolean shaded) { + return this.world.getBrightness(direction, shaded); + } + + @Override + public LightingProvider getLightingProvider() { + return this.world.getLightingProvider(); + } + + @Override + public BlockEntity getBlockEntity(BlockPos pos) { + return this.getBlockEntity(pos.getX(), pos.getY(), pos.getZ()); + } + + public BlockEntity getBlockEntity(int x, int y, int z) { + int relX = x - this.baseX; + int relY = y - this.baseY; + int relZ = z - this.baseZ; + + return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] + .getBlockEntity(relX & 15, relY & 15, relZ & 15); + } + + @Override + public int getColor(BlockPos pos, ColorResolver resolver) { + BiomeColorCache cache; + + if (this.prevColorResolver == resolver) { + cache = this.prevColorCache; + } else { + cache = this.biomeColorCaches.get(resolver); + + if (cache == null) { + this.biomeColorCaches.put(resolver, cache = new BiomeColorCache(resolver, this)); + } + + this.prevColorResolver = resolver; + this.prevColorCache = cache; + } + + return cache.getBlendedColor(pos); + } + + @Override + public int getLightLevel(LightType type, BlockPos pos) { + int relX = pos.getX() - this.baseX; + int relY = pos.getY() - this.baseY; + int relZ = pos.getZ() - this.baseZ; + + return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] + .getLightLevel(type, relX & 15, relY & 15, relZ & 15); + } + + @Override + public int getBaseLightLevel(BlockPos pos, int ambientDarkness) { + return 0; + } + + @Override + public boolean isSkyVisible(BlockPos pos) { + return false; + } + + @Override + public Biome getBiomeForNoiseGen(int x, int y, int z) { + int x2 = (x >> 2) - (this.baseX >> 4); + int z2 = (z >> 2) - (this.baseZ >> 4); + + // Coordinates are in biome space! + // [VanillaCopy] WorldView#getBiomeForNoiseGen(int, int, int) + ClonedChunkSection section = this.sections[getLocalChunkIndex(x2, z2)]; + + if (section != null ) { + return section.getBiomeForNoiseGen(x, y, z); + } + + return this.world.getGeneratorStoredBiome(x, y, z); + } + + /** + * Gets or computes the biome at the given global coordinates. + */ + public Biome getBiome(int x, int y, int z) { + int relX = x - this.baseX; + int relY = y - this.baseY; + int relZ = z - this.baseZ; + + int index = getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4); + + index = index >= biomeCaches.length ? biomeCaches.length - 1 : index; + + BiomeCache cache = this.biomeCaches[index]; + return cache != null ? cache + .getBiome(this, x, relY >> 4, z) : MinecraftClient.getInstance().world.getBiome(new BlockPos(x, y, z)); + } + + public ChunkSectionPos getOrigin() { + return this.origin; + } + + // [VanillaCopy] PalettedContainer#toIndex + public static int getLocalBlockIndex(int x, int y, int z) { + return y << 8 | z << 4 | x; + } + + public static int getLocalSectionIndex(int x, int y, int z) { + return y << TABLE_BITS << TABLE_BITS | z << TABLE_BITS | x; + } + + public static int getLocalChunkIndex(int x, int z) { + return z << TABLE_BITS | x; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java new file mode 100644 index 000000000..54c3b1929 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java @@ -0,0 +1,126 @@ +package me.jellysquid.mods.sodium.client.world; + +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.fluid.FluidState; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.BlockRenderView; +import net.minecraft.world.BlockView; +import net.minecraft.world.LightType; +import net.minecraft.world.RaycastContext; +import net.minecraft.world.chunk.light.LightingProvider; +import net.minecraft.world.level.ColorResolver; + +import javax.annotation.Nullable; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; + +/** + * Wrapper object used to defeat identity comparisons in mods. Since vanilla provides a unique object to them for each + * subchunk, we do the same. + */ +public class WorldSliceLocal implements BlockRenderView { + private final BlockRenderView view; + + public WorldSliceLocal(BlockRenderView view) { + this.view = view; + } + + @Override + public float getBrightness(Direction direction, boolean shaded) { + return view.getBrightness(direction, shaded); + } + + @Override + public LightingProvider getLightingProvider() { + return view.getLightingProvider(); + } + + @Override + public int getColor(BlockPos pos, ColorResolver colorResolver) { + return view.getColor(pos, colorResolver); + } + + @Override + public int getLightLevel(LightType type, BlockPos pos) { + return view.getLightLevel(type, pos); + } + + @Override + public int getBaseLightLevel(BlockPos pos, int ambientDarkness) { + return view.getBaseLightLevel(pos, ambientDarkness); + } + + @Override + public boolean isSkyVisible(BlockPos pos) { + return view.isSkyVisible(pos); + } + + @Override + @Nullable + public BlockEntity getBlockEntity(BlockPos pos) { + return view.getBlockEntity(pos); + } + + @Override + public BlockState getBlockState(BlockPos pos) { + return view.getBlockState(pos); + } + + @Override + public FluidState getFluidState(BlockPos pos) { + return view.getFluidState(pos); + } + + @Override + public int getLuminance(BlockPos pos) { + return view.getLuminance(pos); + } + + @Override + public int getMaxLightLevel() { + return view.getMaxLightLevel(); + } + + @Override + public int getHeight() { + return view.getHeight(); + } + + @Override + public Stream method_29546(Box arg) { + return view.method_29546(arg); + } + + @Override + public BlockHitResult raycast(RaycastContext context) { + return view.raycast(context); + } + + @Override + @Nullable + public BlockHitResult raycastBlock(Vec3d start, Vec3d end, BlockPos pos, VoxelShape shape, BlockState state) { + return view.raycastBlock(start, end, pos, shape, state); + } + + @Override + public double getDismountHeight(VoxelShape blockCollisionShape, Supplier belowBlockCollisionShapeGetter) { + return view.getDismountHeight(blockCollisionShape, belowBlockCollisionShapeGetter); + } + + @Override + public double getDismountHeight(BlockPos pos) { + return view.getDismountHeight(pos); + } + + public static T raycast(RaycastContext arg, BiFunction context, Function blockRaycaster) { + return BlockView.raycast(arg, context, blockRaycaster); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java new file mode 100644 index 000000000..4389ec91b --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java @@ -0,0 +1,39 @@ +package me.jellysquid.mods.sodium.client.world.biome; + +import me.jellysquid.mods.sodium.client.world.ClientWorldExtended; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.source.BiomeAccess; +import net.minecraft.world.biome.source.BiomeAccessType; + +import java.util.Arrays; + +public class BiomeCache { + private final BiomeAccessType type; + private final long seed; + + private final Biome[] biomes; + + public BiomeCache(World world) { + this.type = world.getDimension().getBiomeAccessType(); + this.seed = ((ClientWorldExtended) world).getBiomeSeed(); + + this.biomes = new Biome[16 * 16]; + } + + public Biome getBiome(BiomeAccess.Storage storage, int x, int y, int z) { + int idx = ((z & 15) << 4) | (x & 15); + + Biome biome = this.biomes[idx]; + + if (biome == null) { + this.biomes[idx] = biome = this.type.getBiome(this.seed, x, y, z, storage); + } + + return biome; + } + + public void reset() { + Arrays.fill(this.biomes, null); + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java new file mode 100644 index 000000000..286bdd875 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java @@ -0,0 +1,112 @@ +package me.jellysquid.mods.sodium.client.world.biome; + +import me.jellysquid.mods.sodium.client.util.color.ColorARGB; +import me.jellysquid.mods.sodium.client.world.WorldSlice; +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.world.level.ColorResolver; + +import java.util.Arrays; + +public class BiomeColorCache { + private static final int BLENDED_COLORS_DIM = 16 + 2 * 2; + + private final ColorResolver resolver; + private final WorldSlice slice; + + private final int[] blendedColors; + private final int[] cache; + + private final int radius; + private final int dim; + private final int minX, minZ; + + private final int height; + + private final int blendedColorsMinX; + private final int blendedColorsMinZ; + + public BiomeColorCache(ColorResolver resolver, WorldSlice slice) { + this.resolver = resolver; + this.slice = slice; + this.radius = MinecraftClient.getInstance().options.biomeBlendRadius; + + ChunkSectionPos origin = this.slice.getOrigin(); + + this.minX = origin.getMinX() - (this.radius + 2); + this.minZ = origin.getMinZ() - (this.radius + 2); + + this.height = origin.getMinY(); + this.dim = 16 + ((this.radius + 2) * 2); + + this.blendedColorsMinX = origin.getMinX() - 2; + this.blendedColorsMinZ = origin.getMinZ() - 2; + + this.cache = new int[this.dim * this.dim]; + this.blendedColors = new int[BLENDED_COLORS_DIM * BLENDED_COLORS_DIM]; + + Arrays.fill(this.cache, -1); + Arrays.fill(this.blendedColors, -1); + } + + public int getBlendedColor(BlockPos pos) { + int x2 = pos.getX() - this.blendedColorsMinX; + int z2 = pos.getZ() - this.blendedColorsMinZ; + + int index = (x2 * BLENDED_COLORS_DIM) + z2; + int color = this.blendedColors[index]; + + if (color == -1) { + this.blendedColors[index] = color = this.calculateBlendedColor(pos.getX(), pos.getZ()); + } + + return color; + } + + private int calculateBlendedColor(int posX, int posZ) { + if (this.radius == 0) { + return this.getColor(posX, posZ); + } + + int diameter = (this.radius * 2) + 1; + int area = diameter * diameter; + + int r = 0; + int g = 0; + int b = 0; + + int minX = posX - this.radius; + int minZ = posZ - this.radius; + + int maxX = posX + this.radius; + int maxZ = posZ + this.radius; + + for (int x2 = minX; x2 <= maxX; x2++) { + for (int z2 = minZ; z2 <= maxZ; z2++) { + int color = this.getColor(x2, z2); + + r += ColorARGB.unpackRed(color); + g += ColorARGB.unpackGreen(color); + b += ColorARGB.unpackBlue(color); + } + } + + return ColorARGB.pack(r / area, g / area, b / area, 255); + } + + private int getColor(int x, int z) { + int index = ((x - this.minX) * this.dim) + (z - this.minZ); + int color = this.cache[index]; + + if (color == -1) { + this.cache[index] = color = this.calculateColor(x, z); + } + + return color; + } + + private int calculateColor(int x, int z) { + return this.resolver.getColor(this.slice.getBiome(x, this.height, z), x, z); + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java new file mode 100644 index 000000000..bfb3fb637 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java @@ -0,0 +1,8 @@ +package me.jellysquid.mods.sodium.client.world.biome; + +import net.minecraft.block.BlockState; +import net.minecraft.client.color.block.BlockColorProvider; + +public interface BlockColorsExtended { + BlockColorProvider getColorProvider(BlockState state); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java new file mode 100644 index 000000000..4bf7e4743 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java @@ -0,0 +1,8 @@ +package me.jellysquid.mods.sodium.client.world.biome; + +import net.minecraft.client.color.item.ItemColorProvider; +import net.minecraft.item.ItemStack; + +public interface ItemColorsExtended { + ItemColorProvider getColorProvider(ItemStack stack); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java new file mode 100644 index 000000000..cf0116544 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java @@ -0,0 +1,37 @@ +package me.jellysquid.mods.sodium.client.world.cloned; + +import net.minecraft.util.math.BlockBox; +import net.minecraft.util.math.ChunkSectionPos; + +public class ChunkRenderContext { + private final ChunkSectionPos origin; + private final ClonedChunkSection[] sections; + private final BlockBox volume; + + public ChunkRenderContext(ChunkSectionPos origin, ClonedChunkSection[] sections, BlockBox volume) { + this.origin = origin; + this.sections = sections; + this.volume = volume; + } + + public ClonedChunkSection[] getSections() { + return this.sections; + } + + public ChunkSectionPos getOrigin() { + return this.origin; + } + + public BlockBox getVolume() { + return this.volume; + } + + public void releaseResources() { + for (ClonedChunkSection section : sections) { + if (section != null) { + section.getBackingCache() + .release(section); + } + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java new file mode 100644 index 000000000..e3561e6f5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -0,0 +1,193 @@ +package me.jellysquid.mods.sodium.client.world.cloned; + +import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; +import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; +import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPaletteFallback; +import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalleteArray; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.util.collection.PackedIntegerArray; +import net.minecraft.util.math.BlockBox; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.world.LightType; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.source.BiomeArray; +import net.minecraft.world.chunk.Chunk; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +public class ClonedChunkSection { + private static final LightType[] LIGHT_TYPES = LightType.values(); + private static final ChunkSection EMPTY_SECTION = new ChunkSection(0); + + private final AtomicInteger referenceCount = new AtomicInteger(0); + private final ClonedChunkSectionCache backingCache; + + private final Short2ObjectMap blockEntities; + private final ChunkNibbleArray[] lightDataArrays; + private final World world; + + private ChunkSectionPos pos; + + private PackedIntegerArray blockStateData; + private ClonedPalette blockStatePalette; + + private BiomeArray biomeData; + + private long lastUsedTimestamp = Long.MAX_VALUE; + + ClonedChunkSection(ClonedChunkSectionCache backingCache, World world) { + this.backingCache = backingCache; + this.world = world; + this.blockEntities = new Short2ObjectOpenHashMap<>(); + this.lightDataArrays = new ChunkNibbleArray[LIGHT_TYPES.length]; + } + + public void init(ChunkSectionPos pos) { + WorldChunk chunk = world.getChunk(pos.getX(), pos.getZ()); + + if (chunk == null) { + throw new RuntimeException("Couldn't retrieve chunk at " + pos.toChunkPos()); + } + + ChunkSection section = getChunkSection(chunk, pos); + + if (section == WorldChunk.EMPTY_SECTION /*ChunkSection.isEmpty(section)*/) { + section = EMPTY_SECTION; + } + + this.pos = pos; + + PalettedContainerExtended container = PalettedContainerExtended.cast(section.getContainer());; + + this.blockStateData = copyBlockData(container); + this.blockStatePalette = copyPalette(container); + + for (LightType type : LIGHT_TYPES) { + this.lightDataArrays[type.ordinal()] = world.getLightingProvider() + .get(type) + .getLightSection(pos); + } + + this.biomeData = chunk.getBiomeArray(); + + BlockBox box = new BlockBox(pos.getMinX(), pos.getMinY(), pos.getMinZ(), pos.getMaxX(), pos.getMaxY(), pos.getMaxZ()); + + this.blockEntities.clear(); + + for (Map.Entry entry : chunk.getBlockEntities().entrySet()) { + BlockPos entityPos = entry.getKey(); + + if (box.contains(entityPos)) { + //this.blockEntities.put(BlockPos.asLong(entityPos.getX() & 15, entityPos.getY() & 15, entityPos.getZ() & 15), entry.getValue()); + this.blockEntities.put(ChunkSectionPos.packLocal(entityPos), entry.getValue()); + } + } + } + + public BlockState getBlockState(int x, int y, int z) { + return this.blockStatePalette.get(this.blockStateData.get(y << 8 | z << 4 | x)); + } + + public int getLightLevel(LightType type, int x, int y, int z) { + ChunkNibbleArray array = this.lightDataArrays[type.ordinal()]; + + if (array != null) { + return array.get(x, y, z); + } + + return 0; + } + + public Biome getBiomeForNoiseGen(int x, int y, int z) { + return this.biomeData.getBiomeForNoiseGen(x, y, z); + } + + public BlockEntity getBlockEntity(int x, int y, int z) { + return this.blockEntities.get(packLocal(x, y, z)); + } + + public PackedIntegerArray getBlockData() { + return this.blockStateData; + } + + public ClonedPalette getBlockPalette() { + return this.blockStatePalette; + } + + public ChunkSectionPos getPosition() { + return this.pos; + } + + private static ClonedPalette copyPalette(PalettedContainerExtended container) { + Palette palette = container.getPalette(); + + if (palette instanceof IdListPalette) { + return new ClonedPaletteFallback<>(Block.STATE_IDS); + } + + BlockState[] array = new BlockState[1 << container.getPaletteSize()]; + + for (int i = 0; i < array.length; i++) { + array[i] = palette.getByIndex(i); + + if (array[i] == null) { + break; + } + } + + return new ClonedPalleteArray<>(array, container.getDefaultValue()); + } + + private static PackedIntegerArray copyBlockData(PalettedContainerExtended container) { + PackedIntegerArray array = container.getDataArray(); + long[] storage = array.getStorage(); + + return new PackedIntegerArray(container.getPaletteSize(), array.getSize(), storage.clone()); + } + + private static ChunkSection getChunkSection(Chunk chunk, ChunkSectionPos pos) { + ChunkSection section = null; + + if (!World.isOutOfBuildLimitVertically(ChunkSectionPos.getBlockCoord(pos.getY()))) { + section = chunk.getSectionArray()[pos.getY()]; + } + + return section; + } + + public void acquireReference() { + this.referenceCount.incrementAndGet(); + } + + public boolean releaseReference() { + return this.referenceCount.decrementAndGet() <= 0; + } + + public long getLastUsedTimestamp() { + return this.lastUsedTimestamp; + } + + public void setLastUsedTimestamp(long timestamp) { + this.lastUsedTimestamp = timestamp; + } + + public ClonedChunkSectionCache getBackingCache() { + return this.backingCache; + } + + /** + * @param x The local x-coordinate + * @param y The local y-coordinate + * @param z The local z-coordinate + * @return An index which can be used to key entities or blocks within a chunk + */ + private static short packLocal(int x, int y, int z) { + return (short) (x << 8 | z << 4 | y); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java new file mode 100644 index 000000000..79d89ef33 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java @@ -0,0 +1,73 @@ +package me.jellysquid.mods.sodium.client.world.cloned; + +import it.unimi.dsi.fastutil.longs.Long2ReferenceLinkedOpenHashMap; +import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.world.World; + +import java.util.concurrent.TimeUnit; + +public class ClonedChunkSectionCache { + private static final int MAX_CACHE_SIZE = 512; /* number of entries */ + private static final long MAX_CACHE_DURATION = TimeUnit.SECONDS.toNanos(5); /* number of nanoseconds */ + + private final World world; + + private final Long2ReferenceLinkedOpenHashMap byPosition = new Long2ReferenceLinkedOpenHashMap<>(); + private long time; // updated once per frame to be the elapsed time since application start + + public ClonedChunkSectionCache(World world) { + this.world = world; + this.time = getMonotonicTimeSource(); + } + + public synchronized void cleanup() { + this.time = getMonotonicTimeSource(); + this.byPosition.values() + .removeIf(entry -> this.time > (entry.getLastUsedTimestamp() + MAX_CACHE_DURATION)); + } + + public synchronized ClonedChunkSection acquire(int x, int y, int z) { + long key = ChunkSectionPos.asLong(x, y, z); + ClonedChunkSection section = this.byPosition.get(key); + + if (section == null) { + while (this.byPosition.size() >= MAX_CACHE_SIZE) { + this.byPosition.removeFirst(); + } + + section = this.createSection(x, y, z); + } + + section.setLastUsedTimestamp(this.time); + + return section; + } + + private ClonedChunkSection createSection(int x, int y, int z) { + ClonedChunkSection section = this.allocate(); + + ChunkSectionPos pos = ChunkSectionPos.from(x, y, z); + section.init(pos); + + this.byPosition.putAndMoveToLast(pos.asLong(), section); + + return section; + } + + public synchronized void invalidate(int x, int y, int z) { + this.byPosition.remove(ChunkSectionPos.asLong(x, y, z)); + } + + public void release(ClonedChunkSection section) { + + } + + private ClonedChunkSection allocate() { + return new ClonedChunkSection(this, this.world); + } + + private static long getMonotonicTimeSource() { + // Should be monotonic in JDK 17 on sane platforms... + return System.nanoTime(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PackedIntegerArrayExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PackedIntegerArrayExtended.java new file mode 100644 index 000000000..a7a5bc2ce --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PackedIntegerArrayExtended.java @@ -0,0 +1,7 @@ +package me.jellysquid.mods.sodium.client.world.cloned; + +import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; + +public interface PackedIntegerArrayExtended { + void copyUsingPalette(T[] out, ClonedPalette palette); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java new file mode 100644 index 000000000..2baf1f112 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java @@ -0,0 +1,20 @@ +package me.jellysquid.mods.sodium.client.world.cloned; + +import net.minecraft.util.collection.PackedIntegerArray; +import net.minecraft.world.chunk.Palette; +import net.minecraft.world.chunk.PalettedContainer; + +public interface PalettedContainerExtended { + @SuppressWarnings("unchecked") + static PalettedContainerExtended cast(PalettedContainer container) { + return (PalettedContainerExtended) container; + } + + PackedIntegerArray getDataArray(); + + Palette getPalette(); + + T getDefaultValue(); + + int getPaletteSize(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalette.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalette.java new file mode 100644 index 000000000..8944da988 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalette.java @@ -0,0 +1,5 @@ +package me.jellysquid.mods.sodium.client.world.cloned.palette; + +public interface ClonedPalette { + K get(int id); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java new file mode 100644 index 000000000..c8ed02f4a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java @@ -0,0 +1,16 @@ +package me.jellysquid.mods.sodium.client.world.cloned.palette; + +import net.minecraft.util.collection.IdList; + +public class ClonedPaletteFallback implements ClonedPalette { + private final IdList idList; + + public ClonedPaletteFallback(IdList idList) { + this.idList = idList; + } + + @Override + public K get(int id) { + return this.idList.get(id); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalleteArray.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalleteArray.java new file mode 100644 index 000000000..af0cbfc3e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalleteArray.java @@ -0,0 +1,22 @@ +package me.jellysquid.mods.sodium.client.world.cloned.palette; + +public class ClonedPalleteArray implements ClonedPalette { + private final K[] array; + private final K defaultValue; + + public ClonedPalleteArray(K[] array, K defaultValue) { + this.array = array; + this.defaultValue = defaultValue; + } + + @Override + public K get(int id) { + K value = this.array[id]; + + if (value == null) { + return this.defaultValue; + } + + return value; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/common/config/Option.java b/src/main/java/me/jellysquid/mods/sodium/common/config/Option.java new file mode 100644 index 000000000..79e7ccc83 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/common/config/Option.java @@ -0,0 +1,63 @@ +package me.jellysquid.mods.sodium.common.config; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +public class Option { + private final String name; + + private Set modDefined = null; + private boolean enabled; + private boolean userDefined; + + public Option(String name, boolean enabled, boolean userDefined) { + this.name = name; + this.enabled = enabled; + this.userDefined = userDefined; + } + + public void setEnabled(boolean enabled, boolean userDefined) { + this.enabled = enabled; + this.userDefined = userDefined; + } + + public void addModOverride(boolean enabled, String modId) { + this.enabled = enabled; + + if (this.modDefined == null) { + this.modDefined = new LinkedHashSet<>(); + } + + this.modDefined.add(modId); + } + + public boolean isEnabled() { + return this.enabled; + } + + public boolean isOverridden() { + return this.isUserDefined() || this.isModDefined(); + } + + public boolean isUserDefined() { + return this.userDefined; + } + + public boolean isModDefined() { + return this.modDefined != null; + } + + public String getName() { + return this.name; + } + + public void clearModsDefiningValue() { + this.modDefined = null; + } + + public Collection getDefiningMods() { + return this.modDefined != null ? Collections.unmodifiableCollection(this.modDefined) : Collections.emptyList(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java b/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java new file mode 100644 index 000000000..b131b3b62 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java @@ -0,0 +1,219 @@ +package me.jellysquid.mods.sodium.common.config; + +import net.minecraftforge.fml.loading.FMLEnvironment; +import net.minecraftforge.fml.loading.FMLLoader; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Documentation of these options: https://github.com/jellysquid3/sodium-fabric/wiki/Configuration-File + */ +public class SodiumConfig { + private static final Logger LOGGER = LogManager.getLogger("EmbeddiumConfig"); + + private static final String JSON_KEY_SODIUM_OPTIONS = "sodium:options"; + + private static final Set SYSTEM_OPTIONS = Stream.of( + "core", + "features.chunk_rendering" + ).map(SodiumConfig::getMixinRuleName).collect(Collectors.toSet()); + + private final Map options = new HashMap<>(); + + private SodiumConfig() { + // Defines the default rules which can be configured by the user or other mods. + // You must manually add a rule for any new mixins not covered by an existing package rule. + this.addMixinRule("core", true); // TODO: Don't actually allow the user to disable this + + this.addMixinRule("features.block", true); + this.addMixinRule("features.buffer_builder", true); + this.addMixinRule("features.buffer_builder.fast_advance", true); + this.addMixinRule("features.buffer_builder.fast_sort", true); + this.addMixinRule("features.buffer_builder.intrinsics", true); + this.addMixinRule("features.chunk_rendering", true); + this.addMixinRule("features.debug", true); + this.addMixinRule("features.entity", true); + this.addMixinRule("features.entity.fast_render", true); + this.addMixinRule("features.entity.smooth_lighting", true); + this.addMixinRule("features.gui", true); + this.addMixinRule("features.gui.fast_loading_screen", true); + this.addMixinRule("features.gui.fast_status_bars", true); + this.addMixinRule("features.gui.fast_fps_pie", true); + this.addMixinRule("features.gui.font", true); + this.addMixinRule("features.item", true); + this.addMixinRule("features.matrix_stack", true); + this.addMixinRule("features.model", true); + this.addMixinRule("features.optimized_bamboo", true); + this.addMixinRule("features.options", true); + this.addMixinRule("features.particle", true); + this.addMixinRule("features.particle.cull", true); + this.addMixinRule("features.particle.fast_render", true); + this.addMixinRule("features.render_layer", true); + this.addMixinRule("features.render_layer.leaves", true); + this.addMixinRule("features.sky", true); + this.addMixinRule("features.texture_tracking", true); + this.addMixinRule("features.world_ticking", true); + this.addMixinRule("features.fast_biome_colors", true); + + if(FMLLoader.getLoadingModList().getModFileById("seamless_loading_screen") != null) { this.options.get("mixin.features.gui.fast_loading_screen").addModOverride(false, "seamless_loading_screen"); } + + if(FMLLoader.getLoadingModList().getModFileById("abnormals_core") != null) { this.options.get("mixin.features.world_ticking").addModOverride(false, "abnormals_core"); } + + } + + /** + * Defines a Mixin rule which can be configured by users and other mods. + * @throws IllegalStateException If a rule with that name already exists + * @param mixin The name of the mixin package which will be controlled by this rule + * @param enabled True if the rule will be enabled by default, otherwise false + */ + private void addMixinRule(String mixin, boolean enabled) { + String name = getMixinRuleName(mixin); + + if (this.options.putIfAbsent(name, new Option(name, enabled, false)) != null) { + throw new IllegalStateException("Mixin rule already defined: " + mixin); + } + } + + private void readProperties(Properties props) { + for (Map.Entry entry : props.entrySet()) { + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + + Option option = this.options.get(key); + + if (option == null) { + LOGGER.warn("No configuration key exists with name '{}', ignoring", key); + continue; + } + + boolean enabled; + + if (value.equalsIgnoreCase("true")) { + enabled = true; + } else if (value.equalsIgnoreCase("false")) { + enabled = false; + } else { + LOGGER.warn("Invalid value '{}' encountered for configuration key '{}', ignoring", value, key); + continue; + } + + if(!enabled && FMLEnvironment.production && SYSTEM_OPTIONS.contains(key)) { + LOGGER.warn("Configuration key '{}' is a required option and cannot be disabled", key); + continue; + } + + option.setEnabled(enabled, true); + } + } + + /** + * Returns the effective option for the specified class name. This traverses the package path of the given mixin + * and checks each root for configuration rules. If a configuration rule disables a package, all mixins located in + * that package and its children will be disabled. The effective option is that of the highest-priority rule, either + * a enable rule at the end of the chain or a disable rule at the earliest point in the chain. + * + * @return Null if no options matched the given mixin name, otherwise the effective option for this Mixin + */ + public Option getEffectiveOptionForMixin(String mixinClassName) { + int lastSplit = 0; + int nextSplit; + + Option rule = null; + + while ((nextSplit = mixinClassName.indexOf('.', lastSplit)) != -1) { + String key = getMixinRuleName(mixinClassName.substring(0, nextSplit)); + + Option candidate = this.options.get(key); + + if (candidate != null) { + rule = candidate; + + if (!rule.isEnabled()) { + return rule; + } + } + + lastSplit = nextSplit + 1; + } + + return rule; + } + + /** + * Loads the configuration file from the specified location. If it does not exist, a new configuration file will be + * created. The file on disk will then be updated to include any new options. + */ + public static SodiumConfig load(File file) { + if (!file.exists()) { + try { + writeDefaultConfig(file); + } catch (IOException e) { + LOGGER.warn("Could not write default configuration file", e); + } + + return new SodiumConfig(); + } + + Properties props = new Properties(); + + try (FileInputStream fin = new FileInputStream(file)){ + props.load(fin); + } catch (IOException e) { + throw new RuntimeException("Could not load config file", e); + } + + SodiumConfig config = new SodiumConfig(); + config.readProperties(props); + + return config; + } + + private static void writeDefaultConfig(File file) throws IOException { + File dir = file.getParentFile(); + + if (!dir.exists()) { + if (!dir.mkdirs()) { + throw new IOException("Could not create parent directories"); + } + } else if (!dir.isDirectory()) { + throw new IOException("The parent file is not a directory"); + } + + try (Writer writer = new FileWriter(file)) { + writer.write("# This is the configuration file for Sodium.\n"); + writer.write("#\n"); + writer.write("# You can find information on editing this file and all the available options here:\n"); + writer.write("# https://github.com/jellysquid3/sodium-fabric/wiki/Configuration-File\n"); + writer.write("#\n"); + writer.write("# By default, this file will be empty except for this notice.\n"); + } + } + + private static String getMixinRuleName(String name) { + return "mixin." + name; + } + + public int getOptionCount() { + return this.options.size(); + } + + public int getOptionOverrideCount() { + return (int) this.options.values() + .stream() + .filter(Option::isOverridden) + .count(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java b/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java new file mode 100644 index 000000000..9e50b953e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java @@ -0,0 +1,15 @@ +package me.jellysquid.mods.sodium.common.util; + +import net.minecraft.util.math.Direction; + +/** + * Contains a number of cached arrays to avoid allocations since calling Enum#values() requires the backing array to + * be cloned every time. + */ +public class DirectionUtil { + public static final Direction[] ALL_DIRECTIONS = Direction.values(); + public static final int DIRECTION_COUNT = ALL_DIRECTIONS.length; + + // Provides the same order as enumerating Direction and checking the axis of each value + public static final Direction[] HORIZONTAL_DIRECTIONS = new Direction[] { Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST }; +} diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/IdTable.java b/src/main/java/me/jellysquid/mods/sodium/common/util/IdTable.java new file mode 100644 index 000000000..7308507c0 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/IdTable.java @@ -0,0 +1,60 @@ +package me.jellysquid.mods.sodium.common.util; + +import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue; + +import java.util.Arrays; + +public class IdTable { + private final IntArrayFIFOQueue freeIds = new IntArrayFIFOQueue(); + + private T[] elements; + private int nextId; + private int capacity; + + @SuppressWarnings("unchecked") + public IdTable(int capacity) { + this.elements = (T[]) new Object[capacity]; + this.capacity = capacity; + } + + public int add(T element) { + int id = this.allocateId(); + + if (id >= this.capacity) { + this.grow(); + } + + this.elements[id] = element; + + return id; + } + + private void grow() { + this.elements = Arrays.copyOf(this.elements, this.capacity *= 2); + } + + public void remove(int id) { + this.elements[id] = null; + this.freeIds.enqueue(id); + } + + private int allocateId() { + if (!this.freeIds.isEmpty()) { + return this.freeIds.dequeueInt(); + } + + return this.nextId++; + } + + public T get(int id) { + return this.elements[id]; + } + + public void set(int id, T value) { + this.elements[id] = value; + } + + public Object[] getElements() { + return this.elements; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/ListUtil.java b/src/main/java/me/jellysquid/mods/sodium/common/util/ListUtil.java new file mode 100644 index 000000000..1002fbcc9 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/ListUtil.java @@ -0,0 +1,16 @@ +package me.jellysquid.mods.sodium.common.util; + +import java.util.Collection; + +public class ListUtil { + public static void updateList(Collection collection, Collection before, Collection after) { + if (!before.isEmpty()) { + collection.removeAll(before); + } + + if (!after.isEmpty()) { + collection.addAll(after); + } + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/collections/DequeDrain.java b/src/main/java/me/jellysquid/mods/sodium/common/util/collections/DequeDrain.java new file mode 100644 index 000000000..a9685b9a1 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/collections/DequeDrain.java @@ -0,0 +1,22 @@ +package me.jellysquid.mods.sodium.common.util.collections; + +import java.util.Deque; +import java.util.Iterator; + +public class DequeDrain implements Iterator { + private final Deque deque; + + public DequeDrain(Deque deque) { + this.deque = deque; + } + + @Override + public boolean hasNext() { + return !this.deque.isEmpty(); + } + + @Override + public T next() { + return this.deque.remove(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java b/src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java new file mode 100644 index 000000000..c24c039d4 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java @@ -0,0 +1,52 @@ +package me.jellysquid.mods.sodium.common.util.collections; + +import java.util.Deque; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; + +public class FutureDequeDrain implements Iterator { + private final Deque> deque; + private T next = null; + + public FutureDequeDrain(Deque> deque) { + this.deque = deque; + } + + @Override + public boolean hasNext() { + if (next != null) { + return true; + } + + findNext(); + + return next != null; + } + + private void findNext() { + while (!deque.isEmpty()) { + CompletableFuture future = deque.remove(); + + try { + next = future.join(); + return; + } catch (CancellationException e) { + // no-op + } + } + } + + @Override + public T next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + T result = next; + next = null; + + return result; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/SodiumMixinPlugin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/SodiumMixinPlugin.java new file mode 100644 index 000000000..407a20e37 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/SodiumMixinPlugin.java @@ -0,0 +1,95 @@ +package me.jellysquid.mods.sodium.mixin; + +import me.jellysquid.mods.sodium.common.config.Option; +import me.jellysquid.mods.sodium.common.config.SodiumConfig; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.io.File; +import java.util.List; +import java.util.Set; + +public class SodiumMixinPlugin implements IMixinConfigPlugin { + private static final String MIXIN_PACKAGE_ROOT = "me.jellysquid.mods.sodium.mixin."; + + private final Logger logger = LogManager.getLogger("Embeddium"); + private SodiumConfig config; + + @Override + public void onLoad(String mixinPackage) { + try { + this.config = SodiumConfig.load(new File("./config/rubidium-mixins.properties")); + } catch (Exception e) { + throw new RuntimeException("Could not load configuration file for Embeddium", e); + } + + this.logger.info("Loaded configuration file for Embeddium: {} options available, {} override(s) found", + this.config.getOptionCount(), this.config.getOptionOverrideCount()); + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + if (!mixinClassName.startsWith(MIXIN_PACKAGE_ROOT)) { + this.logger.error("Expected mixin '{}' to start with package root '{}', treating as foreign and " + + "disabling!", mixinClassName, MIXIN_PACKAGE_ROOT); + + return false; + } + + String mixin = mixinClassName.substring(MIXIN_PACKAGE_ROOT.length()); + Option option = this.config.getEffectiveOptionForMixin(mixin); + + if (option == null) { + this.logger.error("No rules matched mixin '{}', treating as foreign and disabling!", mixin); + + return false; + } + + if (option.isOverridden()) { + String source = "[unknown]"; + + if (option.isUserDefined()) { + source = "user configuration"; + } else if (option.isModDefined()) { + source = "mods [" + String.join(", ", option.getDefiningMods()) + "]"; + } + + if (option.isEnabled()) { + this.logger.warn("Force-enabling mixin '{}' as rule '{}' (added by {}) enables it", mixin, + option.getName(), source); + } else { + this.logger.warn("Force-disabling mixin '{}' as rule '{}' (added by {}) disables it and children", mixin, + option.getName(), source); + } + } + + return option.isEnabled(); + } + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/MixinDirection.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/MixinDirection.java new file mode 100644 index 000000000..1a0fd85a0 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/MixinDirection.java @@ -0,0 +1,66 @@ +package me.jellysquid.mods.sodium.mixin.core; + +import net.minecraft.client.render.OverlayVertexConsumer; +import net.minecraft.client.render.model.BakedQuadFactory; +import net.minecraft.client.render.model.json.JsonUnbakedModel; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.Direction; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(Direction.class) +public class MixinDirection { + /** + * Used by: + *

+ * + * @author Mitchell Skaggs + * @reason Avoid looping over all directions and computing the dot product + */ + @Overwrite + public static Direction getFacing(float x, float y, float z) { + // Vanilla quirk: return NORTH if all entries are zero + if (x == 0 && y == 0 && z == 0) + return Direction.NORTH; + + // First choice in ties: negative, positive; Y, Z, X + float yM = Math.abs(y); + float zM = Math.abs(z); + float xM = Math.abs(x); + + if (yM >= zM) { + if (yM >= xM) { + // Y biggest + if (y <= 0) { + return Direction.DOWN; + } else /* y > 0 */ { + return Direction.UP; + } + } else /* zM <= yM < xM */ { + // X biggest, fall through + } + } else /* yM < zM */ { + if (zM >= xM) { + // Z biggest + if (z <= 0) { + return Direction.NORTH; + } else /* z > 0 */ { + return Direction.SOUTH; + } + } else /* yM < zM < xM */ { + // X biggest, fall through + } + } + + // X biggest + if (x <= 0) { + return Direction.WEST; + } else /* x > 0 */ { + return Direction.EAST; + } + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/frustum/MixinFrustum.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/frustum/MixinFrustum.java new file mode 100644 index 000000000..aef74d67c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/frustum/MixinFrustum.java @@ -0,0 +1,115 @@ +package me.jellysquid.mods.sodium.mixin.core.frustum; + +import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; +import net.minecraft.client.render.Frustum; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Matrix4f; +import net.minecraft.util.math.Vector4f; +import net.minecraftforge.common.extensions.IForgeTileEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Frustum.class) +public abstract class MixinFrustum implements FrustumExtended { + @Shadow public abstract boolean isVisible(double minX, double minY, double minZ, double maxX, double maxY, double maxZ); + + private float xF, yF, zF; + + private float nxX, nxY, nxZ, nxW; + private float pxX, pxY, pxZ, pxW; + private float nyX, nyY, nyZ, nyW; + private float pyX, pyY, pyZ, pyW; + private float nzX, nzY, nzZ, nzW; + private float pzX, pzY, pzZ, pzW; + + @Inject(method = "setPosition", at = @At("HEAD")) + private void prePositionUpdate(double cameraX, double cameraY, double cameraZ, CallbackInfo ci) { + this.xF = (float) cameraX; + this.yF = (float) cameraY; + this.zF = (float) cameraZ; + } + + @Inject(method = "transform", at = @At("HEAD")) + private void transform(Matrix4f mat, int x, int y, int z, int index, CallbackInfo ci) { + Vector4f vec = new Vector4f((float) x, (float) y, (float) z, 1.0F); + vec.transform(mat); + vec.normalize(); + + switch (index) { + case 0: + this.nxX = vec.getX(); + this.nxY = vec.getY(); + this.nxZ = vec.getZ(); + this.nxW = vec.getW(); + break; + case 1: + this.pxX = vec.getX(); + this.pxY = vec.getY(); + this.pxZ = vec.getZ(); + this.pxW = vec.getW(); + break; + case 2: + this.nyX = vec.getX(); + this.nyY = vec.getY(); + this.nyZ = vec.getZ(); + this.nyW = vec.getW(); + break; + case 3: + this.pyX = vec.getX(); + this.pyY = vec.getY(); + this.pyZ = vec.getZ(); + this.pyW = vec.getW(); + break; + case 4: + this.nzX = vec.getX(); + this.nzY = vec.getY(); + this.nzZ = vec.getZ(); + this.nzW = vec.getW(); + break; + case 5: + this.pzX = vec.getX(); + this.pzY = vec.getY(); + this.pzZ = vec.getZ(); + this.pzW = vec.getW(); + break; + default: + throw new IllegalArgumentException("Invalid index"); + } + } + + @Override + public boolean fastAabbTest(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + return this.isAnyCornerVisible(minX - this.xF, minY - this.yF, minZ - this.zF, + maxX - this.xF, maxY - this.yF, maxZ - this.zF); + } + + /** + * @author XFactHD (ported by embeddedt) + * @reason Avoid passing infinite extents box into optimized frustum code. + * This is a port of PR #9407 + */ + @Overwrite + public boolean isVisible(Box box) { + if(box.equals(IForgeTileEntity.INFINITE_EXTENT_AABB)) + return true; + return this.isVisible(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ); + } + + /** + * @author JellySquid + * @reason Optimize away object allocations and for-loop + */ + @Overwrite + private boolean isAnyCornerVisible(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + return this.nxX * (this.nxX < 0 ? minX : maxX) + this.nxY * (this.nxY < 0 ? minY : maxY) + this.nxZ * (this.nxZ < 0 ? minZ : maxZ) >= -this.nxW && + this.pxX * (this.pxX < 0 ? minX : maxX) + this.pxY * (this.pxY < 0 ? minY : maxY) + this.pxZ * (this.pxZ < 0 ? minZ : maxZ) >= -this.pxW && + this.nyX * (this.nyX < 0 ? minX : maxX) + this.nyY * (this.nyY < 0 ? minY : maxY) + this.nyZ * (this.nyZ < 0 ? minZ : maxZ) >= -this.nyW && + this.pyX * (this.pyX < 0 ? minX : maxX) + this.pyY * (this.pyY < 0 ? minY : maxY) + this.pyZ * (this.pyZ < 0 ? minZ : maxZ) >= -this.pyW && + this.nzX * (this.nzX < 0 ? minX : maxX) + this.nzY * (this.nzY < 0 ? minY : maxY) + this.nzZ * (this.nzZ < 0 ? minZ : maxZ) >= -this.nzW && + this.pzX * (this.pzX < 0 ? minX : maxX) + this.pzY * (this.pzY < 0 ? minY : maxY) + this.pzZ * (this.pzZ < 0 ? minZ : maxZ) >= -this.pzW; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinGameRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinGameRenderer.java new file mode 100644 index 000000000..9fe8f2c31 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinGameRenderer.java @@ -0,0 +1,17 @@ +package me.jellysquid.mods.sodium.mixin.core.matrix; + +import me.jellysquid.mods.sodium.client.render.GameRendererContext; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.util.math.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GameRenderer.class) +public class MixinGameRenderer { + @Inject(method = "loadProjectionMatrix", at = @At("HEAD")) + public void captureProjectionMatrix(Matrix4f matrix, CallbackInfo ci) { + GameRendererContext.captureProjectionMatrix(matrix); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix3f.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix3f.java new file mode 100644 index 000000000..03fc9c999 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix3f.java @@ -0,0 +1,229 @@ +package me.jellysquid.mods.sodium.mixin.core.matrix; + +import me.jellysquid.mods.sodium.client.util.Norm3b; +import me.jellysquid.mods.sodium.client.util.math.Matrix3fExtended; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Matrix3f; +import net.minecraft.util.math.Quaternion; +import net.minecraft.util.math.Vec3i; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(Matrix3f.class) +public class MixinMatrix3f implements Matrix3fExtended { + @Shadow + protected float a00; + + @Shadow + protected float a10; + + @Shadow + protected float a20; + + @Shadow + protected float a01; + + @Shadow + protected float a11; + + @Shadow + protected float a21; + + @Shadow + protected float a02; + + @Shadow + protected float a12; + + @Shadow + protected float a22; + + @Override + public float transformVecX(float x, float y, float z) { + return this.a00 * x + this.a01 * y + this.a02 * z; + } + + @Override + public float transformVecY(float x, float y, float z) { + return this.a10 * x + this.a11 * y + this.a12 * z; + } + + @Override + public float transformVecZ(float x, float y, float z) { + return this.a20 * x + this.a21 * y + this.a22 * z; + } + + @Override + public void rotate(Quaternion quaternion) { + boolean x = quaternion.getX() != 0.0F; + boolean y = quaternion.getY() != 0.0F; + boolean z = quaternion.getZ() != 0.0F; + + // Try to determine if this is a simple rotation on one axis component only + if (x) { + if (!y && !z) { + this.rotateX(quaternion); + } else { + this.rotateXYZ(quaternion); + } + } else if (y) { + if (!z) { + this.rotateY(quaternion); + } else { + this.rotateXYZ(quaternion); + } + } else if (z) { + this.rotateZ(quaternion); + } + } + + @Override + public int computeNormal(Direction dir) { + Vec3i faceNorm = dir.getVector(); + + float x = faceNorm.getX(); + float y = faceNorm.getY(); + float z = faceNorm.getZ(); + + float x2 = this.a00 * x + this.a01 * y + this.a02 * z; + float y2 = this.a10 * x + this.a11 * y + this.a12 * z; + float z2 = this.a20 * x + this.a21 * y + this.a22 * z; + + return Norm3b.pack(x2, y2, z2); + } + + private void rotateX(Quaternion quaternion) { + float x = quaternion.getX(); + float w = quaternion.getW(); + + float xx = 2.0F * x * x; + + float ta11 = 1.0F - xx; + float ta22 = 1.0F - xx; + + float xw = x * w; + float ta21 = 2.0F * xw; + float ta12 = 2.0F * -xw; + + float a01 = this.a01 * ta11 + this.a02 * ta21; + float a02 = this.a01 * ta12 + this.a02 * ta22; + float a11 = this.a11 * ta11 + this.a12 * ta21; + float a12 = this.a11 * ta12 + this.a12 * ta22; + float a21 = this.a21 * ta11 + this.a22 * ta21; + float a22 = this.a21 * ta12 + this.a22 * ta22; + + this.a01 = a01; + this.a02 = a02; + this.a11 = a11; + this.a12 = a12; + this.a21 = a21; + this.a22 = a22; + } + + private void rotateY(Quaternion quaternion) { + float y = quaternion.getY(); + float w = quaternion.getW(); + + float yy = 2.0F * y * y; + + float ta00 = 1.0F - yy; + float ta22 = 1.0F - yy; + + float yw = y * w; + + float ta20 = 2.0F * (-yw); + float ta02 = 2.0F * (+yw); + + float a00 = this.a00 * ta00 + this.a02 * ta20; + float a02 = this.a00 * ta02 + this.a02 * ta22; + float a10 = this.a10 * ta00 + this.a12 * ta20; + float a12 = this.a10 * ta02 + this.a12 * ta22; + float a20 = this.a20 * ta00 + this.a22 * ta20; + float a22 = this.a20 * ta02 + this.a22 * ta22; + + this.a00 = a00; + this.a02 = a02; + this.a10 = a10; + this.a12 = a12; + this.a20 = a20; + this.a22 = a22; + } + + private void rotateZ(Quaternion quaternion) { + float z = quaternion.getZ(); + float w = quaternion.getW(); + + float zz = 2.0F * z * z; + + float ta00 = 1.0F - zz; + float ta11 = 1.0F - zz; + + float zw = z * w; + + float ta10 = 2.0F * (0.0F + zw); + float ta01 = 2.0F * (0.0F - zw); + + float a00 = this.a00 * ta00 + this.a01 * ta10; + float a01 = this.a00 * ta01 + this.a01 * ta11; + float a10 = this.a10 * ta00 + this.a11 * ta10; + float a11 = this.a10 * ta01 + this.a11 * ta11; + float a20 = this.a20 * ta00 + this.a21 * ta10; + float a21 = this.a20 * ta01 + this.a21 * ta11; + + this.a00 = a00; + this.a01 = a01; + this.a10 = a10; + this.a11 = a11; + this.a20 = a20; + this.a21 = a21; + } + + private void rotateXYZ(Quaternion quaternion) { + float x = quaternion.getX(); + float y = quaternion.getY(); + float z = quaternion.getZ(); + float w = quaternion.getW(); + + float xx = 2.0F * x * x; + float yy = 2.0F * y * y; + float zz = 2.0F * z * z; + + float ta00 = 1.0F - yy - zz; + float ta11 = 1.0F - zz - xx; + float ta22 = 1.0F - xx - yy; + + float xy = x * y; + float yz = y * z; + float zx = z * x; + float xw = x * w; + float yw = y * w; + float zw = z * w; + + float ta10 = 2.0F * (xy + zw); + float ta01 = 2.0F * (xy - zw); + float ta20 = 2.0F * (zx - yw); + float ta02 = 2.0F * (zx + yw); + float ta21 = 2.0F * (yz + xw); + float ta12 = 2.0F * (yz - xw); + + float a00 = this.a00 * ta00 + this.a01 * ta10 + this.a02 * ta20; + float a01 = this.a00 * ta01 + this.a01 * ta11 + this.a02 * ta21; + float a02 = this.a00 * ta02 + this.a01 * ta12 + this.a02 * ta22; + float a10 = this.a10 * ta00 + this.a11 * ta10 + this.a12 * ta20; + float a11 = this.a10 * ta01 + this.a11 * ta11 + this.a12 * ta21; + float a12 = this.a10 * ta02 + this.a11 * ta12 + this.a12 * ta22; + float a20 = this.a20 * ta00 + this.a21 * ta10 + this.a22 * ta20; + float a21 = this.a20 * ta01 + this.a21 * ta11 + this.a22 * ta21; + float a22 = this.a20 * ta02 + this.a21 * ta12 + this.a22 * ta22; + + this.a00 = a00; + this.a01 = a01; + this.a02 = a02; + this.a10 = a10; + this.a11 = a11; + this.a12 = a12; + this.a20 = a20; + this.a21 = a21; + this.a22 = a22; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix4f.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix4f.java new file mode 100644 index 000000000..43361ffd8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix4f.java @@ -0,0 +1,313 @@ +package me.jellysquid.mods.sodium.mixin.core.matrix; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; +import net.minecraft.util.math.Matrix4f; +import net.minecraft.util.math.Quaternion; +import org.lwjgl.system.MemoryUtil; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.nio.BufferUnderflowException; +import java.nio.FloatBuffer; + +@Mixin(Matrix4f.class) +public class MixinMatrix4f implements Matrix4fExtended { + @Shadow + protected float a00; + + @Shadow + protected float a01; + + @Shadow + protected float a02; + + @Shadow + protected float a03; + + @Shadow + protected float a10; + + @Shadow + protected float a11; + + @Shadow + protected float a12; + + @Shadow + protected float a13; + + @Shadow + protected float a20; + + @Shadow + protected float a21; + + @Shadow + protected float a22; + + @Shadow + protected float a23; + + @Shadow + protected float a30; + + @Shadow + protected float a31; + + @Shadow + protected float a32; + + @Shadow + protected float a33; + + @Override + public void translate(float x, float y, float z) { + this.a03 = this.a00 * x + this.a01 * y + this.a02 * z + this.a03; + this.a13 = this.a10 * x + this.a11 * y + this.a12 * z + this.a13; + this.a23 = this.a20 * x + this.a21 * y + this.a22 * z + this.a23; + this.a33 = this.a30 * x + this.a31 * y + this.a32 * z + this.a33; + } + + @Override + public float transformVecX(float x, float y, float z) { + return (this.a00 * x) + (this.a01 * y) + (this.a02 * z) + (this.a03 * 1.0f); + } + + @Override + public float transformVecY(float x, float y, float z) { + return (this.a10 * x) + (this.a11 * y) + (this.a12 * z) + (this.a13 * 1.0f); + } + + @Override + public float transformVecZ(float x, float y, float z) { + return (this.a20 * x) + (this.a21 * y) + (this.a22 * z) + (this.a23 * 1.0f); + } + + @Override + public void rotate(Quaternion quaternion) { + boolean x = quaternion.getX() != 0.0F; + boolean y = quaternion.getY() != 0.0F; + boolean z = quaternion.getZ() != 0.0F; + + // Try to determine if this is a simple rotation on one axis component only + if (x) { + if (!y && !z) { + this.rotateX(quaternion); + } else { + this.rotateXYZ(quaternion); + } + } else if (y) { + if (!z) { + this.rotateY(quaternion); + } else { + this.rotateXYZ(quaternion); + } + } else if (z) { + this.rotateZ(quaternion); + } + } + + private void rotateX(Quaternion quaternion) { + float x = quaternion.getX(); + float w = quaternion.getW(); + + float xx = 2.0F * x * x; + float ta11 = 1.0F - xx; + float ta22 = 1.0F - xx; + + float xw = x * w; + + float ta21 = 2.0F * xw; + float ta12 = 2.0F * -xw; + + float a01 = this.a01 * ta11 + this.a02 * ta21; + float a02 = this.a01 * ta12 + this.a02 * ta22; + float a11 = this.a11 * ta11 + this.a12 * ta21; + float a12 = this.a11 * ta12 + this.a12 * ta22; + float a21 = this.a21 * ta11 + this.a22 * ta21; + float a22 = this.a21 * ta12 + this.a22 * ta22; + float a31 = this.a31 * ta11 + this.a32 * ta21; + float a32 = this.a31 * ta12 + this.a32 * ta22; + + this.a01 = a01; + this.a02 = a02; + this.a11 = a11; + this.a12 = a12; + this.a21 = a21; + this.a22 = a22; + this.a31 = a31; + this.a32 = a32; + } + + private void rotateY(Quaternion quaternion) { + float y = quaternion.getY(); + float w = quaternion.getW(); + + float yy = 2.0F * y * y; + float ta00 = 1.0F - yy; + float ta22 = 1.0F - yy; + float yw = y * w; + float ta20 = 2.0F * -yw; + float ta02 = 2.0F * yw; + + float a00 = this.a00 * ta00 + this.a02 * ta20; + float a02 = this.a00 * ta02 + this.a02 * ta22; + float a10 = this.a10 * ta00 + this.a12 * ta20; + float a12 = this.a10 * ta02 + this.a12 * ta22; + float a20 = this.a20 * ta00 + this.a22 * ta20; + float a22 = this.a20 * ta02 + this.a22 * ta22; + float a30 = this.a30 * ta00 + this.a32 * ta20; + float a32 = this.a30 * ta02 + this.a32 * ta22; + + this.a00 = a00; + this.a02 = a02; + this.a10 = a10; + this.a12 = a12; + this.a20 = a20; + this.a22 = a22; + this.a30 = a30; + this.a32 = a32; + } + + private void rotateZ(Quaternion quaternion) { + float z = quaternion.getZ(); + float w = quaternion.getW(); + + float zz = 2.0F * z * z; + float ta00 = 1.0F - zz; + float ta11 = 1.0F - zz; + float zw = z * w; + float ta10 = 2.0F * zw; + float ta01 = 2.0F * -zw; + + float a00 = this.a00 * ta00 + this.a01 * ta10; + float a01 = this.a00 * ta01 + this.a01 * ta11; + float a10 = this.a10 * ta00 + this.a11 * ta10; + float a11 = this.a10 * ta01 + this.a11 * ta11; + float a20 = this.a20 * ta00 + this.a21 * ta10; + float a21 = this.a20 * ta01 + this.a21 * ta11; + float a30 = this.a30 * ta00 + this.a31 * ta10; + float a31 = this.a30 * ta01 + this.a31 * ta11; + + this.a00 = a00; + this.a01 = a01; + this.a10 = a10; + this.a11 = a11; + this.a20 = a20; + this.a21 = a21; + this.a30 = a30; + this.a31 = a31; + } + + private void rotateXYZ(Quaternion quaternion) { + float x = quaternion.getX(); + float y = quaternion.getY(); + float z = quaternion.getZ(); + float w = quaternion.getW(); + + float xx = 2.0F * x * x; + float yy = 2.0F * y * y; + float zz = 2.0F * z * z; + float ta00 = 1.0F - yy - zz; + float ta11 = 1.0F - zz - xx; + float ta22 = 1.0F - xx - yy; + float xy = x * y; + float yz = y * z; + float zx = z * x; + float xw = x * w; + float yw = y * w; + float zw = z * w; + float ta10 = 2.0F * (xy + zw); + float ta01 = 2.0F * (xy - zw); + float ta20 = 2.0F * (zx - yw); + float ta02 = 2.0F * (zx + yw); + float ta21 = 2.0F * (yz + xw); + float ta12 = 2.0F * (yz - xw); + + float a00 = this.a00 * ta00 + this.a01 * ta10 + this.a02 * ta20; + float a01 = this.a00 * ta01 + this.a01 * ta11 + this.a02 * ta21; + float a02 = this.a00 * ta02 + this.a01 * ta12 + this.a02 * ta22; + float a10 = this.a10 * ta00 + this.a11 * ta10 + this.a12 * ta20; + float a11 = this.a10 * ta01 + this.a11 * ta11 + this.a12 * ta21; + float a12 = this.a10 * ta02 + this.a11 * ta12 + this.a12 * ta22; + float a20 = this.a20 * ta00 + this.a21 * ta10 + this.a22 * ta20; + float a21 = this.a20 * ta01 + this.a21 * ta11 + this.a22 * ta21; + float a22 = this.a20 * ta02 + this.a21 * ta12 + this.a22 * ta22; + float a30 = this.a30 * ta00 + this.a31 * ta10 + this.a32 * ta20; + float a31 = this.a30 * ta01 + this.a31 * ta11 + this.a32 * ta21; + float a32 = this.a30 * ta02 + this.a31 * ta12 + this.a32 * ta22; + + this.a00 = a00; + this.a01 = a01; + this.a02 = a02; + this.a10 = a10; + this.a11 = a11; + this.a12 = a12; + this.a20 = a20; + this.a21 = a21; + this.a22 = a22; + this.a30 = a30; + this.a31 = a31; + this.a32 = a32; + } + + /** + * @reason Optimize + * @author JellySquid + */ + @Overwrite + public void writeRowFirst(FloatBuffer buf) { + if (buf.remaining() < 16) { + throw new BufferUnderflowException(); + } + + if (buf.isDirect() && SodiumClientMod.isDirectMemoryAccessEnabled()) { + this.writeToBufferUnsafe(buf); + } else { + this.writeToBufferSafe(buf); + } + } + + private void writeToBufferUnsafe(FloatBuffer buf) { + long addr = MemoryUtil.memAddress(buf); + + MemoryUtil.memPutFloat(addr + 0, this.a00); + MemoryUtil.memPutFloat(addr + 0, this.a00); + MemoryUtil.memPutFloat(addr + 4, this.a10); + MemoryUtil.memPutFloat(addr + 8, this.a20); + MemoryUtil.memPutFloat(addr + 12, this.a30); + MemoryUtil.memPutFloat(addr + 16, this.a01); + MemoryUtil.memPutFloat(addr + 20, this.a11); + MemoryUtil.memPutFloat(addr + 24, this.a21); + MemoryUtil.memPutFloat(addr + 28, this.a31); + MemoryUtil.memPutFloat(addr + 32, this.a02); + MemoryUtil.memPutFloat(addr + 36, this.a12); + MemoryUtil.memPutFloat(addr + 40, this.a22); + MemoryUtil.memPutFloat(addr + 44, this.a32); + MemoryUtil.memPutFloat(addr + 48, this.a03); + MemoryUtil.memPutFloat(addr + 52, this.a13); + MemoryUtil.memPutFloat(addr + 56, this.a23); + MemoryUtil.memPutFloat(addr + 60, this.a33); + } + + private void writeToBufferSafe(FloatBuffer buf) { + buf.put(0, this.a00); + buf.put(1, this.a10); + buf.put(2, this.a20); + buf.put(3, this.a30); + buf.put(4, this.a01); + buf.put(5, this.a11); + buf.put(6, this.a21); + buf.put(7, this.a31); + buf.put(8, this.a02); + buf.put(9, this.a12); + buf.put(10, this.a22); + buf.put(11, this.a32); + buf.put(12, this.a03); + buf.put(13, this.a13); + buf.put(14, this.a23); + buf.put(15, this.a33); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinBlockColors.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinBlockColors.java new file mode 100644 index 000000000..9cf582d00 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinBlockColors.java @@ -0,0 +1,39 @@ +package me.jellysquid.mods.sodium.mixin.core.model; + +import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; +import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import me.jellysquid.mods.sodium.client.world.biome.BlockColorsExtended; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.client.color.block.BlockColorProvider; +import net.minecraft.client.color.block.BlockColors; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(BlockColors.class) +public class MixinBlockColors implements BlockColorsExtended { + private Reference2ReferenceMap blocksToColor; + + private static final BlockColorProvider DEFAULT_PROVIDER = (state, view, pos, tint) -> -1; + + @Inject(method = "", at = @At("RETURN")) + private void init(CallbackInfo ci) { + this.blocksToColor = new Reference2ReferenceOpenHashMap<>(); + this.blocksToColor.defaultReturnValue(DEFAULT_PROVIDER); + } + + @Inject(method = "registerColorProvider", at = @At("HEAD")) + private void preRegisterColor(BlockColorProvider provider, Block[] blocks, CallbackInfo ci) { + for (Block block : blocks) { + if(provider != null) + this.blocksToColor.put(block, provider); + } + } + + @Override + public BlockColorProvider getColorProvider(BlockState state) { + return this.blocksToColor.get(state.getBlock()); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinItemColors.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinItemColors.java new file mode 100644 index 000000000..5e2c610a3 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinItemColors.java @@ -0,0 +1,40 @@ +package me.jellysquid.mods.sodium.mixin.core.model; + +import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; +import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import me.jellysquid.mods.sodium.client.world.biome.ItemColorsExtended; +import net.minecraft.client.color.item.ItemColorProvider; +import net.minecraft.client.color.item.ItemColors; +import net.minecraft.item.Item; +import net.minecraft.item.ItemConvertible; +import net.minecraft.item.ItemStack; +import net.minecraftforge.registries.IRegistryDelegate; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ItemColors.class) +public class MixinItemColors implements ItemColorsExtended { + private Reference2ReferenceMap, ItemColorProvider> itemsToColor; + + private static final ItemColorProvider DEFAULT_PROVIDER = (stack, tintIdx) -> -1; + + @Inject(method = "", at = @At("RETURN")) + private void init(CallbackInfo ci) { + this.itemsToColor = new Reference2ReferenceOpenHashMap<>(); + this.itemsToColor.defaultReturnValue(DEFAULT_PROVIDER); + } + + @Inject(method = "register", at = @At("HEAD")) + private void preRegisterColor(ItemColorProvider mapper, ItemConvertible[] convertibles, CallbackInfo ci) { + for (ItemConvertible convertible : convertibles) { + this.itemsToColor.put(convertible.asItem().delegate, mapper); + } + } + + @Override + public ItemColorProvider getColorProvider(ItemStack stack) { + return this.itemsToColor.get(stack.getItem().delegate); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java new file mode 100644 index 000000000..e9f9fbd69 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java @@ -0,0 +1,102 @@ +package me.jellysquid.mods.sodium.mixin.core.pipeline; + +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.texture.Sprite; +import net.minecraft.util.math.Direction; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.COLOR_INDEX; +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.LIGHT_INDEX; +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.NORMAL_INDEX; +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.POSITION_INDEX; +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.TEXTURE_INDEX; +import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.vertexOffset; + +@Mixin(BakedQuad.class) +public class MixinBakedQuad implements ModelQuadView { + @Shadow + @Final + protected int[] vertexData; + + @Shadow + @Final + protected Sprite sprite; + + @Shadow + @Final + protected int colorIndex; + + private int cachedFlags; + + @Inject(method = "", at = @At("RETURN")) + private void init(int[] vertexData, int colorIndex, Direction face, Sprite sprite, boolean shade, CallbackInfo ci) { + this.cachedFlags = ModelQuadFlags.getQuadFlags((BakedQuad) (Object) this); + } + + @Override + public float getX(int idx) { + return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + POSITION_INDEX]); + } + + @Override + public float getY(int idx) { + return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + POSITION_INDEX + 1]); + } + + @Override + public float getZ(int idx) { + return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + POSITION_INDEX + 2]); + } + + @Override + public int getColor(int idx) { + if(vertexOffset(idx) + COLOR_INDEX < vertexData.length) { + return this.vertexData[vertexOffset(idx) + COLOR_INDEX]; + } else + { + return vertexData.length; + } + } + + @Override + public Sprite rubidium$getSprite() { + return this.sprite; + } + + @Override + public float getTexU(int idx) { + return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + TEXTURE_INDEX]); + } + + @Override + public float getTexV(int idx) { + return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + TEXTURE_INDEX + 1]); + } + + @Override + public int getFlags() { + return this.cachedFlags; + } + + @Override + public int getLight(int idx) { + return this.vertexData[vertexOffset(idx) + LIGHT_INDEX]; + } + + @Override + public int getNormal(int idx) { + return this.vertexData[vertexOffset(idx) + NORMAL_INDEX]; + } + + @Override + public int getColorIndex() { + return this.colorIndex; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBufferBuilder.java new file mode 100644 index 000000000..6494a8cb7 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBufferBuilder.java @@ -0,0 +1,117 @@ +package me.jellysquid.mods.sodium.mixin.core.pipeline; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; +import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; +import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.type.VertexType; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.util.GlAllocationUtils; +import org.apache.logging.log4j.Logger; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.nio.Buffer; +import java.nio.ByteBuffer; + +@Mixin(BufferBuilder.class) +public abstract class MixinBufferBuilder implements VertexBufferView, VertexDrain { + @Shadow + private int elementOffset; + + @Shadow + private ByteBuffer buffer; + + @Shadow + @Final + private static Logger LOGGER; + + @Shadow + private static int roundBufferSize(int amount) { + throw new UnsupportedOperationException(); + } + + @Shadow + private VertexFormat format; + + @Shadow + private int vertexCount; + + @Redirect(method = "popData", at = @At(value = "INVOKE", target = "Ljava/nio/Buffer;limit(I)Ljava/nio/Buffer;")) + public Buffer debugGetNextBuffer(Buffer buffer, int newLimit) { + ensureBufferCapacity(newLimit); + buffer = (Buffer) this.buffer; + buffer.limit(newLimit); + return buffer; + } + + @Override + public boolean ensureBufferCapacity(int bytes) { + if(format == null) + return false; + + // Ensure that there is always space for 1 more vertex; see BufferBuilder.next() + bytes += format.getVertexSize(); + + if (this.elementOffset + bytes <= this.buffer.capacity()) { + return false; + } + + int newSize = this.buffer.capacity() + roundBufferSize(bytes); + + LOGGER.debug("Needed to grow BufferBuilder buffer: Old size {} bytes, new size {} bytes.", this.buffer.capacity(), newSize); + + this.buffer.position(0); + + ByteBuffer byteBuffer = GlAllocationUtils.allocateByteBuffer(newSize); + byteBuffer.put(this.buffer); + byteBuffer.rewind(); + + this.buffer = byteBuffer; + + return true; + } + + @Override + public ByteBuffer getDirectBuffer() { + return this.buffer; + } + + @Override + public int getWriterPosition() { + return this.elementOffset; + } + + @Override + public BufferVertexFormat getVertexFormat() { + return BufferVertexFormat.from(this.format); + } + + @Override + public void flush(int vertexCount, BufferVertexFormat format) { + if (BufferVertexFormat.from(this.format) != format) { + throw new IllegalStateException("Mis-matched vertex format (expected: [" + format + "], currently using: [" + this.format + "])"); + } + + this.vertexCount += vertexCount; + this.elementOffset += vertexCount * format.getStride(); + } + + @Override + public T createSink(VertexType factory) { + BlittableVertexType blittable = factory.asBlittable(); + + if (blittable != null && blittable.getBufferVertexFormat() == this.getVertexFormat()) { + return blittable.createBufferWriter(this, SodiumClientMod.isDirectMemoryAccessEnabled()); + } + + return factory.createFallbackWriter((VertexConsumer) this); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexConsumer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexConsumer.java new file mode 100644 index 000000000..823cb5f2e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexConsumer.java @@ -0,0 +1,15 @@ +package me.jellysquid.mods.sodium.mixin.core.pipeline; + +import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.type.VertexType; +import net.minecraft.client.render.VertexConsumer; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(VertexConsumer.class) +public interface MixinVertexConsumer extends VertexDrain { + @Override + default T createSink(VertexType factory) { + return factory.createFallbackWriter((VertexConsumer) this); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexFormat.java new file mode 100644 index 000000000..a9766681e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexFormat.java @@ -0,0 +1,17 @@ +package me.jellysquid.mods.sodium.mixin.core.pipeline; + +import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; +import net.minecraft.client.render.VertexFormat; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(VertexFormat.class) +public abstract class MixinVertexFormat implements BufferVertexFormat { + @Shadow + public abstract int getVertexSize(); + + @Override + public int getStride() { + return this.getVertexSize(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinBlockModelRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinBlockModelRenderer.java new file mode 100644 index 000000000..5dbc91252 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinBlockModelRenderer.java @@ -0,0 +1,105 @@ +package me.jellysquid.mods.sodium.mixin.features.block; + +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; +import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; +import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.block.BlockModelRenderer; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.BlockRenderView; +import net.minecraftforge.client.model.data.EmptyModelData; +import net.minecraftforge.client.model.data.IModelData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.List; +import java.util.Random; + +@Mixin(BlockModelRenderer.class) +public class MixinBlockModelRenderer { + private final XoRoShiRoRandom random = new XoRoShiRoRandom(); + + @Inject(method = "render(Lnet/minecraft/world/BlockRenderView;Lnet/minecraft/client/render/model/BakedModel;Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;ZLjava/util/Random;JI)Z", at = @At("HEAD"), cancellable = true) + private void preRenderBlockInWorld(BlockRenderView world, BakedModel model, BlockState state, BlockPos pos, MatrixStack matrixStack, VertexConsumer consumer, boolean cull, Random rand, long seed, int int_1, CallbackInfoReturnable cir) { +// GlobalRenderContext renderer = GlobalRenderContext.getInstance(world); +// BlockRenderer blockRenderer = renderer.getBlockRenderer(); +// +// boolean ret = blockRenderer.renderModel(world, state, pos, model, new FallbackChunkModelBuffers(consumer, matrixStack), cull, seed); +// +// cir.setReturnValue(ret); + } + + /** + * @reason Use optimized vertex writer intrinsics, avoid allocations + * @author JellySquid + */ + @Overwrite + public void renderModel(MatrixStack.Entry entry, VertexConsumer vertexConsumer, BlockState blockState, BakedModel bakedModel, float red, float green, float blue, int light, int overlay, IModelData modelData) { + QuadVertexSink drain = VertexDrain.of(vertexConsumer) + .createSink(VanillaVertexTypes.QUADS); + XoRoShiRoRandom random = this.random; + + if (modelData == null) { + modelData = EmptyModelData.INSTANCE; + } + + // Clamp color ranges + red = MathHelper.clamp(red, 0.0F, 1.0F); + green = MathHelper.clamp(green, 0.0F, 1.0F); + blue = MathHelper.clamp(blue, 0.0F, 1.0F); + + int defaultColor = ColorABGR.pack(red, green, blue, 1.0F); + + for (Direction direction : DirectionUtil.ALL_DIRECTIONS) { + List quads = bakedModel.getQuads(blockState, direction, random.setSeedAndReturn(42L), modelData); + + if (!quads.isEmpty()) { + renderQuad(entry, drain, defaultColor, quads, light, overlay); + } + } + + List quads = bakedModel.getQuads(blockState, null, random.setSeedAndReturn(42L), modelData); + + if (!quads.isEmpty()) { + renderQuad(entry, drain, defaultColor, quads, light, overlay); + } + + drain.flush(); + } + + private static void renderQuad(MatrixStack.Entry entry, QuadVertexSink drain, int defaultColor, List list, int light, int overlay) { + if (list.isEmpty()) { + return; + } + + drain.ensureCapacity(list.size() * 4); + + for (BakedQuad bakedQuad : list) { + int color = bakedQuad.hasColor() ? defaultColor : 0xFFFFFFFF; + + ModelQuadView quad = ((ModelQuadView) bakedQuad); + + for (int i = 0; i < 4; i++) { + drain.writeQuad(entry, quad.getX(i), quad.getY(i), quad.getZ(i), color, quad.getTexU(i), quad.getTexV(i), + light, overlay, ModelQuadUtil.getFacingNormal(bakedQuad.getFace(), quad.getNormal(i))); + } + + SpriteUtil.markSpriteActive(quad.rubidium$getSprite()); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java new file mode 100644 index 000000000..3709ab2af --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java @@ -0,0 +1,27 @@ +package me.jellysquid.mods.sodium.mixin.features.block; + +import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheShared; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.render.LightmapTextureManager; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(WorldRenderer.class) +public class MixinWorldRenderer { + /** + * Reset any global cached state before rendering a frame. This will hopefully ensure that any world state that has + * changed is reflected in vanilla-style rendering. + */ + @Inject(method = "render", at = @At("HEAD")) + private void reset(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, + GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, + CallbackInfo ci) { + ChunkRenderCacheShared.resetCaches(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinBufferBuilder.java new file mode 100644 index 000000000..90e5a686a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinBufferBuilder.java @@ -0,0 +1,56 @@ +package me.jellysquid.mods.sodium.mixin.features.buffer_builder.fast_advance; + +import me.jellysquid.mods.sodium.client.buffer.ExtendedVertexFormat; +import net.minecraft.client.render.*; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(BufferBuilder.class) +public abstract class MixinBufferBuilder extends FixedColorVertexConsumer implements BufferVertexConsumer { + @Shadow + private VertexFormatElement currentElement; + + @Shadow + private int elementOffset; + + @Shadow + private int currentElementId; + + private ExtendedVertexFormat.Element[] embeddium$vertexFormatExtendedElements; + private ExtendedVertexFormat.Element embeddium$currentExtendedElement; + + @Inject(method = "method_23918", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/render/BufferBuilder;format:Lnet/minecraft/client/render/VertexFormat;", + opcode = Opcodes.PUTFIELD + ) + ) + private void onFormatChanged(VertexFormat format, CallbackInfo ci) { + embeddium$vertexFormatExtendedElements = ((ExtendedVertexFormat) format).embeddium$getExtendedElements(); + embeddium$currentExtendedElement = embeddium$vertexFormatExtendedElements[0]; + } + + /** + * @author JellySquid + * @reason Remove modulo operations, recursion, and list dereference + */ + @Override + @Overwrite + public void nextElement() { + if ((currentElementId += embeddium$currentExtendedElement.increment) >= embeddium$vertexFormatExtendedElements.length) + currentElementId -= embeddium$vertexFormatExtendedElements.length; + elementOffset += embeddium$currentExtendedElement.byteLength; + embeddium$currentExtendedElement = embeddium$vertexFormatExtendedElements[currentElementId]; + currentElement = embeddium$currentExtendedElement.actual; + + if (this.colorFixed && this.currentElement.getType() == VertexFormatElement.Type.COLOR) { + BufferVertexConsumer.super.color(this.fixedRed, this.fixedGreen, this.fixedBlue, this.fixedAlpha); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinVertexFormat.java new file mode 100644 index 000000000..62412dd27 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinVertexFormat.java @@ -0,0 +1,55 @@ +package me.jellysquid.mods.sodium.mixin.features.buffer_builder.fast_advance; + +import com.google.common.collect.ImmutableList; +import me.jellysquid.mods.sodium.client.buffer.ExtendedVertexFormat; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.VertexFormatElement; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * Thanks to Maximum for this optimization, taken from Fireblanket. + */ +@Mixin(VertexFormat.class) +public class MixinVertexFormat implements ExtendedVertexFormat { + @Shadow + @Final + private ImmutableList elements; + + private Element[] embeddium$extendedElements; + + @Inject(method = "", at = @At("RETURN")) + private void embeddium$createElementArray(ImmutableList immutableList, CallbackInfo ci) { + this.embeddium$extendedElements = new Element[this.elements.size()]; + + if (this.elements.size() == 0) + return; // prevent crash with mods that create empty VertexFormats + + VertexFormatElement currentElement = elements.get(0); + int id = 0; + for (VertexFormatElement element : this.elements) { + if (element.getType() == VertexFormatElement.Type.PADDING) continue; + + int oldId = id; + int byteLength = 0; + + do { + if (++id >= this.embeddium$extendedElements.length) + id -= this.embeddium$extendedElements.length; + byteLength += currentElement.getByteLength(); + currentElement = this.elements.get(id); + } while (currentElement.getType() == VertexFormatElement.Type.PADDING); + + this.embeddium$extendedElements[oldId] = new Element(element, id - oldId, byteLength); + } + } + + @Override + public Element[] embeddium$getExtendedElements() { + return this.embeddium$extendedElements; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_sort/MixinBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_sort/MixinBufferBuilder.java new file mode 100644 index 000000000..1c4e31a37 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_sort/MixinBufferBuilder.java @@ -0,0 +1,180 @@ +package me.jellysquid.mods.sodium.mixin.features.buffer_builder.fast_sort; + +import com.google.common.primitives.Floats; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.VertexFormat; +import org.lwjgl.system.MemoryStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.util.Arrays; +import java.util.BitSet; + +@Mixin(BufferBuilder.class) +public class MixinBufferBuilder { + @Shadow + private ByteBuffer buffer; + + @Shadow + private int vertexCount; + + @Shadow + private VertexFormat format; + + @Shadow + private int buildStart; + + /** + * @reason Reduce allocations, use stack allocations, avoid unnecessary math and pointer bumping, inline comparators + * @author JellySquid + */ + @Overwrite + public void sortQuads(float cameraX, float cameraY, float cameraZ) { + this.buffer.clear(); + FloatBuffer floatBuffer = this.buffer.asFloatBuffer(); + + int vertexStride = this.format.getVertexSize(); + int quadStride = this.format.getVertexSizeInteger() * 4; + + int quadStart = this.buildStart / 4; + int quadCount = this.vertexCount / 4; + int vertexSizeInteger = this.format.getVertexSizeInteger(); + + float[] distanceArray = new float[quadCount]; + int[] indicesArray = new int[quadCount]; + + for (int quadIdx = 0; quadIdx < quadCount; ++quadIdx) { + distanceArray[quadIdx] = getDistanceSq(floatBuffer, cameraX, cameraY, cameraZ, vertexSizeInteger, quadStart + (quadIdx * vertexStride)); + indicesArray[quadIdx] = quadIdx; + } + + mergeSort(indicesArray, distanceArray); + + BitSet bits = new BitSet(); + + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer tmp = stack.mallocFloat(vertexSizeInteger * 4); + + for (int l = bits.nextClearBit(0); l < indicesArray.length; l = bits.nextClearBit(l + 1)) { + int m = indicesArray[l]; + + if (m != l) { + sliceQuad(floatBuffer, m, quadStride, quadStart); + tmp.clear(); + tmp.put(floatBuffer); + + int n = m; + + for (int o = indicesArray[m]; n != l; o = indicesArray[o]) { + sliceQuad(floatBuffer, o, quadStride, quadStart); + FloatBuffer floatBuffer3 = floatBuffer.slice(); + + sliceQuad(floatBuffer, n, quadStride, quadStart); + floatBuffer.put(floatBuffer3); + + bits.set(n); + n = o; + } + + sliceQuad(floatBuffer, l, quadStride, quadStart); + tmp.flip(); + + floatBuffer.put(tmp); + } + + bits.set(l); + } + } + } + + private static void mergeSort(int[] indicesArray, float[] distanceArray) { + mergeSort(indicesArray, 0, indicesArray.length, distanceArray, Arrays.copyOf(indicesArray, indicesArray.length)); + } + + private static void sliceQuad(FloatBuffer floatBuffer, int quadIdx, int quadStride, int quadStart) { + int base = quadStart + (quadIdx * quadStride); + + floatBuffer.limit(base + quadStride); + floatBuffer.position(base); + } + + private static float getDistanceSq(FloatBuffer buffer, float xCenter, float yCenter, float zCenter, int stride, int start) { + int vertexBase = start; + float x1 = buffer.get(vertexBase); + float y1 = buffer.get(vertexBase + 1); + float z1 = buffer.get(vertexBase + 2); + + vertexBase += stride; + float x2 = buffer.get(vertexBase); + float y2 = buffer.get(vertexBase + 1); + float z2 = buffer.get(vertexBase + 2); + + vertexBase += stride; + float x3 = buffer.get(vertexBase); + float y3 = buffer.get(vertexBase + 1); + float z3 = buffer.get(vertexBase + 2); + + vertexBase += stride; + float x4 = buffer.get(vertexBase); + float y4 = buffer.get(vertexBase + 1); + float z4 = buffer.get(vertexBase + 2); + + float xDist = ((x1 + x2 + x3 + x4) * 0.25F) - xCenter; + float yDist = ((y1 + y2 + y3 + y4) * 0.25F) - yCenter; + float zDist = ((z1 + z2 + z3 + z4) * 0.25F) - zCenter; + + return (xDist * xDist) + (yDist * yDist) + (zDist * zDist); + } + + private static void mergeSort(final int[] a, final int from, final int to, float[] dist, final int[] supp) { + int len = to - from; + + // Insertion sort on smallest arrays + if (len < 16) { + insertionSort(a, from, to, dist); + return; + } + + // Recursively sort halves of a into supp + final int mid = (from + to) >>> 1; + mergeSort(supp, from, mid, dist, a); + mergeSort(supp, mid, to, dist, a); + + // If list is already sorted, just copy from supp to a. This is an + // optimization that results in faster sorts for nearly ordered lists. + if (Floats.compare(dist[supp[mid]], dist[supp[mid - 1]]) <= 0) { + System.arraycopy(supp, from, a, from, len); + return; + } + + // Merge sorted halves (now in supp) into a + for (int i = from, p = from, q = mid; i < to; i++) { + if (q >= to || p < mid && Floats.compare(dist[supp[q]], dist[supp[p]]) <= 0) { + a[i] = supp[p++]; + } else { + a[i] = supp[q++]; + } + } + } + + private static void insertionSort(final int[] a, final int from, final int to, final float[] dist) { + for (int i = from; ++i < to; ) { + int t = a[i]; + int j = i; + + for (int u = a[j - 1]; Floats.compare(dist[u], dist[t]) < 0; u = a[--j - 1]) { + a[j] = u; + if (from == j - 1) { + --j; + break; + } + } + + a[j] = t; + } + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinBufferBuilder.java new file mode 100644 index 000000000..e6a084752 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinBufferBuilder.java @@ -0,0 +1,94 @@ +package me.jellysquid.mods.sodium.mixin.features.buffer_builder.intrinsics; + +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; +import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; +import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import me.jellysquid.mods.sodium.client.util.color.ColorU8; +import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.FixedColorVertexConsumer; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Matrix3f; +import net.minecraft.util.math.Matrix4f; +import net.minecraft.util.math.Vector4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(BufferBuilder.class) +public abstract class MixinBufferBuilder extends FixedColorVertexConsumer { + @Shadow + private boolean field_227826_s_; // is baked quad format + + @Override + public void quad(MatrixStack.Entry matrices, BakedQuad quad, float[] brightnessTable, float r, float g, float b, int[] light, int overlay, boolean colorize) { + if (!this.field_227826_s_) { + super.quad(matrices, quad, brightnessTable, r, g, b, light, overlay, colorize); + + return; + } + + if (this.colorFixed) { + throw new IllegalStateException(); + } + + ModelQuadView quadView = (ModelQuadView) quad; + + Matrix4f modelMatrix = matrices.getModel(); + Matrix3f normalMatrix = matrices.getNormal(); + + int norm = MatrixUtil.computeNormal(normalMatrix, quad.getFace()); + + QuadVertexSink drain = VertexDrain.of(this) + .createSink(VanillaVertexTypes.QUADS); + drain.ensureCapacity(4); + + for (int i = 0; i < 4; i++) { + float x = quadView.getX(i); + float y = quadView.getY(i); + float z = quadView.getZ(i); + + float fR; + float fG; + float fB; + + float brightness = brightnessTable[i]; + + if (colorize) { + int color = quadView.getColor(i); + + float oR = ColorU8.normalize(ColorABGR.unpackRed(color)); + float oG = ColorU8.normalize(ColorABGR.unpackGreen(color)); + float oB = ColorU8.normalize(ColorABGR.unpackBlue(color)); + + fR = oR * brightness * r; + fG = oG * brightness * g; + fB = oB * brightness * b; + } else { + fR = brightness * r; + fG = brightness * g; + fB = brightness * b; + } + + float u = quadView.getTexU(i); + float v = quadView.getTexV(i); + + int color = ColorABGR.pack(fR, fG, fB, 1.0F); + + Vector4f pos = new Vector4f(x, y, z, 1.0F); + pos.transform(modelMatrix); + + int bakedNorm = quadView.getNormal(i); + if(ModelQuadUtil.hasNormal(bakedNorm)) { + norm = MatrixUtil.transformPackedNormal(bakedNorm, normalMatrix); + } + + drain.writeQuad(pos.getX(), pos.getY(), pos.getZ(), color, u, v, ModelQuadUtil.mergeBakedLight(quadView.getLight(i), light[i]), overlay, norm); + } + + drain.flush(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinSpriteTexturedVertexConsumer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinSpriteTexturedVertexConsumer.java new file mode 100644 index 000000000..bd1815ff7 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinSpriteTexturedVertexConsumer.java @@ -0,0 +1,41 @@ +package me.jellysquid.mods.sodium.mixin.features.buffer_builder.intrinsics; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; +import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; +import me.jellysquid.mods.sodium.client.model.vertex.transformers.SpriteTexturedVertexTransformer; +import me.jellysquid.mods.sodium.client.model.vertex.type.VertexType; +import net.minecraft.client.render.SpriteTexturedVertexConsumer; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.texture.Sprite; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(SpriteTexturedVertexConsumer.class) +public abstract class MixinSpriteTexturedVertexConsumer implements VertexDrain { + @Shadow + @Final + private Sprite sprite; + + @Shadow + @Final + private VertexConsumer parent; + + @SuppressWarnings("unchecked") + @Override + public T createSink(VertexType type) { + if (type == VanillaVertexTypes.QUADS) { + return (T) new SpriteTexturedVertexTransformer.Quad(VertexDrain.of(this.parent) + .createSink(VanillaVertexTypes.QUADS), this.sprite); + } else if (type == VanillaVertexTypes.PARTICLES) { + return (T) new SpriteTexturedVertexTransformer.Particle(VertexDrain.of(this.parent) + .createSink(VanillaVertexTypes.PARTICLES), this.sprite); + } else if (type == VanillaVertexTypes.GLYPHS) { + return (T) new SpriteTexturedVertexTransformer.Glyph(VertexDrain.of(this.parent) + .createSink(VanillaVertexTypes.GLYPHS), this.sprite); + } + + return type.createFallbackWriter((VertexConsumer) this); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinWorldRenderer.java new file mode 100644 index 000000000..26c829621 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinWorldRenderer.java @@ -0,0 +1,114 @@ +package me.jellysquid.mods.sodium.mixin.features.buffer_builder.intrinsics; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; +import me.jellysquid.mods.sodium.client.model.vertex.formats.line.LineVertexSink; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; +import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(WorldRenderer.class) +public class MixinWorldRenderer { + /** + * @author JellySquid + * @reason Use intrinsics where possible to speed up vertex writing + */ + @Overwrite + public static void drawBox(MatrixStack matrices, VertexConsumer vertexConsumer, double x1, double y1, double z1, + double x2, double y2, double z2, float red, float green, float blue, float alpha, + float xAxisRed, float yAxisGreen, float zAxisBlue) { + Matrix4f model = matrices.peek().getModel(); + + float x1f = (float) x1; + float y1f = (float) y1; + float z1f = (float) z1; + float x2f = (float) x2; + float y2f = (float) y2; + float z2f = (float) z2; + + int color = ColorABGR.pack(red, green, blue, alpha); + + Matrix4fExtended matrixExt = MatrixUtil.getExtendedMatrix(model); + + float v1x = matrixExt.transformVecX(x1f, y1f, z1f); + float v1y = matrixExt.transformVecY(x1f, y1f, z1f); + float v1z = matrixExt.transformVecZ(x1f, y1f, z1f); + + float v2x = matrixExt.transformVecX(x2f, y1f, z1f); + float v2y = matrixExt.transformVecY(x2f, y1f, z1f); + float v2z = matrixExt.transformVecZ(x2f, y1f, z1f); + + float v3x = matrixExt.transformVecX(x1f, y2f, z1f); + float v3y = matrixExt.transformVecY(x1f, y2f, z1f); + float v3z = matrixExt.transformVecZ(x1f, y2f, z1f); + + float v4x = matrixExt.transformVecX(x1f, y1f, z2f); + float v4y = matrixExt.transformVecY(x1f, y1f, z2f); + float v4z = matrixExt.transformVecZ(x1f, y1f, z2f); + + float v5x = matrixExt.transformVecX(x2f, y2f, z1f); + float v5y = matrixExt.transformVecY(x2f, y2f, z1f); + float v5z = matrixExt.transformVecZ(x2f, y2f, z1f); + + float v6x = matrixExt.transformVecX(x1f, y2f, z2f); + float v6y = matrixExt.transformVecY(x1f, y2f, z2f); + float v6z = matrixExt.transformVecZ(x1f, y2f, z2f); + + float v7x = matrixExt.transformVecX(x2f, y1f, z2f); + float v7y = matrixExt.transformVecY(x2f, y1f, z2f); + float v7z = matrixExt.transformVecZ(x2f, y1f, z2f); + + float v8x = matrixExt.transformVecX(x2f, y2f, z2f); + float v8y = matrixExt.transformVecY(x2f, y2f, z2f); + float v8z = matrixExt.transformVecZ(x2f, y2f, z2f); + + LineVertexSink lines = VertexDrain.of(vertexConsumer) + .createSink(VanillaVertexTypes.LINES); + lines.ensureCapacity(24); + + lines.vertexLine(v1x, v1y, v1z, red, yAxisGreen, zAxisBlue, alpha); + lines.vertexLine(v2x, v2y, v2z, red, yAxisGreen, zAxisBlue, alpha); + + lines.vertexLine(v1x, v1y, v1z, xAxisRed, green, zAxisBlue, alpha); + lines.vertexLine(v3x, v3y, v3z, xAxisRed, green, zAxisBlue, alpha); + + lines.vertexLine(v1x, v1y, v1z, xAxisRed, yAxisGreen, blue, alpha); + lines.vertexLine(v4x, v4y, v4z, xAxisRed, yAxisGreen, blue, alpha); + + lines.vertexLine(v2x, v2y, v2z, color); + lines.vertexLine(v5x, v5y, v5z, color); + + lines.vertexLine(v5x, v5y, v5z, color); + lines.vertexLine(v3x, v3y, v3z, color); + + lines.vertexLine(v3x, v3y, v3z, color); + lines.vertexLine(v6x, v6y, v6z, color); + + lines.vertexLine(v6x, v6y, v6z, color); + lines.vertexLine(v4x, v4y, v4z, color); + + lines.vertexLine(v4x, v4y, v4z, color); + lines.vertexLine(v7x, v7y, v7z, color); + + lines.vertexLine(v7x, v7y, v7z, color); + lines.vertexLine(v2x, v2y, v2z, color); + + lines.vertexLine(v6x, v6y, v6z, color); + lines.vertexLine(v8x, v8y, v8z, color); + + lines.vertexLine(v7x, v7y, v7z, color); + lines.vertexLine(v8x, v8y, v8z, color); + + lines.vertexLine(v5x, v5y, v5z, color); + lines.vertexLine(v8x, v8y, v8z, color); + + lines.flush(); + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinChunkBuilder.java new file mode 100644 index 000000000..d0d36f8c8 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinChunkBuilder.java @@ -0,0 +1,15 @@ +package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; + +import net.minecraft.client.render.chunk.ChunkBuilder; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(ChunkBuilder.class) +public class MixinChunkBuilder { + @ModifyVariable(method = "(Lnet/minecraft/world/World;Lnet/minecraft/client/render/WorldRenderer;Ljava/util/concurrent/Executor;ZLnet/minecraft/client/render/chunk/BlockBufferBuilderStorage;I)V", index = 9, at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayListWithExpectedSize(I)Ljava/util/ArrayList;", remap = false)) + private int modifyThreadPoolSize(int prev) { + // Do not allow any resources to be allocated + return 0; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientChunkManager.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientChunkManager.java new file mode 100644 index 000000000..382b023e2 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientChunkManager.java @@ -0,0 +1,143 @@ +package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; + +import it.unimi.dsi.fastutil.longs.LongIterator; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; +import me.jellysquid.mods.sodium.client.world.ChunkStatusListenerManager; +import net.minecraft.client.world.ClientChunkManager; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.biome.source.BiomeArray; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.WorldChunk; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.concurrent.atomic.AtomicReferenceArray; +import java.util.function.BooleanSupplier; + +@Mixin(ClientChunkManager.class) +public abstract class MixinClientChunkManager implements ChunkStatusListenerManager { + @Shadow + @Nullable + public abstract WorldChunk getChunk(int i, int j, ChunkStatus chunkStatus, boolean bl); + + private final LongOpenHashSet loadedChunks = new LongOpenHashSet(); + private boolean needsTrackingUpdate = false; + + private ChunkStatusListener listener; + + @Inject(method = "loadChunkFromPacket", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;resetChunkColor(II)V", shift = At.Shift.AFTER)) + private void afterLoadChunkFromPacket(int x, int z, BiomeArray biomes, PacketByteBuf buf, NbtCompound tag, int verticalStripBitmask, boolean complete, CallbackInfoReturnable cir) { + if (this.listener != null) { + this.listener.onChunkAdded(x, z); + this.loadedChunks.add(ChunkPos.toLong(x, z)); + } + } + + @Inject(method = "unload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientChunkManager$ClientChunkMap;compareAndSet(ILnet/minecraft/world/chunk/WorldChunk;Lnet/minecraft/world/chunk/WorldChunk;)Lnet/minecraft/world/chunk/WorldChunk;", shift = At.Shift.AFTER)) + private void afterUnloadChunk(int x, int z, CallbackInfo ci) { + if (this.listener != null) { + this.listener.onChunkRemoved(x, z); + this.loadedChunks.remove(ChunkPos.toLong(x, z)); + } + } + + @Inject(method = "tick", at = @At("RETURN")) + private void afterTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { + if (!this.needsTrackingUpdate) { + return; + } + + LongIterator it = this.loadedChunks.iterator(); + + while (it.hasNext()) { + long pos = it.nextLong(); + + int x = ChunkPos.getPackedX(pos); + int z = ChunkPos.getPackedZ(pos); + + if (this.getChunk(x, z, ChunkStatus.FULL, false) == null) { + it.remove(); + + if (this.listener != null) { + this.listener.onChunkRemoved(x, z); + } + } + } + + this.needsTrackingUpdate = false; + } + + @Inject(method = "setChunkMapCenter(II)V", at = @At("RETURN")) + private void afterChunkMapCenterChanged(int x, int z, CallbackInfo ci) { + this.needsTrackingUpdate = true; + } + + @Inject(method = "updateLoadDistance", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/world/ClientChunkManager$ClientChunkMap;set(ILnet/minecraft/world/chunk/WorldChunk;)V", + shift = At.Shift.AFTER)) + private void afterLoadDistanceChanged(int loadDistance, CallbackInfo ci) { + this.needsTrackingUpdate = true; + } + + @Override + public void setListener(ChunkStatusListener listener) { + this.listener = listener; + } + + @Mixin(targets = "net/minecraft/client/world/ClientChunkManager$ClientChunkMap") + public static class MixinClientChunkMap { + @Mutable + @Shadow + @Final + private AtomicReferenceArray chunks; + + @Mutable + @Shadow + @Final + private int diameter; + + @Mutable + @Shadow + @Final + private int radius; + + private int factor; + + @Inject(method = "", at = @At("RETURN")) + private void reinit(ClientChunkManager outer, int loadDistance, CallbackInfo ci) { + // This re-initialization is a bit expensive on memory, but it only happens when either the world is + // switched or the render distance is changed; + this.radius = loadDistance; + + // Make the diameter a power-of-two so we can exploit bit-wise math when computing indices + this.diameter = MathHelper.smallestEncompassingPowerOfTwo(loadDistance * 2 + 1); + + // The factor is used as a bit mask to replace the modulo in getIndex + this.factor = this.diameter - 1; + + this.chunks = new AtomicReferenceArray<>(this.diameter * this.diameter); + } + + /** + * @reason Avoid expensive modulo + * @author JellySquid + */ + @Overwrite + private int getIndex(int chunkX, int chunkZ) { + return (chunkZ & this.factor) * this.diameter + (chunkX & this.factor); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientWorld.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientWorld.java new file mode 100644 index 000000000..b0e4f6161 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientWorld.java @@ -0,0 +1,34 @@ +package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; + +import me.jellysquid.mods.sodium.client.world.ClientWorldExtended; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.profiler.Profiler; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.World; +import net.minecraft.world.dimension.DimensionType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.function.Supplier; + +@Mixin(ClientWorld.class) +public abstract class MixinClientWorld implements ClientWorldExtended { + private long biomeSeed; + + /** + * Captures the biome generation seed so that our own caches can make use of it. + */ + @Inject(method = "", at = @At("RETURN")) + private void init(ClientPlayNetworkHandler clientPlayNetworkHandler, ClientWorld.Properties properties, RegistryKey registryKey, DimensionType dimensionType, int i, Supplier supplier, WorldRenderer worldRenderer, boolean bl, long seed, CallbackInfo ci) { + this.biomeSeed = seed; + } + + @Override + public long getBiomeSeed() { + return this.biomeSeed; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPackedIntegerArray.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPackedIntegerArray.java new file mode 100644 index 000000000..63ecd9400 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPackedIntegerArray.java @@ -0,0 +1,49 @@ +package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; + +import me.jellysquid.mods.sodium.client.world.cloned.PackedIntegerArrayExtended; +import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; +import net.minecraft.util.collection.PackedIntegerArray; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(PackedIntegerArray.class) +public class MixinPackedIntegerArray implements PackedIntegerArrayExtended { + @Shadow + @Final + private long[] storage; + + @Shadow(remap = false) + @Final + private int field_232982_f_; + + @Shadow + @Final + private long maxValue; + + @Shadow + @Final + private int elementBits; + + @Shadow + @Final + private int size; + + @Override + public void copyUsingPalette(T[] out, ClonedPalette palette) { + int idx = 0; + + for (long word : this.storage) { + long l = word; + + for (int j = 0; j < this.field_232982_f_; ++j) { + out[idx] = palette.get((int) (l & this.maxValue)); + l >>= this.elementBits; + + if (++idx >= this.size) { + return; + } + } + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPalettedContainer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPalettedContainer.java new file mode 100644 index 000000000..a34a4cdce --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPalettedContainer.java @@ -0,0 +1,45 @@ +package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; + +import me.jellysquid.mods.sodium.client.world.cloned.PalettedContainerExtended; +import net.minecraft.util.collection.PackedIntegerArray; +import net.minecraft.world.chunk.Palette; +import net.minecraft.world.chunk.PalettedContainer; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(PalettedContainer.class) +public class MixinPalettedContainer implements PalettedContainerExtended { + @Shadow + private int paletteSize; + + @Shadow + protected PackedIntegerArray data; + + @Shadow + private Palette palette; + + @Shadow + @Final + private T defaultValue; + + @Override + public PackedIntegerArray getDataArray() { + return this.data; + } + + @Override + public Palette getPalette() { + return this.palette; + } + + @Override + public T getDefaultValue() { + return this.defaultValue; + } + + @Override + public int getPaletteSize() { + return this.paletteSize; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinRenderLayer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinRenderLayer.java new file mode 100644 index 000000000..4ea0e28a6 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinRenderLayer.java @@ -0,0 +1,24 @@ +package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; + +import com.google.common.collect.ImmutableList; +import net.minecraft.client.render.RenderLayer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Unique; + +import java.util.List; + +@Mixin(RenderLayer.class) +public class MixinRenderLayer { + @Unique + private static final List embeddium$blockLayers = ImmutableList.of(RenderLayer.getSolid(), RenderLayer.getCutoutMipped(), RenderLayer.getCutout(), RenderLayer.getTranslucent(), RenderLayer.getTripwire()); + + /** + * @author Kasualix + * @reason Don't create an immutableList every time this is called. + */ + @Overwrite + public static List getBlockLayers() { + return embeddium$blockLayers; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java new file mode 100644 index 000000000..f4cb572b4 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java @@ -0,0 +1,171 @@ +package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.option.GameOptions; +import net.minecraft.client.render.*; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Matrix4f; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.SortedSet; + +@Mixin(WorldRenderer.class) +public abstract class MixinWorldRenderer { + @Shadow + @Final + private BufferBuilderStorage bufferBuilders; + + @Shadow + @Final + private Long2ObjectMap> blockBreakingProgressions; + + private SodiumWorldRenderer renderer; + + @Redirect(method = "reload()V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/option/GameOptions;viewDistance:I", ordinal = 1)) + private int nullifyBuiltChunkStorage(GameOptions options) { + // Do not allow any resources to be allocated + return 0; + } + + @Inject(method = "", at = @At("RETURN")) + private void init(MinecraftClient client, BufferBuilderStorage bufferBuilders, CallbackInfo ci) { + this.renderer = SodiumWorldRenderer.create(); + } + + @Inject(method = "setWorld", at = @At("RETURN")) + private void onWorldChanged(ClientWorld world, CallbackInfo ci) { + RenderDevice.enterManagedCode(); + + try { + this.renderer.setWorld(world); + } finally { + RenderDevice.exitManagedCode(); + } + } + + /** + * @reason Redirect to our renderer + * @author JellySquid + */ + @Overwrite + public int getCompletedChunkCount() { + return this.renderer.getVisibleChunkCount(); + } + + /** + * @reason Redirect the check to our renderer + * @author JellySquid + */ + @Overwrite + public boolean isTerrainRenderComplete() { + return this.renderer.isTerrainRenderComplete(); + } + + @Inject(method = "scheduleTerrainUpdate", at = @At("RETURN")) + private void onTerrainUpdateScheduled(CallbackInfo ci) { + this.renderer.scheduleTerrainUpdate(); + } + + /** + * @reason Redirect the chunk layer render passes to our renderer + * @author JellySquid + */ + @Overwrite + private void renderLayer(RenderLayer renderLayer, MatrixStack matrixStack, double x, double y, double z) { + RenderDevice.enterManagedCode(); + + try { + this.renderer.drawChunkLayer(renderLayer, matrixStack, x, y, z); + } finally { + RenderDevice.exitManagedCode(); + } + } + + /** + * @reason Redirect the terrain setup phase to our renderer + * @author JellySquid + */ + @Overwrite + private void setupTerrain(Camera camera, Frustum frustum, boolean hasForcedFrustum, int frame, boolean spectator) { + RenderDevice.enterManagedCode(); + + try { + this.renderer.updateChunks(camera, frustum, hasForcedFrustum, frame, spectator); + } finally { + RenderDevice.exitManagedCode(); + } + } + + /** + * @reason Redirect chunk updates to our renderer + * @author JellySquid + */ + @Overwrite + public void scheduleBlockRenders(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + this.renderer.scheduleRebuildForBlockArea(minX, minY, minZ, maxX, maxY, maxZ, false); + } + + /** + * @reason Redirect chunk updates to our renderer + * @author JellySquid + */ + @Overwrite + public void scheduleBlockRenders(int x, int y, int z) { + this.renderer.scheduleRebuildForChunks(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1, false); + } + + /** + * @reason Redirect chunk updates to our renderer + * @author JellySquid + */ + @Overwrite + private void scheduleSectionRender(BlockPos pos, boolean important) { + this.renderer.scheduleRebuildForBlockArea(pos.getX() - 1, pos.getY() - 1, pos.getZ() - 1, pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1, important); + } + + /** + * @reason Redirect chunk updates to our renderer + * @author JellySquid + */ + @Overwrite + private void scheduleChunkRender(int x, int y, int z, boolean important) { + this.renderer.scheduleRebuildForChunk(x, y, z, important); + } + + @Inject(method = "reload()V", at = @At("RETURN")) + private void onReload(CallbackInfo ci) { + RenderDevice.enterManagedCode(); + + try { + this.renderer.reload(); + } finally { + RenderDevice.exitManagedCode(); + } + } + + @Inject(method = "render", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/WorldRenderer;noCullingBlockEntities:Ljava/util/Set;", shift = At.Shift.BEFORE, ordinal = 0)) + private void onRenderTileEntities(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) { + this.renderer.renderTileEntities(matrices, this.bufferBuilders, this.blockBreakingProgressions, camera, tickDelta); + } + + /** + * @reason Replace the debug string + * @author JellySquid + */ + @Overwrite + public String getChunksDebugString() { + return this.renderer.getChunksDebugString(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java new file mode 100644 index 000000000..c214e52c6 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java @@ -0,0 +1,79 @@ +package me.jellysquid.mods.sodium.mixin.features.debug; + +import com.google.common.collect.Lists; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.compat.forge.ForgeBlockRenderer; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderBackend; +import net.minecraft.client.gui.hud.DebugHud; +import net.minecraft.util.Formatting; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.List; + +@Mixin(DebugHud.class) +public abstract class MixinDebugHud { + @Shadow + private static long toMiB(long bytes) { + throw new UnsupportedOperationException(); + } + + @Redirect(method = "getRightText", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList([Ljava/lang/Object;)Ljava/util/ArrayList;")) + private ArrayList redirectRightTextEarly(Object[] elements) { + ArrayList strings = Lists.newArrayList((String[]) elements); + strings.add(""); + strings.add("Embeddium Renderer"); + strings.add(Formatting.UNDERLINE + getFormattedVersionText()); + strings.add(""); + strings.addAll(getChunkRendererDebugStrings()); + + if (SodiumClientMod.options().advanced.ignoreDriverBlacklist) { + strings.add(Formatting.RED + "(!!) Driver blacklist ignored"); + } + + for (int i = 0; i < strings.size(); i++) { + String str = strings.get(i); + + if (str.startsWith("Allocated:")) { + strings.add(i + 1, getNativeMemoryString()); + + break; + } + } + + return strings; + } + + private static String getFormattedVersionText() { + String version = SodiumClientMod.getVersion(); + Formatting color; + + if (version.contains("git.")) { + color = Formatting.RED; + } else { + color = Formatting.GREEN; + } + + return color + version; + } + + private static List getChunkRendererDebugStrings() { + ChunkRenderBackend backend = SodiumWorldRenderer.getInstance().getChunkRenderer(); + + List strings = new ArrayList<>(5); + strings.add("Chunk Renderer: " + backend.getRendererName()); + strings.add("Block Renderer: " + (ForgeBlockRenderer.useForgeLightingPipeline() ? "Forge" : "Sodium")); + strings.addAll(backend.getDebugStrings()); + + return strings; + } + + private static String getNativeMemoryString() { + return "Off-Heap: +" + toMiB(ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getUsed()) + "MB"; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinCuboid.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinCuboid.java new file mode 100644 index 000000000..b2d895cbe --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinCuboid.java @@ -0,0 +1,19 @@ +package me.jellysquid.mods.sodium.mixin.features.entity.fast_render; + +import me.jellysquid.mods.sodium.client.model.ModelCuboidAccessor; +import net.minecraft.client.model.ModelPart; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(ModelPart.Cuboid.class) +public class MixinCuboid implements ModelCuboidAccessor { + @Shadow + @Final + private ModelPart.Quad[] sides; + + @Override + public ModelPart.Quad[] getQuads() { + return this.sides; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinModelPart.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinModelPart.java new file mode 100644 index 000000000..68181b8ff --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinModelPart.java @@ -0,0 +1,70 @@ +package me.jellysquid.mods.sodium.mixin.features.entity.fast_render; + +import it.unimi.dsi.fastutil.objects.ObjectList; +import me.jellysquid.mods.sodium.client.model.ModelCuboidAccessor; +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; +import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; +import me.jellysquid.mods.sodium.client.util.Norm3b; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import me.jellysquid.mods.sodium.client.util.math.Matrix3fExtended; +import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; +import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Vec3f; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(ModelPart.class) +public class MixinModelPart { + private static final float NORM = 1.0F / 16.0F; + + @Shadow + @Final + private ObjectList cuboids; + + /** + * @author JellySquid + * @reason Use optimized vertex writer, avoid allocations, use quick matrix transformations + */ + @Overwrite + private void renderCuboids(MatrixStack.Entry matrices, VertexConsumer vertexConsumer, int light, int overlay, float red, float green, float blue, float alpha) { + Matrix3fExtended normalExt = MatrixUtil.getExtendedMatrix(matrices.getNormal()); + Matrix4fExtended modelExt = MatrixUtil.getExtendedMatrix(matrices.getModel()); + + QuadVertexSink drain = VertexDrain.of(vertexConsumer).createSink(VanillaVertexTypes.QUADS); + drain.ensureCapacity(this.cuboids.size() * 6 * 4); + + int color = ColorABGR.pack(red, green, blue, alpha); + + for (ModelPart.Cuboid cuboid : this.cuboids) { + for (ModelPart.Quad quad : ((ModelCuboidAccessor) cuboid).getQuads()) { + float normX = normalExt.transformVecX(quad.direction); + float normY = normalExt.transformVecY(quad.direction); + float normZ = normalExt.transformVecZ(quad.direction); + + int norm = Norm3b.pack(normX, normY, normZ); + + for (ModelPart.Vertex vertex : quad.vertices) { + Vec3f pos = vertex.pos; + + float x1 = pos.getX() * NORM; + float y1 = pos.getY() * NORM; + float z1 = pos.getZ() * NORM; + + float x2 = modelExt.transformVecX(x1, y1, z1); + float y2 = modelExt.transformVecY(x1, y1, z1); + float z2 = modelExt.transformVecZ(x1, y1, z1); + + drain.writeQuad(x2, y2, z2, color, vertex.u, vertex.v, light, overlay, norm); + } + } + } + + drain.flush(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinEntityRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinEntityRenderer.java new file mode 100644 index 000000000..53f57df22 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinEntityRenderer.java @@ -0,0 +1,51 @@ +package me.jellysquid.mods.sodium.mixin.features.entity.smooth_lighting; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import me.jellysquid.mods.sodium.client.model.light.EntityLighter; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import me.jellysquid.mods.sodium.client.render.entity.EntityLightSampler; +import net.minecraft.client.render.Frustum; +import net.minecraft.client.render.entity.EntityRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(EntityRenderer.class) +public abstract class MixinEntityRenderer implements EntityLightSampler { + @Shadow + protected abstract int getBlockLight(T entity, BlockPos blockPos); + + @Shadow(remap = false) + protected abstract int func_239381_b_(T entity, BlockPos blockPos); + + @Inject(method = "getLight", at = @At("HEAD"), cancellable = true) + private void preGetLight(T entity, float tickDelta, CallbackInfoReturnable cir) { + // Use smooth entity lighting if enabled + if (SodiumClientMod.options().quality.smoothLighting == SodiumGameOptions.LightingQuality.HIGH) { + cir.setReturnValue(EntityLighter.getBlendedLight(this, entity, tickDelta)); + } + } + + @Inject(method = "shouldRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/Frustum;isVisible(Lnet/minecraft/util/math/Box;)Z", shift = At.Shift.AFTER), cancellable = true) + private void preShouldRender(T entity, Frustum frustum, double x, double y, double z, CallbackInfoReturnable cir) { + // If the entity isn't culled already by other means, try to perform a second pass + if (cir.getReturnValue() && !SodiumWorldRenderer.getInstance().isEntityVisible(entity)) { + cir.setReturnValue(false); + } + } + + @Override + public int bridge$getBlockLight(T entity, BlockPos pos) { + return this.getBlockLight(entity, pos); + } + + @Override + public int bridge$getSkyLight(T entity, BlockPos pos) { + return this.func_239381_b_(entity, pos); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinPaintingEntityRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinPaintingEntityRenderer.java new file mode 100644 index 000000000..35c8b1e43 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinPaintingEntityRenderer.java @@ -0,0 +1,59 @@ +package me.jellysquid.mods.sodium.mixin.features.entity.smooth_lighting; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import me.jellysquid.mods.sodium.client.model.light.EntityLighter; +import me.jellysquid.mods.sodium.client.render.entity.EntityLightSampler; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.render.entity.EntityRenderDispatcher; +import net.minecraft.client.render.entity.EntityRenderer; +import net.minecraft.client.render.entity.PaintingEntityRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.decoration.painting.PaintingEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(PaintingEntityRenderer.class) +public abstract class MixinPaintingEntityRenderer extends EntityRenderer implements EntityLightSampler { + private PaintingEntity entity; + private float tickDelta; + + protected MixinPaintingEntityRenderer(EntityRenderDispatcher dispatcher) { + super(dispatcher); + } + + @Inject(method = "render", at = @At(value = "HEAD")) + public void preRender(PaintingEntity paintingEntity, float f, float g, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + this.entity = paintingEntity; + this.tickDelta = g; + } + + /** + * @author FlashyReese + * @reason Redirect Lightmap coord with Sodium's EntityLighter. + */ + @Redirect(method = "func_229122_a_", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;getLightmapCoordinates(Lnet/minecraft/world/BlockRenderView;Lnet/minecraft/util/math/BlockPos;)I")) + public int redirectLightmapCoord(BlockRenderView world, BlockPos pos) { + if (SodiumClientMod.options().quality.smoothLighting == SodiumGameOptions.LightingQuality.HIGH && this.entity != null) { + return EntityLighter.getBlendedLight(this, this.entity, tickDelta); + } else { + return WorldRenderer.getLightmapCoordinates(world, pos); + } + } + + @Override + public int bridge$getBlockLight(PaintingEntity entity, BlockPos pos) { + return this.getBlockLight(entity, pos); + } + + @Override + public int bridge$getSkyLight(PaintingEntity entity, BlockPos pos) { + return this.method_27950(entity, pos); + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBackgroundRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBackgroundRenderer.java new file mode 100644 index 000000000..a9abc761d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBackgroundRenderer.java @@ -0,0 +1,24 @@ +package me.jellysquid.mods.sodium.mixin.features.fast_biome_colors; + +import me.jellysquid.mods.sodium.client.util.color.FastCubicSampler; +import net.minecraft.client.render.BackgroundRenderer; +import net.minecraft.client.render.Camera; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.CubicSampler; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(BackgroundRenderer.class) +public class MixinBackgroundRenderer { + @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/CubicSampler;sampleColor(Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/util/CubicSampler$RgbFetcher;)Lnet/minecraft/util/math/Vec3d;")) + private static Vec3d redirectSampleColor(Vec3d pos, CubicSampler.RgbFetcher rgbFetcher, Camera camera, float tickDelta, ClientWorld world, int i, float f) { + float u = MathHelper.clamp(MathHelper.cos(world.getSkyAngle(tickDelta) * 6.2831855F) * 2.0F + 0.5F, 0.0F, 1.0F); + + return FastCubicSampler.sampleColor(pos, + (x, y, z) -> world.getBiomeAccess().getBiomeForNoiseGen(x, y, z).getFogColor(), + (v) -> world.getSkyProperties().adjustFogColor(v, u)); + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBlock.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBlock.java new file mode 100644 index 000000000..635986051 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBlock.java @@ -0,0 +1,17 @@ +package me.jellysquid.mods.sodium.mixin.features.fast_biome_colors; + +import me.jellysquid.mods.sodium.client.model.quad.blender.BlockColorSettings; +import me.jellysquid.mods.sodium.client.model.quad.blender.DefaultBlockColorSettings; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(Block.class) +public class MixinBlock implements BlockColorSettings { + @Override + public boolean useSmoothColorBlending(BlockRenderView view, BlockState state, BlockPos pos) { + return DefaultBlockColorSettings.isSmoothBlendingAvailable(state.getBlock()); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinFluid.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinFluid.java new file mode 100644 index 000000000..d2e7e2d62 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinFluid.java @@ -0,0 +1,16 @@ +package me.jellysquid.mods.sodium.mixin.features.fast_biome_colors; + +import me.jellysquid.mods.sodium.client.model.quad.blender.BlockColorSettings; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.FluidState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(Fluid.class) +public class MixinFluid implements BlockColorSettings { + @Override + public boolean useSmoothColorBlending(BlockRenderView view, FluidState state, BlockPos pos) { + return true; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/MixinDebugHud.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/MixinDebugHud.java new file mode 100644 index 000000000..6337d5c20 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/MixinDebugHud.java @@ -0,0 +1,133 @@ +package me.jellysquid.mods.sodium.mixin.features.gui; + +import com.google.common.base.Strings; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.hud.DebugHud; +import net.minecraft.client.render.*; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Matrix4f; +import org.apache.commons.lang3.Validate; +import org.lwjgl.opengl.GL20C; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; + +@Mixin(DebugHud.class) +public abstract class MixinDebugHud { + @Shadow + @Final + private MinecraftClient client; + + @Shadow + @Final + private TextRenderer fontRenderer; + + private List capturedList = null; + + @Redirect(method = { "renderLeftText", "renderRightText" }, at = @At(value = "INVOKE", target = "Ljava/util/List;size()I")) + private int preRenderText(List list) { + // Capture the list to be rendered later + this.capturedList = list; + + return 0; // Prevent the rendering of any text + } + + @Inject(method = "renderLeftText", at = @At("RETURN")) + public void renderLeftText(MatrixStack matrixStack, CallbackInfo ci) { + this.renderCapturedText(matrixStack, false); + } + + @Inject(method = "renderRightText", at = @At("RETURN")) + public void renderRightText(MatrixStack matrixStack, CallbackInfo ci) { + this.renderCapturedText(matrixStack, true); + } + + private void renderCapturedText(MatrixStack matrixStack, boolean right) { + Validate.notNull(this.capturedList, "Failed to capture string list"); + + this.renderBackdrop(matrixStack, this.capturedList, right); + this.renderStrings(matrixStack, this.capturedList, right); + + this.capturedList = null; + } + + private void renderStrings(MatrixStack matrixStack, List list, boolean right) { + VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer()); + + Matrix4f modelMatrix = matrixStack.peek().getModel(); + + for (int i = 0; i < list.size(); ++i) { + String string = list.get(i); + + if (!Strings.isNullOrEmpty(string)) { + int height = 9; + int width = this.fontRenderer.getWidth(string); + + float x1 = right ? this.client.getWindow().getScaledWidth() - 2 - width : 2; + float y1 = 2 + (height * i); + + this.fontRenderer.draw(string, x1, y1, 0xe0e0e0, false, modelMatrix, immediate, + false, 0, 15728880, this.fontRenderer.isRightToLeft()); + } + } + + immediate.draw(); + } + + private void renderBackdrop(MatrixStack matrixStack, List list, boolean right) { + RenderSystem.enableBlend(); + RenderSystem.disableTexture(); + RenderSystem.defaultBlendFunc(); + + int color = 0x90505050; + + float f = (float) (color >> 24 & 255) / 255.0F; + float g = (float) (color >> 16 & 255) / 255.0F; + float h = (float) (color >> 8 & 255) / 255.0F; + float k = (float) (color & 255) / 255.0F; + + BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); + bufferBuilder.begin(GL20C.GL_QUADS, VertexFormats.POSITION_COLOR); + + Matrix4f matrix = matrixStack.peek() + .getModel(); + + for (int i = 0; i < list.size(); ++i) { + String string = list.get(i); + + if (Strings.isNullOrEmpty(string)) { + continue; + } + + int height = 9; + int width = this.fontRenderer.getWidth(string); + + int x = right ? this.client.getWindow().getScaledWidth() - 2 - width : 2; + int y = 2 + height * i; + + float x1 = x - 1; + float y1 = y - 1; + float x2 = x + width + 1; + float y2 = y + height - 1; + + bufferBuilder.vertex(matrix, x1, y2, 0.0F).color(g, h, k, f).next(); + bufferBuilder.vertex(matrix, x2, y2, 0.0F).color(g, h, k, f).next(); + bufferBuilder.vertex(matrix, x2, y1, 0.0F).color(g, h, k, f).next(); + bufferBuilder.vertex(matrix, x1, y1, 0.0F).color(g, h, k, f).next(); + } + + bufferBuilder.end(); + + BufferRenderer.draw(bufferBuilder); + RenderSystem.enableTexture(); + RenderSystem.disableBlend(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_fps_pie/MixinMinecraftClient.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_fps_pie/MixinMinecraftClient.java new file mode 100644 index 000000000..06b2f78bb --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_fps_pie/MixinMinecraftClient.java @@ -0,0 +1,43 @@ +package me.jellysquid.mods.sodium.mixin.features.gui.fast_fps_pie; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.profiler.ProfileResult; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(MinecraftClient.class) +public class MixinMinecraftClient { + @Shadow + @Final + public TextRenderer textRenderer; + + private VertexConsumerProvider.Immediate immediate; + + @Inject(method = "drawProfilerResults", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/client/font/TextRenderer;drawWithShadow(Lnet/minecraft/client/util/math/MatrixStack;Ljava/lang/String;FFI)I")) + private void preRenderText(MatrixStack matrices, ProfileResult profileResult, CallbackInfo ci) { + this.immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer()); + } + + @Redirect(method = "drawProfilerResults", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/font/TextRenderer;drawWithShadow(Lnet/minecraft/client/util/math/MatrixStack;Ljava/lang/String;FFI)I")) + private int drawWithShadow(TextRenderer textRenderer, MatrixStack matrices, String text, float x, float y, int color) { + if (text != null) { + return this.textRenderer.draw(text, x, y, color, true, matrices.peek().getModel(), this.immediate, + false, 0, 15728880, this.textRenderer.isRightToLeft()); + } + return 0; + } + + @Inject(method = "drawProfilerResults", at = @At("TAIL")) + private void renderText(MatrixStack matrices, ProfileResult profileResult, CallbackInfo ci) { + this.immediate.draw(); + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_loading_screen/MixinLevelLoadingScreen.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_loading_screen/MixinLevelLoadingScreen.java new file mode 100644 index 000000000..a12d11281 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_loading_screen/MixinLevelLoadingScreen.java @@ -0,0 +1,132 @@ +package me.jellysquid.mods.sodium.mixin.features.gui.fast_loading_screen; + +import com.mojang.blaze3d.systems.RenderSystem; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; +import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.BasicScreenQuadVertexSink; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import me.jellysquid.mods.sodium.client.util.color.ColorARGB; +import net.minecraft.client.gui.WorldGenerationProgressTracker; +import net.minecraft.client.gui.screen.LevelLoadingScreen; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexFormats; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Matrix4f; +import net.minecraft.world.chunk.ChunkStatus; +import org.lwjgl.opengl.GL20C; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +/** + * Re-implements the loading screen with considerations to reduce draw calls and other sources of overhead. This can + * improve world load times on slower processors with very few cores. + */ +@Mixin(LevelLoadingScreen.class) +public class MixinLevelLoadingScreen { + @Mutable + @Shadow + @Final + private static Object2IntMap STATUS_TO_COLOR; + + private static Reference2IntOpenHashMap STATUS_TO_COLOR_FAST; + + private static final int NULL_STATUS_COLOR = ColorABGR.pack(0, 0, 0, 0xFF); + private static final int DEFAULT_STATUS_COLOR = ColorARGB.pack(0, 0x11, 0xFF, 0xFF); + + /** + * This implementation differs from vanilla's in the following key ways. + * - All tiles are batched together in one draw call, reducing CPU overhead by an order of magnitudes. + * - Reference hashing is used for faster ChunkStatus -> Color lookup. + * - Colors are stored in ABGR format so conversion is not necessary every tile draw. + * + * @reason Significantly optimized implementation. + * @author JellySquid + */ + @Overwrite + public static void drawChunkMap(MatrixStack matrixStack, WorldGenerationProgressTracker tracker, int mapX, int mapY, int mapScale, int mapPadding) { + if (STATUS_TO_COLOR_FAST == null) { + STATUS_TO_COLOR_FAST = new Reference2IntOpenHashMap<>(STATUS_TO_COLOR.size()); + STATUS_TO_COLOR_FAST.put(null, NULL_STATUS_COLOR); + STATUS_TO_COLOR.object2IntEntrySet() + .forEach(entry -> STATUS_TO_COLOR_FAST.put(entry.getKey(), ColorARGB.toABGR(entry.getIntValue(), 0xFF))); + } + + Matrix4f matrix = matrixStack.peek().getModel(); + + Tessellator tessellator = Tessellator.getInstance(); + + RenderSystem.enableBlend(); + RenderSystem.disableTexture(); + RenderSystem.defaultBlendFunc(); + + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL20C.GL_QUADS, VertexFormats.POSITION_COLOR); + + BasicScreenQuadVertexSink sink = VertexDrain.of(buffer).createSink(VanillaVertexTypes.BASIC_SCREEN_QUADS); + + int centerSize = tracker.getCenterSize(); + int size = tracker.getSize(); + + int tileSize = mapScale + mapPadding; + + if (mapPadding != 0) { + int mapRenderCenterSize = centerSize * tileSize - mapPadding; + int radius = mapRenderCenterSize / 2 + 1; + + sink.ensureCapacity(4 * 4); + addRect(matrix, sink, mapX - radius, mapY - radius, mapX - radius + 1, mapY + radius, DEFAULT_STATUS_COLOR); + addRect(matrix, sink, mapX + radius - 1, mapY - radius, mapX + radius, mapY + radius, DEFAULT_STATUS_COLOR); + addRect(matrix, sink, mapX - radius, mapY - radius, mapX + radius, mapY - radius + 1, DEFAULT_STATUS_COLOR); + addRect(matrix, sink, mapX - radius, mapY + radius - 1, mapX + radius, mapY + radius, DEFAULT_STATUS_COLOR); + } + + int mapRenderSize = size * tileSize - mapPadding; + int mapStartX = mapX - mapRenderSize / 2; + int mapStartY = mapY - mapRenderSize / 2; + + ChunkStatus prevStatus = null; + int prevColor = NULL_STATUS_COLOR; + + sink.ensureCapacity(size * size * 4); + for (int x = 0; x < size; ++x) { + int tileX = mapStartX + x * tileSize; + + for (int z = 0; z < size; ++z) { + int tileY = mapStartY + z * tileSize; + + ChunkStatus status = tracker.getChunkStatus(x, z); + int color; + + if (prevStatus == status) { + color = prevColor; + } else { + color = STATUS_TO_COLOR_FAST.getInt(status); + + prevStatus = status; + prevColor = color; + } + + addRect(matrix, sink, tileX, tileY, tileX + mapScale, tileY + mapScale, color); + } + } + + sink.flush(); + tessellator.draw(); + + RenderSystem.enableTexture(); + RenderSystem.disableBlend(); + } + + private static void addRect(Matrix4f matrix, BasicScreenQuadVertexSink sink, int x1, int y1, int x2, int y2, int color) { + sink.writeQuad(matrix, x1, y2, 0, color); + sink.writeQuad(matrix, x2, y2, 0, color); + sink.writeQuad(matrix, x2, y1, 0, color); + sink.writeQuad(matrix, x1, y1, 0, color); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_status_bars/MixinInGameHud.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_status_bars/MixinInGameHud.java new file mode 100644 index 000000000..b345997d4 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_status_bars/MixinInGameHud.java @@ -0,0 +1,60 @@ +package me.jellysquid.mods.sodium.mixin.features.gui.fast_status_bars; + +import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.hud.InGameHud; +import net.minecraft.client.render.*; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(InGameHud.class) +public abstract class MixinInGameHud extends DrawableHelper { + @Shadow + protected abstract PlayerEntity getCameraPlayer(); + + private final BufferBuilder bufferBuilder = new BufferBuilder(8192); + // It's possible for status bar rendering to be skipped + private boolean isRenderingStatusBars; + + @Inject(method = "renderStatusBars", at = @At("HEAD")) + private void preRenderStatusBars(MatrixStack matrices, CallbackInfo ci) { + if (this.getCameraPlayer() != null) { + this.bufferBuilder.begin(4, VertexFormats.POSITION_TEXTURE); + this.isRenderingStatusBars = true; + } else { + this.isRenderingStatusBars = false; + } + } + + @Redirect(method = { "renderStatusBars", "drawHeart" }, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;drawTexture(Lnet/minecraft/client/util/math/MatrixStack;IIIIII)V")) + private void drawTexture(InGameHud inGameHud, MatrixStack matrices, int x0, int y0, int u, int v, int width, int height) { + Matrix4f matrix = matrices.peek().getModel(); + int x1 = x0 + width; + int y1 = y0 + height; + int z = this.getZOffset(); + // Default texture size is 256x256 + float u0 = u / 256f; + float u1 = (u + width) / 256f; + float v0 = v / 256f; + float v1 = (v + height) / 256f; + + this.bufferBuilder.vertex(matrix, x0, y1, z).texture(u0, v1).next(); + this.bufferBuilder.vertex(matrix, x1, y1, z).texture(u1, v1).next(); + this.bufferBuilder.vertex(matrix, x1, y0, z).texture(u1, v0).next(); + this.bufferBuilder.vertex(matrix, x0, y0, z).texture(u0, v0).next(); + } + + @Inject(method = "renderStatusBars", at = @At("RETURN")) + private void renderStatusBars(MatrixStack matrices, CallbackInfo ci) { + if (this.isRenderingStatusBars) { + this.bufferBuilder.end(); + BufferRenderer.draw(this.bufferBuilder); + } + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/font/MixinGlyphRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/font/MixinGlyphRenderer.java new file mode 100644 index 000000000..370175bec --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/font/MixinGlyphRenderer.java @@ -0,0 +1,75 @@ +package me.jellysquid.mods.sodium.mixin.features.gui.font; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; +import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import net.minecraft.client.font.GlyphRenderer; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.util.math.Matrix4f; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(GlyphRenderer.class) +public class MixinGlyphRenderer { + @Shadow + @Final + private float minX; + + @Shadow + @Final + private float maxX; + + @Shadow + @Final + private float minY; + + @Shadow + @Final + private float maxY; + + @Shadow + @Final + private float minU; + + @Shadow + @Final + private float minV; + + @Shadow + @Final + private float maxV; + + @Shadow + @Final + private float maxU; + + /** + * @reason Use intrinsics + * @author JellySquid + */ + @Overwrite + public void draw(boolean italic, float x, float y, Matrix4f matrix, VertexConsumer vertexConsumer, float red, float green, float blue, float alpha, int light) { + float x1 = x + this.minX; + float x2 = x + this.maxX; + float y1 = this.minY - 3.0F; + float y2 = this.maxY - 3.0F; + float h1 = y + y1; + float h2 = y + y2; + float w1 = italic ? 1.0F - 0.25F * y1 : 0.0F; + float w2 = italic ? 1.0F - 0.25F * y2 : 0.0F; + + int color = ColorABGR.pack(red, green, blue, alpha); + + GlyphVertexSink drain = VertexDrain.of(vertexConsumer) + .createSink(VanillaVertexTypes.GLYPHS); + drain.ensureCapacity(4); + drain.writeGlyph(matrix, x1 + w1, h1, 0.0F, color, this.minU, this.minV, light); + drain.writeGlyph(matrix, x1 + w2, h2, 0.0F, color, this.minU, this.maxV, light); + drain.writeGlyph(matrix, x2 + w2, h2, 0.0F, color, this.maxU, this.maxV, light); + drain.writeGlyph(matrix, x2 + w1, h1, 0.0F, color, this.maxU, this.minV, light); + drain.flush(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/item/MixinItemRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/item/MixinItemRenderer.java new file mode 100644 index 000000000..61d585db7 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/item/MixinItemRenderer.java @@ -0,0 +1,124 @@ +package me.jellysquid.mods.sodium.mixin.features.item; + +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; +import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; +import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import me.jellysquid.mods.sodium.client.util.color.ColorARGB; +import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; +import me.jellysquid.mods.sodium.client.world.biome.ItemColorsExtended; +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.client.color.item.ItemColorProvider; +import net.minecraft.client.color.item.ItemColors; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.Direction; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.List; + +@Mixin(ItemRenderer.class) +public class MixinItemRenderer { + private final XoRoShiRoRandom random = new XoRoShiRoRandom(); + + @Shadow + @Final + private ItemColors colorMap; + + /** + * @reason Avoid allocations + * @author JellySquid + */ + @Overwrite + public void renderBakedItemModel(BakedModel model, ItemStack stack, int light, int overlay, MatrixStack matrices, VertexConsumer vertices) { + XoRoShiRoRandom random = this.random; + + for (Direction direction : DirectionUtil.ALL_DIRECTIONS) { + List quads = model.getQuads(null, direction, random.setSeedAndReturn(42L)); + + if (!quads.isEmpty()) { + this.renderBakedItemQuads(matrices, vertices, quads, stack, light, overlay); + } + } + + List quads = model.getQuads(null, null, random.setSeedAndReturn(42L)); + + if (!quads.isEmpty()) { + this.renderBakedItemQuads(matrices, vertices, quads, stack, light, overlay); + } + } + + /** + * @reason Use vertex building intrinsics + * @author JellySquid + */ + @Overwrite + public void renderBakedItemQuads(MatrixStack matrices, VertexConsumer vertexConsumer, List quads, ItemStack stack, int light, int overlay) { + MatrixStack.Entry entry = matrices.peek(); + + ItemColorProvider colorProvider = null; + + QuadVertexSink drain = VertexDrain.of(vertexConsumer) + .createSink(VanillaVertexTypes.QUADS); + drain.ensureCapacity(quads.size() * 4); + + for (BakedQuad bakedQuad : quads) { + int color = 0xFFFFFFFF; + + if (!stack.isEmpty() && bakedQuad.hasColor()) { + if (colorProvider == null) { + colorProvider = ((ItemColorsExtended) this.colorMap).getColorProvider(stack); + } + + try { + if (colorProvider == null) { + color = ColorARGB.toABGR(this.colorMap.getColorMultiplier(stack, bakedQuad.getColorIndex()), 255); + } else { + color = ColorARGB.toABGR((colorProvider.getColor(stack, bakedQuad.getColorIndex())), 255); + } + }catch(Exception e) { + } + } + + ModelQuadView quad = ((ModelQuadView) bakedQuad); + + for (int i = 0; i < 4; i++) { + + int fColor = multARGBInts(quad.getColor(i), color); + + drain.writeQuad(entry, quad.getX(i), quad.getY(i), quad.getZ(i), fColor, quad.getTexU(i), quad.getTexV(i), + ModelQuadUtil.mergeBakedLight(quad.getLight(i), light), overlay, ModelQuadUtil.getFacingNormal(bakedQuad.getFace(), quad.getNormal(i))); + } + + SpriteUtil.markSpriteActive(quad.rubidium$getSprite()); + } + + drain.flush(); + } + + private int multARGBInts(int colorA, int colorB) { + // Most common case: Either quad coloring or tint-based coloring, but not both + if (colorA == -1) { + return colorB; + } else if (colorB == -1) { + return colorA; + } + // General case (rare): Both colorings, actually perform the multiplication + int a = (int)((ColorABGR.unpackAlpha(colorA)/255.0f) * (ColorABGR.unpackAlpha(colorB)/255.0f) * 255.0f); + int b = (int)((ColorABGR.unpackBlue(colorA)/255.0f) * (ColorABGR.unpackBlue(colorB)/255.0f) * 255.0f); + int g = (int)((ColorABGR.unpackGreen(colorA)/255.0f) * (ColorABGR.unpackGreen(colorB)/255.0f) * 255.0f); + int r = (int)((ColorABGR.unpackRed(colorA)/255.0f) * (ColorABGR.unpackRed(colorB)/255.0f) * 255.0f); + return ColorABGR.pack(r, g, b, a); + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinMatrixStack.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinMatrixStack.java new file mode 100644 index 000000000..18c1ad048 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinMatrixStack.java @@ -0,0 +1,47 @@ +package me.jellysquid.mods.sodium.mixin.features.matrix_stack; + +import me.jellysquid.mods.sodium.client.util.math.Matrix3fExtended; +import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; +import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Quaternion; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Deque; + +@Mixin(MatrixStack.class) +public class MixinMatrixStack { + @Shadow + @Final + private Deque stack; + + /** + * @reason Use our faster specialized function + * @author JellySquid + */ + @Overwrite + public void translate(double x, double y, double z) { + MatrixStack.Entry entry = this.stack.getLast(); + + Matrix4fExtended mat = MatrixUtil.getExtendedMatrix(entry.getModel()); + mat.translate((float) x, (float) y, (float) z); + } + + /** + * @reason Use our faster specialized function + * @author JellySquid + */ + @Overwrite + public void multiply(Quaternion q) { + MatrixStack.Entry entry = this.stack.getLast(); + + Matrix4fExtended mat4 = MatrixUtil.getExtendedMatrix(entry.getModel()); + mat4.rotate(q); + + Matrix3fExtended mat3 = MatrixUtil.getExtendedMatrix(entry.getNormal()); + mat3.rotate(q); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinVertexConsumer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinVertexConsumer.java new file mode 100644 index 000000000..aee0f0f73 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinVertexConsumer.java @@ -0,0 +1,48 @@ +package me.jellysquid.mods.sodium.mixin.features.matrix_stack; + +import me.jellysquid.mods.sodium.client.util.math.Matrix3fExtended; +import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; +import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.util.math.Matrix3f; +import net.minecraft.util.math.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(VertexConsumer.class) +public interface MixinVertexConsumer { + @Shadow + VertexConsumer normal(float x, float y, float z); + + @Shadow + VertexConsumer vertex(double x, double y, double z); + + /** + * @reason Avoid allocations + * @author JellySquid + */ + @Overwrite + default VertexConsumer vertex(Matrix4f matrix, float x, float y, float z) { + Matrix4fExtended ext = MatrixUtil.getExtendedMatrix(matrix); + float x2 = ext.transformVecX(x, y, z); + float y2 = ext.transformVecY(x, y, z); + float z2 = ext.transformVecZ(x, y, z); + + return this.vertex(x2, y2, z2); + } + + /** + * @reason Avoid allocations + * @author JellySquid + */ + @Overwrite + default VertexConsumer normal(Matrix3f matrix, float x, float y, float z) { + Matrix3fExtended ext = MatrixUtil.getExtendedMatrix(matrix); + float x2 = ext.transformVecX(x, y, z); + float y2 = ext.transformVecY(x, y, z); + float z2 = ext.transformVecZ(x, y, z); + + return this.normal(x2, y2, z2); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinMultipartBakedModel.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinMultipartBakedModel.java new file mode 100644 index 000000000..7b372cf73 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinMultipartBakedModel.java @@ -0,0 +1,82 @@ +package me.jellysquid.mods.sodium.mixin.features.model; + +import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.render.model.MultipartBakedModel; +import net.minecraft.util.math.Direction; +import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.data.MultipartModelData; +import org.apache.commons.lang3.tuple.Pair; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.locks.StampedLock; +import java.util.function.Predicate; + +@Mixin(MultipartBakedModel.class) +public class MixinMultipartBakedModel { + private final Map stateCacheFast = new Reference2ReferenceOpenHashMap<>(); + private final StampedLock lock = new StampedLock(); + + @Shadow + @Final + private List, BakedModel>> components; + + /** + * @author JellySquid + * @reason Avoid expensive allocations and replace bitfield indirection + */ + @Overwrite + public List getQuads(BlockState state, Direction face, Random random, IModelData modelData) { + if (state == null) { + return Collections.emptyList(); + } + + BakedModel[] models; + + long readStamp = this.lock.readLock(); + try { + models = this.stateCacheFast.get(state); + } finally { + this.lock.unlockRead(readStamp); + } + + if (models == null) { + long writeStamp = this.lock.writeLock(); + try { + List modelList = new ArrayList<>(this.components.size()); + + for (Pair, BakedModel> pair : this.components) { + if (pair.getLeft().test(state)) { + modelList.add(pair.getRight()); + } + } + + models = modelList.toArray(new BakedModel[modelList.size()]); + this.stateCacheFast.put(state, models); + } finally { + this.lock.unlockWrite(writeStamp); + } + } + + List quads = new ArrayList<>(); + long seed = random.nextLong(); + + for (BakedModel model : models) { + random.setSeed(seed); + quads.addAll(model.getQuads(state, face, random, MultipartModelData.resolve(model, modelData))); + } + + return quads; + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinWeightedBakedModel.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinWeightedBakedModel.java new file mode 100644 index 000000000..fcf3cab88 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinWeightedBakedModel.java @@ -0,0 +1,60 @@ +package me.jellysquid.mods.sodium.mixin.features.model; + +import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.render.model.WeightedBakedModel; +import net.minecraft.util.math.Direction; +import net.minecraftforge.client.model.data.IModelData; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Collections; +import java.util.List; +import java.util.Random; + +@Mixin(WeightedBakedModel.class) +public class MixinWeightedBakedModel { + @Shadow + @Final + private List models; + + @Shadow + @Final + private int totalWeight; + + /** + * @author JellySquid + * @reason Avoid excessive object allocations + */ + @Overwrite + public List getQuads(@Nullable BlockState state, @Nullable Direction face, Random random, IModelData modelData) { + WeightedBakedModel.Entry entry = getAt(this.models, Math.abs((int) random.nextLong()) % this.totalWeight); + + if (entry != null) { + return entry.model.getQuads(state, face, random, modelData); + } + + return Collections.emptyList(); + } + + private static T getAt(List pool, int totalWeight) { + int i = 0; + int len = pool.size(); + + T weighted; + + do { + if (i >= len) { + return null; + } + + weighted = pool.get(i++); + totalWeight -= weighted.weight; + } while (totalWeight >= 0); + + return weighted; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/optimized_bamboo/MixinBambooBlock.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/optimized_bamboo/MixinBambooBlock.java new file mode 100644 index 000000000..3e9f812ab --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/optimized_bamboo/MixinBambooBlock.java @@ -0,0 +1,22 @@ +package me.jellysquid.mods.sodium.mixin.features.optimized_bamboo; + +import net.minecraft.block.BambooBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(BambooBlock.class) +public class MixinBambooBlock extends Block { + public MixinBambooBlock(Settings settings) { + super(settings); + } + + // This is a fix for an oversight on Mojang's side, where this block always returns 1.0 regardless of the state. It returns the same result, + // but improves performance significantly. This was originally found by darkevilmac in https://github.com/TridentMC/FastBamboo. + @Override + public float getAmbientOcclusionLightLevel(BlockState state, BlockView world, BlockPos pos) { + return 1.0f; + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinGameOptions.java new file mode 100644 index 000000000..47546b10c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinGameOptions.java @@ -0,0 +1,34 @@ +package me.jellysquid.mods.sodium.mixin.features.options; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import net.minecraft.client.option.CloudRenderMode; +import net.minecraft.client.option.GameOptions; +import net.minecraft.client.option.GraphicsMode; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(GameOptions.class) +public class MixinGameOptions { + @Shadow + public int viewDistance; + + @Shadow + public GraphicsMode graphicsMode; + + /** + * @author JellySquid + * @reason Make the cloud render mode user-configurable + */ + @Overwrite + public CloudRenderMode getCloudRenderMode() { + SodiumGameOptions options = SodiumClientMod.options(); + + if (this.viewDistance < 4 || !options.quality.enableClouds) { + return CloudRenderMode.OFF; + } + + return options.quality.cloudQuality.isFancy(this.graphicsMode) ? CloudRenderMode.FANCY : CloudRenderMode.FAST; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinInGameHud.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinInGameHud.java new file mode 100644 index 000000000..688eebf1c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinInGameHud.java @@ -0,0 +1,15 @@ +package me.jellysquid.mods.sodium.mixin.features.options; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraftforge.client.gui.ForgeIngameGui; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ForgeIngameGui.class) +public class MixinInGameHud { + @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;isFancyGraphicsOrBetter()Z")) + private boolean redirectFancyGraphicsVignette() { + return SodiumClientMod.options().quality.enableVignette; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinMinecraftClient.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinMinecraftClient.java new file mode 100644 index 000000000..54e569d2b --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinMinecraftClient.java @@ -0,0 +1,19 @@ +package me.jellysquid.mods.sodium.mixin.features.options; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import net.minecraft.client.MinecraftClient; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(MinecraftClient.class) +public class MixinMinecraftClient { + /** + * @author JellySquid + * @reason Make ambient occlusion user configurable + */ + @Overwrite + public static boolean isAmbientOcclusionEnabled() { + return SodiumClientMod.options().quality.smoothLighting != SodiumGameOptions.LightingQuality.OFF; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinOptionsScreen.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinOptionsScreen.java new file mode 100644 index 000000000..5a2916e0c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinOptionsScreen.java @@ -0,0 +1,27 @@ +package me.jellysquid.mods.sodium.mixin.features.options; + +import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.option.OptionsScreen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Dynamic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(OptionsScreen.class) +public class MixinOptionsScreen extends Screen { + protected MixinOptionsScreen(Text title) { + super(title); + } + + @Dynamic + @Inject(method = "func_213059_g(Lnet/minecraft/client/gui/widget/ButtonWidget;)V", at = @At("HEAD"), cancellable = true) + private void open(ButtonWidget widget, CallbackInfo ci) { + this.client.openScreen(new SodiumOptionsGUI(this)); + + ci.cancel(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinWorldRenderer.java new file mode 100644 index 000000000..9b10b1ff5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinWorldRenderer.java @@ -0,0 +1,16 @@ +package me.jellysquid.mods.sodium.mixin.features.options; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.WorldRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(WorldRenderer.class) +public class MixinWorldRenderer { + @Redirect(method = "renderWeather", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;isFancyGraphicsOrBetter()Z")) + private boolean redirectGetFancyWeather() { + return SodiumClientMod.options().quality.weatherQuality.isFancy(MinecraftClient.getInstance().options.graphicsMode); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/particle/fast_render/MixinBillboardParticle.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/particle/fast_render/MixinBillboardParticle.java new file mode 100644 index 000000000..53cdd0479 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/particle/fast_render/MixinBillboardParticle.java @@ -0,0 +1,120 @@ +package me.jellysquid.mods.sodium.mixin.features.particle.fast_render; + +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; +import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.ParticleVertexSink; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import net.minecraft.client.particle.BillboardParticle; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Quaternion; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(BillboardParticle.class) +public abstract class MixinBillboardParticle extends Particle { + @Shadow + public abstract float getSize(float tickDelta); + + @Shadow + protected abstract float getMinU(); + + @Shadow + protected abstract float getMaxU(); + + @Shadow + protected abstract float getMinV(); + + @Shadow + protected abstract float getMaxV(); + + protected MixinBillboardParticle(ClientWorld world, double x, double y, double z) { + super(world, x, y, z); + } + + /** + * @reason Optimize function + * @author JellySquid + */ + @Overwrite + public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) { + Vec3d vec3d = camera.getPos(); + + float x = (float) (MathHelper.lerp(tickDelta, this.prevPosX, this.x) - vec3d.getX()); + float y = (float) (MathHelper.lerp(tickDelta, this.prevPosY, this.y) - vec3d.getY()); + float z = (float) (MathHelper.lerp(tickDelta, this.prevPosZ, this.z) - vec3d.getZ()); + + Quaternion quaternion; + + if (this.angle == 0.0F) { + quaternion = camera.getRotation(); + } else { + float angle = MathHelper.lerp(tickDelta, this.prevAngle, this.angle); + + quaternion = new Quaternion(camera.getRotation()); + quaternion.hamiltonProduct(Vec3f.POSITIVE_Z.getRadialQuaternion(angle)); + } + + float size = this.getSize(tickDelta); + int light = this.getBrightness(tickDelta); + + float minU = this.getMinU(); + float maxU = this.getMaxU(); + float minV = this.getMinV(); + float maxV = this.getMaxV(); + + int color = ColorABGR.pack(this.colorRed, this.colorGreen, this.colorBlue, this.colorAlpha); + + ParticleVertexSink drain = VertexDrain.of(vertexConsumer) + .createSink(VanillaVertexTypes.PARTICLES); + + addVertex(drain, quaternion,-1.0F, -1.0F, x, y, z, maxU, maxV, color, light, size); + addVertex(drain, quaternion,-1.0F, 1.0F, x, y, z, maxU, minV, color, light, size); + addVertex(drain, quaternion,1.0F, 1.0F, x, y, z, minU, minV, color, light, size); + addVertex(drain, quaternion,1.0F, -1.0F, x, y, z, minU, maxV, color, light, size); + + drain.flush(); + } + + private static void addVertex(ParticleVertexSink drain, Quaternion rotation, + float x, float y, float posX, float posY, float posZ, float u, float v, int color, int light, float size) { + // Quaternion q0 = new Quaternion(rotation); + float q0x = rotation.getX(); + float q0y = rotation.getY(); + float q0z = rotation.getZ(); + float q0w = rotation.getW(); + + // q0.hamiltonProduct(x, y, 0.0f, 0.0f) + float q1x = (q0w * x) - (q0z * y); + float q1y = (q0w * y) + (q0z * x); + float q1w = (q0x * y) - (q0y * x); + float q1z = -(q0x * x) - (q0y * y); + + // Quaternion q2 = new Quaternion(rotation); + // q2.conjugate() + float q2x = -q0x; + float q2y = -q0y; + float q2z = -q0z; + float q2w = q0w; + + // q2.hamiltonProduct(q1) + float q3x = q1z * q2x + q1x * q2w + q1y * q2z - q1w * q2y; + float q3y = q1z * q2y - q1x * q2z + q1y * q2w + q1w * q2x; + float q3z = q1z * q2z + q1x * q2y - q1y * q2x + q1w * q2w; + + // Vector3f f = new Vector3f(q2.getX(), q2.getY(), q2.getZ()) + // f.multiply(size) + // f.add(pos) + float fx = (q3x * size) + posX; + float fy = (q3y * size) + posY; + float fz = (q3z * size) + posZ; + + drain.writeParticle(fx, fy, fz, u, v, color, light); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/MixinTexturedRenderLayers.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/MixinTexturedRenderLayers.java new file mode 100644 index 000000000..be7525309 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/MixinTexturedRenderLayers.java @@ -0,0 +1,34 @@ +package me.jellysquid.mods.sodium.mixin.features.render_layer; + +import net.minecraft.client.render.TexturedRenderLayers; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.SignType; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Map; + +@Mixin(TexturedRenderLayers.class) +public class MixinTexturedRenderLayers { + @Shadow + @Final + public static Map WOOD_TYPE_TEXTURES; + + // Instantiating a SpriteIdentifier every time a sign tries to grab a texture identifier causes a significant + // performance impact as no RenderLayer will ever be cached for the sprite. Minecraft already maintains a + // SignType -> SpriteIdentifier cache but for some reason doesn't use it. + @Inject(method = "createSignTextureId", at = @At("HEAD"), cancellable = true) + private static void preGetSignTextureId(SignType type, CallbackInfoReturnable ci) { + if (WOOD_TYPE_TEXTURES != null) { + SpriteIdentifier sprite = WOOD_TYPE_TEXTURES.get(type); + + if (type != null) { + ci.setReturnValue(sprite); + } + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinLeavesBlock.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinLeavesBlock.java new file mode 100644 index 000000000..31fecbe38 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinLeavesBlock.java @@ -0,0 +1,27 @@ +package me.jellysquid.mods.sodium.mixin.features.render_layer.leaves; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.LeavesBlock; +import net.minecraft.block.Material; +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.math.Direction; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(LeavesBlock.class) +public class MixinLeavesBlock extends Block { + public MixinLeavesBlock() { + super(Settings.of(Material.AIR)); + throw new AssertionError("Mixin constructor called!"); + } + + @Override + public boolean isSideInvisible(BlockState state, BlockState stateFrom, Direction direction) { + if (SodiumClientMod.options().quality.leavesQuality.isFancy(MinecraftClient.getInstance().options.graphicsMode)) { + return super.isSideInvisible(state, stateFrom, direction); + } else { + return stateFrom.getBlock() instanceof LeavesBlock || super.isSideInvisible(state, stateFrom, direction); + } + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinRenderLayers.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinRenderLayers.java new file mode 100644 index 000000000..f318c4a90 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinRenderLayers.java @@ -0,0 +1,54 @@ +package me.jellysquid.mods.sodium.mixin.features.render_layer.leaves; + +import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.block.Block; +import net.minecraft.client.option.GraphicsMode; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.RenderLayers; +import net.minecraft.fluid.Fluid; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Map; + +@Mixin(RenderLayers.class) +public class MixinRenderLayers { + @Mutable + @Shadow + @Final + private static Map BLOCKS; + + @Mutable + @Shadow + @Final + private static Map FLUIDS; + + static { + // Replace the backing collection types with something a bit faster, since this is a hot spot in chunk rendering. + BLOCKS = new Reference2ReferenceOpenHashMap<>(BLOCKS); + FLUIDS = new Reference2ReferenceOpenHashMap<>(FLUIDS); + } + + @Unique + private static boolean embeddium$leavesFancy; + + @Redirect( + method = { "getBlockLayer", "getMovingBlockLayer", "canRenderInLayer(Lnet/minecraft/block/BlockState;Lnet/minecraft/client/render/RenderLayer;)Z" }, + at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/RenderLayers;fancyGraphicsOrBetter:Z")) + private static boolean redirectLeavesShouldBeFancy() { + return embeddium$leavesFancy; + } + + @Inject(method = "setFancyGraphicsOrBetter", at = @At("RETURN")) + private static void onSetFancyGraphicsOrBetter(boolean fancyGraphicsOrBetter, CallbackInfo ci) { + embeddium$leavesFancy = SodiumClientMod.options().quality.leavesQuality.isFancy(fancyGraphicsOrBetter ? GraphicsMode.FANCY : GraphicsMode.FAST); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/sky/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/sky/MixinWorldRenderer.java new file mode 100644 index 000000000..d362a20d2 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/sky/MixinWorldRenderer.java @@ -0,0 +1,57 @@ +package me.jellysquid.mods.sodium.mixin.features.sky; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.BackgroundRenderer; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(WorldRenderer.class) +public class MixinWorldRenderer { + @Shadow + @Final + private MinecraftClient client; + + /** + *

Prevents the sky layer from rendering when the fog distance is reduced + * from the default. This helps prevent situations where the sky can be seen + * through chunks culled by fog occlusion. This also fixes the vanilla issue + * MC-152504 since it + * is also caused by being able to see the sky through invisible chunks.

+ * + *

However, this fix comes with some caveats. When underwater, it becomes + * impossible to see the sun, stars, and moon since the sky is not rendered. + * While this does not exactly match the vanilla game, it is consistent with + * what Bedrock Edition does, so it can be considered vanilla-style. This is + * also more "correct" in the sense that underwater fog is applied to chunks + * outside of water, so the fog should also be covering the sun and sky.

+ * + *

When updating Sodium to new releases of the game, please check for new + * ways the fog can be reduced in {@link BackgroundRenderer#applyFog()}.

+ */ + @Inject(method = "renderSky", at = @At("HEAD"), cancellable = true) + private void preRenderSky(MatrixStack matrices, float tickDelta, CallbackInfo callbackInfo) { + Camera camera = this.client.gameRenderer.getCamera(); + Vec3d cameraPosition = camera.getPos(); + Entity cameraEntity = camera.getFocusedEntity(); + + boolean hasBlindness = cameraEntity instanceof LivingEntity && ((LivingEntity) cameraEntity).hasStatusEffect(StatusEffects.BLINDNESS); + boolean useThickFog = this.client.world.getSkyProperties().useThickFog(MathHelper.floor(cameraPosition.getX()), + MathHelper.floor(cameraPosition.getY())) || this.client.inGameHud.getBossBarHud().shouldThickenFog(); + + if (hasBlindness || useThickFog) { + callbackInfo.cancel(); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSprite.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSprite.java new file mode 100644 index 000000000..945c8098e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSprite.java @@ -0,0 +1,84 @@ +package me.jellysquid.mods.sodium.mixin.features.texture_tracking; + +import com.mojang.blaze3d.systems.RenderSystem; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.render.texture.SpriteExtended; +import net.minecraft.client.resource.metadata.AnimationResourceMetadata; +import net.minecraft.client.texture.Sprite; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(Sprite.class) +public abstract class MixinSprite implements SpriteExtended { + private boolean forceNextUpdate; + + @Shadow + private int frameTicks; + + @Shadow + @Final + private AnimationResourceMetadata animationMetadata; + + @Shadow + private int frameIndex; + + @Shadow + public abstract int getFrameCount(); + + @Shadow + protected abstract void upload(int int_1); + + @Shadow + @Final + private Sprite.Interpolation interpolation; + + /** + * @author JellySquid + * @reason Allow conditional texture updating + */ + @Overwrite + public void tickAnimation() { + this.frameTicks++; + + boolean onDemand = SodiumClientMod.options().advanced.animateOnlyVisibleTextures; + + if (!onDemand || this.forceNextUpdate) { + this.uploadTexture(); + } + } + + private void uploadTexture() { + if (this.frameTicks >= this.animationMetadata.getFrameTime(this.frameIndex)) { + int prevFrameIndex = this.animationMetadata.getFrameIndex(this.frameIndex); + int frameCount = this.animationMetadata.getFrameCount() == 0 ? this.getFrameCount() : this.animationMetadata.getFrameCount(); + + this.frameIndex = (this.frameIndex + 1) % frameCount; + this.frameTicks = 0; + + int frameIndex = this.animationMetadata.getFrameIndex(this.frameIndex); + + if (prevFrameIndex != frameIndex && frameIndex >= 0 && frameIndex < this.getFrameCount()) { + this.upload(frameIndex); + } + } else if (this.interpolation != null) { + if (!RenderSystem.isOnRenderThread()) { + RenderSystem.recordRenderCall(this::updateInterpolatedTexture); + } else { + this.updateInterpolatedTexture(); + } + } + + this.forceNextUpdate = false; + } + + @Override + public void markActive() { + this.forceNextUpdate = true; + } + + private void updateInterpolatedTexture() { + this.interpolation.apply(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteAtlasTexture.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteAtlasTexture.java new file mode 100644 index 000000000..954ccd4f4 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteAtlasTexture.java @@ -0,0 +1,21 @@ +package me.jellysquid.mods.sodium.mixin.features.texture_tracking; + +import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteAtlasTexture; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(SpriteAtlasTexture.class) +public class MixinSpriteAtlasTexture { + @Inject(method = "getSprite", at = @At("RETURN")) + private void preReturnSprite(CallbackInfoReturnable cir) { + Sprite sprite = cir.getReturnValue(); + + if (sprite != null) { + SpriteUtil.markSpriteActive(sprite); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteBillboardParticle.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteBillboardParticle.java new file mode 100644 index 000000000..28849fb25 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteBillboardParticle.java @@ -0,0 +1,40 @@ +package me.jellysquid.mods.sodium.mixin.features.texture_tracking; + +import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import net.minecraft.client.particle.BillboardParticle; +import net.minecraft.client.particle.SpriteBillboardParticle; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.world.ClientWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(SpriteBillboardParticle.class) +public abstract class MixinSpriteBillboardParticle extends BillboardParticle { + @Shadow + protected Sprite sprite; + + private boolean shouldTickSprite; + + protected MixinSpriteBillboardParticle(ClientWorld world, double x, double y, double z) { + super(world, x, y, z); + } + + @Inject(method = "setSprite(Lnet/minecraft/client/texture/Sprite;)V", at = @At("RETURN")) + private void afterSetSprite(Sprite sprite, CallbackInfo ci) { + this.shouldTickSprite = sprite != null && sprite.isAnimated(); + } + + @Override + public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) { + if (this.shouldTickSprite) { + SpriteUtil.markSpriteActive(this.sprite); + } + + super.buildGeometry(vertexConsumer, camera, tickDelta); + } +} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/world_ticking/MixinClientWorld.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/world_ticking/MixinClientWorld.java new file mode 100644 index 000000000..cd8f299ba --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/world_ticking/MixinClientWorld.java @@ -0,0 +1,111 @@ +package me.jellysquid.mods.sodium.mixin.features.world_ticking; + +import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.fluid.FluidState; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.profiler.Profiler; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.MutableWorldProperties; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeParticleConfig; +import net.minecraft.world.dimension.DimensionType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Random; +import java.util.function.Supplier; + +@Mixin(ClientWorld.class) +public abstract class MixinClientWorld extends World { + @Shadow + protected abstract void addParticle(BlockPos pos, BlockState state, ParticleEffect parameters, boolean bl); + + protected MixinClientWorld(MutableWorldProperties mutableWorldProperties, RegistryKey registryKey, + DimensionType dimensionType, Supplier profiler, boolean bl, boolean bl2, long l) { + super(mutableWorldProperties, registryKey, dimensionType, profiler, bl, bl2, l); + } + + @Redirect(method = "doRandomBlockDisplayTicks", at = @At(value = "NEW", target = "java/util/Random")) + private Random redirectRandomTickRandom() { + return new XoRoShiRoRandom(); + } + + /** + * @reason Avoid allocations, branch code out, early-skip some code + * @author JellySquid + */ + @Overwrite + public void randomBlockDisplayTick(int xCenter, int yCenter, int zCenter, int radius, Random random, boolean spawnBarrierParticles, BlockPos.Mutable pos) { + int x = xCenter + (random.nextInt(radius) - random.nextInt(radius)); + int y = yCenter + (random.nextInt(radius) - random.nextInt(radius)); + int z = zCenter + (random.nextInt(radius) - random.nextInt(radius)); + + pos.set(x, y, z); + + BlockState blockState = this.getBlockState(pos); + + if (!blockState.isAir()) { + this.performBlockDisplayTick(blockState, pos, random, spawnBarrierParticles); + } + + if (!blockState.isFullCube(this, pos)) { + this.performBiomeParticleDisplayTick(pos, random); + } + + FluidState fluidState = blockState.getFluidState(); + + if (!fluidState.isEmpty()) { + this.performFluidDisplayTick(blockState, fluidState, pos, random); + } + } + + private void performBlockDisplayTick(BlockState blockState, BlockPos pos, Random random, boolean spawnBarrierParticles) { + blockState.getBlock().randomDisplayTick(blockState, this, pos, random); + + if (spawnBarrierParticles && blockState.isOf(Blocks.BARRIER)) { + this.performBarrierDisplayTick(pos); + } + } + + private void performBarrierDisplayTick(BlockPos pos) { + this.addParticle(ParticleTypes.BARRIER, pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, + 0.0D, 0.0D, 0.0D); + } + + private void performBiomeParticleDisplayTick(BlockPos pos, Random random) { + BiomeParticleConfig config = this.getBiome(pos) + .getParticleConfig() + .orElse(null); + + if (config != null && config.shouldAddParticle(random)) { + this.addParticle(config.getParticle(), + pos.getX() + random.nextDouble(), + pos.getY() + random.nextDouble(), + pos.getZ() + random.nextDouble(), + 0.0D, 0.0D, 0.0D); + } + } + + private void performFluidDisplayTick(BlockState blockState, FluidState fluidState, BlockPos pos, Random random) { + fluidState.randomDisplayTick(this, pos, random); + + ParticleEffect particleEffect = fluidState.getParticle(); + + if (particleEffect != null && random.nextInt(10) == 0) { + boolean solid = blockState.isSideSolidFullSquare(this, pos, Direction.DOWN); + + // FIXME: don't allocate here + BlockPos blockPos = pos.down(); + this.addParticle(blockPos, this.getBlockState(blockPos), particleEffect, solid); + } + } +} diff --git a/src/main/resources/META-INF/sodium_at.cfg b/src/main/resources/META-INF/sodium_at.cfg new file mode 100644 index 000000000..2a6b57017 --- /dev/null +++ b/src/main/resources/META-INF/sodium_at.cfg @@ -0,0 +1,18 @@ +public net.minecraft.client.renderer.model.ModelRenderer$PositionTextureVertex +public net.minecraft.client.renderer.model.ModelRenderer$TexturedQuad +public net.minecraft.client.renderer.texture.TextureAtlasSprite$InterpolationData + +public net.minecraft.client.renderer.texture.TextureAtlasSprite$InterpolationData func_229257_a_()V # uploadInterpolatedFrame +public net.minecraft.client.renderer.culling.ClippingHelper func_228953_a_(DDDDDD)Z # cubeInFrustum + +public net.minecraft.state.StateHolder field_235892_c_ # owner +public net.minecraft.client.renderer.model.WeightedBakedModel$WeightedModel +public net.minecraft.client.renderer.model.WeightedBakedModel$WeightedModel field_185281_b # model + +public com.mojang.blaze3d.platform.GlStateManager$FogState +public com.mojang.blaze3d.platform.GlStateManager field_225663_h_ # FOG +public net.minecraft.client.renderer.FogRenderer field_205093_c # fogRed +public net.minecraft.client.renderer.FogRenderer field_205094_d # fogGreen +public net.minecraft.client.renderer.FogRenderer field_205095_e # fogBlue +public com.mojang.blaze3d.platform.GlStateManager$BooleanState +public com.mojang.blaze3d.platform.GlStateManager$BooleanState field_179201_b # enabled \ No newline at end of file diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json new file mode 100644 index 000000000..7b89303f8 --- /dev/null +++ b/src/main/resources/assets/sodium/lang/en_us.json @@ -0,0 +1,82 @@ +{ + "sodium.option_impact.low": "Low", + "sodium.option_impact.medium": "Medium", + "sodium.option_impact.high": "High", + "sodium.option_impact.extreme": "Extreme", + "sodium.option_impact.varies": "Varies", + "sodium.options.pages.quality": "Quality", + "sodium.options.pages.performance": "Performance", + "sodium.options.pages.advanced": "Advanced", + "sodium.options.view_distance.tooltip": "The render distance controls how far away terrain will be rendered. Shorter distances mean that less terrain will be rendered, improving frame rates.", + "sodium.options.simulation_distance.tooltip": "The simulation distance controls how far away terrain and entities will be loaded and ticked. Shorter distances can reduce the internal server's load and may improve frame rates.", + "sodium.options.brightness.tooltip": "Controls the brightness (gamma) of the game.", + "sodium.options.clouds.name": "Clouds", + "sodium.options.clouds.tooltip": "Controls whether or not clouds will be visible.", + "sodium.options.gui_scale.tooltip": "Sets the maximum scale factor to be used for the user interface. If 'auto' is used, then the largest scale factor will always be used.", + "sodium.options.fullscreen.tooltip": "If enabled, the game will display in full-screen (if supported).", + "sodium.options.v_sync.tooltip": "If enabled, the game's frame rate will be synchronized to the monitor's refresh rate, making for a generally smoother experience at the expense of overall input latency. This setting might reduce performance if your system is too slow.", + "sodium.options.fps_limit.tooltip": "Limits the maximum number of frames per second. This can help reduce battery usage and general system load when multi-tasking. If V-Sync is enabled, this option will be ignored unless it is lower than your display's refresh rate.", + "sodium.options.view_bobbing.tooltip": "If enabled, the player's view will sway and bob when moving around. Players who experience motion sickness while playing can benefit from disabling this.", + "sodium.options.attack_indicator.tooltip": "Controls where the Attack Indicator is displayed on screen.", + "sodium.options.autosave_indicator.tooltip": "If enabled, an indicator will be shown when the game is saving the world to disk.", + "sodium.options.graphics_quality.tooltip": "The default graphics quality controls some legacy options and is necessary for mod compatibility. If the options below are left to \"Default\", they will use this setting.", + "sodium.options.clouds_quality.tooltip": "Controls the quality of rendered clouds in the sky.", + "sodium.options.weather_quality.tooltip": "Controls the quality of rain and snow effects.", + "sodium.options.leaves_quality.name": "Leaves Quality", + "sodium.options.leaves_quality.tooltip": "Controls the quality of leaves.", + "sodium.options.particle_quality.name": "Particle Quality", + "sodium.options.particle_quality.tooltip": "Controls the maximum number of particles which can be present on screen at any one time.", + "sodium.options.smooth_lighting.tooltip": "Controls whether blocks will be smoothly lit and shaded. This slightly increases the amount of time needed to re-build a chunk, but doesn't affect frame rates.", + "sodium.options.biome_blend.value": "%s block(s)", + "sodium.options.biome_blend.tooltip": "Controls the range which biomes will be sampled for block colorization. Higher values greatly increase the amount of time it takes to build chunks for diminishing improvements in quality.", + "sodium.options.entity_distance.tooltip": "Controls how far away entities can render from the player. Higher values increase the render distance at the expense of frame rates.", + "sodium.options.entity_shadows.tooltip": "If enabled, basic shadows will be rendered beneath mobs and other entities.", + "sodium.options.vignette.name": "Vignette", + "sodium.options.vignette.tooltip": "If enabled, a vignette effect will be rendered on the player's view. This is very unlikely to make a difference to frame rates unless you are fill-rate limited.", + "sodium.options.mipmap_levels.tooltip": "Controls the number of mipmaps which will be used for block model textures. Higher values provide better rendering of blocks in the distance, but may adversely affect performance with many animated textures.", + "sodium.options.use_chunk_multidraw.name": "Use Chunk Multi-Draw", + "sodium.options.use_chunk_multidraw.tooltip": "Multi-draw allows multiple chunks to be rendered with fewer draw calls, greatly reducing CPU overhead when rendering the world while also potentially allowing for more efficient GPU utilization. This optimization may cause issues with some graphics drivers, so you should try disabling it if you are experiencing glitches.", + "sodium.options.use_vertex_objects.name": "Use Vertex Array Objects", + "sodium.options.use_vertex_objects.tooltip": "Helps to improve performance by moving information about how vertex data should be rendered into the driver, allowing it to better optimize for repeated rendering of the same objects. There is generally no reason to disable this unless you're using incompatible mods.", + "sodium.options.use_block_face_culling.name": "Use Block Face Culling", + "sodium.options.use_block_face_culling.tooltip": "If enabled, only the sides of blocks which are facing the camera will be submitted for rendering. This can eliminate a large number of block faces very early in the rendering process, saving memory bandwidth and time on the GPU. Some resource packs may have issues with this option, so try disabling it if you're seeing holes in blocks.", + "sodium.options.use_compact_vertex_format.name": "Use Compact Vertex Format", + "sodium.options.use_compact_vertex_format.tooltip": "If enabled, a more compact vertex format will be used for rendering chunks. This can reduce graphics memory usage and bandwidth requirements significantly, especially for integrated graphics cards, but can cause z-fighting with some resource packs due to how it reduces the precision of position and texture coordinate attributes.", + "sodium.options.use_fog_occlusion.name": "Use Fog Occlusion", + "sodium.options.use_fog_occlusion.tooltip": "If enabled, chunks which are determined to be fully hidden by fog effects will not be rendered, helping to improve performance. The improvement can be more dramatic when fog effects are heavier (such as while underwater), but it may cause undesirable visual artifacts between the sky and fog in some scenarios.", + "sodium.options.use_entity_culling.name": "Use Entity Culling", + "sodium.options.use_entity_culling.tooltip": "If enabled, entities determined not to be in any visible chunks will be skipped during rendering. This can help improve performance by avoiding the rendering of entities located underground or behind walls.", + "sodium.options.use_particle_culling.name": "Use Particle Culling", + "sodium.options.use_particle_culling.tooltip": "If enabled, only particles which are determined to be visible will be rendered. This can provide a significant improvement to frame rates when many particles are nearby.", + "sodium.options.animate_only_visible_textures.name": "Animate Only Visible Textures", + "sodium.options.animate_only_visible_textures.tooltip": "If enabled, only animated textures determined to be visible will be updated. This can provide a significant boost to frame rates on some hardware, especially with heavier resource packs. If you experience issues with some textures not being animated, try disabling this option.", + "sodium.options.translucency_sorting.name": "Translucency Sorting", + "sodium.options.translucency_sorting.tooltip": "If enabled, translucent blocks will be sorted correctly from back to front to provide better rendering, especially when multiple translucent blocks are in view and layered. This is a bit of an expensive operation.", + "sodium.options.cpu_render_ahead_limit.name": "CPU Render-Ahead Limit", + "sodium.options.cpu_render_ahead_limit.tooltip": "Specifies the maximum number of frames the CPU can be waiting on the GPU to finish rendering. Very low or high values may create frame rate instability.", + "sodium.options.cpu_render_ahead_limit.value": "%s frame(s)", + "sodium.options.allow_direct_memory_access.name": "Allow Direct Memory Access", + "sodium.options.allow_direct_memory_access.tooltip": "If enabled, some critical code paths will be allowed to use direct memory access for performance. This often greatly reduces CPU overhead for chunk and entity rendering, but can make it harder to diagnose some bugs and crashes. You should only disable this if you've been asked to or otherwise know what you're doing.", + "sodium.options.ignore_driver_blacklist.name": "Ignore Driver Blacklist", + "sodium.options.ignore_driver_blacklist.tooltip": "If enabled, known incompatibilities with your hardware/driver configuration will be ignored, allowing you to enable options that may cause issues with your game. You should generally not touch this option unless you know exactly what you are doing. After changing this option, you must save, close, and then re-open the settings screen.", + "sodium.options.enable_memory_tracing.name": "Enable Memory Tracing", + "sodium.options.enable_memory_tracing.tooltip": "Debugging feature. If enabled, stack traces will be collected alongside memory allocations to help improve diagnostic information when memory leaks are detected.", + "sodium.options.performance_impact_string": "Performance Impact: %s", + "sodium.options.use_persistent_mapping.name": "Use Persistent Mapping", + "sodium.options.use_persistent_mapping.tooltip": "If enabled, a small amount of memory will be persistently mapped for speeding up chunk updates and entity rendering.\n\nRequires OpenGL 4.4 or ARB_buffer_storage.", + "sodium.options.chunk_memory_allocator.name": "Chunk Memory Allocator", + "sodium.options.chunk_memory_allocator.tooltip": "Selects the memory allocator that will be used for chunk rendering.\n- ASYNC: Fastest option, works well with most modern graphics drivers.\n- SWAP: Fallback option for older graphics drivers. May increase memory usage significantly.", + "sodium.options.chunk_memory_allocator.async": "Async", + "sodium.options.chunk_memory_allocator.swap": "Swap", + "sodium.options.chunk_update_threads.name": "Chunk Update Threads", + "sodium.options.chunk_update_threads.tooltip": "Specifies the number of threads to use for chunk building. Using more threads can speed up chunk loading and update speed, but may negatively impact frame times.", + "sodium.options.always_defer_chunk_updates.name": "Always Defer Chunk Updates", + "sodium.options.always_defer_chunk_updates.tooltip": "If enabled, rendering will never wait for chunk updates to finish, even if they are important. This can greatly improve frame rates in some scenarios, but it may create significant visual lag in the world.", + "sodium.options.use_no_error_context.name": "Use No Error Context", + "sodium.options.use_no_error_context.tooltip": "If enabled, the OpenGL context will be created with error checking disabled. This may slightly improve performance, but it also increases the risk that the game will crash instead of gracefully handling OpenGL errors. You should disable this option if you are experiencing sudden unexplained crashes.", + "sodium.options.threads.value": "%s thread(s)", + "sodium.options.default": "Default", + "sodium.options.buttons.undo": "Undo", + "sodium.options.buttons.apply": "Apply", + "sodium.options.buttons.donate": "Buy coffee for JellySquid!" +} \ No newline at end of file diff --git a/src/main/resources/assets/sodium/lang/es_ar.json b/src/main/resources/assets/sodium/lang/es_ar.json new file mode 100644 index 000000000..a6847a8a5 --- /dev/null +++ b/src/main/resources/assets/sodium/lang/es_ar.json @@ -0,0 +1,66 @@ +{ + "sodium.option_impact.low": "Bajo", + "sodium.option_impact.medium": "Medio", + "sodium.option_impact.high": "Alto", + "sodium.option_impact.extreme": "Extremo", + "sodium.option_impact.varies": "Varía", + "sodium.options.pages.quality": "Calidad", + "sodium.options.pages.performance": "Rendimiento", + "sodium.options.pages.advanced": "Avanzado", + "sodium.options.view_distance.tooltip": "La distancia de renderizado controla la distancia a la que se renderizará el terreno. Las distancias más cortas significan que se renderizará menos terreno, lo que mejora la velocidad de fotogramas.", + "sodium.options.simulation_distance.tooltip": "La distancia de simulación controla la distancia a la que se cargarán y marcarán el terreno y las entidades. Las distancias más cortas pueden reducir la carga del servidor interno y pueden mejorar la velocidad de fotogramas.", + "sodium.options.brightness.tooltip": "Controla el brillo (gamma) del juego.", + "sodium.options.gui_scale.tooltip": "Establece el factor de escala máximo que se utilizará para la interfaz de usuario. Si se utiliza 'auto', siempre se utilizará el factor de escala más grande.", + "sodium.options.fullscreen.tooltip": "Si se activa, el juego se mostrará en pantalla completa (si es compatible).", + "sodium.options.v_sync.tooltip": "Si se activa, la velocidad de fotogramas del juego se sincronizará con la frecuencia de refresco del monitor, lo que hará que la experiencia sea más fluida a expensas de la latencia de entrada general. Este ajuste puede reducir el rendimiento si tu sistema es demasiado lento.", + "sodium.options.fps_limit.tooltip": "Limita el número máximo de fotogramas por segundo. Esto puede ayudar a reducir el uso de la batería y la carga general del sistema cuando se realiza una multitarea. Si V-Sync está activado, esta opción se ignorará a menos que sea inferior a la frecuencia de refresco de tu pantalla.", + "sodium.options.view_bobbing.tooltip": "Si está activada, la vista del jugador se balanceará y oscilará cuando se mueva. Los jugadores que experimenten mareos al jugar pueden beneficiarse de desactivar esta opción.", + "sodium.options.attack_indicator.tooltip": "Controla dónde se muestra el indicador de ataque en la pantalla.", + "sodium.options.autosave_indicator.tooltip": "Si se activa, se mostrará un indicador cuando el juego esté guardando el mundo en el disco.", + "sodium.options.graphics_quality.tooltip": "La calidad gráfica por defecto controla algunas opciones heredadas y es necesaria para la compatibilidad de los mods. Si las opciones de abajo se dejan en \"Default\", utilizarán esta configuración.", + "sodium.options.clouds_quality.tooltip": "Controla la calidad de las nubes renderizadas en el cielo.", + "sodium.options.weather_quality.tooltip": "Controla la calidad de los efectos de lluvia y nieve.", + "sodium.options.leaves_quality.name": "Calidad de las Hojas", + "sodium.options.leaves_quality.tooltip": "Controla la calidad de las hojas.", + "sodium.options.particle_quality.name": "Calidad de las Partículas", + "sodium.options.particle_quality.tooltip": "Controla el número máximo de partículas que pueden estar presentes en la pantalla en un momento dado.", + "sodium.options.smooth_lighting.tooltip": "Controla si los bloques serán iluminados y sombreados suavemente. Esto aumenta ligeramente el tiempo necesario para reconstruir un trozo, pero no afecta a la velocidad de fotogramas.", + "sodium.options.biome_blend.value": "%s bloque(s)", + "sodium.options.biome_blend.tooltip": "Controla el rango que los biomas serán muestreados para la coloración de los bloques. Los valores más altos aumentan en gran medida la cantidad de tiempo que se necesita para construir trozos para disminuir las mejoras en la calidad.", + "sodium.options.entity_distance.tooltip": "Controla la distancia a la que se pueden renderizar las entidades desde el jugador. Los valores más altos aumentan la distancia de renderizado a expensas de la velocidad de fotogramas.", + "sodium.options.entity_shadows.tooltip": "Si está activada, las sombras básicas se mostrarán debajo de los monstruos y otras entidades.", + "sodium.options.vignette.name": "Viñeta", + "sodium.options.vignette.tooltip": "Si se habilita, se renderizará un efecto de viñeta en la vista del jugador. Es muy poco probable que esto suponga una diferencia en la tasa de fotogramas, a menos que la tasa de llenado sea limitada.", + "sodium.options.mipmap_levels.tooltip": "Controla el número de mipmaps que se utilizarán para las texturas del modelo de bloques. Los valores más altos proporcionan un mejor renderizado de los bloques en la distancia, pero pueden afectar negativamente al rendimiento con muchas texturas animadas.", + "sodium.options.use_block_face_culling.name": "Usar eliminación selectiva de caras de bloques", + "sodium.options.use_block_face_culling.tooltip": "Si se activa, sólo se enviarán a renderizar las caras de los bloques que estén orientadas hacia la cámara. Esto puede eliminar un gran número de caras de bloques muy pronto en el proceso de renderizado, ahorrando ancho de banda de memoria y tiempo en la GPU. Algunos paquetes de recursos pueden tener problemas con esta opción, así que prueba a desactivarla si ves agujeros en los bloques.", + "sodium.options.use_fog_occlusion.name": "Usar Oclusión de Niebla", + "sodium.options.use_fog_occlusion.tooltip": "Si se activa, los trozos que se determinan como totalmente ocultos por los efectos de niebla no se renderizarán, lo que ayuda a mejorar el rendimiento. La mejora puede ser más dramática cuando los efectos de niebla son más pesados (como cuando se está bajo el agua), pero puede causar artefactos visuales indeseables entre el cielo y la niebla en algunos escenarios.", + "sodium.options.use_entity_culling.name": "Usar Eliminación de Entidades", + "sodium.options.use_entity_culling.tooltip": "Si se activa, las entidades que se determinen que no están en ningún trozo visible se omitirán durante el renderizado. Esto puede ayudar a mejorar el rendimiento al evitar la renderización de las entidades situadas bajo tierra o detrás de las paredes.", + "sodium.options.use_particle_culling.name": "Utilice la Eliminación de Partículas", + "sodium.options.use_particle_culling.tooltip": "Si se activa, sólo se renderizarán las partículas que se determinen como visibles. Esto puede proporcionar una mejora significativa en la velocidad de fotogramas cuando hay muchas partículas cerca.", + "sodium.options.animate_only_visible_textures.name": "Animar Sólo las Texturas Visibles", + "sodium.options.animate_only_visible_textures.tooltip": "Si se activa, sólo se actualizarán las texturas animadas que sean visibles. Esto puede proporcionar un aumento significativo de la velocidad de fotogramas en algunos equipos, especialmente con paquetes de recursos más pesados. Si tienes problemas con algunas texturas que no se animan, prueba a desactivar esta opción.", + "sodium.options.cpu_render_ahead_limit.name": "Límite de Procesamiento Anticipado de CPU", + "sodium.options.cpu_render_ahead_limit.tooltip": "Especifica el número máximo de fotogramas que la CPU puede esperar a que la GPU termine de renderizar. Los valores muy bajos o altos pueden crear inestabilidad en la tasa de fotogramas.", + "sodium.options.cpu_render_ahead_limit.value": "%s fotograma(s)", + "sodium.options.allow_direct_memory_access.name": "Permitir Aacceso Directo a la Memoria", + "sodium.options.allow_direct_memory_access.tooltip": "Si se activa, se permitirá que algunas rutas de código críticas utilicen el acceso directo a la memoria para mejorar el rendimiento. Esto suele reducir en gran medida la sobrecarga de la CPU para el renderizado de trozos y entidades, pero puede dificultar el diagnóstico de algunos fallos y caídas. Sólo deberías desactivar esto si te lo han pedido o si sabes lo que estás haciendo.", + "sodium.options.enable_memory_tracing.name": "Habilitar Seguimiento de Memoria", + "sodium.options.enable_memory_tracing.tooltip": "Función de depuración. Si está activada, se recogerán los rastros de pila junto con las asignaciones de memoria para ayudar a mejorar la información de diagnóstico cuando se detecten fugas de memoria.", + "sodium.options.performance_impact_string": "Impacto en el Rendimiento: %s", + "sodium.options.use_persistent_mapping.name": "Utilizar el Mapeo Persistente", + "sodium.options.use_persistent_mapping.tooltip": "Si se activa, una pequeña cantidad de memoria será mapeada de forma persistente para acelerar las actualizaciones de chunk y el renderizado de entidades.\n\nRequiere OpenGL 4.4 o ARB_buffer_storage.", + "sodium.options.chunk_memory_allocator.name": "Asignador de Memoria de Chunks", + "sodium.options.chunk_memory_allocator.tooltip": "Selecciona el asignador de memoria que se utilizará para el renderizado de los trozos.\n- ASYNC: Opción más rápida, funciona bien con la mayoría de los controladores gráficos modernos.\n- SWAP: Opción de reserva para los controladores gráficos más antiguos. Puede aumentar significativamente el uso de la memoria.", + "sodium.options.chunk_memory_allocator.async": "Async", + "sodium.options.chunk_memory_allocator.swap": "Intercambiar", + "sodium.options.chunk_update_threads.name": "Subprocesos de Actualización de Chunks", + "sodium.options.chunk_update_threads.tooltip": "Especifica el número de hilos que se van a utilizar para la construcción de los trozos. El uso de más hilos puede acelerar la carga de trozos y la velocidad de actualización, pero puede afectar negativamente a los tiempos de fotogramas.", + "sodium.options.always_defer_chunk_updates.name": "Aplazar Siempre las Actualizaciones de Chunks", + "sodium.options.always_defer_chunk_updates.tooltip": "Si se activa, el renderizado nunca esperará a que terminen las actualizaciones de los chunk, incluso si son importantes. Esto puede mejorar mucho la velocidad de fotogramas en algunos escenarios, pero puede crear un retraso visual significativo en el mundo.", + "sodium.options.buttons.undo": "Deshacer", + "sodium.options.buttons.apply": "Aplicar", + "sodium.options.buttons.donate": "¡Compra café para JellySquid!" +} diff --git a/src/main/resources/assets/sodium/lang/es_es.json b/src/main/resources/assets/sodium/lang/es_es.json new file mode 100644 index 000000000..a6847a8a5 --- /dev/null +++ b/src/main/resources/assets/sodium/lang/es_es.json @@ -0,0 +1,66 @@ +{ + "sodium.option_impact.low": "Bajo", + "sodium.option_impact.medium": "Medio", + "sodium.option_impact.high": "Alto", + "sodium.option_impact.extreme": "Extremo", + "sodium.option_impact.varies": "Varía", + "sodium.options.pages.quality": "Calidad", + "sodium.options.pages.performance": "Rendimiento", + "sodium.options.pages.advanced": "Avanzado", + "sodium.options.view_distance.tooltip": "La distancia de renderizado controla la distancia a la que se renderizará el terreno. Las distancias más cortas significan que se renderizará menos terreno, lo que mejora la velocidad de fotogramas.", + "sodium.options.simulation_distance.tooltip": "La distancia de simulación controla la distancia a la que se cargarán y marcarán el terreno y las entidades. Las distancias más cortas pueden reducir la carga del servidor interno y pueden mejorar la velocidad de fotogramas.", + "sodium.options.brightness.tooltip": "Controla el brillo (gamma) del juego.", + "sodium.options.gui_scale.tooltip": "Establece el factor de escala máximo que se utilizará para la interfaz de usuario. Si se utiliza 'auto', siempre se utilizará el factor de escala más grande.", + "sodium.options.fullscreen.tooltip": "Si se activa, el juego se mostrará en pantalla completa (si es compatible).", + "sodium.options.v_sync.tooltip": "Si se activa, la velocidad de fotogramas del juego se sincronizará con la frecuencia de refresco del monitor, lo que hará que la experiencia sea más fluida a expensas de la latencia de entrada general. Este ajuste puede reducir el rendimiento si tu sistema es demasiado lento.", + "sodium.options.fps_limit.tooltip": "Limita el número máximo de fotogramas por segundo. Esto puede ayudar a reducir el uso de la batería y la carga general del sistema cuando se realiza una multitarea. Si V-Sync está activado, esta opción se ignorará a menos que sea inferior a la frecuencia de refresco de tu pantalla.", + "sodium.options.view_bobbing.tooltip": "Si está activada, la vista del jugador se balanceará y oscilará cuando se mueva. Los jugadores que experimenten mareos al jugar pueden beneficiarse de desactivar esta opción.", + "sodium.options.attack_indicator.tooltip": "Controla dónde se muestra el indicador de ataque en la pantalla.", + "sodium.options.autosave_indicator.tooltip": "Si se activa, se mostrará un indicador cuando el juego esté guardando el mundo en el disco.", + "sodium.options.graphics_quality.tooltip": "La calidad gráfica por defecto controla algunas opciones heredadas y es necesaria para la compatibilidad de los mods. Si las opciones de abajo se dejan en \"Default\", utilizarán esta configuración.", + "sodium.options.clouds_quality.tooltip": "Controla la calidad de las nubes renderizadas en el cielo.", + "sodium.options.weather_quality.tooltip": "Controla la calidad de los efectos de lluvia y nieve.", + "sodium.options.leaves_quality.name": "Calidad de las Hojas", + "sodium.options.leaves_quality.tooltip": "Controla la calidad de las hojas.", + "sodium.options.particle_quality.name": "Calidad de las Partículas", + "sodium.options.particle_quality.tooltip": "Controla el número máximo de partículas que pueden estar presentes en la pantalla en un momento dado.", + "sodium.options.smooth_lighting.tooltip": "Controla si los bloques serán iluminados y sombreados suavemente. Esto aumenta ligeramente el tiempo necesario para reconstruir un trozo, pero no afecta a la velocidad de fotogramas.", + "sodium.options.biome_blend.value": "%s bloque(s)", + "sodium.options.biome_blend.tooltip": "Controla el rango que los biomas serán muestreados para la coloración de los bloques. Los valores más altos aumentan en gran medida la cantidad de tiempo que se necesita para construir trozos para disminuir las mejoras en la calidad.", + "sodium.options.entity_distance.tooltip": "Controla la distancia a la que se pueden renderizar las entidades desde el jugador. Los valores más altos aumentan la distancia de renderizado a expensas de la velocidad de fotogramas.", + "sodium.options.entity_shadows.tooltip": "Si está activada, las sombras básicas se mostrarán debajo de los monstruos y otras entidades.", + "sodium.options.vignette.name": "Viñeta", + "sodium.options.vignette.tooltip": "Si se habilita, se renderizará un efecto de viñeta en la vista del jugador. Es muy poco probable que esto suponga una diferencia en la tasa de fotogramas, a menos que la tasa de llenado sea limitada.", + "sodium.options.mipmap_levels.tooltip": "Controla el número de mipmaps que se utilizarán para las texturas del modelo de bloques. Los valores más altos proporcionan un mejor renderizado de los bloques en la distancia, pero pueden afectar negativamente al rendimiento con muchas texturas animadas.", + "sodium.options.use_block_face_culling.name": "Usar eliminación selectiva de caras de bloques", + "sodium.options.use_block_face_culling.tooltip": "Si se activa, sólo se enviarán a renderizar las caras de los bloques que estén orientadas hacia la cámara. Esto puede eliminar un gran número de caras de bloques muy pronto en el proceso de renderizado, ahorrando ancho de banda de memoria y tiempo en la GPU. Algunos paquetes de recursos pueden tener problemas con esta opción, así que prueba a desactivarla si ves agujeros en los bloques.", + "sodium.options.use_fog_occlusion.name": "Usar Oclusión de Niebla", + "sodium.options.use_fog_occlusion.tooltip": "Si se activa, los trozos que se determinan como totalmente ocultos por los efectos de niebla no se renderizarán, lo que ayuda a mejorar el rendimiento. La mejora puede ser más dramática cuando los efectos de niebla son más pesados (como cuando se está bajo el agua), pero puede causar artefactos visuales indeseables entre el cielo y la niebla en algunos escenarios.", + "sodium.options.use_entity_culling.name": "Usar Eliminación de Entidades", + "sodium.options.use_entity_culling.tooltip": "Si se activa, las entidades que se determinen que no están en ningún trozo visible se omitirán durante el renderizado. Esto puede ayudar a mejorar el rendimiento al evitar la renderización de las entidades situadas bajo tierra o detrás de las paredes.", + "sodium.options.use_particle_culling.name": "Utilice la Eliminación de Partículas", + "sodium.options.use_particle_culling.tooltip": "Si se activa, sólo se renderizarán las partículas que se determinen como visibles. Esto puede proporcionar una mejora significativa en la velocidad de fotogramas cuando hay muchas partículas cerca.", + "sodium.options.animate_only_visible_textures.name": "Animar Sólo las Texturas Visibles", + "sodium.options.animate_only_visible_textures.tooltip": "Si se activa, sólo se actualizarán las texturas animadas que sean visibles. Esto puede proporcionar un aumento significativo de la velocidad de fotogramas en algunos equipos, especialmente con paquetes de recursos más pesados. Si tienes problemas con algunas texturas que no se animan, prueba a desactivar esta opción.", + "sodium.options.cpu_render_ahead_limit.name": "Límite de Procesamiento Anticipado de CPU", + "sodium.options.cpu_render_ahead_limit.tooltip": "Especifica el número máximo de fotogramas que la CPU puede esperar a que la GPU termine de renderizar. Los valores muy bajos o altos pueden crear inestabilidad en la tasa de fotogramas.", + "sodium.options.cpu_render_ahead_limit.value": "%s fotograma(s)", + "sodium.options.allow_direct_memory_access.name": "Permitir Aacceso Directo a la Memoria", + "sodium.options.allow_direct_memory_access.tooltip": "Si se activa, se permitirá que algunas rutas de código críticas utilicen el acceso directo a la memoria para mejorar el rendimiento. Esto suele reducir en gran medida la sobrecarga de la CPU para el renderizado de trozos y entidades, pero puede dificultar el diagnóstico de algunos fallos y caídas. Sólo deberías desactivar esto si te lo han pedido o si sabes lo que estás haciendo.", + "sodium.options.enable_memory_tracing.name": "Habilitar Seguimiento de Memoria", + "sodium.options.enable_memory_tracing.tooltip": "Función de depuración. Si está activada, se recogerán los rastros de pila junto con las asignaciones de memoria para ayudar a mejorar la información de diagnóstico cuando se detecten fugas de memoria.", + "sodium.options.performance_impact_string": "Impacto en el Rendimiento: %s", + "sodium.options.use_persistent_mapping.name": "Utilizar el Mapeo Persistente", + "sodium.options.use_persistent_mapping.tooltip": "Si se activa, una pequeña cantidad de memoria será mapeada de forma persistente para acelerar las actualizaciones de chunk y el renderizado de entidades.\n\nRequiere OpenGL 4.4 o ARB_buffer_storage.", + "sodium.options.chunk_memory_allocator.name": "Asignador de Memoria de Chunks", + "sodium.options.chunk_memory_allocator.tooltip": "Selecciona el asignador de memoria que se utilizará para el renderizado de los trozos.\n- ASYNC: Opción más rápida, funciona bien con la mayoría de los controladores gráficos modernos.\n- SWAP: Opción de reserva para los controladores gráficos más antiguos. Puede aumentar significativamente el uso de la memoria.", + "sodium.options.chunk_memory_allocator.async": "Async", + "sodium.options.chunk_memory_allocator.swap": "Intercambiar", + "sodium.options.chunk_update_threads.name": "Subprocesos de Actualización de Chunks", + "sodium.options.chunk_update_threads.tooltip": "Especifica el número de hilos que se van a utilizar para la construcción de los trozos. El uso de más hilos puede acelerar la carga de trozos y la velocidad de actualización, pero puede afectar negativamente a los tiempos de fotogramas.", + "sodium.options.always_defer_chunk_updates.name": "Aplazar Siempre las Actualizaciones de Chunks", + "sodium.options.always_defer_chunk_updates.tooltip": "Si se activa, el renderizado nunca esperará a que terminen las actualizaciones de los chunk, incluso si son importantes. Esto puede mejorar mucho la velocidad de fotogramas en algunos escenarios, pero puede crear un retraso visual significativo en el mundo.", + "sodium.options.buttons.undo": "Deshacer", + "sodium.options.buttons.apply": "Aplicar", + "sodium.options.buttons.donate": "¡Compra café para JellySquid!" +} diff --git a/src/main/resources/assets/sodium/lang/es_mx.json b/src/main/resources/assets/sodium/lang/es_mx.json new file mode 100644 index 000000000..a6847a8a5 --- /dev/null +++ b/src/main/resources/assets/sodium/lang/es_mx.json @@ -0,0 +1,66 @@ +{ + "sodium.option_impact.low": "Bajo", + "sodium.option_impact.medium": "Medio", + "sodium.option_impact.high": "Alto", + "sodium.option_impact.extreme": "Extremo", + "sodium.option_impact.varies": "Varía", + "sodium.options.pages.quality": "Calidad", + "sodium.options.pages.performance": "Rendimiento", + "sodium.options.pages.advanced": "Avanzado", + "sodium.options.view_distance.tooltip": "La distancia de renderizado controla la distancia a la que se renderizará el terreno. Las distancias más cortas significan que se renderizará menos terreno, lo que mejora la velocidad de fotogramas.", + "sodium.options.simulation_distance.tooltip": "La distancia de simulación controla la distancia a la que se cargarán y marcarán el terreno y las entidades. Las distancias más cortas pueden reducir la carga del servidor interno y pueden mejorar la velocidad de fotogramas.", + "sodium.options.brightness.tooltip": "Controla el brillo (gamma) del juego.", + "sodium.options.gui_scale.tooltip": "Establece el factor de escala máximo que se utilizará para la interfaz de usuario. Si se utiliza 'auto', siempre se utilizará el factor de escala más grande.", + "sodium.options.fullscreen.tooltip": "Si se activa, el juego se mostrará en pantalla completa (si es compatible).", + "sodium.options.v_sync.tooltip": "Si se activa, la velocidad de fotogramas del juego se sincronizará con la frecuencia de refresco del monitor, lo que hará que la experiencia sea más fluida a expensas de la latencia de entrada general. Este ajuste puede reducir el rendimiento si tu sistema es demasiado lento.", + "sodium.options.fps_limit.tooltip": "Limita el número máximo de fotogramas por segundo. Esto puede ayudar a reducir el uso de la batería y la carga general del sistema cuando se realiza una multitarea. Si V-Sync está activado, esta opción se ignorará a menos que sea inferior a la frecuencia de refresco de tu pantalla.", + "sodium.options.view_bobbing.tooltip": "Si está activada, la vista del jugador se balanceará y oscilará cuando se mueva. Los jugadores que experimenten mareos al jugar pueden beneficiarse de desactivar esta opción.", + "sodium.options.attack_indicator.tooltip": "Controla dónde se muestra el indicador de ataque en la pantalla.", + "sodium.options.autosave_indicator.tooltip": "Si se activa, se mostrará un indicador cuando el juego esté guardando el mundo en el disco.", + "sodium.options.graphics_quality.tooltip": "La calidad gráfica por defecto controla algunas opciones heredadas y es necesaria para la compatibilidad de los mods. Si las opciones de abajo se dejan en \"Default\", utilizarán esta configuración.", + "sodium.options.clouds_quality.tooltip": "Controla la calidad de las nubes renderizadas en el cielo.", + "sodium.options.weather_quality.tooltip": "Controla la calidad de los efectos de lluvia y nieve.", + "sodium.options.leaves_quality.name": "Calidad de las Hojas", + "sodium.options.leaves_quality.tooltip": "Controla la calidad de las hojas.", + "sodium.options.particle_quality.name": "Calidad de las Partículas", + "sodium.options.particle_quality.tooltip": "Controla el número máximo de partículas que pueden estar presentes en la pantalla en un momento dado.", + "sodium.options.smooth_lighting.tooltip": "Controla si los bloques serán iluminados y sombreados suavemente. Esto aumenta ligeramente el tiempo necesario para reconstruir un trozo, pero no afecta a la velocidad de fotogramas.", + "sodium.options.biome_blend.value": "%s bloque(s)", + "sodium.options.biome_blend.tooltip": "Controla el rango que los biomas serán muestreados para la coloración de los bloques. Los valores más altos aumentan en gran medida la cantidad de tiempo que se necesita para construir trozos para disminuir las mejoras en la calidad.", + "sodium.options.entity_distance.tooltip": "Controla la distancia a la que se pueden renderizar las entidades desde el jugador. Los valores más altos aumentan la distancia de renderizado a expensas de la velocidad de fotogramas.", + "sodium.options.entity_shadows.tooltip": "Si está activada, las sombras básicas se mostrarán debajo de los monstruos y otras entidades.", + "sodium.options.vignette.name": "Viñeta", + "sodium.options.vignette.tooltip": "Si se habilita, se renderizará un efecto de viñeta en la vista del jugador. Es muy poco probable que esto suponga una diferencia en la tasa de fotogramas, a menos que la tasa de llenado sea limitada.", + "sodium.options.mipmap_levels.tooltip": "Controla el número de mipmaps que se utilizarán para las texturas del modelo de bloques. Los valores más altos proporcionan un mejor renderizado de los bloques en la distancia, pero pueden afectar negativamente al rendimiento con muchas texturas animadas.", + "sodium.options.use_block_face_culling.name": "Usar eliminación selectiva de caras de bloques", + "sodium.options.use_block_face_culling.tooltip": "Si se activa, sólo se enviarán a renderizar las caras de los bloques que estén orientadas hacia la cámara. Esto puede eliminar un gran número de caras de bloques muy pronto en el proceso de renderizado, ahorrando ancho de banda de memoria y tiempo en la GPU. Algunos paquetes de recursos pueden tener problemas con esta opción, así que prueba a desactivarla si ves agujeros en los bloques.", + "sodium.options.use_fog_occlusion.name": "Usar Oclusión de Niebla", + "sodium.options.use_fog_occlusion.tooltip": "Si se activa, los trozos que se determinan como totalmente ocultos por los efectos de niebla no se renderizarán, lo que ayuda a mejorar el rendimiento. La mejora puede ser más dramática cuando los efectos de niebla son más pesados (como cuando se está bajo el agua), pero puede causar artefactos visuales indeseables entre el cielo y la niebla en algunos escenarios.", + "sodium.options.use_entity_culling.name": "Usar Eliminación de Entidades", + "sodium.options.use_entity_culling.tooltip": "Si se activa, las entidades que se determinen que no están en ningún trozo visible se omitirán durante el renderizado. Esto puede ayudar a mejorar el rendimiento al evitar la renderización de las entidades situadas bajo tierra o detrás de las paredes.", + "sodium.options.use_particle_culling.name": "Utilice la Eliminación de Partículas", + "sodium.options.use_particle_culling.tooltip": "Si se activa, sólo se renderizarán las partículas que se determinen como visibles. Esto puede proporcionar una mejora significativa en la velocidad de fotogramas cuando hay muchas partículas cerca.", + "sodium.options.animate_only_visible_textures.name": "Animar Sólo las Texturas Visibles", + "sodium.options.animate_only_visible_textures.tooltip": "Si se activa, sólo se actualizarán las texturas animadas que sean visibles. Esto puede proporcionar un aumento significativo de la velocidad de fotogramas en algunos equipos, especialmente con paquetes de recursos más pesados. Si tienes problemas con algunas texturas que no se animan, prueba a desactivar esta opción.", + "sodium.options.cpu_render_ahead_limit.name": "Límite de Procesamiento Anticipado de CPU", + "sodium.options.cpu_render_ahead_limit.tooltip": "Especifica el número máximo de fotogramas que la CPU puede esperar a que la GPU termine de renderizar. Los valores muy bajos o altos pueden crear inestabilidad en la tasa de fotogramas.", + "sodium.options.cpu_render_ahead_limit.value": "%s fotograma(s)", + "sodium.options.allow_direct_memory_access.name": "Permitir Aacceso Directo a la Memoria", + "sodium.options.allow_direct_memory_access.tooltip": "Si se activa, se permitirá que algunas rutas de código críticas utilicen el acceso directo a la memoria para mejorar el rendimiento. Esto suele reducir en gran medida la sobrecarga de la CPU para el renderizado de trozos y entidades, pero puede dificultar el diagnóstico de algunos fallos y caídas. Sólo deberías desactivar esto si te lo han pedido o si sabes lo que estás haciendo.", + "sodium.options.enable_memory_tracing.name": "Habilitar Seguimiento de Memoria", + "sodium.options.enable_memory_tracing.tooltip": "Función de depuración. Si está activada, se recogerán los rastros de pila junto con las asignaciones de memoria para ayudar a mejorar la información de diagnóstico cuando se detecten fugas de memoria.", + "sodium.options.performance_impact_string": "Impacto en el Rendimiento: %s", + "sodium.options.use_persistent_mapping.name": "Utilizar el Mapeo Persistente", + "sodium.options.use_persistent_mapping.tooltip": "Si se activa, una pequeña cantidad de memoria será mapeada de forma persistente para acelerar las actualizaciones de chunk y el renderizado de entidades.\n\nRequiere OpenGL 4.4 o ARB_buffer_storage.", + "sodium.options.chunk_memory_allocator.name": "Asignador de Memoria de Chunks", + "sodium.options.chunk_memory_allocator.tooltip": "Selecciona el asignador de memoria que se utilizará para el renderizado de los trozos.\n- ASYNC: Opción más rápida, funciona bien con la mayoría de los controladores gráficos modernos.\n- SWAP: Opción de reserva para los controladores gráficos más antiguos. Puede aumentar significativamente el uso de la memoria.", + "sodium.options.chunk_memory_allocator.async": "Async", + "sodium.options.chunk_memory_allocator.swap": "Intercambiar", + "sodium.options.chunk_update_threads.name": "Subprocesos de Actualización de Chunks", + "sodium.options.chunk_update_threads.tooltip": "Especifica el número de hilos que se van a utilizar para la construcción de los trozos. El uso de más hilos puede acelerar la carga de trozos y la velocidad de actualización, pero puede afectar negativamente a los tiempos de fotogramas.", + "sodium.options.always_defer_chunk_updates.name": "Aplazar Siempre las Actualizaciones de Chunks", + "sodium.options.always_defer_chunk_updates.tooltip": "Si se activa, el renderizado nunca esperará a que terminen las actualizaciones de los chunk, incluso si son importantes. Esto puede mejorar mucho la velocidad de fotogramas en algunos escenarios, pero puede crear un retraso visual significativo en el mundo.", + "sodium.options.buttons.undo": "Deshacer", + "sodium.options.buttons.apply": "Aplicar", + "sodium.options.buttons.donate": "¡Compra café para JellySquid!" +} diff --git a/src/main/resources/assets/sodium/lang/ko_kr.json b/src/main/resources/assets/sodium/lang/ko_kr.json new file mode 100644 index 000000000..34a7ddf98 --- /dev/null +++ b/src/main/resources/assets/sodium/lang/ko_kr.json @@ -0,0 +1,68 @@ +{ + "sodium.option_impact.low": "하", + "sodium.option_impact.medium": "중", + "sodium.option_impact.high": "상", + "sodium.option_impact.extreme": "최상", + "sodium.option_impact.varies": "때때로 다름", + "sodium.options.pages.quality": "품질", + "sodium.options.pages.performance": "성능", + "sodium.options.pages.advanced": "고급", + "sodium.options.view_distance.tooltip": "렌더 거리는 지형이 어느 거리에서부터 표시될 지 조절합니다. 짧은 거리일수록 더 적게 표시되어 프레임이 향상됩니다.", + "sodium.options.simulation_distance.tooltip": "시뮬레이션 거리는 지형과 개체가 어느 거리에서부터 로딩되고 작동할 지 조절합니다. 짧은 거리일수록 내부 서버의 부하를 줄이고 프레임이 향상될 수 있습니다.", + "sodium.options.brightness.tooltip": "화면의 밝기(감마)를 조절합니다.", + "sodium.options.clouds.name": "구름", + "sodium.options.clouds.tooltip": "구름 표시 여부를 조절합니다..", + "sodium.options.gui_scale.tooltip": "사용자 인터페이스 크기를 조절합니다. '자동' 사용 시, 항상 가장 큰 크기를 사용합니다.", + "sodium.options.fullscreen.tooltip": "활성화 시, 게임이 전체 화면으로 표시됩니다 (지원되는 경우).", + "sodium.options.v_sync.tooltip": "활성화 시, 게임의 프레임이 모니터의 주사율과 동기화되며, 입력 지연을 대가로 일반적으로 더 부드러운 화면을 제공합니다. 이 설정은 시스템이 좋지 않을 경우 성능 저하를 일으킬 수 있습니다.", + "sodium.options.fps_limit.tooltip": "초당 최대 프레임 수를 제한합니다. 이 설정은 배터리 사용량 및 멀티테스킹 시 시스템 부하를 줄일 수 있습니다. V-Sync 활성화 시, 제한값이 모니터의 주사율보다 높으면 설정이 무시됩니다.", + "sodium.options.view_bobbing.tooltip": "활성화 시, 화면의 움직임이 사실적으로 표시됩니다. 게임 플레이 중 멀미를 경험하면 이 설정을 비활성화함으로써 도움이 될 수 있습니다.", + "sodium.options.attack_indicator.tooltip": "공격 지표를 조절합니다.", + "sodium.options.autosave_indicator.tooltip": "활성화 시, 월드 자동 저장 아이콘이 표시됩니다.", + "sodium.options.graphics_quality.tooltip": "기본 그래픽 설정을 조절하며, 모드 호환성에 영향을 줍니다. 아래 옵션들에 '기본'을 사용할 경우 이 그래픽 설정을 따릅니다.", + "sodium.options.clouds_quality.tooltip": "구름의 품질을 조절합니다.", + "sodium.options.weather_quality.tooltip": "비 및 눈 효과의 품질을 조절합니다.", + "sodium.options.leaves_quality.name": "나뭇잎", + "sodium.options.leaves_quality.tooltip": "나뭇잎의 품질을 조절합니다.", + "sodium.options.particle_quality.name": "입자", + "sodium.options.particle_quality.tooltip": "한 화면에 표시할 수 있는 최대 입자 수를 조절합니다.", + "sodium.options.smooth_lighting.tooltip": "블럭이 부드러운 조명 및 음영 효과를 가질 지 조절합니다. 이 설정은 청크 재생성 시간을 조금 증가시키지만 프레임에 영향을 주지 않습니다.", + "sodium.options.biome_blend.value": "%s 블럭", + "sodium.options.biome_blend.tooltip": "생물 균계 혼합에 따른 블럭 색 혼합 범위를 조절합니다. 설정값이 높을 수록 품질 향상을 위해 청크 생성시간이 크게 늘어납니다.", + "sodium.options.entity_distance.tooltip": "개체가 어느 거리에서부터 플레이어에게 표시될 지 조절합니다. 설정값이 높을 수록 개체 표시 거리가 늘어나고 프레임이 저하됩니다.", + "sodium.options.entity_shadows.tooltip": "활성화 시, 기본 그림자가 몹 및 다른 개체 아래에 표시됩니다.", + "sodium.options.vignette.name": "비네팅", + "sodium.options.vignette.tooltip": "활성화 시, 플레이어의 시야에 비네팅 효과가 표시됩니다. 필레이트 제한이 걸려있지 않는 한 프레임에 영향을 줄 가능성은 매우 낮습니다.", + "sodium.options.mipmap_levels.tooltip": "블럭 모델 텍스쳐에 사용할 밉맵 갯수를 조절합니다. 설정값이 높을 수록 먼 거리에서 더 나은 블럭 표시를 제공하지만, 움직이는 텍스쳐가 많을 경우 성능에 영향을 줄 수 있습니다.", + "sodium.options.use_block_face_culling.name": "블럭 면 컬링 사용", + "sodium.options.use_block_face_culling.tooltip": "활성화 시, 플레이어의 시야에 보이는 블럭 면만 렌더됩니다. 이 설정으로 많은 양의 블럭 면을 렌더링 초기 단계에 줄여서 GPU의 메모리 대역폭과 시간을 줄입니다. 일부 리소스 팩에서 문제가 생길 수 있으므로 블럭에 구멍이 보인다면 비활성화함으로써 도움이 될 수 있습니다.", + "sodium.options.use_fog_occlusion.name": "안개 오클루전 사용", + "sodium.options.use_fog_occlusion.tooltip": "활성화 시, 플레이어의 시야에서 안개에 의해 전혀 보이지 않는 청크는 렌더되지 않으며 성능이 향상됩니다. 안개가 심할 수록 성능 향상이 더 극적으로 나타날 수 있습니다 (물 안속에 상황). 하지만 하늘과 안개 사이에서의 일부 상황에는 예기치 않은 시야 버그의 원인이 될 수 있습니다.", + "sodium.options.use_entity_culling.name": "개체 컬링 사용", + "sodium.options.use_entity_culling.tooltip": "활성화 시, 플레이어의 시야에서 보이지 않는 청크에 위치한 개체들은 렌더되지 않습니다. 이 설정은 땅 속이나 벽 뒤에 위치해 있는 개체들을 렌더링 단계에서 제외함으로써 성능이 향상될 수 있습니다.", + "sodium.options.use_particle_culling.name": "입자 컬링 사용", + "sodium.options.use_particle_culling.tooltip": "활성화 시, 플레이어의 시야에서 보이는 입자만 렌더됩니다. 이 설정은 주변에 입자 수가 많을 경우 프레임을 크게 향상시킬 수 있습니다.", + "sodium.options.animate_only_visible_textures.name": "보이는 텍스쳐만 애니메이션 사용", + "sodium.options.animate_only_visible_textures.tooltip": "활성화 시, 플레이어의 시야에서 보이는 텍스쳐만 애니메이션이 업데이트됩니다. 이 설정은 일부 하드웨어에서 (특히 무거운 리소스팩을 사용할 때) 프레임을 크게 향상시킬 수 있습니다. 일부 텍스쳐 애니메이션이 작동하지 않는 문제가 발생한다면 비활성화함으로써 도움이 될 수 있습니다.", + "sodium.options.cpu_render_ahead_limit.name": "CPU 렌더 제한", + "sodium.options.cpu_render_ahead_limit.tooltip": "렌더링을 완료하기 위해 CPU가 GPU에서 대기할 수 있는 최대 프레임 수를 조절합니다. 매우 낮거나 매우 높은 설정 값은 프레임이 요동칠 수 있습니다.", + "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.enable_memory_tracing.name": "메모리 추적", + "sodium.options.enable_memory_tracing.tooltip": "디버그 기능. 활성화 시, 스택에 메모리 할당이 수집되어 메모리 누수가 감지된 경우 진단에 도움을 줄 수 있습니다.", + "sodium.options.performance_impact_string": "성능 영향: %s", + "sodium.options.use_persistent_mapping.name": "영구 매핑 사용", + "sodium.options.use_persistent_mapping.tooltip": "활성화 시, 적은 양의 메모리가 영구적으로 청크 업데이트와 개체 렌더링을 위해 매핑됩니다.\n\nOpenGL 4.4 또는 ARB_buffer_storage가 요구됩니다.", + "sodium.options.chunk_memory_allocator.name": "청크 메모리 관리", + "sodium.options.chunk_memory_allocator.tooltip": "청크 렌더링에 사용될 메모리 할당자를 선택합니다.\n- ASYNC: 가장 빠른 옵션, 대부분의 최신 그래픽 드라이버와 함께 잘 작동합니다.\n- SWAP: 오래된 그래픽 드라이버를 위한 대체 옵션. 메모리 사용량이 크게 증가할 수 있습니다.", + "sodium.options.chunk_memory_allocator.async": "Async", + "sodium.options.chunk_memory_allocator.swap": "Swap", + "sodium.options.chunk_update_threads.name": "청크 업데이트 스레드", + "sodium.options.chunk_update_threads.tooltip": "청크 업데이트에 사용할 스레드 갯수를 지정합니다. 더 많은 스레드를 사용하면 청크 로딩과 업데이트 속도를 향상시킬 수 있지만 프레임 시간에 부정적인 영향을 줄 수 있습니다.", + "sodium.options.always_defer_chunk_updates.name": "항상 청크 업데이트 미루기", + "sodium.options.always_defer_chunk_updates.tooltip": "활성화 시, 렌더링은 청크 업데이트가 아무리 중요하더라도 그것이 끝나기까지 기다리지 않습니다. 일부 상황에서 프레임을 크게 향상시킬 수 있지만 월드에 상당한 시야 랙을 발생시킬 수 있습니다.", + "sodium.options.buttons.undo": "취소", + "sodium.options.buttons.apply": "완료", + "sodium.options.buttons.donate": "개발자 후원하기" +} \ No newline at end of file diff --git a/src/main/resources/assets/sodium/lang/pt_br.json b/src/main/resources/assets/sodium/lang/pt_br.json new file mode 100644 index 000000000..04b7e7630 --- /dev/null +++ b/src/main/resources/assets/sodium/lang/pt_br.json @@ -0,0 +1,66 @@ +{ + "sodium.option_impact.low": "Baixo", + "sodium.option_impact.medium": "Médio", + "sodium.option_impact.high": "Alto", + "sodium.option_impact.extreme": "Extremo", + "sodium.option_impact.varies": "Variável", + "sodium.options.pages.quality": "Qualidade", + "sodium.options.pages.performance": "Desempenho", + "sodium.options.pages.advanced": "Opções Avançadas", + "sodium.options.view_distance.tooltip": "A distância de processamento visual controla o quão longe o terreno será carregado. Distâncias menores significam será carregado menos terreno, o que aumenta a taxa de quadros.", + "sodium.options.simulation_distance.tooltip": "A distância de simulação controla o quão longe o terreno e entiades serão simulados e automatizados. Distâncias menores exigem menos dos servidores, o que aumenta a taxa de quadros.", + "sodium.options.brightness.tooltip": "Controla o quão claro o jogo é. Aumentar o brilho pode ajudar pessoas com monitores muito reflexivos ou que estão em ambientes muito claros", + "sodium.options.gui_scale.tooltip": "Define a escala máxima da interface. Se \"auto\" for usado, a maior escala será usada.", + "sodium.options.fullscreen.tooltip": "Caso habilitado e suportado, o jogo será exibido em tela cheia.", + "sodium.options.v_sync.tooltip": "Caso habilitado, a taxa de quadros sera sincronizada com a taxa de atualização do monitor, tornando a experiência visual mais confortável ao custo de um certo atraso visual pouco perceptível. Esta opção pode reduzir o desempenho caso seu computador seja lento.", + "sodium.options.fps_limit.tooltip": "Limita o número máximo de quadros por segundo. Isto pode ajudar a reduzir o consumo de bateria e o carregamento do sistema quando executa multi-tarefas. Se a sincronização vertical estiver ligada, esta opção será ignorada, a menos que seja menor que a taxa de atualização do seu monitor", + "sodium.options.view_bobbing.tooltip": "Caso habilitado, a câmera do jogador irá se balançar quando se movimentar. Jogadores sucetíveis a enjôos podem se beneficiar ao desabilitar esta opção.", + "sodium.options.attack_indicator.tooltip": "Controla onde o indicador de ataque aparece na tela.", + "sodium.options.autosave_indicator.tooltip": "Caso habilitado, um indicador será mostrado quando o jogo estiver sendo salvo.", + "sodium.options.graphics_quality.tooltip": "A qualidade gráfica padrão controla algumas opções de legado e é necessária para a melhor compatibilidade com mods. Caso as opções abaixo estejam como \"Padrão\", elas usarão esta configuração.", + "sodium.options.clouds_quality.tooltip": "Controla a qualidade das nuvens no céu. Elas podem ser planas ou possuírem três dimensões.", + "sodium.options.weather_quality.tooltip": "Controla a qualidade e quantidade de partículas de chuva e neve.", + "sodium.options.leaves_quality.name": "Qualidade das folhas", + "sodium.options.leaves_quality.tooltip": "Controla a qualidade das folhas.", + "sodium.options.particle_quality.name": "Qualidade das partículas", + "sodium.options.particle_quality.tooltip": "Controla o número máximo de partículas que aparecem na tela ao mesmo tempo.", + "sodium.options.smooth_lighting.tooltip": "Controla o quão suave é a iluminação e sombreamento nos blocos. Isso aumenta o tempo necessário para reconstruir uma região, mas não afeta a taxa de quadros.", + "sodium.options.biome_blend.value": "%s bloco(s)", + "sodium.options.biome_blend.tooltip": "Controla o alcance do limiar de cores do terreno e folhagem dos biomas. Valores altos aumentam significativamente o tempo de geração do mundo para diminuir as melhorias na qualidade.", + "sodium.options.entity_distance.tooltip": "Controla o quão longe as criaturas podem ser processadas visualmente. Valores altos aumentam a distância de processamento visual ao custo de uma diminuição da taxa de quadros.", + "sodium.options.entity_shadows.tooltip": "Caso habilitado, uma sombra projetada bem simples será mostrada abaixo de riaturas e outras entidades, inclusive jogadores.", + "sodium.options.vignette.name": "Vinheta", + "sodium.options.vignette.tooltip": "Caso habilitada, um efeito de escurecimento das bordas da tela será aplicado na câmera em primeira pessoa do jogador. É muitíssimo pouco provável que este efeito possua algum efeito na taxa de quadros, a menos que o computador possua uma taxa de preenchimento limitada.", + "sodium.options.mipmap_levels.tooltip": "Controla o a filtragem de texturas de blocos a uma certa distância. Valores altos proporcionam uma qualidade melhor dos blocos que estão muito distantes, mas afeta o desempenho se houverem muitos blocos animados.", + "sodium.options.use_block_face_culling.name": "Utilizar abate de face de bloco", + "sodium.options.use_block_face_culling.tooltip": "Caso habilitado, apenas a lateral dos blocos que estão viradas para a câmera serão processadas visualmente. Isto elimina um número imenso de faces de blocos no estágio de carregamento, salvando memória e processamento visual da placa de vídeo. Alguns pacotes de recursos podem ter problemas com esta opção, então tente desativar esta opção caso esteja vendo falhas em blocos.", + "sodium.options.use_fog_occlusion.name": "Utilizar oclusão de neblina", + "sodium.options.use_fog_occlusion.tooltip": "Caso habilitado, regiões que devem estar completamente escondidas pela neblina não serão carregadas para favorecer o desempenho. O aumento no desempenho pode ser ainda mais evidente quando os efeitos de neblina estão mais intensos, como quando se está debaixo d'água, mas, em alguns casos, pode causar falhas de processamento visual de terreno indesejáveis.", + "sodium.options.use_entity_culling.name": "Utilizar abate de entidades", + "sodium.options.use_entity_culling.tooltip": "Caso habilitado, entidades que não devem estar visíveis, como atrás de blocos ou debaixo da terra, por exemplo, serão ignoradas no processamento visual, o que aumenta o desempenho.", + "sodium.options.use_particle_culling.name": "Utilizar abate de partículas", + "sodium.options.use_particle_culling.tooltip": "Caso habilitado, apenas partículas que devem estar visíveis serão processadas visualmente. Isto pode aumenta o desempenho quando se está em locais com muitas partículas.", + "sodium.options.animate_only_visible_textures.name": "Animar apenas texturas visíveis", + "sodium.options.animate_only_visible_textures.tooltip": "Caso habilitado, apenas texturas animadas visíveis serão processadas visualmente. Isto pode aumentas significativamente o desempenho em alguns computadores, especialmente quando se usa muitos pacotes de recursos. Caso esteja experienciando falhas na animação em texturas, desabilite esta opção.", + "sodium.options.cpu_render_ahead_limit.name": "Limite de processamento visual adiantado do processador", + "sodium.options.cpu_render_ahead_limit.tooltip": "Especifica o número máximo de quadros que o processador pode esperar a placa de vídeo terminar de processar. Números muito baixos ou altos podem criar instabilidade na taxa de quadros.", + "sodium.options.cpu_render_ahead_limit.value": "%s quadro(s)", + "sodium.options.allow_direct_memory_access.name": "Permitir acesso direto à memória", + "sodium.options.allow_direct_memory_access.tooltip": "Caso habilitado, alguns caminhos de código críticos poderão ter acesso direto à memória para fins de desempenho. Isto geralmente reduz bastante sobrecargas no processador no que tange o processamento visual de entidades, mas pode ser mais difícil diagnosticar alguns erros ou interrupções (crashes). Você só deve desabilitar esta opção se for requerido ou souber o que está fazendo.", + "sodium.options.enable_memory_tracing.name": "Habilitar rastreio de memória", + "sodium.options.enable_memory_tracing.tooltip": "Recurso de diagnóstico. Caso habilitado, dados de rastreamentos serão coletados junto com as alocações de memória para ajudar a melhorar as informações de diagnóstico quando vazamentos de memória forem detectados .", + "sodium.options.performance_impact_string": "Impacto no desempenho: %s", + "sodium.options.use_persistent_mapping.name": "Utilizar mapeamento de persistência", + "sodium.options.use_persistent_mapping.tooltip": "Caso habilitado, uma pequena quantidade de memória será persistentemente mapeada como um filtro de teste para envio de regiões, ajudando a reduzir sobrecargas do processador e instabilidade de tempo de quadro quando carregando ou atualizando regiões.\n\nRequer OpenGL 4.4 ou ARB_buffer_storage.", + "sodium.options.chunk_memory_allocator.name": "Alocador de memória de regiões", + "sodium.options.chunk_memory_allocator.tooltip": "Seleciona um alocador de memória para ser usado no processamento visual das regiões.\n- ASSÍNCRONO: Opção mais rápida, funcina melhor com placas gráficas mais atuais.\n- ALTERNATE: Opção para máquinas antigas. Pode aumentar o uso da memória significativamente.", + "sodium.options.chunk_memory_allocator.async": "Assíncrono", + "sodium.options.chunk_memory_allocator.swap": "Alternante", + "sodium.options.chunk_update_threads.name": "Tópicos de atualizações de regiões", + "sodium.options.chunk_update_threads.tooltip": "Especifica o número de tópicos a serem usadas no carregamento de regiões. Utilizar mais tópicos pode acelerar o carregamento e atualização de regiões, mas pode impactar negativamente a taxa de quadros.", + "sodium.options.always_defer_chunk_updates.name": "Sempre adiar atualizações de regiões", + "sodium.options.always_defer_chunk_updates.tooltip": "Caso habilitado, o processamento visual nunca vai aguardar o término das atualizações de regiões, mesmo quado são importantes. Isto pode aumentar significativamente a taxa de quadros em alguns casos, mas pode criar vários erros visuais no mundo.", + "sodium.options.buttons.undo": "Desfazer", + "sodium.options.buttons.apply": "Aplicar", + "sodium.options.buttons.donate": "Doações" +} diff --git a/src/main/resources/assets/sodium/lang/ru_ru.json b/src/main/resources/assets/sodium/lang/ru_ru.json new file mode 100644 index 000000000..542a7f151 --- /dev/null +++ b/src/main/resources/assets/sodium/lang/ru_ru.json @@ -0,0 +1,66 @@ +{ + "sodium.option_impact.low": "Низкое", + "sodium.option_impact.medium": "Среднее", + "sodium.option_impact.high": "Высокое", + "sodium.option_impact.extreme": "Огромное", + "sodium.option_impact.varies": "Разное", + "sodium.options.pages.quality": "Качество", + "sodium.options.pages.performance": "Производительность", + "sodium.options.pages.advanced": "Расширенные", + "sodium.options.view_distance.tooltip": "Дальность прорисовки определяет, как далеко будет видна местность. Меньшие значения соответствуют меньшей площади, что улучшает частоту кадров.", + "sodium.options.simulation_distance.tooltip": "Дальность симуляции определяет, как далеко местность и сущности будут загружаться и обрабатываться. Меньшие значения могут уменьшить нагрузку на внутренний сервер и увеличить частоту кадров.", + "sodium.options.brightness.tooltip": "Управляет яркостью (гаммой) игры.", + "sodium.options.gui_scale.tooltip": "Устанавливает коэффициент масштабирования для интерфейса. При выборе «Авто» всегда будет использоваться наибольший размер.", + "sodium.options.fullscreen.tooltip": "Если включено, игра будет открыта во весь экран (если доступно).", + "sodium.options.v_sync.tooltip": "Если включена, частота кадров будет синхронизирована с частотой обновления монитора, обеспечивая более плавную игру за счет небольшой задержки ввода. Может понизить производительность слабых систем.", + "sodium.options.fps_limit.tooltip": "Ограничивает максимальное количество кадров в секунду. Это поможет уменьшить энергопотребление и нагрузку на систему в обеспечении многозадачности. При включённой вертикальной синхронизации этот параметр будет игнорироваться, если он выше частоты обновления вашего экрана.", + "sodium.options.view_bobbing.tooltip": "Если включено, обзор игрока будет покачиваться при движении. Отключение этого параметра может помочь людям, страдающим от укачивания во время игры.", + "sodium.options.attack_indicator.tooltip": "Управляет расположением индикатора атаки на экране.", + "sodium.options.autosave_indicator.tooltip": "Если включено, при сохранении игрой мира на диск будет показываться индикатор.", + "sodium.options.graphics_quality.tooltip": "Качество графики по умолчанию управляет некоторыми зависимыми настройками и необходимо для совместимости с модами. Опции ниже со значением «По умолчанию» будут использовать этот параметр.", + "sodium.options.clouds_quality.tooltip": "Управляет качеством отрисовки облаков в небе.", + "sodium.options.weather_quality.tooltip": "Управляет качеством эффектов дождя и снега.", + "sodium.options.leaves_quality.name": "Качество листьев", + "sodium.options.leaves_quality.tooltip": "Управляет качеством листьев.", + "sodium.options.particle_quality.name": "Качество частиц", + "sodium.options.particle_quality.tooltip": "Управляет максимальным количеством частиц, которые могут одновременно присутствовать на экране.", + "sodium.options.smooth_lighting.tooltip": "Управляет мягким освещением и затенением блоков. Это немного увеличивает время сборки чанка, однако не влияет на частоту кадров.", + "sodium.options.biome_blend.value": "Блоков: %s", + "sodium.options.biome_blend.tooltip": "Управляет диапазоном анализа биомов для расцветки блока. Более высокие значения сильно увеличивают затрачиваемое на сборку чанков время ради незначительного улучшения качества.", + "sodium.options.entity_distance.tooltip": "Управляет дальностью видимости сущностей. Высокие значения увеличивают расстояние отображения за счёт частоты кадров.", + "sodium.options.entity_shadows.tooltip": "Если включено, под мобами и другими сущностями будут отображаться простые тени.", + "sodium.options.vignette.name": "Виньетирование", + "sodium.options.vignette.tooltip": "Если включено, на экране игрока будет отображаться эффект виньетирования. Вряд ли повлияет на частоту кадров, если ваш ГП не ограничен скоростью заполнения пикселей.", + "sodium.options.mipmap_levels.tooltip": "Управляет количеством уровней детализации для текстур блоков. Более высокие значения обеспечивают лучший вид на расстоянии, но могут негативно повлиять на производительность с большим количеством анимированных текстур.", + "sodium.options.use_block_face_culling.name": "Отбраковка поверхностей блоков", + "sodium.options.use_block_face_culling.tooltip": "Если включено, на рендеринг будут выводиться только видимые для камеры поверхности блоков. Это может исключить большое количество поверхностей на ранней стадии отрисовки, экономя пропускную способность памяти и время для ГП. Некоторые наборы ресурсов могут иметь проблемы с этой опцией, поэтому попробуйте отключить её, если вы видите дыры в блоках.", + "sodium.options.use_fog_occlusion.name": "Окклюзия тумана", + "sodium.options.use_fog_occlusion.tooltip": "Если включено, чанки, определённые как полностью скрытые в тумане, не будут отображаться ради повышения производительности. Улучшение может быть более значительным, когда эффект тумана сильнее (например, под водой), но в некоторых сценах это может привести к нежелательным визуальным артефактам между небом и туманом.", + "sodium.options.use_entity_culling.name": "Отбраковка сущностей", + "sodium.options.use_entity_culling.tooltip": "Если включено, сущности, обнаруженные вне видимых чанков, не будут выводиться на рендеринг. Это может помочь улучшить производительность, исключив рендеринг сущностей, находящихся под землёй или за стенами.", + "sodium.options.use_particle_culling.name": "Отбраковка частиц", + "sodium.options.use_particle_culling.tooltip": "Если включено, будут отображаться только те частицы, которые определены как видимые. Это может обеспечить значительное улучшение частоты кадров, когда рядом находится много частиц.", + "sodium.options.animate_only_visible_textures.name": "Анимировать только видимое", + "sodium.options.animate_only_visible_textures.tooltip": "Если включено, будут обновляться лишь видимые анимированные текстуры. Это может значительно повысить частоту кадров на некоторых устройствах, особенно с \"тяжёлыми\" наборами ресурсов. Если у каких-то текстур возникают проблемы с анимацией, попробуйте отключить эту опцию.", + "sodium.options.cpu_render_ahead_limit.name": "Лимит подготовки кадров", + "sodium.options.cpu_render_ahead_limit.tooltip": "Задаёт максимальное количество кадров, которые ЦП может подготавливать для рендеринга на ГП. Очень низкие или высокие значения могут дестабилизировать частоту кадров.", + "sodium.options.cpu_render_ahead_limit.value": "Кадров: %s", + "sodium.options.allow_direct_memory_access.name": "Разрешить прямой доступ к памяти", + "sodium.options.allow_direct_memory_access.tooltip": "Если включено, некоторым важнейшим частям кода будет разрешено использовать прямой доступ к памяти для повышения производительности. Зачастую это сильно снижает накладные расходы на ЦП при рендеринге чанков и сущностей, но может усложнить диагностику некоторых ошибок и вылетов. Отключать это стоит, только если вы следуете инструкциям или точно знаете, что делаете.", + "sodium.options.enable_memory_tracing.name": "Включить трассировку памяти", + "sodium.options.enable_memory_tracing.tooltip": "Функция отладки. Если включено, трассировка стека будет собираться вместе с распределением памяти, чтобы помочь улучшить диагностическую информацию при обнаружении утечек памяти.", + "sodium.options.performance_impact_string": "Влияние на FPS: %s", + "sodium.options.use_persistent_mapping.name": "Постоянный буфер памяти", + "sodium.options.use_persistent_mapping.tooltip": "Если включено, небольшое количество памяти будет постоянно использоваться в качестве промежуточного буфера для загрузки чанков, помогая уменьшить накладные расходы на ЦП и нестабильность времени отрисовки кадра при их загрузке/выгрузке.\n\nТребуется OpenGL 4.4 или ARB_buffer_storage.", + "sodium.options.chunk_memory_allocator.name": "Распределение памяти", + "sodium.options.chunk_memory_allocator.tooltip": "Выбирает распределитель памяти, используемый для рендеринга чанков.\n- ASYNC: Быстрейший вариант, хорошо работает с большинством современных графических драйверов.\n- SWAP: Запасной вариант для старых графических драйверов. Может существенно увеличить использование памяти.", + "sodium.options.chunk_memory_allocator.async": "Async", + "sodium.options.chunk_memory_allocator.swap": "Swap", + "sodium.options.chunk_update_threads.name": "Потоки обновления чанков", + "sodium.options.chunk_update_threads.tooltip": "Задаёт количество потоков для сборки чанков. Использование большего количества потоков способствует повышению скорости обновления и загрузки чанков, но может негативно повлиять на время кадра.", + "sodium.options.always_defer_chunk_updates.name": "Всегда откладывать обновления", + "sodium.options.always_defer_chunk_updates.tooltip": "Если включено, рендеринг никогда не будет ожидать завершения обновлений чанков, даже если они важны. Это способствует сильному увеличению частоты кадров в некоторых ситуациях, но может привести к появлению существенных визуальных ошибок в мире.", + "sodium.options.buttons.undo": "Отмена", + "sodium.options.buttons.apply": "Применить", + "sodium.options.buttons.donate": "Угостите нас кофе!" +} \ No newline at end of file diff --git a/src/main/resources/assets/sodium/lang/zh_cn.json b/src/main/resources/assets/sodium/lang/zh_cn.json new file mode 100644 index 000000000..c5ca2765a --- /dev/null +++ b/src/main/resources/assets/sodium/lang/zh_cn.json @@ -0,0 +1,82 @@ +{ + "sodium.option_impact.low": "低", + "sodium.option_impact.medium": "中", + "sodium.option_impact.high": "高", + "sodium.option_impact.extreme": "极高", + "sodium.option_impact.varies": "视情况而定", + "sodium.options.pages.quality": "品质", + "sodium.options.pages.performance": "性能", + "sodium.options.pages.advanced": "高级", + "sodium.options.view_distance.tooltip": "渲染距离控制地形应被渲染至多远。更低的距离意味着更少的可见地形,也就有利于提升帧率。", + "sodium.options.simulation_distance.tooltip": "模拟距离控制加载事件/实体运算的距离。较短的距离可以减少内置服务端的负载,并可能提高帧率。", + "sodium.options.brightness.tooltip": "控制游戏画面的亮度(伽马值)。", + "sodium.options.clouds.name": "云", + "sodium.options.clouds.tooltip": "控制云是否可见。", + "sodium.options.gui_scale.tooltip": "设置界面尺寸比例。如果设置为“自动”,则使用可能的最大比例。", + "sodium.options.fullscreen.tooltip": "启用后,游戏将全屏显示(若支持)。", + "sodium.options.v_sync.tooltip": "启用后,游戏的帧率将与显示器的刷新率同步,从而在牺牲整体输入延迟的情况下获得更流畅的体验。如果设备配置过低,此设置可能会降低性能。", + "sodium.options.fps_limit.tooltip": "限制最大帧率。此选项有限制游戏渲染速度的的效果,因此开启此选项有利于提升电池续航或多任务处理。启用垂直同步时此选项会被自动忽略,除非该值低于显示器的刷新", + "sodium.options.view_bobbing.tooltip": "启用后,玩家在移动时的视角会摇晃摆动。禁用该选项可缓解晕动症症状。", + "sodium.options.attack_indicator.tooltip": "控制攻击指示器显示在屏幕上的位置。", + "sodium.options.autosave_indicator.tooltip": "启用后,当游戏在保存世界到磁盘时,就会显示一个指示器。", + "sodium.options.graphics_quality.tooltip": "默认图像品质控制一些原版选项,且对于Mod兼容性是必要的。若下方的选项保留为“默认”,则将会使用此选项的品质。", + "sodium.options.clouds_quality.tooltip": "控制云在空中的渲染品质。", + "sodium.options.weather_quality.tooltip": "控制雨、雪的渲染质量。", + "sodium.options.leaves_quality.name": "树叶", + "sodium.options.leaves_quality.tooltip": "控制树叶的渲染品质。", + "sodium.options.particle_quality.name": "粒子", + "sodium.options.particle_quality.tooltip": "控制每次可以在屏幕上出现的粒子的最大数量。", + "sodium.options.smooth_lighting.tooltip": "控制光照的平滑效果\n\n关 - 无平滑光照\n低 - 只平滑方块的光照\n高 (新!) - 平滑方块和实体的光照", + "sodium.options.biome_blend.value": "%s个方块", + "sodium.options.biome_blend.tooltip": "控制生物群系之间方块颜色的采样范围。较高的值会极大地增加渲染区块时因质量改进而所花费的时间。", + "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.use_chunk_multidraw.name": "使用区块多重绘制技术", + "sodium.options.use_chunk_multidraw.tooltip": "多重绘制技术允许使用较少的绘制调用渲染多个区块,大大减少了在渲染世界时的CPU开销,同时还可能更有效地利用GPU。这种优化可能会导致一些显卡驱动程序出现问题,所以如果您遇到故障,可以尝试禁用它。", + "sodium.options.use_vertex_objects.name": "使用顶点数组对象", + "sodium.options.use_vertex_objects.tooltip": "将关于如何渲染顶点数据的信息移动到驱动程序中来提高性能,使其能够更好地优化重复渲染相同对象的情况。通常情况下,除非使用了不兼容的模组,没有禁用它的理由。", + "sodium.options.use_block_face_culling.name": "启用方块表面剔除", + "sodium.options.use_block_face_culling.tooltip": "启用后,将只会渲染面向镜头的方块表面。 这可以在渲染过程的早期剔除大量方块表面,从而节省GPU上的内存带宽和时间。 某些资源包可能会遇到此选项的问题,因此如果你看到方块显示不全,请尝试禁用它。", + "sodium.options.use_compact_vertex_format.name": "使用紧凑型顶点格式", + "sodium.options.use_compact_vertex_format.tooltip": "如果启用,将使用更紧凑的顶点格式来渲染区块。这可以显著减少图形内存使用和带宽需求,尤其是对于集成显卡而言。但是,由于它减少了位置和纹理坐标属性的精度,可能会导致一些资源包出现深度冲突问题。", + "sodium.options.use_fog_occlusion.name": "启用迷雾遮挡", + "sodium.options.use_fog_occlusion.tooltip": "启用后,被迷雾效果完全隐藏的区块将不会被渲染,有助于提高性能。 当迷雾效果较重时(例如在水下时),改进可能会更加显着,但在某些情况下可能会导致天空和雾之间出现不良的视觉伪影。", + "sodium.options.use_entity_culling.name": "启用实体剔除", + "sodium.options.use_entity_culling.tooltip": "启用后,则在渲染期间跳过在不可见区块的实体。 这可以通过避免渲染位于地下或墙后的实体来帮助提高性能。", + "sodium.options.use_particle_culling.name": "启用颗粒剔除", + "sodium.options.use_particle_culling.tooltip": "启用后,将仅渲染可见的颗粒。当周围有许多颗粒时,这可以显著地提高帧率。", + "sodium.options.animate_only_visible_textures.name": "仅渲染可见的动态材质", + "sodium.options.animate_only_visible_textures.tooltip": "启用后,将只会更新可见的动画材质。 这可以显着提高某些低配电脑的帧率。 尤其是对于较大的资源包。因此如果你看到动态材质不生效,请尝试禁用此选项。", + "sodium.options.translucency_sorting.name": "透明度排序", + "sodium.options.translucency_sorting.tooltip": "启用后,透明方块将被正确排序,从后向前渲染,以提供更好的渲染效果,特别是当你的视野中有多个重叠的透明方块时。此操作在性能上相对较昂贵。", + "sodium.options.cpu_render_ahead_limit.name": "CPU提前渲染限制", + "sodium.options.cpu_render_ahead_limit.tooltip": "指定CPU可以在GPU上等待完成渲染的最大帧数。很低或很高的值可能会导致帧速率不稳定。", + "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.ignore_driver_blacklist.name": "忽略驱动程序黑名单", + "sodium.options.ignore_driver_blacklist.tooltip": "如果启用,将忽略与您的硬件/驱动程序配置已知的不兼容性,允许您启用可能会导致游戏问题的选项。通常情况下,除非您完全知道自己在做什么,否则不应该触碰这个选项。在更改此选项后,您必须保存、关闭,然后重新打开设置屏幕。", + "sodium.options.enable_memory_tracing.name": "启用内存跟踪", + "sodium.options.enable_memory_tracing.tooltip": "调试功能。 启用后,堆栈追踪将与内存分配一起收集,以帮助在检测到内存泄漏时改进诊断信息。", + "sodium.options.performance_impact_string": "性能影响:%s", + "sodium.options.use_persistent_mapping.name": "启用持久映射区域", + "sodium.options.use_persistent_mapping.tooltip": "启用后, 将少量内存一直作为区块刷新的映射缓冲区,有助于减少加载或更新区块时的CPU占用及帧率不稳定。\n\n需要OpenGL4.4或ARB_buffer_storge。", + "sodium.options.chunk_memory_allocator.name": "区块内存分配器", + "sodium.options.chunk_memory_allocator.tooltip": "选择区块渲染的内存分配器。\n-异步:最快的选项,适合大多数现代图形显示驱动。\n-交换:旧图形显示驱动的备用选项。可能会显著增加内存占用。", + "sodium.options.chunk_memory_allocator.async": "异步", + "sodium.options.chunk_memory_allocator.swap": "交换", + "sodium.options.chunk_update_threads.name": "区块更新线程数", + "sodium.options.chunk_update_threads.tooltip": "指定用于区块构建的线程数。使用更多线程可以提高区块加载/更新速度,但可能会对帧速率有负面影响。", + "sodium.options.always_defer_chunk_updates.name": "延迟区块更新", + "sodium.options.always_defer_chunk_updates.tooltip": "启用后,渲染将不会等待区块更新完成,即使它们很重要。这可以在某些场景中大大提升帧速率,但可能会在世界中造成显著的视觉滞后", + "sodium.options.use_no_error_context.name": "使用无错误上下文", + "sodium.options.use_no_error_context.tooltip": "如果启用,OpenGL上下文将被创建时禁用错误检查。这可能会略微提高性能,但也增加了游戏崩溃而不是优雅处理OpenGL错误的风险。如果您遇到无法解释的突发崩溃,应禁用此选项。", + "sodium.options.threads.value": "%s 线程", + "sodium.options.default": "默认", + "sodium.options.buttons.undo": "撤销", + "sodium.options.buttons.apply": "应用", + "sodium.options.buttons.donate": "给JellySquid买杯咖啡!" +} diff --git a/src/main/resources/assets/sodium/shaders/chunk_gl20.f.glsl b/src/main/resources/assets/sodium/shaders/chunk_gl20.f.glsl new file mode 100644 index 000000000..c9649f24c --- /dev/null +++ b/src/main/resources/assets/sodium/shaders/chunk_gl20.f.glsl @@ -0,0 +1,54 @@ +#version 110 + +varying vec4 v_Color; // The interpolated vertex color +varying vec2 v_TexCoord; // The interpolated block texture coordinates +varying vec2 v_LightCoord; // The interpolated light map texture coordinates + +uniform sampler2D u_BlockTex; // The block texture sampler +uniform sampler2D u_LightTex; // The light map texture sampler + +#ifdef USE_FOG +varying float v_FragDistance; +uniform vec4 u_FogColor; // The color of the fog +#endif + +#ifdef USE_FOG_EXP2 +uniform float u_FogDensity; + +// e^(-density * c^2) +float getFogFactor() { + float dist = v_FragDistance * u_FogDensity; + return 1.0 / exp2(dist * dist); +} +#endif + +#ifdef USE_FOG_LINEAR +uniform float u_FogLength; // FogStart - FogEnd +uniform float u_FogEnd; + +// (end - dist) / (end - start) +float getFogFactor() { + return (u_FogEnd - v_FragDistance) / u_FogLength; +} +#endif + +void main() { + // Block texture sample + vec4 sampleBlockTex = texture2D(u_BlockTex, v_TexCoord); + + // Light map texture sample + vec4 sampleLightTex = texture2D(u_LightTex, v_LightCoord); + + // Blend the colors from both textures and the vertex itself + vec4 diffuseColor = sampleBlockTex * sampleLightTex * v_Color; + +#ifdef USE_FOG + float fogFactor = clamp(getFogFactor(), 0.0, 1.0); + + gl_FragColor = mix(u_FogColor, diffuseColor, fogFactor); + gl_FragColor.a = diffuseColor.a; +#else + // No fog is being used, so the fragment color is just that of the blended texture color + gl_FragColor = diffuseColor; +#endif +} diff --git a/src/main/resources/assets/sodium/shaders/chunk_gl20.v.glsl b/src/main/resources/assets/sodium/shaders/chunk_gl20.v.glsl new file mode 100644 index 000000000..9732b17b6 --- /dev/null +++ b/src/main/resources/assets/sodium/shaders/chunk_gl20.v.glsl @@ -0,0 +1,40 @@ +#version 110 +attribute vec3 a_Pos; // The position of the vertex +attribute vec4 a_Color; // The color of the vertex +attribute vec2 a_TexCoord; // The block texture coordinate of the vertex +attribute vec2 a_LightCoord; // The light map texture coordinate of the vertex + +varying vec4 v_Color; +varying vec2 v_TexCoord; +varying vec2 v_LightCoord; + +#ifdef USE_FOG +varying float v_FragDistance; +#endif + +uniform mat4 u_ModelViewProjectionMatrix; +uniform vec3 u_ModelScale; +uniform vec2 u_TextureScale; + +// The model translation for this draw call. +attribute vec4 d_ModelOffset; + +void main() { + // Translates the vertex position around the position of the camera + // This can be used to calculate the distance of the vertex from the camera without needing to + // transform it into model-view space with a matrix, which is much slower. + vec3 pos = (a_Pos * u_ModelScale) + d_ModelOffset.xyz; + +#ifdef USE_FOG + v_FragDistance = length(pos); +#endif + + // Transform the vertex position into model-view-projection space + gl_Position = u_ModelViewProjectionMatrix * vec4(pos, 1.0); + + // Pass the color and texture coordinates to the fragment shader + v_Color = a_Color; + v_TexCoord = a_TexCoord * u_TextureScale; + v_LightCoord = a_LightCoord; +} + diff --git a/src/main/resources/assets/sodium/textures/gui/arrows.png b/src/main/resources/assets/sodium/textures/gui/arrows.png new file mode 100644 index 0000000000000000000000000000000000000000..01161492cb7771ebafee21ca018171d35883c91c GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`cAhSdAr_~TfBgUdzn)Er(QK>F z4wa6JJmw7(6n{LK!J(=0#7cx&LQ+!lqG*Ef;VcHb)(YN*CSq;}H5LF3mcO9>c}JMa QSD;A@p00i_>zopr0E Date: Sat, 4 Nov 2023 21:53:51 -0700 Subject: [PATCH 033/301] 1.7.10ify --- .../compat/forge/ForgeBlockRenderer.java | 37 +- .../compat/forge/IForgeBakedModel.java | 23 ++ .../compat/forge/IForgeBlockState.java | 5 + .../compat/forge/IForgeVertexBuilder.java | 5 + .../angelica/compat/forge/IModelData.java | 5 + .../compat/forge}/SinkingVertexBuilder.java | 18 +- .../compat/forge/VertexBufferConsumer.java | 8 + .../compat/forge/VertexLighterFlat.java | 26 ++ .../compat/forge/VertexLighterSmoothAo.java | 11 + .../angelica/compat/mojang/BakedModel.java | 15 + .../angelica/compat/mojang/BakedQuad.java | 21 + .../angelica/compat/mojang/Biome.java | 5 + .../angelica/compat/mojang/BiomeAccess.java | 7 + .../compat/mojang/BiomeAccessType.java | 6 + .../compat/mojang/BlockColorProvider.java | 5 + .../angelica/compat/mojang/BlockColors.java | 5 + .../angelica/compat/mojang/BlockPos.java | 71 ++++ .../compat/mojang/BlockRenderType.java | 7 + .../compat/mojang/BlockRenderView.java | 23 ++ .../angelica/compat/mojang/BlockState.java | 49 +++ .../angelica/compat/mojang/BlockView.java | 6 + .../angelica/compat/mojang/BufferBuilder.java | 34 +- .../angelica/compat/mojang/BufferSource.java | 4 +- .../angelica/compat/mojang/Camera.java | 10 + .../angelica/compat/mojang/ChunkCuller.java | 5 + .../compat/mojang/ChunkOcclusionData.java | 35 ++ .../compat/mojang/ChunkSectionPos.java | 48 +++ .../angelica/compat/mojang/ColorResolver.java | 6 + .../compat/mojang/DefaultVertexFormat.java | 12 +- .../angelica/compat/mojang/GameRenderer.java | 4 +- .../angelica/compat/mojang/LevelRenderer.java | 2 +- .../angelica/compat/mojang/LightType.java | 12 + .../{PoseStack.java => MatrixStack.java} | 56 +-- .../compat/mojang/MultiBufferSource.java | 4 +- .../compat/mojang/PackedIntegerArray.java | 5 + .../{RenderType.java => RenderLayer.java} | 16 +- ...RenderStateShard.java => RenderPhase.java} | 6 +- .../compat/mojang/VertexConsumer.java | 32 +- .../angelica/compat/mojang/VoxelShape.java | 8 + .../angelica/compat/mojang/VoxelShapes.java | 12 + .../angelica/compat/mojang/WorldRenderer.java | 8 + .../angelica/glsm/GLStateManager.java | 22 ++ .../angelica/glsm/states/Color4.java | 9 + .../angelica/glsm/states/FogState.java | 11 + .../gtnewhorizons/angelica/mixins/Mixins.java | 2 +- .../notfine/settings/MixinGameSettings.java | 2 +- .../{startup => }/MixinFramebuffer.java | 2 +- .../renderer/MixinLayeredTexture.java | 2 +- .../mixins/early/textures/ISpriteExt.java | 14 + .../textures/MixinTextureAtlasSprite.java | 6 +- .../transform/GLStateManagerTransformer.java | 2 +- .../mods/sodium/client/RubidiumStub.java | 14 - .../mods/sodium/client/SodiumClientMod.java | 28 +- .../client/buffer/ExtendedVertexFormat.java | 4 +- .../sodium/client/compat/FlywheelCompat.java | 32 -- .../sodium/client/compat/ccl/CCLCompat.java | 84 ---- .../compat/modernui/MuiGuiScaleHook.java | 45 --- .../gl/attribute/BufferVertexFormat.java | 2 +- .../gl/attribute/GlVertexAttributeFormat.java | 8 +- .../sodium/client/gl/buffer/GlBuffer.java | 4 +- .../client/gl/buffer/GlBufferTarget.java | 14 +- .../client/gl/buffer/GlBufferUsage.java | 20 +- .../sodium/client/gl/compat/FogHelper.java | 56 ++- .../client/gl/device/DrawCommandList.java | 3 +- .../client/gl/device/GLRenderDevice.java | 22 +- .../client/gl/func/GlBufferCopyFunctions.java | 8 +- .../sodium/client/gl/func/GlFunctions.java | 6 +- .../gl/func/GlIndirectMultiDrawFunctions.java | 20 +- .../gl/func/GlInstancedArrayFunctions.java | 8 +- .../gl/func/GlVertexArrayFunctions.java | 12 +- .../sodium/client/gl/shader/GlProgram.java | 29 +- .../sodium/client/gl/shader/GlShader.java | 21 +- .../sodium/client/gl/shader/ShaderLoader.java | 10 +- .../sodium/client/gl/shader/ShaderType.java | 6 +- .../client/gl/shader/ShaderWorkarounds.java | 53 --- .../client/gl/state/GlStateTracker.java | 19 +- .../tessellation/GlAbstractTessellation.java | 7 +- .../tessellation/GlFallbackTessellation.java | 4 +- .../gl/tessellation/GlPrimitiveType.java | 8 +- .../client/gl/util/GlMultiDrawBatch.java | 18 +- .../client/gl/util/MemoryUtilHelper.java | 28 -- .../client/gui/SodiumGameOptionPages.java | 366 ------------------ .../sodium/client/gui/SodiumGameOptions.java | 149 ------- .../sodium/client/gui/SodiumOptionsGUI.java | 316 --------------- .../gui/options/FormattedTextProvider.java | 7 - .../sodium/client/gui/options/Option.java | 35 -- .../sodium/client/gui/options/OptionFlag.java | 7 - .../client/gui/options/OptionGroup.java | 39 -- .../client/gui/options/OptionImpact.java | 24 -- .../sodium/client/gui/options/OptionImpl.java | 217 ----------- .../sodium/client/gui/options/OptionPage.java | 45 --- .../client/gui/options/TextProvider.java | 5 - .../gui/options/binding/GenericBinding.java | 24 -- .../gui/options/binding/OptionBinding.java | 7 - .../compat/VanillaBooleanOptionBinding.java | 23 -- .../client/gui/options/control/Control.java | 12 - .../gui/options/control/ControlElement.java | 58 --- .../control/ControlValueFormatter.java | 47 --- .../gui/options/control/CyclingControl.java | 121 ------ .../gui/options/control/SliderControl.java | 164 -------- .../gui/options/control/TickBoxControl.java | 94 ----- .../storage/MinecraftOptionsStorage.java | 25 -- .../gui/options/storage/OptionStorage.java | 7 - .../options/storage/SodiumOptionsStorage.java | 30 -- .../client/gui/widgets/AbstractWidget.java | 77 ---- .../client/gui/widgets/FlatButtonWidget.java | 76 ---- .../client/model/ModelCuboidAccessor.java | 7 - .../client/model/light/EntityLighter.java | 22 +- .../client/model/light/LightPipeline.java | 8 +- .../light/cache/ArrayLightDataCache.java | 6 +- .../model/light/cache/HashLightDataCache.java | 7 +- .../model/light/data/LightDataAccess.java | 32 +- .../model/light/flat/FlatLightPipeline.java | 13 +- .../client/model/light/smooth/AoFaceData.java | 20 +- .../model/light/smooth/AoNeighborInfo.java | 20 +- .../light/smooth/SmoothLightPipeline.java | 36 +- .../sodium/client/model/quad/ModelQuad.java | 8 +- .../client/model/quad/ModelQuadView.java | 6 +- .../model/quad/ModelQuadViewMutable.java | 6 +- .../model/quad/blender/BiomeColorBlender.java | 14 +- .../quad/blender/BlockColorSettings.java | 8 +- .../blender/ConfigurableColorBlender.java | 16 +- .../blender/DefaultBlockColorSettings.java | 3 +- .../quad/blender/FlatBiomeColorBlender.java | 8 +- .../quad/blender/SmoothBiomeColorBlender.java | 10 +- .../quad/properties/ModelQuadFacing.java | 6 +- .../model/quad/properties/ModelQuadFlags.java | 22 +- .../client/model/vertex/VertexDrain.java | 2 +- .../client/model/vertex/VertexSink.java | 2 +- .../vertex/buffer/VertexBufferBuilder.java | 6 +- .../buffer/VertexBufferWriterUnsafe.java | 1 - .../vertex/fallback/VertexWriterFallback.java | 3 +- .../vertex/formats/glyph/GlyphVertexSink.java | 8 +- .../vertex/formats/glyph/GlyphVertexType.java | 5 +- .../writer/GlyphVertexBufferWriterUnsafe.java | 1 - .../writer/GlyphVertexWriterFallback.java | 3 +- .../vertex/formats/line/LineVertexSink.java | 6 +- .../vertex/formats/line/LineVertexType.java | 5 +- .../writer/LineVertexBufferWriterUnsafe.java | 1 - .../line/writer/LineVertexWriterFallback.java | 3 +- .../formats/particle/ParticleVertexSink.java | 7 +- .../formats/particle/ParticleVertexType.java | 4 +- .../ParticleVertexBufferWriterUnsafe.java | 1 - .../writer/ParticleVertexWriterFallback.java | 3 +- .../vertex/formats/quad/QuadVertexSink.java | 13 +- .../vertex/formats/quad/QuadVertexType.java | 5 +- .../writer/QuadVertexBufferWriterUnsafe.java | 1 - .../quad/writer/QuadVertexWriterFallback.java | 3 +- .../BasicScreenQuadVertexSink.java | 8 +- .../BasicScreenQuadVertexType.java | 5 +- ...sicScreenQuadVertexBufferWriterUnsafe.java | 1 - .../BasicScreenQuadVertexWriterFallback.java | 3 +- .../SpriteTexturedVertexTransformer.java | 10 +- .../model/vertex/type/VanillaVertexType.java | 2 +- .../client/model/vertex/type/VertexType.java | 2 +- .../client/render/GameRendererContext.java | 7 +- .../client/render/SodiumWorldRenderer.java | 83 ++-- .../render/chunk/ChunkRenderBackend.java | 2 +- .../render/chunk/ChunkRenderColumn.java | 30 +- .../render/chunk/ChunkRenderContainer.java | 8 +- .../render/chunk/ChunkRenderManager.java | 38 +- .../multidraw/ChunkDrawCallBatcher.java | 41 +- .../multidraw/ChunkDrawParamsVector.java | 50 +-- .../IndirectCommandBufferVector.java | 8 +- .../MultidrawChunkRenderBackend.java | 34 +- .../backends/multidraw/StructBuffer.java | 13 +- .../oneshot/ChunkRenderBackendOneshot.java | 21 +- .../chunk/compile/ChunkBufferSorter.java | 45 +-- .../chunk/compile/ChunkBuildBuffers.java | 3 +- .../render/chunk/compile/ChunkBuilder.java | 20 +- .../client/render/chunk/cull/ChunkCuller.java | 5 +- .../chunk/cull/graph/ChunkGraphCuller.java | 28 +- .../chunk/cull/graph/ChunkGraphNode.java | 18 +- .../render/chunk/data/ChunkRenderBounds.java | 2 +- .../render/chunk/data/ChunkRenderData.java | 35 +- .../hfp/HFPModelVertexBufferWriterUnsafe.java | 1 - .../chunk/format/hfp/HFPModelVertexType.java | 5 +- .../sfp/SFPModelVertexBufferWriterUnsafe.java | 1 - .../chunk/format/sfp/SFPModelVertexType.java | 3 +- .../render/chunk/passes/BlockRenderPass.java | 12 +- .../chunk/passes/BlockRenderPassManager.java | 13 +- .../chunk/region/ChunkRegionManager.java | 2 +- .../render/chunk/shader/ChunkProgram.java | 21 +- .../shader/ChunkRenderShaderBackend.java | 15 +- .../chunk/shader/ChunkShaderFogComponent.java | 8 +- .../chunk/tasks/ChunkRenderRebuildTask.java | 49 +-- .../ChunkRenderTranslucencySortTask.java | 9 +- .../render/entity/EntityLightSampler.java | 2 +- .../render/occlusion/BlockOcclusionCache.java | 20 +- .../client/render/pipeline/BlockRenderer.java | 62 +-- .../render/pipeline/ChunkRenderCache.java | 4 +- .../client/render/pipeline/FluidRenderer.java | 116 +++--- .../context/ChunkRenderCacheLocal.java | 5 +- .../context/ChunkRenderCacheShared.java | 6 +- .../client/render/texture/SpriteUtil.java | 4 +- .../sodium/client/util/ModelQuadUtil.java | 8 +- .../mods/sodium/client/util/Norm3b.java | 36 +- .../client/util/color/FastCubicSampler.java | 34 +- .../client/util/math/Matrix3fExtended.java | 19 +- .../client/util/math/Matrix4fExtended.java | 1 - .../sodium/client/util/math/MatrixUtil.java | 8 +- .../mods/sodium/client/world/WorldSlice.java | 80 ++-- .../sodium/client/world/WorldSliceLocal.java | 29 +- .../sodium/client/world/biome/BiomeCache.java | 8 +- .../client/world/biome/BiomeColorCache.java | 18 +- .../world/biome/BlockColorsExtended.java | 4 +- .../world/biome/ItemColorsExtended.java | 1 - .../world/cloned/ChunkRenderContext.java | 10 +- .../world/cloned/ClonedChunkSection.java | 29 +- .../world/cloned/ClonedChunkSectionCache.java | 2 +- .../cloned/PalettedContainerExtended.java | 4 +- .../cloned/palette/ClonedPaletteFallback.java | 1 - .../sodium/common/config/SodiumConfig.java | 2 - .../sodium/common/util/DirectionUtil.java | 29 +- .../mods/sodium/mixin/SodiumMixinPlugin.java | 95 ----- .../sodium/mixin/core/MixinDirection.java | 66 ---- .../mixin/core/frustum/MixinFrustum.java | 115 ------ .../mixin/core/matrix/MixinGameRenderer.java | 17 - .../mixin/core/matrix/MixinMatrix3f.java | 229 ----------- .../mixin/core/matrix/MixinMatrix4f.java | 313 --------------- .../mixin/core/model/MixinBlockColors.java | 39 -- .../mixin/core/model/MixinItemColors.java | 40 -- .../mixin/core/pipeline/MixinBakedQuad.java | 102 ----- .../core/pipeline/MixinBufferBuilder.java | 117 ------ .../core/pipeline/MixinVertexConsumer.java | 15 - .../core/pipeline/MixinVertexFormat.java | 17 - .../block/MixinBlockModelRenderer.java | 105 ----- .../features/block/MixinWorldRenderer.java | 27 -- .../fast_advance/MixinBufferBuilder.java | 56 --- .../fast_advance/MixinVertexFormat.java | 55 --- .../fast_sort/MixinBufferBuilder.java | 180 --------- .../intrinsics/MixinBufferBuilder.java | 94 ----- .../MixinSpriteTexturedVertexConsumer.java | 41 -- .../intrinsics/MixinWorldRenderer.java | 114 ------ .../chunk_rendering/MixinChunkBuilder.java | 15 - .../MixinClientChunkManager.java | 143 ------- .../chunk_rendering/MixinClientWorld.java | 34 -- .../MixinPackedIntegerArray.java | 49 --- .../MixinPalettedContainer.java | 45 --- .../chunk_rendering/MixinRenderLayer.java | 24 -- .../chunk_rendering/MixinWorldRenderer.java | 171 -------- .../mixin/features/debug/MixinDebugHud.java | 79 ---- .../entity/fast_render/MixinCuboid.java | 19 - .../entity/fast_render/MixinModelPart.java | 70 ---- .../smooth_lighting/MixinEntityRenderer.java | 51 --- .../MixinPaintingEntityRenderer.java | 59 --- .../MixinBackgroundRenderer.java | 24 -- .../fast_biome_colors/MixinBlock.java | 17 - .../fast_biome_colors/MixinFluid.java | 16 - .../mixin/features/gui/MixinDebugHud.java | 133 ------- .../fast_fps_pie/MixinMinecraftClient.java | 43 -- .../MixinLevelLoadingScreen.java | 132 ------- .../gui/fast_status_bars/MixinInGameHud.java | 60 --- .../features/gui/font/MixinGlyphRenderer.java | 75 ---- .../features/item/MixinItemRenderer.java | 124 ------ .../matrix_stack/MixinMatrixStack.java | 47 --- .../matrix_stack/MixinVertexConsumer.java | 48 --- .../model/MixinMultipartBakedModel.java | 82 ---- .../model/MixinWeightedBakedModel.java | 60 --- .../optimized_bamboo/MixinBambooBlock.java | 22 -- .../features/options/MixinGameOptions.java | 34 -- .../features/options/MixinInGameHud.java | 15 - .../options/MixinMinecraftClient.java | 19 - .../features/options/MixinOptionsScreen.java | 27 -- .../features/options/MixinWorldRenderer.java | 16 - .../fast_render/MixinBillboardParticle.java | 120 ------ .../MixinTexturedRenderLayers.java | 34 -- .../render_layer/leaves/MixinLeavesBlock.java | 27 -- .../leaves/MixinRenderLayers.java | 54 --- .../features/sky/MixinWorldRenderer.java | 57 --- .../texture_tracking/MixinSprite.java | 84 ---- .../MixinSpriteAtlasTexture.java | 21 - .../MixinSpriteBillboardParticle.java | 40 -- .../world_ticking/MixinClientWorld.java | 111 ------ .../impl/BufferSegment.java | 8 +- .../impl/FullyBufferedMultiBufferSource.java | 28 +- .../OldFullyBufferedMultiBufferSource.java | 24 +- .../impl/RenderTypeUtil.java | 4 +- .../impl/SegmentedBufferBuilder.java | 12 +- .../impl/WrappableRenderType.java | 4 +- .../GraphTranslucencyRenderOrderManager.java | 28 +- .../impl/ordering/RenderOrderManager.java | 6 +- .../ordering/SimpleRenderOrderManager.java | 8 +- .../TranslucencyRenderOrderManager.java | 16 +- .../wrappers/TaggingRenderTypeWrapper.java | 14 +- .../block_rendering/BlockMaterialMapping.java | 8 +- .../BlockRenderingSettings.java | 8 +- .../fantastic/WrappingMultiBufferSource.java | 4 +- .../net/coderbot/iris/gl/shader/GlShader.java | 1 + .../layer/BlockEntityRenderStateShard.java | 4 +- .../iris/layer/EntityRenderStateShard.java | 4 +- .../layer/IsBlockEntityRenderStateShard.java | 4 +- .../iris/layer/IsEntityRenderStateShard.java | 4 +- .../iris/layer/IsOutlineRenderStateShard.java | 4 +- .../iris/layer/OuterWrappedRenderType.java | 20 +- .../coderbot/iris/pipeline/HandRenderer.java | 14 +- .../iris/pipeline/HorizonRenderer.java | 24 +- .../iris/pipeline/ShadowRenderer.java | 32 +- .../iris/pipeline/WorldRenderingPhase.java | 14 +- .../coderbot/iris/shadow/ShadowMatrices.java | 20 +- .../iris/uniforms/MatrixUniforms.java | 2 +- 301 files changed, 1706 insertions(+), 7632 deletions(-) rename src/main/java/{me/jellysquid/mods/sodium/client => com/gtnewhorizons/angelica}/compat/forge/ForgeBlockRenderer.java (76%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBakedModel.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBlockState.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeVertexBuilder.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/IModelData.java rename src/main/java/{me/jellysquid/mods/sodium/client/compat/ccl => com/gtnewhorizons/angelica/compat/forge}/SinkingVertexBuilder.java (90%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterSmoothAo.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/Biome.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColors.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkCuller.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightType.java rename src/main/java/com/gtnewhorizons/angelica/compat/mojang/{PoseStack.java => MatrixStack.java} (50%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java rename src/main/java/com/gtnewhorizons/angelica/compat/mojang/{RenderType.java => RenderLayer.java} (62%) rename src/main/java/com/gtnewhorizons/angelica/compat/mojang/{RenderStateShard.java => RenderPhase.java} (82%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRenderer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java rename src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/{startup => }/MixinFramebuffer.java (93%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/ISpriteExt.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/RubidiumStub.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/compat/FlywheelCompat.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/CCLCompat.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/compat/modernui/MuiGuiScaleHook.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderWorkarounds.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gl/util/MemoryUtilHelper.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/FormattedTextProvider.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/SodiumMixinPlugin.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/MixinDirection.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/frustum/MixinFrustum.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinGameRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix3f.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix4f.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinBlockColors.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinItemColors.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBufferBuilder.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexConsumer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexFormat.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinBlockModelRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinBufferBuilder.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinVertexFormat.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_sort/MixinBufferBuilder.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinBufferBuilder.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinSpriteTexturedVertexConsumer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinWorldRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinChunkBuilder.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientChunkManager.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientWorld.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPackedIntegerArray.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPalettedContainer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinRenderLayer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinCuboid.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinModelPart.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinEntityRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinPaintingEntityRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBackgroundRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBlock.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinFluid.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/MixinDebugHud.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_fps_pie/MixinMinecraftClient.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_loading_screen/MixinLevelLoadingScreen.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_status_bars/MixinInGameHud.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/font/MixinGlyphRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/item/MixinItemRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinMatrixStack.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinVertexConsumer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinMultipartBakedModel.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinWeightedBakedModel.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/optimized_bamboo/MixinBambooBlock.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinGameOptions.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinInGameHud.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinMinecraftClient.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinOptionsScreen.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinWorldRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/particle/fast_render/MixinBillboardParticle.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/MixinTexturedRenderLayers.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinLeavesBlock.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinRenderLayers.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/sky/MixinWorldRenderer.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSprite.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteAtlasTexture.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteBillboardParticle.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/mixin/features/world_ticking/MixinClientWorld.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compat/forge/ForgeBlockRenderer.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeBlockRenderer.java similarity index 76% rename from src/main/java/me/jellysquid/mods/sodium/client/compat/forge/ForgeBlockRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeBlockRenderer.java index 71538df9f..d7a4149f7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compat/forge/ForgeBlockRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeBlockRenderer.java @@ -1,26 +1,20 @@ -package me.jellysquid.mods.sodium.client.compat.forge; +package com.gtnewhorizons.angelica.compat.forge; +import com.gtnewhorizons.angelica.compat.mojang.BakedModel; +import com.gtnewhorizons.angelica.compat.mojang.BakedQuad; +import com.gtnewhorizons.angelica.compat.mojang.BlockColors; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.model.light.LightMode; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; import me.jellysquid.mods.sodium.client.render.occlusion.BlockOcclusionCache; import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.block.BlockState; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.BlockRenderView; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.client.model.pipeline.VertexBufferConsumer; -import net.minecraftforge.client.model.pipeline.VertexLighterFlat; -import net.minecraftforge.client.model.pipeline.VertexLighterSmoothAo; -import net.minecraftforge.common.ForgeConfig; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraftforge.common.util.ForgeDirection; import java.util.List; import java.util.Random; @@ -32,7 +26,8 @@ * it may be replaced in an existing copy of Embeddium with an alternate LGPL-2.1 implementation. */ public class ForgeBlockRenderer { - private final BlockColors colors = MinecraftClient.getInstance().getBlockColors(); + // TODO: Sodium + private final BlockColors colors = null; //Minecraft.getMinecraft().getBlockColors(); private final ThreadLocal lighterFlat = ThreadLocal.withInitial(() -> new VertexLighterFlat(colors)); private final ThreadLocal lighterSmooth = ThreadLocal.withInitial(() -> new VertexLighterSmoothAo(colors)); private final ThreadLocal consumerFlat = ThreadLocal.withInitial(VertexBufferConsumer::new); @@ -42,7 +37,7 @@ public class ForgeBlockRenderer { private static boolean useForgeLightingPipeline = false; public static void init() { - useForgeLightingPipeline = ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.get(); + useForgeLightingPipeline = true;//ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.get(); } public static boolean useForgeLightingPipeline() { @@ -51,7 +46,7 @@ public static boolean useForgeLightingPipeline() { private void processQuad(ChunkRenderData.Builder renderData, BakedQuad quad) { ModelQuadView src = (ModelQuadView)quad; - Sprite sprite = src.rubidium$getSprite(); + TextureAtlasSprite sprite = src.rubidium$getSprite(); if (sprite != null) { renderData.addSprite(sprite); @@ -86,7 +81,7 @@ public boolean renderBlock(LightMode mode, BlockState state, BlockPos pos, Block } } - for(Direction side : DirectionUtil.ALL_DIRECTIONS) + for(ForgeDirection side : DirectionUtil.ALL_DIRECTIONS) { random.setSeed(seed); quads = model.getQuads(state, side, random, data); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBakedModel.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBakedModel.java new file mode 100644 index 000000000..01a7eb8a8 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBakedModel.java @@ -0,0 +1,23 @@ +package com.gtnewhorizons.angelica.compat.forge; + +import com.gtnewhorizons.angelica.compat.mojang.BakedModel; +import com.gtnewhorizons.angelica.compat.mojang.BakedQuad; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import net.minecraftforge.common.util.ForgeDirection; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Random; + +public interface IForgeBakedModel { + default BakedModel getBakedModel() + { + return (BakedModel) this; + } + + default List getQuads(@Nullable BlockState state, @Nullable ForgeDirection side, @NotNull Random rand, @NotNull IModelData extraData) + { + return getBakedModel().getQuads(state, side, rand); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBlockState.java new file mode 100644 index 000000000..679700acb --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBlockState.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.compat.forge; + +public interface IForgeBlockState { + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeVertexBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeVertexBuilder.java new file mode 100644 index 000000000..83f9f066c --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeVertexBuilder.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.compat.forge; + +public interface IForgeVertexBuilder { + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IModelData.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IModelData.java new file mode 100644 index 000000000..fb2ed15d0 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IModelData.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.compat.forge; + +public interface IModelData { + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/SinkingVertexBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/SinkingVertexBuilder.java similarity index 90% rename from src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/SinkingVertexBuilder.java rename to src/main/java/com/gtnewhorizons/angelica/compat/forge/SinkingVertexBuilder.java index f873714b8..90943951e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/SinkingVertexBuilder.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/SinkingVertexBuilder.java @@ -1,13 +1,11 @@ -package me.jellysquid.mods.sodium.client.compat.ccl; +package com.gtnewhorizons.angelica.compat.forge; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.util.math.Direction; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.util.ForgeDirection; import javax.annotation.Nonnull; import java.nio.ByteBuffer; @@ -20,7 +18,7 @@ * * @author KitsuneAlex */ -@OnlyIn(Dist.CLIENT) + public final class SinkingVertexBuilder implements VertexConsumer { private final ByteBuffer buffer = ByteBuffer.allocateDirect(2097152).order(ByteOrder.nativeOrder()); private final int[] sideCount = new int[ModelQuadFacing.VALUES.length]; @@ -38,7 +36,7 @@ public final class SinkingVertexBuilder implements VertexConsumer { private int light; private static final ThreadLocal instance = ThreadLocal.withInitial(SinkingVertexBuilder::new); - + @Nonnull public static SinkingVertexBuilder getInstance() { return instance.get(); @@ -93,7 +91,7 @@ public VertexConsumer normal(float x, float y, float z) { @Override public void next() { - final Direction dir = Direction.fromVector((int) nx, (int) ny, (int) nz); + final ForgeDirection dir = DirectionUtil.fromVector((int) nx, (int) ny, (int) nz); final int normal = dir != null ? dir.ordinal() : -1; // Write the current quad vertex's normal, position, UVs, color and raw light values @@ -123,7 +121,7 @@ public void flush(@Nonnull ChunkModelBuffers buffers) { for (int quadIdx = 0; quadIdx < numQuads; quadIdx++) { final int normal = buffer.getInt((quadIdx << 2) << 5); - final Direction dir = normal != -1 ? DirectionUtil.ALL_DIRECTIONS[normal] : null; + final ForgeDirection dir = normal != -1 ? DirectionUtil.ALL_DIRECTIONS[normal] : null; final ModelQuadFacing facing = dir != null ? ModelQuadFacing.fromDirection(dir) : ModelQuadFacing.UNASSIGNED; sideCount[facing.ordinal()]++; } @@ -143,7 +141,7 @@ public void flush(@Nonnull ChunkModelBuffers buffers) { while (buffer.position() < byteSize) { final int normal = buffer.getInt(); // Fetch first normal for pre-selecting the vertex sink - final Direction dir = normal != -1 ? DirectionUtil.ALL_DIRECTIONS[normal] : null; + final ForgeDirection dir = normal != -1 ? DirectionUtil.ALL_DIRECTIONS[normal] : null; final ModelQuadFacing facing = dir != null ? ModelQuadFacing.fromDirection(dir) : ModelQuadFacing.UNASSIGNED; final int facingIdx = facing.ordinal(); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java new file mode 100644 index 000000000..8da39c532 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java @@ -0,0 +1,8 @@ +package com.gtnewhorizons.angelica.compat.forge; + +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; + +public class VertexBufferConsumer { + + public void setBuffer(VertexConsumer buffer) {} +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java new file mode 100644 index 000000000..34a303342 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java @@ -0,0 +1,26 @@ +package com.gtnewhorizons.angelica.compat.forge; + +import com.gtnewhorizons.angelica.compat.mojang.BlockColors; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; + +public class VertexLighterFlat { + + public VertexLighterFlat(BlockColors colors) {} + + public void setParent(VertexBufferConsumer consumer) {} + + public void setTransform(MatrixStack.Entry peek) {} + + public void setWorld(BlockRenderView world) {} + + public void setState(BlockState state) {} + + public void setBlockPos(BlockPos pos) {} + + public void updateBlockInfo() {} + + public void resetBlockInfo() {} +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterSmoothAo.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterSmoothAo.java new file mode 100644 index 000000000..b1eba3495 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterSmoothAo.java @@ -0,0 +1,11 @@ +package com.gtnewhorizons.angelica.compat.forge; + +import com.gtnewhorizons.angelica.compat.mojang.BlockColors; + +public class VertexLighterSmoothAo extends VertexLighterFlat { + + public VertexLighterSmoothAo(BlockColors colors) { + super(colors); + + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java new file mode 100644 index 000000000..50089a5fc --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java @@ -0,0 +1,15 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import com.gtnewhorizons.angelica.compat.forge.IForgeBakedModel; +import com.gtnewhorizons.angelica.compat.forge.IModelData; +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.List; +import java.util.Random; + +public interface BakedModel extends IForgeBakedModel { + + List getQuads(BlockState state, ForgeDirection face, Random random); + + IModelData getModelData(BlockRenderView world, BlockPos pos, BlockState state, IModelData modelData); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java new file mode 100644 index 000000000..3eee1d139 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java @@ -0,0 +1,21 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import com.gtnewhorizons.angelica.compat.forge.VertexLighterFlat; +import net.minecraftforge.common.util.ForgeDirection; + +public class BakedQuad { + + public void pipe(VertexLighterFlat lighter) {} + + public boolean hasColor() { + return true; + } + + public ForgeDirection getFace() { + return ForgeDirection.UNKNOWN; + } + + public boolean hasShade() { + return true; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Biome.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Biome.java new file mode 100644 index 000000000..8f7c8f6d4 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Biome.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class Biome { + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java new file mode 100644 index 000000000..3b2424ba1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java @@ -0,0 +1,7 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class BiomeAccess { + public interface Storage { + Biome getBiomeForNoiseGen(int biomeX, int biomeY, int biomeZ); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java new file mode 100644 index 000000000..404f49182 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java @@ -0,0 +1,6 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public interface BiomeAccessType { + + Biome getBiome(long seed, int x, int y, int z, BiomeAccess.Storage storage); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java new file mode 100644 index 000000000..be4697e2b --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class BlockColorProvider { + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColors.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColors.java new file mode 100644 index 000000000..f2f9cca47 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColors.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class BlockColors { + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java new file mode 100644 index 000000000..c9d71a364 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java @@ -0,0 +1,71 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import net.minecraft.util.MathHelper; +import org.joml.Vector3i; + +import java.math.RoundingMode; + +import static com.google.common.math.IntMath.log2; + +public class BlockPos extends Vector3i { + + private static final int SIZE_BITS_X = 1 + log2(MathHelper.roundUpToPowerOfTwo(30000000), RoundingMode.UNNECESSARY); + private static final int SIZE_BITS_Z = SIZE_BITS_X; + private static final int SIZE_BITS_Y = 64 - SIZE_BITS_X - SIZE_BITS_Z; + private static final long BITS_X = (1L << SIZE_BITS_X) - 1L; + private static final long BITS_Y = (1L << SIZE_BITS_Y) - 1L; + private static final long BITS_Z = (1L << SIZE_BITS_Z) - 1L; + private static final int BIT_SHIFT_Z = SIZE_BITS_Y; + private static final int BIT_SHIFT_X = SIZE_BITS_Y + SIZE_BITS_Z; + + public BlockPos() { + super(); + } + public BlockPos(int x, int y, int z) { + super(x, y, z); + } + + public int getX() { + return this.x; + } + public int getY() { + return this.y; + } + public int getZ() { + return this.z; + } + + public BlockPos set(int x, int y, int z) { + super.set(x, y, z); + return this; + } + + public long asLong() { + return asLong(this.x, this.y, this.z); + } + + public static long asLong(int x, int y, int z) { + long l = 0L; + l |= ((long)x & BITS_X) << BIT_SHIFT_X; + l |= ((long)y & BITS_Y) << 0; + l |= ((long)z & BITS_Z) << BIT_SHIFT_Z; + return l; + } + + + public static int unpackLongX(long packedPos) { + return (int)(packedPos << 64 - BIT_SHIFT_X - SIZE_BITS_X >> 64 - SIZE_BITS_X); + } + + public static int unpackLongY(long packedPos) { + return (int)(packedPos << 64 - SIZE_BITS_Y >> 64 - SIZE_BITS_Y); + } + + public static int unpackLongZ(long packedPos) { + return (int)(packedPos << 64 - BIT_SHIFT_Z - SIZE_BITS_Z >> 64 - SIZE_BITS_Z); + } + + public static class Mutable extends BlockPos { + + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java new file mode 100644 index 000000000..aced71efd --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java @@ -0,0 +1,7 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public enum BlockRenderType { + INVISIBLE, + ENTITYBLOCK_ANIMATED, + MODEL +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java new file mode 100644 index 000000000..8915878a1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java @@ -0,0 +1,23 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +public interface BlockRenderView extends BlockView { + + float getBrightness(ForgeDirection face, boolean shade); + + LightingProvider getLightingProvider(); + + TileEntity getBlockEntity(BlockPos pos); + + int getColor(BlockPos pos, ColorResolver resolver); + + int getLightLevel(LightType type, BlockPos pos); + + int getBaseLightLevel(BlockPos pos, int ambientDarkness); + + boolean isSkyVisible(BlockPos pos); + + Biome getBiomeForNoiseGen(int x, int y, int z); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java new file mode 100644 index 000000000..30db9e694 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java @@ -0,0 +1,49 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import com.gtnewhorizons.angelica.compat.forge.IForgeBlockState; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import org.joml.Vector3d; + +public class BlockState implements IForgeBlockState { + + public boolean isSideInvisible(BlockState adjState, ForgeDirection facing) { + return false; + } + + public boolean isOpaque() { + return true; + } + + public VoxelShape getCullingFace(BlockView view, BlockPos pos, ForgeDirection facing) { + return null; + } + + public int getLightValue(BlockRenderView world, BlockPos pos) { return 15;} + + public float getAmbientOcclusionLightLevel(BlockRenderView world, BlockPos pos) { return 1.0f; } + + public boolean hasEmissiveLighting(BlockRenderView world, BlockPos pos) { + return false; + } + + public boolean shouldBlockVision(BlockRenderView world, BlockPos pos) { return true;} + + public int getOpacity(BlockRenderView world, BlockPos pos) { + return 15; + } + + public boolean isOpaqueFullCube(World world, BlockPos pos) { + return true; + } + + public boolean isFullCube(BlockRenderView world, BlockPos pos) { return true; } + + public Vector3d getModelOffset(BlockRenderView world, BlockPos pos) { + return null; + } + + public boolean isAir() { + return false; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java new file mode 100644 index 000000000..363712fbe --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java @@ -0,0 +1,6 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public interface BlockView { + + BlockState getBlockState(BlockPos adjPos); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java index 2945a92cd..cbf8fe9d4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java @@ -2,11 +2,13 @@ import net.coderbot.batchedentityrendering.impl.BufferBuilderExt; import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.NotNull; import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; import java.util.List; +// This is the Tessellator - TODO: Merge/Overwrite public class BufferBuilder implements VertexConsumer, BufferBuilderExt { private ByteBuffer buffer; private List vertexCounts; @@ -37,8 +39,38 @@ public VertexConsumer vertex(double d, double e, double f) { return null; } + @NotNull @Override - public void endVertex() { + public VertexConsumer color(int r, int g, int b, int a) { + return null; + } + + @NotNull + @Override + public VertexConsumer texture(float u, float v) { + return null; + } + + @NotNull + @Override + public VertexConsumer overlay(int u, int v) { + return null; + } + + @NotNull + @Override + public VertexConsumer light(int u, int v) { + return null; + } + + @NotNull + @Override + public VertexConsumer normal(float x, float y, float z) { + return null; + } + + @Override + public void next() { } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java index 260b1615a..9322f68f2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java @@ -6,9 +6,9 @@ public class BufferSource implements MultiBufferSource { public BufferSource(BufferBuilder bufferBuilder, Map kvMap) {} - public VertexConsumer getBuffer(RenderType renderType) { + public VertexConsumer getBuffer(RenderLayer renderType) { return null; } public void endBatch() {} - public void endBatch(RenderType type) {} + public void endBatch(RenderLayer type) {} } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java index 38ac41ea6..8e0c9e03c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java @@ -1,5 +1,7 @@ package com.gtnewhorizons.angelica.compat.mojang; +import org.joml.Vector3d; + public class Camera { public boolean isDetached() { @@ -9,4 +11,12 @@ public boolean isDetached() { public Object getEntity() { return null; } + + public BlockPos getBlockPos() { + return new BlockPos(); + } + + public Vector3d getPos() { + return new Vector3d(); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkCuller.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkCuller.java new file mode 100644 index 000000000..0a1e84b6d --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkCuller.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public interface ChunkCuller { + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java new file mode 100644 index 000000000..4e138ef84 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java @@ -0,0 +1,35 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.BitSet; +import java.util.EnumSet; + +public class ChunkOcclusionData { + private static final int DIRECTION_COUNT = ForgeDirection.values().length; + private final BitSet visibility; + + public ChunkOcclusionData() { + this.visibility = new BitSet(DIRECTION_COUNT * DIRECTION_COUNT); + } + + public void addOpenEdgeFaces(EnumSet faces) { + for (ForgeDirection dirFrom : faces) { + for (ForgeDirection dirTo : faces) { + this.setVisibleThrough(dirFrom, dirTo, true); + } + } + + for (ForgeDirection direction : faces) { + this.visibility.set(direction.ordinal() * DIRECTION_COUNT + direction.ordinal()); + } + } + public void setVisibleThrough(ForgeDirection from, ForgeDirection to, boolean visible) { + this.visibility.set(from.ordinal() + to.ordinal() * DIRECTION_COUNT, visible); + this.visibility.set(to.ordinal() + from.ordinal() * DIRECTION_COUNT, visible); + } + + public boolean isVisibleThrough(ForgeDirection from, ForgeDirection to) { + return this.visibility.get(from.ordinal() + to.ordinal() * DIRECTION_COUNT); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java new file mode 100644 index 000000000..5c27d7d88 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java @@ -0,0 +1,48 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import org.joml.Vector3i; + +public class ChunkSectionPos extends Vector3i { + private ChunkSectionPos(int x, int y, int z) { + super(x, y, z); + } + public static ChunkSectionPos from(int x, int y, int z) { + return new ChunkSectionPos(x, y, z); + } + + + public static long asLong(int x, int y, int z) { + long l = 0L; + l |= ((long)x & 4194303L) << 42; + l |= ((long)y & 1048575L) << 0; + l |= ((long)z & 4194303L) << 20; + return l; + } + public long asLong() { + return asLong(this.x, this.y, this.z); + } + + public int getMinX() { + return this.x << 4; + } + + public int getMinY() { + return this.y << 4; + } + + public int getMinZ() { + return this.z << 4; + } + + public int getMaxX() { + return (this.x << 4) + 15; + } + + public int getMaxY() { + return (this.y << 4) + 15; + } + + public int getMaxZ() { + return (this.z << 4) + 15; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java new file mode 100644 index 000000000..19c413049 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java @@ -0,0 +1,6 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public interface ColorResolver { + + int getColor(Biome biome, int x, int z); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java index 379988b31..15cf10852 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java @@ -13,8 +13,18 @@ public class DefaultVertexFormat { public static final VertexFormatElement ELEMENT_UV2 = new VertexFormatElement(2, Type.SHORT, Usage.UV, 2); public static final VertexFormatElement ELEMENT_NORMAL = new VertexFormatElement(0, Type.BYTE, Usage.NORMAL, 3); public static final VertexFormatElement ELEMENT_PADDING = new VertexFormatElement(0, Type.BYTE, Usage.PADDING, 1); - + public static final VertexFormat BLOCK = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV0).add(ELEMENT_UV2).add(ELEMENT_NORMAL).add(ELEMENT_PADDING).build()); + public static final VertexFormat NEW_ENTITY = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV0).add(ELEMENT_UV1).add(ELEMENT_UV2).add(ELEMENT_NORMAL).add(ELEMENT_PADDING).build()); + public static final VertexFormat PARTICLE = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_UV0).add(ELEMENT_COLOR).add(ELEMENT_UV2).build()); public static final VertexFormat POSITION = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).build()); + public static final VertexFormat POSITION_COLOR = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).build()); + public static final VertexFormat POSITION_COLOR_LIGHTMAP = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV2).build()); public static final VertexFormat POSITION_TEX = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_UV0).build()); + public static final VertexFormat POSITION_COLOR_TEX = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV0).build()); + public static final VertexFormat POSITION_TEX_COLOR = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_UV0).add(ELEMENT_COLOR).build()); + public static final VertexFormat POSITION_COLOR_TEX_LIGHTMAP = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV0).add(ELEMENT_UV2).build()); + public static final VertexFormat POSITION_TEX_LIGHTMAP_COLOR = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_UV0).add(ELEMENT_UV2).add(ELEMENT_COLOR).build()); + public static final VertexFormat POSITION_TEX_COLOR_NORMAL = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_UV0).add(ELEMENT_COLOR).add(ELEMENT_NORMAL).add(ELEMENT_PADDING).build()); + } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java index 9552d1531..26523a9fa 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java @@ -2,9 +2,9 @@ public class GameRenderer { - public void invokeBobHurt(PoseStack poseStack, float tickDelta) {} + public void invokeBobHurt(MatrixStack poseStack, float tickDelta) {} - public void invokeBobView(PoseStack poseStack, float tickDelta) {} + public void invokeBobView(MatrixStack poseStack, float tickDelta) {} public boolean getRenderHand() { return true; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LevelRenderer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LevelRenderer.java index 87f38bd5f..af3781168 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LevelRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LevelRenderer.java @@ -2,5 +2,5 @@ public class LevelRenderer { - public void invokeRenderChunkLayer(RenderType solid, PoseStack modelView, double cameraX, double cameraY, double cameraZ) {} + public void invokeRenderChunkLayer(RenderLayer solid, MatrixStack modelView, double cameraX, double cameraY, double cameraZ) {} } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightType.java new file mode 100644 index 000000000..ced4e7ef5 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightType.java @@ -0,0 +1,12 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public enum LightType { + SKY(15), + BLOCK(0); + + public final int value; + + LightType(int value) { + this.value = value; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PoseStack.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java similarity index 50% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/PoseStack.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java index a6e0d42cd..5c2bcb1be 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PoseStack.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java @@ -6,56 +6,56 @@ import java.util.Deque; -public class PoseStack { - private final Deque poseStack; +public class MatrixStack { + private final Deque matrixStack; - public PoseStack() { - this.poseStack = Queues.newArrayDeque(); - poseStack.add(new Pose(new Matrix4f().identity(), new Matrix3f().identity())); + public MatrixStack() { + this.matrixStack = Queues.newArrayDeque(); + matrixStack.add(new Entry(new Matrix4f().identity(), new Matrix3f().identity())); } - public Pose last() { - return (Pose)this.poseStack.getLast(); + public Entry peek() { + return (Entry)this.matrixStack.getLast(); } public void pushPose() { - final Pose lv = (Pose)this.poseStack.getLast(); - this.poseStack.addLast(new Pose(new Matrix4f(lv.pose), new Matrix3f(lv.normal))); + final Entry lv = (Entry)this.matrixStack.getLast(); + this.matrixStack.addLast(new Entry(new Matrix4f(lv.model), new Matrix3f(lv.normal))); } public void popPose() { - this.poseStack.removeLast(); + this.matrixStack.removeLast(); } public boolean clear() { - return this.poseStack.size() == 1; + return this.matrixStack.size() == 1; } public void translate(double d, double e, double f) { - final Pose lv = (Pose)this.poseStack.getLast(); - lv.pose.translate((float)d, (float)e, (float)f); + final Entry lv = (Entry)this.matrixStack.getLast(); + lv.model.translate((float)d, (float)e, (float)f); } public void rotateX(float f) { - final Pose lv = (Pose)this.poseStack.getLast(); - lv.pose.rotateX(f); + final Entry lv = (Entry)this.matrixStack.getLast(); + lv.model.rotateX(f); lv.normal.rotateX(f); } public void rotateY(float f) { - final Pose lv = (Pose)this.poseStack.getLast(); - lv.pose.rotateY(f); + final Entry lv = (Entry)this.matrixStack.getLast(); + lv.model.rotateY(f); lv.normal.rotateY(f); } public void rotateZ(float f) { - final Pose lv = (Pose)this.poseStack.getLast(); - lv.pose.rotateZ(f); + final Entry lv = (Entry)this.matrixStack.getLast(); + lv.model.rotateZ(f); lv.normal.rotateZ(f); } public void scale(float f, float g, float h) { - final Pose lv = (Pose)this.poseStack.getLast(); - lv.pose.scale(f, g, h); + final Entry lv = (Entry)this.matrixStack.getLast(); + lv.model.scale(f, g, h); if (f == g && g == h) { if (f > 0.0F) { @@ -82,20 +82,20 @@ private static float invSqrt(float x) { return x; } - public static final class Pose { - private final Matrix4f pose; + public static final class Entry { + private final Matrix4f model; private final Matrix3f normal; - private Pose(Matrix4f pose, Matrix3f normal) { - this.pose = pose; + private Entry(Matrix4f model, Matrix3f normal) { + this.model = model; this.normal = normal; } - public Matrix4f pose() { - return pose; + public Matrix4f getModel() { + return model; } - public Matrix3f normal() { + public Matrix3f getNormal() { return normal; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java index 67d192e76..6377c95a5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java @@ -3,9 +3,9 @@ import java.util.Map; public interface MultiBufferSource { - static BufferSource immediateWithBuffers(Map map, BufferBuilder arg) { + static BufferSource immediateWithBuffers(Map map, BufferBuilder arg) { return new BufferSource(arg, map); } - VertexConsumer getBuffer(RenderType arg); + VertexConsumer getBuffer(RenderLayer arg); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java new file mode 100644 index 000000000..5818decf3 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class PackedIntegerArray { + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java similarity index 62% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderType.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java index ab2609a0e..9de27c46e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderType.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java @@ -2,27 +2,27 @@ import java.util.Optional; -public abstract class RenderType { +public abstract class RenderLayer { // Aka: RenderType (Iris) - public RenderType(String name, VertexFormat format, int mode, int i, Object o, boolean b, Runnable setupRenderState, Runnable clearRenderState) {} + public RenderLayer(String name, VertexFormat format, int mode, int i, Object o, boolean b, Runnable setupRenderState, Runnable clearRenderState) {} - public static RenderType solid() { + public static RenderLayer solid() { return null; } - public static RenderType cutout() { + public static RenderLayer cutout() { return null; } - public static RenderType cutoutMipped() { + public static RenderLayer cutoutMipped() { return null; } - public static RenderType translucent() { + public static RenderLayer translucent() { return null; } - public static RenderType tripwire() { + public static RenderLayer tripwire() { return null; } @@ -52,7 +52,7 @@ public Object affectsCrumbling() { return null; } - public Optional outline() { + public Optional outline() { return Optional.empty(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderStateShard.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java similarity index 82% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderStateShard.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index e48aacbfe..7d0aae037 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderStateShard.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -2,12 +2,12 @@ import javax.annotation.Nullable; -public abstract class RenderStateShard { +public abstract class RenderPhase { protected final String name; protected Runnable setupState; protected final Runnable clearState; - public RenderStateShard(String name, Runnable setupState, Runnable clearState) { + public RenderPhase(String name, Runnable setupState, Runnable clearState) { this.name = name; this.setupState = setupState; this.clearState = clearState; @@ -17,7 +17,7 @@ public boolean equals(@Nullable Object object) { if (this == object) { return true; } else if (object != null && this.getClass() == object.getClass()) { - final RenderStateShard lv = (RenderStateShard)object; + final RenderPhase lv = (RenderPhase)object; return this.name.equals(lv.name); } else { return false; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java index 156ef1286..ce0b3573b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java @@ -1,7 +1,35 @@ package com.gtnewhorizons.angelica.compat.mojang; -public interface VertexConsumer { +import com.gtnewhorizons.angelica.compat.forge.IForgeVertexBuilder; + +import javax.annotation.Nonnull; + +public interface VertexConsumer extends IForgeVertexBuilder { VertexConsumer vertex(double d, double e, double f); - void endVertex(); + + @Nonnull + VertexConsumer color(int r, int g, int b, int a); + + @Nonnull + VertexConsumer texture(float u, float v); + + @Nonnull + VertexConsumer overlay(int u, int v); + + @Nonnull + VertexConsumer light(int u, int v); + + @Nonnull + VertexConsumer normal(float x, float y, float z); + + void next(); + + default VertexConsumer overlay(int overlay) { + return this.overlay(overlay & 0xFFFF, overlay >> 16 & 0xFFFF); + } + + default VertexConsumer light(int light) { + return this.light(light & 0xFFFF, light >> 16 & 0xFFFF); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java new file mode 100644 index 000000000..7da3c011b --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java @@ -0,0 +1,8 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class VoxelShape { + + public boolean isEmpty() { + return false; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java new file mode 100644 index 000000000..c01f128de --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java @@ -0,0 +1,12 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public final class VoxelShapes { + + public static VoxelShape fullCube() { + return null; + } + + public static boolean matchesAnywhere(VoxelShape shape1, VoxelShape shape2, Object predicate) { + return false; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRenderer.java new file mode 100644 index 000000000..b1102a7d7 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRenderer.java @@ -0,0 +1,8 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class WorldRenderer { + public static int getLightmapCoordinates(BlockRenderView world, BlockState state, BlockPos pos) { + return 15; + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index f707d2ee4..679a770b0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -3,7 +3,9 @@ import com.gtnewhorizons.angelica.glsm.states.AlphaState; import com.gtnewhorizons.angelica.glsm.states.BlendState; import com.gtnewhorizons.angelica.glsm.states.BooleanState; +import com.gtnewhorizons.angelica.glsm.states.Color4; import com.gtnewhorizons.angelica.glsm.states.DepthState; +import com.gtnewhorizons.angelica.glsm.states.FogState; import com.gtnewhorizons.angelica.glsm.states.GLColorMask; import com.gtnewhorizons.angelica.glsm.states.TextureState; import lombok.Getter; @@ -38,6 +40,10 @@ public class GLStateManager { @Getter private static final DepthState Depth = new DepthState(); @Getter + private static final FogState Fog = new FogState(); + @Getter + private static final Color4 Color = new Color4(); + @Getter private static final GLColorMask ColorMask = new GLColorMask(); @Getter private static final BooleanState Cull = new BooleanState(GL11.GL_CULL_FACE); @@ -148,6 +154,22 @@ public static void glDepthMask(boolean mask) { GL11.glDepthMask(mask); } } + public static void glColor4f(float red, float green, float blue, float alpha) { + if(red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { + Color.red = red; + Color.green = green; + Color.blue = blue; + Color.alpha = alpha; + GL11.glColor4f(red, green, blue, alpha); + } + } + + public static void clearCurrentColor() { + Color.red = -1.0F; + Color.green = -1.0F; + Color.blue = -1.0F; + Color.alpha = -1.0F; + } public static void glColorMask(boolean red, boolean green, boolean blue, boolean alpha) { // Iris diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java new file mode 100644 index 000000000..c86b0af44 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java @@ -0,0 +1,9 @@ +package com.gtnewhorizons.angelica.glsm.states; + +public class Color4 { + public float red = 1.0F; + public float green = 1.0F; + public float blue = 1.0F; + public float alpha = 1.0F; + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java new file mode 100644 index 000000000..cd2a24082 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java @@ -0,0 +1,11 @@ +package com.gtnewhorizons.angelica.glsm.states; + +import org.lwjgl.opengl.GL11; + +public class FogState { + public BooleanState mode = new BooleanState(GL11.GL_FOG); + public int fogMode = GL11.GL_EXP; + public float density = 1.0F; + public float start; + public float end = 1.0F; +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 944a728f5..fcb691fa0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -12,13 +12,13 @@ public enum Mixins { IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( - "shaders.startup.MixinFramebuffer", "shaders.startup.MixinGameSettings", "shaders.startup.MixinGuiMainMenu", "shaders.startup.MixinInitRenderer") ), IRIS_RENDERING(new Builder("Iris Shaders").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( + "shaders.startup.MixinFramebuffer", "shaders.MixinEntityRenderer", "shaders.MixinItem", "shaders.MixinOpenGlHelper" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java index 39e89d25b..1f693654e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java @@ -18,7 +18,7 @@ public abstract class MixinGameSettings { private static String[] GUISCALES = new String[] { "options.guiScale.auto", "options.guiScale.small", - "options.guiScale.normal", + "options.guiScale.getNormal", "options.guiScale.large", "options.guiScale.massive" }; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinFramebuffer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java similarity index 93% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinFramebuffer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java index 4a15f7538..038f5153d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinFramebuffer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.shaders.startup; +package com.gtnewhorizons.angelica.mixins.early.shaders; import net.coderbot.iris.rendertarget.IRenderTargetExt; import net.minecraft.client.shader.Framebuffer; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java index 3bb04399f..0b9587c02 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java @@ -20,7 +20,7 @@ public class MixinLayeredTexture { /** * @author glowredman - * @reason must take normal and specular maps into account + * @reason must take getNormal and specular maps into account */ @Overwrite public void loadTexture(IResourceManager p_110551_1_) throws IOException { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/ISpriteExt.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/ISpriteExt.java new file mode 100644 index 000000000..238496054 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/ISpriteExt.java @@ -0,0 +1,14 @@ +package com.gtnewhorizons.angelica.mixins.early.textures; + +import net.minecraft.client.resources.data.AnimationMetadataSection; + +public interface ISpriteExt { + + boolean isAnimation(); + + int getFrame(); + + void callUpload(int frameIndex); + + AnimationMetadataSection getMetadata(); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java index 34bbb54d0..a93dc8472 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java @@ -6,23 +6,27 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(TextureAtlasSprite.class) -public abstract class MixinTextureAtlasSprite { +public abstract class MixinTextureAtlasSprite implements ISpriteExt { @Shadow private AnimationMetadataSection animationMetadata; @Shadow protected int frameCounter; + @Override public boolean isAnimation() { return animationMetadata != null && animationMetadata.getFrameCount() > 1; } + @Override public int getFrame() { return frameCounter; } + @Override public void callUpload(int frameIndex) {} + @Override public AnimationMetadataSection getMetadata() { return animationMetadata; } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index c6b8d0403..e554f0041 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -33,7 +33,7 @@ public class GLStateManagerTransformer implements IClassTransformer { public static final Map> EnabledRedirects = ImmutableMap.of( GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", - "glColorMask", "glAlphaFunc", "glDrawArrays") + "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor4f") ,GL13, Sets.newHashSet("glActiveTexture") ,GL14, Sets.newHashSet("glBlendFuncSeparate") ,EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") diff --git a/src/main/java/me/jellysquid/mods/sodium/client/RubidiumStub.java b/src/main/java/me/jellysquid/mods/sodium/client/RubidiumStub.java deleted file mode 100644 index 1900bc2fa..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/RubidiumStub.java +++ /dev/null @@ -1,14 +0,0 @@ -package me.jellysquid.mods.sodium.client; - -import net.minecraftforge.fml.ExtensionPoint; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.network.FMLNetworkConstants; -import org.apache.commons.lang3.tuple.Pair; - -@Mod("rubidium") -public class RubidiumStub { - public RubidiumStub() { - ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index e6b609587..564a38a56 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -1,20 +1,16 @@ package me.jellysquid.mods.sodium.client; -import me.jellysquid.mods.sodium.client.compat.ccl.CCLCompat; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; -import net.minecraftforge.fml.ExtensionPoint; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.fml.loading.FMLPaths; -import net.minecraftforge.fml.network.FMLNetworkConstants; +import com.gtnewhorizons.angelica.Tags; +import cpw.mods.fml.common.Mod; import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -@Mod(SodiumClientMod.MODID) +@Mod(modid = SodiumClientMod.MODID, + name = SodiumClientMod.NAME, + version = Tags.VERSION, + acceptedMinecraftVersions = "[1.7.10]", + acceptableRemoteVersions = "*") public class SodiumClientMod { private static SodiumGameOptions CONFIG; public static Logger LOGGER = LogManager.getLogger("Embeddium"); @@ -22,9 +18,7 @@ public class SodiumClientMod { private static String MOD_VERSION; public static final String MODID = "embeddium"; - - public static boolean flywheelLoaded; - public static boolean cclLoaded; + public static final String NAME = "Embeddium"; public SodiumClientMod() { FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onInitializeClient); @@ -33,13 +27,7 @@ public SodiumClientMod() { } public void onInitializeClient(final FMLClientSetupEvent event) { - flywheelLoaded = ModList.get().isLoaded("flywheel"); - cclLoaded = ModList.get().isLoaded("codechickenlib"); MOD_VERSION = ModList.get().getModContainerById(MODID).get().getModInfo().getVersion().toString(); - - if(cclLoaded) { - CCLCompat.init(); - } } public static SodiumGameOptions options() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java index 92812e043..6f64f7bc6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.buffer; -import net.minecraft.client.render.VertexFormatElement; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement; public interface ExtendedVertexFormat { Element[] embeddium$getExtendedElements(); @@ -16,4 +16,4 @@ public Element(VertexFormatElement actual, int increment, int byteLength) { this.byteLength = byteLength; } } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compat/FlywheelCompat.java b/src/main/java/me/jellysquid/mods/sodium/client/compat/FlywheelCompat.java deleted file mode 100644 index 9f631cbae..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/compat/FlywheelCompat.java +++ /dev/null @@ -1,32 +0,0 @@ -package me.jellysquid.mods.sodium.client.compat; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.block.entity.BlockEntity; - -import java.util.Collection; - -public class FlywheelCompat { - - /** - * Filters a collection of TileEntities to avoid rendering conflicts with Flywheel. - * - * @param blockEntities The collection to be filtered. - */ - public static void filterBlockEntityList(Collection blockEntities) { - if (SodiumClientMod.flywheelLoaded && Backend.getInstance().canUseInstancing()) { - InstancedRenderRegistry r = InstancedRenderRegistry.getInstance(); - blockEntities.removeIf(r::shouldSkipRender); - } - } - - public static boolean isSkipped(BlockEntity be) { - if(!SodiumClientMod.flywheelLoaded) - return false; - if(!Backend.getInstance().canUseInstancing()) - return false; - return InstancedRenderRegistry.getInstance().shouldSkipRender(be); - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/CCLCompat.java b/src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/CCLCompat.java deleted file mode 100644 index ad275a559..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/compat/ccl/CCLCompat.java +++ /dev/null @@ -1,84 +0,0 @@ -package me.jellysquid.mods.sodium.client.compat.ccl; - -import codechicken.lib.render.block.BlockRenderingRegistry; -import codechicken.lib.render.block.ICCBlockRenderer; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.fluid.Fluid; -import net.minecraft.fluid.FluidState; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; -import net.minecraftforge.registries.IRegistryDelegate; -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class CCLCompat { - - public static Map, ICCBlockRenderer> customBlockRenderers; - public static Map, ICCBlockRenderer> customFluidRenderers; - public static List customGlobalRenderers; - - public static @NotNull List getCustomRenderers(final @NotNull BlockRenderView world, final @NotNull BlockPos pos) { - final BlockState state = world.getBlockState(pos); - final Block block = state.getBlock(); - - final FluidState fluidState = state.getFluidState(); - final Fluid fluid = fluidState.getFluid(); - - if(customGlobalRenderers == null) - return new ArrayList<>(); - - final ArrayList renderers = new ArrayList<>(customGlobalRenderers); - - if(customBlockRenderers != null) - for (final Map.Entry, ICCBlockRenderer> entry : customBlockRenderers.entrySet()) { - final Block entryBlock = entry.getKey().get(); - - if (entryBlock.is(block)) { - renderers.add(entry.getValue()); - } - } - - if(customFluidRenderers != null) - for (final Map.Entry, ICCBlockRenderer> entry : customFluidRenderers.entrySet()) { - final Fluid entryFluid = entry.getKey().get(); - - if (entryFluid.matchesType(fluid)) { - renderers.add(entry.getValue()); - } - } - - return renderers; - } - - - @SuppressWarnings("unchecked") - public static void init() { - try { - SodiumClientMod.LOGGER.info("Retrieving block renderers"); - final Field blockRenderersField = BlockRenderingRegistry.class.getDeclaredField("blockRenderers"); - blockRenderersField.setAccessible(true); - customBlockRenderers = (Map, ICCBlockRenderer>) blockRenderersField.get(null); - - SodiumClientMod.LOGGER.info("Retrieving fluid renderers"); - final Field fluidRenderersField = BlockRenderingRegistry.class.getDeclaredField("fluidRenderers"); - fluidRenderersField.setAccessible(true); - customFluidRenderers = (Map, ICCBlockRenderer>) fluidRenderersField.get(null); - - SodiumClientMod.LOGGER.info("Retrieving global renderers"); - final Field globalRenderersField = BlockRenderingRegistry.class.getDeclaredField("globalRenderers"); - globalRenderersField.setAccessible(true); - customGlobalRenderers = (List) globalRenderersField.get(null); - } - catch (final @NotNull Throwable t) { - SodiumClientMod.LOGGER.error("Could not retrieve custom renderers"); - } - - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/compat/modernui/MuiGuiScaleHook.java b/src/main/java/me/jellysquid/mods/sodium/client/compat/modernui/MuiGuiScaleHook.java deleted file mode 100644 index 4c8c9d551..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/compat/modernui/MuiGuiScaleHook.java +++ /dev/null @@ -1,45 +0,0 @@ -package me.jellysquid.mods.sodium.client.compat.modernui; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.client.MinecraftClient; - -import java.lang.reflect.Method; -import java.util.stream.Stream; - -/** - * Ugly hack to get around Modern UI overwriting calculateScaleFactor and not conforming to vanilla standards - * by returning the max size when scale = 0. - */ -public class MuiGuiScaleHook { - private static final Method calcGuiScalesMethod; - static { - calcGuiScalesMethod = Stream.of("icyllis.modernui.forge.MForgeCompat", "icyllis.modernui.forge.MuiForgeApi").flatMap(clzName -> { - try { - return Stream.of(Class.forName(clzName)); - } catch(Throwable e) { - return Stream.of(); - } - }).flatMap(clz -> { - try { - Method m = clz.getDeclaredMethod("calcGuiScales"); - m.setAccessible(true); - return Stream.of(m); - } catch(Throwable e) { - return Stream.of(); - } - }).findFirst().orElse(null); - if(calcGuiScalesMethod != null) - SodiumClientMod.logger().info("Found ModernUI GUI scale hook"); - } - public static int getMaxGuiScale() { - if(calcGuiScalesMethod != null) { - try { - return ((int)calcGuiScalesMethod.invoke(null)) & 0xf; - } catch(Throwable e) { - e.printStackTrace(); - } - } - // default vanilla logic - return MinecraftClient.getInstance().getWindow().calculateScaleFactor(0, MinecraftClient.getInstance().forcesUnicodeFont()); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java index 344656465..e5c05565d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.gl.attribute; -import net.minecraft.client.render.VertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; public interface BufferVertexFormat { static BufferVertexFormat from(VertexFormat format) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java index 09e5b5e67..43324e3eb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.client.gl.attribute; -import org.lwjgl.opengl.GL20C; +import org.lwjgl.opengl.GL11; /** * An enumeration over the supported data types that can be used for vertex attributes. */ public class GlVertexAttributeFormat { - public static final GlVertexAttributeFormat FLOAT = new GlVertexAttributeFormat(GL20C.GL_FLOAT, 4); - public static final GlVertexAttributeFormat UNSIGNED_SHORT = new GlVertexAttributeFormat(GL20C.GL_UNSIGNED_SHORT, 2); - public static final GlVertexAttributeFormat UNSIGNED_BYTE = new GlVertexAttributeFormat(GL20C.GL_UNSIGNED_BYTE, 1); + public static final GlVertexAttributeFormat FLOAT = new GlVertexAttributeFormat(GL11.GL_FLOAT, 4); + public static final GlVertexAttributeFormat UNSIGNED_SHORT = new GlVertexAttributeFormat(GL11.GL_UNSIGNED_SHORT, 2); + public static final GlVertexAttributeFormat UNSIGNED_BYTE = new GlVertexAttributeFormat(GL11.GL_UNSIGNED_BYTE, 1); private final int glId; private final int size; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBuffer.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBuffer.java index 96bf38c9f..0aa420a93 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBuffer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBuffer.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.gl.buffer; -import com.mojang.blaze3d.platform.GlStateManager; import me.jellysquid.mods.sodium.client.gl.GlObject; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import org.lwjgl.opengl.GL15; public abstract class GlBuffer extends GlObject { public static final int NULL_BUFFER_ID = 0; @@ -12,7 +12,7 @@ public abstract class GlBuffer extends GlObject { protected GlBuffer(RenderDevice owner, GlBufferUsage usage) { super(owner); - this.setHandle(GlStateManager.genBuffers()); + this.setHandle(GL15.glGenBuffers()); this.usage = usage; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferTarget.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferTarget.java index 265e222d9..8de59ec0d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferTarget.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferTarget.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.client.gl.buffer; -import org.lwjgl.opengl.GL20C; -import org.lwjgl.opengl.GL31C; -import org.lwjgl.opengl.GL40C; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL31; +import org.lwjgl.opengl.GL40; public enum GlBufferTarget { - ARRAY_BUFFER(GL20C.GL_ARRAY_BUFFER, GL20C.GL_ARRAY_BUFFER_BINDING), - COPY_READ_BUFFER(GL31C.GL_COPY_READ_BUFFER, GL31C.GL_COPY_READ_BUFFER), - COPY_WRITE_BUFFER(GL31C.GL_COPY_WRITE_BUFFER, GL31C.GL_COPY_WRITE_BUFFER), - DRAW_INDIRECT_BUFFER(GL40C.GL_DRAW_INDIRECT_BUFFER, GL40C.GL_DRAW_INDIRECT_BUFFER_BINDING); + ARRAY_BUFFER(GL15.GL_ARRAY_BUFFER, GL15.GL_ARRAY_BUFFER_BINDING), + COPY_READ_BUFFER(GL31.GL_COPY_READ_BUFFER, GL31.GL_COPY_READ_BUFFER), + COPY_WRITE_BUFFER(GL31.GL_COPY_WRITE_BUFFER, GL31.GL_COPY_WRITE_BUFFER), + DRAW_INDIRECT_BUFFER(GL40.GL_DRAW_INDIRECT_BUFFER, GL40.GL_DRAW_INDIRECT_BUFFER_BINDING); public static final GlBufferTarget[] VALUES = GlBufferTarget.values(); public static final int COUNT = VALUES.length; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferUsage.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferUsage.java index d7acb91d3..d779dad5c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferUsage.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/buffer/GlBufferUsage.java @@ -1,17 +1,17 @@ package me.jellysquid.mods.sodium.client.gl.buffer; -import org.lwjgl.opengl.GL20C; +import org.lwjgl.opengl.GL15; public enum GlBufferUsage { - GL_STREAM_DRAW(GL20C.GL_STREAM_DRAW), - GL_STREAM_READ(GL20C.GL_STREAM_READ), - GL_STREAM_COPY(GL20C.GL_STREAM_COPY), - GL_STATIC_DRAW(GL20C.GL_STATIC_DRAW), - GL_STATIC_READ(GL20C.GL_STATIC_READ), - GL_STATIC_COPY(GL20C.GL_STATIC_COPY), - GL_DYNAMIC_DRAW(GL20C.GL_DYNAMIC_DRAW), - GL_DYNAMIC_READ(GL20C.GL_DYNAMIC_READ), - GL_DYNAMIC_COPY(GL20C.GL_DYNAMIC_COPY); + GL_STREAM_DRAW(GL15.GL_STREAM_DRAW), + GL_STREAM_READ(GL15.GL_STREAM_READ), + GL_STREAM_COPY(GL15.GL_STREAM_COPY), + GL_STATIC_DRAW(GL15.GL_STATIC_DRAW), + GL_STATIC_READ(GL15.GL_STATIC_READ), + GL_STATIC_COPY(GL15.GL_STATIC_COPY), + GL_DYNAMIC_DRAW(GL15.GL_DYNAMIC_DRAW), + GL_DYNAMIC_READ(GL15.GL_DYNAMIC_READ), + GL_DYNAMIC_COPY(GL15.GL_DYNAMIC_COPY); private final int id; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java index dba0f1cc5..d0afedee0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java @@ -1,63 +1,55 @@ package me.jellysquid.mods.sodium.client.gl.compat; -import com.mojang.blaze3d.platform.GlStateManager; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkFogMode; -import net.minecraft.client.render.BackgroundRenderer; -import net.minecraft.util.math.MathHelper; -import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL11; public class FogHelper { private static final float FAR_PLANE_THRESHOLD_EXP = (float) Math.log(1.0f / 0.0019f); - private static final float FAR_PLANE_THRESHOLD_EXP2 = MathHelper.sqrt(FAR_PLANE_THRESHOLD_EXP); + private static final float FAR_PLANE_THRESHOLD_EXP2 = (float) Math.sqrt(FAR_PLANE_THRESHOLD_EXP); public static float getFogEnd() { - return GlStateManager.FOG.end; + return GLStateManager.getFog().end; } public static float getFogStart() { - return GlStateManager.FOG.start; + return GLStateManager.getFog().start; } public static float getFogDensity() { - return GlStateManager.FOG.density; + return GLStateManager.getFog().density; } /** * Retrieves the current fog mode from the fixed-function pipeline. */ public static ChunkFogMode getFogMode() { - int mode = GlStateManager.FOG.mode; + int mode = GLStateManager.getFog().fogMode; - if(mode == 0 || !GlStateManager.FOG.capState.state) + if(mode == 0 || !GLStateManager.getFog().mode.isEnabled()) return ChunkFogMode.NONE; - switch (mode) { - case GL20.GL_EXP2: - case GL20.GL_EXP: - return ChunkFogMode.EXP2; - case GL20.GL_LINEAR: - return ChunkFogMode.LINEAR; - default: - throw new UnsupportedOperationException("Unknown fog mode: " + mode); - } + return switch (mode) { + case GL11.GL_EXP2, GL11.GL_EXP -> ChunkFogMode.EXP2; + case GL11.GL_LINEAR -> ChunkFogMode.LINEAR; + default -> throw new UnsupportedOperationException("Unknown fog mode: " + mode); + }; } public static float getFogCutoff() { - int mode = GlStateManager.FOG.mode; - - switch (mode) { - case GL20.GL_LINEAR: - return getFogEnd(); - case GL20.GL_EXP: - return FAR_PLANE_THRESHOLD_EXP / getFogDensity(); - case GL20.GL_EXP2: - return FAR_PLANE_THRESHOLD_EXP2 / getFogDensity(); - default: - return 0.0f; - } + int mode = GLStateManager.getFog().fogMode; + + return switch (mode) { + case GL11.GL_LINEAR -> getFogEnd(); + case GL11.GL_EXP -> FAR_PLANE_THRESHOLD_EXP / getFogDensity(); + case GL11.GL_EXP2 -> FAR_PLANE_THRESHOLD_EXP2 / getFogDensity(); + default -> 0.0f; + }; } public static float[] getFogColor() { - return new float[]{BackgroundRenderer.red, BackgroundRenderer.green, BackgroundRenderer.blue, 1.0F}; + // TODO: Sodium +// return new float[]{BackgroundRenderer.red, BackgroundRenderer.green, BackgroundRenderer.blue, 1.0F}; + return new float[]{0.0F, 0.0F, 0.0F, 1.0F}; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java index cc6b2e7bc..b6a186a30 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java @@ -1,11 +1,12 @@ package me.jellysquid.mods.sodium.client.gl.device; +import java.nio.ByteBuffer; import java.nio.IntBuffer; public interface DrawCommandList extends AutoCloseable { void multiDrawArrays(IntBuffer first, IntBuffer count); - void multiDrawArraysIndirect(long pointer, int count, int stride); + void multiDrawArraysIndirect(ByteBuffer buffer, int count, int stride); void endTessellating(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java index c55633e9a..092a750ff 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.gl.device; -import com.mojang.blaze3d.platform.GlStateManager; import me.jellysquid.mods.sodium.client.gl.array.GlVertexArray; import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; @@ -13,6 +12,9 @@ import me.jellysquid.mods.sodium.client.gl.tessellation.GlTessellation; import me.jellysquid.mods.sodium.client.gl.tessellation.GlVertexArrayTessellation; import me.jellysquid.mods.sodium.client.gl.tessellation.TessellationBinding; +import org.lwjgl.opengl.GL14; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL31; import java.nio.ByteBuffer; import java.nio.IntBuffer; @@ -76,7 +78,7 @@ public void bindVertexArray(GlVertexArray array) { public void uploadData(GlMutableBuffer glBuffer, ByteBuffer byteBuffer) { this.bindBuffer(GlBufferTarget.ARRAY_BUFFER, glBuffer); - GlStateManager.bufferData(GlBufferTarget.ARRAY_BUFFER.getTargetParameter(), byteBuffer, glBuffer.getUsageHint().getId()); + GL15.glBufferData(GlBufferTarget.ARRAY_BUFFER.getTargetParameter(), byteBuffer, glBuffer.getUsageHint().getId()); glBuffer.setSize(byteBuffer.limit()); } @@ -90,20 +92,20 @@ public void copyBufferSubData(GlBuffer src, GlMutableBuffer dst, long readOffset this.bindBuffer(GlBufferTarget.COPY_READ_BUFFER, src); this.bindBuffer(GlBufferTarget.COPY_WRITE_BUFFER, dst); - GlFunctions.BUFFER_COPY.glCopyBufferSubData(GL31C.GL_COPY_READ_BUFFER, GL31C.GL_COPY_WRITE_BUFFER, readOffset, writeOffset, bytes); + GlFunctions.BUFFER_COPY.glCopyBufferSubData(GL31.GL_COPY_READ_BUFFER, GL31.GL_COPY_WRITE_BUFFER, readOffset, writeOffset, bytes); } @Override public void bindBuffer(GlBufferTarget target, GlBuffer buffer) { if (this.stateTracker.makeBufferActive(target, buffer)) { - GlStateManager.bindBuffers(target.getTargetParameter(), buffer.handle()); + GL15.glBindBuffer(target.getTargetParameter(), buffer.handle()); } } @Override public void unbindBuffer(GlBufferTarget target) { if (this.stateTracker.makeBufferActive(target, null)) { - GlStateManager.bindBuffers(target.getTargetParameter(), GlBuffer.NULL_BUFFER_ID); + GL15.glBindBuffer(target.getTargetParameter(), GlBuffer.NULL_BUFFER_ID); } } @@ -123,7 +125,7 @@ public void invalidateBuffer(GlMutableBuffer glBuffer) { public void allocateBuffer(GlBufferTarget target, GlMutableBuffer buffer, long bufferSize) { this.bindBuffer(target, buffer); - GL20C.glBufferData(target.getTargetParameter(), bufferSize, buffer.getUsageHint().getId()); + GL15.glBufferData(target.getTargetParameter(), bufferSize, buffer.getUsageHint().getId()); buffer.setSize(bufferSize); } @@ -132,7 +134,7 @@ public void deleteBuffer(GlBuffer buffer) { int handle = buffer.handle(); buffer.invalidateHandle(); - GlStateManager.deleteBuffers(handle); + GL15.glDeleteBuffers(handle); } @Override @@ -192,13 +194,13 @@ public ImmediateDrawCommandList() { @Override public void multiDrawArrays(IntBuffer first, IntBuffer count) { GlPrimitiveType primitiveType = GLRenderDevice.this.activeTessellation.getPrimitiveType(); - GL20C.glMultiDrawArrays(primitiveType.getId(), first, count); + GL14.glMultiDrawArrays(primitiveType.getId(), first, count); } @Override - public void multiDrawArraysIndirect(long pointer, int count, int stride) { + public void multiDrawArraysIndirect(ByteBuffer buffer, int count, int stride) { GlPrimitiveType primitiveType = GLRenderDevice.this.activeTessellation.getPrimitiveType(); - GlFunctions.INDIRECT_DRAW.glMultiDrawArraysIndirect(primitiveType.getId(), pointer, count, stride); + GlFunctions.INDIRECT_DRAW.glMultiDrawArraysIndirect(primitiveType.getId(), buffer, count, stride); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlBufferCopyFunctions.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlBufferCopyFunctions.java index c55d0c577..1ea1d8501 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlBufferCopyFunctions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlBufferCopyFunctions.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.gl.func; import org.lwjgl.opengl.ARBCopyBuffer; -import org.lwjgl.opengl.GL31C; -import org.lwjgl.opengl.GLCapabilities; +import org.lwjgl.opengl.ContextCapabilities; +import org.lwjgl.opengl.GL31; /** * Requires OpenGL 3.1+ or the ARB_copy_buffer extension. @@ -11,7 +11,7 @@ public enum GlBufferCopyFunctions { CORE { @Override public void glCopyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size) { - GL31C.glCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); + GL31.glCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); } }, ARB { @@ -27,7 +27,7 @@ public void glCopyBufferSubData(int readTarget, int writeTarget, long readOffset } }; - static GlBufferCopyFunctions load(GLCapabilities capabilities) { + static GlBufferCopyFunctions load(ContextCapabilities capabilities) { if (capabilities.OpenGL31) { return GlBufferCopyFunctions.CORE; } else if (capabilities.GL_ARB_copy_buffer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlFunctions.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlFunctions.java index fdf59f22a..3ee84b09c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlFunctions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlFunctions.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.client.gl.func; -import org.lwjgl.opengl.GL; -import org.lwjgl.opengl.GLCapabilities; +import org.lwjgl.opengl.ContextCapabilities; +import org.lwjgl.opengl.GLContext; public class GlFunctions { - private static final GLCapabilities capabilities = GL.getCapabilities(); + private static final ContextCapabilities capabilities = GLContext.getCapabilities(); public static final GlVertexArrayFunctions VERTEX_ARRAY = GlVertexArrayFunctions.load(capabilities); public static final GlBufferCopyFunctions BUFFER_COPY = GlBufferCopyFunctions.load(capabilities); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java index a13e294d2..7c3157a8e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java @@ -1,30 +1,32 @@ package me.jellysquid.mods.sodium.client.gl.func; import org.lwjgl.opengl.ARBMultiDrawIndirect; -import org.lwjgl.opengl.GL43C; -import org.lwjgl.opengl.GLCapabilities; +import org.lwjgl.opengl.ContextCapabilities; +import org.lwjgl.opengl.GL43; + +import java.nio.ByteBuffer; public enum GlIndirectMultiDrawFunctions { CORE { @Override - public void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride) { - GL43C.glMultiDrawArraysIndirect(mode, indirect, primcount, stride); + public void glMultiDrawArraysIndirect(int mode, ByteBuffer buffer, int primcount, int stride) { + GL43.glMultiDrawArraysIndirect(mode, buffer, primcount, stride); } }, ARB { @Override - public void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride) { - ARBMultiDrawIndirect.glMultiDrawArraysIndirect(mode, indirect, primcount, stride); + public void glMultiDrawArraysIndirect(int mode, ByteBuffer buffer, int primcount, int stride) { + ARBMultiDrawIndirect.glMultiDrawArraysIndirect(mode, buffer, primcount, stride); } }, UNSUPPORTED { @Override - public void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride) { + public void glMultiDrawArraysIndirect(int mode, ByteBuffer buffer, int primcount, int stride) { throw new UnsupportedOperationException(); } }; - public static GlIndirectMultiDrawFunctions load(GLCapabilities capabilities) { + public static GlIndirectMultiDrawFunctions load(ContextCapabilities capabilities) { if (capabilities.OpenGL43) { return CORE; } else if (capabilities.GL_ARB_multi_draw_indirect && capabilities.GL_ARB_draw_indirect) { @@ -34,5 +36,5 @@ public static GlIndirectMultiDrawFunctions load(GLCapabilities capabilities) { } } - public abstract void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride); + public abstract void glMultiDrawArraysIndirect(int mode, ByteBuffer buffer, int primcount, int stride); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlInstancedArrayFunctions.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlInstancedArrayFunctions.java index 95f575beb..4ec13d7e4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlInstancedArrayFunctions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlInstancedArrayFunctions.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.client.gl.func; import org.lwjgl.opengl.ARBInstancedArrays; -import org.lwjgl.opengl.GL33C; -import org.lwjgl.opengl.GLCapabilities; +import org.lwjgl.opengl.ContextCapabilities; +import org.lwjgl.opengl.GL33; public enum GlInstancedArrayFunctions { CORE { @Override public void glVertexAttribDivisor(int index, int divisor) { - GL33C.glVertexAttribDivisor(index, divisor); + GL33.glVertexAttribDivisor(index, divisor); } }, ARB { @@ -24,7 +24,7 @@ public void glVertexAttribDivisor(int index, int divisor) { } }; - public static GlInstancedArrayFunctions load(GLCapabilities capabilities) { + public static GlInstancedArrayFunctions load(ContextCapabilities capabilities) { if (capabilities.OpenGL33) { return CORE; } else if (capabilities.GL_ARB_instanced_arrays) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlVertexArrayFunctions.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlVertexArrayFunctions.java index 8b639bb85..1a9bab73b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlVertexArrayFunctions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlVertexArrayFunctions.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.gl.func; import org.lwjgl.opengl.ARBVertexArrayObject; -import org.lwjgl.opengl.GL30C; -import org.lwjgl.opengl.GLCapabilities; +import org.lwjgl.opengl.ContextCapabilities; +import org.lwjgl.opengl.GL30; /** * Requires OpenGL 3.0+ or the ARB_vertex_array_object extension. @@ -11,17 +11,17 @@ public enum GlVertexArrayFunctions { BASE { @Override public void glBindVertexArray(int id) { - GL30C.glBindVertexArray(id); + GL30.glBindVertexArray(id); } @Override public int glGenVertexArrays() { - return GL30C.glGenVertexArrays(); + return GL30.glGenVertexArrays(); } @Override public void glDeleteVertexArrays(int id) { - GL30C.glDeleteVertexArrays(id); + GL30.glDeleteVertexArrays(id); } }, ARB { @@ -57,7 +57,7 @@ public void glDeleteVertexArrays(int id) { } }; - static GlVertexArrayFunctions load(GLCapabilities capabilities) { + static GlVertexArrayFunctions load(ContextCapabilities capabilities) { if (capabilities.OpenGL30) { return BASE; } else if (capabilities.GL_ARB_vertex_array_object) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java index 8891f1ebf..722a15590 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java @@ -1,12 +1,13 @@ package me.jellysquid.mods.sodium.client.gl.shader; -import com.mojang.blaze3d.platform.GlStateManager; +import io.github.douira.glsl_transformer.ast.node.Identifier; import me.jellysquid.mods.sodium.client.gl.GlObject; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import net.minecraft.util.Identifier; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.lwjgl.opengl.GL20C; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; + /** * An OpenGL shader program. @@ -28,11 +29,11 @@ public static Builder builder(Identifier identifier) { } public void bind() { - GlStateManager.useProgram(this.handle()); + GL20.glUseProgram(this.handle()); } public void unbind() { - GlStateManager.useProgram(0); + GL20.glUseProgram(0); } public Identifier getName() { @@ -46,7 +47,7 @@ public Identifier getName() { * @throws NullPointerException If no uniform exists with the given name */ public int getUniformLocation(String name) { - int index = GlStateManager.getUniformLocation(this.handle(), name); + int index = GL20.glGetUniformLocation(this.handle(), name); if (index < 0) { throw new NullPointerException("No uniform exists with name: " + name); @@ -56,7 +57,7 @@ public int getUniformLocation(String name) { } public void delete() { - GlStateManager.deleteProgram(this.handle()); + GL20.glDeleteProgram(this.handle()); this.invalidateHandle(); } @@ -67,11 +68,11 @@ public static class Builder { public Builder(Identifier name) { this.name = name; - this.program = GlStateManager.createProgram(); + this.program = GL20.glCreateProgram(); } public Builder attachShader(GlShader shader) { - GlStateManager.attachShader(this.program, shader.handle()); + GL20.glAttachShader(this.program, shader.handle()); return this; } @@ -86,17 +87,17 @@ public Builder attachShader(GlShader shader) { * @return An instantiated shader container as provided by the factory */ public

P build(ProgramFactory

factory) { - GlStateManager.linkProgram(this.program); + GL20.glLinkProgram(this.program); - String log = GL20C.glGetProgramInfoLog(this.program); + String log = GL20.glGetProgramInfoLog(this.program, GL20.GL_INFO_LOG_LENGTH); if (!log.isEmpty()) { LOGGER.warn("Program link log for " + this.name + ": " + log); } - int result = GlStateManager.getProgram(this.program, GL20C.GL_LINK_STATUS); + int result = GL20.glGetProgrami(this.program, GL20.GL_LINK_STATUS); - if (result != GL20C.GL_TRUE) { + if (result != GL11.GL_TRUE) { throw new RuntimeException("Shader program linking failed, see log for details"); } @@ -104,7 +105,7 @@ public

P build(ProgramFactory

factory) { } public Builder bindAttribute(String name, ShaderBindingPoint binding) { - GL20C.glBindAttribLocation(this.program, binding.getGenericAttributeIndex(), name); + GL20.glBindAttribLocation(this.program, binding.getGenericAttributeIndex(), name); return this; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java index 6fe345e95..36537d6ef 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.client.gl.shader; -import com.mojang.blaze3d.platform.GlStateManager; +import io.github.douira.glsl_transformer.ast.node.Identifier; import me.jellysquid.mods.sodium.client.gl.GlObject; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import net.minecraft.util.Identifier; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.lwjgl.opengl.GL20C; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; import java.io.BufferedReader; import java.io.IOException; @@ -27,19 +27,20 @@ public GlShader(RenderDevice owner, ShaderType type, Identifier name, String src src = processShader(src, constants); - int handle = GlStateManager.createShader(type.id); - ShaderWorkarounds.safeShaderSource(handle, src); - GlStateManager.compileShader(handle); + int handle = GL20.glCreateShader(type.id); + // TODO: ShaderWorkaround + GL20.glShaderSource(handle, src); + GL20.glCompileShader(handle); - String log = GL20C.glGetShaderInfoLog(handle); + String log = GL20.glGetShaderInfoLog(handle, GL20.GL_INFO_LOG_LENGTH); if (!log.isEmpty()) { LOGGER.warn("Shader compilation log for " + this.name + ": " + log); } - int result = GlStateManager.getShader(handle, GL20C.GL_COMPILE_STATUS); + int result = GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS); - if (result != GL20C.GL_TRUE) { + if (result != GL11.GL_TRUE) { throw new RuntimeException("Shader compilation failed, see log for details"); } @@ -84,7 +85,7 @@ public Identifier getName() { } public void delete() { - GlStateManager.deleteShader(this.handle()); + GL20.glDeleteShader(this.handle()); this.invalidateHandle(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java index 33acceac1..0486dc4b0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.gl.shader; +import io.github.douira.glsl_transformer.ast.node.Identifier; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import net.minecraft.util.Identifier; import org.apache.commons.io.IOUtils; import java.io.IOException; @@ -23,7 +23,7 @@ public class ShaderLoader { * @return An OpenGL shader object compiled with the given user defines */ public static GlShader loadShader(RenderDevice device, ShaderType type, Identifier name, ShaderConstants constants) { - return new GlShader(device, type, name, getShaderSource(getShaderPath(name)), constants); + return new GlShader(device, type, name, getShaderSource(getShaderPath(name, type)), constants); } /** @@ -31,11 +31,11 @@ public static GlShader loadShader(RenderDevice device, ShaderType type, Identifi */ @Deprecated public static GlShader loadShader(RenderDevice device, ShaderType type, Identifier name, List constants) { - return new GlShader(device, type, name, getShaderSource(getShaderPath(name)), ShaderConstants.fromStringList(constants)); + return new GlShader(device, type, name, getShaderSource(getShaderPath(name, type)), ShaderConstants.fromStringList(constants)); } - private static String getShaderPath(Identifier name) { - return String.format("/assets/%s/shaders/%s", name.getNamespace(), name.getPath()); + private static String getShaderPath(Identifier name, ShaderType type) { + return String.format("/assets/sodium/shaders/%s.%s.glsl", name.getName(), type == ShaderType.VERTEX ? "v" : "f"); } private static String getShaderSource(String path) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java index 4791e3dc8..9b4889b7d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java @@ -1,13 +1,13 @@ package me.jellysquid.mods.sodium.client.gl.shader; -import org.lwjgl.opengl.GL20C; +import org.lwjgl.opengl.GL20; /** * An enumeration over the supported OpenGL shader types. */ public enum ShaderType { - VERTEX(GL20C.GL_VERTEX_SHADER), - FRAGMENT(GL20C.GL_FRAGMENT_SHADER); + VERTEX(GL20.GL_VERTEX_SHADER), + FRAGMENT(GL20.GL_FRAGMENT_SHADER); public final int id; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderWorkarounds.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderWorkarounds.java deleted file mode 100644 index d13bbfaee..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderWorkarounds.java +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2020 Grondag -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package me.jellysquid.mods.sodium.client.gl.shader; - -import org.lwjgl.PointerBuffer; -import org.lwjgl.opengl.GL20C; -import org.lwjgl.system.MemoryStack; -import org.lwjgl.system.MemoryUtil; - -import java.nio.ByteBuffer; - -/** - * Contains a workaround for a crash in nglShaderSource on some AMD drivers. Copied from the following Canvas commit: - * https://github.com/grondag/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96 - */ -class ShaderWorkarounds { - /** - * Identical in function to {@link GL20C#glShaderSource(int, CharSequence)} but - * passes a null pointer for string length to force the driver to rely on the null - * terminator for string length. This is a workaround for an apparent flaw with some - * AMD drivers that don't receive or interpret the length correctly, resulting in - * an access violation when the driver tries to read past the string memory. - * - *

Hat tip to fewizz for the find and the fix. - */ - static void safeShaderSource(int glId, CharSequence source) { - final MemoryStack stack = MemoryStack.stackGet(); - final int stackPointer = stack.getPointer(); - - try { - final ByteBuffer sourceBuffer = MemoryUtil.memUTF8(source, true); - final PointerBuffer pointers = stack.mallocPointer(1); - pointers.put(sourceBuffer); - - GL20C.nglShaderSource(glId, 1, pointers.address0(), 0); - org.lwjgl.system.APIUtil.apiArrayFree(pointers.address0(), 1); - } finally { - stack.setPointer(stackPointer); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java index 94f51b355..8ffd079a1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java @@ -1,10 +1,11 @@ package me.jellysquid.mods.sodium.client.gl.state; -import com.mojang.blaze3d.platform.GlStateManager; import me.jellysquid.mods.sodium.client.gl.array.GlVertexArray; import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; -import org.lwjgl.opengl.GL30C; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL30; import java.util.Arrays; @@ -29,7 +30,7 @@ private boolean makeBufferActive(GlBufferTarget target, int buffer) { int prevBuffer = this.bufferState[target.ordinal()]; if (prevBuffer == UNASSIGNED_HANDLE) { - this.bufferRestoreState[target.ordinal()] = GlStateManager.getInteger(target.getBindingParameter()); + this.bufferRestoreState[target.ordinal()] = GL11.glGetInteger(target.getBindingParameter()); } this.bufferState[target.ordinal()] = buffer; @@ -45,7 +46,7 @@ private boolean makeVertexArrayActive(int array) { int prevArray = this.vertexArrayState; if (prevArray == UNASSIGNED_HANDLE) { - this.vertexArrayRestoreState = GlStateManager.getInteger(GL30C.GL_VERTEX_ARRAY_BINDING); + this.vertexArrayRestoreState = GL11.glGetInteger(GL30.GL_VERTEX_ARRAY_BINDING); } this.vertexArrayState = array; @@ -55,15 +56,13 @@ private boolean makeVertexArrayActive(int array) { public void applyRestoreState() { for (int i = 0; i < GlBufferTarget.COUNT; i++) { - if (this.bufferState[i] != this.bufferRestoreState[i] && - this.bufferRestoreState[i] != UNASSIGNED_HANDLE) { - GlStateManager.bindBuffers(GlBufferTarget.VALUES[i].getTargetParameter(), this.bufferRestoreState[i]); + if (this.bufferState[i] != this.bufferRestoreState[i] && this.bufferRestoreState[i] != UNASSIGNED_HANDLE) { + GL15.glBindBuffer(GlBufferTarget.VALUES[i].getTargetParameter(), this.bufferRestoreState[i]); } } - if (this.vertexArrayState != this.vertexArrayRestoreState && - this.vertexArrayRestoreState != UNASSIGNED_HANDLE) { - GL30C.glBindVertexArray(this.vertexArrayRestoreState); + if (this.vertexArrayState != this.vertexArrayRestoreState && this.vertexArrayRestoreState != UNASSIGNED_HANDLE) { + GL30.glBindVertexArray(this.vertexArrayRestoreState); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java index ab6c790d3..95a46cb7a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.client.gl.tessellation; -import com.mojang.blaze3d.platform.GlStateManager; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.func.GlFunctions; +import org.lwjgl.opengl.GL20; public abstract class GlAbstractTessellation implements GlTessellation { protected final GlPrimitiveType primitiveType; @@ -25,9 +25,8 @@ protected void bindAttributes(CommandList commandList) { commandList.bindBuffer(GlBufferTarget.ARRAY_BUFFER, binding.getBuffer()); for (GlVertexAttributeBinding attrib : binding.getAttributeBindings()) { - GlStateManager.vertexAttribPointer(attrib.getIndex(), attrib.getCount(), attrib.getFormat(), attrib.isNormalized(), - attrib.getStride(), attrib.getPointer()); - GlStateManager.enableVertexAttribArray(attrib.getIndex()); + GL20.glVertexAttribPointer(attrib.getIndex(), attrib.getCount(), attrib.getFormat(), attrib.isNormalized(), attrib.getStride(), attrib.getPointer()); + GL20.glEnableVertexAttribArray(attrib.getIndex()); if (binding.isInstanced()) { GlFunctions.INSTANCED_ARRAY.glVertexAttribDivisor(attrib.getIndex(), 1); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlFallbackTessellation.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlFallbackTessellation.java index 7cb4eb937..2cb9531d2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlFallbackTessellation.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlFallbackTessellation.java @@ -2,7 +2,7 @@ import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeBinding; import me.jellysquid.mods.sodium.client.gl.device.CommandList; -import org.lwjgl.opengl.GL20C; +import org.lwjgl.opengl.GL20; public class GlFallbackTessellation extends GlAbstractTessellation { public GlFallbackTessellation(GlPrimitiveType primitiveType, TessellationBinding[] bindings) { @@ -23,7 +23,7 @@ public void bind(CommandList commandList) { public void unbind(CommandList commandList) { for (TessellationBinding binding : this.bindings) { for (GlVertexAttributeBinding attrib : binding.getAttributeBindings()) { - GL20C.glDisableVertexAttribArray(attrib.getIndex()); + GL20.glDisableVertexAttribArray(attrib.getIndex()); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlPrimitiveType.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlPrimitiveType.java index fb8f0297c..20d4aa72b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlPrimitiveType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/tessellation/GlPrimitiveType.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.gl.tessellation; -import org.lwjgl.opengl.GL20C; +import org.lwjgl.opengl.GL11; public enum GlPrimitiveType { - LINES(GL20C.GL_LINES), - TRIANGLES(GL20C.GL_TRIANGLES), - QUADS(GL20C.GL_QUADS); + LINES(GL11.GL_LINES), + TRIANGLES(GL11.GL_TRIANGLES), + QUADS(GL11.GL_QUADS); private final int id; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/GlMultiDrawBatch.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/util/GlMultiDrawBatch.java index a069a484d..d38ee8d2d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/GlMultiDrawBatch.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/util/GlMultiDrawBatch.java @@ -1,7 +1,8 @@ package me.jellysquid.mods.sodium.client.gl.util; +import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL20; -import org.lwjgl.system.MemoryUtil; + import java.nio.IntBuffer; @@ -10,14 +11,14 @@ * uses {@link GL20#glMultiDrawArrays(int, IntBuffer, IntBuffer)} and should be compatible on any relevant platform. */ public class GlMultiDrawBatch { - private final IntBuffer bufIndices; - private final IntBuffer bufLen; + private IntBuffer bufIndices; + private IntBuffer bufLen; private int count; private boolean isBuilding; public GlMultiDrawBatch(int capacity) { - this.bufIndices = MemoryUtil.memAllocInt(capacity); - this.bufLen = MemoryUtil.memAllocInt(capacity); + this.bufIndices = BufferUtils.createIntBuffer(capacity); + this.bufLen = BufferUtils.createIntBuffer(capacity); } public IntBuffer getIndicesBuffer() { @@ -58,7 +59,10 @@ public boolean isBuilding() { } public void delete() { - MemoryUtilHelper.memFree(this.bufIndices); - MemoryUtilHelper.memFree(this.bufLen); + this.bufIndices.clear(); + this.bufLen.clear(); + + this.bufIndices = null; + this.bufLen = null; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/MemoryUtilHelper.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/util/MemoryUtilHelper.java deleted file mode 100644 index 851b73f7f..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/util/MemoryUtilHelper.java +++ /dev/null @@ -1,28 +0,0 @@ -package me.jellysquid.mods.sodium.client.gl.util; - -import org.jetbrains.annotations.Nullable; -import org.lwjgl.PointerBuffer; -import org.lwjgl.system.MemoryUtil; - -import java.nio.Buffer; - -/** - * Contains versions of MemoryUtil#memFree that hopefully work on all versions of LWJGL 3 released - * in the past few years. - * - * LWJGL 3.2.3 made breaking changes to memFree, which is why this class is needed: - * https://github.com/LWJGL/lwjgl3/releases/tag/3.2.3 - */ -public class MemoryUtilHelper { - // memFree for custom / pointer buffers *was* changed. - public static void memFree(@Nullable PointerBuffer ptr) { - if (ptr != null) { - MemoryUtil.nmemFree(ptr.address0()); - } - } - - // memFree for normal buffers was not changed. - public static void memFree(@Nullable Buffer ptr) { - MemoryUtil.memFree(ptr); - } -} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java deleted file mode 100644 index 1f06ddff5..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ /dev/null @@ -1,366 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui; - -import com.google.common.collect.ImmutableList; -import me.jellysquid.mods.sodium.client.compat.modernui.MuiGuiScaleHook; -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; -import me.jellysquid.mods.sodium.client.gui.options.OptionGroup; -import me.jellysquid.mods.sodium.client.gui.options.OptionImpact; -import me.jellysquid.mods.sodium.client.gui.options.OptionImpl; -import me.jellysquid.mods.sodium.client.gui.options.OptionPage; -import me.jellysquid.mods.sodium.client.gui.options.binding.compat.VanillaBooleanOptionBinding; -import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; -import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl; -import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl; -import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl; -import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; -import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage; -import me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw.MultidrawChunkRenderBackend; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.Framebuffer; -import net.minecraft.client.option.AttackIndicator; -import net.minecraft.client.option.GraphicsMode; -import net.minecraft.client.option.ParticlesMode; -import net.minecraft.client.util.Window; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; - -import java.util.ArrayList; -import java.util.List; - -public class SodiumGameOptionPages { - private static final SodiumOptionsStorage sodiumOpts = new SodiumOptionsStorage(); - private static final MinecraftOptionsStorage vanillaOpts = new MinecraftOptionsStorage(); - - public static OptionPage general() { - List groups = new ArrayList<>(); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(new TranslatableText("options.renderDistance")) - .setTooltip(new TranslatableText("sodium.options.view_distance.tooltip")) - .setControl(option -> new SliderControl(option, 2, 32, 1, ControlValueFormatter.quantity("options.chunks"))) - .setBinding((options, value) -> options.viewDistance = value, options -> options.viewDistance) - .setImpact(OptionImpact.HIGH) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(new TranslatableText("options.gamma")) - .setTooltip(new TranslatableText("sodium.options.brightness.tooltip")) - .setControl(opt -> new SliderControl(opt, 0, 100, 1, ControlValueFormatter.brightness())) - .setBinding((opts, value) -> opts.gamma = value * 0.01D, (opts) -> (int) (opts.gamma / 0.01D)) - .build()) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.clouds.name")) - .setTooltip(new TranslatableText("sodium.options.clouds.tooltip")) - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> { - opts.quality.enableClouds = value; - - if (MinecraftClient.isFabulousGraphicsOrBetter()) { - Framebuffer framebuffer = MinecraftClient.getInstance().worldRenderer.getCloudsFramebuffer(); - if (framebuffer != null) { - framebuffer.clear(MinecraftClient.IS_SYSTEM_MAC); - } - } - }, (opts) -> opts.quality.enableClouds) - .setImpact(OptionImpact.LOW) - .build()) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(new TranslatableText("options.guiScale")) - .setTooltip(new TranslatableText("sodium.options.gui_scale.tooltip")) - .setControl(option -> new SliderControl(option, 0, MuiGuiScaleHook.getMaxGuiScale(), 1, ControlValueFormatter.guiScale())) - .setBinding((opts, value) -> { - opts.guiScale = value; - - MinecraftClient client = MinecraftClient.getInstance(); - client.onResolutionChanged(); - }, opts -> opts.guiScale) - .build()) - .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(new TranslatableText("options.fullscreen")) - .setTooltip(new TranslatableText("sodium.options.fullscreen.tooltip")) - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> { - opts.fullscreen = value; - - MinecraftClient client = MinecraftClient.getInstance(); - Window window = client.getWindow(); - - if (window != null && window.isFullscreen() != opts.fullscreen) { - window.toggleFullscreen(); - - // The client might not be able to enter full-screen mode - opts.fullscreen = window.isFullscreen(); - } - }, (opts) -> opts.fullscreen) - .build()) - .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(new TranslatableText("options.vsync")) - .setTooltip(new TranslatableText("sodium.options.v_sync.tooltip")) - .setControl(TickBoxControl::new) - .setBinding(new VanillaBooleanOptionBinding(Option.VSYNC)) - .setImpact(OptionImpact.VARIES) - .build()) - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(new TranslatableText("options.framerateLimit")) - .setTooltip(new TranslatableText("sodium.options.fps_limit.tooltip")) - .setControl(option -> new SliderControl(option, 5, 260, 5, ControlValueFormatter.fpsLimit())) - .setBinding((opts, value) -> { - opts.maxFps = value; - MinecraftClient.getInstance().getWindow().setFramerateLimit(value); - }, opts -> opts.maxFps) - .build()) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(new TranslatableText("options.viewBobbing")) - .setTooltip(new TranslatableText("sodium.options.view_bobbing.tooltip")) - .setControl(TickBoxControl::new) - .setBinding(new VanillaBooleanOptionBinding(Option.VIEW_BOBBING)) - .build()) - .add(OptionImpl.createBuilder(AttackIndicator.class, vanillaOpts) - .setName(new TranslatableText("options.attackIndicator")) - .setTooltip(new TranslatableText("sodium.options.attack_indicator.tooltip")) - .setControl(opts -> new CyclingControl<>(opts, AttackIndicator.class, new Text[] { new TranslatableText("options.off"), new TranslatableText("options.attack.crosshair"), new TranslatableText("options.attack.hotbar") })) - .setBinding((opts, value) -> opts.attackIndicator = value, (opts) -> opts.attackIndicator) - .build()) - .build()); - - return new OptionPage(new TranslatableText("stat.generalButton"), ImmutableList.copyOf(groups)); - } - - public static OptionPage quality() { - List groups = new ArrayList<>(); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(GraphicsMode.class, vanillaOpts) - .setName(new TranslatableText("options.graphics")) - .setTooltip(new TranslatableText("sodium.options.graphics_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, GraphicsMode.class, new Text[] { new TranslatableText("options.graphics.fast"), new TranslatableText("options.graphics.fancy"), new TranslatableText("options.graphics.fabulous") })) - .setBinding( - (opts, value) -> opts.graphicsMode = value, - opts -> opts.graphicsMode) - .setImpact(OptionImpact.HIGH) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) - .setName(new TranslatableText("options.renderClouds")) - .setTooltip(new TranslatableText("sodium.options.clouds_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) - .setBinding((opts, value) -> opts.quality.cloudQuality = value, opts -> opts.quality.cloudQuality) - .setImpact(OptionImpact.LOW) - .build()) - .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) - .setName(new TranslatableText("soundCategory.weather")) - .setTooltip(new TranslatableText("sodium.options.weather_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) - .setBinding((opts, value) -> opts.quality.weatherQuality = value, opts -> opts.quality.weatherQuality) - .setImpact(OptionImpact.MEDIUM) - .build()) - .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.leaves_quality.name")) - .setTooltip(new TranslatableText("sodium.options.leaves_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) - .setBinding((opts, value) -> opts.quality.leavesQuality = value, opts -> opts.quality.leavesQuality) - .setImpact(OptionImpact.MEDIUM) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .add(OptionImpl.createBuilder(ParticlesMode.class, vanillaOpts) - .setName(new TranslatableText("options.particles")) - .setTooltip(new TranslatableText("sodium.options.particle_quality.tooltip")) - .setControl(opt -> new CyclingControl<>(opt, ParticlesMode.class, new Text[] { new TranslatableText("options.particles.all"), new TranslatableText("options.particles.decreased"), new TranslatableText("options.particles.minimal") })) - .setBinding((opts, value) -> opts.particles = value, (opts) -> opts.particles) - .setImpact(OptionImpact.MEDIUM) - .build()) - .add(OptionImpl.createBuilder(SodiumGameOptions.LightingQuality.class, sodiumOpts) - .setName(new TranslatableText("options.ao")) - .setTooltip(new TranslatableText("sodium.options.smooth_lighting.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.LightingQuality.class)) - .setBinding((opts, value) -> opts.quality.smoothLighting = value, opts -> opts.quality.smoothLighting) - .setImpact(OptionImpact.MEDIUM) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(new TranslatableText("options.biomeBlendRadius")) - .setTooltip(new TranslatableText("sodium.options.biome_blend.tooltip")) - .setControl(option -> new SliderControl(option, 0, 7, 1, ControlValueFormatter.quantityOrDisabled("sodium.options.biome_blend.value", "gui.none"))) - .setBinding((opts, value) -> opts.biomeBlendRadius = value, opts -> opts.biomeBlendRadius) - .setImpact(OptionImpact.LOW) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(new TranslatableText("options.entityDistanceScaling")) - .setTooltip(new TranslatableText("sodium.options.entity_distance.tooltip")) - .setControl(option -> new SliderControl(option, 50, 500, 25, ControlValueFormatter.percentage())) - .setBinding((opts, value) -> opts.entityDistanceScaling = value / 100.0F, opts -> Math.round(opts.entityDistanceScaling * 100.0F)) - .setImpact(OptionImpact.MEDIUM) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(new TranslatableText("options.entityShadows")) - .setTooltip(new TranslatableText("sodium.options.entity_shadows.tooltip")) - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.entityShadows = value, opts -> opts.entityShadows) - .setImpact(OptionImpact.LOW) - .build()) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.vignette.name")) - .setTooltip(new TranslatableText("sodium.options.vignette.tooltip")) - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.quality.enableVignette = value, opts -> opts.quality.enableVignette) - .setImpact(OptionImpact.LOW) - .build()) - .build()); - - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(new TranslatableText("options.mipmapLevels")) - .setTooltip(new TranslatableText("sodium.options.mipmap_levels.tooltip")) - .setControl(option -> new SliderControl(option, 0, 4, 1, ControlValueFormatter.multiplier())) - .setBinding((opts, value) -> opts.mipmapLevels = value, opts -> opts.mipmapLevels) - .setImpact(OptionImpact.MEDIUM) - .setFlags(OptionFlag.REQUIRES_ASSET_RELOAD) - .build()) - .build()); - - - return new OptionPage(new TranslatableText("sodium.options.pages.quality"), ImmutableList.copyOf(groups)); - } - - public static OptionPage advanced() { - List groups = new ArrayList<>(); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.use_chunk_multidraw.name")) - .setTooltip(new TranslatableText("sodium.options.use_chunk_multidraw.tooltip")) - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.advanced.useChunkMultidraw = value, opts -> opts.advanced.useChunkMultidraw) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .setImpact(OptionImpact.EXTREME) - .setEnabled(MultidrawChunkRenderBackend.isSupported(sodiumOpts.getData().advanced.ignoreDriverBlacklist)) - .build()) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.use_vertex_objects.name")) - .setTooltip(new TranslatableText("sodium.options.use_vertex_objects.tooltip")) - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.advanced.useVertexArrayObjects = value, opts -> opts.advanced.useVertexArrayObjects) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .setImpact(OptionImpact.LOW) - .build()) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.use_block_face_culling.name")) - .setTooltip(new TranslatableText("sodium.options.use_block_face_culling.tooltip")) - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.MEDIUM) - .setBinding((opts, value) -> opts.advanced.useBlockFaceCulling = value, opts -> opts.advanced.useBlockFaceCulling) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.use_compact_vertex_format.name")) - .setTooltip(new TranslatableText("sodium.options.use_compact_vertex_format.tooltip")) - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.MEDIUM) - .setBinding((opts, value) -> opts.advanced.useCompactVertexFormat = value, opts -> opts.advanced.useCompactVertexFormat) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.use_fog_occlusion.name")) - .setTooltip(new TranslatableText("sodium.options.use_fog_occlusion.tooltip")) - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.advanced.useFogOcclusion = value, opts -> opts.advanced.useFogOcclusion) - .setImpact(OptionImpact.MEDIUM) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.translucency_sorting.name")) - .setTooltip(new TranslatableText("sodium.options.translucency_sorting.tooltip")) - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.advanced.translucencySorting = value, opts -> opts.advanced.translucencySorting) - .setImpact(OptionImpact.MEDIUM) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.use_entity_culling.name")) - .setTooltip(new TranslatableText("sodium.options.use_entity_culling.tooltip")) - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.MEDIUM) - .setBinding((opts, value) -> opts.advanced.useEntityCulling = value, opts -> opts.advanced.useEntityCulling) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.animate_only_visible_textures.name")) - .setTooltip(new TranslatableText("sodium.options.animate_only_visible_textures.tooltip")) - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.HIGH) - .setBinding((opts, value) -> opts.advanced.animateOnlyVisibleTextures = value, opts -> opts.advanced.animateOnlyVisibleTextures) - .build() - ) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.allow_direct_memory_access.name")) - .setTooltip(new TranslatableText("sodium.options.allow_direct_memory_access.tooltip")) - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.HIGH) - .setBinding((opts, value) -> opts.advanced.allowDirectMemoryAccess = value, opts -> opts.advanced.allowDirectMemoryAccess) - .build() - ) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.ignore_driver_blacklist.name")) - .setTooltip(new TranslatableText("sodium.options.ignore_driver_blacklist.tooltip")) - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.advanced.ignoreDriverBlacklist = value, opts -> opts.advanced.ignoreDriverBlacklist) - .build() - ) - .build()); - - return new OptionPage(new TranslatableText("sodium.options.pages.advanced"), ImmutableList.copyOf(groups)); - } - - public static OptionPage performance() { - List groups = new ArrayList<>(); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(int.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.chunk_update_threads.name")) - .setTooltip(new TranslatableText("sodium.options.chunk_update_threads.tooltip")) - .setControl(o -> new SliderControl(o, 0, Runtime.getRuntime().availableProcessors(), 1, ControlValueFormatter.quantityOrDisabled("sodium.options.threads.value", "sodium.options.default"))) - .setImpact(OptionImpact.HIGH) - .setBinding((opts, value) -> opts.performance.chunkBuilderThreads = value, opts -> opts.performance.chunkBuilderThreads) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.always_defer_chunk_updates.name")) - .setTooltip(new TranslatableText("sodium.options.always_defer_chunk_updates.tooltip")) - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.HIGH) - .setBinding((opts, value) -> opts.performance.alwaysDeferChunkUpdates = value, opts -> opts.performance.alwaysDeferChunkUpdates) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .build()); - - return new OptionPage(new TranslatableText("sodium.options.pages.performance"), ImmutableList.copyOf(groups)); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java deleted file mode 100644 index 82cb38980..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ /dev/null @@ -1,149 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui; - -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonSyntaxException; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.options.FormattedTextProvider; -import net.minecraft.client.option.GraphicsMode; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; - -import java.io.FileReader; -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; - -public class SodiumGameOptions { - public final QualitySettings quality = new QualitySettings(); - public final AdvancedSettings advanced = new AdvancedSettings(); - public final PerformanceSettings performance = new PerformanceSettings(); - public final NotificationSettings notifications = new NotificationSettings(); - - private Path configPath; - - public static class AdvancedSettings { - public boolean useVertexArrayObjects = true; - public boolean useChunkMultidraw = true; - - public boolean animateOnlyVisibleTextures = true; - public boolean useEntityCulling = true; - public boolean useParticleCulling = true; - public boolean useFogOcclusion = true; - public boolean useCompactVertexFormat = true; - public boolean useBlockFaceCulling = true; - public boolean allowDirectMemoryAccess = true; - public boolean ignoreDriverBlacklist = false; - public boolean translucencySorting = false; - } - - public static class PerformanceSettings { - public int chunkBuilderThreads = 0; - public boolean alwaysDeferChunkUpdates = false; - } - - public static class QualitySettings { - public GraphicsQuality cloudQuality = GraphicsQuality.DEFAULT; - public GraphicsQuality weatherQuality = GraphicsQuality.DEFAULT; - public GraphicsQuality leavesQuality = GraphicsQuality.DEFAULT; - - public boolean enableVignette = true; - public boolean enableClouds = true; - - public LightingQuality smoothLighting = LightingQuality.HIGH; - } - - public static class NotificationSettings { - public boolean hideDonationButton = false; - } - - public enum GraphicsQuality implements FormattedTextProvider { - DEFAULT(new TranslatableText("generator.default")), - FANCY(new TranslatableText("options.clouds.fancy")), - FAST(new TranslatableText("options.clouds.fast")); - - private final Text name; - - GraphicsQuality(Text name) { - this.name = name; - } - - @Override - public Text getLocalizedName() { - return this.name; - } - - public boolean isFancy(GraphicsMode graphicsMode) { - return (this == FANCY) || (this == DEFAULT && (graphicsMode == GraphicsMode.FANCY || graphicsMode == GraphicsMode.FABULOUS)); - } - } - - public enum LightingQuality implements FormattedTextProvider { - HIGH(new TranslatableText("options.ao.max")), - LOW(new TranslatableText("options.ao.min")), - OFF(new TranslatableText("options.ao.off")); - - private final Text name; - - LightingQuality(Text name) { - this.name = name; - } - - @Override - public Text getLocalizedName() { - return this.name; - } - } - - private static final Gson GSON = new GsonBuilder() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .setPrettyPrinting() - .excludeFieldsWithModifiers(Modifier.PRIVATE) - .create(); - - public static SodiumGameOptions load(Path path) { - SodiumGameOptions config; - boolean resaveConfig = true; - - if (Files.exists(path)) { - try (FileReader reader = new FileReader(path.toFile())) { - config = GSON.fromJson(reader, SodiumGameOptions.class); - } catch (IOException e) { - throw new RuntimeException("Could not parse config", e); - } catch (JsonSyntaxException e) { - SodiumClientMod.logger().error("Could not parse config, will fallback to default settings", e); - config = new SodiumGameOptions(); - resaveConfig = false; - } - } else { - config = new SodiumGameOptions(); - } - - config.configPath = path; - - try { - if(resaveConfig) - config.writeChanges(); - } catch (IOException e) { - throw new RuntimeException("Couldn't update config file", e); - } - - return config; - } - - public void writeChanges() throws IOException { - Path dir = this.configPath.getParent(); - - if (!Files.exists(dir)) { - Files.createDirectories(dir); - } else if (!Files.isDirectory(dir)) { - throw new IOException("Not a directory: " + dir); - } - - Files.write(this.configPath, GSON.toJson(this) - .getBytes(StandardCharsets.UTF_8)); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java deleted file mode 100644 index 597e306e7..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java +++ /dev/null @@ -1,316 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; -import me.jellysquid.mods.sodium.client.gui.options.OptionGroup; -import me.jellysquid.mods.sodium.client.gui.options.OptionImpact; -import me.jellysquid.mods.sodium.client.gui.options.OptionPage; -import me.jellysquid.mods.sodium.client.gui.options.control.Control; -import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; -import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; -import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget; -import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.Drawable; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.option.VideoOptionsScreen; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.OrderedText; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.Formatting; -import net.minecraft.util.Language; -import net.minecraft.util.Util; -import org.lwjgl.glfw.GLFW; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.stream.Stream; - -public class SodiumOptionsGUI extends Screen { - private final List pages = new ArrayList<>(); - - private final List> controls = new ArrayList<>(); - private final List drawable = new ArrayList<>(); - - private final Screen prevScreen; - - private OptionPage currentPage; - - private FlatButtonWidget applyButton, closeButton, undoButton; - private FlatButtonWidget donateButton, hideDonateButton; - - private boolean hasPendingChanges; - private ControlElement hoveredElement; - - public SodiumOptionsGUI(Screen prevScreen) { - super(new TranslatableText("Rubidium Options")); - - this.prevScreen = prevScreen; - - this.pages.add(SodiumGameOptionPages.general()); - this.pages.add(SodiumGameOptionPages.quality()); - this.pages.add(SodiumGameOptionPages.advanced()); - this.pages.add(SodiumGameOptionPages.performance()); - } - - public void setPage(OptionPage page) { - this.currentPage = page; - - this.rebuildGUI(); - } - - @Override - protected void init() { - super.init(); - - this.rebuildGUI(); - } - - private void rebuildGUI() { - this.controls.clear(); - this.children.clear(); - this.drawable.clear(); - - if (this.currentPage == null) { - if (this.pages.isEmpty()) { - throw new IllegalStateException("No pages are available?!"); - } - - // Just use the first page for now - this.currentPage = this.pages.get(0); - } - - this.rebuildGUIPages(); - this.rebuildGUIOptions(); - - this.undoButton = new FlatButtonWidget(new Dim2i(this.width - 211, this.height - 26, 65, 20), new TranslatableText("sodium.options.buttons.undo").getString(), this::undoChanges); - this.applyButton = new FlatButtonWidget(new Dim2i(this.width - 142, this.height - 26, 65, 20), new TranslatableText("sodium.options.buttons.apply").getString(), this::applyChanges); - this.closeButton = new FlatButtonWidget(new Dim2i(this.width - 73, this.height - 26, 65, 20), new TranslatableText("gui.done").getString(), this::onClose); - this.donateButton = new FlatButtonWidget(new Dim2i(this.width - 128, 6, 100, 20), new TranslatableText("sodium.options.buttons.donate").getString(), this::openDonationPage); - this.hideDonateButton = new FlatButtonWidget(new Dim2i(this.width - 26, 6, 20, 20), "x", this::hideDonationButton); - - if (SodiumClientMod.options().notifications.hideDonationButton) { - this.setDonationButtonVisibility(false); - } - - this.children.add(this.undoButton); - this.children.add(this.applyButton); - this.children.add(this.closeButton); - this.children.add(this.donateButton); - this.children.add(this.hideDonateButton); - - for (Element element : this.children) { - if (element instanceof Drawable) { - this.drawable.add((Drawable) element); - } - } - } - - private void setDonationButtonVisibility(boolean value) { - this.donateButton.setVisible(value); - this.hideDonateButton.setVisible(value); - } - - private void hideDonationButton() { - SodiumGameOptions options = SodiumClientMod.options(); - options.notifications.hideDonationButton = true; - - try { - options.writeChanges(); - } catch (IOException e) { - throw new RuntimeException("Failed to save configuration", e); - } - - this.setDonationButtonVisibility(false); - } - - private void rebuildGUIPages() { - int x = 6; - int y = 6; - - for (OptionPage page : this.pages) { - int width = 12 + this.textRenderer.getWidth(page.getNewName()); - - FlatButtonWidget button = new FlatButtonWidget(new Dim2i(x, y, width, 18), page.getNewName(), () -> this.setPage(page)); - button.setSelected(this.currentPage == page); - - x += width + 6; - - this.children.add(button); - } - } - - private void rebuildGUIOptions() { - int x = 6; - int y = 28; - - for (OptionGroup group : this.currentPage.getGroups()) { - // Add each option's control element - for (Option option : group.getOptions()) { - Control control = option.getControl(); - ControlElement element = control.createElement(new Dim2i(x, y, 200, 18)); - - this.controls.add(element); - this.children.add(element); - - // Move down to the next option - y += 18; - } - - // Add padding beneath each option group - y += 4; - } - } - - @Override - public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { - super.renderBackground(matrixStack); - - this.updateControls(); - - for (Drawable drawable : this.drawable) { - drawable.render(matrixStack, mouseX, mouseY, delta); - } - - if (this.hoveredElement != null) { - this.renderOptionTooltip(matrixStack, this.hoveredElement); - } - } - - private void updateControls() { - ControlElement hovered = this.getActiveControls() - .filter(ControlElement::isHovered) - .findFirst() - .orElse(null); - - boolean hasChanges = this.getAllOptions() - .anyMatch(Option::hasChanged); - - for (OptionPage page : this.pages) { - for (Option option : page.getOptions()) { - if (option.hasChanged()) { - hasChanges = true; - } - } - } - - this.applyButton.setEnabled(hasChanges); - this.undoButton.setVisible(hasChanges); - this.closeButton.setEnabled(!hasChanges); - - this.hasPendingChanges = hasChanges; - this.hoveredElement = hovered; - } - - private Stream> getAllOptions() { - return this.pages.stream() - .flatMap(s -> s.getOptions().stream()); - } - - private Stream> getActiveControls() { - return this.controls.stream(); - } - - private void renderOptionTooltip(MatrixStack matrixStack, ControlElement element) { - Dim2i dim = element.getDimensions(); - - int textPadding = 3; - int boxPadding = 3; - - int boxWidth = 200; - - int boxY = dim.getOriginY(); - int boxX = dim.getLimitX() + boxPadding; - - Option option = element.getOption(); - List tooltip = new ArrayList<>(this.textRenderer.wrapLines(option.getTooltip(), boxWidth - (textPadding * 2))); - - OptionImpact impact = option.getImpact(); - - if (impact != null) { - tooltip.add(Language.getInstance().reorder(new TranslatableText("sodium.options.performance_impact_string", impact.toDisplayString()).formatted(Formatting.GRAY))); - } - - int boxHeight = (tooltip.size() * 12) + boxPadding; - int boxYLimit = boxY + boxHeight; - int boxYCutoff = this.height - 40; - - // If the box is going to be cutoff on the Y-axis, move it back up the difference - if (boxYLimit > boxYCutoff) { - boxY -= boxYLimit - boxYCutoff; - } - - this.fillGradient(matrixStack, boxX, boxY, boxX + boxWidth, boxY + boxHeight, 0xE0000000, 0xE0000000); - - for (int i = 0; i < tooltip.size(); i++) { - this.textRenderer.draw(matrixStack, tooltip.get(i), boxX + textPadding, boxY + textPadding + (i * 12), 0xFFFFFFFF); - } - } - - private void applyChanges() { - final HashSet> dirtyStorages = new HashSet<>(); - final EnumSet flags = EnumSet.noneOf(OptionFlag.class); - - this.getAllOptions().forEach((option -> { - if (!option.hasChanged()) { - return; - } - - option.applyChanges(); - - flags.addAll(option.getFlags()); - dirtyStorages.add(option.getStorage()); - })); - - MinecraftClient client = MinecraftClient.getInstance(); - - if (flags.contains(OptionFlag.REQUIRES_RENDERER_RELOAD)) { - client.worldRenderer.reload(); - } - - if (flags.contains(OptionFlag.REQUIRES_ASSET_RELOAD)) { - client.setMipmapLevels(client.options.mipmapLevels); - client.reloadResourcesConcurrently(); - } - - for (OptionStorage storage : dirtyStorages) { - storage.save(); - } - } - - private void undoChanges() { - this.getAllOptions() - .forEach(Option::reset); - } - - private void openDonationPage() { - Util.getOperatingSystem() - .open("https://caffeinemc.net/donate"); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (keyCode == GLFW.GLFW_KEY_P && (modifiers & GLFW.GLFW_MOD_SHIFT) != 0) { - MinecraftClient.getInstance().openScreen(new VideoOptionsScreen(this.prevScreen, MinecraftClient.getInstance().options)); - - return true; - } - - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean shouldCloseOnEsc() { - return !this.hasPendingChanges; - } - - @Override - public void onClose() { - this.client.openScreen(this.prevScreen); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/FormattedTextProvider.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/FormattedTextProvider.java deleted file mode 100644 index 0f3a79209..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/FormattedTextProvider.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -import net.minecraft.text.Text; - -public interface FormattedTextProvider { - Text getLocalizedName(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java deleted file mode 100644 index 55477f48c..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java +++ /dev/null @@ -1,35 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -import me.jellysquid.mods.sodium.client.gui.options.control.Control; -import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; -import net.minecraft.text.Text; - -import java.util.Collection; - -public interface Option { - Text getNewName(); - - String getName(); - - Text getTooltip(); - - OptionImpact getImpact(); - - Control getControl(); - - T getValue(); - - void setValue(T value); - - void reset(); - - OptionStorage getStorage(); - - boolean isAvailable(); - - boolean hasChanged(); - - void applyChanges(); - - Collection getFlags(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java deleted file mode 100644 index d7ac00621..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -public enum OptionFlag { - REQUIRES_RENDERER_RELOAD, - REQUIRES_ASSET_RELOAD, - REQUIRES_GAME_RESTART -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java deleted file mode 100644 index 97426724a..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -import com.google.common.collect.ImmutableList; -import org.apache.commons.lang3.Validate; - -import java.util.ArrayList; -import java.util.List; - -public class OptionGroup { - private final ImmutableList> options; - - private OptionGroup(ImmutableList> options) { - this.options = options; - } - - public static Builder createBuilder() { - return new Builder(); - } - - public ImmutableList> getOptions() { - return this.options; - } - - public static class Builder { - private final List> options = new ArrayList<>(); - - public Builder add(Option option) { - this.options.add(option); - - return this; - } - - public OptionGroup build() { - Validate.notEmpty(this.options, "At least one option must be specified"); - - return new OptionGroup(ImmutableList.copyOf(this.options)); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java deleted file mode 100644 index e5ab58cd9..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java +++ /dev/null @@ -1,24 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -import net.minecraft.text.TranslatableText; -import net.minecraft.util.Formatting; - -public enum OptionImpact { - LOW(Formatting.GREEN, new TranslatableText("sodium.option_impact.low").getString()), - MEDIUM(Formatting.YELLOW, new TranslatableText("sodium.option_impact.medium").getString()), - HIGH(Formatting.GOLD, new TranslatableText("sodium.option_impact.high").getString()), - EXTREME(Formatting.RED, new TranslatableText("sodium.option_impact.extreme").getString()), - VARIES(Formatting.WHITE, new TranslatableText("sodium.option_impact.varies").getString()); - - private final Formatting color; - private final String text; - - OptionImpact(Formatting color, String text) { - this.color = color; - this.text = text; - } - - public String toDisplayString() { - return this.color + this.text; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java deleted file mode 100644 index 10518748e..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java +++ /dev/null @@ -1,217 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -import me.jellysquid.mods.sodium.client.gui.options.binding.GenericBinding; -import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding; -import me.jellysquid.mods.sodium.client.gui.options.control.Control; -import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import org.apache.commons.lang3.Validate; - -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.function.BiConsumer; -import java.util.function.Function; - -public class OptionImpl implements Option { - private final OptionStorage storage; - - private final OptionBinding binding; - private final Control control; - - private final EnumSet flags; - - private final Text name; - private final Text tooltip; - - private final OptionImpact impact; - - private T value; - private T modifiedValue; - - private final boolean enabled; - - private OptionImpl(OptionStorage storage, - Text name, - Text tooltip, - OptionBinding binding, - Function, Control> control, - EnumSet flags, - OptionImpact impact, - boolean enabled) { - this.storage = storage; - this.name = name; - this.tooltip = tooltip; - this.binding = binding; - this.impact = impact; - this.flags = flags; - this.control = control.apply(this); - this.enabled = enabled; - - this.reset(); - } - - @Override - public Text getNewName() { - return this.name; - } - - @Override - public String getName() { - return this.getNewName().getString(); - } - - @Override - public Text getTooltip() { - return this.tooltip; - } - - @Override - public OptionImpact getImpact() { - return this.impact; - } - - @Override - public Control getControl() { - return this.control; - } - - @Override - public T getValue() { - return this.modifiedValue; - } - - @Override - public void setValue(T value) { - this.modifiedValue = value; - } - - @Override - public void reset() { - this.value = this.binding.getValue(this.storage.getData()); - this.modifiedValue = this.value; - } - - @Override - public OptionStorage getStorage() { - return this.storage; - } - - @Override - public boolean isAvailable() { - return this.enabled; - } - - @Override - public boolean hasChanged() { - return !this.value.equals(this.modifiedValue); - } - - @Override - public void applyChanges() { - this.binding.setValue(this.storage.getData(), this.modifiedValue); - this.value = this.modifiedValue; - } - - @Override - public Collection getFlags() { - return this.flags; - } - - public static Builder createBuilder(Class type, OptionStorage storage) { - return new Builder<>(storage); - } - - public static class Builder { - private final OptionStorage storage; - private Text name; - private Text tooltip; - private OptionBinding binding; - private Function, Control> control; - private OptionImpact impact; - private final EnumSet flags = EnumSet.noneOf(OptionFlag.class); - private boolean enabled = true; - - private Builder(OptionStorage storage) { - this.storage = storage; - } - - public Builder setName(Text name) { - Validate.notNull(name, "Argument must not be null"); - - this.name = name; - - return this; - } - - public Builder setName(String name) { - return setName(new LiteralText(name)); - } - - public Builder setTooltip(Text tooltip) { - Validate.notNull(tooltip, "Argument must not be null"); - - this.tooltip = tooltip; - - return this; - } - - public Builder setTooltip(String tooltip) { - return setTooltip(new LiteralText(tooltip)); - } - - public Builder setBinding(BiConsumer setter, Function getter) { - Validate.notNull(setter, "Setter must not be null"); - Validate.notNull(getter, "Getter must not be null"); - - this.binding = new GenericBinding<>(setter, getter); - - return this; - } - - - public Builder setBinding(OptionBinding binding) { - Validate.notNull(binding, "Argument must not be null"); - - this.binding = binding; - - return this; - } - - public Builder setControl(Function, Control> control) { - Validate.notNull(control, "Argument must not be null"); - - this.control = control; - - return this; - } - - public Builder setImpact(OptionImpact impact) { - this.impact = impact; - - return this; - } - - public Builder setEnabled(boolean value) { - this.enabled = value; - - return this; - } - - public Builder setFlags(OptionFlag... flags) { - Collections.addAll(this.flags, flags); - - return this; - } - - public OptionImpl build() { - Validate.notNull(this.name, "Name must be specified"); - Validate.notNull(this.tooltip, "Tooltip must be specified"); - Validate.notNull(this.binding, "Option binding must be specified"); - Validate.notNull(this.control, "Control must be specified"); - - return new OptionImpl<>(this.storage, this.name, this.tooltip, this.binding, this.control, this.flags, this.impact, this.enabled); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java deleted file mode 100644 index 5d4cd852b..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java +++ /dev/null @@ -1,45 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -import com.google.common.collect.ImmutableList; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; - -public class OptionPage { - private final Text name; - private final ImmutableList groups; - private final ImmutableList> options; - - public OptionPage(String name, ImmutableList groups) { - this(new LiteralText(name), groups); - } - - public OptionPage(Text name, ImmutableList groups) { - this.name = name; - this.groups = groups; - - ImmutableList.Builder> builder = ImmutableList.builder(); - - for (OptionGroup group : groups) { - builder.addAll(group.getOptions()); - } - - this.options = builder.build(); - } - - public ImmutableList getGroups() { - return this.groups; - } - - public ImmutableList> getOptions() { - return this.options; - } - - public Text getNewName() { - return this.name; - } - - public String getName() { - return this.getNewName().getString(); - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java deleted file mode 100644 index a7ace2ef5..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java +++ /dev/null @@ -1,5 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -public interface TextProvider { - String getLocalizedName(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java deleted file mode 100644 index 9e166c93e..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java +++ /dev/null @@ -1,24 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.binding; - -import java.util.function.BiConsumer; -import java.util.function.Function; - -public class GenericBinding implements OptionBinding { - private final BiConsumer setter; - private final Function getter; - - public GenericBinding(BiConsumer setter, Function getter) { - this.setter = setter; - this.getter = getter; - } - - @Override - public void setValue(S storage, T value) { - this.setter.accept(storage, value); - } - - @Override - public T getValue(S storage) { - return this.getter.apply(storage); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java deleted file mode 100644 index 5e597a679..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.binding; - -public interface OptionBinding { - void setValue(S storage, T value); - - T getValue(S storage); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java deleted file mode 100644 index 97fb26305..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java +++ /dev/null @@ -1,23 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.binding.compat; - -import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding; -import net.minecraft.client.option.BooleanOption; -import net.minecraft.client.option.GameOptions; - -public class VanillaBooleanOptionBinding implements OptionBinding { - private final BooleanOption option; - - public VanillaBooleanOptionBinding(BooleanOption option) { - this.option = option; - } - - @Override - public void setValue(GameOptions storage, Boolean value) { - this.option.set(storage, value.toString()); - } - - @Override - public Boolean getValue(GameOptions storage) { - return this.option.get(storage); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java deleted file mode 100644 index 28931db82..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java +++ /dev/null @@ -1,12 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.util.Dim2i; - -public interface Control { - Option getOption(); - - ControlElement createElement(Dim2i dim); - - int getMaxWidth(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java deleted file mode 100644 index 380b2a145..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java +++ /dev/null @@ -1,58 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.gui.widgets.AbstractWidget; -import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.Formatting; - -public class ControlElement extends AbstractWidget { - protected final Option option; - - protected final Dim2i dim; - - protected boolean hovered; - - public ControlElement(Option option, Dim2i dim) { - this.option = option; - this.dim = dim; - } - - public boolean isHovered() { - return this.hovered; - } - - @Override - public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { - String name = this.option.getName(); - String label; - - if (this.hovered && this.font.getWidth(name) > (this.dim.getWidth() - this.option.getControl().getMaxWidth())) { - name = name.substring(0, Math.min(name.length(), 10)) + "..."; - } - - if (this.option.isAvailable()) { - if (this.option.hasChanged()) { - label = Formatting.ITALIC + name + " *"; - } else { - label = Formatting.WHITE + name; - } - } else { - label = String.valueOf(Formatting.GRAY) + Formatting.STRIKETHROUGH + name; - } - - this.hovered = this.dim.containsCursor(mouseX, mouseY); - - - this.drawRect(this.dim.getOriginX(), this.dim.getOriginY(), this.dim.getLimitX(), this.dim.getLimitY(), this.hovered ? 0xE0000000 : 0x90000000); - this.drawString(matrixStack, label, this.dim.getOriginX() + 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); - } - - public Option getOption() { - return this.option; - } - - public Dim2i getDimensions() { - return this.dim; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java deleted file mode 100644 index 1220b2975..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java +++ /dev/null @@ -1,47 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import net.minecraft.text.TranslatableText; - -public interface ControlValueFormatter { - static ControlValueFormatter guiScale() { - return (v) -> (v == 0) ? new TranslatableText("options.guiScale.auto").getString() : new TranslatableText(v + "x").getString(); - } - - static ControlValueFormatter fpsLimit() { - return (v) -> (v == 260) ? new TranslatableText("options.framerateLimit.max").getString() : new TranslatableText("options.framerate", v).getString(); - } - - static ControlValueFormatter brightness() { - return (v) -> { - if (v == 0) { - return new TranslatableText("options.gamma.min").getString(); - } else if (v == 100) { - return new TranslatableText("options.gamma.max").getString(); - } else { - return new TranslatableText(v + "%").getString(); - } - }; - } - - String format(int value); - - static ControlValueFormatter percentage() { - return (v) -> new TranslatableText(v + "%").getString(); - } - - static ControlValueFormatter multiplier() { - return (v) -> new TranslatableText(v + "x").getString(); - } - - static ControlValueFormatter quantity(String name) { - return (v) -> new TranslatableText(name, v).getString(); - } - - static ControlValueFormatter quantityOrDisabled(String name, String disableText) { - return (v) -> new TranslatableText(v == 0 ? disableText : name, v).getString(); - } - - static ControlValueFormatter number() { - return String::valueOf; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java deleted file mode 100644 index d8e778cfd..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java +++ /dev/null @@ -1,121 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import me.jellysquid.mods.sodium.client.gui.options.FormattedTextProvider; -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.gui.options.TextProvider; -import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; -import org.apache.commons.lang3.Validate; - -import java.util.Arrays; - -public class CyclingControl> implements Control { - private final Option option; - private final T[] allowedValues; - private final Text[] names; - - public CyclingControl(Option option, Class enumType) { - this(option, enumType, enumType.getEnumConstants()); - } - - public CyclingControl(Option option, Class enumType, Text[] names) { - T[] universe = enumType.getEnumConstants(); - - Validate.isTrue(universe.length == names.length, "Mismatch between universe length and names array length"); - Validate.notEmpty(universe, "The enum universe must contain at least one item"); - - this.option = option; - this.allowedValues = universe; - this.names = names; - } - - @Deprecated - public CyclingControl(Option option, Class enumType, String[] names) { - this(option, enumType, Arrays.stream(names).map(LiteralText::new).toArray(Text[]::new)); - } - - public CyclingControl(Option option, Class enumType, T[] allowedValues) { - T[] universe = enumType.getEnumConstants(); - - this.option = option; - this.allowedValues = allowedValues; - this.names = new Text[universe.length]; - - for (int i = 0; i < this.names.length; i++) { - Text name; - T value = universe[i]; - - if (value instanceof TextProvider) { - name = new LiteralText(((TextProvider)value).getLocalizedName()); - } else if(value instanceof FormattedTextProvider) { - name = ((FormattedTextProvider)value).getLocalizedName(); - } else { - name = new LiteralText(value.name()); - } - - this.names[i] = name; - } - } - - @Override - public Option getOption() { - return this.option; - } - - @Override - public ControlElement createElement(Dim2i dim) { - return new CyclingControlElement<>(this.option, dim, this.allowedValues, this.names); - } - - @Override - public int getMaxWidth() { - return 70; - } - - private static class CyclingControlElement> extends ControlElement { - private final T[] allowedValues; - private final Text[] names; - private int currentIndex; - - public CyclingControlElement(Option option, Dim2i dim, T[] allowedValues, Text[] names) { - super(option, dim); - - this.allowedValues = allowedValues; - this.names = names; - this.currentIndex = 0; - - for (int i = 0; i < allowedValues.length; i++) { - if (allowedValues[i] == option.getValue()) { - this.currentIndex = i; - break; - } - } - } - - @Override - public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { - super.render(matrixStack, mouseX, mouseY, delta); - - Enum value = this.option.getValue(); - Text name = this.names[value.ordinal()]; - - int strWidth = this.getTextWidth(name); - this.drawText(matrixStack, name, this.dim.getLimitX() - strWidth - 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { - this.currentIndex = (this.option.getValue().ordinal() + 1) % this.allowedValues.length; - this.option.setValue(this.allowedValues[this.currentIndex]); - this.playClickSound(); - - return true; - } - - return false; - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java deleted file mode 100644 index 0eca60523..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java +++ /dev/null @@ -1,164 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.util.math.Rect2i; -import net.minecraft.util.math.MathHelper; -import org.apache.commons.lang3.Validate; - -public class SliderControl implements Control { - private final Option option; - - private final int min, max, interval; - - private final ControlValueFormatter mode; - - public SliderControl(Option option, int min, int max, int interval, ControlValueFormatter mode) { - Validate.isTrue(max > min, "The maximum value must be greater than the minimum value"); - Validate.isTrue(interval > 0, "The slider interval must be greater than zero"); - Validate.isTrue(((max - min) % interval) == 0, "The maximum value must be divisable by the interval"); - Validate.notNull(mode, "The slider mode must not be null"); - - this.option = option; - this.min = min; - this.max = max; - this.interval = interval; - this.mode = mode; - } - - @Override - public ControlElement createElement(Dim2i dim) { - return new Button(this.option, dim, this.min, this.max, this.interval, this.mode); - } - - @Override - public Option getOption() { - return this.option; - } - - @Override - public int getMaxWidth() { - return 130; - } - - private static class Button extends ControlElement { - private static final int THUMB_WIDTH = 2, TRACK_HEIGHT = 1; - - private final Rect2i sliderBounds; - private final ControlValueFormatter formatter; - - private final int min; - private final int range; - private final int interval; - - private double thumbPosition; - - public Button(Option option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter) { - super(option, dim); - - this.min = min; - this.range = max - min; - this.interval = interval; - this.thumbPosition = this.getThumbPositionForValue(option.getValue()); - this.formatter = formatter; - - this.sliderBounds = new Rect2i(dim.getLimitX() - 96, dim.getCenterY() - 5, 90, 10); - } - - @Override - public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { - super.render(matrixStack, mouseX, mouseY, delta); - - if (this.option.isAvailable() && this.hovered) { - this.renderSlider(matrixStack); - } else { - this.renderStandaloneValue(matrixStack); - } - } - - private void renderStandaloneValue(MatrixStack matrixStack) { - int sliderX = this.sliderBounds.getX(); - int sliderY = this.sliderBounds.getY(); - int sliderWidth = this.sliderBounds.getWidth(); - int sliderHeight = this.sliderBounds.getHeight(); - - String label = this.formatter.format(this.option.getValue()); - int labelWidth = this.font.getWidth(label); - - this.drawString(matrixStack, label, sliderX + sliderWidth - labelWidth, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); - } - - private void renderSlider(MatrixStack matrixStack) { - int sliderX = this.sliderBounds.getX(); - int sliderY = this.sliderBounds.getY(); - int sliderWidth = this.sliderBounds.getWidth(); - int sliderHeight = this.sliderBounds.getHeight(); - - this.thumbPosition = this.getThumbPositionForValue(option.getValue()); - - double thumbOffset = MathHelper.clamp((double) (this.getIntValue() - this.min) / this.range * sliderWidth, 0, sliderWidth); - - double thumbX = sliderX + thumbOffset - THUMB_WIDTH; - double trackY = sliderY + (sliderHeight / 2) - ((double) TRACK_HEIGHT / 2); - - this.drawRect(thumbX, sliderY, thumbX + (THUMB_WIDTH * 2), sliderY + sliderHeight, 0xFFFFFFFF); - this.drawRect(sliderX, trackY, sliderX + sliderWidth, trackY + TRACK_HEIGHT, 0xFFFFFFFF); - - String label = String.valueOf(this.getIntValue()); - - int labelWidth = this.font.getWidth(label); - - this.drawString(matrixStack, label, sliderX - labelWidth - 6, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); - } - - public int getIntValue() { - return this.min + (this.interval * (int) Math.round(this.getSnappedThumbPosition() / this.interval)); - } - - public double getSnappedThumbPosition() { - return this.thumbPosition / (1.0D / this.range); - } - - public double getThumbPositionForValue(int value) { - return (value - this.min) * (1.0D / this.range); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (this.option.isAvailable() && button == 0 && this.sliderBounds.contains((int) mouseX, (int) mouseY)) { - this.setValueFromMouse(mouseX); - - return true; - } - - return false; - } - - private void setValueFromMouse(double d) { - this.setValue((d - (double) this.sliderBounds.getX()) / (double) this.sliderBounds.getWidth()); - } - - private void setValue(double d) { - this.thumbPosition = MathHelper.clamp(d, 0.0D, 1.0D); - - int value = this.getIntValue(); - - if (this.option.getValue() != value) { - this.option.setValue(value); - } - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - if (this.option.isAvailable() && button == 0) { - this.setValueFromMouse(mouseX); - - return true; - } - - return false; - } - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java deleted file mode 100644 index 63bc41c12..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java +++ /dev/null @@ -1,94 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.util.math.Rect2i; - -public class TickBoxControl implements Control { - private final Option option; - - public TickBoxControl(Option option) { - this.option = option; - } - - @Override - public ControlElement createElement(Dim2i dim) { - return new TickBoxControlElement(this.option, dim); - } - - @Override - public int getMaxWidth() { - return 30; - } - - @Override - public Option getOption() { - return this.option; - } - - private static class TickBoxControlElement extends ControlElement { - private final Rect2i button; - - public TickBoxControlElement(Option option, Dim2i dim) { - super(option, dim); - - this.button = new Rect2i(dim.getLimitX() - 16, dim.getCenterY() - 5, 10, 10); - } - - @Override - public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { - super.render(matrixStack, mouseX, mouseY, delta); - - final int x = this.button.getX(); - final int y = this.button.getY(); - final int w = x + this.button.getWidth(); - final int h = y + this.button.getHeight(); - - final boolean enabled = this.option.isAvailable(); - final boolean ticked = enabled && this.option.getValue(); - - final int color; - - if (enabled) { - color = ticked ? 0xFF94E4D3 : 0xFFFFFFFF; - } else { - color = 0xFFAAAAAA; - } - - if (ticked) { - this.drawRect(x + 2, y + 2, w - 2, h - 2, color); - } - - this.drawRectOutline(x, y, w, h, color); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { - this.option.setValue(!this.option.getValue()); - this.playClickSound(); - - return true; - } - - return false; - } - - protected void drawRectOutline(int x, int y, int w, int h, int color) { - final float a = (float) (color >> 24 & 255) / 255.0F; - final float r = (float) (color >> 16 & 255) / 255.0F; - final float g = (float) (color >> 8 & 255) / 255.0F; - final float b = (float) (color & 255) / 255.0F; - - this.drawQuads(vertices -> { - addQuad(vertices, x, y, w, y + 1, a, r, g, b); - addQuad(vertices, x, h - 1, w, h, a, r, g, b); - addQuad(vertices, x, y, x + 1, h, a, r, g, b); - addQuad(vertices, w - 1, y, w, h, a, r, g, b); - }); - } - } - - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java deleted file mode 100644 index 30663f78d..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.storage; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.option.GameOptions; - -public class MinecraftOptionsStorage implements OptionStorage { - private final MinecraftClient client; - - public MinecraftOptionsStorage() { - this.client = MinecraftClient.getInstance(); - } - - @Override - public GameOptions getData() { - return this.client.options; - } - - @Override - public void save() { - this.getData().write(); - - SodiumClientMod.logger().info("Flushed changes to Minecraft configuration"); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java deleted file mode 100644 index a2e4966da..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.storage; - -public interface OptionStorage { - T getData(); - - void save(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java deleted file mode 100644 index c8b3372b5..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java +++ /dev/null @@ -1,30 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.storage; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; - -import java.io.IOException; - -public class SodiumOptionsStorage implements OptionStorage { - private final SodiumGameOptions options; - - public SodiumOptionsStorage() { - this.options = SodiumClientMod.options(); - } - - @Override - public SodiumGameOptions getData() { - return this.options; - } - - @Override - public void save() { - try { - this.options.writeChanges(); - } catch (IOException e) { - throw new RuntimeException("Couldn't save configuration changes", e); - } - - SodiumClientMod.logger().info("Flushed changes to Rubidium configuration"); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java deleted file mode 100644 index cb7b292db..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java +++ /dev/null @@ -1,77 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.widgets; - -import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.Drawable; -import net.minecraft.client.gui.Element; -import net.minecraft.client.render.*; -import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.sound.SoundEvents; -import net.minecraft.text.Text; -import org.lwjgl.opengl.GL20C; - -import java.util.function.Consumer; - -public abstract class AbstractWidget implements Drawable, Element { - protected final TextRenderer font; - - protected AbstractWidget() { - this.font = MinecraftClient.getInstance().textRenderer; - } - - protected void drawString(MatrixStack matrixStack, String str, int x, int y, int color) { - this.font.draw(matrixStack, str, x, y, color); - } - - protected void drawText(MatrixStack matrixStack, Text text, int x, int y, int color) { - this.font.draw(matrixStack, text, x, y, color); - } - - protected void drawRect(double x1, double y1, double x2, double y2, int color) { - float a = (float) (color >> 24 & 255) / 255.0F; - float r = (float) (color >> 16 & 255) / 255.0F; - float g = (float) (color >> 8 & 255) / 255.0F; - float b = (float) (color & 255) / 255.0F; - - this.drawQuads(vertices -> addQuad(vertices, x1, y1, x2, y2, a, r, g, b)); - } - - protected void drawQuads(Consumer consumer) { - RenderSystem.enableBlend(); - RenderSystem.disableTexture(); - RenderSystem.defaultBlendFunc(); - - BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); - bufferBuilder.begin(GL20C.GL_QUADS, VertexFormats.POSITION_COLOR); - - consumer.accept(bufferBuilder); - - bufferBuilder.end(); - - BufferRenderer.draw(bufferBuilder); - RenderSystem.enableTexture(); - RenderSystem.disableBlend(); - } - - protected static void addQuad(VertexConsumer consumer, double x1, double y1, double x2, double y2, float a, float r, float g, float b) { - consumer.vertex(x2, y1, 0.0D).color(r, g, b, a).next(); - consumer.vertex(x1, y1, 0.0D).color(r, g, b, a).next(); - consumer.vertex(x1, y2, 0.0D).color(r, g, b, a).next(); - consumer.vertex(x2, y2, 0.0D).color(r, g, b, a).next(); - } - - protected void playClickSound() { - MinecraftClient.getInstance().getSoundManager() - .play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - } - - protected int getStringWidth(String text) { - return this.font.getWidth(text); - } - - protected int getTextWidth(Text text) { - return this.font.getWidth(text); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java deleted file mode 100644 index f697aa8c9..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java +++ /dev/null @@ -1,76 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.widgets; - -import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.gui.Drawable; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; - -public class FlatButtonWidget extends AbstractWidget implements Drawable { - private final Dim2i dim; - private final Text label; - private final Runnable action; - - private boolean selected; - private boolean enabled = true; - private boolean visible = true; - - public FlatButtonWidget(Dim2i dim, String label, Runnable action) { - this(dim, new LiteralText(label), action); - } - - public FlatButtonWidget(Dim2i dim, Text label, Runnable action) { - this.dim = dim; - this.label = label; - this.action = action; - } - - @Override - public void render(MatrixStack matrixStack, int mouseX, int mouseY, float delta) { - if (!this.visible) { - return; - } - - boolean hovered = this.dim.containsCursor(mouseX, mouseY); - - int backgroundColor = this.enabled ? (hovered ? 0xE0000000 : 0x90000000) : 0x60000000; - int textColor = this.enabled ? 0xFFFFFFFF : 0x90FFFFFF; - - int strWidth = this.font.getWidth(this.label); - - this.drawRect(this.dim.getOriginX(), this.dim.getOriginY(), this.dim.getLimitX(), this.dim.getLimitY(), backgroundColor); - this.drawString(matrixStack, this.label.getString(), this.dim.getCenterX() - (strWidth / 2), this.dim.getCenterY() - 4, textColor); - - if (this.enabled && this.selected) { - this.drawRect(this.dim.getOriginX(), this.dim.getLimitY() - 1, this.dim.getLimitX(), this.dim.getLimitY(), 0xFF94E4D3); - } - } - - public void setSelected(boolean selected) { - this.selected = selected; - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (!this.enabled || !this.visible) { - return false; - } - - if (button == 0 && this.dim.containsCursor(mouseX, mouseY)) { - this.action.run(); - this.playClickSound(); - - return true; - } - - return false; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public void setVisible(boolean visible) { - this.visible = visible; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java b/src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java deleted file mode 100644 index c252815ae..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/ModelCuboidAccessor.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.model; - -import net.minecraft.client.model.ModelPart; - -public interface ModelCuboidAccessor { - ModelPart.Quad[] getQuads(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java index 18999c0f2..1783b0c81 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java @@ -1,10 +1,12 @@ package me.jellysquid.mods.sodium.client.model.light; +import cofh.lib.util.helpers.MathHelper; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; import me.jellysquid.mods.sodium.client.render.entity.EntityLightSampler; -import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; + +import static org.joml.Math.lerp; public class EntityLighter { private static final double MIN_BOX_SIZE = 0.001D; @@ -16,15 +18,15 @@ public static int getBlendedLight(EntityLightSampler light boolean calcBlockLight = !entity.isOnFire(); // Find the interpolated position of the entity - double x1 = MathHelper.lerp(tickDelta, entity.prevX, entity.getX()); - double y1 = MathHelper.lerp(tickDelta, entity.prevY, entity.getY()); - double z1 = MathHelper.lerp(tickDelta, entity.prevZ, entity.getZ()); + double x1 = lerp(tickDelta, entity.prevPosX, entity.posX); + double y1 = lerp(tickDelta, entity.prevPosY, entity.posY); + double z1 = lerp(tickDelta, entity.prevPosZ, entity.posZ); // Bounding boxes with no volume cause issues, ensure they're non-zero // Notably, armor stands in "Marker" mode decide this is a cute thing to do // https://github.com/jellysquid3/sodium-fabric/issues/60 - double width = Math.max(entity.getWidth(), MIN_BOX_SIZE); - double height = Math.max(entity.getHeight(), MIN_BOX_SIZE); + double width = Math.max(entity.width, MIN_BOX_SIZE); + double height = Math.max(entity.height, MIN_BOX_SIZE); double x2 = x1 + width; double y2 = y1 + height; @@ -59,10 +61,10 @@ public static int getBlendedLight(EntityLightSampler light for (int bZ = bMinZ; bZ < bMaxZ; bZ++) { pos.set(bX, bY, bZ); - BlockState blockState = entity.world.getBlockState(pos); + BlockState blockState = entity.worldObj.getBlockState(pos); // Do not consider light-blocking volumes - if (blockState.isOpaqueFullCube(entity.world, pos) && blockState.getLightValue(entity.world, pos) <= 0) { + if (blockState.isOpaqueFullCube(entity.worldObj, pos) && blockState.getLightValue(entity.worldObj, pos) <= 0) { continue; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java index f431e2b4a..e81603d2c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/LightPipeline.java @@ -1,13 +1,13 @@ package me.jellysquid.mods.sodium.client.model.light; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; +import net.minecraftforge.common.util.ForgeDirection; /** * Light pipelines allow model quads for any location in the world to be lit using various backends, including fluids - * and block entities. + * and block entities. */ public interface LightPipeline { /** @@ -18,5 +18,5 @@ public interface LightPipeline { * @param face The pre-computed facing vector of the quad * @param shade True if the block is shaded by ambient occlusion */ - void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction face, boolean shade); + void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, ForgeDirection cullFace, ForgeDirection face, boolean shade); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java index ce9503fdf..78d5b125b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.client.model.light.cache; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; import me.jellysquid.mods.sodium.client.world.WorldSlice; -import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.world.BlockRenderView; import java.util.Arrays; @@ -54,4 +54,4 @@ public long get(int x, int y, int z) { return this.light[l] = this.compute(x, y, z); } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java index ffbc58b33..93cad2763 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java @@ -1,9 +1,10 @@ package me.jellysquid.mods.sodium.client.model.light.cache; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import it.unimi.dsi.fastutil.longs.Long2LongLinkedOpenHashMap; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; + /** * A light data cache which uses a hash table to store previously accessed values. @@ -34,4 +35,4 @@ public long get(int x, int y, int z) { public void clearCache() { this.map.clear(); } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java index 02e774bef..e03114d24 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.client.model.light.data; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.WorldRenderer; +import net.minecraftforge.common.util.ForgeDirection; /** * The light data cache is used to make accessing the light data and occlusion properties of blocks cheaper. The data @@ -25,24 +25,20 @@ public abstract class LightDataAccess { private final BlockPos.Mutable pos = new BlockPos.Mutable(); protected BlockRenderView world; - public long get(int x, int y, int z, Direction d1, Direction d2) { - return this.get(x + d1.getOffsetX() + d2.getOffsetX(), - y + d1.getOffsetY() + d2.getOffsetY(), - z + d1.getOffsetZ() + d2.getOffsetZ()); + public long get(int x, int y, int z, ForgeDirection d1, ForgeDirection d2) { + return this.get(x + d1.offsetX + d2.offsetX, y + d1.offsetY + d2.offsetY, z + d1.offsetZ + d2.offsetZ); } - public long get(int x, int y, int z, Direction dir) { - return this.get(x + dir.getOffsetX(), - y + dir.getOffsetY(), - z + dir.getOffsetZ()); + public long get(int x, int y, int z, ForgeDirection dir) { + return this.get(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); } - public long get(BlockPos pos, Direction dir) { - return this.get(pos.getX(), pos.getY(), pos.getZ(), dir); + public long get(BlockPos pos, ForgeDirection dir) { + return this.get(pos.x, pos.y, pos.z, dir); } public long get(BlockPos pos) { - return this.get(pos.getX(), pos.getY(), pos.getZ()); + return this.get(pos.x, pos.y, pos.getZ()); } /** @@ -102,7 +98,7 @@ public static long packFC(boolean fullCube) { public static boolean unpackFC(long word) { return ((word >>> 58) & 0b1) != 0; } - + public static long packLM(int lm) { return (long) lm & 0xFFFFFFFFL; } @@ -124,4 +120,4 @@ public static float unpackAO(long word) { public BlockRenderView getWorld() { return this.world; } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java index d0a893e62..2a87fd05d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java @@ -1,15 +1,14 @@ package me.jellysquid.mods.sodium.client.model.light.flat; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.BlockRenderView; +import net.minecraftforge.common.util.ForgeDirection; import java.util.Arrays; @@ -28,7 +27,7 @@ public FlatLightPipeline(LightDataAccess lightCache) { } @Override - public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction face, boolean shade) { + public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, ForgeDirection cullFace, ForgeDirection face, boolean shade) { int lightmap; // To match vanilla behavior, use the cull face if it exists/is available @@ -56,7 +55,7 @@ public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direc * behind tinted glass. {@link LightDataAccess} cannot efficiently store lightmaps computed with * inconsistent values so this method exists to mirror vanilla behavior as closely as possible. */ - private int getOffsetLightmap(BlockPos pos, Direction face) { + private int getOffsetLightmap(BlockPos pos, ForgeDirection face) { int lightmap = LightDataAccess.unpackLM(this.lightCache.get(pos, face)); // If the block light is not 15 (max)... if ((lightmap & 0xF0) != 0xF0) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java index 7833dc21d..a6edf74e1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoFaceData.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.model.light.smooth; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; +import net.minecraftforge.common.util.ForgeDirection; import static me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache.unpackAO; import static me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache.unpackFO; @@ -18,19 +18,19 @@ class AoFaceData { private int flags; - public void initLightData(LightDataAccess cache, BlockPos pos, Direction direction, boolean offset) { - final int x = pos.getX(); - final int y = pos.getY(); - final int z = pos.getZ(); + public void initLightData(LightDataAccess cache, BlockPos pos, ForgeDirection direction, boolean offset) { + final int x = pos.x; + final int y = pos.y; + final int z = pos.z; final int adjX; final int adjY; final int adjZ; if (offset) { - adjX = x + direction.getOffsetX(); - adjY = y + direction.getOffsetY(); - adjZ = z + direction.getOffsetZ(); + adjX = x + direction.offsetX; + adjY = y + direction.offsetY; + adjZ = z + direction.offsetZ; } else { adjX = x; adjY = y; @@ -50,7 +50,7 @@ public void initLightData(LightDataAccess cache, BlockPos pos, Direction directi final float caao = unpackAO(adjWord); - Direction[] faces = AoNeighborInfo.get(direction).faces; + ForgeDirection[] faces = AoNeighborInfo.get(direction).faces; final long e0 = cache.get(adjX, adjY, adjZ, faces[0]); final int e0lm = unpackLM(e0); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java index 660e588c5..faf126614 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java @@ -1,13 +1,13 @@ package me.jellysquid.mods.sodium.client.model.light.smooth; -import net.minecraft.util.math.Direction; +import net.minecraftforge.common.util.ForgeDirection; /** * The neighbor information for each face of a block, used when performing smooth lighting in order to calculate * the occlusion of each corner. */ enum AoNeighborInfo { - DOWN(new Direction[] { Direction.WEST, Direction.EAST, Direction.NORTH, Direction.SOUTH }, 0.5F) { + DOWN(new ForgeDirection[] { ForgeDirection.WEST, ForgeDirection.EAST, ForgeDirection.NORTH, ForgeDirection.SOUTH }, 0.5F) { @Override public void calculateCornerWeights(float x, float y, float z, float[] out) { final float u = z; @@ -37,7 +37,7 @@ public float getDepth(float x, float y, float z) { return y; } }, - UP(new Direction[] { Direction.EAST, Direction.WEST, Direction.NORTH, Direction.SOUTH }, 1.0F) { + UP(new ForgeDirection[] { ForgeDirection.EAST, ForgeDirection.WEST, ForgeDirection.NORTH, ForgeDirection.SOUTH }, 1.0F) { @Override public void calculateCornerWeights(float x, float y, float z, float[] out) { final float u = z; @@ -67,7 +67,7 @@ public float getDepth(float x, float y, float z) { return 1.0f - y; } }, - NORTH(new Direction[] { Direction.UP, Direction.DOWN, Direction.EAST, Direction.WEST }, 0.8F) { + NORTH(new ForgeDirection[] { ForgeDirection.UP, ForgeDirection.DOWN, ForgeDirection.EAST, ForgeDirection.WEST }, 0.8F) { @Override public void calculateCornerWeights(float x, float y, float z, float[] out) { final float u = 1.0f - x; @@ -97,7 +97,7 @@ public float getDepth(float x, float y, float z) { return z; } }, - SOUTH(new Direction[] { Direction.WEST, Direction.EAST, Direction.DOWN, Direction.UP }, 0.8F) { + SOUTH(new ForgeDirection[] { ForgeDirection.WEST, ForgeDirection.EAST, ForgeDirection.DOWN, ForgeDirection.UP }, 0.8F) { @Override public void calculateCornerWeights(float x, float y, float z, float[] out) { final float u = y; @@ -127,7 +127,7 @@ public float getDepth(float x, float y, float z) { return 1.0f - z; } }, - WEST(new Direction[] { Direction.UP, Direction.DOWN, Direction.NORTH, Direction.SOUTH }, 0.6F) { + WEST(new ForgeDirection[] { ForgeDirection.UP, ForgeDirection.DOWN, ForgeDirection.NORTH, ForgeDirection.SOUTH }, 0.6F) { @Override public void calculateCornerWeights(float x, float y, float z, float[] out) { final float u = z; @@ -157,7 +157,7 @@ public float getDepth(float x, float y, float z) { return x; } }, - EAST(new Direction[] { Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH }, 0.6F) { + EAST(new ForgeDirection[] { ForgeDirection.DOWN, ForgeDirection.UP, ForgeDirection.NORTH, ForgeDirection.SOUTH }, 0.6F) { @Override public void calculateCornerWeights(float x, float y, float z, float[] out) { final float u = z; @@ -192,7 +192,7 @@ public float getDepth(float x, float y, float z) { * The direction of each corner block from this face, which can be retrieved by offsetting the position of the origin * block by the direction vector. */ - public final Direction[] faces; + public final ForgeDirection[] faces; /** * The constant brightness modifier for this face. This data exists to emulate the results of the OpenGL lighting @@ -200,7 +200,7 @@ public float getDepth(float x, float y, float z) { */ public final float strength; - AoNeighborInfo(Direction[] directions, float strength) { + AoNeighborInfo(ForgeDirection[] directions, float strength) { this.faces = directions; this.strength = strength; } @@ -243,7 +243,7 @@ public float getDepth(float x, float y, float z) { /** * @return Returns the {@link AoNeighborInfo} which corresponds with the specified direction */ - public static AoNeighborInfo get(Direction direction) { + public static AoNeighborInfo get(ForgeDirection direction) { return VALUES[direction.getId()]; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java index 265f22996..4bbac4afb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java @@ -1,13 +1,14 @@ package me.jellysquid.mods.sodium.client.model.light.smooth; +import com.google.common.math.DoubleMath; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import net.minecraftforge.common.util.ForgeDirection; + /** * A light pipeline which produces smooth interpolated lighting and ambient occlusion for model quads. This @@ -36,6 +37,7 @@ * unnecessary computation */ public class SmoothLightPipeline implements LightPipeline { + public static final double TOLERANCE = 1.0E-5F; /** * The cache which light data will be accessed from. */ @@ -65,7 +67,7 @@ public SmoothLightPipeline(LightDataAccess cache) { } @Override - public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction face, boolean shade) { + public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, ForgeDirection cullFace, ForgeDirection face, boolean shade) { this.updateCachedData(pos.asLong()); int flags = quad.getFlags(); @@ -97,7 +99,7 @@ public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direc * have two contributing sides. * Flags: IS_ALIGNED, !IS_PARTIAL */ - private void applyAlignedFullFace(AoNeighborInfo neighborInfo, BlockPos pos, Direction dir, QuadLightData out) { + private void applyAlignedFullFace(AoNeighborInfo neighborInfo, BlockPos pos, ForgeDirection dir, QuadLightData out) { AoFaceData faceData = this.getCachedFaceData(pos, dir, true); neighborInfo.mapCorners(faceData.lm, faceData.ao, out.lm, out.br); } @@ -106,7 +108,7 @@ private void applyAlignedFullFace(AoNeighborInfo neighborInfo, BlockPos pos, Dir * Calculates the light data for a grid-aligned quad that does not cover the entire block volume's face. * Flags: IS_ALIGNED, IS_PARTIAL */ - private void applyAlignedPartialFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out) { + private void applyAlignedPartialFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, ForgeDirection dir, QuadLightData out) { for (int i = 0; i < 4; i++) { // Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting float cx = clamp(quad.getX(i)); @@ -120,13 +122,13 @@ private void applyAlignedPartialFace(AoNeighborInfo neighborInfo, ModelQuadView } /** - * This method is the same as {@link #applyNonParallelFace(AoNeighborInfo, ModelQuadView, BlockPos, Direction, + * This method is the same as {@link #applyNonParallelFace(AoNeighborInfo, ModelQuadView, BlockPos, ForgeDirection, * QuadLightData)} but with the check for a depth of approximately 0 removed. If the quad is parallel but not * aligned, all of its vertices will have the same depth and this depth must be approximately greater than 0, * meaning the check for 0 will always return false. * Flags: !IS_ALIGNED, IS_PARALLEL */ - private void applyParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out) { + private void applyParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, ForgeDirection dir, QuadLightData out) { for (int i = 0; i < 4; i++) { // Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting float cx = clamp(quad.getX(i)); @@ -140,7 +142,7 @@ private void applyParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, // If the quad is approximately grid-aligned (not inset) to the other side of the block, avoid unnecessary // computation by treating it is as aligned - if (MathHelper.approximatelyEquals(depth, 1.0F)) { + if (DoubleMath.fuzzyEquals(depth, 1.0F, TOLERANCE)) { this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, false); } else { // Blend the occlusion factor between the blocks directly beside this face and the blocks above it @@ -153,7 +155,7 @@ private void applyParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, /** * Flags: !IS_ALIGNED, !IS_PARALLEL */ - private void applyNonParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out) { + private void applyNonParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, ForgeDirection dir, QuadLightData out) { for (int i = 0; i < 4; i++) { // Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting float cx = clamp(quad.getX(i)); @@ -166,9 +168,9 @@ private void applyNonParallelFace(AoNeighborInfo neighborInfo, ModelQuadView qua float depth = neighborInfo.getDepth(cx, cy, cz); // If the quad is approximately grid-aligned (not inset), avoid unnecessary computation by treating it is as aligned - if (MathHelper.approximatelyEquals(depth, 0.0F)) { + if (DoubleMath.fuzzyEquals(depth, 0.0F, TOLERANCE)) { this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, true); - } else if (MathHelper.approximatelyEquals(depth, 1.0F)) { + } else if (DoubleMath.fuzzyEquals(depth, 1.0F, TOLERANCE)) { this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, false); } else { // Blend the occlusion factor between the blocks directly beside this face and the blocks above it @@ -178,7 +180,7 @@ private void applyNonParallelFace(AoNeighborInfo neighborInfo, ModelQuadView qua } } - private void applyAlignedPartialFaceVertex(BlockPos pos, Direction dir, float[] w, int i, QuadLightData out, boolean offset) { + private void applyAlignedPartialFaceVertex(BlockPos pos, ForgeDirection dir, float[] w, int i, QuadLightData out, boolean offset) { AoFaceData faceData = this.getCachedFaceData(pos, dir, offset); if (!faceData.hasUnpackedLightData()) { @@ -193,7 +195,7 @@ private void applyAlignedPartialFaceVertex(BlockPos pos, Direction dir, float[] out.lm[i] = getLightMapCoord(sl, bl); } - private void applyInsetPartialFaceVertex(BlockPos pos, Direction dir, float n1d, float n2d, float[] w, int i, QuadLightData out) { + private void applyInsetPartialFaceVertex(BlockPos pos, ForgeDirection dir, float n1d, float n2d, float[] w, int i, QuadLightData out) { AoFaceData n1 = this.getCachedFaceData(pos, dir, false); if (!n1.hasUnpackedLightData()) { @@ -215,7 +217,7 @@ private void applyInsetPartialFaceVertex(BlockPos pos, Direction dir, float n1d, out.lm[i] = getLightMapCoord(sl, bl); } - private void applySidedBrightness(QuadLightData out, Direction face, boolean shade) { + private void applySidedBrightness(QuadLightData out, ForgeDirection face, boolean shade) { float brightness = this.lightCache.getWorld().getBrightness(face, shade); float[] br = out.br; @@ -227,7 +229,7 @@ private void applySidedBrightness(QuadLightData out, Direction face, boolean sha /** * Returns the cached data for a given facing or calculates it if it hasn't been cached. */ - private AoFaceData getCachedFaceData(BlockPos pos, Direction face, boolean offset) { + private AoFaceData getCachedFaceData(BlockPos pos, ForgeDirection face, boolean offset) { AoFaceData data = this.cachedFaceData[offset ? face.ordinal() : face.ordinal() + 6]; if (!data.hasLightData()) { @@ -267,4 +269,4 @@ private static int getLightMapCoord(float sl, float bl) { return (((int) sl & 0xFF) << 16) | ((int) bl & 0xFF); } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java index feb2f3d73..16cd79869 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuad.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.quad; -import net.minecraft.client.texture.Sprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.COLOR_INDEX; import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.LIGHT_INDEX; @@ -18,7 +18,7 @@ public class ModelQuad implements ModelQuadViewMutable { private final int[] data = new int[VERTEX_SIZE * 4]; private int flags; - private Sprite sprite; + private TextureAtlasSprite sprite; private int colorIdx; @Override @@ -67,7 +67,7 @@ public void setFlags(int flags) { } @Override - public void setSprite(Sprite sprite) { + public void setSprite(TextureAtlasSprite sprite) { this.sprite = sprite; } @@ -132,7 +132,7 @@ public int getFlags() { } @Override - public Sprite rubidium$getSprite() { + public TextureAtlasSprite rubidium$getSprite() { return this.sprite; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java index f230df5f8..8a2bc18cd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.quad; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import net.minecraft.client.texture.Sprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import java.nio.ByteBuffer; @@ -50,7 +50,7 @@ public interface ModelQuadView { int getLight(int idx); /** - * @return The integer-encoded normal vector for the vertex at index {@param idx} + * @return The integer-encoded getNormal vector for the vertex at index {@param idx} */ int getNormal(int idx); @@ -81,5 +81,5 @@ default void copyInto(ByteBuffer buf, int position) { /** * @return The sprite texture used by this quad, or null if none is attached */ - Sprite rubidium$getSprite(); + TextureAtlasSprite rubidium$getSprite(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java index 01579a64d..df3efdb3d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.quad; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import net.minecraft.client.texture.Sprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; /** * Provides a mutable view to a model quad. @@ -43,7 +43,7 @@ public interface ModelQuadViewMutable extends ModelQuadView { void setLight(int idx, int light); /** - * Sets the integer-encoded normal vector of the vertex at index {@param idx} to the value {@param light} + * Sets the integer-encoded getNormal vector of the vertex at index {@param idx} to the value {@param light} */ void setNormal(int idx, int norm); @@ -55,7 +55,7 @@ public interface ModelQuadViewMutable extends ModelQuadView { /** * Sets the sprite used by this quad */ - void setSprite(Sprite sprite); + void setSprite(TextureAtlasSprite sprite); /** * Sets the color index used by this quad diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java index 8994f6d70..3472db75b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.model.quad.blender; +import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import net.minecraft.block.BlockState; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.color.block.BlockColorProvider; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; +import net.minecraft.client.Minecraft; public interface BiomeColorBlender { /** @@ -22,8 +22,8 @@ public interface BiomeColorBlender { */ int[] getColors(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, ModelQuadView quad); - - static BiomeColorBlender create(MinecraftClient client) { + + static BiomeColorBlender create(Minecraft client) { return new ConfigurableColorBlender(client); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java index b7c6cad13..90da70f59 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.model.quad.blender; -import net.minecraft.state.State; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; + public interface BlockColorSettings { /** @@ -23,4 +23,4 @@ static boolean isSmoothBlendingEnabled(BlockRenderView world, State st return false; } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java index 42d52817e..fa6890931 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java @@ -1,22 +1,22 @@ package me.jellysquid.mods.sodium.client.model.quad.blender; +import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import net.minecraft.block.BlockState; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.color.block.BlockColorProvider; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; +import net.minecraft.client.Minecraft; class ConfigurableColorBlender implements BiomeColorBlender { private final BiomeColorBlender defaultBlender; private final BiomeColorBlender smoothBlender; - public ConfigurableColorBlender(MinecraftClient client) { + public ConfigurableColorBlender(Minecraft client) { this.defaultBlender = new FlatBiomeColorBlender(); this.smoothBlender = isSmoothBlendingEnabled(client) ? new SmoothBiomeColorBlender() : this.defaultBlender; } - private static boolean isSmoothBlendingEnabled(MinecraftClient client) { + private static boolean isSmoothBlendingEnabled(Minecraft client) { return client.options.biomeBlendRadius > 0; } @@ -34,4 +34,4 @@ public int[] getColors(BlockColorProvider colorizer, BlockRenderView world, Bloc return blender.getColors(colorizer, world, state, origin, quad); } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java index 7a2cd3be0..46a505ad3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java @@ -3,7 +3,6 @@ import com.google.common.collect.Sets; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import net.minecraft.block.Block; -import net.minecraft.block.Blocks; import java.util.Set; @@ -16,4 +15,4 @@ public class DefaultBlockColorSettings { public static boolean isSmoothBlendingAvailable(Block block) { return BLENDED_BLOCKS.contains(block); } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java index c134c4917..ffb16f19c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.model.quad.blender; +import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.util.color.ColorARGB; -import net.minecraft.block.BlockState; -import net.minecraft.client.color.block.BlockColorProvider; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; import java.util.Arrays; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java index 1b00ef1b7..820887bc1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.client.model.quad.blender; +import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; import me.jellysquid.mods.sodium.client.util.color.ColorARGB; import me.jellysquid.mods.sodium.client.util.color.ColorU8; -import net.minecraft.block.BlockState; -import net.minecraft.client.color.block.BlockColorProvider; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; public class SmoothBiomeColorBlender implements BiomeColorBlender { private final int[] cachedRet = new int[4]; @@ -114,4 +114,4 @@ private int getInterpolatedVertexColor(BlockColorProvider colorizer, BlockRender return ColorABGR.pack(ColorU8.normalize(fr), ColorU8.normalize(fg), ColorU8.normalize(fb)); } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index 933b286f3..af809f805 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.quad.properties; -import net.minecraft.util.math.Direction; +import net.minecraftforge.common.util.ForgeDirection; public enum ModelQuadFacing { UP, @@ -14,7 +14,7 @@ public enum ModelQuadFacing { public static final ModelQuadFacing[] VALUES = ModelQuadFacing.values(); public static final int COUNT = VALUES.length; - public static ModelQuadFacing fromDirection(Direction dir) { + public static ModelQuadFacing fromDirection(ForgeDirection dir) { switch (dir) { case DOWN: return DOWN; @@ -32,7 +32,7 @@ public static ModelQuadFacing fromDirection(Direction dir) { return UNASSIGNED; } } - + public ModelQuadFacing getOpposite() { switch (this) { case UP: diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java index bccce149e..fbd5629b0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.model.quad.properties; +import com.gtnewhorizons.angelica.compat.mojang.BakedQuad; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.util.math.Direction; +import net.minecraftforge.common.util.ForgeDirection; public class ModelQuadFlags { /** @@ -34,7 +34,7 @@ public static boolean contains(int flags, int mask) { */ public static int getQuadFlags(BakedQuad bakedQuad) { ModelQuadView quad = (ModelQuadView) bakedQuad; - Direction face = bakedQuad.getFace(); + ForgeDirection face = bakedQuad.getFace(); float minX = 32.0F; float minY = 32.0F; @@ -58,21 +58,21 @@ public static int getQuadFlags(BakedQuad bakedQuad) { } boolean partial = false; - + switch (face.getAxis()) { - case X : + case X : partial = minY >= 0.0001f || minZ >= 0.0001f || maxY <= 0.9999F || maxZ <= 0.9999F; break; - case Y : + case Y : partial = minX >= 0.0001f || minZ >= 0.0001f || maxX <= 0.9999F || maxZ <= 0.9999F; break; - case Z : + case Z : partial = minX >= 0.0001f || minY >= 0.0001f || maxX <= 0.9999F || maxY <= 0.9999F; break; }; boolean parallel = false; - + switch(face.getAxis()) { case X : parallel = minX == maxX; @@ -87,7 +87,7 @@ public static int getQuadFlags(BakedQuad bakedQuad) { boolean aligned = false; boolean flag = false; - + switch (face) { case DOWN : flag = minY < 0.0001f; @@ -108,7 +108,7 @@ public static int getQuadFlags(BakedQuad bakedQuad) { flag = maxX > 0.9999F; break; }; - + aligned = parallel && flag; int flags = 0; @@ -127,4 +127,4 @@ public static int getQuadFlags(BakedQuad bakedQuad) { return flags; } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java index decfdc3d0..c2c8bac33 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.type.VertexType; -import net.minecraft.client.render.VertexConsumer; /** * A drain allows the instantiation of {@link VertexSink} and is implemented on outputs which take vertex data. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java index 4d932b365..b30e0c99f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java @@ -26,7 +26,7 @@ public interface VertexSink { * Flushes any written vertex data to the {@link VertexDrain} this sink is connected to, ensuring it is actually * written to the backing storage. This should be called after vertex data has been written to this sink. * - * It is valid to flush a sink at any time. Only vertices that have been written since the last flush will be + * It is valid to flush a sink at any time. Only vertices that have been written since the peek flush will be * flushed when calling this method. If no vertices need to be flushed, this method does nothing. * * For optimal performance, callers should wait until they have written out as much vertex data as possible before diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java index ff79f8a03..7d589050f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex.buffer; import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; -import net.minecraft.client.util.GlAllocationUtils; +import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; @@ -15,7 +15,7 @@ public class VertexBufferBuilder implements VertexBufferView { public VertexBufferBuilder(BufferVertexFormat vertexFormat, int initialCapacity) { this.vertexFormat = vertexFormat; - this.buffer = GlAllocationUtils.allocateByteBuffer(initialCapacity); + this.buffer = BufferUtils.createByteBuffer(initialCapacity); this.capacity = initialCapacity; this.writerOffset = 0; } @@ -25,7 +25,7 @@ private void grow(int len) { int cap = Math.max(this.capacity * 2, this.capacity + len); // Allocate a new buffer and copy the old buffer's contents into it - ByteBuffer buffer = GlAllocationUtils.allocateByteBuffer(cap); + ByteBuffer buffer = BufferUtils.createByteBuffer(cap); buffer.put(this.buffer); buffer.position(0); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java index 405d9c767..22984520b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java @@ -1,7 +1,6 @@ package me.jellysquid.mods.sodium.client.model.vertex.buffer; import me.jellysquid.mods.sodium.client.model.vertex.type.BufferVertexType; -import org.lwjgl.system.MemoryUtil; /** * An unsafe {@link VertexBufferWriter} implementation which uses direct memory operations to enable fast blitting of diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java index a1af0e689..ff6436c72 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java @@ -1,7 +1,8 @@ package me.jellysquid.mods.sodium.client.model.vertex.fallback; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; -import net.minecraft.client.render.VertexConsumer; + /** * The base implementation for a {@link VertexSink} which writes to a black-boxed {@link VertexConsumer}. This is the diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java index cd3e3cafc..4503c8fcc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph; +import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.util.math.Matrix4f; +import org.joml.Matrix4f; public interface GlyphVertexSink extends VertexSink { - VertexFormat VERTEX_FORMAT = VertexFormats.POSITION_COLOR_TEXTURE_LIGHT; + VertexFormat VERTEX_FORMAT = DefaultVertexFormat.PARTICLE; /** * Writes a glyph vertex to the sink. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java index 22da53544..2be896c8a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java @@ -1,13 +1,14 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer.GlyphVertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer.GlyphVertexBufferWriterUnsafe; 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.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexFormat; + public class GlyphVertexType implements VanillaVertexType, BlittableVertexType { @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java index 748fa87f9..6c39c4ff8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java @@ -4,7 +4,6 @@ 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 org.lwjgl.system.MemoryUtil; public class GlyphVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements GlyphVertexSink { public GlyphVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java index cd7313c9f..3eb3adbf2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java @@ -1,9 +1,10 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import net.minecraft.client.render.VertexConsumer; + public class GlyphVertexWriterFallback extends VertexWriterFallback implements GlyphVertexSink { public GlyphVertexWriterFallback(VertexConsumer consumer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java index 4ec8e06a0..ea8f06945 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.line; +import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; public interface LineVertexSink extends VertexSink { - VertexFormat VERTEX_FORMAT = VertexFormats.POSITION_COLOR; + VertexFormat VERTEX_FORMAT = DefaultVertexFormat.POSITION_COLOR; /** * Writes a line vertex to the sink. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java index 5b4be974f..5e2ca5f05 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java @@ -1,13 +1,14 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.line; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexFormat; + public class LineVertexType implements VanillaVertexType, BlittableVertexType { @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java index 952b27b99..9b6290623 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java @@ -4,7 +4,6 @@ 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.line.LineVertexSink; -import org.lwjgl.system.MemoryUtil; public class LineVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements LineVertexSink { public LineVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java index 8c99564ae..205d8fa15 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java @@ -1,9 +1,10 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.formats.line.LineVertexSink; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import net.minecraft.client.render.VertexConsumer; + public class LineVertexWriterFallback extends VertexWriterFallback implements LineVertexSink { public LineVertexWriterFallback(VertexConsumer consumer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java index 854114757..4d111e608 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java @@ -1,11 +1,12 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.particle; +import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; + public interface ParticleVertexSink extends VertexSink { - VertexFormat VERTEX_FORMAT = VertexFormats.POSITION_TEXTURE_COLOR_LIGHT; + VertexFormat VERTEX_FORMAT = DefaultVertexFormat.PARTICLE; /** * @param x The x-position of the vertex diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java index 41fbfcfd2..cdaff0e62 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java @@ -1,13 +1,13 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.particle; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexFormat; public class ParticleVertexType implements VanillaVertexType, BlittableVertexType { @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java index 7cb08d8c6..770c70655 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java @@ -4,7 +4,6 @@ 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.particle.ParticleVertexSink; -import org.lwjgl.system.MemoryUtil; public class ParticleVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ParticleVertexSink { public ParticleVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java index e9f683250..7d11cb0fd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java @@ -1,9 +1,10 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.ParticleVertexSink; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import net.minecraft.client.render.VertexConsumer; + public class ParticleVertexWriterFallback extends VertexWriterFallback implements ParticleVertexSink { public ParticleVertexWriterFallback(VertexConsumer consumer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java index 9b622b6b9..07006063e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java @@ -1,14 +1,15 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.quad; +import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.client.util.math.MatrixStack; + public interface QuadVertexSink extends VertexSink { - VertexFormat VERTEX_FORMAT = VertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL; + VertexFormat VERTEX_FORMAT = DefaultVertexFormat.BLOCK; // POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL /** * Writes a quad vertex to this sink. @@ -21,14 +22,14 @@ public interface QuadVertexSink extends VertexSink { * @param v The y-texture of the vertex * @param light The packed light-map coordinates of the vertex * @param overlay The packed overlay-map coordinates of the vertex - * @param normal The 3-byte packed normal vector of the vertex + * @param normal The 3-byte packed getNormal vector of the vertex */ void writeQuad(float x, float y, float z, int color, float u, float v, int light, int overlay, int normal); /** * Writes a quad vertex to the sink, transformed by the given matrices. * - * @param matrices The matrices to transform the vertex's position and normal vectors by + * @param matrices The matrices to transform the vertex's position and getNormal vectors by */ default void writeQuad(MatrixStack.Entry matrices, float x, float y, float z, int color, float u, float v, int light, int overlay, int normal) { Matrix4fExtended modelMatrix = MatrixUtil.getExtendedMatrix(matrices.getModel()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java index eefb6e907..094c9e9fe 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java @@ -1,13 +1,14 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.quad; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer.QuadVertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer.QuadVertexBufferWriterUnsafe; 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.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexFormat; + public class QuadVertexType implements VanillaVertexType, BlittableVertexType { @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java index 58c0a500e..104a6339e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java @@ -4,7 +4,6 @@ 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.quad.QuadVertexSink; -import org.lwjgl.system.MemoryUtil; public class QuadVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements QuadVertexSink { public QuadVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java index 994c7a4a8..4c85cf9a4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java @@ -1,10 +1,11 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; import me.jellysquid.mods.sodium.client.util.Norm3b; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import net.minecraft.client.render.VertexConsumer; + public class QuadVertexWriterFallback extends VertexWriterFallback implements QuadVertexSink { public QuadVertexWriterFallback(VertexConsumer consumer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java index c65081338..e0d7836d2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad; +import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.util.math.Matrix4f; +import org.joml.Matrix4f; public interface BasicScreenQuadVertexSink extends VertexSink { - VertexFormat VERTEX_FORMAT = VertexFormats.POSITION_COLOR; + VertexFormat VERTEX_FORMAT = DefaultVertexFormat.POSITION_COLOR; /** * Writes a quad vertex to this sink. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java index 1cd287fa8..796dd3e70 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java @@ -1,13 +1,14 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexFormat; + public class BasicScreenQuadVertexType implements VanillaVertexType, BlittableVertexType { @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java index 4606f8181..6f5b93ec1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java @@ -4,7 +4,6 @@ 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.screen_quad.BasicScreenQuadVertexSink; -import org.lwjgl.system.MemoryUtil; public class BasicScreenQuadVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements BasicScreenQuadVertexSink { public BasicScreenQuadVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java index 9b85637b6..6633bc48f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java @@ -1,9 +1,10 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.BasicScreenQuadVertexSink; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import net.minecraft.client.render.VertexConsumer; + public class BasicScreenQuadVertexWriterFallback extends VertexWriterFallback implements BasicScreenQuadVertexSink { public BasicScreenQuadVertexWriterFallback(VertexConsumer consumer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/SpriteTexturedVertexTransformer.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/SpriteTexturedVertexTransformer.java index ce9408617..2ed30abb8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/SpriteTexturedVertexTransformer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/transformers/SpriteTexturedVertexTransformer.java @@ -4,7 +4,7 @@ import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.ParticleVertexSink; import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; -import net.minecraft.client.texture.Sprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; /** * Base implementation for a {@link VertexSink} which transforms texture coordinates relative to a sprite's bounds. @@ -18,7 +18,7 @@ public abstract class SpriteTexturedVertexTransformer exte private final float uMaxMin; private final float vMaxMin; - public SpriteTexturedVertexTransformer(T delegate, Sprite sprite) { + public SpriteTexturedVertexTransformer(T delegate, TextureAtlasSprite sprite) { super(delegate); this.uMin = sprite.getMinU(); @@ -37,7 +37,7 @@ protected float transformTextureV(float v) { } public static class Quad extends SpriteTexturedVertexTransformer implements QuadVertexSink { - public Quad(QuadVertexSink delegate, Sprite sprite) { + public Quad(QuadVertexSink delegate, TextureAtlasSprite sprite) { super(delegate, sprite); } @@ -51,7 +51,7 @@ public void writeQuad(float x, float y, float z, int color, float u, float v, in } public static class Particle extends SpriteTexturedVertexTransformer implements ParticleVertexSink { - public Particle(ParticleVertexSink delegate, Sprite sprite) { + public Particle(ParticleVertexSink delegate, TextureAtlasSprite sprite) { super(delegate, sprite); } @@ -65,7 +65,7 @@ public void writeParticle(float x, float y, float z, float u, float v, int color } public static class Glyph extends SpriteTexturedVertexTransformer implements GlyphVertexSink { - public Glyph(GlyphVertexSink delegate, Sprite sprite) { + public Glyph(GlyphVertexSink delegate, TextureAtlasSprite sprite) { super(delegate, sprite); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java index b69fb2061..50aa85301 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.model.vertex.type; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; -import net.minecraft.client.render.VertexFormat; public interface VanillaVertexType extends BufferVertexType { default BufferVertexFormat getBufferVertexFormat() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java index c742a6c50..e12fccd6d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex.type; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; -import net.minecraft.client.render.VertexConsumer; /** * Provides factories which create a {@link VertexSink} for the given vertex format. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java index a3312807c..a407335ba 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java @@ -1,8 +1,7 @@ package me.jellysquid.mods.sodium.client.render; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Matrix4f; -import org.lwjgl.system.MemoryStack; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import org.joml.Matrix4f; import java.nio.FloatBuffer; @@ -10,7 +9,7 @@ public class GameRendererContext { private static Matrix4f PROJECTION_MATRIX; public static void captureProjectionMatrix(Matrix4f matrix) { - PROJECTION_MATRIX = matrix.copy(); + PROJECTION_MATRIX.set(matrix); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index e8491cd31..dc77fdc16 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -1,13 +1,18 @@ package me.jellysquid.mods.sodium.client.render; -import com.mojang.blaze3d.systems.RenderSystem; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import cofh.lib.util.helpers.MathHelper; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.rwtema.extrautils.block.Box; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderBackend; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderManager; @@ -22,17 +27,15 @@ import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; import me.jellysquid.mods.sodium.client.world.ChunkStatusListenerManager; import me.jellysquid.mods.sodium.common.util.ListUtil; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.render.*; -import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; -import net.minecraft.client.render.model.ModelLoader; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.world.ClientWorld; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.entity.Entity; -import net.minecraft.util.math.*; -import net.minecraft.util.profiler.Profiler; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.profiler.Profiler; +import net.minecraft.tileentity.TileEntity; +import org.joml.Vector3d; +import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap; import java.util.Set; import java.util.SortedSet; @@ -43,9 +46,9 @@ public class SodiumWorldRenderer implements ChunkStatusListener { private static SodiumWorldRenderer instance; - private final MinecraftClient client; + private final Minecraft client; - private ClientWorld world; + private WorldClient world; private int renderDistance; private double lastCameraX, lastCameraY, lastCameraZ; @@ -54,9 +57,9 @@ public class SodiumWorldRenderer implements ChunkStatusListener { private boolean useEntityCulling; private final LongSet loadedChunkPositions = new LongOpenHashSet(); - private final Set globalBlockEntities = new ObjectOpenHashSet<>(); + private final Set globalBlockEntities = new ObjectOpenHashSet<>(); - private Frustum frustum; + private Frustrum frustum; private ChunkRenderManager chunkRenderManager; private BlockRenderPassManager renderPassManager; private ChunkRenderBackend chunkRenderBackend; @@ -66,7 +69,7 @@ public class SodiumWorldRenderer implements ChunkStatusListener { */ public static SodiumWorldRenderer create() { if (instance == null) { - instance = new SodiumWorldRenderer(MinecraftClient.getInstance()); + instance = new SodiumWorldRenderer(Minecraft.getMinecraft()); } return instance; @@ -84,11 +87,11 @@ public static SodiumWorldRenderer getInstance() { return instance; } - private SodiumWorldRenderer(MinecraftClient client) { + private SodiumWorldRenderer(Minecraft client) { this.client = client; } - public void setWorld(ClientWorld world) { + public void setWorld(WorldClient world) { // Check that the world is actually changing if (this.world == world) { return; @@ -105,7 +108,7 @@ public void setWorld(ClientWorld world) { } } - private void loadWorld(ClientWorld world) { + private void loadWorld(WorldClient world) { this.world = world; ChunkRenderCacheShared.createRenderContext(this.world); @@ -164,21 +167,21 @@ public boolean isTerrainRenderComplete() { /** * Called prior to any chunk rendering in order to update necessary state. */ - public void updateChunks(Camera camera, Frustum frustum, boolean hasForcedFrustum, int frame, boolean spectator) { + public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrustum, int frame, boolean spectator) { this.frustum = frustum; this.useEntityCulling = SodiumClientMod.options().advanced.useEntityCulling; Profiler profiler = this.client.getProfiler(); - profiler.push("camera_setup"); + profiler.startSection("camera_setup"); - ClientPlayerEntity player = this.client.player; + EntityPlayer player = this.client.thePlayer; if (player == null) { throw new IllegalStateException("Client instance has no active player entity"); } - Vec3d pos = camera.getPos(); + Vector3d pos = camera.getPos(); this.chunkRenderManager.setCameraPosition(pos.x, pos.y, pos.z); @@ -198,21 +201,21 @@ public void updateChunks(Camera camera, Frustum frustum, boolean hasForcedFrustu this.lastCameraPitch = pitch; this.lastCameraYaw = yaw; - profiler.swap("chunk_update"); + profiler.endStartSection("chunk_update"); this.chunkRenderManager.updateChunks(); if (!hasForcedFrustum && this.chunkRenderManager.isDirty()) { - profiler.swap("chunk_graph_rebuild"); + profiler.endStartSection("chunk_graph_rebuild"); this.chunkRenderManager.update(camera, (FrustumExtended) frustum, frame, spectator); } - profiler.swap("visible_chunk_tick"); + profiler.endStartSection("visible_chunk_tick"); this.chunkRenderManager.tickVisibleRenders(); - profiler.pop(); + profiler.endSection(); Entity.setRenderDistanceMultiplier(MathHelper.clamp((double) this.client.options.viewDistance / 8.0D, 1.0D, 2.5D) * (double) this.client.options.entityDistanceScaling); } @@ -228,7 +231,7 @@ public void drawChunkLayer(RenderLayer renderLayer, MatrixStack matrixStack, dou pass.endDrawing(); - RenderSystem.clearCurrentColor(); + GLStateManager.clearCurrentColor(); } public void reload() { @@ -283,7 +286,7 @@ private static ChunkRenderBackend createChunkRenderBackend(RenderDevice devic } } - private boolean checkBEVisibility(BlockEntity entity) { + private boolean checkBEVisibility(TileEntity entity) { return frustum.isVisible(entity.getRenderBoundingBox()); } @@ -291,18 +294,18 @@ public void renderTileEntities(MatrixStack matrices, BufferBuilderStorage buffer Camera camera, float tickDelta) { VertexConsumerProvider.Immediate immediate = bufferBuilders.getEntityVertexConsumers(); - Vec3d cameraPos = camera.getPos(); - double x = cameraPos.getX(); - double y = cameraPos.getY(); - double z = cameraPos.getZ(); + Vector3d cameraPos = camera.getPos(); + double x = cameraPos.x; + double y = cameraPos.y; + double z = cameraPos.z; - for (BlockEntity blockEntity : this.chunkRenderManager.getVisibleBlockEntities()) { + for (TileEntity blockEntity : this.chunkRenderManager.getVisibleBlockEntities()) { if(blockEntity.isRemoved() || !checkBEVisibility(blockEntity)) continue; BlockPos pos = blockEntity.getPos(); matrices.push(); - matrices.translate((double) pos.getX() - x, (double) pos.getY() - y, (double) pos.getZ() - z); + matrices.translate((double) pos.x - x, (double) pos.y - y, (double) pos.z - z); VertexConsumerProvider consumer = immediate; SortedSet breakingInfos = blockBreakingProgressions.get(pos.asLong()); @@ -322,13 +325,13 @@ public void renderTileEntities(MatrixStack matrices, BufferBuilderStorage buffer matrices.pop(); } - for (BlockEntity blockEntity : this.globalBlockEntities) { + for (TileEntity blockEntity : this.globalBlockEntities) { if(!checkBEVisibility(blockEntity)) continue; BlockPos pos = blockEntity.getPos(); matrices.push(); - matrices.translate((double) pos.getX() - x, (double) pos.getY() - y, (double) pos.getZ() - z); + matrices.translate((double) pos.x - x, (double) pos.y - y, (double) pos.z - z); BlockEntityRenderDispatcher.INSTANCE.render(blockEntity, tickDelta, matrices, immediate); @@ -409,7 +412,7 @@ public boolean isEntityVisible(Entity entity) { /** * @return The frustum of the current player's camera used to cull chunks */ - public Frustum getFrustum() { + public Frustrum getFrustum() { return this.frustum; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java index a845d6856..1880b76d5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.render.chunk; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterator; -import net.minecraft.client.util.math.MatrixStack; import java.util.Collections; import java.util.Iterator; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderColumn.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderColumn.java index 1995bb692..57f989ecb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderColumn.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderColumn.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk; import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.util.math.Direction; +import net.minecraftforge.common.util.ForgeDirection; public class ChunkRenderColumn { @SuppressWarnings("unchecked") @@ -16,15 +16,15 @@ public ChunkRenderColumn(int x, int z) { this.x = x; this.z = z; - this.setAdjacentColumn(Direction.UP, this); - this.setAdjacentColumn(Direction.DOWN, this); + this.setAdjacentColumn(ForgeDirection.UP, this); + this.setAdjacentColumn(ForgeDirection.DOWN, this); } - public void setAdjacentColumn(Direction dir, ChunkRenderColumn column) { + public void setAdjacentColumn(ForgeDirection dir, ChunkRenderColumn column) { this.adjacent[dir.ordinal()] = column; } - public ChunkRenderColumn getAdjacentColumn(Direction dir) { + public ChunkRenderColumn getAdjacentColumn(ForgeDirection dir) { return this.adjacent[dir.ordinal()]; } @@ -48,24 +48,24 @@ public int getZ() { } public boolean areNeighborsPresent() { - for (Direction dir : DirectionUtil.HORIZONTAL_DIRECTIONS) { + for (ForgeDirection dir : DirectionUtil.HORIZONTAL_DIRECTIONS) { ChunkRenderColumn adj = this.adjacent[dir.ordinal()]; if (adj == null) { return false; } - Direction corner; + ForgeDirection corner; // Access the adjacent corner chunk from the neighbor in this direction - if (dir == Direction.NORTH) { - corner = Direction.EAST; - } else if (dir == Direction.SOUTH) { - corner = Direction.WEST; - } else if (dir == Direction.WEST) { - corner = Direction.NORTH; - } else if (dir == Direction.EAST) { - corner = Direction.SOUTH; + if (dir == ForgeDirection.NORTH) { + corner = ForgeDirection.EAST; + } else if (dir == ForgeDirection.SOUTH) { + corner = ForgeDirection.WEST; + } else if (dir == ForgeDirection.WEST) { + corner = ForgeDirection.NORTH; + } else if (dir == ForgeDirection.EAST) { + corner = ForgeDirection.SOUTH; } else { continue; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java index 8f2a564a8..cf688faf8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java @@ -1,5 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderBounds; @@ -7,9 +9,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkSectionPos; + import java.lang.reflect.Array; import java.util.concurrent.CompletableFuture; @@ -189,7 +189,7 @@ public boolean isOutsideFrustum(FrustumExtended frustum) { * time before this render is drawn if {@link ChunkRenderContainer#isTickable()} is true. */ public void tick() { - for (Sprite sprite : this.data.getAnimatedSprites()) { + for (TextureAtlasSprite sprite : this.data.getAnimatedSprites()) { SpriteUtil.markSpriteActive(sprite); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 79dcd8e7d..9f1ecafbc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -1,5 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -30,15 +32,11 @@ import me.jellysquid.mods.sodium.common.util.DirectionUtil; import me.jellysquid.mods.sodium.common.util.IdTable; import me.jellysquid.mods.sodium.common.util.collections.FutureDequeDrain; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.Camera; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.chunk.ChunkSection; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import org.joml.Vector3d; import java.util.ArrayDeque; import java.util.Collection; @@ -82,10 +80,10 @@ public class ChunkRenderManager implements ChunkSt private final ChunkRenderList[] chunkRenderLists = new ChunkRenderList[BlockRenderPass.COUNT]; private final ObjectList> tickableChunks = new ObjectArrayList<>(); - private final ObjectList visibleBlockEntities = new ObjectArrayList<>(); + private final ObjectList visibleBlockEntities = new ObjectArrayList<>(); private final SodiumWorldRenderer renderer; - private final ClientWorld world; + private final WorldClient world; private final ChunkCuller culler; private final boolean useBlockFaceCulling; @@ -104,7 +102,7 @@ public class ChunkRenderManager implements ChunkSt private boolean alwaysDeferChunkUpdates; - public ChunkRenderManager(SodiumWorldRenderer renderer, ChunkRenderBackend backend, BlockRenderPassManager renderPassManager, ClientWorld world, int renderDistance) { + public ChunkRenderManager(SodiumWorldRenderer renderer, ChunkRenderBackend backend, BlockRenderPassManager renderPassManager, WorldClient world, int renderDistance) { this.backend = backend; this.renderer = renderer; this.world = world; @@ -136,7 +134,7 @@ public void update(Camera camera, FrustumExtended frustum, int frame, boolean sp } private void setup(Camera camera) { - Vec3d cameraPos = camera.getPos(); + Vector3d cameraPos = camera.getPos(); this.cameraX = (float) cameraPos.x; this.cameraY = (float) cameraPos.y; @@ -290,7 +288,7 @@ private int computeVisibleFaces(ChunkRenderContainer render) { } private void addEntitiesToRenderLists(ChunkRenderContainer render) { - Collection blockEntities = render.getData().getBlockEntities(); + Collection blockEntities = render.getData().getBlockEntities(); if (!blockEntities.isEmpty()) { this.visibleBlockEntities.addAll(blockEntities); @@ -330,7 +328,7 @@ private void unloadPending() { } } - public Collection getVisibleBlockEntities() { + public Collection getVisibleBlockEntities() { return this.visibleBlockEntities; } @@ -400,7 +398,7 @@ private void unloadSections(ChunkRenderColumn column) { } private void connectNeighborColumns(ChunkRenderColumn column) { - for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + for (ForgeDirection dir : DirectionUtil.ALL_DIRECTIONS) { ChunkRenderColumn adj = this.getAdjacentColumn(column, dir); if (adj != null) { @@ -412,7 +410,7 @@ private void connectNeighborColumns(ChunkRenderColumn column) { } private void disconnectNeighborColumns(ChunkRenderColumn column) { - for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + for (ForgeDirection dir : DirectionUtil.ALL_DIRECTIONS) { ChunkRenderColumn adj = column.getAdjacentColumn(dir); if (adj != null) { @@ -423,8 +421,8 @@ private void disconnectNeighborColumns(ChunkRenderColumn column) { } } - private ChunkRenderColumn getAdjacentColumn(ChunkRenderColumn column, Direction dir) { - return this.getColumn(column.getX() + dir.getOffsetX(), column.getZ() + dir.getOffsetZ()); + private ChunkRenderColumn getAdjacentColumn(ChunkRenderColumn column, ForgeDirection dir) { + return this.getColumn(column.getX() + dir.offsetX, column.getZ() + dir.offsetZ); } private ChunkRenderColumn getColumn(int x, int z) { @@ -572,7 +570,7 @@ public int getTotalSections() { } private void scheduleRebuildOffThread(int x, int y, int z, boolean important) { - MinecraftClient.getInstance().submit(() -> this.scheduleRebuild(x, y, z, important)); + Minecraft.getMinecraft().submit(() -> this.scheduleRebuild(x, y, z, important)); } public void scheduleRebuild(int x, int y, int z, boolean important) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java index fc2ad3aca..33ba73a82 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java @@ -1,10 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.util.math.MathHelper; -import org.lwjgl.system.MemoryUtil; -import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; /** @@ -25,7 +21,7 @@ protected ChunkDrawCallBatcher(int capacity) { } public static ChunkDrawCallBatcher create(int capacity) { - return SodiumClientMod.isDirectMemoryAccessEnabled() ? new UnsafeChunkDrawCallBatcher(capacity) : new NioChunkDrawCallBatcher(capacity); + return new NioChunkDrawCallBatcher(capacity); } public void begin() { @@ -53,44 +49,11 @@ public boolean isBuilding() { public int getCount() { return this.count; } - + public boolean isEmpty() { return this.count <= 0; } - public static class UnsafeChunkDrawCallBatcher extends ChunkDrawCallBatcher { - - private final long basePointer; - private long writePointer; - - public UnsafeChunkDrawCallBatcher(int capacity) { - super(capacity); - - this.basePointer = MemoryUtil.memAddress(this.buffer); - } - - @Override - public void begin() { - super.begin(); - - this.writePointer = this.basePointer; - } - - @Override - public void addIndirectDrawCall(int first, int count, int baseInstance, int instanceCount) { - if (this.count++ >= this.capacity) { - throw new BufferUnderflowException(); - } - - MemoryUtil.memPutInt(this.writePointer , count); // Vertex Count - MemoryUtil.memPutInt(this.writePointer + 4, instanceCount); // Instance Count - MemoryUtil.memPutInt(this.writePointer + 8, first); // Vertex Start - MemoryUtil.memPutInt(this.writePointer + 12, baseInstance); // Base Instance - - this.writePointer += this.stride; - } - } - public static class NioChunkDrawCallBatcher extends ChunkDrawCallBatcher { private int writeOffset; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java index 03e17f304..2c993110f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java @@ -1,7 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import org.lwjgl.system.MemoryUtil; +import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; @@ -20,7 +19,7 @@ protected ChunkDrawParamsVector(int capacity) { } public static ChunkDrawParamsVector create(int capacity) { - return SodiumClientMod.isDirectMemoryAccessEnabled() ? new UnsafeChunkDrawCallVector(capacity) : new NioChunkDrawCallVector(capacity); + return new NioChunkDrawCallVector(capacity); } public abstract void pushChunkDrawParams(float x, float y, float z); @@ -30,49 +29,10 @@ public void reset() { } protected void growBuffer() { + ByteBuffer oldBuffer = this.buffer; this.capacity = this.capacity * 2; - this.buffer = MemoryUtil.memRealloc(this.buffer, this.capacity * this.stride); - } - - public static class UnsafeChunkDrawCallVector extends ChunkDrawParamsVector { - private long basePointer; - private long writePointer; - - public UnsafeChunkDrawCallVector(int capacity) { - super(capacity); - - this.basePointer = MemoryUtil.memAddress(this.buffer); - } - - @Override - public void pushChunkDrawParams(float x, float y, float z) { - if (this.count++ >= this.capacity) { - this.growBuffer(); - } - - MemoryUtil.memPutFloat(this.writePointer , x); - MemoryUtil.memPutFloat(this.writePointer + 4, y); - MemoryUtil.memPutFloat(this.writePointer + 8, z); - - this.writePointer += this.stride; - } - - @Override - protected void growBuffer() { - super.growBuffer(); - - long offset = this.writePointer - this.basePointer; - - this.basePointer = MemoryUtil.memAddress(this.buffer); - this.writePointer = this.basePointer + offset; - } - - @Override - public void reset() { - super.reset(); - - this.writePointer = this.basePointer; - } + this.buffer = BufferUtils.createByteBuffer(this.capacity * this.stride); + buffer.put(oldBuffer.rewind()); } public static class NioChunkDrawCallVector extends ChunkDrawParamsVector { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java index e1b4a4fa5..8e798b424 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java @@ -1,6 +1,8 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; -import org.lwjgl.system.MemoryUtil; +import org.lwjgl.BufferUtils; + +import java.nio.ByteBuffer; public class IndirectCommandBufferVector extends StructBuffer { protected IndirectCommandBufferVector(int capacity) { @@ -30,6 +32,8 @@ public void pushCommandBuffer(ChunkDrawCallBatcher batcher) { } protected void growBuffer(int n) { - this.buffer = MemoryUtil.memRealloc(this.buffer, Math.max(this.buffer.capacity() * 2, this.buffer.capacity() + n)); + ByteBuffer oldBuffer = this.buffer; + this.buffer = BufferUtils.createByteBuffer(Math.max(oldBuffer.capacity() * 2, oldBuffer.capacity() + n)); + buffer.put(oldBuffer.rewind()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java index 1b78d8913..5cfdf2c35 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; -import com.mojang.blaze3d.platform.GlStateManager; import it.unimi.dsi.fastutil.objects.ObjectArrayFIFOQueue; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import me.jellysquid.mods.sodium.client.gl.arena.GlBufferArena; @@ -35,10 +34,11 @@ import me.jellysquid.mods.sodium.client.render.chunk.region.ChunkRegionManager; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkRenderShaderBackend; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; -import net.minecraft.util.Formatting; +import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.Util; -import org.lwjgl.opengl.GL20C; +import org.lwjgl.opengl.GL11; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; @@ -186,14 +186,10 @@ public void upload(CommandList commandList, Iterator region : this.pendingBatches) { ChunkDrawCallBatcher batch = region.getDrawBatcher(); if (!batch.isEmpty()) { try (DrawCommandList drawCommandList = commandList.beginTessellating(region.getTessellation())) { - drawCommandList.multiDrawArraysIndirect(pointer, batch.getCount(), 0 /* tightly packed */); + drawCommandList.multiDrawArraysIndirect(buffer, batch.getCount(), 0 /* tightly packed */); } } - pointer += batch.getArrayLength(); } this.pendingBatches.clear(); @@ -329,7 +324,7 @@ private void setupDrawBatches(CommandList commandList, ChunkRenderListIterator getDebugStrings() { List list = new ArrayList<>(); list.add(String.format("Active Buffers: %s", this.bufferManager.getAllocatedRegionCount())); - list.add(String.format("Submission Mode: %s", this.commandBuffer != null ? - Formatting.AQUA + "Buffer" : Formatting.LIGHT_PURPLE + "Client Memory")); + list.add(String.format("Submission Mode: %s", this.commandBuffer != null ? EnumChatFormatting.AQUA + "Buffer" : EnumChatFormatting.LIGHT_PURPLE + "Client Memory")); return list; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java index a0c84f711..69f75a732 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; -import me.jellysquid.mods.sodium.client.gl.util.MemoryUtilHelper; -import org.lwjgl.system.MemoryUtil; +import org.lwjgl.BufferUtils; + import java.nio.ByteBuffer; @@ -11,7 +11,7 @@ public abstract class StructBuffer { protected final int stride; protected StructBuffer(int bytes, int stride) { - this.buffer = MemoryUtil.memAlloc(bytes * stride); + this.buffer = BufferUtils.createByteBuffer(bytes * stride); this.stride = stride; } @@ -20,10 +20,7 @@ public ByteBuffer getBuffer() { } public void delete() { - MemoryUtilHelper.memFree(this.buffer); - } - - public long getBufferAddress() { - return MemoryUtil.memAddress(this.buffer); + this.buffer.clear(); + this.buffer = null; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkRenderBackendOneshot.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkRenderBackendOneshot.java index 1d94bee1a..63d2c09cc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkRenderBackendOneshot.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/oneshot/ChunkRenderBackendOneshot.java @@ -16,10 +16,8 @@ import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkRenderShaderBackend; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; -import org.lwjgl.opengl.GL20C; -import org.lwjgl.system.MemoryStack; +import org.lwjgl.opengl.GL20; -import java.nio.FloatBuffer; import java.util.Iterator; public class ChunkRenderBackendOneshot extends ChunkRenderShaderBackend { @@ -85,18 +83,11 @@ public void render(CommandList commandList, ChunkRenderListIterator { private ClonedChunkSectionCache sectionCache; private World world; - private Vec3d cameraPosition = Vec3d.ZERO; + private Vector3d cameraPosition = new Vector3d(); private BlockRenderPassManager renderPassManager; private final int limitThreads; @@ -86,7 +86,7 @@ public void startWorkers() { throw new IllegalStateException("Threads are still alive while in the STOPPED state"); } - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getMinecraft(); for (int i = 0; i < this.limitThreads; i++) { ChunkBuildBuffers buffers = new ChunkBuildBuffers(this.vertexType, this.renderPassManager); @@ -186,13 +186,13 @@ public CompletableFuture> schedule(ChunkRenderBuildTask t * Sets the current camera position of the player used for task prioritization. */ public void setCameraPosition(double x, double y, double z) { - this.cameraPosition = new Vec3d(x, y, z); + this.cameraPosition = new Vector3d(x, y, z); } /** * Returns the current camera position of the player used for task prioritization. */ - public Vec3d getCameraPosition() { + public Vector3d getCameraPosition() { return this.cameraPosition; } @@ -210,7 +210,7 @@ public boolean isBuildQueueEmpty() { * @param world The world instance * @param renderPassManager The render pass manager used for the world */ - public void init(ClientWorld world, BlockRenderPassManager renderPassManager) { + public void init(WorldClient world, BlockRenderPassManager renderPassManager) { if (world == null) { throw new NullPointerException("World is null"); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java index da48d7e64..c718516f4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java @@ -1,9 +1,10 @@ package me.jellysquid.mods.sodium.client.render.chunk.cull; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionData; import it.unimi.dsi.fastutil.ints.IntArrayList; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.chunk.ChunkOcclusionData; + public interface ChunkCuller { IntArrayList computeVisible(Camera camera, FrustumExtended frustum, int frame, boolean spectator); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java index cc05f88cb..e2e44599b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java @@ -1,19 +1,19 @@ package me.jellysquid.mods.sodium.client.render.chunk.cull.graph; +import cofh.lib.util.helpers.MathHelper; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionData; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import me.jellysquid.mods.sodium.client.render.chunk.cull.ChunkCuller; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.chunk.ChunkOcclusionData; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; +import net.minecraft.client.Minecraft; import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; import java.util.ArrayList; import java.util.Comparator; @@ -47,7 +47,7 @@ public IntArrayList computeVisible(Camera camera, FrustumExtended frustum, int f ChunkGraphNode node = queue.getNode(i); short cullData = node.computeQueuePop(); - for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + for (ForgeDirection dir : DirectionUtil.ALL_DIRECTIONS) { if (useOcclusionCulling && (cullData & (1 << dir.ordinal())) == 0) { continue; } @@ -73,7 +73,7 @@ private boolean isWithinRenderDistance(ChunkGraphNode adj) { private void initSearch(Camera camera, FrustumExtended frustum, int frame, boolean spectator) { this.activeFrame = frame; this.frustum = frustum; - this.useOcclusionCulling = MinecraftClient.getInstance().chunkCullingEnabled; + this.useOcclusionCulling = Minecraft.getMinecraft().chunkCullingEnabled; this.visible.clear(); @@ -127,7 +127,7 @@ private void initSearch(Camera camera, FrustumExtended frustum, int frame, boole } - private void bfsEnqueue(ChunkGraphNode parent, ChunkGraphNode node, Direction flow, short parentalData) { + private void bfsEnqueue(ChunkGraphNode parent, ChunkGraphNode node, ForgeDirection flow, short parentalData) { if (node.getLastVisibleFrame() == this.activeFrame) { node.updateCullingState(flow, parentalData); return; @@ -145,7 +145,7 @@ private void bfsEnqueue(ChunkGraphNode parent, ChunkGraphNode node, Direction fl } private void connectNeighborNodes(ChunkGraphNode node) { - for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + for (ForgeDirection dir : DirectionUtil.ALL_DIRECTIONS) { ChunkGraphNode adj = this.findAdjacentNode(node, dir); if (adj != null) { @@ -157,7 +157,7 @@ private void connectNeighborNodes(ChunkGraphNode node) { } private void disconnectNeighborNodes(ChunkGraphNode node) { - for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + for (ForgeDirection dir : DirectionUtil.ALL_DIRECTIONS) { ChunkGraphNode adj = node.getConnectedNode(dir); if (adj != null) { @@ -168,8 +168,8 @@ private void disconnectNeighborNodes(ChunkGraphNode node) { } } - private ChunkGraphNode findAdjacentNode(ChunkGraphNode node, Direction dir) { - return this.getNode(node.getChunkX() + dir.getOffsetX(), node.getChunkY() + dir.getOffsetY(), node.getChunkZ() + dir.getOffsetZ()); + private ChunkGraphNode findAdjacentNode(ChunkGraphNode node, ForgeDirection dir) { + return this.getNode(node.getChunkX() + dir.offsetX, node.getChunkY() + dir.offsetY, node.getChunkZ() + dir.offsetZ); } private ChunkGraphNode getNode(int x, int y, int z) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphNode.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphNode.java index a8057f926..688898e9b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphNode.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphNode.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.render.chunk.cull.graph; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionData; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.client.render.chunk.ChunkOcclusionData; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; +import net.minecraftforge.common.util.ForgeDirection; public class ChunkGraphNode { private static final long DEFAULT_VISIBILITY_DATA = calculateVisibilityData(ChunkRenderData.EMPTY.getOcclusionData()); @@ -30,7 +30,7 @@ public ChunkGraphNode(int chunkX, int chunkY, int chunkZ, int id) { this.visibilityData = DEFAULT_VISIBILITY_DATA; } - public ChunkGraphNode getConnectedNode(Direction dir) { + public ChunkGraphNode getConnectedNode(ForgeDirection dir) { return this.nodes[dir.ordinal()]; } @@ -54,7 +54,7 @@ public int getChunkZ() { return this.chunkZ; } - public void setAdjacentNode(Direction dir, ChunkGraphNode node) { + public void setAdjacentNode(ForgeDirection dir, ChunkGraphNode node) { this.nodes[dir.ordinal()] = node; } @@ -65,8 +65,8 @@ public void setOcclusionData(ChunkOcclusionData occlusionData) { private static long calculateVisibilityData(ChunkOcclusionData occlusionData) { long visibilityData = 0; - for (Direction from : DirectionUtil.ALL_DIRECTIONS) { - for (Direction to : DirectionUtil.ALL_DIRECTIONS) { + for (ForgeDirection from : DirectionUtil.ALL_DIRECTIONS) { + for (ForgeDirection to : DirectionUtil.ALL_DIRECTIONS) { if (occlusionData == null || occlusionData.isVisibleThrough(from, to)) { visibilityData |= (1L << ((from.ordinal() << 3) + to.ordinal())); } @@ -91,7 +91,7 @@ public short computeQueuePop() { return retVal; } - public void updateCullingState(Direction flow, short parent) { + public void updateCullingState(ForgeDirection flow, short parent) { int inbound = flow.ordinal(); this.cullingState |= (visibilityData >> (inbound<<3)) & 0xFF; this.cullingState &= ~(1 << (inbound + 8)); @@ -147,7 +147,7 @@ public int getOriginZ() { * given by {@param pos} */ public double getSquaredDistance(BlockPos pos) { - return this.getSquaredDistance(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D); + return this.getSquaredDistance(pos.x + 0.5D, pos.y + 0.5D, pos.z + 0.5D); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java index 9e933dfa9..4a06495ab 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.data; -import net.minecraft.util.math.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; public class ChunkRenderBounds { public static final ChunkRenderBounds ALWAYS_FALSE = new ChunkRenderBounds(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java index 79208602d..9a95d571f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java @@ -1,14 +1,15 @@ package me.jellysquid.mods.sodium.client.render.chunk.data; +import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionData; +import com.gtnewhorizons.angelica.mixins.early.textures.ISpriteExt; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.render.chunk.ChunkOcclusionData; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.Direction; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; import java.util.ArrayList; import java.util.Collection; @@ -27,15 +28,15 @@ public class ChunkRenderData { .build(); public static final ChunkRenderData EMPTY = createEmptyData(); - private List globalBlockEntities; - private List blockEntities; + private List globalBlockEntities; + private List blockEntities; private EnumMap meshes; private ChunkOcclusionData occlusionData; private ChunkRenderBounds bounds; - private List animatedSprites; + private List animatedSprites; private boolean isEmpty; private int meshByteSize; @@ -56,14 +57,14 @@ public ChunkOcclusionData getOcclusionData() { return this.occlusionData; } - public List getAnimatedSprites() { + public List getAnimatedSprites() { return this.animatedSprites; } /** * The collection of block entities contained by this rendered chunk. */ - public Collection getBlockEntities() { + public Collection getBlockEntities() { return this.blockEntities; } @@ -71,7 +72,7 @@ public Collection getBlockEntities() { * The collection of block entities contained by this rendered chunk section which are not part of its culling * volume. These entities should always be rendered regardless of the render being visible in the frustum. */ - public Collection getGlobalBlockEntities() { + public Collection getGlobalBlockEntities() { return this.globalBlockEntities; } @@ -124,9 +125,9 @@ public ChunkRenderData copyAndReplaceMesh(Map re } public static class Builder { - private final List globalBlockEntities = new ArrayList<>(); - private final List blockEntities = new ArrayList<>(); - private final Set animatedSprites = new ObjectOpenHashSet<>(); + private final List globalBlockEntities = new ArrayList<>(); + private final List blockEntities = new ArrayList<>(); + private final Set animatedSprites = new ObjectOpenHashSet<>(); private final EnumMap meshes = new EnumMap<>(BlockRenderPass.class); @@ -152,8 +153,8 @@ public void setOcclusionData(ChunkOcclusionData data) { * before rendering as necessary. * @param sprite The sprite */ - public void addSprite(Sprite sprite) { - if (sprite.isAnimated()) { + public void addSprite(TextureAtlasSprite sprite) { + if (((ISpriteExt)sprite).isAnimation()) { this.animatedSprites.add(sprite); } } @@ -167,7 +168,7 @@ public void setMesh(BlockRenderPass pass, ChunkMeshData data) { * @param entity The block entity itself * @param cull True if the block entity can be culled to this chunk render's volume, otherwise false */ - public void addBlockEntity(BlockEntity entity, boolean cull) { + public void addBlockEntity(TileEntity entity, boolean cull) { (cull ? this.blockEntities : this.globalBlockEntities).add(entity); } @@ -201,7 +202,7 @@ public ChunkRenderData build() { private static ChunkRenderData createEmptyData() { ChunkOcclusionData occlusionData = new ChunkOcclusionData(); - occlusionData.addOpenEdgeFaces(EnumSet.allOf(Direction.class)); + occlusionData.addOpenEdgeFaces(EnumSet.allOf(ForgeDirection.class)); Builder meshInfo = new Builder(); meshInfo.setOcclusionData(occlusionData); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java index 1766b3d01..9dbc96bd1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java @@ -5,7 +5,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.format.DefaultModelVertexFormats; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexUtil; -import org.lwjgl.system.MemoryUtil; public class HFPModelVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ModelVertexSink { public HFPModelVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java index 884b0b370..22355e26f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.format.hfp; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; @@ -7,7 +8,7 @@ import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; -import net.minecraft.client.render.VertexConsumer; + /** * Uses half-precision floating point numbers to represent position coordinates and normalized unsigned shorts for @@ -22,7 +23,7 @@ public class HFPModelVertexType implements ChunkVertexType { .addElement(ChunkMeshAttribute.TEXTURE, 12, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, false) .addElement(ChunkMeshAttribute.LIGHT, 16, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, true) .build(); - + public static final float MODEL_SCALE = (32.0f / 65536.0f); public static final float TEXTURE_SCALE = (1.0f / 32768.0f); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java index 510b244f3..3e3944d21 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java @@ -4,7 +4,6 @@ import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.render.chunk.format.DefaultModelVertexFormats; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; -import org.lwjgl.system.MemoryUtil; public class SFPModelVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ModelVertexSink { public SFPModelVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java index ddcc12f04..984f1640d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.format.sfp; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; @@ -7,7 +8,7 @@ import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; -import net.minecraft.client.render.VertexConsumer; + /** * Simple vertex format which uses single-precision floating point numbers to represent position and texture diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java index 7531055a0..14bbeb93e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.client.render.chunk.passes; -import net.minecraft.client.render.RenderLayer; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; // TODO: Move away from using an enum, make this extensible public enum BlockRenderPass { - SOLID(RenderLayer.getSolid(), false), - CUTOUT(RenderLayer.getCutout(), false), - CUTOUT_MIPPED(RenderLayer.getCutoutMipped(), false), - TRANSLUCENT(RenderLayer.getTranslucent(), true), - TRIPWIRE(RenderLayer.getTripwire(), true); + SOLID(RenderLayer.solid(), false), + CUTOUT(RenderLayer.cutout(), false), + CUTOUT_MIPPED(RenderLayer.cutoutMipped(), false), + TRANSLUCENT(RenderLayer.translucent(), true), + TRIPWIRE(RenderLayer.tripwire(), true); public static final BlockRenderPass[] VALUES = BlockRenderPass.values(); public static final int COUNT = VALUES.length; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java index 6207e2cb1..8cbfc865c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java @@ -1,7 +1,8 @@ package me.jellysquid.mods.sodium.client.render.chunk.passes; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import it.unimi.dsi.fastutil.objects.Reference2IntArrayMap; -import net.minecraft.client.render.RenderLayer; + /** * Maps vanilla render layers to render passes used by Sodium. This provides compatibility with the render layers already @@ -36,11 +37,11 @@ private void addMapping(RenderLayer layer, BlockRenderPass type) { */ public static BlockRenderPassManager createDefaultMappings() { BlockRenderPassManager mapper = new BlockRenderPassManager(); - mapper.addMapping(RenderLayer.getSolid(), BlockRenderPass.SOLID); - mapper.addMapping(RenderLayer.getCutoutMipped(), BlockRenderPass.CUTOUT_MIPPED); - mapper.addMapping(RenderLayer.getCutout(), BlockRenderPass.CUTOUT); - mapper.addMapping(RenderLayer.getTranslucent(), BlockRenderPass.TRANSLUCENT); - mapper.addMapping(RenderLayer.getTripwire(), BlockRenderPass.TRIPWIRE); + mapper.addMapping(RenderLayer.solid(), BlockRenderPass.SOLID); + mapper.addMapping(RenderLayer.cutoutMipped(), BlockRenderPass.CUTOUT_MIPPED); + mapper.addMapping(RenderLayer.cutout(), BlockRenderPass.CUTOUT); + mapper.addMapping(RenderLayer.translucent(), BlockRenderPass.TRANSLUCENT); + mapper.addMapping(RenderLayer.tripwire(), BlockRenderPass.TRIPWIRE); return mapper; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java index 72ae14f5f..0b8845916 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.render.chunk.region; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectIterator; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; import me.jellysquid.mods.sodium.client.util.MathUtil; -import net.minecraft.util.math.ChunkSectionPos; import org.apache.commons.lang3.Validate; public class ChunkRegionManager { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java index 18c81eb39..bf2b42f45 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java @@ -1,13 +1,13 @@ package me.jellysquid.mods.sodium.client.render.chunk.shader; -import com.mojang.blaze3d.platform.GlStateManager; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import io.github.douira.glsl_transformer.ast.node.Identifier; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; import me.jellysquid.mods.sodium.client.render.GameRendererContext; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.Identifier; -import org.lwjgl.opengl.GL20C; -import org.lwjgl.system.MemoryStack; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; import java.util.function.Function; @@ -39,17 +39,16 @@ protected ChunkProgram(RenderDevice owner, Identifier name, int handle, Function } public void setup(MatrixStack matrixStack, float modelScale, float textureScale) { - GlStateManager.uniform1(this.uBlockTex, 0); - GlStateManager.uniform1(this.uLightTex, 2); + GL20.glUniform1i(this.uBlockTex, 0); + GL20.glUniform1i(this.uLightTex, 2); - GL20C.glUniform3f(this.uModelScale, modelScale, modelScale, modelScale); - GL20C.glUniform2f(this.uTextureScale, textureScale, textureScale); + GL20.glUniform3f(this.uModelScale, modelScale, modelScale, modelScale); + GL20.glUniform2f(this.uTextureScale, textureScale, textureScale); this.fogShader.setup(); try (MemoryStack memoryStack = MemoryStack.stackPush()) { - GlStateManager.uniformMatrix4(this.uModelViewProjectionMatrix, false, - GameRendererContext.getModelViewProjectionMatrix(matrixStack.peek(), memoryStack)); + GL20.glUniformMatrix4(this.uModelViewProjectionMatrix, false, GameRendererContext.getModelViewProjectionMatrix(matrixStack.peek(), memoryStack)); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java index 92762ae07..2b3b294f5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java @@ -1,5 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.shader; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import io.github.douira.glsl_transformer.ast.node.Identifier; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; import me.jellysquid.mods.sodium.client.gl.compat.FogHelper; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; @@ -11,13 +13,10 @@ 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.format.ChunkMeshAttribute; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.Identifier; import java.util.EnumMap; -public abstract class ChunkRenderShaderBackend - implements ChunkRenderBackend { +public abstract class ChunkRenderShaderBackend implements ChunkRenderBackend { private final EnumMap programs = new EnumMap<>(ChunkFogMode.class); protected final ChunkVertexType vertexType; @@ -31,14 +30,12 @@ public ChunkRenderShaderBackend(ChunkVertexType vertexType) { } private ChunkProgram createShader(RenderDevice device, ChunkFogMode fogMode, GlVertexFormat vertexFormat) { - GlShader vertShader = ShaderLoader.loadShader(device, ShaderType.VERTEX, - new Identifier("sodium", "chunk_gl20.v.glsl"), fogMode.getDefines()); + GlShader vertShader = ShaderLoader.loadShader(device, ShaderType.VERTEX, new Identifier("chunk_gl20"), fogMode.getDefines()); - GlShader fragShader = ShaderLoader.loadShader(device, ShaderType.FRAGMENT, - new Identifier("sodium", "chunk_gl20.f.glsl"), fogMode.getDefines()); + GlShader fragShader = ShaderLoader.loadShader(device, ShaderType.FRAGMENT, new Identifier("chunk_gl20"), fogMode.getDefines()); try { - return GlProgram.builder(new Identifier("sodium", "chunk_shader")) + return GlProgram.builder(new Identifier("chunk_shader")) .attachShader(vertShader) .attachShader(fragShader) .bindAttribute("a_Pos", ChunkShaderBindingPoints.POSITION) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java index bc9c1392d..42700d755 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java @@ -1,7 +1,8 @@ package me.jellysquid.mods.sodium.client.render.chunk.shader; import me.jellysquid.mods.sodium.client.gl.compat.FogHelper; -import org.lwjgl.opengl.GL20C; +import org.joml.Vector3f; +import org.lwjgl.opengl.GL20; /** * These shader implementations try to remain compatible with the deprecated fixed function pipeline by manually @@ -38,8 +39,9 @@ public Exp2(ChunkProgram program) { @Override public void setup() { - GL20C.glUniform4fv(this.uFogColor, FogHelper.getFogColor()); - GL20C.glUniform1f(this.uFogDensity, FogHelper.getFogDensity()); + final Vector3f fogColor = FogHelper.getFogColor(); + GL20.glUniform4f(this.uFogColor, FogHelper.getFogColor()); + GL20.glUniform1f(this.uFogDensity, FogHelper.getFogDensity()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 1ae270cbc..8bce66b6b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -1,7 +1,13 @@ package me.jellysquid.mods.sodium.client.render.chunk.tasks; +import com.gtnewhorizons.angelica.compat.forge.IModelData; +import com.gtnewhorizons.angelica.compat.mojang.BakedModel; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderType; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.rwtema.extrautils.ChunkPos; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.compat.FlywheelCompat; 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; @@ -14,25 +20,10 @@ import me.jellysquid.mods.sodium.client.util.task.CancellationSource; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; -import net.minecraft.block.BlockRenderType; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.RenderLayers; -import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; -import net.minecraft.client.render.block.entity.BlockEntityRenderer; -import net.minecraft.client.render.chunk.ChunkOcclusionDataBuilder; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.fluid.FluidState; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.client.Minecraft; +import net.minecraft.tileentity.TileEntity; import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.model.ModelDataManager; -import net.minecraftforge.client.model.data.EmptyModelData; -import net.minecraftforge.client.model.data.IModelData; +import org.joml.Vector3d; import java.util.Map; @@ -52,7 +43,7 @@ public class ChunkRenderRebuildTask extends ChunkR private final Map modelDataMap; - private Vec3d camera; + private Vector3d camera; private final boolean translucencySorting; @@ -60,13 +51,13 @@ public ChunkRenderRebuildTask(ChunkRenderContainer render, ChunkRenderContext this.render = render; this.offset = offset; this.context = context; - this.camera = Vec3d.ZERO; + this.camera = new Vector3d(); this.translucencySorting = SodiumClientMod.options().advanced.translucencySorting; - this.modelDataMap = ModelDataManager.getModelData(MinecraftClient.getInstance().world, new ChunkPos(ChunkSectionPos.getSectionCoord(this.render.getOriginX()), ChunkSectionPos.getSectionCoord(this.render.getOriginZ()))); + this.modelDataMap = ModelDataManager.getModelData(Minecraft.getMinecraft().world, new ChunkPos(ChunkSectionPos.getSectionCoord(this.render.getOriginX()), ChunkSectionPos.getSectionCoord(this.render.getOriginZ()))); } - public ChunkRenderRebuildTask withCameraPosition(Vec3d camera) { + public ChunkRenderRebuildTask withCameraPosition(Vector3d camera) { this.camera = camera; return this; } @@ -106,7 +97,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB // TODO: commit this separately pos.set(baseX + relX, baseY + relY, baseZ + relZ); - buffers.setRenderOffset(pos.getX() - renderOffset.getX(), pos.getY() - renderOffset.getY(), pos.getZ() - renderOffset.getZ()); + buffers.setRenderOffset(pos.x - renderOffset.getX(), pos.y - renderOffset.getY(), pos.z - renderOffset.getZ()); if (blockState.getRenderType() == BlockRenderType.MODEL) { for (RenderLayer layer : RenderLayer.getBlockLayers()) { @@ -117,8 +108,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB ForgeHooksClient.setRenderLayer(layer); IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); - BakedModel model = cache.getBlockModels() - .getModel(blockState); + BakedModel model = cache.getBlockModels().getModel(blockState); long seed = blockState.getRenderingSeed(pos); @@ -146,15 +136,12 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB } if (blockState.hasTileEntity()) { - BlockEntity entity = slice.getBlockEntity(pos); + TileEntity entity = slice.getBlockEntity(pos); if (entity != null) { - BlockEntityRenderer renderer = BlockEntityRenderDispatcher.INSTANCE.get(entity); + BlockEntityRenderer renderer = BlockEntityRenderDispatcher.INSTANCE.get(entity); if (renderer != null) { - if (!FlywheelCompat.isSkipped(entity)) - renderData.addBlockEntity(entity, !renderer.rendersOutsideBoundingBox(entity)); - bounds.addBlock(relX, relY, relZ); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java index 13f7fad63..686083e6a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.tasks; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import me.jellysquid.mods.sodium.client.gl.buffer.VertexData; import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; @@ -13,9 +14,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheLocal; import me.jellysquid.mods.sodium.client.util.task.CancellationSource; -import net.minecraft.client.util.GlAllocationUtils; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import org.joml.Vector3d; import java.nio.ByteBuffer; import java.util.Arrays; @@ -30,9 +29,9 @@ public class ChunkRenderTranslucencySortTask exten private final ChunkRenderContainer render; private final BlockPos offset; - private final Vec3d camera; + private final Vector3d camera; - public ChunkRenderTranslucencySortTask(ChunkRenderContainer render, BlockPos offset, Vec3d camera) { + public ChunkRenderTranslucencySortTask(ChunkRenderContainer render, BlockPos offset, Vector3d camera) { this.render = render; this.offset = offset; this.camera = camera; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/entity/EntityLightSampler.java b/src/main/java/me/jellysquid/mods/sodium/client/render/entity/EntityLightSampler.java index 34b6de495..afad9c830 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/entity/EntityLightSampler.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/entity/EntityLightSampler.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.entity; import net.minecraft.entity.Entity; -import net.minecraft.util.math.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; public interface EntityLightSampler { int bridge$getBlockLight(T entity, BlockPos pos); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java b/src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java index 31c53e720..663c227dc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java @@ -1,13 +1,12 @@ package me.jellysquid.mods.sodium.client.render.occlusion; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.BlockView; +import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; +import com.gtnewhorizons.angelica.compat.mojang.VoxelShapes; import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap; -import net.minecraft.block.BlockState; -import net.minecraft.util.function.BooleanBiFunction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.util.shape.VoxelShapes; -import net.minecraft.world.BlockView; +import net.minecraftforge.common.util.ForgeDirection; public class BlockOcclusionCache { private static final byte UNCACHED_VALUE = (byte) 127; @@ -28,9 +27,9 @@ public BlockOcclusionCache() { * @param facing The facing direction of the side to check * @return True if the block side facing {@param dir} is not occluded, otherwise false */ - public boolean shouldDrawSide(BlockState selfState, BlockView view, BlockPos pos, Direction facing) { + public boolean shouldDrawSide(BlockState selfState, BlockView view, BlockPos pos, ForgeDirection facing) { BlockPos.Mutable adjPos = this.cpos; - adjPos.set(pos.getX() + facing.getOffsetX(), pos.getY() + facing.getOffsetY(), pos.getZ() + facing.getOffsetZ()); + adjPos.set(pos.x + facing.offsetX, pos.y + facing.offsetY, pos.z + facing.offsetZ); BlockState adjState = view.getBlockState(adjPos); @@ -80,7 +79,8 @@ private boolean calculate(VoxelShape selfShape, VoxelShape adjShape) { return cached == 1; } - boolean ret = VoxelShapes.matchesAnywhere(selfShape, adjShape, BooleanBiFunction.ONLY_FIRST); + // TODO: Sodium + boolean ret = VoxelShapes.matchesAnywhere(selfShape, adjShape, null /*BooleanBiFunction.ONLY_FIRST*/); this.map.put(cache.copy(), (byte) (ret ? 1 : 0)); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index a63fb8227..ac2079f0d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -1,10 +1,15 @@ package me.jellysquid.mods.sodium.client.render.pipeline; -import codechicken.lib.render.block.ICCBlockRenderer; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.compat.ccl.CCLCompat; -import me.jellysquid.mods.sodium.client.compat.ccl.SinkingVertexBuilder; -import me.jellysquid.mods.sodium.client.compat.forge.ForgeBlockRenderer; +import com.gtnewhorizons.angelica.compat.forge.ForgeBlockRenderer; +import com.gtnewhorizons.angelica.compat.forge.IModelData; +import com.gtnewhorizons.angelica.compat.forge.SinkingVertexBuilder; +import com.gtnewhorizons.angelica.compat.mojang.BakedModel; +import com.gtnewhorizons.angelica.compat.mojang.BakedQuad; +import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import me.jellysquid.mods.sodium.client.model.light.LightMode; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; @@ -22,18 +27,9 @@ import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; import me.jellysquid.mods.sodium.client.world.biome.BlockColorsExtended; import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.block.BlockState; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.color.block.BlockColorProvider; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.BlockRenderView; -import net.minecraftforge.client.model.data.IModelData; +import net.minecraft.client.Minecraft; +import net.minecraftforge.common.util.ForgeDirection; +import org.joml.Vector3d; import java.util.List; import java.util.Random; @@ -55,7 +51,7 @@ public class BlockRenderer { private final boolean useAmbientOcclusion; - public BlockRenderer(MinecraftClient client, LightPipelineProvider lighters, BiomeColorBlender biomeColorBlender) { + public BlockRenderer(Minecraft client, LightPipelineProvider lighters, BiomeColorBlender biomeColorBlender) { this.blockColors = (BlockColorsExtended) client.getBlockColors(); this.biomeColorBlender = biomeColorBlender; @@ -68,31 +64,15 @@ public BlockRenderer(MinecraftClient client, LightPipelineProvider lighters, Bio public boolean renderModel(BlockRenderView world, BlockState state, BlockPos pos, BakedModel model, ChunkModelBuffers buffers, boolean cull, long seed, IModelData modelData) { LightMode mode = this.getLightingMode(state, model, world, pos); LightPipeline lighter = this.lighters.getLighter(mode); - Vec3d offset = state.getModelOffset(world, pos); + Vector3d offset = state.getModelOffset(world, pos); boolean rendered = false; modelData = model.getModelData(world, pos, state, modelData); - if(SodiumClientMod.cclLoaded) { - final MatrixStack mStack = new MatrixStack(); - final SinkingVertexBuilder builder = SinkingVertexBuilder.getInstance(); - for (final ICCBlockRenderer renderer : CCLCompat.getCustomRenderers(world, pos)) { - if (renderer.canHandleBlock(world, pos, state)) { - mStack.isEmpty(); - - builder.reset(); - rendered = renderer.renderBlock(state, pos, world, mStack, builder, random, modelData); - builder.flush(buffers); - - return rendered; - } - } - } - if(ForgeBlockRenderer.useForgeLightingPipeline()) { MatrixStack mStack; - if(offset != Vec3d.ZERO) { + if(offset != Vector3d.ZERO) { mStack = new MatrixStack(); mStack.translate(offset.x, offset.y, offset.z); } else @@ -104,7 +84,7 @@ public boolean renderModel(BlockRenderView world, BlockState state, BlockPos pos return rendered; } - for (Direction dir : DirectionUtil.ALL_DIRECTIONS) { + for (ForgeDirection dir : DirectionUtil.ALL_DIRECTIONS) { this.random.setSeed(seed); List sided = model.getQuads(state, dir, this.random, modelData); @@ -133,8 +113,8 @@ public boolean renderModel(BlockRenderView world, BlockState state, BlockPos pos return rendered; } - private void renderQuadList(BlockRenderView world, BlockState state, BlockPos pos, LightPipeline lighter, Vec3d offset, - ChunkModelBuffers buffers, List quads, Direction cullFace) { + private void renderQuadList(BlockRenderView world, BlockState state, BlockPos pos, LightPipeline lighter, Vector3d offset, + ChunkModelBuffers buffers, List quads, ForgeDirection cullFace) { ModelQuadFacing facing = cullFace == null ? ModelQuadFacing.UNASSIGNED : ModelQuadFacing.fromDirection(cullFace); BlockColorProvider colorizer = null; @@ -161,7 +141,7 @@ private void renderQuadList(BlockRenderView world, BlockState state, BlockPos po sink.flush(); } - private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, ModelVertexSink sink, Vec3d offset, + private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, ModelVertexSink sink, Vector3d offset, BlockColorProvider colorProvider, BakedQuad bakedQuad, QuadLightData light, ChunkRenderData.Builder renderData) { ModelQuadView src = (ModelQuadView) bakedQuad; @@ -190,7 +170,7 @@ private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, M sink.writeQuad(x, y, z, color, u, v, lm); } - Sprite sprite = src.rubidium$getSprite(); + TextureAtlasSprite sprite = src.rubidium$getSprite(); if (sprite != null) { renderData.addSprite(sprite); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java index 3d713c45a..2cf785800 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.client.render.pipeline; import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; public class ChunkRenderCache { protected BiomeColorBlender createBiomeColorBlender() { - return BiomeColorBlender.create(MinecraftClient.getInstance()); + return BiomeColorBlender.create(Minecraft.getMinecraft()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java index bdd4f78cd..8671c0b22 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java @@ -1,5 +1,11 @@ package me.jellysquid.mods.sodium.client.render.pipeline; +import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; +import com.gtnewhorizons.angelica.compat.mojang.VoxelShapes; import me.jellysquid.mods.sodium.client.model.light.LightMode; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; @@ -15,21 +21,15 @@ import me.jellysquid.mods.sodium.client.util.Norm3b; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.block.BlockState; -import net.minecraft.block.SideShapeType; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.color.block.BlockColorProvider; -import net.minecraft.client.texture.Sprite; -import net.minecraft.fluid.Fluid; -import net.minecraft.fluid.FluidState; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.util.shape.VoxelShapes; -import net.minecraft.world.BlockRenderView; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.MathHelper; import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import org.joml.Vector3d; + +import static org.joml.Math.lerp; public class FluidRenderer { @@ -50,7 +50,7 @@ public class FluidRenderer { private final QuadLightData quadLightData = new QuadLightData(); private final int[] quadColors = new int[4]; - public FluidRenderer(MinecraftClient client, LightPipelineProvider lighters, BiomeColorBlender biomeColorBlender) { + public FluidRenderer(Minecraft client, LightPipelineProvider lighters, BiomeColorBlender biomeColorBlender) { int normal = Norm3b.pack(0.0f, 1.0f, 0.0f); for (int i = 0; i < 4; i++) { @@ -61,10 +61,10 @@ public FluidRenderer(MinecraftClient client, LightPipelineProvider lighters, Bio this.biomeColorBlender = biomeColorBlender; } - private boolean isFluidOccluded(BlockRenderView world, int x, int y, int z, Direction dir, Fluid fluid) { + private boolean isFluidOccluded(BlockRenderView world, int x, int y, int z, ForgeDirection dir, Fluid fluid) { BlockPos pos = this.scratchPos.set(x, y, z); BlockState blockState = world.getBlockState(pos); - BlockPos adjPos = this.scratchPos.set(x + dir.getOffsetX(), y + dir.getOffsetY(), z + dir.getOffsetZ()); + BlockPos adjPos = this.scratchPos.set(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); if (blockState.isOpaque()) { return world.getFluidState(adjPos).getFluid().matchesType(fluid) || blockState.isSideSolid(world,pos,dir, SideShapeType.FULL); @@ -73,8 +73,8 @@ private boolean isFluidOccluded(BlockRenderView world, int x, int y, int z, Dire return world.getFluidState(adjPos).getFluid().matchesType(fluid); } - private boolean isSideExposed(BlockRenderView world, int x, int y, int z, Direction dir, float height) { - BlockPos pos = this.scratchPos.set(x + dir.getOffsetX(), y + dir.getOffsetY(), z + dir.getOffsetZ()); + private boolean isSideExposed(BlockRenderView world, int x, int y, int z, ForgeDirection dir, float height) { + BlockPos pos = this.scratchPos.set(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); BlockState blockState = world.getBlockState(pos); if (blockState.isOpaque()) { @@ -83,7 +83,7 @@ private boolean isSideExposed(BlockRenderView world, int x, int y, int z, Direct // Hoist these checks to avoid allocating the shape below if (shape == VoxelShapes.fullCube()) { // The top face always be inset, so if the shape above is a full cube it can't possibly occlude - return dir == Direction.UP; + return dir == ForgeDirection.UP; } else if (shape.isEmpty()) { return true; } @@ -97,25 +97,25 @@ private boolean isSideExposed(BlockRenderView world, int x, int y, int z, Direct } public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos, ChunkModelBuffers buffers) { - int posX = pos.getX(); - int posY = pos.getY(); - int posZ = pos.getZ(); + int posX = pos.x; + int posY = pos.y; + int posZ = pos.z; Fluid fluid = fluidState.getFluid(); - boolean sfUp = this.isFluidOccluded(world, posX, posY, posZ, Direction.UP, fluid); - boolean sfDown = this.isFluidOccluded(world, posX, posY, posZ, Direction.DOWN, fluid) || - !this.isSideExposed(world, posX, posY, posZ, Direction.DOWN, 0.8888889F); - boolean sfNorth = this.isFluidOccluded(world, posX, posY, posZ, Direction.NORTH, fluid); - boolean sfSouth = this.isFluidOccluded(world, posX, posY, posZ, Direction.SOUTH, fluid); - boolean sfWest = this.isFluidOccluded(world, posX, posY, posZ, Direction.WEST, fluid); - boolean sfEast = this.isFluidOccluded(world, posX, posY, posZ, Direction.EAST, fluid); + boolean sfUp = this.isFluidOccluded(world, posX, posY, posZ, ForgeDirection.UP, fluid); + boolean sfDown = this.isFluidOccluded(world, posX, posY, posZ, ForgeDirection.DOWN, fluid) || + !this.isSideExposed(world, posX, posY, posZ, ForgeDirection.DOWN, 0.8888889F); + boolean sfNorth = this.isFluidOccluded(world, posX, posY, posZ, ForgeDirection.NORTH, fluid); + boolean sfSouth = this.isFluidOccluded(world, posX, posY, posZ, ForgeDirection.SOUTH, fluid); + boolean sfWest = this.isFluidOccluded(world, posX, posY, posZ, ForgeDirection.WEST, fluid); + boolean sfEast = this.isFluidOccluded(world, posX, posY, posZ, ForgeDirection.EAST, fluid); if (sfUp && sfDown && sfEast && sfWest && sfNorth && sfSouth) { return false; } - Sprite[] sprites = ForgeHooksClient.getFluidSprites(world, pos, fluidState); + TextureAtlasSprite[] sprites = ForgeHooksClient.getFluidSprites(world, pos, fluidState); boolean hc = fluidState.getFluid().getAttributes().getColor() != 0xffffffff; boolean rendered = false; @@ -129,20 +129,20 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos final ModelQuadViewMutable quad = this.quad; - LightMode lightMode = hc && MinecraftClient.isAmbientOcclusionEnabled() ? LightMode.SMOOTH : LightMode.FLAT; + LightMode lightMode = hc && Minecraft.isAmbientOcclusionEnabled() ? LightMode.SMOOTH : LightMode.FLAT; LightPipeline lighter = this.lighters.getLighter(lightMode); quad.setFlags(0); - if (!sfUp && this.isSideExposed(world, posX, posY, posZ, Direction.UP, Math.min(Math.min(h1, h2), Math.min(h3, h4)))) { + if (!sfUp && this.isSideExposed(world, posX, posY, posZ, ForgeDirection.UP, Math.min(Math.min(h1, h2), Math.min(h3, h4)))) { h1 -= 0.001F; h2 -= 0.001F; h3 -= 0.001F; h4 -= 0.001F; - Vec3d velocity = fluidState.getVelocity(world, pos); + Vector3d velocity = fluidState.getVelocity(world, pos); - Sprite sprite; + TextureAtlasSprite sprite; ModelQuadFacing facing; float u1, u2, u3, u4; float v1, v2, v3, v4; @@ -161,7 +161,7 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos } else { sprite = sprites[1]; facing = ModelQuadFacing.UNASSIGNED; - float dir = (float) MathHelper.atan2(velocity.z, velocity.x) - (1.5707964f); + float dir = (float) Math.atan2(velocity.z, velocity.x) - (1.5707964f); float sin = MathHelper.sin(dir) * 0.25F; float cos = MathHelper.cos(dir) * 0.25F; u1 = sprite.getFrameU(8.0F + (-cos - sin) * 16.0F); @@ -176,18 +176,18 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos float uAvg = (u1 + u2 + u3 + u4) / 4.0F; float vAvg = (v1 + v2 + v3 + v4) / 4.0F; - float s1 = (float) sprites[0].getWidth() / (sprites[0].getMaxU() - sprites[0].getMinU()); - float s2 = (float) sprites[0].getHeight() / (sprites[0].getMaxV() - sprites[0].getMinV()); + float s1 = (float) sprites[0].getIconWidth() / (sprites[0].getMaxU() - sprites[0].getMinU()); + float s2 = (float) sprites[0].getIconHeight() / (sprites[0].getMaxV() - sprites[0].getMinV()); float s3 = 4.0F / Math.max(s2, s1); - u1 = MathHelper.lerp(s3, u1, uAvg); - u2 = MathHelper.lerp(s3, u2, uAvg); - u3 = MathHelper.lerp(s3, u3, uAvg); - u4 = MathHelper.lerp(s3, u4, uAvg); - v1 = MathHelper.lerp(s3, v1, vAvg); - v2 = MathHelper.lerp(s3, v2, vAvg); - v3 = MathHelper.lerp(s3, v3, vAvg); - v4 = MathHelper.lerp(s3, v4, vAvg); + u1 = lerp(s3, u1, uAvg); + u2 = lerp(s3, u2, uAvg); + u3 = lerp(s3, u3, uAvg); + u4 = lerp(s3, u4, uAvg); + v1 = lerp(s3, v1, vAvg); + v2 = lerp(s3, v2, vAvg); + v3 = lerp(s3, v3, vAvg); + v4 = lerp(s3, v4, vAvg); quad.setSprite(sprite); @@ -196,7 +196,7 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos this.setVertex(quad, 2, 1.0F, h3, 1.0F, u3, v3); this.setVertex(quad, 3, 1.0F, h4, 0.0f, u4, v4); - this.calculateQuadColors(quad, world, pos, lighter, Direction.UP, 1.0F, hc); + this.calculateQuadColors(quad, world, pos, lighter, ForgeDirection.UP, 1.0F, hc); this.flushQuad(buffers, quad, facing, false); if (fluidState.method_15756(world, this.scratchPos.set(posX, posY + 1, posZ))) { @@ -212,7 +212,7 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos } if (!sfDown) { - Sprite sprite = sprites[0]; + TextureAtlasSprite sprite = sprites[0]; float minU = sprite.getMinU(); float maxU = sprite.getMaxU(); @@ -225,7 +225,7 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos this.setVertex(quad, 2, 1.0F, yOffset, 0.0f, maxU, minV); this.setVertex(quad, 3, 1.0F, yOffset, 1.0F, maxU, maxV); - this.calculateQuadColors(quad, world, pos, lighter, Direction.DOWN, 1.0F, hc); + this.calculateQuadColors(quad, world, pos, lighter, ForgeDirection.DOWN, 1.0F, hc); this.flushQuad(buffers, quad, ModelQuadFacing.DOWN, false); rendered = true; @@ -233,7 +233,7 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos quad.setFlags(ModelQuadFlags.IS_ALIGNED); - for (Direction dir : DirectionUtil.HORIZONTAL_DIRECTIONS) { + for (ForgeDirection dir : DirectionUtil.HORIZONTAL_DIRECTIONS) { float c1; float c2; float x1; @@ -295,12 +295,12 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos } if (this.isSideExposed(world, posX, posY, posZ, dir, Math.max(c1, c2))) { - int adjX = posX + dir.getOffsetX(); - int adjY = posY + dir.getOffsetY(); - int adjZ = posZ + dir.getOffsetZ(); + int adjX = posX + dir.offsetX; + int adjY = posY + dir.offsetY; + int adjZ = posZ + dir.offsetZ; - Sprite sprite = sprites[1]; - Sprite oSprite = sprites[2]; + TextureAtlasSprite sprite = sprites[1]; + TextureAtlasSprite oSprite = sprites[2]; if (oSprite != null) { BlockPos adjPos = this.scratchPos.set(adjX, adjY, adjZ); @@ -326,7 +326,7 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos this.setVertex(quad, 2, x1, yOffset, z1, u1, v3); this.setVertex(quad, 3, x1, c1, z1, u1, v1); - float br = dir.getAxis() == Direction.Axis.Z ? 0.8F : 0.6F; + float br = dir.getAxis() == ForgeDirection.Axis.Z ? 0.8F : 0.6F; ModelQuadFacing facing = ModelQuadFacing.fromDirection(dir); @@ -349,7 +349,7 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos return rendered; } - private void calculateQuadColors(ModelQuadView quad, BlockRenderView world, BlockPos pos, LightPipeline lighter, Direction dir, float brightness, boolean colorized) { + private void calculateQuadColors(ModelQuadView quad, BlockRenderView world, BlockPos pos, LightPipeline lighter, ForgeDirection dir, float brightness, boolean colorized) { QuadLightData light = this.quadLightData; lighter.calculate(quad, pos, light, null, dir, false); @@ -395,7 +395,7 @@ private void flushQuad(ChunkModelBuffers buffers, ModelQuadView quad, ModelQuadF vertexIdx += lightOrder; } - Sprite sprite = quad.rubidium$getSprite(); + TextureAtlasSprite sprite = quad.rubidium$getSprite(); if (sprite != null) { buffers.getRenderData().addSprite(sprite); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java index cdabe32b8..b0ac6f345 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java @@ -9,8 +9,7 @@ import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.WorldSliceLocal; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.block.BlockModels; +import net.minecraft.client.Minecraft; import net.minecraft.world.World; public class ChunkRenderCacheLocal extends ChunkRenderCache { @@ -23,7 +22,7 @@ public class ChunkRenderCacheLocal extends ChunkRenderCache { private final WorldSlice worldSlice; private WorldSliceLocal localSlice; - public ChunkRenderCacheLocal(MinecraftClient client, World world) { + public ChunkRenderCacheLocal(Minecraft client, World world) { this.worldSlice = new WorldSlice(world); this.lightDataCache = new ArrayLightDataCache(this.worldSlice); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java index 0a8c6f253..ada91f23c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java @@ -1,13 +1,13 @@ package me.jellysquid.mods.sodium.client.render.pipeline.context; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.cache.HashLightDataCache; import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; -import net.minecraft.client.MinecraftClient; -import net.minecraft.world.BlockRenderView; +import net.minecraft.client.Minecraft; import java.util.Map; @@ -18,7 +18,7 @@ public class ChunkRenderCacheShared extends ChunkRenderCache { private final HashLightDataCache lightCache; private ChunkRenderCacheShared(BlockRenderView world) { - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getMinecraft(); this.lightCache = new HashLightDataCache(world); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java index 5f06c319d..e0b3719c1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/texture/SpriteUtil.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.client.render.texture; -import net.minecraft.client.texture.Sprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; public class SpriteUtil { - public static void markSpriteActive(Sprite sprite) { + public static void markSpriteActive(TextureAtlasSprite sprite) { if (sprite instanceof SpriteExtended) { ((SpriteExtended) sprite).markActive(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java index e81efc582..71a6c2be0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.util; import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.util.math.Direction; +import net.minecraftforge.common.util.ForgeDirection; /** * Provides some utilities and constants for interacting with vanilla's model quad vertex format. @@ -39,13 +39,13 @@ public class ModelQuadUtil { } /** - * Returns the normal vector for a model quad with the given {@param facing}. + * Returns the getNormal vector for a model quad with the given {@param facing}. */ - public static int getFacingNormal(Direction facing) { + public static int getFacingNormal(ForgeDirection facing) { return NORMALS[facing.ordinal()]; } - public static int getFacingNormal(Direction facing, int bakedNormal) { + public static int getFacingNormal(ForgeDirection facing, int bakedNormal) { if(!hasNormal(bakedNormal)) return NORMALS[facing.ordinal()]; return bakedNormal; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java b/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java index 5df3e52c5..262504ec7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.util; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3f; -import net.minecraft.util.math.Vec3i; +import cofh.lib.util.helpers.MathHelper; +import org.joml.Vector3f; +import org.joml.Vector3i; /** - * Provides some utilities for working with packed normal vectors. Each normal component provides 8 bits of + * Provides some utilities for working with packed getNormal vectors. Each getNormal component provides 8 bits of * precision in the range of [-1.0,1.0]. * * | 32 | 24 | 16 | 8 | @@ -14,7 +14,7 @@ */ public class Norm3b { /** - * The maximum value of a normal's vector component. + * The maximum value of a getNormal's vector component. */ private static final float COMPONENT_RANGE = 127.0f; @@ -24,20 +24,20 @@ public class Norm3b { */ private static final float NORM = 1.0f / COMPONENT_RANGE; - static int pack(Vec3i norm) { - return pack(norm.getX(), norm.getY(), norm.getZ()); + static int pack(Vector3i norm) { + return pack(norm.x, norm.y, norm.z); } - public static int pack(Vec3f dir) { - return pack(dir.getX(), dir.getY(), dir.getZ()); + public static int pack(Vector3f dir) { + return pack(dir.x, dir.y, dir.z); } /** * Packs the specified vector components into a 32-bit integer in XYZ ordering with the 8 bits of padding at the * end. - * @param x The x component of the normal's vector - * @param y The y component of the normal's vector - * @param z The z component of the normal's vector + * @param x The x component of the getNormal's vector + * @param y The y component of the getNormal's vector + * @param z The z component of the getNormal's vector */ public static int pack(float x, float y, float z) { int normX = encode(x); @@ -57,24 +57,24 @@ private static int encode(float comp) { } /** - * Unpacks the x-component of the packed normal, denormalizing it to a float in the range of -1.0..1.0. - * @param norm The packed normal + * Unpacks the x-component of the packed getNormal, denormalizing it to a float in the range of -1.0..1.0. + * @param norm The packed getNormal */ public static float unpackX(int norm) { return ((byte) (norm & 0xFF)) * NORM; } /** - * Unpacks the y-component of the packed normal, denormalizing it to a float in the range of -1.0..1.0. - * @param norm The packed normal + * Unpacks the y-component of the packed getNormal, denormalizing it to a float in the range of -1.0..1.0. + * @param norm The packed getNormal */ public static float unpackY(int norm) { return ((byte) ((norm >> 8) & 0xFF)) * NORM; } /** - * Unpacks the z-component of the packed normal, denormalizing it to a float in the range of -1.0..1.0. - * @param norm The packed normal + * Unpacks the z-component of the packed getNormal, denormalizing it to a float in the range of -1.0..1.0. + * @param norm The packed getNormal */ public static float unpackZ(int norm) { return ((byte) ((norm >> 16) & 0xFF)) * NORM; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java index 244c1034e..7c5b757dc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java @@ -1,18 +1,20 @@ package me.jellysquid.mods.sodium.client.util.color; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; +import cofh.lib.util.helpers.MathHelper; +import org.joml.Vector3d; import java.util.function.Function; +import static org.joml.Math.lerp; + public class FastCubicSampler { private static final double[] DENSITY_CURVE = new double[] { 0.0D, 1.0D, 4.0D, 6.0D, 4.0D, 1.0D, 0.0D }; private static final int DIAMETER = 6; - public static Vec3d sampleColor(Vec3d pos, ColorFetcher colorFetcher, Function transformer) { - int intX = MathHelper.floor(pos.getX()); - int intY = MathHelper.floor(pos.getY()); - int intZ = MathHelper.floor(pos.getZ()); + public static Vector3d sampleColor(Vector3d pos, ColorFetcher colorFetcher, Function transformer) { + int intX = MathHelper.floor(pos.x); + int intY = MathHelper.floor(pos.y); + int intZ = MathHelper.floor(pos.z); int[] values = new int[DIAMETER * DIAMETER * DIAMETER]; @@ -33,29 +35,29 @@ public static Vec3d sampleColor(Vec3d pos, ColorFetcher colorFetcher, Function palette = section.getBlockPalette(); @@ -232,7 +235,7 @@ private static BlockState nullableState(BlockState state) { @Override public BlockState getBlockState(BlockPos pos) { - return this.getBlockState(pos.getX(), pos.getY(), pos.getZ()); + return this.getBlockState(pos.x, pos.y, pos.z); } public BlockState getBlockState(int x, int y, int z) { @@ -251,12 +254,11 @@ public BlockState getBlockStateRelative(int x, int y, int z) { @Override public FluidState getFluidState(BlockPos pos) { - return this.getBlockState(pos) - .getFluidState(); + return this.getBlockState(pos).getFluidState(); } @Override - public float getBrightness(Direction direction, boolean shaded) { + public float getBrightness(ForgeDirection direction, boolean shaded) { return this.world.getBrightness(direction, shaded); } @@ -266,11 +268,11 @@ public LightingProvider getLightingProvider() { } @Override - public BlockEntity getBlockEntity(BlockPos pos) { - return this.getBlockEntity(pos.getX(), pos.getY(), pos.getZ()); + public TileEntity getBlockEntity(BlockPos pos) { + return this.getBlockEntity(pos.x, pos.y, pos.z); } - public BlockEntity getBlockEntity(int x, int y, int z) { + public TileEntity getBlockEntity(int x, int y, int z) { int relX = x - this.baseX; int relY = y - this.baseY; int relZ = z - this.baseZ; @@ -301,9 +303,9 @@ public int getColor(BlockPos pos, ColorResolver resolver) { @Override public int getLightLevel(LightType type, BlockPos pos) { - int relX = pos.getX() - this.baseX; - int relY = pos.getY() - this.baseY; - int relZ = pos.getZ() - this.baseZ; + int relX = pos.x - this.baseX; + int relY = pos.y - this.baseY; + int relZ = pos.z - this.baseZ; return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] .getLightLevel(type, relX & 15, relY & 15, relZ & 15); @@ -349,7 +351,7 @@ public Biome getBiome(int x, int y, int z) { BiomeCache cache = this.biomeCaches[index]; return cache != null ? cache - .getBiome(this, x, relY >> 4, z) : MinecraftClient.getInstance().world.getBiome(new BlockPos(x, y, z)); + .getBiome(this, x, relY >> 4, z) : Minecraft.getMinecraft().theWorld.getBiome(new BlockPos(x, y, z)); } public ChunkSectionPos getOrigin() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java index 54c3b1929..9d6ac3ce0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java @@ -1,20 +1,13 @@ package me.jellysquid.mods.sodium.client.world; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.fluid.FluidState; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.world.BlockRenderView; -import net.minecraft.world.BlockView; -import net.minecraft.world.LightType; -import net.minecraft.world.RaycastContext; -import net.minecraft.world.chunk.light.LightingProvider; -import net.minecraft.world.level.ColorResolver; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; +import com.rwtema.extrautils.block.Box; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import org.joml.Vector3d; import javax.annotation.Nullable; import java.util.function.BiFunction; @@ -34,7 +27,7 @@ public WorldSliceLocal(BlockRenderView view) { } @Override - public float getBrightness(Direction direction, boolean shaded) { + public float getBrightness(ForgeDirection direction, boolean shaded) { return view.getBrightness(direction, shaded); } @@ -65,7 +58,7 @@ public boolean isSkyVisible(BlockPos pos) { @Override @Nullable - public BlockEntity getBlockEntity(BlockPos pos) { + public TileEntity getBlockEntity(BlockPos pos) { return view.getBlockEntity(pos); } @@ -106,7 +99,7 @@ public BlockHitResult raycast(RaycastContext context) { @Override @Nullable - public BlockHitResult raycastBlock(Vec3d start, Vec3d end, BlockPos pos, VoxelShape shape, BlockState state) { + public BlockHitResult raycastBlock(Vector3d start, Vector3d end, BlockPos pos, VoxelShape shape, BlockState state) { return view.raycastBlock(start, end, pos, shape, state); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java index 4389ec91b..a142c7f95 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.client.world.biome; +import com.gtnewhorizons.angelica.compat.mojang.Biome; +import com.gtnewhorizons.angelica.compat.mojang.BiomeAccess; +import com.gtnewhorizons.angelica.compat.mojang.BiomeAccessType; import me.jellysquid.mods.sodium.client.world.ClientWorldExtended; import net.minecraft.world.World; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.source.BiomeAccess; -import net.minecraft.world.biome.source.BiomeAccessType; import java.util.Arrays; @@ -36,4 +36,4 @@ public Biome getBiome(BiomeAccess.Storage storage, int x, int y, int z) { public void reset() { Arrays.fill(this.biomes, null); } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java index 286bdd875..5e1d677cc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java @@ -1,11 +1,11 @@ package me.jellysquid.mods.sodium.client.world.biome; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.ColorResolver; import me.jellysquid.mods.sodium.client.util.color.ColorARGB; import me.jellysquid.mods.sodium.client.world.WorldSlice; -import net.minecraft.client.MinecraftClient; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.world.level.ColorResolver; +import net.minecraft.client.Minecraft; import java.util.Arrays; @@ -30,7 +30,7 @@ public class BiomeColorCache { public BiomeColorCache(ColorResolver resolver, WorldSlice slice) { this.resolver = resolver; this.slice = slice; - this.radius = MinecraftClient.getInstance().options.biomeBlendRadius; + this.radius = Minecraft.getMinecraft().options.biomeBlendRadius; ChunkSectionPos origin = this.slice.getOrigin(); @@ -51,14 +51,14 @@ public BiomeColorCache(ColorResolver resolver, WorldSlice slice) { } public int getBlendedColor(BlockPos pos) { - int x2 = pos.getX() - this.blendedColorsMinX; - int z2 = pos.getZ() - this.blendedColorsMinZ; + int x2 = pos.x - this.blendedColorsMinX; + int z2 = pos.z - this.blendedColorsMinZ; int index = (x2 * BLENDED_COLORS_DIM) + z2; int color = this.blendedColors[index]; if (color == -1) { - this.blendedColors[index] = color = this.calculateBlendedColor(pos.getX(), pos.getZ()); + this.blendedColors[index] = color = this.calculateBlendedColor(pos.x, pos.getZ()); } return color; @@ -109,4 +109,4 @@ private int getColor(int x, int z) { private int calculateColor(int x, int z) { return this.resolver.getColor(this.slice.getBiome(x, this.height, z), x, z); } -} \ No newline at end of file +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java index bfb3fb637..d863808b2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.world.biome; -import net.minecraft.block.BlockState; -import net.minecraft.client.color.block.BlockColorProvider; +import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; public interface BlockColorsExtended { BlockColorProvider getColorProvider(BlockState state); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java index 4bf7e4743..885f14cb0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.world.biome; -import net.minecraft.client.color.item.ItemColorProvider; import net.minecraft.item.ItemStack; public interface ItemColorsExtended { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java index cf0116544..9b44abfb5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java @@ -1,14 +1,14 @@ package me.jellysquid.mods.sodium.client.world.cloned; -import net.minecraft.util.math.BlockBox; -import net.minecraft.util.math.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import net.minecraft.world.gen.structure.StructureBoundingBox; public class ChunkRenderContext { private final ChunkSectionPos origin; private final ClonedChunkSection[] sections; - private final BlockBox volume; + private final StructureBoundingBox volume; - public ChunkRenderContext(ChunkSectionPos origin, ClonedChunkSection[] sections, BlockBox volume) { + public ChunkRenderContext(ChunkSectionPos origin, ClonedChunkSection[] sections, StructureBoundingBox volume) { this.origin = origin; this.sections = sections; this.volume = volume; @@ -22,7 +22,7 @@ public ChunkSectionPos getOrigin() { return this.origin; } - public BlockBox getVolume() { + public StructureBoundingBox getVolume() { return this.volume; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index e3561e6f5..300453eac 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -1,22 +1,21 @@ package me.jellysquid.mods.sodium.client.world.cloned; +import com.gtnewhorizons.angelica.compat.mojang.Biome; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.LightType; +import com.gtnewhorizons.angelica.compat.mojang.PackedIntegerArray; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPaletteFallback; import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalleteArray; import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.util.collection.PackedIntegerArray; -import net.minecraft.util.math.BlockBox; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.world.LightType; +import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.source.BiomeArray; import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.gen.structure.StructureBoundingBox; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -28,7 +27,7 @@ public class ClonedChunkSection { private final AtomicInteger referenceCount = new AtomicInteger(0); private final ClonedChunkSectionCache backingCache; - private final Short2ObjectMap blockEntities; + private final Short2ObjectMap blockEntities; private final ChunkNibbleArray[] lightDataArrays; private final World world; @@ -49,7 +48,7 @@ public class ClonedChunkSection { } public void init(ChunkSectionPos pos) { - WorldChunk chunk = world.getChunk(pos.getX(), pos.getZ()); + Chunk chunk = world.getChunkFromChunkCoords(pos.x, pos.z); if (chunk == null) { throw new RuntimeException("Couldn't retrieve chunk at " + pos.toChunkPos()); @@ -76,11 +75,11 @@ public void init(ChunkSectionPos pos) { this.biomeData = chunk.getBiomeArray(); - BlockBox box = new BlockBox(pos.getMinX(), pos.getMinY(), pos.getMinZ(), pos.getMaxX(), pos.getMaxY(), pos.getMaxZ()); + StructureBoundingBox box = new StructureBoundingBox(pos.getMinX(), pos.getMinY(), pos.getMinZ(), pos.getMaxX(), pos.getMaxY(), pos.getMaxZ()); this.blockEntities.clear(); - for (Map.Entry entry : chunk.getBlockEntities().entrySet()) { + for (Map.Entry entry : chunk.getBlockEntities().entrySet()) { BlockPos entityPos = entry.getKey(); if (box.contains(entityPos)) { @@ -108,7 +107,7 @@ public Biome getBiomeForNoiseGen(int x, int y, int z) { return this.biomeData.getBiomeForNoiseGen(x, y, z); } - public BlockEntity getBlockEntity(int x, int y, int z) { + public TileEntity getBlockEntity(int x, int y, int z) { return this.blockEntities.get(packLocal(x, y, z)); } @@ -155,7 +154,7 @@ private static ChunkSection getChunkSection(Chunk chunk, ChunkSectionPos pos) { ChunkSection section = null; if (!World.isOutOfBuildLimitVertically(ChunkSectionPos.getBlockCoord(pos.getY()))) { - section = chunk.getSectionArray()[pos.getY()]; + section = chunk.getSectionArray()[pos.y]; } return section; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java index 79d89ef33..08424bfb2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.world.cloned; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import it.unimi.dsi.fastutil.longs.Long2ReferenceLinkedOpenHashMap; -import net.minecraft.util.math.ChunkSectionPos; import net.minecraft.world.World; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java index 2baf1f112..ffcb9690c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java @@ -1,8 +1,6 @@ package me.jellysquid.mods.sodium.client.world.cloned; -import net.minecraft.util.collection.PackedIntegerArray; -import net.minecraft.world.chunk.Palette; -import net.minecraft.world.chunk.PalettedContainer; + public interface PalettedContainerExtended { @SuppressWarnings("unchecked") diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java index c8ed02f4a..2fe1c33b4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.world.cloned.palette; -import net.minecraft.util.collection.IdList; public class ClonedPaletteFallback implements ClonedPalette { private final IdList idList; diff --git a/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java b/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java index b131b3b62..f8afb950b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java @@ -1,7 +1,5 @@ package me.jellysquid.mods.sodium.common.config; -import net.minecraftforge.fml.loading.FMLEnvironment; -import net.minecraftforge.fml.loading.FMLLoader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java b/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java index 9e50b953e..eac19d5a6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java @@ -1,15 +1,36 @@ package me.jellysquid.mods.sodium.common.util; -import net.minecraft.util.math.Direction; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraftforge.common.util.ForgeDirection; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.stream.Collectors; /** * Contains a number of cached arrays to avoid allocations since calling Enum#values() requires the backing array to * be cloned every time. */ public class DirectionUtil { - public static final Direction[] ALL_DIRECTIONS = Direction.values(); + public static final ForgeDirection[] ALL_DIRECTIONS = ForgeDirection.values(); public static final int DIRECTION_COUNT = ALL_DIRECTIONS.length; - // Provides the same order as enumerating Direction and checking the axis of each value - public static final Direction[] HORIZONTAL_DIRECTIONS = new Direction[] { Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST }; + // Provides the same order as enumerating ForgeDirection and checking the axis of each value + public static final ForgeDirection[] HORIZONTAL_DIRECTIONS = new ForgeDirection[] { ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST }; + + private static final Long2ObjectMap VECTOR_TO_DIRECTION = (Long2ObjectMap) Arrays.stream(ALL_DIRECTIONS).collect(Collectors.toMap((arg) -> { + return (new BlockPos(arg.offsetX, arg.offsetY, arg.offsetZ)).asLong(); + }, (arg) -> { + return arg; + }, (arg, arg2) -> { + throw new IllegalArgumentException("Duplicate keys"); + }, Long2ObjectOpenHashMap::new)); + + @Nullable + public static ForgeDirection fromVector(int x, int y, int z) { + return (ForgeDirection)VECTOR_TO_DIRECTION.get(BlockPos.asLong(x, y, z)); + } + } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/SodiumMixinPlugin.java b/src/main/java/me/jellysquid/mods/sodium/mixin/SodiumMixinPlugin.java deleted file mode 100644 index 407a20e37..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/SodiumMixinPlugin.java +++ /dev/null @@ -1,95 +0,0 @@ -package me.jellysquid.mods.sodium.mixin; - -import me.jellysquid.mods.sodium.common.config.Option; -import me.jellysquid.mods.sodium.common.config.SodiumConfig; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.objectweb.asm.tree.ClassNode; -import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; -import org.spongepowered.asm.mixin.extensibility.IMixinInfo; - -import java.io.File; -import java.util.List; -import java.util.Set; - -public class SodiumMixinPlugin implements IMixinConfigPlugin { - private static final String MIXIN_PACKAGE_ROOT = "me.jellysquid.mods.sodium.mixin."; - - private final Logger logger = LogManager.getLogger("Embeddium"); - private SodiumConfig config; - - @Override - public void onLoad(String mixinPackage) { - try { - this.config = SodiumConfig.load(new File("./config/rubidium-mixins.properties")); - } catch (Exception e) { - throw new RuntimeException("Could not load configuration file for Embeddium", e); - } - - this.logger.info("Loaded configuration file for Embeddium: {} options available, {} override(s) found", - this.config.getOptionCount(), this.config.getOptionOverrideCount()); - } - - @Override - public String getRefMapperConfig() { - return null; - } - - @Override - public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - if (!mixinClassName.startsWith(MIXIN_PACKAGE_ROOT)) { - this.logger.error("Expected mixin '{}' to start with package root '{}', treating as foreign and " + - "disabling!", mixinClassName, MIXIN_PACKAGE_ROOT); - - return false; - } - - String mixin = mixinClassName.substring(MIXIN_PACKAGE_ROOT.length()); - Option option = this.config.getEffectiveOptionForMixin(mixin); - - if (option == null) { - this.logger.error("No rules matched mixin '{}', treating as foreign and disabling!", mixin); - - return false; - } - - if (option.isOverridden()) { - String source = "[unknown]"; - - if (option.isUserDefined()) { - source = "user configuration"; - } else if (option.isModDefined()) { - source = "mods [" + String.join(", ", option.getDefiningMods()) + "]"; - } - - if (option.isEnabled()) { - this.logger.warn("Force-enabling mixin '{}' as rule '{}' (added by {}) enables it", mixin, - option.getName(), source); - } else { - this.logger.warn("Force-disabling mixin '{}' as rule '{}' (added by {}) disables it and children", mixin, - option.getName(), source); - } - } - - return option.isEnabled(); - } - @Override - public void acceptTargets(Set myTargets, Set otherTargets) { - - } - - @Override - public List getMixins() { - return null; - } - - @Override - public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } - - @Override - public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/MixinDirection.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/MixinDirection.java deleted file mode 100644 index 1a0fd85a0..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/MixinDirection.java +++ /dev/null @@ -1,66 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.core; - -import net.minecraft.client.render.OverlayVertexConsumer; -import net.minecraft.client.render.model.BakedQuadFactory; -import net.minecraft.client.render.model.json.JsonUnbakedModel; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.Direction; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -@Mixin(Direction.class) -public class MixinDirection { - /** - * Used by: - *

    - *
  • {@link OverlayVertexConsumer}
  • - *
  • UV-locked faces and cullfaces in {@link JsonUnbakedModel} and {@link BakedQuadFactory}
  • - *
  • Raycasts, when creating the {@link BlockHitResult}
  • - *
- * - * @author Mitchell Skaggs - * @reason Avoid looping over all directions and computing the dot product - */ - @Overwrite - public static Direction getFacing(float x, float y, float z) { - // Vanilla quirk: return NORTH if all entries are zero - if (x == 0 && y == 0 && z == 0) - return Direction.NORTH; - - // First choice in ties: negative, positive; Y, Z, X - float yM = Math.abs(y); - float zM = Math.abs(z); - float xM = Math.abs(x); - - if (yM >= zM) { - if (yM >= xM) { - // Y biggest - if (y <= 0) { - return Direction.DOWN; - } else /* y > 0 */ { - return Direction.UP; - } - } else /* zM <= yM < xM */ { - // X biggest, fall through - } - } else /* yM < zM */ { - if (zM >= xM) { - // Z biggest - if (z <= 0) { - return Direction.NORTH; - } else /* z > 0 */ { - return Direction.SOUTH; - } - } else /* yM < zM < xM */ { - // X biggest, fall through - } - } - - // X biggest - if (x <= 0) { - return Direction.WEST; - } else /* x > 0 */ { - return Direction.EAST; - } - } -} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/frustum/MixinFrustum.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/frustum/MixinFrustum.java deleted file mode 100644 index aef74d67c..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/frustum/MixinFrustum.java +++ /dev/null @@ -1,115 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.core.frustum; - -import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; -import net.minecraft.client.render.Frustum; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.Matrix4f; -import net.minecraft.util.math.Vector4f; -import net.minecraftforge.common.extensions.IForgeTileEntity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(Frustum.class) -public abstract class MixinFrustum implements FrustumExtended { - @Shadow public abstract boolean isVisible(double minX, double minY, double minZ, double maxX, double maxY, double maxZ); - - private float xF, yF, zF; - - private float nxX, nxY, nxZ, nxW; - private float pxX, pxY, pxZ, pxW; - private float nyX, nyY, nyZ, nyW; - private float pyX, pyY, pyZ, pyW; - private float nzX, nzY, nzZ, nzW; - private float pzX, pzY, pzZ, pzW; - - @Inject(method = "setPosition", at = @At("HEAD")) - private void prePositionUpdate(double cameraX, double cameraY, double cameraZ, CallbackInfo ci) { - this.xF = (float) cameraX; - this.yF = (float) cameraY; - this.zF = (float) cameraZ; - } - - @Inject(method = "transform", at = @At("HEAD")) - private void transform(Matrix4f mat, int x, int y, int z, int index, CallbackInfo ci) { - Vector4f vec = new Vector4f((float) x, (float) y, (float) z, 1.0F); - vec.transform(mat); - vec.normalize(); - - switch (index) { - case 0: - this.nxX = vec.getX(); - this.nxY = vec.getY(); - this.nxZ = vec.getZ(); - this.nxW = vec.getW(); - break; - case 1: - this.pxX = vec.getX(); - this.pxY = vec.getY(); - this.pxZ = vec.getZ(); - this.pxW = vec.getW(); - break; - case 2: - this.nyX = vec.getX(); - this.nyY = vec.getY(); - this.nyZ = vec.getZ(); - this.nyW = vec.getW(); - break; - case 3: - this.pyX = vec.getX(); - this.pyY = vec.getY(); - this.pyZ = vec.getZ(); - this.pyW = vec.getW(); - break; - case 4: - this.nzX = vec.getX(); - this.nzY = vec.getY(); - this.nzZ = vec.getZ(); - this.nzW = vec.getW(); - break; - case 5: - this.pzX = vec.getX(); - this.pzY = vec.getY(); - this.pzZ = vec.getZ(); - this.pzW = vec.getW(); - break; - default: - throw new IllegalArgumentException("Invalid index"); - } - } - - @Override - public boolean fastAabbTest(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { - return this.isAnyCornerVisible(minX - this.xF, minY - this.yF, minZ - this.zF, - maxX - this.xF, maxY - this.yF, maxZ - this.zF); - } - - /** - * @author XFactHD (ported by embeddedt) - * @reason Avoid passing infinite extents box into optimized frustum code. - * This is a port of PR #9407 - */ - @Overwrite - public boolean isVisible(Box box) { - if(box.equals(IForgeTileEntity.INFINITE_EXTENT_AABB)) - return true; - return this.isVisible(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ); - } - - /** - * @author JellySquid - * @reason Optimize away object allocations and for-loop - */ - @Overwrite - private boolean isAnyCornerVisible(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { - return this.nxX * (this.nxX < 0 ? minX : maxX) + this.nxY * (this.nxY < 0 ? minY : maxY) + this.nxZ * (this.nxZ < 0 ? minZ : maxZ) >= -this.nxW && - this.pxX * (this.pxX < 0 ? minX : maxX) + this.pxY * (this.pxY < 0 ? minY : maxY) + this.pxZ * (this.pxZ < 0 ? minZ : maxZ) >= -this.pxW && - this.nyX * (this.nyX < 0 ? minX : maxX) + this.nyY * (this.nyY < 0 ? minY : maxY) + this.nyZ * (this.nyZ < 0 ? minZ : maxZ) >= -this.nyW && - this.pyX * (this.pyX < 0 ? minX : maxX) + this.pyY * (this.pyY < 0 ? minY : maxY) + this.pyZ * (this.pyZ < 0 ? minZ : maxZ) >= -this.pyW && - this.nzX * (this.nzX < 0 ? minX : maxX) + this.nzY * (this.nzY < 0 ? minY : maxY) + this.nzZ * (this.nzZ < 0 ? minZ : maxZ) >= -this.nzW && - this.pzX * (this.pzX < 0 ? minX : maxX) + this.pzY * (this.pzY < 0 ? minY : maxY) + this.pzZ * (this.pzZ < 0 ? minZ : maxZ) >= -this.pzW; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinGameRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinGameRenderer.java deleted file mode 100644 index 9fe8f2c31..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinGameRenderer.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.core.matrix; - -import me.jellysquid.mods.sodium.client.render.GameRendererContext; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.util.math.Matrix4f; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(GameRenderer.class) -public class MixinGameRenderer { - @Inject(method = "loadProjectionMatrix", at = @At("HEAD")) - public void captureProjectionMatrix(Matrix4f matrix, CallbackInfo ci) { - GameRendererContext.captureProjectionMatrix(matrix); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix3f.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix3f.java deleted file mode 100644 index 03fc9c999..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix3f.java +++ /dev/null @@ -1,229 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.core.matrix; - -import me.jellysquid.mods.sodium.client.util.Norm3b; -import me.jellysquid.mods.sodium.client.util.math.Matrix3fExtended; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Matrix3f; -import net.minecraft.util.math.Quaternion; -import net.minecraft.util.math.Vec3i; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(Matrix3f.class) -public class MixinMatrix3f implements Matrix3fExtended { - @Shadow - protected float a00; - - @Shadow - protected float a10; - - @Shadow - protected float a20; - - @Shadow - protected float a01; - - @Shadow - protected float a11; - - @Shadow - protected float a21; - - @Shadow - protected float a02; - - @Shadow - protected float a12; - - @Shadow - protected float a22; - - @Override - public float transformVecX(float x, float y, float z) { - return this.a00 * x + this.a01 * y + this.a02 * z; - } - - @Override - public float transformVecY(float x, float y, float z) { - return this.a10 * x + this.a11 * y + this.a12 * z; - } - - @Override - public float transformVecZ(float x, float y, float z) { - return this.a20 * x + this.a21 * y + this.a22 * z; - } - - @Override - public void rotate(Quaternion quaternion) { - boolean x = quaternion.getX() != 0.0F; - boolean y = quaternion.getY() != 0.0F; - boolean z = quaternion.getZ() != 0.0F; - - // Try to determine if this is a simple rotation on one axis component only - if (x) { - if (!y && !z) { - this.rotateX(quaternion); - } else { - this.rotateXYZ(quaternion); - } - } else if (y) { - if (!z) { - this.rotateY(quaternion); - } else { - this.rotateXYZ(quaternion); - } - } else if (z) { - this.rotateZ(quaternion); - } - } - - @Override - public int computeNormal(Direction dir) { - Vec3i faceNorm = dir.getVector(); - - float x = faceNorm.getX(); - float y = faceNorm.getY(); - float z = faceNorm.getZ(); - - float x2 = this.a00 * x + this.a01 * y + this.a02 * z; - float y2 = this.a10 * x + this.a11 * y + this.a12 * z; - float z2 = this.a20 * x + this.a21 * y + this.a22 * z; - - return Norm3b.pack(x2, y2, z2); - } - - private void rotateX(Quaternion quaternion) { - float x = quaternion.getX(); - float w = quaternion.getW(); - - float xx = 2.0F * x * x; - - float ta11 = 1.0F - xx; - float ta22 = 1.0F - xx; - - float xw = x * w; - float ta21 = 2.0F * xw; - float ta12 = 2.0F * -xw; - - float a01 = this.a01 * ta11 + this.a02 * ta21; - float a02 = this.a01 * ta12 + this.a02 * ta22; - float a11 = this.a11 * ta11 + this.a12 * ta21; - float a12 = this.a11 * ta12 + this.a12 * ta22; - float a21 = this.a21 * ta11 + this.a22 * ta21; - float a22 = this.a21 * ta12 + this.a22 * ta22; - - this.a01 = a01; - this.a02 = a02; - this.a11 = a11; - this.a12 = a12; - this.a21 = a21; - this.a22 = a22; - } - - private void rotateY(Quaternion quaternion) { - float y = quaternion.getY(); - float w = quaternion.getW(); - - float yy = 2.0F * y * y; - - float ta00 = 1.0F - yy; - float ta22 = 1.0F - yy; - - float yw = y * w; - - float ta20 = 2.0F * (-yw); - float ta02 = 2.0F * (+yw); - - float a00 = this.a00 * ta00 + this.a02 * ta20; - float a02 = this.a00 * ta02 + this.a02 * ta22; - float a10 = this.a10 * ta00 + this.a12 * ta20; - float a12 = this.a10 * ta02 + this.a12 * ta22; - float a20 = this.a20 * ta00 + this.a22 * ta20; - float a22 = this.a20 * ta02 + this.a22 * ta22; - - this.a00 = a00; - this.a02 = a02; - this.a10 = a10; - this.a12 = a12; - this.a20 = a20; - this.a22 = a22; - } - - private void rotateZ(Quaternion quaternion) { - float z = quaternion.getZ(); - float w = quaternion.getW(); - - float zz = 2.0F * z * z; - - float ta00 = 1.0F - zz; - float ta11 = 1.0F - zz; - - float zw = z * w; - - float ta10 = 2.0F * (0.0F + zw); - float ta01 = 2.0F * (0.0F - zw); - - float a00 = this.a00 * ta00 + this.a01 * ta10; - float a01 = this.a00 * ta01 + this.a01 * ta11; - float a10 = this.a10 * ta00 + this.a11 * ta10; - float a11 = this.a10 * ta01 + this.a11 * ta11; - float a20 = this.a20 * ta00 + this.a21 * ta10; - float a21 = this.a20 * ta01 + this.a21 * ta11; - - this.a00 = a00; - this.a01 = a01; - this.a10 = a10; - this.a11 = a11; - this.a20 = a20; - this.a21 = a21; - } - - private void rotateXYZ(Quaternion quaternion) { - float x = quaternion.getX(); - float y = quaternion.getY(); - float z = quaternion.getZ(); - float w = quaternion.getW(); - - float xx = 2.0F * x * x; - float yy = 2.0F * y * y; - float zz = 2.0F * z * z; - - float ta00 = 1.0F - yy - zz; - float ta11 = 1.0F - zz - xx; - float ta22 = 1.0F - xx - yy; - - float xy = x * y; - float yz = y * z; - float zx = z * x; - float xw = x * w; - float yw = y * w; - float zw = z * w; - - float ta10 = 2.0F * (xy + zw); - float ta01 = 2.0F * (xy - zw); - float ta20 = 2.0F * (zx - yw); - float ta02 = 2.0F * (zx + yw); - float ta21 = 2.0F * (yz + xw); - float ta12 = 2.0F * (yz - xw); - - float a00 = this.a00 * ta00 + this.a01 * ta10 + this.a02 * ta20; - float a01 = this.a00 * ta01 + this.a01 * ta11 + this.a02 * ta21; - float a02 = this.a00 * ta02 + this.a01 * ta12 + this.a02 * ta22; - float a10 = this.a10 * ta00 + this.a11 * ta10 + this.a12 * ta20; - float a11 = this.a10 * ta01 + this.a11 * ta11 + this.a12 * ta21; - float a12 = this.a10 * ta02 + this.a11 * ta12 + this.a12 * ta22; - float a20 = this.a20 * ta00 + this.a21 * ta10 + this.a22 * ta20; - float a21 = this.a20 * ta01 + this.a21 * ta11 + this.a22 * ta21; - float a22 = this.a20 * ta02 + this.a21 * ta12 + this.a22 * ta22; - - this.a00 = a00; - this.a01 = a01; - this.a02 = a02; - this.a10 = a10; - this.a11 = a11; - this.a12 = a12; - this.a20 = a20; - this.a21 = a21; - this.a22 = a22; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix4f.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix4f.java deleted file mode 100644 index 43361ffd8..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/matrix/MixinMatrix4f.java +++ /dev/null @@ -1,313 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.core.matrix; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; -import net.minecraft.util.math.Matrix4f; -import net.minecraft.util.math.Quaternion; -import org.lwjgl.system.MemoryUtil; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.nio.BufferUnderflowException; -import java.nio.FloatBuffer; - -@Mixin(Matrix4f.class) -public class MixinMatrix4f implements Matrix4fExtended { - @Shadow - protected float a00; - - @Shadow - protected float a01; - - @Shadow - protected float a02; - - @Shadow - protected float a03; - - @Shadow - protected float a10; - - @Shadow - protected float a11; - - @Shadow - protected float a12; - - @Shadow - protected float a13; - - @Shadow - protected float a20; - - @Shadow - protected float a21; - - @Shadow - protected float a22; - - @Shadow - protected float a23; - - @Shadow - protected float a30; - - @Shadow - protected float a31; - - @Shadow - protected float a32; - - @Shadow - protected float a33; - - @Override - public void translate(float x, float y, float z) { - this.a03 = this.a00 * x + this.a01 * y + this.a02 * z + this.a03; - this.a13 = this.a10 * x + this.a11 * y + this.a12 * z + this.a13; - this.a23 = this.a20 * x + this.a21 * y + this.a22 * z + this.a23; - this.a33 = this.a30 * x + this.a31 * y + this.a32 * z + this.a33; - } - - @Override - public float transformVecX(float x, float y, float z) { - return (this.a00 * x) + (this.a01 * y) + (this.a02 * z) + (this.a03 * 1.0f); - } - - @Override - public float transformVecY(float x, float y, float z) { - return (this.a10 * x) + (this.a11 * y) + (this.a12 * z) + (this.a13 * 1.0f); - } - - @Override - public float transformVecZ(float x, float y, float z) { - return (this.a20 * x) + (this.a21 * y) + (this.a22 * z) + (this.a23 * 1.0f); - } - - @Override - public void rotate(Quaternion quaternion) { - boolean x = quaternion.getX() != 0.0F; - boolean y = quaternion.getY() != 0.0F; - boolean z = quaternion.getZ() != 0.0F; - - // Try to determine if this is a simple rotation on one axis component only - if (x) { - if (!y && !z) { - this.rotateX(quaternion); - } else { - this.rotateXYZ(quaternion); - } - } else if (y) { - if (!z) { - this.rotateY(quaternion); - } else { - this.rotateXYZ(quaternion); - } - } else if (z) { - this.rotateZ(quaternion); - } - } - - private void rotateX(Quaternion quaternion) { - float x = quaternion.getX(); - float w = quaternion.getW(); - - float xx = 2.0F * x * x; - float ta11 = 1.0F - xx; - float ta22 = 1.0F - xx; - - float xw = x * w; - - float ta21 = 2.0F * xw; - float ta12 = 2.0F * -xw; - - float a01 = this.a01 * ta11 + this.a02 * ta21; - float a02 = this.a01 * ta12 + this.a02 * ta22; - float a11 = this.a11 * ta11 + this.a12 * ta21; - float a12 = this.a11 * ta12 + this.a12 * ta22; - float a21 = this.a21 * ta11 + this.a22 * ta21; - float a22 = this.a21 * ta12 + this.a22 * ta22; - float a31 = this.a31 * ta11 + this.a32 * ta21; - float a32 = this.a31 * ta12 + this.a32 * ta22; - - this.a01 = a01; - this.a02 = a02; - this.a11 = a11; - this.a12 = a12; - this.a21 = a21; - this.a22 = a22; - this.a31 = a31; - this.a32 = a32; - } - - private void rotateY(Quaternion quaternion) { - float y = quaternion.getY(); - float w = quaternion.getW(); - - float yy = 2.0F * y * y; - float ta00 = 1.0F - yy; - float ta22 = 1.0F - yy; - float yw = y * w; - float ta20 = 2.0F * -yw; - float ta02 = 2.0F * yw; - - float a00 = this.a00 * ta00 + this.a02 * ta20; - float a02 = this.a00 * ta02 + this.a02 * ta22; - float a10 = this.a10 * ta00 + this.a12 * ta20; - float a12 = this.a10 * ta02 + this.a12 * ta22; - float a20 = this.a20 * ta00 + this.a22 * ta20; - float a22 = this.a20 * ta02 + this.a22 * ta22; - float a30 = this.a30 * ta00 + this.a32 * ta20; - float a32 = this.a30 * ta02 + this.a32 * ta22; - - this.a00 = a00; - this.a02 = a02; - this.a10 = a10; - this.a12 = a12; - this.a20 = a20; - this.a22 = a22; - this.a30 = a30; - this.a32 = a32; - } - - private void rotateZ(Quaternion quaternion) { - float z = quaternion.getZ(); - float w = quaternion.getW(); - - float zz = 2.0F * z * z; - float ta00 = 1.0F - zz; - float ta11 = 1.0F - zz; - float zw = z * w; - float ta10 = 2.0F * zw; - float ta01 = 2.0F * -zw; - - float a00 = this.a00 * ta00 + this.a01 * ta10; - float a01 = this.a00 * ta01 + this.a01 * ta11; - float a10 = this.a10 * ta00 + this.a11 * ta10; - float a11 = this.a10 * ta01 + this.a11 * ta11; - float a20 = this.a20 * ta00 + this.a21 * ta10; - float a21 = this.a20 * ta01 + this.a21 * ta11; - float a30 = this.a30 * ta00 + this.a31 * ta10; - float a31 = this.a30 * ta01 + this.a31 * ta11; - - this.a00 = a00; - this.a01 = a01; - this.a10 = a10; - this.a11 = a11; - this.a20 = a20; - this.a21 = a21; - this.a30 = a30; - this.a31 = a31; - } - - private void rotateXYZ(Quaternion quaternion) { - float x = quaternion.getX(); - float y = quaternion.getY(); - float z = quaternion.getZ(); - float w = quaternion.getW(); - - float xx = 2.0F * x * x; - float yy = 2.0F * y * y; - float zz = 2.0F * z * z; - float ta00 = 1.0F - yy - zz; - float ta11 = 1.0F - zz - xx; - float ta22 = 1.0F - xx - yy; - float xy = x * y; - float yz = y * z; - float zx = z * x; - float xw = x * w; - float yw = y * w; - float zw = z * w; - float ta10 = 2.0F * (xy + zw); - float ta01 = 2.0F * (xy - zw); - float ta20 = 2.0F * (zx - yw); - float ta02 = 2.0F * (zx + yw); - float ta21 = 2.0F * (yz + xw); - float ta12 = 2.0F * (yz - xw); - - float a00 = this.a00 * ta00 + this.a01 * ta10 + this.a02 * ta20; - float a01 = this.a00 * ta01 + this.a01 * ta11 + this.a02 * ta21; - float a02 = this.a00 * ta02 + this.a01 * ta12 + this.a02 * ta22; - float a10 = this.a10 * ta00 + this.a11 * ta10 + this.a12 * ta20; - float a11 = this.a10 * ta01 + this.a11 * ta11 + this.a12 * ta21; - float a12 = this.a10 * ta02 + this.a11 * ta12 + this.a12 * ta22; - float a20 = this.a20 * ta00 + this.a21 * ta10 + this.a22 * ta20; - float a21 = this.a20 * ta01 + this.a21 * ta11 + this.a22 * ta21; - float a22 = this.a20 * ta02 + this.a21 * ta12 + this.a22 * ta22; - float a30 = this.a30 * ta00 + this.a31 * ta10 + this.a32 * ta20; - float a31 = this.a30 * ta01 + this.a31 * ta11 + this.a32 * ta21; - float a32 = this.a30 * ta02 + this.a31 * ta12 + this.a32 * ta22; - - this.a00 = a00; - this.a01 = a01; - this.a02 = a02; - this.a10 = a10; - this.a11 = a11; - this.a12 = a12; - this.a20 = a20; - this.a21 = a21; - this.a22 = a22; - this.a30 = a30; - this.a31 = a31; - this.a32 = a32; - } - - /** - * @reason Optimize - * @author JellySquid - */ - @Overwrite - public void writeRowFirst(FloatBuffer buf) { - if (buf.remaining() < 16) { - throw new BufferUnderflowException(); - } - - if (buf.isDirect() && SodiumClientMod.isDirectMemoryAccessEnabled()) { - this.writeToBufferUnsafe(buf); - } else { - this.writeToBufferSafe(buf); - } - } - - private void writeToBufferUnsafe(FloatBuffer buf) { - long addr = MemoryUtil.memAddress(buf); - - MemoryUtil.memPutFloat(addr + 0, this.a00); - MemoryUtil.memPutFloat(addr + 0, this.a00); - MemoryUtil.memPutFloat(addr + 4, this.a10); - MemoryUtil.memPutFloat(addr + 8, this.a20); - MemoryUtil.memPutFloat(addr + 12, this.a30); - MemoryUtil.memPutFloat(addr + 16, this.a01); - MemoryUtil.memPutFloat(addr + 20, this.a11); - MemoryUtil.memPutFloat(addr + 24, this.a21); - MemoryUtil.memPutFloat(addr + 28, this.a31); - MemoryUtil.memPutFloat(addr + 32, this.a02); - MemoryUtil.memPutFloat(addr + 36, this.a12); - MemoryUtil.memPutFloat(addr + 40, this.a22); - MemoryUtil.memPutFloat(addr + 44, this.a32); - MemoryUtil.memPutFloat(addr + 48, this.a03); - MemoryUtil.memPutFloat(addr + 52, this.a13); - MemoryUtil.memPutFloat(addr + 56, this.a23); - MemoryUtil.memPutFloat(addr + 60, this.a33); - } - - private void writeToBufferSafe(FloatBuffer buf) { - buf.put(0, this.a00); - buf.put(1, this.a10); - buf.put(2, this.a20); - buf.put(3, this.a30); - buf.put(4, this.a01); - buf.put(5, this.a11); - buf.put(6, this.a21); - buf.put(7, this.a31); - buf.put(8, this.a02); - buf.put(9, this.a12); - buf.put(10, this.a22); - buf.put(11, this.a32); - buf.put(12, this.a03); - buf.put(13, this.a13); - buf.put(14, this.a23); - buf.put(15, this.a33); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinBlockColors.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinBlockColors.java deleted file mode 100644 index 9cf582d00..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinBlockColors.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.core.model; - -import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; -import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.world.biome.BlockColorsExtended; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.client.color.block.BlockColorProvider; -import net.minecraft.client.color.block.BlockColors; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(BlockColors.class) -public class MixinBlockColors implements BlockColorsExtended { - private Reference2ReferenceMap blocksToColor; - - private static final BlockColorProvider DEFAULT_PROVIDER = (state, view, pos, tint) -> -1; - - @Inject(method = "", at = @At("RETURN")) - private void init(CallbackInfo ci) { - this.blocksToColor = new Reference2ReferenceOpenHashMap<>(); - this.blocksToColor.defaultReturnValue(DEFAULT_PROVIDER); - } - - @Inject(method = "registerColorProvider", at = @At("HEAD")) - private void preRegisterColor(BlockColorProvider provider, Block[] blocks, CallbackInfo ci) { - for (Block block : blocks) { - if(provider != null) - this.blocksToColor.put(block, provider); - } - } - - @Override - public BlockColorProvider getColorProvider(BlockState state) { - return this.blocksToColor.get(state.getBlock()); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinItemColors.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinItemColors.java deleted file mode 100644 index 5e2c610a3..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/model/MixinItemColors.java +++ /dev/null @@ -1,40 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.core.model; - -import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; -import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.world.biome.ItemColorsExtended; -import net.minecraft.client.color.item.ItemColorProvider; -import net.minecraft.client.color.item.ItemColors; -import net.minecraft.item.Item; -import net.minecraft.item.ItemConvertible; -import net.minecraft.item.ItemStack; -import net.minecraftforge.registries.IRegistryDelegate; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(ItemColors.class) -public class MixinItemColors implements ItemColorsExtended { - private Reference2ReferenceMap, ItemColorProvider> itemsToColor; - - private static final ItemColorProvider DEFAULT_PROVIDER = (stack, tintIdx) -> -1; - - @Inject(method = "", at = @At("RETURN")) - private void init(CallbackInfo ci) { - this.itemsToColor = new Reference2ReferenceOpenHashMap<>(); - this.itemsToColor.defaultReturnValue(DEFAULT_PROVIDER); - } - - @Inject(method = "register", at = @At("HEAD")) - private void preRegisterColor(ItemColorProvider mapper, ItemConvertible[] convertibles, CallbackInfo ci) { - for (ItemConvertible convertible : convertibles) { - this.itemsToColor.put(convertible.asItem().delegate, mapper); - } - } - - @Override - public ItemColorProvider getColorProvider(ItemStack stack) { - return this.itemsToColor.get(stack.getItem().delegate); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java deleted file mode 100644 index e9f9fbd69..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBakedQuad.java +++ /dev/null @@ -1,102 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.core.pipeline; - -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.Direction; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.COLOR_INDEX; -import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.LIGHT_INDEX; -import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.NORMAL_INDEX; -import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.POSITION_INDEX; -import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.TEXTURE_INDEX; -import static me.jellysquid.mods.sodium.client.util.ModelQuadUtil.vertexOffset; - -@Mixin(BakedQuad.class) -public class MixinBakedQuad implements ModelQuadView { - @Shadow - @Final - protected int[] vertexData; - - @Shadow - @Final - protected Sprite sprite; - - @Shadow - @Final - protected int colorIndex; - - private int cachedFlags; - - @Inject(method = "", at = @At("RETURN")) - private void init(int[] vertexData, int colorIndex, Direction face, Sprite sprite, boolean shade, CallbackInfo ci) { - this.cachedFlags = ModelQuadFlags.getQuadFlags((BakedQuad) (Object) this); - } - - @Override - public float getX(int idx) { - return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + POSITION_INDEX]); - } - - @Override - public float getY(int idx) { - return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + POSITION_INDEX + 1]); - } - - @Override - public float getZ(int idx) { - return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + POSITION_INDEX + 2]); - } - - @Override - public int getColor(int idx) { - if(vertexOffset(idx) + COLOR_INDEX < vertexData.length) { - return this.vertexData[vertexOffset(idx) + COLOR_INDEX]; - } else - { - return vertexData.length; - } - } - - @Override - public Sprite rubidium$getSprite() { - return this.sprite; - } - - @Override - public float getTexU(int idx) { - return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + TEXTURE_INDEX]); - } - - @Override - public float getTexV(int idx) { - return Float.intBitsToFloat(this.vertexData[vertexOffset(idx) + TEXTURE_INDEX + 1]); - } - - @Override - public int getFlags() { - return this.cachedFlags; - } - - @Override - public int getLight(int idx) { - return this.vertexData[vertexOffset(idx) + LIGHT_INDEX]; - } - - @Override - public int getNormal(int idx) { - return this.vertexData[vertexOffset(idx) + NORMAL_INDEX]; - } - - @Override - public int getColorIndex() { - return this.colorIndex; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBufferBuilder.java deleted file mode 100644 index 6494a8cb7..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinBufferBuilder.java +++ /dev/null @@ -1,117 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.core.pipeline; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; -import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; -import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; -import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; -import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; -import me.jellysquid.mods.sodium.client.model.vertex.type.VertexType; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.util.GlAllocationUtils; -import org.apache.logging.log4j.Logger; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.nio.Buffer; -import java.nio.ByteBuffer; - -@Mixin(BufferBuilder.class) -public abstract class MixinBufferBuilder implements VertexBufferView, VertexDrain { - @Shadow - private int elementOffset; - - @Shadow - private ByteBuffer buffer; - - @Shadow - @Final - private static Logger LOGGER; - - @Shadow - private static int roundBufferSize(int amount) { - throw new UnsupportedOperationException(); - } - - @Shadow - private VertexFormat format; - - @Shadow - private int vertexCount; - - @Redirect(method = "popData", at = @At(value = "INVOKE", target = "Ljava/nio/Buffer;limit(I)Ljava/nio/Buffer;")) - public Buffer debugGetNextBuffer(Buffer buffer, int newLimit) { - ensureBufferCapacity(newLimit); - buffer = (Buffer) this.buffer; - buffer.limit(newLimit); - return buffer; - } - - @Override - public boolean ensureBufferCapacity(int bytes) { - if(format == null) - return false; - - // Ensure that there is always space for 1 more vertex; see BufferBuilder.next() - bytes += format.getVertexSize(); - - if (this.elementOffset + bytes <= this.buffer.capacity()) { - return false; - } - - int newSize = this.buffer.capacity() + roundBufferSize(bytes); - - LOGGER.debug("Needed to grow BufferBuilder buffer: Old size {} bytes, new size {} bytes.", this.buffer.capacity(), newSize); - - this.buffer.position(0); - - ByteBuffer byteBuffer = GlAllocationUtils.allocateByteBuffer(newSize); - byteBuffer.put(this.buffer); - byteBuffer.rewind(); - - this.buffer = byteBuffer; - - return true; - } - - @Override - public ByteBuffer getDirectBuffer() { - return this.buffer; - } - - @Override - public int getWriterPosition() { - return this.elementOffset; - } - - @Override - public BufferVertexFormat getVertexFormat() { - return BufferVertexFormat.from(this.format); - } - - @Override - public void flush(int vertexCount, BufferVertexFormat format) { - if (BufferVertexFormat.from(this.format) != format) { - throw new IllegalStateException("Mis-matched vertex format (expected: [" + format + "], currently using: [" + this.format + "])"); - } - - this.vertexCount += vertexCount; - this.elementOffset += vertexCount * format.getStride(); - } - - @Override - public T createSink(VertexType factory) { - BlittableVertexType blittable = factory.asBlittable(); - - if (blittable != null && blittable.getBufferVertexFormat() == this.getVertexFormat()) { - return blittable.createBufferWriter(this, SodiumClientMod.isDirectMemoryAccessEnabled()); - } - - return factory.createFallbackWriter((VertexConsumer) this); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexConsumer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexConsumer.java deleted file mode 100644 index 823cb5f2e..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexConsumer.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.core.pipeline; - -import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; -import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; -import me.jellysquid.mods.sodium.client.model.vertex.type.VertexType; -import net.minecraft.client.render.VertexConsumer; -import org.spongepowered.asm.mixin.Mixin; - -@Mixin(VertexConsumer.class) -public interface MixinVertexConsumer extends VertexDrain { - @Override - default T createSink(VertexType factory) { - return factory.createFallbackWriter((VertexConsumer) this); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexFormat.java deleted file mode 100644 index a9766681e..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/core/pipeline/MixinVertexFormat.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.core.pipeline; - -import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; -import net.minecraft.client.render.VertexFormat; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(VertexFormat.class) -public abstract class MixinVertexFormat implements BufferVertexFormat { - @Shadow - public abstract int getVertexSize(); - - @Override - public int getStride() { - return this.getVertexSize(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinBlockModelRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinBlockModelRenderer.java deleted file mode 100644 index 5dbc91252..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinBlockModelRenderer.java +++ /dev/null @@ -1,105 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.block; - -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; -import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; -import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; -import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.block.BlockModelRenderer; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.BlockRenderView; -import net.minecraftforge.client.model.data.EmptyModelData; -import net.minecraftforge.client.model.data.IModelData; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.List; -import java.util.Random; - -@Mixin(BlockModelRenderer.class) -public class MixinBlockModelRenderer { - private final XoRoShiRoRandom random = new XoRoShiRoRandom(); - - @Inject(method = "render(Lnet/minecraft/world/BlockRenderView;Lnet/minecraft/client/render/model/BakedModel;Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;ZLjava/util/Random;JI)Z", at = @At("HEAD"), cancellable = true) - private void preRenderBlockInWorld(BlockRenderView world, BakedModel model, BlockState state, BlockPos pos, MatrixStack matrixStack, VertexConsumer consumer, boolean cull, Random rand, long seed, int int_1, CallbackInfoReturnable cir) { -// GlobalRenderContext renderer = GlobalRenderContext.getInstance(world); -// BlockRenderer blockRenderer = renderer.getBlockRenderer(); -// -// boolean ret = blockRenderer.renderModel(world, state, pos, model, new FallbackChunkModelBuffers(consumer, matrixStack), cull, seed); -// -// cir.setReturnValue(ret); - } - - /** - * @reason Use optimized vertex writer intrinsics, avoid allocations - * @author JellySquid - */ - @Overwrite - public void renderModel(MatrixStack.Entry entry, VertexConsumer vertexConsumer, BlockState blockState, BakedModel bakedModel, float red, float green, float blue, int light, int overlay, IModelData modelData) { - QuadVertexSink drain = VertexDrain.of(vertexConsumer) - .createSink(VanillaVertexTypes.QUADS); - XoRoShiRoRandom random = this.random; - - if (modelData == null) { - modelData = EmptyModelData.INSTANCE; - } - - // Clamp color ranges - red = MathHelper.clamp(red, 0.0F, 1.0F); - green = MathHelper.clamp(green, 0.0F, 1.0F); - blue = MathHelper.clamp(blue, 0.0F, 1.0F); - - int defaultColor = ColorABGR.pack(red, green, blue, 1.0F); - - for (Direction direction : DirectionUtil.ALL_DIRECTIONS) { - List quads = bakedModel.getQuads(blockState, direction, random.setSeedAndReturn(42L), modelData); - - if (!quads.isEmpty()) { - renderQuad(entry, drain, defaultColor, quads, light, overlay); - } - } - - List quads = bakedModel.getQuads(blockState, null, random.setSeedAndReturn(42L), modelData); - - if (!quads.isEmpty()) { - renderQuad(entry, drain, defaultColor, quads, light, overlay); - } - - drain.flush(); - } - - private static void renderQuad(MatrixStack.Entry entry, QuadVertexSink drain, int defaultColor, List list, int light, int overlay) { - if (list.isEmpty()) { - return; - } - - drain.ensureCapacity(list.size() * 4); - - for (BakedQuad bakedQuad : list) { - int color = bakedQuad.hasColor() ? defaultColor : 0xFFFFFFFF; - - ModelQuadView quad = ((ModelQuadView) bakedQuad); - - for (int i = 0; i < 4; i++) { - drain.writeQuad(entry, quad.getX(i), quad.getY(i), quad.getZ(i), color, quad.getTexU(i), quad.getTexV(i), - light, overlay, ModelQuadUtil.getFacingNormal(bakedQuad.getFace(), quad.getNormal(i))); - } - - SpriteUtil.markSpriteActive(quad.rubidium$getSprite()); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java deleted file mode 100644 index 3709ab2af..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java +++ /dev/null @@ -1,27 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.block; - -import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheShared; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.LightmapTextureManager; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Matrix4f; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(WorldRenderer.class) -public class MixinWorldRenderer { - /** - * Reset any global cached state before rendering a frame. This will hopefully ensure that any world state that has - * changed is reflected in vanilla-style rendering. - */ - @Inject(method = "render", at = @At("HEAD")) - private void reset(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, - GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, - CallbackInfo ci) { - ChunkRenderCacheShared.resetCaches(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinBufferBuilder.java deleted file mode 100644 index 90e5a686a..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinBufferBuilder.java +++ /dev/null @@ -1,56 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.buffer_builder.fast_advance; - -import me.jellysquid.mods.sodium.client.buffer.ExtendedVertexFormat; -import net.minecraft.client.render.*; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(BufferBuilder.class) -public abstract class MixinBufferBuilder extends FixedColorVertexConsumer implements BufferVertexConsumer { - @Shadow - private VertexFormatElement currentElement; - - @Shadow - private int elementOffset; - - @Shadow - private int currentElementId; - - private ExtendedVertexFormat.Element[] embeddium$vertexFormatExtendedElements; - private ExtendedVertexFormat.Element embeddium$currentExtendedElement; - - @Inject(method = "method_23918", - at = @At( - value = "FIELD", - target = "Lnet/minecraft/client/render/BufferBuilder;format:Lnet/minecraft/client/render/VertexFormat;", - opcode = Opcodes.PUTFIELD - ) - ) - private void onFormatChanged(VertexFormat format, CallbackInfo ci) { - embeddium$vertexFormatExtendedElements = ((ExtendedVertexFormat) format).embeddium$getExtendedElements(); - embeddium$currentExtendedElement = embeddium$vertexFormatExtendedElements[0]; - } - - /** - * @author JellySquid - * @reason Remove modulo operations, recursion, and list dereference - */ - @Override - @Overwrite - public void nextElement() { - if ((currentElementId += embeddium$currentExtendedElement.increment) >= embeddium$vertexFormatExtendedElements.length) - currentElementId -= embeddium$vertexFormatExtendedElements.length; - elementOffset += embeddium$currentExtendedElement.byteLength; - embeddium$currentExtendedElement = embeddium$vertexFormatExtendedElements[currentElementId]; - currentElement = embeddium$currentExtendedElement.actual; - - if (this.colorFixed && this.currentElement.getType() == VertexFormatElement.Type.COLOR) { - BufferVertexConsumer.super.color(this.fixedRed, this.fixedGreen, this.fixedBlue, this.fixedAlpha); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinVertexFormat.java deleted file mode 100644 index 62412dd27..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_advance/MixinVertexFormat.java +++ /dev/null @@ -1,55 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.buffer_builder.fast_advance; - -import com.google.common.collect.ImmutableList; -import me.jellysquid.mods.sodium.client.buffer.ExtendedVertexFormat; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormatElement; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -/** - * Thanks to Maximum for this optimization, taken from Fireblanket. - */ -@Mixin(VertexFormat.class) -public class MixinVertexFormat implements ExtendedVertexFormat { - @Shadow - @Final - private ImmutableList elements; - - private Element[] embeddium$extendedElements; - - @Inject(method = "", at = @At("RETURN")) - private void embeddium$createElementArray(ImmutableList immutableList, CallbackInfo ci) { - this.embeddium$extendedElements = new Element[this.elements.size()]; - - if (this.elements.size() == 0) - return; // prevent crash with mods that create empty VertexFormats - - VertexFormatElement currentElement = elements.get(0); - int id = 0; - for (VertexFormatElement element : this.elements) { - if (element.getType() == VertexFormatElement.Type.PADDING) continue; - - int oldId = id; - int byteLength = 0; - - do { - if (++id >= this.embeddium$extendedElements.length) - id -= this.embeddium$extendedElements.length; - byteLength += currentElement.getByteLength(); - currentElement = this.elements.get(id); - } while (currentElement.getType() == VertexFormatElement.Type.PADDING); - - this.embeddium$extendedElements[oldId] = new Element(element, id - oldId, byteLength); - } - } - - @Override - public Element[] embeddium$getExtendedElements() { - return this.embeddium$extendedElements; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_sort/MixinBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_sort/MixinBufferBuilder.java deleted file mode 100644 index 1c4e31a37..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/fast_sort/MixinBufferBuilder.java +++ /dev/null @@ -1,180 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.buffer_builder.fast_sort; - -import com.google.common.primitives.Floats; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.VertexFormat; -import org.lwjgl.system.MemoryStack; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.util.Arrays; -import java.util.BitSet; - -@Mixin(BufferBuilder.class) -public class MixinBufferBuilder { - @Shadow - private ByteBuffer buffer; - - @Shadow - private int vertexCount; - - @Shadow - private VertexFormat format; - - @Shadow - private int buildStart; - - /** - * @reason Reduce allocations, use stack allocations, avoid unnecessary math and pointer bumping, inline comparators - * @author JellySquid - */ - @Overwrite - public void sortQuads(float cameraX, float cameraY, float cameraZ) { - this.buffer.clear(); - FloatBuffer floatBuffer = this.buffer.asFloatBuffer(); - - int vertexStride = this.format.getVertexSize(); - int quadStride = this.format.getVertexSizeInteger() * 4; - - int quadStart = this.buildStart / 4; - int quadCount = this.vertexCount / 4; - int vertexSizeInteger = this.format.getVertexSizeInteger(); - - float[] distanceArray = new float[quadCount]; - int[] indicesArray = new int[quadCount]; - - for (int quadIdx = 0; quadIdx < quadCount; ++quadIdx) { - distanceArray[quadIdx] = getDistanceSq(floatBuffer, cameraX, cameraY, cameraZ, vertexSizeInteger, quadStart + (quadIdx * vertexStride)); - indicesArray[quadIdx] = quadIdx; - } - - mergeSort(indicesArray, distanceArray); - - BitSet bits = new BitSet(); - - try (MemoryStack stack = MemoryStack.stackPush()) { - FloatBuffer tmp = stack.mallocFloat(vertexSizeInteger * 4); - - for (int l = bits.nextClearBit(0); l < indicesArray.length; l = bits.nextClearBit(l + 1)) { - int m = indicesArray[l]; - - if (m != l) { - sliceQuad(floatBuffer, m, quadStride, quadStart); - tmp.clear(); - tmp.put(floatBuffer); - - int n = m; - - for (int o = indicesArray[m]; n != l; o = indicesArray[o]) { - sliceQuad(floatBuffer, o, quadStride, quadStart); - FloatBuffer floatBuffer3 = floatBuffer.slice(); - - sliceQuad(floatBuffer, n, quadStride, quadStart); - floatBuffer.put(floatBuffer3); - - bits.set(n); - n = o; - } - - sliceQuad(floatBuffer, l, quadStride, quadStart); - tmp.flip(); - - floatBuffer.put(tmp); - } - - bits.set(l); - } - } - } - - private static void mergeSort(int[] indicesArray, float[] distanceArray) { - mergeSort(indicesArray, 0, indicesArray.length, distanceArray, Arrays.copyOf(indicesArray, indicesArray.length)); - } - - private static void sliceQuad(FloatBuffer floatBuffer, int quadIdx, int quadStride, int quadStart) { - int base = quadStart + (quadIdx * quadStride); - - floatBuffer.limit(base + quadStride); - floatBuffer.position(base); - } - - private static float getDistanceSq(FloatBuffer buffer, float xCenter, float yCenter, float zCenter, int stride, int start) { - int vertexBase = start; - float x1 = buffer.get(vertexBase); - float y1 = buffer.get(vertexBase + 1); - float z1 = buffer.get(vertexBase + 2); - - vertexBase += stride; - float x2 = buffer.get(vertexBase); - float y2 = buffer.get(vertexBase + 1); - float z2 = buffer.get(vertexBase + 2); - - vertexBase += stride; - float x3 = buffer.get(vertexBase); - float y3 = buffer.get(vertexBase + 1); - float z3 = buffer.get(vertexBase + 2); - - vertexBase += stride; - float x4 = buffer.get(vertexBase); - float y4 = buffer.get(vertexBase + 1); - float z4 = buffer.get(vertexBase + 2); - - float xDist = ((x1 + x2 + x3 + x4) * 0.25F) - xCenter; - float yDist = ((y1 + y2 + y3 + y4) * 0.25F) - yCenter; - float zDist = ((z1 + z2 + z3 + z4) * 0.25F) - zCenter; - - return (xDist * xDist) + (yDist * yDist) + (zDist * zDist); - } - - private static void mergeSort(final int[] a, final int from, final int to, float[] dist, final int[] supp) { - int len = to - from; - - // Insertion sort on smallest arrays - if (len < 16) { - insertionSort(a, from, to, dist); - return; - } - - // Recursively sort halves of a into supp - final int mid = (from + to) >>> 1; - mergeSort(supp, from, mid, dist, a); - mergeSort(supp, mid, to, dist, a); - - // If list is already sorted, just copy from supp to a. This is an - // optimization that results in faster sorts for nearly ordered lists. - if (Floats.compare(dist[supp[mid]], dist[supp[mid - 1]]) <= 0) { - System.arraycopy(supp, from, a, from, len); - return; - } - - // Merge sorted halves (now in supp) into a - for (int i = from, p = from, q = mid; i < to; i++) { - if (q >= to || p < mid && Floats.compare(dist[supp[q]], dist[supp[p]]) <= 0) { - a[i] = supp[p++]; - } else { - a[i] = supp[q++]; - } - } - } - - private static void insertionSort(final int[] a, final int from, final int to, final float[] dist) { - for (int i = from; ++i < to; ) { - int t = a[i]; - int j = i; - - for (int u = a[j - 1]; Floats.compare(dist[u], dist[t]) < 0; u = a[--j - 1]) { - a[j] = u; - if (from == j - 1) { - --j; - break; - } - } - - a[j] = t; - } - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinBufferBuilder.java deleted file mode 100644 index e6a084752..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinBufferBuilder.java +++ /dev/null @@ -1,94 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.buffer_builder.intrinsics; - -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; -import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; -import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; -import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import me.jellysquid.mods.sodium.client.util.color.ColorU8; -import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.FixedColorVertexConsumer; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Matrix3f; -import net.minecraft.util.math.Matrix4f; -import net.minecraft.util.math.Vector4f; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(BufferBuilder.class) -public abstract class MixinBufferBuilder extends FixedColorVertexConsumer { - @Shadow - private boolean field_227826_s_; // is baked quad format - - @Override - public void quad(MatrixStack.Entry matrices, BakedQuad quad, float[] brightnessTable, float r, float g, float b, int[] light, int overlay, boolean colorize) { - if (!this.field_227826_s_) { - super.quad(matrices, quad, brightnessTable, r, g, b, light, overlay, colorize); - - return; - } - - if (this.colorFixed) { - throw new IllegalStateException(); - } - - ModelQuadView quadView = (ModelQuadView) quad; - - Matrix4f modelMatrix = matrices.getModel(); - Matrix3f normalMatrix = matrices.getNormal(); - - int norm = MatrixUtil.computeNormal(normalMatrix, quad.getFace()); - - QuadVertexSink drain = VertexDrain.of(this) - .createSink(VanillaVertexTypes.QUADS); - drain.ensureCapacity(4); - - for (int i = 0; i < 4; i++) { - float x = quadView.getX(i); - float y = quadView.getY(i); - float z = quadView.getZ(i); - - float fR; - float fG; - float fB; - - float brightness = brightnessTable[i]; - - if (colorize) { - int color = quadView.getColor(i); - - float oR = ColorU8.normalize(ColorABGR.unpackRed(color)); - float oG = ColorU8.normalize(ColorABGR.unpackGreen(color)); - float oB = ColorU8.normalize(ColorABGR.unpackBlue(color)); - - fR = oR * brightness * r; - fG = oG * brightness * g; - fB = oB * brightness * b; - } else { - fR = brightness * r; - fG = brightness * g; - fB = brightness * b; - } - - float u = quadView.getTexU(i); - float v = quadView.getTexV(i); - - int color = ColorABGR.pack(fR, fG, fB, 1.0F); - - Vector4f pos = new Vector4f(x, y, z, 1.0F); - pos.transform(modelMatrix); - - int bakedNorm = quadView.getNormal(i); - if(ModelQuadUtil.hasNormal(bakedNorm)) { - norm = MatrixUtil.transformPackedNormal(bakedNorm, normalMatrix); - } - - drain.writeQuad(pos.getX(), pos.getY(), pos.getZ(), color, u, v, ModelQuadUtil.mergeBakedLight(quadView.getLight(i), light[i]), overlay, norm); - } - - drain.flush(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinSpriteTexturedVertexConsumer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinSpriteTexturedVertexConsumer.java deleted file mode 100644 index bd1815ff7..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinSpriteTexturedVertexConsumer.java +++ /dev/null @@ -1,41 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.buffer_builder.intrinsics; - -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; -import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; -import me.jellysquid.mods.sodium.client.model.vertex.transformers.SpriteTexturedVertexTransformer; -import me.jellysquid.mods.sodium.client.model.vertex.type.VertexType; -import net.minecraft.client.render.SpriteTexturedVertexConsumer; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.texture.Sprite; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(SpriteTexturedVertexConsumer.class) -public abstract class MixinSpriteTexturedVertexConsumer implements VertexDrain { - @Shadow - @Final - private Sprite sprite; - - @Shadow - @Final - private VertexConsumer parent; - - @SuppressWarnings("unchecked") - @Override - public T createSink(VertexType type) { - if (type == VanillaVertexTypes.QUADS) { - return (T) new SpriteTexturedVertexTransformer.Quad(VertexDrain.of(this.parent) - .createSink(VanillaVertexTypes.QUADS), this.sprite); - } else if (type == VanillaVertexTypes.PARTICLES) { - return (T) new SpriteTexturedVertexTransformer.Particle(VertexDrain.of(this.parent) - .createSink(VanillaVertexTypes.PARTICLES), this.sprite); - } else if (type == VanillaVertexTypes.GLYPHS) { - return (T) new SpriteTexturedVertexTransformer.Glyph(VertexDrain.of(this.parent) - .createSink(VanillaVertexTypes.GLYPHS), this.sprite); - } - - return type.createFallbackWriter((VertexConsumer) this); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinWorldRenderer.java deleted file mode 100644 index 26c829621..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/buffer_builder/intrinsics/MixinWorldRenderer.java +++ /dev/null @@ -1,114 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.buffer_builder.intrinsics; - -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; -import me.jellysquid.mods.sodium.client.model.vertex.formats.line.LineVertexSink; -import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; -import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Matrix4f; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -@Mixin(WorldRenderer.class) -public class MixinWorldRenderer { - /** - * @author JellySquid - * @reason Use intrinsics where possible to speed up vertex writing - */ - @Overwrite - public static void drawBox(MatrixStack matrices, VertexConsumer vertexConsumer, double x1, double y1, double z1, - double x2, double y2, double z2, float red, float green, float blue, float alpha, - float xAxisRed, float yAxisGreen, float zAxisBlue) { - Matrix4f model = matrices.peek().getModel(); - - float x1f = (float) x1; - float y1f = (float) y1; - float z1f = (float) z1; - float x2f = (float) x2; - float y2f = (float) y2; - float z2f = (float) z2; - - int color = ColorABGR.pack(red, green, blue, alpha); - - Matrix4fExtended matrixExt = MatrixUtil.getExtendedMatrix(model); - - float v1x = matrixExt.transformVecX(x1f, y1f, z1f); - float v1y = matrixExt.transformVecY(x1f, y1f, z1f); - float v1z = matrixExt.transformVecZ(x1f, y1f, z1f); - - float v2x = matrixExt.transformVecX(x2f, y1f, z1f); - float v2y = matrixExt.transformVecY(x2f, y1f, z1f); - float v2z = matrixExt.transformVecZ(x2f, y1f, z1f); - - float v3x = matrixExt.transformVecX(x1f, y2f, z1f); - float v3y = matrixExt.transformVecY(x1f, y2f, z1f); - float v3z = matrixExt.transformVecZ(x1f, y2f, z1f); - - float v4x = matrixExt.transformVecX(x1f, y1f, z2f); - float v4y = matrixExt.transformVecY(x1f, y1f, z2f); - float v4z = matrixExt.transformVecZ(x1f, y1f, z2f); - - float v5x = matrixExt.transformVecX(x2f, y2f, z1f); - float v5y = matrixExt.transformVecY(x2f, y2f, z1f); - float v5z = matrixExt.transformVecZ(x2f, y2f, z1f); - - float v6x = matrixExt.transformVecX(x1f, y2f, z2f); - float v6y = matrixExt.transformVecY(x1f, y2f, z2f); - float v6z = matrixExt.transformVecZ(x1f, y2f, z2f); - - float v7x = matrixExt.transformVecX(x2f, y1f, z2f); - float v7y = matrixExt.transformVecY(x2f, y1f, z2f); - float v7z = matrixExt.transformVecZ(x2f, y1f, z2f); - - float v8x = matrixExt.transformVecX(x2f, y2f, z2f); - float v8y = matrixExt.transformVecY(x2f, y2f, z2f); - float v8z = matrixExt.transformVecZ(x2f, y2f, z2f); - - LineVertexSink lines = VertexDrain.of(vertexConsumer) - .createSink(VanillaVertexTypes.LINES); - lines.ensureCapacity(24); - - lines.vertexLine(v1x, v1y, v1z, red, yAxisGreen, zAxisBlue, alpha); - lines.vertexLine(v2x, v2y, v2z, red, yAxisGreen, zAxisBlue, alpha); - - lines.vertexLine(v1x, v1y, v1z, xAxisRed, green, zAxisBlue, alpha); - lines.vertexLine(v3x, v3y, v3z, xAxisRed, green, zAxisBlue, alpha); - - lines.vertexLine(v1x, v1y, v1z, xAxisRed, yAxisGreen, blue, alpha); - lines.vertexLine(v4x, v4y, v4z, xAxisRed, yAxisGreen, blue, alpha); - - lines.vertexLine(v2x, v2y, v2z, color); - lines.vertexLine(v5x, v5y, v5z, color); - - lines.vertexLine(v5x, v5y, v5z, color); - lines.vertexLine(v3x, v3y, v3z, color); - - lines.vertexLine(v3x, v3y, v3z, color); - lines.vertexLine(v6x, v6y, v6z, color); - - lines.vertexLine(v6x, v6y, v6z, color); - lines.vertexLine(v4x, v4y, v4z, color); - - lines.vertexLine(v4x, v4y, v4z, color); - lines.vertexLine(v7x, v7y, v7z, color); - - lines.vertexLine(v7x, v7y, v7z, color); - lines.vertexLine(v2x, v2y, v2z, color); - - lines.vertexLine(v6x, v6y, v6z, color); - lines.vertexLine(v8x, v8y, v8z, color); - - lines.vertexLine(v7x, v7y, v7z, color); - lines.vertexLine(v8x, v8y, v8z, color); - - lines.vertexLine(v5x, v5y, v5z, color); - lines.vertexLine(v8x, v8y, v8z, color); - - lines.flush(); - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinChunkBuilder.java deleted file mode 100644 index d0d36f8c8..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinChunkBuilder.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; - -import net.minecraft.client.render.chunk.ChunkBuilder; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; - -@Mixin(ChunkBuilder.class) -public class MixinChunkBuilder { - @ModifyVariable(method = "(Lnet/minecraft/world/World;Lnet/minecraft/client/render/WorldRenderer;Ljava/util/concurrent/Executor;ZLnet/minecraft/client/render/chunk/BlockBufferBuilderStorage;I)V", index = 9, at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayListWithExpectedSize(I)Ljava/util/ArrayList;", remap = false)) - private int modifyThreadPoolSize(int prev) { - // Do not allow any resources to be allocated - return 0; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientChunkManager.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientChunkManager.java deleted file mode 100644 index 382b023e2..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientChunkManager.java +++ /dev/null @@ -1,143 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; - -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; -import me.jellysquid.mods.sodium.client.world.ChunkStatusListenerManager; -import net.minecraft.client.world.ClientChunkManager; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.biome.source.BiomeArray; -import net.minecraft.world.chunk.ChunkStatus; -import net.minecraft.world.chunk.WorldChunk; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.concurrent.atomic.AtomicReferenceArray; -import java.util.function.BooleanSupplier; - -@Mixin(ClientChunkManager.class) -public abstract class MixinClientChunkManager implements ChunkStatusListenerManager { - @Shadow - @Nullable - public abstract WorldChunk getChunk(int i, int j, ChunkStatus chunkStatus, boolean bl); - - private final LongOpenHashSet loadedChunks = new LongOpenHashSet(); - private boolean needsTrackingUpdate = false; - - private ChunkStatusListener listener; - - @Inject(method = "loadChunkFromPacket", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;resetChunkColor(II)V", shift = At.Shift.AFTER)) - private void afterLoadChunkFromPacket(int x, int z, BiomeArray biomes, PacketByteBuf buf, NbtCompound tag, int verticalStripBitmask, boolean complete, CallbackInfoReturnable cir) { - if (this.listener != null) { - this.listener.onChunkAdded(x, z); - this.loadedChunks.add(ChunkPos.toLong(x, z)); - } - } - - @Inject(method = "unload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientChunkManager$ClientChunkMap;compareAndSet(ILnet/minecraft/world/chunk/WorldChunk;Lnet/minecraft/world/chunk/WorldChunk;)Lnet/minecraft/world/chunk/WorldChunk;", shift = At.Shift.AFTER)) - private void afterUnloadChunk(int x, int z, CallbackInfo ci) { - if (this.listener != null) { - this.listener.onChunkRemoved(x, z); - this.loadedChunks.remove(ChunkPos.toLong(x, z)); - } - } - - @Inject(method = "tick", at = @At("RETURN")) - private void afterTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { - if (!this.needsTrackingUpdate) { - return; - } - - LongIterator it = this.loadedChunks.iterator(); - - while (it.hasNext()) { - long pos = it.nextLong(); - - int x = ChunkPos.getPackedX(pos); - int z = ChunkPos.getPackedZ(pos); - - if (this.getChunk(x, z, ChunkStatus.FULL, false) == null) { - it.remove(); - - if (this.listener != null) { - this.listener.onChunkRemoved(x, z); - } - } - } - - this.needsTrackingUpdate = false; - } - - @Inject(method = "setChunkMapCenter(II)V", at = @At("RETURN")) - private void afterChunkMapCenterChanged(int x, int z, CallbackInfo ci) { - this.needsTrackingUpdate = true; - } - - @Inject(method = "updateLoadDistance", - at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/world/ClientChunkManager$ClientChunkMap;set(ILnet/minecraft/world/chunk/WorldChunk;)V", - shift = At.Shift.AFTER)) - private void afterLoadDistanceChanged(int loadDistance, CallbackInfo ci) { - this.needsTrackingUpdate = true; - } - - @Override - public void setListener(ChunkStatusListener listener) { - this.listener = listener; - } - - @Mixin(targets = "net/minecraft/client/world/ClientChunkManager$ClientChunkMap") - public static class MixinClientChunkMap { - @Mutable - @Shadow - @Final - private AtomicReferenceArray chunks; - - @Mutable - @Shadow - @Final - private int diameter; - - @Mutable - @Shadow - @Final - private int radius; - - private int factor; - - @Inject(method = "", at = @At("RETURN")) - private void reinit(ClientChunkManager outer, int loadDistance, CallbackInfo ci) { - // This re-initialization is a bit expensive on memory, but it only happens when either the world is - // switched or the render distance is changed; - this.radius = loadDistance; - - // Make the diameter a power-of-two so we can exploit bit-wise math when computing indices - this.diameter = MathHelper.smallestEncompassingPowerOfTwo(loadDistance * 2 + 1); - - // The factor is used as a bit mask to replace the modulo in getIndex - this.factor = this.diameter - 1; - - this.chunks = new AtomicReferenceArray<>(this.diameter * this.diameter); - } - - /** - * @reason Avoid expensive modulo - * @author JellySquid - */ - @Overwrite - private int getIndex(int chunkX, int chunkZ) { - return (chunkZ & this.factor) * this.diameter + (chunkX & this.factor); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientWorld.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientWorld.java deleted file mode 100644 index b0e4f6161..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinClientWorld.java +++ /dev/null @@ -1,34 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; - -import me.jellysquid.mods.sodium.client.world.ClientWorldExtended; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.profiler.Profiler; -import net.minecraft.util.registry.RegistryKey; -import net.minecraft.world.World; -import net.minecraft.world.dimension.DimensionType; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.function.Supplier; - -@Mixin(ClientWorld.class) -public abstract class MixinClientWorld implements ClientWorldExtended { - private long biomeSeed; - - /** - * Captures the biome generation seed so that our own caches can make use of it. - */ - @Inject(method = "", at = @At("RETURN")) - private void init(ClientPlayNetworkHandler clientPlayNetworkHandler, ClientWorld.Properties properties, RegistryKey registryKey, DimensionType dimensionType, int i, Supplier supplier, WorldRenderer worldRenderer, boolean bl, long seed, CallbackInfo ci) { - this.biomeSeed = seed; - } - - @Override - public long getBiomeSeed() { - return this.biomeSeed; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPackedIntegerArray.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPackedIntegerArray.java deleted file mode 100644 index 63ecd9400..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPackedIntegerArray.java +++ /dev/null @@ -1,49 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; - -import me.jellysquid.mods.sodium.client.world.cloned.PackedIntegerArrayExtended; -import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; -import net.minecraft.util.collection.PackedIntegerArray; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(PackedIntegerArray.class) -public class MixinPackedIntegerArray implements PackedIntegerArrayExtended { - @Shadow - @Final - private long[] storage; - - @Shadow(remap = false) - @Final - private int field_232982_f_; - - @Shadow - @Final - private long maxValue; - - @Shadow - @Final - private int elementBits; - - @Shadow - @Final - private int size; - - @Override - public void copyUsingPalette(T[] out, ClonedPalette palette) { - int idx = 0; - - for (long word : this.storage) { - long l = word; - - for (int j = 0; j < this.field_232982_f_; ++j) { - out[idx] = palette.get((int) (l & this.maxValue)); - l >>= this.elementBits; - - if (++idx >= this.size) { - return; - } - } - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPalettedContainer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPalettedContainer.java deleted file mode 100644 index a34a4cdce..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinPalettedContainer.java +++ /dev/null @@ -1,45 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; - -import me.jellysquid.mods.sodium.client.world.cloned.PalettedContainerExtended; -import net.minecraft.util.collection.PackedIntegerArray; -import net.minecraft.world.chunk.Palette; -import net.minecraft.world.chunk.PalettedContainer; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(PalettedContainer.class) -public class MixinPalettedContainer implements PalettedContainerExtended { - @Shadow - private int paletteSize; - - @Shadow - protected PackedIntegerArray data; - - @Shadow - private Palette palette; - - @Shadow - @Final - private T defaultValue; - - @Override - public PackedIntegerArray getDataArray() { - return this.data; - } - - @Override - public Palette getPalette() { - return this.palette; - } - - @Override - public T getDefaultValue() { - return this.defaultValue; - } - - @Override - public int getPaletteSize() { - return this.paletteSize; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinRenderLayer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinRenderLayer.java deleted file mode 100644 index 4ea0e28a6..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinRenderLayer.java +++ /dev/null @@ -1,24 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; - -import com.google.common.collect.ImmutableList; -import net.minecraft.client.render.RenderLayer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Unique; - -import java.util.List; - -@Mixin(RenderLayer.class) -public class MixinRenderLayer { - @Unique - private static final List embeddium$blockLayers = ImmutableList.of(RenderLayer.getSolid(), RenderLayer.getCutoutMipped(), RenderLayer.getCutout(), RenderLayer.getTranslucent(), RenderLayer.getTripwire()); - - /** - * @author Kasualix - * @reason Don't create an immutableList every time this is called. - */ - @Overwrite - public static List getBlockLayers() { - return embeddium$blockLayers; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java deleted file mode 100644 index f4cb572b4..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java +++ /dev/null @@ -1,171 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.chunk_rendering; - -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; -import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.option.GameOptions; -import net.minecraft.client.render.*; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Matrix4f; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.SortedSet; - -@Mixin(WorldRenderer.class) -public abstract class MixinWorldRenderer { - @Shadow - @Final - private BufferBuilderStorage bufferBuilders; - - @Shadow - @Final - private Long2ObjectMap> blockBreakingProgressions; - - private SodiumWorldRenderer renderer; - - @Redirect(method = "reload()V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/option/GameOptions;viewDistance:I", ordinal = 1)) - private int nullifyBuiltChunkStorage(GameOptions options) { - // Do not allow any resources to be allocated - return 0; - } - - @Inject(method = "", at = @At("RETURN")) - private void init(MinecraftClient client, BufferBuilderStorage bufferBuilders, CallbackInfo ci) { - this.renderer = SodiumWorldRenderer.create(); - } - - @Inject(method = "setWorld", at = @At("RETURN")) - private void onWorldChanged(ClientWorld world, CallbackInfo ci) { - RenderDevice.enterManagedCode(); - - try { - this.renderer.setWorld(world); - } finally { - RenderDevice.exitManagedCode(); - } - } - - /** - * @reason Redirect to our renderer - * @author JellySquid - */ - @Overwrite - public int getCompletedChunkCount() { - return this.renderer.getVisibleChunkCount(); - } - - /** - * @reason Redirect the check to our renderer - * @author JellySquid - */ - @Overwrite - public boolean isTerrainRenderComplete() { - return this.renderer.isTerrainRenderComplete(); - } - - @Inject(method = "scheduleTerrainUpdate", at = @At("RETURN")) - private void onTerrainUpdateScheduled(CallbackInfo ci) { - this.renderer.scheduleTerrainUpdate(); - } - - /** - * @reason Redirect the chunk layer render passes to our renderer - * @author JellySquid - */ - @Overwrite - private void renderLayer(RenderLayer renderLayer, MatrixStack matrixStack, double x, double y, double z) { - RenderDevice.enterManagedCode(); - - try { - this.renderer.drawChunkLayer(renderLayer, matrixStack, x, y, z); - } finally { - RenderDevice.exitManagedCode(); - } - } - - /** - * @reason Redirect the terrain setup phase to our renderer - * @author JellySquid - */ - @Overwrite - private void setupTerrain(Camera camera, Frustum frustum, boolean hasForcedFrustum, int frame, boolean spectator) { - RenderDevice.enterManagedCode(); - - try { - this.renderer.updateChunks(camera, frustum, hasForcedFrustum, frame, spectator); - } finally { - RenderDevice.exitManagedCode(); - } - } - - /** - * @reason Redirect chunk updates to our renderer - * @author JellySquid - */ - @Overwrite - public void scheduleBlockRenders(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - this.renderer.scheduleRebuildForBlockArea(minX, minY, minZ, maxX, maxY, maxZ, false); - } - - /** - * @reason Redirect chunk updates to our renderer - * @author JellySquid - */ - @Overwrite - public void scheduleBlockRenders(int x, int y, int z) { - this.renderer.scheduleRebuildForChunks(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1, false); - } - - /** - * @reason Redirect chunk updates to our renderer - * @author JellySquid - */ - @Overwrite - private void scheduleSectionRender(BlockPos pos, boolean important) { - this.renderer.scheduleRebuildForBlockArea(pos.getX() - 1, pos.getY() - 1, pos.getZ() - 1, pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1, important); - } - - /** - * @reason Redirect chunk updates to our renderer - * @author JellySquid - */ - @Overwrite - private void scheduleChunkRender(int x, int y, int z, boolean important) { - this.renderer.scheduleRebuildForChunk(x, y, z, important); - } - - @Inject(method = "reload()V", at = @At("RETURN")) - private void onReload(CallbackInfo ci) { - RenderDevice.enterManagedCode(); - - try { - this.renderer.reload(); - } finally { - RenderDevice.exitManagedCode(); - } - } - - @Inject(method = "render", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/WorldRenderer;noCullingBlockEntities:Ljava/util/Set;", shift = At.Shift.BEFORE, ordinal = 0)) - private void onRenderTileEntities(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) { - this.renderer.renderTileEntities(matrices, this.bufferBuilders, this.blockBreakingProgressions, camera, tickDelta); - } - - /** - * @reason Replace the debug string - * @author JellySquid - */ - @Overwrite - public String getChunksDebugString() { - return this.renderer.getChunksDebugString(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java deleted file mode 100644 index c214e52c6..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java +++ /dev/null @@ -1,79 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.debug; - -import com.google.common.collect.Lists; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.compat.forge.ForgeBlockRenderer; -import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; -import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderBackend; -import net.minecraft.client.gui.hud.DebugHud; -import net.minecraft.util.Formatting; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.lang.management.ManagementFactory; -import java.util.ArrayList; -import java.util.List; - -@Mixin(DebugHud.class) -public abstract class MixinDebugHud { - @Shadow - private static long toMiB(long bytes) { - throw new UnsupportedOperationException(); - } - - @Redirect(method = "getRightText", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList([Ljava/lang/Object;)Ljava/util/ArrayList;")) - private ArrayList redirectRightTextEarly(Object[] elements) { - ArrayList strings = Lists.newArrayList((String[]) elements); - strings.add(""); - strings.add("Embeddium Renderer"); - strings.add(Formatting.UNDERLINE + getFormattedVersionText()); - strings.add(""); - strings.addAll(getChunkRendererDebugStrings()); - - if (SodiumClientMod.options().advanced.ignoreDriverBlacklist) { - strings.add(Formatting.RED + "(!!) Driver blacklist ignored"); - } - - for (int i = 0; i < strings.size(); i++) { - String str = strings.get(i); - - if (str.startsWith("Allocated:")) { - strings.add(i + 1, getNativeMemoryString()); - - break; - } - } - - return strings; - } - - private static String getFormattedVersionText() { - String version = SodiumClientMod.getVersion(); - Formatting color; - - if (version.contains("git.")) { - color = Formatting.RED; - } else { - color = Formatting.GREEN; - } - - return color + version; - } - - private static List getChunkRendererDebugStrings() { - ChunkRenderBackend backend = SodiumWorldRenderer.getInstance().getChunkRenderer(); - - List strings = new ArrayList<>(5); - strings.add("Chunk Renderer: " + backend.getRendererName()); - strings.add("Block Renderer: " + (ForgeBlockRenderer.useForgeLightingPipeline() ? "Forge" : "Sodium")); - strings.addAll(backend.getDebugStrings()); - - return strings; - } - - private static String getNativeMemoryString() { - return "Off-Heap: +" + toMiB(ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getUsed()) + "MB"; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinCuboid.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinCuboid.java deleted file mode 100644 index b2d895cbe..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinCuboid.java +++ /dev/null @@ -1,19 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.entity.fast_render; - -import me.jellysquid.mods.sodium.client.model.ModelCuboidAccessor; -import net.minecraft.client.model.ModelPart; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(ModelPart.Cuboid.class) -public class MixinCuboid implements ModelCuboidAccessor { - @Shadow - @Final - private ModelPart.Quad[] sides; - - @Override - public ModelPart.Quad[] getQuads() { - return this.sides; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinModelPart.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinModelPart.java deleted file mode 100644 index 68181b8ff..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/fast_render/MixinModelPart.java +++ /dev/null @@ -1,70 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.entity.fast_render; - -import it.unimi.dsi.fastutil.objects.ObjectList; -import me.jellysquid.mods.sodium.client.model.ModelCuboidAccessor; -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; -import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; -import me.jellysquid.mods.sodium.client.util.Norm3b; -import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import me.jellysquid.mods.sodium.client.util.math.Matrix3fExtended; -import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; -import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; -import net.minecraft.client.model.ModelPart; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Vec3f; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(ModelPart.class) -public class MixinModelPart { - private static final float NORM = 1.0F / 16.0F; - - @Shadow - @Final - private ObjectList cuboids; - - /** - * @author JellySquid - * @reason Use optimized vertex writer, avoid allocations, use quick matrix transformations - */ - @Overwrite - private void renderCuboids(MatrixStack.Entry matrices, VertexConsumer vertexConsumer, int light, int overlay, float red, float green, float blue, float alpha) { - Matrix3fExtended normalExt = MatrixUtil.getExtendedMatrix(matrices.getNormal()); - Matrix4fExtended modelExt = MatrixUtil.getExtendedMatrix(matrices.getModel()); - - QuadVertexSink drain = VertexDrain.of(vertexConsumer).createSink(VanillaVertexTypes.QUADS); - drain.ensureCapacity(this.cuboids.size() * 6 * 4); - - int color = ColorABGR.pack(red, green, blue, alpha); - - for (ModelPart.Cuboid cuboid : this.cuboids) { - for (ModelPart.Quad quad : ((ModelCuboidAccessor) cuboid).getQuads()) { - float normX = normalExt.transformVecX(quad.direction); - float normY = normalExt.transformVecY(quad.direction); - float normZ = normalExt.transformVecZ(quad.direction); - - int norm = Norm3b.pack(normX, normY, normZ); - - for (ModelPart.Vertex vertex : quad.vertices) { - Vec3f pos = vertex.pos; - - float x1 = pos.getX() * NORM; - float y1 = pos.getY() * NORM; - float z1 = pos.getZ() * NORM; - - float x2 = modelExt.transformVecX(x1, y1, z1); - float y2 = modelExt.transformVecY(x1, y1, z1); - float z2 = modelExt.transformVecZ(x1, y1, z1); - - drain.writeQuad(x2, y2, z2, color, vertex.u, vertex.v, light, overlay, norm); - } - } - } - - drain.flush(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinEntityRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinEntityRenderer.java deleted file mode 100644 index 53f57df22..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinEntityRenderer.java +++ /dev/null @@ -1,51 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.entity.smooth_lighting; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; -import me.jellysquid.mods.sodium.client.model.light.EntityLighter; -import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; -import me.jellysquid.mods.sodium.client.render.entity.EntityLightSampler; -import net.minecraft.client.render.Frustum; -import net.minecraft.client.render.entity.EntityRenderer; -import net.minecraft.entity.Entity; -import net.minecraft.util.math.BlockPos; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(EntityRenderer.class) -public abstract class MixinEntityRenderer implements EntityLightSampler { - @Shadow - protected abstract int getBlockLight(T entity, BlockPos blockPos); - - @Shadow(remap = false) - protected abstract int func_239381_b_(T entity, BlockPos blockPos); - - @Inject(method = "getLight", at = @At("HEAD"), cancellable = true) - private void preGetLight(T entity, float tickDelta, CallbackInfoReturnable cir) { - // Use smooth entity lighting if enabled - if (SodiumClientMod.options().quality.smoothLighting == SodiumGameOptions.LightingQuality.HIGH) { - cir.setReturnValue(EntityLighter.getBlendedLight(this, entity, tickDelta)); - } - } - - @Inject(method = "shouldRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/Frustum;isVisible(Lnet/minecraft/util/math/Box;)Z", shift = At.Shift.AFTER), cancellable = true) - private void preShouldRender(T entity, Frustum frustum, double x, double y, double z, CallbackInfoReturnable cir) { - // If the entity isn't culled already by other means, try to perform a second pass - if (cir.getReturnValue() && !SodiumWorldRenderer.getInstance().isEntityVisible(entity)) { - cir.setReturnValue(false); - } - } - - @Override - public int bridge$getBlockLight(T entity, BlockPos pos) { - return this.getBlockLight(entity, pos); - } - - @Override - public int bridge$getSkyLight(T entity, BlockPos pos) { - return this.func_239381_b_(entity, pos); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinPaintingEntityRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinPaintingEntityRenderer.java deleted file mode 100644 index 35c8b1e43..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/entity/smooth_lighting/MixinPaintingEntityRenderer.java +++ /dev/null @@ -1,59 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.entity.smooth_lighting; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; -import me.jellysquid.mods.sodium.client.model.light.EntityLighter; -import me.jellysquid.mods.sodium.client.render.entity.EntityLightSampler; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.client.render.entity.EntityRenderDispatcher; -import net.minecraft.client.render.entity.EntityRenderer; -import net.minecraft.client.render.entity.PaintingEntityRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.decoration.painting.PaintingEntity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(PaintingEntityRenderer.class) -public abstract class MixinPaintingEntityRenderer extends EntityRenderer implements EntityLightSampler { - private PaintingEntity entity; - private float tickDelta; - - protected MixinPaintingEntityRenderer(EntityRenderDispatcher dispatcher) { - super(dispatcher); - } - - @Inject(method = "render", at = @At(value = "HEAD")) - public void preRender(PaintingEntity paintingEntity, float f, float g, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { - this.entity = paintingEntity; - this.tickDelta = g; - } - - /** - * @author FlashyReese - * @reason Redirect Lightmap coord with Sodium's EntityLighter. - */ - @Redirect(method = "func_229122_a_", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;getLightmapCoordinates(Lnet/minecraft/world/BlockRenderView;Lnet/minecraft/util/math/BlockPos;)I")) - public int redirectLightmapCoord(BlockRenderView world, BlockPos pos) { - if (SodiumClientMod.options().quality.smoothLighting == SodiumGameOptions.LightingQuality.HIGH && this.entity != null) { - return EntityLighter.getBlendedLight(this, this.entity, tickDelta); - } else { - return WorldRenderer.getLightmapCoordinates(world, pos); - } - } - - @Override - public int bridge$getBlockLight(PaintingEntity entity, BlockPos pos) { - return this.getBlockLight(entity, pos); - } - - @Override - public int bridge$getSkyLight(PaintingEntity entity, BlockPos pos) { - return this.method_27950(entity, pos); - } -} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBackgroundRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBackgroundRenderer.java deleted file mode 100644 index a9abc761d..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBackgroundRenderer.java +++ /dev/null @@ -1,24 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.fast_biome_colors; - -import me.jellysquid.mods.sodium.client.util.color.FastCubicSampler; -import net.minecraft.client.render.BackgroundRenderer; -import net.minecraft.client.render.Camera; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.CubicSampler; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(BackgroundRenderer.class) -public class MixinBackgroundRenderer { - @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/CubicSampler;sampleColor(Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/util/CubicSampler$RgbFetcher;)Lnet/minecraft/util/math/Vec3d;")) - private static Vec3d redirectSampleColor(Vec3d pos, CubicSampler.RgbFetcher rgbFetcher, Camera camera, float tickDelta, ClientWorld world, int i, float f) { - float u = MathHelper.clamp(MathHelper.cos(world.getSkyAngle(tickDelta) * 6.2831855F) * 2.0F + 0.5F, 0.0F, 1.0F); - - return FastCubicSampler.sampleColor(pos, - (x, y, z) -> world.getBiomeAccess().getBiomeForNoiseGen(x, y, z).getFogColor(), - (v) -> world.getSkyProperties().adjustFogColor(v, u)); - } -} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBlock.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBlock.java deleted file mode 100644 index 635986051..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinBlock.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.fast_biome_colors; - -import me.jellysquid.mods.sodium.client.model.quad.blender.BlockColorSettings; -import me.jellysquid.mods.sodium.client.model.quad.blender.DefaultBlockColorSettings; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; -import org.spongepowered.asm.mixin.Mixin; - -@Mixin(Block.class) -public class MixinBlock implements BlockColorSettings { - @Override - public boolean useSmoothColorBlending(BlockRenderView view, BlockState state, BlockPos pos) { - return DefaultBlockColorSettings.isSmoothBlendingAvailable(state.getBlock()); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinFluid.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinFluid.java deleted file mode 100644 index d2e7e2d62..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/fast_biome_colors/MixinFluid.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.fast_biome_colors; - -import me.jellysquid.mods.sodium.client.model.quad.blender.BlockColorSettings; -import net.minecraft.fluid.Fluid; -import net.minecraft.fluid.FluidState; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; -import org.spongepowered.asm.mixin.Mixin; - -@Mixin(Fluid.class) -public class MixinFluid implements BlockColorSettings { - @Override - public boolean useSmoothColorBlending(BlockRenderView view, FluidState state, BlockPos pos) { - return true; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/MixinDebugHud.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/MixinDebugHud.java deleted file mode 100644 index 6337d5c20..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/MixinDebugHud.java +++ /dev/null @@ -1,133 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.gui; - -import com.google.common.base.Strings; -import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.hud.DebugHud; -import net.minecraft.client.render.*; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Matrix4f; -import org.apache.commons.lang3.Validate; -import org.lwjgl.opengl.GL20C; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.List; - -@Mixin(DebugHud.class) -public abstract class MixinDebugHud { - @Shadow - @Final - private MinecraftClient client; - - @Shadow - @Final - private TextRenderer fontRenderer; - - private List capturedList = null; - - @Redirect(method = { "renderLeftText", "renderRightText" }, at = @At(value = "INVOKE", target = "Ljava/util/List;size()I")) - private int preRenderText(List list) { - // Capture the list to be rendered later - this.capturedList = list; - - return 0; // Prevent the rendering of any text - } - - @Inject(method = "renderLeftText", at = @At("RETURN")) - public void renderLeftText(MatrixStack matrixStack, CallbackInfo ci) { - this.renderCapturedText(matrixStack, false); - } - - @Inject(method = "renderRightText", at = @At("RETURN")) - public void renderRightText(MatrixStack matrixStack, CallbackInfo ci) { - this.renderCapturedText(matrixStack, true); - } - - private void renderCapturedText(MatrixStack matrixStack, boolean right) { - Validate.notNull(this.capturedList, "Failed to capture string list"); - - this.renderBackdrop(matrixStack, this.capturedList, right); - this.renderStrings(matrixStack, this.capturedList, right); - - this.capturedList = null; - } - - private void renderStrings(MatrixStack matrixStack, List list, boolean right) { - VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer()); - - Matrix4f modelMatrix = matrixStack.peek().getModel(); - - for (int i = 0; i < list.size(); ++i) { - String string = list.get(i); - - if (!Strings.isNullOrEmpty(string)) { - int height = 9; - int width = this.fontRenderer.getWidth(string); - - float x1 = right ? this.client.getWindow().getScaledWidth() - 2 - width : 2; - float y1 = 2 + (height * i); - - this.fontRenderer.draw(string, x1, y1, 0xe0e0e0, false, modelMatrix, immediate, - false, 0, 15728880, this.fontRenderer.isRightToLeft()); - } - } - - immediate.draw(); - } - - private void renderBackdrop(MatrixStack matrixStack, List list, boolean right) { - RenderSystem.enableBlend(); - RenderSystem.disableTexture(); - RenderSystem.defaultBlendFunc(); - - int color = 0x90505050; - - float f = (float) (color >> 24 & 255) / 255.0F; - float g = (float) (color >> 16 & 255) / 255.0F; - float h = (float) (color >> 8 & 255) / 255.0F; - float k = (float) (color & 255) / 255.0F; - - BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); - bufferBuilder.begin(GL20C.GL_QUADS, VertexFormats.POSITION_COLOR); - - Matrix4f matrix = matrixStack.peek() - .getModel(); - - for (int i = 0; i < list.size(); ++i) { - String string = list.get(i); - - if (Strings.isNullOrEmpty(string)) { - continue; - } - - int height = 9; - int width = this.fontRenderer.getWidth(string); - - int x = right ? this.client.getWindow().getScaledWidth() - 2 - width : 2; - int y = 2 + height * i; - - float x1 = x - 1; - float y1 = y - 1; - float x2 = x + width + 1; - float y2 = y + height - 1; - - bufferBuilder.vertex(matrix, x1, y2, 0.0F).color(g, h, k, f).next(); - bufferBuilder.vertex(matrix, x2, y2, 0.0F).color(g, h, k, f).next(); - bufferBuilder.vertex(matrix, x2, y1, 0.0F).color(g, h, k, f).next(); - bufferBuilder.vertex(matrix, x1, y1, 0.0F).color(g, h, k, f).next(); - } - - bufferBuilder.end(); - - BufferRenderer.draw(bufferBuilder); - RenderSystem.enableTexture(); - RenderSystem.disableBlend(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_fps_pie/MixinMinecraftClient.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_fps_pie/MixinMinecraftClient.java deleted file mode 100644 index 06b2f78bb..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_fps_pie/MixinMinecraftClient.java +++ /dev/null @@ -1,43 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.gui.fast_fps_pie; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.profiler.ProfileResult; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(MinecraftClient.class) -public class MixinMinecraftClient { - @Shadow - @Final - public TextRenderer textRenderer; - - private VertexConsumerProvider.Immediate immediate; - - @Inject(method = "drawProfilerResults", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/client/font/TextRenderer;drawWithShadow(Lnet/minecraft/client/util/math/MatrixStack;Ljava/lang/String;FFI)I")) - private void preRenderText(MatrixStack matrices, ProfileResult profileResult, CallbackInfo ci) { - this.immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer()); - } - - @Redirect(method = "drawProfilerResults", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/font/TextRenderer;drawWithShadow(Lnet/minecraft/client/util/math/MatrixStack;Ljava/lang/String;FFI)I")) - private int drawWithShadow(TextRenderer textRenderer, MatrixStack matrices, String text, float x, float y, int color) { - if (text != null) { - return this.textRenderer.draw(text, x, y, color, true, matrices.peek().getModel(), this.immediate, - false, 0, 15728880, this.textRenderer.isRightToLeft()); - } - return 0; - } - - @Inject(method = "drawProfilerResults", at = @At("TAIL")) - private void renderText(MatrixStack matrices, ProfileResult profileResult, CallbackInfo ci) { - this.immediate.draw(); - } -} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_loading_screen/MixinLevelLoadingScreen.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_loading_screen/MixinLevelLoadingScreen.java deleted file mode 100644 index a12d11281..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_loading_screen/MixinLevelLoadingScreen.java +++ /dev/null @@ -1,132 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.gui.fast_loading_screen; - -import com.mojang.blaze3d.systems.RenderSystem; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; -import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.BasicScreenQuadVertexSink; -import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import me.jellysquid.mods.sodium.client.util.color.ColorARGB; -import net.minecraft.client.gui.WorldGenerationProgressTracker; -import net.minecraft.client.gui.screen.LevelLoadingScreen; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Matrix4f; -import net.minecraft.world.chunk.ChunkStatus; -import org.lwjgl.opengl.GL20C; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -/** - * Re-implements the loading screen with considerations to reduce draw calls and other sources of overhead. This can - * improve world load times on slower processors with very few cores. - */ -@Mixin(LevelLoadingScreen.class) -public class MixinLevelLoadingScreen { - @Mutable - @Shadow - @Final - private static Object2IntMap STATUS_TO_COLOR; - - private static Reference2IntOpenHashMap STATUS_TO_COLOR_FAST; - - private static final int NULL_STATUS_COLOR = ColorABGR.pack(0, 0, 0, 0xFF); - private static final int DEFAULT_STATUS_COLOR = ColorARGB.pack(0, 0x11, 0xFF, 0xFF); - - /** - * This implementation differs from vanilla's in the following key ways. - * - All tiles are batched together in one draw call, reducing CPU overhead by an order of magnitudes. - * - Reference hashing is used for faster ChunkStatus -> Color lookup. - * - Colors are stored in ABGR format so conversion is not necessary every tile draw. - * - * @reason Significantly optimized implementation. - * @author JellySquid - */ - @Overwrite - public static void drawChunkMap(MatrixStack matrixStack, WorldGenerationProgressTracker tracker, int mapX, int mapY, int mapScale, int mapPadding) { - if (STATUS_TO_COLOR_FAST == null) { - STATUS_TO_COLOR_FAST = new Reference2IntOpenHashMap<>(STATUS_TO_COLOR.size()); - STATUS_TO_COLOR_FAST.put(null, NULL_STATUS_COLOR); - STATUS_TO_COLOR.object2IntEntrySet() - .forEach(entry -> STATUS_TO_COLOR_FAST.put(entry.getKey(), ColorARGB.toABGR(entry.getIntValue(), 0xFF))); - } - - Matrix4f matrix = matrixStack.peek().getModel(); - - Tessellator tessellator = Tessellator.getInstance(); - - RenderSystem.enableBlend(); - RenderSystem.disableTexture(); - RenderSystem.defaultBlendFunc(); - - BufferBuilder buffer = tessellator.getBuffer(); - buffer.begin(GL20C.GL_QUADS, VertexFormats.POSITION_COLOR); - - BasicScreenQuadVertexSink sink = VertexDrain.of(buffer).createSink(VanillaVertexTypes.BASIC_SCREEN_QUADS); - - int centerSize = tracker.getCenterSize(); - int size = tracker.getSize(); - - int tileSize = mapScale + mapPadding; - - if (mapPadding != 0) { - int mapRenderCenterSize = centerSize * tileSize - mapPadding; - int radius = mapRenderCenterSize / 2 + 1; - - sink.ensureCapacity(4 * 4); - addRect(matrix, sink, mapX - radius, mapY - radius, mapX - radius + 1, mapY + radius, DEFAULT_STATUS_COLOR); - addRect(matrix, sink, mapX + radius - 1, mapY - radius, mapX + radius, mapY + radius, DEFAULT_STATUS_COLOR); - addRect(matrix, sink, mapX - radius, mapY - radius, mapX + radius, mapY - radius + 1, DEFAULT_STATUS_COLOR); - addRect(matrix, sink, mapX - radius, mapY + radius - 1, mapX + radius, mapY + radius, DEFAULT_STATUS_COLOR); - } - - int mapRenderSize = size * tileSize - mapPadding; - int mapStartX = mapX - mapRenderSize / 2; - int mapStartY = mapY - mapRenderSize / 2; - - ChunkStatus prevStatus = null; - int prevColor = NULL_STATUS_COLOR; - - sink.ensureCapacity(size * size * 4); - for (int x = 0; x < size; ++x) { - int tileX = mapStartX + x * tileSize; - - for (int z = 0; z < size; ++z) { - int tileY = mapStartY + z * tileSize; - - ChunkStatus status = tracker.getChunkStatus(x, z); - int color; - - if (prevStatus == status) { - color = prevColor; - } else { - color = STATUS_TO_COLOR_FAST.getInt(status); - - prevStatus = status; - prevColor = color; - } - - addRect(matrix, sink, tileX, tileY, tileX + mapScale, tileY + mapScale, color); - } - } - - sink.flush(); - tessellator.draw(); - - RenderSystem.enableTexture(); - RenderSystem.disableBlend(); - } - - private static void addRect(Matrix4f matrix, BasicScreenQuadVertexSink sink, int x1, int y1, int x2, int y2, int color) { - sink.writeQuad(matrix, x1, y2, 0, color); - sink.writeQuad(matrix, x2, y2, 0, color); - sink.writeQuad(matrix, x2, y1, 0, color); - sink.writeQuad(matrix, x1, y1, 0, color); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_status_bars/MixinInGameHud.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_status_bars/MixinInGameHud.java deleted file mode 100644 index b345997d4..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/fast_status_bars/MixinInGameHud.java +++ /dev/null @@ -1,60 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.gui.fast_status_bars; - -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.gui.hud.InGameHud; -import net.minecraft.client.render.*; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.util.math.Matrix4f; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(InGameHud.class) -public abstract class MixinInGameHud extends DrawableHelper { - @Shadow - protected abstract PlayerEntity getCameraPlayer(); - - private final BufferBuilder bufferBuilder = new BufferBuilder(8192); - // It's possible for status bar rendering to be skipped - private boolean isRenderingStatusBars; - - @Inject(method = "renderStatusBars", at = @At("HEAD")) - private void preRenderStatusBars(MatrixStack matrices, CallbackInfo ci) { - if (this.getCameraPlayer() != null) { - this.bufferBuilder.begin(4, VertexFormats.POSITION_TEXTURE); - this.isRenderingStatusBars = true; - } else { - this.isRenderingStatusBars = false; - } - } - - @Redirect(method = { "renderStatusBars", "drawHeart" }, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;drawTexture(Lnet/minecraft/client/util/math/MatrixStack;IIIIII)V")) - private void drawTexture(InGameHud inGameHud, MatrixStack matrices, int x0, int y0, int u, int v, int width, int height) { - Matrix4f matrix = matrices.peek().getModel(); - int x1 = x0 + width; - int y1 = y0 + height; - int z = this.getZOffset(); - // Default texture size is 256x256 - float u0 = u / 256f; - float u1 = (u + width) / 256f; - float v0 = v / 256f; - float v1 = (v + height) / 256f; - - this.bufferBuilder.vertex(matrix, x0, y1, z).texture(u0, v1).next(); - this.bufferBuilder.vertex(matrix, x1, y1, z).texture(u1, v1).next(); - this.bufferBuilder.vertex(matrix, x1, y0, z).texture(u1, v0).next(); - this.bufferBuilder.vertex(matrix, x0, y0, z).texture(u0, v0).next(); - } - - @Inject(method = "renderStatusBars", at = @At("RETURN")) - private void renderStatusBars(MatrixStack matrices, CallbackInfo ci) { - if (this.isRenderingStatusBars) { - this.bufferBuilder.end(); - BufferRenderer.draw(this.bufferBuilder); - } - } -} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/font/MixinGlyphRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/font/MixinGlyphRenderer.java deleted file mode 100644 index 370175bec..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/gui/font/MixinGlyphRenderer.java +++ /dev/null @@ -1,75 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.gui.font; - -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; -import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; -import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import net.minecraft.client.font.GlyphRenderer; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.util.math.Matrix4f; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(GlyphRenderer.class) -public class MixinGlyphRenderer { - @Shadow - @Final - private float minX; - - @Shadow - @Final - private float maxX; - - @Shadow - @Final - private float minY; - - @Shadow - @Final - private float maxY; - - @Shadow - @Final - private float minU; - - @Shadow - @Final - private float minV; - - @Shadow - @Final - private float maxV; - - @Shadow - @Final - private float maxU; - - /** - * @reason Use intrinsics - * @author JellySquid - */ - @Overwrite - public void draw(boolean italic, float x, float y, Matrix4f matrix, VertexConsumer vertexConsumer, float red, float green, float blue, float alpha, int light) { - float x1 = x + this.minX; - float x2 = x + this.maxX; - float y1 = this.minY - 3.0F; - float y2 = this.maxY - 3.0F; - float h1 = y + y1; - float h2 = y + y2; - float w1 = italic ? 1.0F - 0.25F * y1 : 0.0F; - float w2 = italic ? 1.0F - 0.25F * y2 : 0.0F; - - int color = ColorABGR.pack(red, green, blue, alpha); - - GlyphVertexSink drain = VertexDrain.of(vertexConsumer) - .createSink(VanillaVertexTypes.GLYPHS); - drain.ensureCapacity(4); - drain.writeGlyph(matrix, x1 + w1, h1, 0.0F, color, this.minU, this.minV, light); - drain.writeGlyph(matrix, x1 + w2, h2, 0.0F, color, this.minU, this.maxV, light); - drain.writeGlyph(matrix, x2 + w2, h2, 0.0F, color, this.maxU, this.maxV, light); - drain.writeGlyph(matrix, x2 + w1, h1, 0.0F, color, this.maxU, this.minV, light); - drain.flush(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/item/MixinItemRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/item/MixinItemRenderer.java deleted file mode 100644 index 61d585db7..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/item/MixinItemRenderer.java +++ /dev/null @@ -1,124 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.item; - -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; -import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; -import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import me.jellysquid.mods.sodium.client.util.color.ColorARGB; -import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; -import me.jellysquid.mods.sodium.client.world.biome.ItemColorsExtended; -import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.client.color.item.ItemColorProvider; -import net.minecraft.client.color.item.ItemColors; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.item.ItemRenderer; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.Direction; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.List; - -@Mixin(ItemRenderer.class) -public class MixinItemRenderer { - private final XoRoShiRoRandom random = new XoRoShiRoRandom(); - - @Shadow - @Final - private ItemColors colorMap; - - /** - * @reason Avoid allocations - * @author JellySquid - */ - @Overwrite - public void renderBakedItemModel(BakedModel model, ItemStack stack, int light, int overlay, MatrixStack matrices, VertexConsumer vertices) { - XoRoShiRoRandom random = this.random; - - for (Direction direction : DirectionUtil.ALL_DIRECTIONS) { - List quads = model.getQuads(null, direction, random.setSeedAndReturn(42L)); - - if (!quads.isEmpty()) { - this.renderBakedItemQuads(matrices, vertices, quads, stack, light, overlay); - } - } - - List quads = model.getQuads(null, null, random.setSeedAndReturn(42L)); - - if (!quads.isEmpty()) { - this.renderBakedItemQuads(matrices, vertices, quads, stack, light, overlay); - } - } - - /** - * @reason Use vertex building intrinsics - * @author JellySquid - */ - @Overwrite - public void renderBakedItemQuads(MatrixStack matrices, VertexConsumer vertexConsumer, List quads, ItemStack stack, int light, int overlay) { - MatrixStack.Entry entry = matrices.peek(); - - ItemColorProvider colorProvider = null; - - QuadVertexSink drain = VertexDrain.of(vertexConsumer) - .createSink(VanillaVertexTypes.QUADS); - drain.ensureCapacity(quads.size() * 4); - - for (BakedQuad bakedQuad : quads) { - int color = 0xFFFFFFFF; - - if (!stack.isEmpty() && bakedQuad.hasColor()) { - if (colorProvider == null) { - colorProvider = ((ItemColorsExtended) this.colorMap).getColorProvider(stack); - } - - try { - if (colorProvider == null) { - color = ColorARGB.toABGR(this.colorMap.getColorMultiplier(stack, bakedQuad.getColorIndex()), 255); - } else { - color = ColorARGB.toABGR((colorProvider.getColor(stack, bakedQuad.getColorIndex())), 255); - } - }catch(Exception e) { - } - } - - ModelQuadView quad = ((ModelQuadView) bakedQuad); - - for (int i = 0; i < 4; i++) { - - int fColor = multARGBInts(quad.getColor(i), color); - - drain.writeQuad(entry, quad.getX(i), quad.getY(i), quad.getZ(i), fColor, quad.getTexU(i), quad.getTexV(i), - ModelQuadUtil.mergeBakedLight(quad.getLight(i), light), overlay, ModelQuadUtil.getFacingNormal(bakedQuad.getFace(), quad.getNormal(i))); - } - - SpriteUtil.markSpriteActive(quad.rubidium$getSprite()); - } - - drain.flush(); - } - - private int multARGBInts(int colorA, int colorB) { - // Most common case: Either quad coloring or tint-based coloring, but not both - if (colorA == -1) { - return colorB; - } else if (colorB == -1) { - return colorA; - } - // General case (rare): Both colorings, actually perform the multiplication - int a = (int)((ColorABGR.unpackAlpha(colorA)/255.0f) * (ColorABGR.unpackAlpha(colorB)/255.0f) * 255.0f); - int b = (int)((ColorABGR.unpackBlue(colorA)/255.0f) * (ColorABGR.unpackBlue(colorB)/255.0f) * 255.0f); - int g = (int)((ColorABGR.unpackGreen(colorA)/255.0f) * (ColorABGR.unpackGreen(colorB)/255.0f) * 255.0f); - int r = (int)((ColorABGR.unpackRed(colorA)/255.0f) * (ColorABGR.unpackRed(colorB)/255.0f) * 255.0f); - return ColorABGR.pack(r, g, b, a); - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinMatrixStack.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinMatrixStack.java deleted file mode 100644 index 18c1ad048..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinMatrixStack.java +++ /dev/null @@ -1,47 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.matrix_stack; - -import me.jellysquid.mods.sodium.client.util.math.Matrix3fExtended; -import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; -import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Quaternion; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.Deque; - -@Mixin(MatrixStack.class) -public class MixinMatrixStack { - @Shadow - @Final - private Deque stack; - - /** - * @reason Use our faster specialized function - * @author JellySquid - */ - @Overwrite - public void translate(double x, double y, double z) { - MatrixStack.Entry entry = this.stack.getLast(); - - Matrix4fExtended mat = MatrixUtil.getExtendedMatrix(entry.getModel()); - mat.translate((float) x, (float) y, (float) z); - } - - /** - * @reason Use our faster specialized function - * @author JellySquid - */ - @Overwrite - public void multiply(Quaternion q) { - MatrixStack.Entry entry = this.stack.getLast(); - - Matrix4fExtended mat4 = MatrixUtil.getExtendedMatrix(entry.getModel()); - mat4.rotate(q); - - Matrix3fExtended mat3 = MatrixUtil.getExtendedMatrix(entry.getNormal()); - mat3.rotate(q); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinVertexConsumer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinVertexConsumer.java deleted file mode 100644 index aee0f0f73..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/matrix_stack/MixinVertexConsumer.java +++ /dev/null @@ -1,48 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.matrix_stack; - -import me.jellysquid.mods.sodium.client.util.math.Matrix3fExtended; -import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; -import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.util.math.Matrix3f; -import net.minecraft.util.math.Matrix4f; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(VertexConsumer.class) -public interface MixinVertexConsumer { - @Shadow - VertexConsumer normal(float x, float y, float z); - - @Shadow - VertexConsumer vertex(double x, double y, double z); - - /** - * @reason Avoid allocations - * @author JellySquid - */ - @Overwrite - default VertexConsumer vertex(Matrix4f matrix, float x, float y, float z) { - Matrix4fExtended ext = MatrixUtil.getExtendedMatrix(matrix); - float x2 = ext.transformVecX(x, y, z); - float y2 = ext.transformVecY(x, y, z); - float z2 = ext.transformVecZ(x, y, z); - - return this.vertex(x2, y2, z2); - } - - /** - * @reason Avoid allocations - * @author JellySquid - */ - @Overwrite - default VertexConsumer normal(Matrix3f matrix, float x, float y, float z) { - Matrix3fExtended ext = MatrixUtil.getExtendedMatrix(matrix); - float x2 = ext.transformVecX(x, y, z); - float y2 = ext.transformVecY(x, y, z); - float z2 = ext.transformVecZ(x, y, z); - - return this.normal(x2, y2, z2); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinMultipartBakedModel.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinMultipartBakedModel.java deleted file mode 100644 index 7b372cf73..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinMultipartBakedModel.java +++ /dev/null @@ -1,82 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.model; - -import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.render.model.MultipartBakedModel; -import net.minecraft.util.math.Direction; -import net.minecraftforge.client.model.data.IModelData; -import net.minecraftforge.client.model.data.MultipartModelData; -import org.apache.commons.lang3.tuple.Pair; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.locks.StampedLock; -import java.util.function.Predicate; - -@Mixin(MultipartBakedModel.class) -public class MixinMultipartBakedModel { - private final Map stateCacheFast = new Reference2ReferenceOpenHashMap<>(); - private final StampedLock lock = new StampedLock(); - - @Shadow - @Final - private List, BakedModel>> components; - - /** - * @author JellySquid - * @reason Avoid expensive allocations and replace bitfield indirection - */ - @Overwrite - public List getQuads(BlockState state, Direction face, Random random, IModelData modelData) { - if (state == null) { - return Collections.emptyList(); - } - - BakedModel[] models; - - long readStamp = this.lock.readLock(); - try { - models = this.stateCacheFast.get(state); - } finally { - this.lock.unlockRead(readStamp); - } - - if (models == null) { - long writeStamp = this.lock.writeLock(); - try { - List modelList = new ArrayList<>(this.components.size()); - - for (Pair, BakedModel> pair : this.components) { - if (pair.getLeft().test(state)) { - modelList.add(pair.getRight()); - } - } - - models = modelList.toArray(new BakedModel[modelList.size()]); - this.stateCacheFast.put(state, models); - } finally { - this.lock.unlockWrite(writeStamp); - } - } - - List quads = new ArrayList<>(); - long seed = random.nextLong(); - - for (BakedModel model : models) { - random.setSeed(seed); - quads.addAll(model.getQuads(state, face, random, MultipartModelData.resolve(model, modelData))); - } - - return quads; - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinWeightedBakedModel.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinWeightedBakedModel.java deleted file mode 100644 index fcf3cab88..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/model/MixinWeightedBakedModel.java +++ /dev/null @@ -1,60 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.model; - -import net.minecraft.block.BlockState; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.render.model.WeightedBakedModel; -import net.minecraft.util.math.Direction; -import net.minecraftforge.client.model.data.IModelData; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.Collections; -import java.util.List; -import java.util.Random; - -@Mixin(WeightedBakedModel.class) -public class MixinWeightedBakedModel { - @Shadow - @Final - private List models; - - @Shadow - @Final - private int totalWeight; - - /** - * @author JellySquid - * @reason Avoid excessive object allocations - */ - @Overwrite - public List getQuads(@Nullable BlockState state, @Nullable Direction face, Random random, IModelData modelData) { - WeightedBakedModel.Entry entry = getAt(this.models, Math.abs((int) random.nextLong()) % this.totalWeight); - - if (entry != null) { - return entry.model.getQuads(state, face, random, modelData); - } - - return Collections.emptyList(); - } - - private static T getAt(List pool, int totalWeight) { - int i = 0; - int len = pool.size(); - - T weighted; - - do { - if (i >= len) { - return null; - } - - weighted = pool.get(i++); - totalWeight -= weighted.weight; - } while (totalWeight >= 0); - - return weighted; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/optimized_bamboo/MixinBambooBlock.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/optimized_bamboo/MixinBambooBlock.java deleted file mode 100644 index 3e9f812ab..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/optimized_bamboo/MixinBambooBlock.java +++ /dev/null @@ -1,22 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.optimized_bamboo; - -import net.minecraft.block.BambooBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockView; -import org.spongepowered.asm.mixin.Mixin; - -@Mixin(BambooBlock.class) -public class MixinBambooBlock extends Block { - public MixinBambooBlock(Settings settings) { - super(settings); - } - - // This is a fix for an oversight on Mojang's side, where this block always returns 1.0 regardless of the state. It returns the same result, - // but improves performance significantly. This was originally found by darkevilmac in https://github.com/TridentMC/FastBamboo. - @Override - public float getAmbientOcclusionLightLevel(BlockState state, BlockView world, BlockPos pos) { - return 1.0f; - } -} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinGameOptions.java deleted file mode 100644 index 47546b10c..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinGameOptions.java +++ /dev/null @@ -1,34 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.options; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; -import net.minecraft.client.option.CloudRenderMode; -import net.minecraft.client.option.GameOptions; -import net.minecraft.client.option.GraphicsMode; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(GameOptions.class) -public class MixinGameOptions { - @Shadow - public int viewDistance; - - @Shadow - public GraphicsMode graphicsMode; - - /** - * @author JellySquid - * @reason Make the cloud render mode user-configurable - */ - @Overwrite - public CloudRenderMode getCloudRenderMode() { - SodiumGameOptions options = SodiumClientMod.options(); - - if (this.viewDistance < 4 || !options.quality.enableClouds) { - return CloudRenderMode.OFF; - } - - return options.quality.cloudQuality.isFancy(this.graphicsMode) ? CloudRenderMode.FANCY : CloudRenderMode.FAST; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinInGameHud.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinInGameHud.java deleted file mode 100644 index 688eebf1c..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinInGameHud.java +++ /dev/null @@ -1,15 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.options; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraftforge.client.gui.ForgeIngameGui; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(ForgeIngameGui.class) -public class MixinInGameHud { - @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;isFancyGraphicsOrBetter()Z")) - private boolean redirectFancyGraphicsVignette() { - return SodiumClientMod.options().quality.enableVignette; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinMinecraftClient.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinMinecraftClient.java deleted file mode 100644 index 54e569d2b..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinMinecraftClient.java +++ /dev/null @@ -1,19 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.options; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; -import net.minecraft.client.MinecraftClient; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -@Mixin(MinecraftClient.class) -public class MixinMinecraftClient { - /** - * @author JellySquid - * @reason Make ambient occlusion user configurable - */ - @Overwrite - public static boolean isAmbientOcclusionEnabled() { - return SodiumClientMod.options().quality.smoothLighting != SodiumGameOptions.LightingQuality.OFF; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinOptionsScreen.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinOptionsScreen.java deleted file mode 100644 index 5a2916e0c..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinOptionsScreen.java +++ /dev/null @@ -1,27 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.options; - -import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.option.OptionsScreen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.text.Text; -import org.spongepowered.asm.mixin.Dynamic; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(OptionsScreen.class) -public class MixinOptionsScreen extends Screen { - protected MixinOptionsScreen(Text title) { - super(title); - } - - @Dynamic - @Inject(method = "func_213059_g(Lnet/minecraft/client/gui/widget/ButtonWidget;)V", at = @At("HEAD"), cancellable = true) - private void open(ButtonWidget widget, CallbackInfo ci) { - this.client.openScreen(new SodiumOptionsGUI(this)); - - ci.cancel(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinWorldRenderer.java deleted file mode 100644 index 9b10b1ff5..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinWorldRenderer.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.options; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.WorldRenderer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(WorldRenderer.class) -public class MixinWorldRenderer { - @Redirect(method = "renderWeather", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;isFancyGraphicsOrBetter()Z")) - private boolean redirectGetFancyWeather() { - return SodiumClientMod.options().quality.weatherQuality.isFancy(MinecraftClient.getInstance().options.graphicsMode); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/particle/fast_render/MixinBillboardParticle.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/particle/fast_render/MixinBillboardParticle.java deleted file mode 100644 index 53cdd0479..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/particle/fast_render/MixinBillboardParticle.java +++ /dev/null @@ -1,120 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.particle.fast_render; - -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -import me.jellysquid.mods.sodium.client.model.vertex.VertexDrain; -import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.ParticleVertexSink; -import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import net.minecraft.client.particle.BillboardParticle; -import net.minecraft.client.particle.Particle; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Quaternion; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.Vec3f; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(BillboardParticle.class) -public abstract class MixinBillboardParticle extends Particle { - @Shadow - public abstract float getSize(float tickDelta); - - @Shadow - protected abstract float getMinU(); - - @Shadow - protected abstract float getMaxU(); - - @Shadow - protected abstract float getMinV(); - - @Shadow - protected abstract float getMaxV(); - - protected MixinBillboardParticle(ClientWorld world, double x, double y, double z) { - super(world, x, y, z); - } - - /** - * @reason Optimize function - * @author JellySquid - */ - @Overwrite - public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) { - Vec3d vec3d = camera.getPos(); - - float x = (float) (MathHelper.lerp(tickDelta, this.prevPosX, this.x) - vec3d.getX()); - float y = (float) (MathHelper.lerp(tickDelta, this.prevPosY, this.y) - vec3d.getY()); - float z = (float) (MathHelper.lerp(tickDelta, this.prevPosZ, this.z) - vec3d.getZ()); - - Quaternion quaternion; - - if (this.angle == 0.0F) { - quaternion = camera.getRotation(); - } else { - float angle = MathHelper.lerp(tickDelta, this.prevAngle, this.angle); - - quaternion = new Quaternion(camera.getRotation()); - quaternion.hamiltonProduct(Vec3f.POSITIVE_Z.getRadialQuaternion(angle)); - } - - float size = this.getSize(tickDelta); - int light = this.getBrightness(tickDelta); - - float minU = this.getMinU(); - float maxU = this.getMaxU(); - float minV = this.getMinV(); - float maxV = this.getMaxV(); - - int color = ColorABGR.pack(this.colorRed, this.colorGreen, this.colorBlue, this.colorAlpha); - - ParticleVertexSink drain = VertexDrain.of(vertexConsumer) - .createSink(VanillaVertexTypes.PARTICLES); - - addVertex(drain, quaternion,-1.0F, -1.0F, x, y, z, maxU, maxV, color, light, size); - addVertex(drain, quaternion,-1.0F, 1.0F, x, y, z, maxU, minV, color, light, size); - addVertex(drain, quaternion,1.0F, 1.0F, x, y, z, minU, minV, color, light, size); - addVertex(drain, quaternion,1.0F, -1.0F, x, y, z, minU, maxV, color, light, size); - - drain.flush(); - } - - private static void addVertex(ParticleVertexSink drain, Quaternion rotation, - float x, float y, float posX, float posY, float posZ, float u, float v, int color, int light, float size) { - // Quaternion q0 = new Quaternion(rotation); - float q0x = rotation.getX(); - float q0y = rotation.getY(); - float q0z = rotation.getZ(); - float q0w = rotation.getW(); - - // q0.hamiltonProduct(x, y, 0.0f, 0.0f) - float q1x = (q0w * x) - (q0z * y); - float q1y = (q0w * y) + (q0z * x); - float q1w = (q0x * y) - (q0y * x); - float q1z = -(q0x * x) - (q0y * y); - - // Quaternion q2 = new Quaternion(rotation); - // q2.conjugate() - float q2x = -q0x; - float q2y = -q0y; - float q2z = -q0z; - float q2w = q0w; - - // q2.hamiltonProduct(q1) - float q3x = q1z * q2x + q1x * q2w + q1y * q2z - q1w * q2y; - float q3y = q1z * q2y - q1x * q2z + q1y * q2w + q1w * q2x; - float q3z = q1z * q2z + q1x * q2y - q1y * q2x + q1w * q2w; - - // Vector3f f = new Vector3f(q2.getX(), q2.getY(), q2.getZ()) - // f.multiply(size) - // f.add(pos) - float fx = (q3x * size) + posX; - float fy = (q3y * size) + posY; - float fz = (q3z * size) + posZ; - - drain.writeParticle(fx, fy, fz, u, v, color, light); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/MixinTexturedRenderLayers.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/MixinTexturedRenderLayers.java deleted file mode 100644 index be7525309..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/MixinTexturedRenderLayers.java +++ /dev/null @@ -1,34 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.render_layer; - -import net.minecraft.client.render.TexturedRenderLayers; -import net.minecraft.client.util.SpriteIdentifier; -import net.minecraft.util.SignType; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.Map; - -@Mixin(TexturedRenderLayers.class) -public class MixinTexturedRenderLayers { - @Shadow - @Final - public static Map WOOD_TYPE_TEXTURES; - - // Instantiating a SpriteIdentifier every time a sign tries to grab a texture identifier causes a significant - // performance impact as no RenderLayer will ever be cached for the sprite. Minecraft already maintains a - // SignType -> SpriteIdentifier cache but for some reason doesn't use it. - @Inject(method = "createSignTextureId", at = @At("HEAD"), cancellable = true) - private static void preGetSignTextureId(SignType type, CallbackInfoReturnable ci) { - if (WOOD_TYPE_TEXTURES != null) { - SpriteIdentifier sprite = WOOD_TYPE_TEXTURES.get(type); - - if (type != null) { - ci.setReturnValue(sprite); - } - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinLeavesBlock.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinLeavesBlock.java deleted file mode 100644 index 31fecbe38..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinLeavesBlock.java +++ /dev/null @@ -1,27 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.render_layer.leaves; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.LeavesBlock; -import net.minecraft.block.Material; -import net.minecraft.client.MinecraftClient; -import net.minecraft.util.math.Direction; -import org.spongepowered.asm.mixin.Mixin; - -@Mixin(LeavesBlock.class) -public class MixinLeavesBlock extends Block { - public MixinLeavesBlock() { - super(Settings.of(Material.AIR)); - throw new AssertionError("Mixin constructor called!"); - } - - @Override - public boolean isSideInvisible(BlockState state, BlockState stateFrom, Direction direction) { - if (SodiumClientMod.options().quality.leavesQuality.isFancy(MinecraftClient.getInstance().options.graphicsMode)) { - return super.isSideInvisible(state, stateFrom, direction); - } else { - return stateFrom.getBlock() instanceof LeavesBlock || super.isSideInvisible(state, stateFrom, direction); - } - } -} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinRenderLayers.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinRenderLayers.java deleted file mode 100644 index f318c4a90..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/render_layer/leaves/MixinRenderLayers.java +++ /dev/null @@ -1,54 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.render_layer.leaves; - -import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.block.Block; -import net.minecraft.client.option.GraphicsMode; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.RenderLayers; -import net.minecraft.fluid.Fluid; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.Shadow; -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.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.Map; - -@Mixin(RenderLayers.class) -public class MixinRenderLayers { - @Mutable - @Shadow - @Final - private static Map BLOCKS; - - @Mutable - @Shadow - @Final - private static Map FLUIDS; - - static { - // Replace the backing collection types with something a bit faster, since this is a hot spot in chunk rendering. - BLOCKS = new Reference2ReferenceOpenHashMap<>(BLOCKS); - FLUIDS = new Reference2ReferenceOpenHashMap<>(FLUIDS); - } - - @Unique - private static boolean embeddium$leavesFancy; - - @Redirect( - method = { "getBlockLayer", "getMovingBlockLayer", "canRenderInLayer(Lnet/minecraft/block/BlockState;Lnet/minecraft/client/render/RenderLayer;)Z" }, - at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/RenderLayers;fancyGraphicsOrBetter:Z")) - private static boolean redirectLeavesShouldBeFancy() { - return embeddium$leavesFancy; - } - - @Inject(method = "setFancyGraphicsOrBetter", at = @At("RETURN")) - private static void onSetFancyGraphicsOrBetter(boolean fancyGraphicsOrBetter, CallbackInfo ci) { - embeddium$leavesFancy = SodiumClientMod.options().quality.leavesQuality.isFancy(fancyGraphicsOrBetter ? GraphicsMode.FANCY : GraphicsMode.FAST); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/sky/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/sky/MixinWorldRenderer.java deleted file mode 100644 index d362a20d2..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/sky/MixinWorldRenderer.java +++ /dev/null @@ -1,57 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.sky; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.BackgroundRenderer; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.WorldRenderer; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.effect.StatusEffects; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(WorldRenderer.class) -public class MixinWorldRenderer { - @Shadow - @Final - private MinecraftClient client; - - /** - *

Prevents the sky layer from rendering when the fog distance is reduced - * from the default. This helps prevent situations where the sky can be seen - * through chunks culled by fog occlusion. This also fixes the vanilla issue - * MC-152504 since it - * is also caused by being able to see the sky through invisible chunks.

- * - *

However, this fix comes with some caveats. When underwater, it becomes - * impossible to see the sun, stars, and moon since the sky is not rendered. - * While this does not exactly match the vanilla game, it is consistent with - * what Bedrock Edition does, so it can be considered vanilla-style. This is - * also more "correct" in the sense that underwater fog is applied to chunks - * outside of water, so the fog should also be covering the sun and sky.

- * - *

When updating Sodium to new releases of the game, please check for new - * ways the fog can be reduced in {@link BackgroundRenderer#applyFog()}.

- */ - @Inject(method = "renderSky", at = @At("HEAD"), cancellable = true) - private void preRenderSky(MatrixStack matrices, float tickDelta, CallbackInfo callbackInfo) { - Camera camera = this.client.gameRenderer.getCamera(); - Vec3d cameraPosition = camera.getPos(); - Entity cameraEntity = camera.getFocusedEntity(); - - boolean hasBlindness = cameraEntity instanceof LivingEntity && ((LivingEntity) cameraEntity).hasStatusEffect(StatusEffects.BLINDNESS); - boolean useThickFog = this.client.world.getSkyProperties().useThickFog(MathHelper.floor(cameraPosition.getX()), - MathHelper.floor(cameraPosition.getY())) || this.client.inGameHud.getBossBarHud().shouldThickenFog(); - - if (hasBlindness || useThickFog) { - callbackInfo.cancel(); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSprite.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSprite.java deleted file mode 100644 index 945c8098e..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSprite.java +++ /dev/null @@ -1,84 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.texture_tracking; - -import com.mojang.blaze3d.systems.RenderSystem; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.render.texture.SpriteExtended; -import net.minecraft.client.resource.metadata.AnimationResourceMetadata; -import net.minecraft.client.texture.Sprite; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(Sprite.class) -public abstract class MixinSprite implements SpriteExtended { - private boolean forceNextUpdate; - - @Shadow - private int frameTicks; - - @Shadow - @Final - private AnimationResourceMetadata animationMetadata; - - @Shadow - private int frameIndex; - - @Shadow - public abstract int getFrameCount(); - - @Shadow - protected abstract void upload(int int_1); - - @Shadow - @Final - private Sprite.Interpolation interpolation; - - /** - * @author JellySquid - * @reason Allow conditional texture updating - */ - @Overwrite - public void tickAnimation() { - this.frameTicks++; - - boolean onDemand = SodiumClientMod.options().advanced.animateOnlyVisibleTextures; - - if (!onDemand || this.forceNextUpdate) { - this.uploadTexture(); - } - } - - private void uploadTexture() { - if (this.frameTicks >= this.animationMetadata.getFrameTime(this.frameIndex)) { - int prevFrameIndex = this.animationMetadata.getFrameIndex(this.frameIndex); - int frameCount = this.animationMetadata.getFrameCount() == 0 ? this.getFrameCount() : this.animationMetadata.getFrameCount(); - - this.frameIndex = (this.frameIndex + 1) % frameCount; - this.frameTicks = 0; - - int frameIndex = this.animationMetadata.getFrameIndex(this.frameIndex); - - if (prevFrameIndex != frameIndex && frameIndex >= 0 && frameIndex < this.getFrameCount()) { - this.upload(frameIndex); - } - } else if (this.interpolation != null) { - if (!RenderSystem.isOnRenderThread()) { - RenderSystem.recordRenderCall(this::updateInterpolatedTexture); - } else { - this.updateInterpolatedTexture(); - } - } - - this.forceNextUpdate = false; - } - - @Override - public void markActive() { - this.forceNextUpdate = true; - } - - private void updateInterpolatedTexture() { - this.interpolation.apply(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteAtlasTexture.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteAtlasTexture.java deleted file mode 100644 index 954ccd4f4..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteAtlasTexture.java +++ /dev/null @@ -1,21 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.texture_tracking; - -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.texture.SpriteAtlasTexture; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(SpriteAtlasTexture.class) -public class MixinSpriteAtlasTexture { - @Inject(method = "getSprite", at = @At("RETURN")) - private void preReturnSprite(CallbackInfoReturnable cir) { - Sprite sprite = cir.getReturnValue(); - - if (sprite != null) { - SpriteUtil.markSpriteActive(sprite); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteBillboardParticle.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteBillboardParticle.java deleted file mode 100644 index 28849fb25..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/texture_tracking/MixinSpriteBillboardParticle.java +++ /dev/null @@ -1,40 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.texture_tracking; - -import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; -import net.minecraft.client.particle.BillboardParticle; -import net.minecraft.client.particle.SpriteBillboardParticle; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.world.ClientWorld; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(SpriteBillboardParticle.class) -public abstract class MixinSpriteBillboardParticle extends BillboardParticle { - @Shadow - protected Sprite sprite; - - private boolean shouldTickSprite; - - protected MixinSpriteBillboardParticle(ClientWorld world, double x, double y, double z) { - super(world, x, y, z); - } - - @Inject(method = "setSprite(Lnet/minecraft/client/texture/Sprite;)V", at = @At("RETURN")) - private void afterSetSprite(Sprite sprite, CallbackInfo ci) { - this.shouldTickSprite = sprite != null && sprite.isAnimated(); - } - - @Override - public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) { - if (this.shouldTickSprite) { - SpriteUtil.markSpriteActive(this.sprite); - } - - super.buildGeometry(vertexConsumer, camera, tickDelta); - } -} \ No newline at end of file diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/world_ticking/MixinClientWorld.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/world_ticking/MixinClientWorld.java deleted file mode 100644 index cd8f299ba..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/world_ticking/MixinClientWorld.java +++ /dev/null @@ -1,111 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.world_ticking; - -import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.fluid.FluidState; -import net.minecraft.particle.ParticleEffect; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.profiler.Profiler; -import net.minecraft.util.registry.RegistryKey; -import net.minecraft.world.MutableWorldProperties; -import net.minecraft.world.World; -import net.minecraft.world.biome.BiomeParticleConfig; -import net.minecraft.world.dimension.DimensionType; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.Random; -import java.util.function.Supplier; - -@Mixin(ClientWorld.class) -public abstract class MixinClientWorld extends World { - @Shadow - protected abstract void addParticle(BlockPos pos, BlockState state, ParticleEffect parameters, boolean bl); - - protected MixinClientWorld(MutableWorldProperties mutableWorldProperties, RegistryKey registryKey, - DimensionType dimensionType, Supplier profiler, boolean bl, boolean bl2, long l) { - super(mutableWorldProperties, registryKey, dimensionType, profiler, bl, bl2, l); - } - - @Redirect(method = "doRandomBlockDisplayTicks", at = @At(value = "NEW", target = "java/util/Random")) - private Random redirectRandomTickRandom() { - return new XoRoShiRoRandom(); - } - - /** - * @reason Avoid allocations, branch code out, early-skip some code - * @author JellySquid - */ - @Overwrite - public void randomBlockDisplayTick(int xCenter, int yCenter, int zCenter, int radius, Random random, boolean spawnBarrierParticles, BlockPos.Mutable pos) { - int x = xCenter + (random.nextInt(radius) - random.nextInt(radius)); - int y = yCenter + (random.nextInt(radius) - random.nextInt(radius)); - int z = zCenter + (random.nextInt(radius) - random.nextInt(radius)); - - pos.set(x, y, z); - - BlockState blockState = this.getBlockState(pos); - - if (!blockState.isAir()) { - this.performBlockDisplayTick(blockState, pos, random, spawnBarrierParticles); - } - - if (!blockState.isFullCube(this, pos)) { - this.performBiomeParticleDisplayTick(pos, random); - } - - FluidState fluidState = blockState.getFluidState(); - - if (!fluidState.isEmpty()) { - this.performFluidDisplayTick(blockState, fluidState, pos, random); - } - } - - private void performBlockDisplayTick(BlockState blockState, BlockPos pos, Random random, boolean spawnBarrierParticles) { - blockState.getBlock().randomDisplayTick(blockState, this, pos, random); - - if (spawnBarrierParticles && blockState.isOf(Blocks.BARRIER)) { - this.performBarrierDisplayTick(pos); - } - } - - private void performBarrierDisplayTick(BlockPos pos) { - this.addParticle(ParticleTypes.BARRIER, pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, - 0.0D, 0.0D, 0.0D); - } - - private void performBiomeParticleDisplayTick(BlockPos pos, Random random) { - BiomeParticleConfig config = this.getBiome(pos) - .getParticleConfig() - .orElse(null); - - if (config != null && config.shouldAddParticle(random)) { - this.addParticle(config.getParticle(), - pos.getX() + random.nextDouble(), - pos.getY() + random.nextDouble(), - pos.getZ() + random.nextDouble(), - 0.0D, 0.0D, 0.0D); - } - } - - private void performFluidDisplayTick(BlockState blockState, FluidState fluidState, BlockPos pos, Random random) { - fluidState.randomDisplayTick(this, pos, random); - - ParticleEffect particleEffect = fluidState.getParticle(); - - if (particleEffect != null && random.nextInt(10) == 0) { - boolean solid = blockState.isSideSolidFullSquare(this, pos, Direction.DOWN); - - // FIXME: don't allocate here - BlockPos blockPos = pos.down(); - this.addParticle(blockPos, this.getBlockState(blockPos), particleEffect, solid); - } - } -} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java index 6bf1b01d5..99153fbc6 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java @@ -1,16 +1,16 @@ package net.coderbot.batchedentityrendering.impl; import com.gtnewhorizons.angelica.compat.mojang.DrawState; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import java.nio.ByteBuffer; public class BufferSegment { private final ByteBuffer slice; private final DrawState drawState; - private final RenderType type; + private final RenderLayer type; - public BufferSegment(ByteBuffer slice, DrawState drawState, RenderType type) { + public BufferSegment(ByteBuffer slice, DrawState drawState, RenderLayer type) { this.slice = slice; this.drawState = drawState; this.type = type; @@ -24,7 +24,7 @@ public DrawState getDrawState() { return drawState; } - public RenderType getRenderType() { + public RenderLayer getRenderType() { return type; } } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java index b512068c1..870be16f5 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java @@ -4,7 +4,7 @@ import net.coderbot.batchedentityrendering.impl.ordering.RenderOrderManager; import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; import com.gtnewhorizons.angelica.compat.mojang.BufferSource; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import net.coderbot.iris.fantastic.WrappingMultiBufferSource; import net.minecraft.client.Minecraft; @@ -27,14 +27,14 @@ public class FullyBufferedMultiBufferSource extends BufferSource implements Memo /** * An LRU cache mapping RenderType objects to a relevant buffer. */ - private final LinkedHashMap affinities; + private final LinkedHashMap affinities; private int drawCalls; private int renderTypes; private final BufferSegmentRenderer segmentRenderer; private final UnflushableWrapper unflushableWrapper; - private final List> wrappingFunctionStack; - private Function wrappingFunction = null; + private final List> wrappingFunctionStack; + private Function wrappingFunction = null; public FullyBufferedMultiBufferSource() { super(new BufferBuilder(0), Collections.emptyMap()); @@ -56,7 +56,7 @@ public FullyBufferedMultiBufferSource() { } @Override - public VertexConsumer getBuffer(RenderType renderType) { + public VertexConsumer getBuffer(RenderLayer renderType) { if (wrappingFunction != null) { renderType = wrappingFunction.apply(renderType); } @@ -70,8 +70,8 @@ public VertexConsumer getBuffer(RenderType renderType) { } else { // We remove the element from the map that is used least-frequently. // With how we've configured our LinkedHashMap, that is the first element. - Iterator> iterator = affinities.entrySet().iterator(); - Map.Entry evicted = iterator.next(); + Iterator> iterator = affinities.entrySet().iterator(); + Map.Entry evicted = iterator.next(); iterator.remove(); // The previous type is no longer associated with this buffer ... @@ -93,7 +93,7 @@ public void endBatch() { profiler.startSection("collect"); - Map> typeToSegment = new HashMap<>(); + Map> typeToSegment = new HashMap<>(); for (SegmentedBufferBuilder builder : builders) { List segments = builder.getSegments(); @@ -105,11 +105,11 @@ public void endBatch() { profiler.endStartSection("resolve ordering"); - Iterable renderOrder = renderOrderManager.getRenderOrder(); + Iterable renderOrder = renderOrderManager.getRenderOrder(); profiler.endStartSection("draw buffers"); - for (RenderType type : renderOrder) { + for (RenderLayer type : renderOrder) { type.setupRenderState(); renderTypes += 1; @@ -144,7 +144,7 @@ public void resetDrawCalls() { } @Override - public void endBatch(RenderType type) { + public void endBatch(RenderLayer type) { // Disable explicit flushing } @@ -190,7 +190,7 @@ public void endGroup() { } @Override - public void pushWrappingFunction(Function wrappingFunction) { + public void pushWrappingFunction(Function wrappingFunction) { if (this.wrappingFunction != null) { this.wrappingFunctionStack.add(this.wrappingFunction); } @@ -227,7 +227,7 @@ private static class UnflushableWrapper extends BufferSource implements Groupabl } @Override - public VertexConsumer getBuffer(RenderType renderType) { + public VertexConsumer getBuffer(RenderLayer renderType) { return wrapped.getBuffer(renderType); } @@ -237,7 +237,7 @@ public void endBatch() { } @Override - public void endBatch(RenderType type) { + public void endBatch(RenderLayer type) { // Disable explicit flushing } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java index 1a1a5ba6f..01256851c 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java @@ -4,7 +4,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; import com.gtnewhorizons.angelica.compat.mojang.BufferSource; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import java.util.ArrayList; @@ -17,13 +17,13 @@ import java.util.Set; public class OldFullyBufferedMultiBufferSource extends BufferSource { - private final Map bufferBuilders; - private final Object2IntMap unused; + private final Map bufferBuilders; + private final Object2IntMap unused; private final Set activeBuffers; private boolean flushed; - private final Set typesThisFrame; - private final List typesInOrder; + private final Set typesThisFrame; + private final List typesInOrder; public OldFullyBufferedMultiBufferSource() { super(new BufferBuilder(0), Collections.emptyMap()); @@ -37,7 +37,7 @@ public OldFullyBufferedMultiBufferSource() { this.typesInOrder = new ArrayList<>(); } - private TransparencyType getTransparencyType(RenderType type) { + private TransparencyType getTransparencyType(RenderLayer type) { while (type instanceof WrappableRenderType) { type = ((WrappableRenderType) type).unwrap(); } @@ -51,7 +51,7 @@ private TransparencyType getTransparencyType(RenderType type) { } @Override - public VertexConsumer getBuffer(RenderType renderType) { + public VertexConsumer getBuffer(RenderLayer renderType) { flushed = false; BufferBuilder buffer = bufferBuilders.computeIfAbsent(renderType, type -> new BufferBuilder(type.bufferSize())); @@ -84,7 +84,7 @@ public void endBatch() { return; } - List removedTypes = new ArrayList<>(); + List removedTypes = new ArrayList<>(); unused.forEach((unusedType, unusedCount) -> { if (unusedCount < 10) { @@ -101,14 +101,14 @@ public void endBatch() { } }); - for (RenderType removed : removedTypes) { + for (RenderLayer removed : removedTypes) { unused.removeInt(removed); } // Make sure translucent types are rendered after non-translucent ones. typesInOrder.sort(Comparator.comparing(this::getTransparencyType)); - for (RenderType type : typesInOrder) { + for (RenderLayer type : typesInOrder) { drawInternal(type); } @@ -119,11 +119,11 @@ public void endBatch() { } @Override - public void endBatch(RenderType type) { + public void endBatch(RenderLayer type) { // Disable explicit flushing } - private void drawInternal(RenderType type) { + private void drawInternal(RenderLayer type) { BufferBuilder buffer = bufferBuilders.get(type); if (buffer == null) { diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java index 1897d2d58..2ad098b6a 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java @@ -1,10 +1,10 @@ package net.coderbot.batchedentityrendering.impl; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import org.lwjgl.opengl.GL11; public class RenderTypeUtil { - public static boolean isTriangleStripDrawMode(RenderType renderType) { + public static boolean isTriangleStripDrawMode(RenderLayer renderType) { return renderType.mode() == GL11.GL_TRIANGLE_STRIP; } } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java b/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java index b7084412f..6efd95852 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java @@ -3,7 +3,7 @@ import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; import com.gtnewhorizons.angelica.compat.mojang.DrawState; import com.gtnewhorizons.angelica.compat.mojang.MultiBufferSource; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import org.apache.commons.lang3.tuple.Pair; @@ -15,8 +15,8 @@ public class SegmentedBufferBuilder implements MultiBufferSource, MemoryTrackingBuffer { private final BufferBuilder buffer; - private final List usedTypes; - private RenderType currentType; + private final List usedTypes; + private RenderLayer currentType; public SegmentedBufferBuilder() { // 2 MB initial allocation @@ -27,7 +27,7 @@ public SegmentedBufferBuilder() { } @Override - public VertexConsumer getBuffer(RenderType renderType) { + public VertexConsumer getBuffer(RenderLayer renderType) { if (!Objects.equals(currentType, renderType)) { if (currentType != null) { if (shouldSortOnUpload(currentType)) { @@ -70,7 +70,7 @@ public List getSegments() { List segments = new ArrayList<>(usedTypes.size()); - for (RenderType type : usedTypes) { + for (RenderLayer type : usedTypes) { Pair pair = buffer.popNextBuffer(); DrawState drawState = pair.getLeft(); @@ -84,7 +84,7 @@ public List getSegments() { return segments; } - private static boolean shouldSortOnUpload(RenderType type) { + private static boolean shouldSortOnUpload(RenderLayer type) { return type.shouldSortOnUpload(); } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java b/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java index b4054de23..026ea5ad8 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java @@ -1,10 +1,10 @@ package net.coderbot.batchedentityrendering.impl; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; public interface WrappableRenderType { /** * Returns the underlying wrapped RenderType. Might return itself if this RenderType doesn't wrap anything. */ - RenderType unwrap(); + RenderLayer unwrap(); } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java index 82b52e1ba..fbdda0129 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java @@ -10,7 +10,7 @@ import net.coderbot.batchedentityrendering.impl.BlendingStateHolder; import net.coderbot.batchedentityrendering.impl.TransparencyType; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import java.util.ArrayList; import java.util.EnumMap; @@ -18,10 +18,10 @@ public class GraphTranslucencyRenderOrderManager implements RenderOrderManager { private final FeedbackArcSetProvider feedbackArcSetProvider; - private final EnumMap> types; + private final EnumMap> types; private boolean inGroup = false; - private final EnumMap currentTypes; + private final EnumMap currentTypes; public GraphTranslucencyRenderOrderManager() { feedbackArcSetProvider = new SimpleFeedbackArcSetProvider(); @@ -33,7 +33,7 @@ public GraphTranslucencyRenderOrderManager() { } } - private static TransparencyType getTransparencyType(RenderType type) { + private static TransparencyType getTransparencyType(RenderLayer type) { while (type instanceof WrappableRenderType) { type = ((WrappableRenderType) type).unwrap(); } @@ -46,13 +46,13 @@ private static TransparencyType getTransparencyType(RenderType type) { return TransparencyType.GENERAL_TRANSPARENT; } - public void begin(RenderType renderType) { + public void begin(RenderLayer renderType) { TransparencyType transparencyType = getTransparencyType(renderType); - Digraph graph = types.get(transparencyType); + Digraph graph = types.get(transparencyType); graph.add(renderType); if (inGroup) { - RenderType previous = currentTypes.put(transparencyType, renderType); + RenderLayer previous = currentTypes.put(transparencyType, renderType); if (previous == null) { return; @@ -102,21 +102,21 @@ public void reset() { } } - public Iterable getRenderOrder() { + public Iterable getRenderOrder() { int layerCount = 0; - for (Digraph graph : types.values()) { + for (Digraph graph : types.values()) { layerCount += graph.getVertexCount(); } - List allLayers = new ArrayList<>(layerCount); + List allLayers = new ArrayList<>(layerCount); - for (Digraph graph : types.values()) { + for (Digraph graph : types.values()) { // TODO: Make sure that FAS can't become a bottleneck! // Running NP-hard algorithms in a real time rendering loop might not be an amazing idea. // This shouldn't be necessary in sane scenes, though, and if there aren't cycles, // then this *should* be relatively inexpensive, since it'll bail out and return an empty set. - FeedbackArcSet arcSet = + FeedbackArcSet arcSet = feedbackArcSetProvider.getFeedbackArcSet(graph, graph, FeedbackArcSetPolicy.MIN_WEIGHT); if (arcSet.getEdgeCount() > 0) { @@ -125,8 +125,8 @@ public Iterable getRenderOrder() { // Our feedback arc set algorithm finds some dependency links that can be removed hopefully // without disrupting the overall order too much. Hopefully it isn't too slow! - for (RenderType source : arcSet.vertices()) { - for (RenderType target : arcSet.targets(source)) { + for (RenderLayer source : arcSet.vertices()) { + for (RenderLayer target : arcSet.targets(source)) { graph.remove(source, target); } } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java index cd75ad501..b3067c008 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java @@ -1,12 +1,12 @@ package net.coderbot.batchedentityrendering.impl.ordering; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; public interface RenderOrderManager { - void begin(RenderType type); + void begin(RenderLayer type); void startGroup(); boolean maybeStartGroup(); void endGroup(); void reset(); - Iterable getRenderOrder(); + Iterable getRenderOrder(); } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java index ddbeddc24..c3ecb0235 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java @@ -1,17 +1,17 @@ package net.coderbot.batchedentityrendering.impl.ordering; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import java.util.LinkedHashSet; public class SimpleRenderOrderManager implements RenderOrderManager { - private final LinkedHashSet renderTypes; + private final LinkedHashSet renderTypes; public SimpleRenderOrderManager() { renderTypes = new LinkedHashSet<>(); } - public void begin(RenderType type) { + public void begin(RenderLayer type) { renderTypes.add(type); } @@ -33,7 +33,7 @@ public void reset() { renderTypes.clear(); } - public Iterable getRenderOrder() { + public Iterable getRenderOrder() { return renderTypes; } } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java index f320be937..6a210b775 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java @@ -3,7 +3,7 @@ import net.coderbot.batchedentityrendering.impl.BlendingStateHolder; import net.coderbot.batchedentityrendering.impl.TransparencyType; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import java.util.ArrayList; import java.util.EnumMap; @@ -11,7 +11,7 @@ import java.util.List; public class TranslucencyRenderOrderManager implements RenderOrderManager { - private final EnumMap> renderTypes; + private final EnumMap> renderTypes; public TranslucencyRenderOrderManager() { renderTypes = new EnumMap<>(TransparencyType.class); @@ -21,7 +21,7 @@ public TranslucencyRenderOrderManager() { } } - private static TransparencyType getTransparencyType(RenderType type) { + private static TransparencyType getTransparencyType(RenderLayer type) { while (type instanceof WrappableRenderType) { type = ((WrappableRenderType) type).unwrap(); } @@ -34,7 +34,7 @@ private static TransparencyType getTransparencyType(RenderType type) { return TransparencyType.GENERAL_TRANSPARENT; } - public void begin(RenderType type) { + public void begin(RenderLayer type) { renderTypes.get(getTransparencyType(type)).add(type); } @@ -58,16 +58,16 @@ public void reset() { }); } - public Iterable getRenderOrder() { + public Iterable getRenderOrder() { int layerCount = 0; - for (LinkedHashSet set : renderTypes.values()) { + for (LinkedHashSet set : renderTypes.values()) { layerCount += set.size(); } - List allRenderTypes = new ArrayList<>(layerCount); + List allRenderTypes = new ArrayList<>(layerCount); - for (LinkedHashSet set : renderTypes.values()) { + for (LinkedHashSet set : renderTypes.values()) { allRenderTypes.addAll(set); } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java index 0da70a272..9a7be847d 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java @@ -1,17 +1,17 @@ package net.coderbot.batchedentityrendering.impl.wrappers; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import org.jetbrains.annotations.Nullable; import java.util.Objects; import java.util.Optional; -public class TaggingRenderTypeWrapper extends RenderType implements WrappableRenderType { +public class TaggingRenderTypeWrapper extends RenderLayer implements WrappableRenderType { private final int tag; - private final RenderType wrapped; + private final RenderLayer wrapped; - public TaggingRenderTypeWrapper(String name, RenderType wrapped, int tag) { + public TaggingRenderTypeWrapper(String name, RenderLayer wrapped, int tag) { super(name, wrapped.format(), wrapped.mode(), wrapped.bufferSize(), wrapped.affectsCrumbling(), shouldSortOnUpload(wrapped), wrapped::setupRenderState, wrapped::clearRenderState); @@ -20,12 +20,12 @@ public TaggingRenderTypeWrapper(String name, RenderType wrapped, int tag) { } @Override - public RenderType unwrap() { + public RenderLayer unwrap() { return this.wrapped; } @Override - public Optional outline() { + public Optional outline() { return this.wrapped.outline(); } @@ -61,7 +61,7 @@ public String toString() { return "tagged(" +tag+ "):" + this.wrapped.toString(); } - private static boolean shouldSortOnUpload(RenderType type) { + private static boolean shouldSortOnUpload(RenderLayer type) { return true; // TODO: Iris // return ((RenderTypeAccessor) type).shouldSortOnUpload(); diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java index d8678a9d1..65386884a 100644 --- a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java @@ -4,7 +4,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import net.coderbot.iris.shaderpack.materialmap.BlockEntry; import net.coderbot.iris.shaderpack.materialmap.BlockRenderType; import net.coderbot.iris.shaderpack.materialmap.NamespacedId; @@ -28,8 +28,8 @@ public static Object2IntMap createBlockStateIdMap(Int2ObjectMap createBlockTypeMap(Map blockPropertiesMap) { - Map blockTypeIds = new Reference2ReferenceOpenHashMap<>(); + public static Map createBlockTypeMap(Map blockPropertiesMap) { + Map blockTypeIds = new Reference2ReferenceOpenHashMap<>(); blockPropertiesMap.forEach((id, blockType) -> { ResourceLocation resourceLocation = new ResourceLocation(id.getNamespace(), id.getName()); @@ -42,7 +42,7 @@ public static Map createBlockTypeMap(Map blockStateIds; - private Map blockTypeIds; + private Map blockTypeIds; private Object2IntFunction entityIds; private float ambientOcclusionLevel; private boolean disableDirectionalShading; @@ -47,7 +47,7 @@ public Object2IntMap getBlockStateIds() { } @Nullable - public Map getBlockTypeIds() { + public Map getBlockTypeIds() { return blockTypeIds; } @@ -67,7 +67,7 @@ public void setBlockStateIds(Object2IntMap blockStateIds) { this.blockStateIds = blockStateIds; } - public void setBlockTypeIds(Map blockTypeIds) { + public void setBlockTypeIds(Map blockTypeIds) { if (this.blockTypeIds != null && this.blockTypeIds.equals(blockTypeIds)) { return; } diff --git a/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java b/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java index 00a8067bd..b5d9c3de3 100644 --- a/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java +++ b/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java @@ -1,10 +1,10 @@ package net.coderbot.iris.fantastic; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import java.util.function.Function; public interface WrappingMultiBufferSource { - void pushWrappingFunction(Function wrappingFunction); + void pushWrappingFunction(Function wrappingFunction); void popWrappingFunction(); void assertWrapStackEmpty(); } diff --git a/src/main/java/net/coderbot/iris/gl/shader/GlShader.java b/src/main/java/net/coderbot/iris/gl/shader/GlShader.java index 9955d562d..7ae367108 100644 --- a/src/main/java/net/coderbot/iris/gl/shader/GlShader.java +++ b/src/main/java/net/coderbot/iris/gl/shader/GlShader.java @@ -31,6 +31,7 @@ private static int createShader(ShaderType type, String name, String src) { int handle = GL20.glCreateShader(type.id); // TODO: Iris // ShaderWorkarounds.safeShaderSource(handle, src); + // TODO: ShaderWorkaround GL20.glShaderSource(handle, src + '\0'); GL20.glCompileShader(handle); diff --git a/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java index d93393004..fa942e968 100644 --- a/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java @@ -1,9 +1,9 @@ package net.coderbot.iris.layer; -import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; +import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; import net.coderbot.iris.uniforms.CapturedRenderingState; -public final class BlockEntityRenderStateShard extends RenderStateShard { +public final class BlockEntityRenderStateShard extends RenderPhase { private static final BlockEntityRenderStateShard UNIDENTIFIED = new BlockEntityRenderStateShard(-1); private final int entityId; diff --git a/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java index 32f1b9905..95ca0b5b9 100644 --- a/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java @@ -1,9 +1,9 @@ package net.coderbot.iris.layer; -import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; +import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; import net.coderbot.iris.uniforms.CapturedRenderingState; -public final class EntityRenderStateShard extends RenderStateShard { +public final class EntityRenderStateShard extends RenderPhase { private static final EntityRenderStateShard UNIDENTIFIED = new EntityRenderStateShard(-1); private final int entityId; diff --git a/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java index 78b5ef68a..7b9dfcec3 100644 --- a/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java @@ -1,8 +1,8 @@ package net.coderbot.iris.layer; -import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; +import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; -public class IsBlockEntityRenderStateShard extends RenderStateShard { +public class IsBlockEntityRenderStateShard extends RenderPhase { public static final IsBlockEntityRenderStateShard INSTANCE = new IsBlockEntityRenderStateShard(); private IsBlockEntityRenderStateShard() { diff --git a/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java index d3a435b43..6fc880954 100644 --- a/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java @@ -1,8 +1,8 @@ package net.coderbot.iris.layer; -import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; +import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; -public class IsEntityRenderStateShard extends RenderStateShard { +public class IsEntityRenderStateShard extends RenderPhase { public static final IsEntityRenderStateShard INSTANCE = new IsEntityRenderStateShard(); private IsEntityRenderStateShard() { diff --git a/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java index ba0799752..64509ce1e 100644 --- a/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java @@ -1,8 +1,8 @@ package net.coderbot.iris.layer; -import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; +import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; -public class IsOutlineRenderStateShard extends RenderStateShard { +public class IsOutlineRenderStateShard extends RenderPhase { public static final IsOutlineRenderStateShard INSTANCE = new IsOutlineRenderStateShard(); private IsOutlineRenderStateShard() { diff --git a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java index f842825ad..c709e2a5e 100644 --- a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java +++ b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java @@ -1,18 +1,18 @@ package net.coderbot.iris.layer; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import com.gtnewhorizons.angelica.compat.mojang.RenderStateShard; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import org.jetbrains.annotations.Nullable; import java.util.Objects; import java.util.Optional; -public class OuterWrappedRenderType extends RenderType implements WrappableRenderType { - private final RenderStateShard extra; - private final RenderType wrapped; +public class OuterWrappedRenderType extends RenderLayer implements WrappableRenderType { + private final RenderPhase extra; + private final RenderLayer wrapped; - private OuterWrappedRenderType(String name, RenderType wrapped, RenderStateShard extra) { + private OuterWrappedRenderType(String name, RenderLayer wrapped, RenderPhase extra) { super(name, wrapped.format(), wrapped.mode(), wrapped.bufferSize(), wrapped.affectsCrumbling(), shouldSortOnUpload(wrapped), wrapped::setupRenderState, wrapped::clearRenderState); @@ -20,7 +20,7 @@ private OuterWrappedRenderType(String name, RenderType wrapped, RenderStateShard this.wrapped = wrapped; } - public static OuterWrappedRenderType wrapExactlyOnce(String name, RenderType wrapped, RenderStateShard extra) { + public static OuterWrappedRenderType wrapExactlyOnce(String name, RenderLayer wrapped, RenderPhase extra) { if (wrapped instanceof OuterWrappedRenderType) { wrapped = ((OuterWrappedRenderType) wrapped).unwrap(); } @@ -43,12 +43,12 @@ public void clearRenderState() { } @Override - public RenderType unwrap() { + public RenderLayer unwrap() { return this.wrapped; } @Override - public Optional outline() { + public Optional outline() { return this.wrapped.outline(); } @@ -84,7 +84,7 @@ public String toString() { return "iris_wrapped:" + this.wrapped.toString(); } - private static boolean shouldSortOnUpload(RenderType type) { + private static boolean shouldSortOnUpload(RenderLayer type) { return true; // TODO: Iris // return ((RenderTypeAccessor) type).shouldSortOnUpload(); diff --git a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java index 49a5ddea2..7a2fcbdf3 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java @@ -4,7 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.GameRenderer; import com.gtnewhorizons.angelica.compat.mojang.InteractionHand; -import com.gtnewhorizons.angelica.compat.mojang.PoseStack; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import net.irisshaders.iris.api.v0.IrisApi; import net.minecraft.client.Minecraft; import net.minecraft.entity.EntityLiving; @@ -22,8 +22,8 @@ public class HandRenderer { public static final float DEPTH = 0.125F; - private void setupGlState(GameRenderer gameRenderer, Camera camera, PoseStack poseStack, float tickDelta) { - final PoseStack.Pose pose = poseStack.last(); + private void setupGlState(GameRenderer gameRenderer, Camera camera, MatrixStack poseStack, float tickDelta) { + final MatrixStack.Entry pose = poseStack.peek(); // We need to scale the matrix by 0.125 so the hand doesn't clip through blocks. Matrix4f scaleMatrix = new Matrix4f().scale(1F, 1F, DEPTH); @@ -35,8 +35,8 @@ private void setupGlState(GameRenderer gameRenderer, Camera camera, PoseStack po // RenderSystem.multMatrix(arg); // RenderSystem.matrixMode(5888); - pose.pose().identity(); - pose.normal().identity(); + pose.getModel().identity(); + pose.getNormal().identity(); gameRenderer.invokeBobHurt(poseStack, tickDelta); @@ -74,7 +74,7 @@ public boolean isAnyHandTranslucent() { return isHandTranslucent(InteractionHand.MAIN_HAND) || isHandTranslucent(InteractionHand.OFF_HAND); } - public void renderSolid(PoseStack poseStack, float tickDelta, Camera camera, GameRenderer gameRenderer, WorldRenderingPipeline pipeline) { + public void renderSolid(MatrixStack poseStack, float tickDelta, Camera camera, GameRenderer gameRenderer, WorldRenderingPipeline pipeline) { if (!canRender(camera, gameRenderer) || !IrisApi.getInstance().isShaderPackInUse()) { return; } @@ -109,7 +109,7 @@ public void renderSolid(PoseStack poseStack, float tickDelta, Camera camera, Gam ACTIVE = false; } - public void renderTranslucent(PoseStack poseStack, float tickDelta, Camera camera, GameRenderer gameRenderer, WorldRenderingPipeline pipeline) { + public void renderTranslucent(MatrixStack poseStack, float tickDelta, Camera camera, GameRenderer gameRenderer, WorldRenderingPipeline pipeline) { if (!canRender(camera, gameRenderer) || !isAnyHandTranslucent() || !IrisApi.getInstance().isShaderPackInUse()) { return; } diff --git a/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java index afb1c14ce..71bdc25a6 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java @@ -69,13 +69,13 @@ private void rebuildBuffer() { private void buildQuad(VertexConsumer consumer, double x1, double z1, double x2, double z2) { consumer.vertex(x1, BOTTOM, z1); - consumer.endVertex(); + consumer.next(); consumer.vertex(x1, TOP, z1); - consumer.endVertex(); + consumer.next(); consumer.vertex(x2, TOP, z2); - consumer.endVertex(); + consumer.next(); consumer.vertex(x2, BOTTOM, z2); - consumer.endVertex(); + consumer.next(); } private void buildHalf(VertexConsumer consumer, double adjacent, double opposite, boolean invert) { @@ -117,13 +117,13 @@ private void buildBottomPlane(VertexConsumer consumer, int radius) { for (int x = -radius; x <= radius; x += 64) { for (int z = -radius; z <= radius; z += 64) { consumer.vertex(x + 64, BOTTOM, z); - consumer.endVertex(); + consumer.next(); consumer.vertex(x, BOTTOM, z); - consumer.endVertex(); + consumer.next(); consumer.vertex(x, BOTTOM, z + 64); - consumer.endVertex(); + consumer.next(); consumer.vertex(x + 64, BOTTOM, z + 64); - consumer.endVertex(); + consumer.next(); } } } @@ -135,13 +135,13 @@ private void buildTopPlane(VertexConsumer consumer, int radius) { for (int x = -radius; x <= radius; x += 64) { for (int z = -radius; z <= radius; z += 64) { consumer.vertex(x + 64, TOP, z); - consumer.endVertex(); + consumer.next(); consumer.vertex(x + 64, TOP, z + 64); - consumer.endVertex(); + consumer.next(); consumer.vertex(x, TOP, z + 64); - consumer.endVertex(); + consumer.next(); consumer.vertex(x, TOP, z); - consumer.endVertex(); + consumer.next(); } } } diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 6440e6e7f..8bead198d 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -9,9 +9,9 @@ import com.gtnewhorizons.angelica.compat.mojang.BufferSource; import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.LevelRenderer; -import com.gtnewhorizons.angelica.compat.mojang.PoseStack; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.compat.mojang.RenderBuffers; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.shaderpack.OptionalBoolean; import net.coderbot.iris.shaderpack.PackDirectives; @@ -135,7 +135,7 @@ public void setUsesImages(boolean usesImages) { this.packHasVoxelization = packHasVoxelization || usesImages; } - public static PoseStack createShadowModelView(float sunPathRotation, float intervalSize) { + public static MatrixStack createShadowModelView(float sunPathRotation, float intervalSize) { // Determine the camera position Vector3d cameraPos = CameraUniforms.getUnshiftedCameraPosition(); @@ -144,7 +144,7 @@ public static PoseStack createShadowModelView(float sunPathRotation, float inter double cameraZ = cameraPos.z; // Set up our modelview matrix stack - PoseStack modelView = new PoseStack(); + MatrixStack modelView = new MatrixStack(); ShadowMatrices.createModelViewMatrix(modelView, getShadowAngle(), intervalSize, sunPathRotation, cameraX, cameraY, cameraZ); return modelView; @@ -265,7 +265,7 @@ private FrustumHolder createShadowFrustum(float renderMultiplier, FrustumHolder if (distance <= 0 || distance > Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16) { distanceInfo = Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16 - + " blocks (capped by normal render distance)"; + + " blocks (capped by getNormal render distance)"; cullingInfo = "disabled " + reason; return holder.setInfo(new NonCullingFrustum(), distanceInfo, cullingInfo); } else { @@ -289,7 +289,7 @@ private FrustumHolder createShadowFrustum(float renderMultiplier, FrustumHolder if (distance >= Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16) { distanceInfo = Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16 - + " blocks (capped by normal render distance)"; + + " blocks (capped by getNormal render distance)"; boxCuller = null; } else { distanceInfo = distance + " blocks " + setter; @@ -347,7 +347,7 @@ private void copyPreTranslucentDepth() { targets.copyPreTranslucentDepth(); } - private void renderEntities(LevelRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { + private void renderEntities(LevelRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { // TODO: Render // EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); @@ -386,7 +386,7 @@ private void renderEntities(LevelRenderer levelRenderer, Frustrum frustum, Buffe profiler.endSection(); } - private void renderPlayerEntity(LevelRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { + private void renderPlayerEntity(LevelRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { // TODO: Render // EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); @@ -423,7 +423,7 @@ private void renderPlayerEntity(LevelRenderer levelRenderer, Frustrum frustum, B profiler.endSection(); } - private void renderBlockEntities(BufferSource bufferSource, PoseStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta, boolean hasEntityFrustum) { + private void renderBlockEntities(BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta, boolean hasEntityFrustum) { profiler.startSection("build blockentities"); int shadowBlockEntities = 0; @@ -471,9 +471,9 @@ public void renderShadows(LevelRenderer levelRenderer, Camera playerCamera) { visibleTileEntities = new ArrayList<>(); // Create our camera - PoseStack modelView = createShadowModelView(this.sunPathRotation, this.intervalSize); + MatrixStack modelView = createShadowModelView(this.sunPathRotation, this.intervalSize); // TODO: Render -// MODELVIEW = modelView.last().pose().copy(); +// MODELVIEW = modelView.peek().getModel().copy(); float[] projMatrix; if (this.fov != null) { // If FOV is not null, the pack wants a perspective based projection matrix. (This is to support legacy packs) @@ -540,9 +540,9 @@ public void renderShadows(LevelRenderer levelRenderer, Camera playerCamera) { // Render all opaque terrain unless pack requests not to if (shouldRenderTerrain) { - levelRenderer.invokeRenderChunkLayer(RenderType.solid(), modelView, cameraX, cameraY, cameraZ); - levelRenderer.invokeRenderChunkLayer(RenderType.cutout(), modelView, cameraX, cameraY, cameraZ); - levelRenderer.invokeRenderChunkLayer(RenderType.cutoutMipped(), modelView, cameraX, cameraY, cameraZ); + levelRenderer.invokeRenderChunkLayer(RenderLayer.solid(), modelView, cameraX, cameraY, cameraZ); + levelRenderer.invokeRenderChunkLayer(RenderLayer.cutout(), modelView, cameraX, cameraY, cameraZ); + levelRenderer.invokeRenderChunkLayer(RenderLayer.cutoutMipped(), modelView, cameraX, cameraY, cameraZ); } profiler.endStartSection("entities"); @@ -601,10 +601,10 @@ public void renderShadows(LevelRenderer levelRenderer, Camera playerCamera) { profiler.endStartSection("translucent terrain"); // TODO: Prevent these calls from scheduling translucent sorting... - // It doesn't matter a ton, since this just means that they won't be sorted in the normal rendering pass. + // It doesn't matter a ton, since this just means that they won't be sorted in the getNormal rendering pass. // Just something to watch out for, however... if (shouldRenderTranslucent) { - levelRenderer.invokeRenderChunkLayer(RenderType.translucent(), modelView, cameraX, cameraY, cameraZ); + levelRenderer.invokeRenderChunkLayer(RenderLayer.translucent(), modelView, cameraX, cameraY, cameraZ); } // Note: Apparently tripwire isn't rendered in the shadow pass. diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java index de0bf5e75..7a2490f00 100644 --- a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java @@ -1,6 +1,6 @@ package net.coderbot.iris.pipeline; -import com.gtnewhorizons.angelica.compat.mojang.RenderType; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; public enum WorldRenderingPhase { NONE, @@ -28,16 +28,16 @@ public enum WorldRenderingPhase { WORLD_BORDER, HAND_TRANSLUCENT; - public static WorldRenderingPhase fromTerrainRenderType(RenderType renderType) { - if (renderType == RenderType.solid()) { + public static WorldRenderingPhase fromTerrainRenderType(RenderLayer renderType) { + if (renderType == RenderLayer.solid()) { return WorldRenderingPhase.TERRAIN_SOLID; - } else if (renderType == RenderType.cutout()) { + } else if (renderType == RenderLayer.cutout()) { return WorldRenderingPhase.TERRAIN_CUTOUT; - } else if (renderType == RenderType.cutoutMipped()) { + } else if (renderType == RenderLayer.cutoutMipped()) { return WorldRenderingPhase.TERRAIN_CUTOUT_MIPPED; - } else if (renderType == RenderType.translucent()) { + } else if (renderType == RenderLayer.translucent()) { return WorldRenderingPhase.TERRAIN_TRANSLUCENT; - } else if (renderType == RenderType.tripwire()) { + } else if (renderType == RenderLayer.tripwire()) { return WorldRenderingPhase.TRIPWIRE; } else { throw new IllegalStateException("Illegal render type!"); diff --git a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java index 4ef230d26..63d7d557c 100644 --- a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java +++ b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java @@ -1,6 +1,6 @@ package net.coderbot.iris.shadow; -import com.gtnewhorizons.angelica.compat.mojang.PoseStack; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import org.joml.Matrix4f; import java.nio.FloatBuffer; @@ -41,7 +41,7 @@ public static float[] createPerspectiveMatrix(float fov) { }; } - public static void createBaselineModelViewMatrix(PoseStack target, float shadowAngle, float sunPathRotation) { + public static void createBaselineModelViewMatrix(MatrixStack target, float shadowAngle, float sunPathRotation) { float skyAngle; if (shadowAngle < 0.25f) { @@ -50,16 +50,16 @@ public static void createBaselineModelViewMatrix(PoseStack target, float shadowA skyAngle = shadowAngle - 0.25f; } - target.last().normal().identity(); - target.last().pose().identity(); + target.peek().getNormal().identity(); + target.peek().getModel().identity(); - target.last().pose().translate(0.0f, 0.0f, -100.0f); + target.peek().getModel().translate(0.0f, 0.0f, -100.0f); target.rotateX(90F * DEGREES_TO_RADIANS); target.rotateZ(sunPathRotation * DEGREES_TO_RADIANS); target.rotateZ(skyAngle * -360.0f * DEGREES_TO_RADIANS); } - public static void snapModelViewToGrid(PoseStack target, float shadowIntervalSize, double cameraX, double cameraY, double cameraZ) { + public static void snapModelViewToGrid(MatrixStack target, float shadowIntervalSize, double cameraX, double cameraY, double cameraZ) { if (Math.abs(shadowIntervalSize) == 0.0F) { // Avoid a division by zero - semantically, this just means that the snapping does not take place, // if the shadow interval (size of each grid "cell") is zero. @@ -87,10 +87,10 @@ public static void snapModelViewToGrid(PoseStack target, float shadowIntervalSiz offsetY -= halfIntervalSize; offsetZ -= halfIntervalSize; - target.last().pose().translate(offsetX, offsetY, offsetZ); + target.peek().getModel().translate(offsetX, offsetY, offsetZ); } - public static void createModelViewMatrix(PoseStack target, float shadowAngle, float shadowIntervalSize, + public static void createModelViewMatrix(MatrixStack target, float shadowAngle, float shadowIntervalSize, float sunPathRotation, double cameraX, double cameraY, double cameraZ) { createBaselineModelViewMatrix(target, shadowAngle, sunPathRotation); snapModelViewToGrid(target, shadowIntervalSize, cameraX, cameraY, cameraZ); @@ -152,7 +152,7 @@ public static void main(String[] args) { 1 }; - PoseStack modelView = new PoseStack(); + MatrixStack modelView = new MatrixStack(); // NB: At dawn, the shadow angle is NOT zero. // When DayTime=0, skyAngle = 282 degrees. @@ -160,7 +160,7 @@ public static void main(String[] args) { createModelViewMatrix(modelView, 0.03451777f, 2.0f, 0.0f, 0.646045982837677f, 82.53274536132812f, -514.0264282226562f); - test("model view at dawn", expectedModelViewAtDawn, toFloatArray(modelView.last().pose())); + test("model view at dawn", expectedModelViewAtDawn, toFloatArray(modelView.peek().getModel())); } private static float[] toFloatArray(Matrix4f matrix4f) { diff --git a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java index 6fb288ef8..5f7a8b153 100644 --- a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java @@ -20,7 +20,7 @@ public static void addMatrixUniforms(UniformHolder uniforms, PackDirectives dire // TODO: In some cases, gbufferProjectionInverse takes on a value much different than OptiFine... // We need to audit Mojang's linear algebra. addMatrix(uniforms, "Projection", CapturedRenderingState.INSTANCE::getGbufferProjection); - addShadowMatrix(uniforms, "ModelView", () -> ShadowRenderer.createShadowModelView(directives.getSunPathRotation(), directives.getShadowDirectives().getIntervalSize()).last().pose()); + addShadowMatrix(uniforms, "ModelView", () -> ShadowRenderer.createShadowModelView(directives.getSunPathRotation(), directives.getShadowDirectives().getIntervalSize()).peek().getModel()); addShadowArrayMatrix(uniforms, "Projection", () -> ShadowMatrices.createOrthoMatrix(directives.getShadowDirectives().getDistance())); } From 566adcf1e3f02ff932905b969f8e8f8d8f52fb52 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 5 Nov 2023 18:33:42 -0800 Subject: [PATCH 034/301] More 1.7.10ify --- .../angelica/compat/forge/EmptyModelData.java | 7 + .../compat/forge/ForgeHooksClientExt.java | 20 +++ .../angelica/compat/mojang/BiomeAccess.java | 4 +- .../compat/mojang/BiomeAccessType.java | 4 +- .../compat/mojang/BlockBreakingInfo.java | 15 ++ .../compat/mojang/BlockColorProvider.java | 4 +- .../angelica/compat/mojang/BlockModels.java | 6 + .../angelica/compat/mojang/BlockPos.java | 5 + .../compat/mojang/BlockRenderView.java | 5 +- .../angelica/compat/mojang/BlockState.java | 35 ++++- .../compat/mojang/BufferBuilderStorage.java | 12 ++ .../mojang/ChunkOcclusionDataBuilder.java | 8 + .../angelica/compat/mojang/ChunkPos.java | 30 ++++ .../compat/mojang/ChunkSectionPos.java | 36 +++++ .../angelica/compat/mojang/ColorResolver.java | 4 +- .../angelica/compat/mojang/FluidState.java | 27 ++++ .../angelica/compat/mojang/IdList.java | 61 ++++++++ .../compat/mojang/IndexedIterable.java | 10 ++ .../compat/mojang/ItemColorProvider.java | 7 + .../compat/mojang/LightingProvider.java | 10 ++ .../angelica/compat/mojang/LightingView.java | 9 ++ .../angelica/compat/mojang/MatrixStack.java | 4 +- .../angelica/compat/mojang/ModelLoader.java | 9 ++ .../compat/mojang/OverlayVertexConsumer.java | 50 +++++++ .../compat/mojang/PackedIntegerArray.java | 3 + .../mojang/{Biome.java => Palette.java} | 2 +- .../compat/mojang/PalettedContainer.java | 5 + .../angelica/compat/mojang/RenderLayer.java | 6 + .../angelica/compat/mojang/RenderLayers.java | 11 ++ .../angelica/compat/mojang/SideShapeType.java | 7 + .../compat/mojang/VertexConsumerProvider.java | 7 + .../angelica/compat/mojang/VoxelShapes.java | 10 ++ .../mods/sodium/client/SodiumClientMod.java | 16 +- .../sodium/client/gui/SodiumGameOptions.java | 137 ++++++++++++++++++ .../client/model/light/EntityLighter.java | 3 +- .../quad/blender/BlockColorSettings.java | 18 ++- .../client/render/GameRendererContext.java | 21 +-- .../client/render/SodiumWorldRenderer.java | 17 ++- .../render/chunk/ChunkRenderManager.java | 4 +- .../render/chunk/shader/ChunkProgram.java | 6 +- .../chunk/tasks/ChunkRenderRebuildTask.java | 13 +- .../client/render/pipeline/FluidRenderer.java | 57 ++++---- .../context/ChunkRenderCacheLocal.java | 4 +- .../client/util/math/Matrix3fExtended.java | 2 +- .../client/util/math/Matrix4fExtended.java | 2 +- .../mods/sodium/client/world/WorldSlice.java | 20 +-- .../sodium/client/world/WorldSliceLocal.java | 94 ++++++------ .../sodium/client/world/biome/BiomeCache.java | 10 +- .../world/biome/ItemColorsExtended.java | 1 + .../world/cloned/ClonedChunkSection.java | 53 ++++--- .../cloned/PalettedContainerExtended.java | 4 +- .../cloned/palette/ClonedPaletteFallback.java | 1 + .../coderbot/iris/pipeline/HandRenderer.java | 8 +- .../iris/pipeline/ShadowRenderer.java | 4 +- 54 files changed, 765 insertions(+), 163 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/EmptyModelData.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeHooksClientExt.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ItemColorProvider.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingProvider.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingView.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ModelLoader.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java rename src/main/java/com/gtnewhorizons/angelica/compat/mojang/{Biome.java => Palette.java} (64%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/PalettedContainer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/EmptyModelData.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/EmptyModelData.java new file mode 100644 index 000000000..273d59019 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/EmptyModelData.java @@ -0,0 +1,7 @@ +package com.gtnewhorizons.angelica.compat.forge; + +public enum EmptyModelData implements IModelData { + INSTANCE; + + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeHooksClientExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeHooksClientExt.java new file mode 100644 index 000000000..31732fe12 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeHooksClientExt.java @@ -0,0 +1,20 @@ +package com.gtnewhorizons.angelica.compat.forge; + +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.compat.mojang.FluidState; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; + +public class ForgeHooksClientExt { + + static final ThreadLocal renderLayer = new ThreadLocal<>(); + + public static void setRenderLayer(RenderLayer layer) { + renderLayer.set(layer); + } + + public static TextureAtlasSprite[] getFluidSprites(BlockRenderView world, BlockPos pos, FluidState fluidState) { + return new TextureAtlasSprite[0]; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java index 3b2424ba1..638f10620 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java @@ -1,7 +1,9 @@ package com.gtnewhorizons.angelica.compat.mojang; +import net.minecraft.world.biome.BiomeGenBase; + public class BiomeAccess { public interface Storage { - Biome getBiomeForNoiseGen(int biomeX, int biomeY, int biomeZ); + BiomeGenBase getBiomeForNoiseGen(int biomeX, int biomeY, int biomeZ); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java index 404f49182..81d699bd6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java @@ -1,6 +1,8 @@ package com.gtnewhorizons.angelica.compat.mojang; +import net.minecraft.world.biome.BiomeGenBase; + public interface BiomeAccessType { - Biome getBiome(long seed, int x, int y, int z, BiomeAccess.Storage storage); + BiomeGenBase getBiome(long seed, int x, int y, int z, BiomeAccess.Storage storage); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java new file mode 100644 index 000000000..a0f96c7d4 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java @@ -0,0 +1,15 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import org.jetbrains.annotations.NotNull; + +public class BlockBreakingInfo implements Comparable { + + @Override + public int compareTo(@NotNull BlockBreakingInfo o) { + return 0; + } + + public int getStage() { + return 0; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java index be4697e2b..3993b64c0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java @@ -1,5 +1,7 @@ package com.gtnewhorizons.angelica.compat.mojang; -public class BlockColorProvider { +import javax.annotation.Nullable; +public interface BlockColorProvider { + int getColor(BlockState state, @Nullable BlockRenderView world, @Nullable BlockPos pos, int tintIndex); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java new file mode 100644 index 000000000..be8f69f79 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java @@ -0,0 +1,6 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class BlockModels { + + public BakedModel getModel(BlockState blockState) { return null; } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java index c9d71a364..4d9bd1feb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.compat.mojang; import net.minecraft.util.MathHelper; +import net.minecraft.world.ChunkPosition; import org.joml.Vector3i; import java.math.RoundingMode; @@ -25,6 +26,10 @@ public BlockPos(int x, int y, int z) { super(x, y, z); } + public BlockPos(ChunkPosition chunkPosition) { + super(chunkPosition.chunkPosX, chunkPosition.chunkPosY, chunkPosition.chunkPosZ); + } + public int getX() { return this.x; } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java index 8915878a1..0b8277ec1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.compat.mojang; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.common.util.ForgeDirection; public interface BlockRenderView extends BlockView { @@ -19,5 +20,7 @@ public interface BlockRenderView extends BlockView { boolean isSkyVisible(BlockPos pos); - Biome getBiomeForNoiseGen(int x, int y, int z); + BiomeGenBase getBiomeForNoiseGen(int x, int y, int z); + + FluidState getFluidState(BlockPos set); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java index 30db9e694..0cc714bb5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.compat.mojang; import com.gtnewhorizons.angelica.compat.forge.IForgeBlockState; +import net.minecraft.block.material.Material; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import org.joml.Vector3d; @@ -19,7 +20,7 @@ public VoxelShape getCullingFace(BlockView view, BlockPos pos, ForgeDirection fa return null; } - public int getLightValue(BlockRenderView world, BlockPos pos) { return 15;} + public int getLightValue(World world, BlockPos pos) { return 15;} public float getAmbientOcclusionLightLevel(BlockRenderView world, BlockPos pos) { return 1.0f; } @@ -46,4 +47,36 @@ public Vector3d getModelOffset(BlockRenderView world, BlockPos pos) { public boolean isAir() { return false; } + + public BlockRenderType getRenderType() { + return BlockRenderType.MODEL; + } + + public boolean hasTileEntity() { + return true; + } + + public long getRenderingSeed(BlockPos.Mutable pos) { + return 0; + } + + public FluidState getFluidState() { + return null; + } + + public boolean shouldDisplayFluidOverlay(BlockRenderView world, BlockPos adjPos, FluidState fluidState) { + return true; + } + + public Material getMaterial() { + return null; + } + + public boolean isSideSolid(BlockRenderView world, BlockPos pos, ForgeDirection dir, SideShapeType sideShapeType) { + return true; + } + + public VoxelShape getCullingShape(BlockRenderView world, BlockPos pos) { + return null; + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java new file mode 100644 index 000000000..c1a87c4c7 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java @@ -0,0 +1,12 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class BufferBuilderStorage { + + public VertexConsumerProvider.Immediate getEntityVertexConsumers() { + return null; + } + + public MultiBufferSource getEffectVertexConsumers() { + return null; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java new file mode 100644 index 000000000..1d3124b35 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java @@ -0,0 +1,8 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class ChunkOcclusionDataBuilder { + + public ChunkOcclusionData build() { + return null; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java new file mode 100644 index 000000000..0654702d1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java @@ -0,0 +1,30 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +// ChunkCoordIntPair +public class ChunkPos { + public final int x; + public final int z; + + public ChunkPos(int x, int z) { + this.x = x; + this.z = z; + } + + public ChunkPos(BlockPos pos) { + this.x = pos.getX() >> 4; + this.z = pos.getZ() >> 4; + } + + public ChunkPos(long pos) { + this.x = (int)pos; + this.z = (int)(pos >> 32); + } + + public long toLong() { + return toLong(this.x, this.z); + } + + public static long toLong(int x, int z) { + return (long)x & 4294967295L | ((long)z & 4294967295L) << 32; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java index 5c27d7d88..ff1180a71 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java @@ -2,7 +2,16 @@ import org.joml.Vector3i; +// ChunkPosition maybe? public class ChunkSectionPos extends Vector3i { + + public static int getSectionCoord(int coord) { + return coord >> 4; + } + public static int getBlockCoord(int sectionCoord) { + return sectionCoord << 4; + } + private ChunkSectionPos(int x, int y, int z) { super(x, y, z); } @@ -10,6 +19,9 @@ public static ChunkSectionPos from(int x, int y, int z) { return new ChunkSectionPos(x, y, z); } + public static ChunkSectionPos from(BlockPos pos) { + return new ChunkSectionPos(getSectionCoord(pos.getX()), getSectionCoord(pos.getY()), getSectionCoord(pos.getZ())); + } public static long asLong(int x, int y, int z) { long l = 0L; @@ -18,10 +30,30 @@ public static long asLong(int x, int y, int z) { l |= ((long)z & 4194303L) << 20; return l; } + + public static int getLocalCoord(int coord) { + return coord & 15; + } + + public static short packLocal(BlockPos pos) { + int i = getLocalCoord(pos.x); + int j = getLocalCoord(pos.y); + int k = getLocalCoord(pos.z); + return (short)(i << 8 | k << 4 | j << 0); + } + public long asLong() { return asLong(this.x, this.y, this.z); } + public int getSectionY() { + return this.y; + } + + public int getSectionZ() { + return this.z; + } + public int getMinX() { return this.x << 4; } @@ -45,4 +77,8 @@ public int getMaxY() { public int getMaxZ() { return (this.z << 4) + 15; } + + public ChunkPos toChunkPos() { + return new ChunkPos(this.getSectionX(), this.getSectionZ()); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java index 19c413049..a0a2cba28 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java @@ -1,6 +1,8 @@ package com.gtnewhorizons.angelica.compat.mojang; +import net.minecraft.world.biome.BiomeGenBase; + public interface ColorResolver { - int getColor(Biome biome, int x, int z); + int getColor(BiomeGenBase biome, int x, int z); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java new file mode 100644 index 000000000..1d2475b85 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java @@ -0,0 +1,27 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import net.minecraftforge.fluids.Fluid; +import org.joml.Vector3d; + +public class FluidState { + + public boolean isEmpty() { + return false; + } + + public Fluid getFluid() { + return null; + } + + public Vector3d getVelocity(BlockRenderView world, BlockPos pos) { + return new Vector3d(); + } + + public boolean method_15756(BlockRenderView world, BlockPos set) { + return true; + } + + public float getHeight(BlockRenderView world, BlockPos pos) { + return 0.0f; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java new file mode 100644 index 000000000..1e9b81115 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java @@ -0,0 +1,61 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import com.google.common.base.Predicates; +import com.google.common.collect.Iterators; +import com.google.common.collect.Lists; + +import javax.annotation.Nullable; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; + +public class IdList implements IndexedIterable { + protected int nextId; + protected final IdentityHashMap idMap; + protected final List list; + + public IdList() { + this(512); + } + + public IdList(int initialSize) { + this.list = Lists.newArrayListWithExpectedSize(initialSize); + this.idMap = new IdentityHashMap(initialSize); + } + + public void set(T value, int id) { + this.idMap.put(value, id); + + while(this.list.size() <= id) { + this.list.add(null); + } + + this.list.set(id, value); + if (this.nextId <= id) { + this.nextId = id + 1; + } + + } + + public void add(T value) { + this.set(value, this.nextId); + } + + public int getRawId(T entry) { + Integer integer = (Integer)this.idMap.get(entry); + return integer == null ? -1 : integer; + } + + @Nullable + public final T get(int index) { + return index >= 0 && index < this.list.size() ? this.list.get(index) : null; + } + + public Iterator iterator() { + return Iterators.filter(this.list.iterator(), Predicates.notNull()); + } + + public int size() { + return this.idMap.size(); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java new file mode 100644 index 000000000..75ea6d14a --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java @@ -0,0 +1,10 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import javax.annotation.Nullable; + +public interface IndexedIterable extends Iterable { + int getRawId(T entry); + + @Nullable + T get(int index); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ItemColorProvider.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ItemColorProvider.java new file mode 100644 index 000000000..1779aca63 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ItemColorProvider.java @@ -0,0 +1,7 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import net.minecraft.item.ItemStack; + +public interface ItemColorProvider { + int getColor(ItemStack stack, int tintIndex); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingProvider.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingProvider.java new file mode 100644 index 000000000..41ce17115 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingProvider.java @@ -0,0 +1,10 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +// LightingEngine from archaicfix/phosphor? +public class LightingProvider implements LightingView { + + @Override + public void setSectionStatus(ChunkSectionPos pos, boolean notReady) { + + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingView.java new file mode 100644 index 000000000..4e4778cfb --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingView.java @@ -0,0 +1,9 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public interface LightingView { + default void setSectionStatus(BlockPos pos, boolean notReady) { + this.setSectionStatus(ChunkSectionPos.from(pos), notReady); + } + + void setSectionStatus(ChunkSectionPos pos, boolean notReady); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java index 5c2bcb1be..fa695b453 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java @@ -18,12 +18,12 @@ public Entry peek() { return (Entry)this.matrixStack.getLast(); } - public void pushPose() { + public void push() { final Entry lv = (Entry)this.matrixStack.getLast(); this.matrixStack.addLast(new Entry(new Matrix4f(lv.model), new Matrix3f(lv.normal))); } - public void popPose() { + public void pop() { this.matrixStack.removeLast(); } public boolean clear() { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ModelLoader.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ModelLoader.java new file mode 100644 index 000000000..5a8fbcae1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ModelLoader.java @@ -0,0 +1,9 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import java.util.Collections; +import java.util.List; + +public class ModelLoader { + public static final List BLOCK_DESTRUCTION_RENDER_LAYERS = Collections.emptyList(); + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java new file mode 100644 index 000000000..8b30554f3 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java @@ -0,0 +1,50 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix3f; +import org.joml.Matrix4f; + +public class OverlayVertexConsumer implements VertexConsumer { + + public OverlayVertexConsumer(VertexConsumer buffer, Matrix4f model, Matrix3f normal) {} + + @Override + public VertexConsumer vertex(double d, double e, double f) { + return null; + } + + @NotNull + @Override + public VertexConsumer color(int r, int g, int b, int a) { + return null; + } + + @NotNull + @Override + public VertexConsumer texture(float u, float v) { + return null; + } + + @NotNull + @Override + public VertexConsumer overlay(int u, int v) { + return null; + } + + @NotNull + @Override + public VertexConsumer light(int u, int v) { + return null; + } + + @NotNull + @Override + public VertexConsumer normal(float x, float y, float z) { + return null; + } + + @Override + public void next() { + + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java index 5818decf3..a75fce68a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java @@ -2,4 +2,7 @@ public class PackedIntegerArray { + public int get(int i) { + return 0; + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Biome.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Palette.java similarity index 64% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/Biome.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/Palette.java index 8f7c8f6d4..4e240590d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Biome.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Palette.java @@ -1,5 +1,5 @@ package com.gtnewhorizons.angelica.compat.mojang; -public class Biome { +public interface Palette { } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PalettedContainer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PalettedContainer.java new file mode 100644 index 000000000..151215c31 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PalettedContainer.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class PalettedContainer { + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java index 9de27c46e..30b7ec797 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java @@ -1,5 +1,7 @@ package com.gtnewhorizons.angelica.compat.mojang; +import java.util.Collections; +import java.util.List; import java.util.Optional; public abstract class RenderLayer { // Aka: RenderType (Iris) @@ -26,6 +28,10 @@ public static RenderLayer tripwire() { return null; } + public static List getBlockLayers() { + return Collections.emptyList(); + } + public void setupRenderState() {} public void clearRenderState() {} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java new file mode 100644 index 000000000..ce5eab0d4 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java @@ -0,0 +1,11 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class RenderLayers { + public static boolean canRenderInLayer(BlockState state, RenderLayer type) { + return true; + } + + public static boolean canRenderInLayer(FluidState fluidState, RenderLayer layer) { + return true; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java new file mode 100644 index 000000000..92d526124 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java @@ -0,0 +1,7 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public enum SideShapeType { + FULL, + CENTER, + RIGID; +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java new file mode 100644 index 000000000..fc0444221 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java @@ -0,0 +1,7 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public interface VertexConsumerProvider { + public static class Immediate implements VertexConsumerProvider { + + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java index c01f128de..6b91a9437 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java @@ -1,5 +1,7 @@ package com.gtnewhorizons.angelica.compat.mojang; +import net.minecraftforge.common.util.ForgeDirection; + public final class VoxelShapes { public static VoxelShape fullCube() { @@ -9,4 +11,12 @@ public static VoxelShape fullCube() { public static boolean matchesAnywhere(VoxelShape shape1, VoxelShape shape2, Object predicate) { return false; } + + public static VoxelShape cuboid(double v, double v1, double v2, double v3, float height, double v4) { + return null; + } + + public static boolean isSideCovered(VoxelShape threshold, VoxelShape shape, ForgeDirection dir) { + return true; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index 564a38a56..8cce75bd4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -2,7 +2,8 @@ import com.gtnewhorizons.angelica.Tags; import cpw.mods.fml.common.Mod; -import org.apache.commons.lang3.tuple.Pair; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -21,13 +22,13 @@ public class SodiumClientMod { public static final String NAME = "Embeddium"; public SodiumClientMod() { - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onInitializeClient); - - ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); +// FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onInitializeClient); +// +// ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); } - public void onInitializeClient(final FMLClientSetupEvent event) { - MOD_VERSION = ModList.get().getModContainerById(MODID).get().getModInfo().getVersion().toString(); + public void onInitializeClient(final FMLInitializationEvent event) { + MOD_VERSION = Tags.VERSION; // ModList.get().getModContainerById(MODID).get().getModInfo().getVersion().toString(); } public static SodiumGameOptions options() { @@ -47,7 +48,8 @@ public static Logger logger() { } private static SodiumGameOptions loadConfig() { - return SodiumGameOptions.load(FMLPaths.CONFIGDIR.get().resolve("rubidium-options.json")); +// return SodiumGameOptions.load(FMLPaths.CONFIGDIR.get().resolve("rubidium-options.json")); + return null; } public static String getVersion() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java new file mode 100644 index 000000000..1dda55a7d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -0,0 +1,137 @@ +package me.jellysquid.mods.sodium.client.gui; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; +import me.jellysquid.mods.sodium.client.SodiumClientMod; + + +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +public class SodiumGameOptions { + public final QualitySettings quality = new QualitySettings(); + public final AdvancedSettings advanced = new AdvancedSettings(); + public final PerformanceSettings performance = new PerformanceSettings(); + public final NotificationSettings notifications = new NotificationSettings(); + + private Path configPath; + + public static class AdvancedSettings { + public boolean useVertexArrayObjects = true; + public boolean useChunkMultidraw = true; + + public boolean animateOnlyVisibleTextures = true; + public boolean useEntityCulling = true; + public boolean useParticleCulling = true; + public boolean useFogOcclusion = true; + public boolean useCompactVertexFormat = true; + public boolean useBlockFaceCulling = true; + public boolean allowDirectMemoryAccess = true; + public boolean ignoreDriverBlacklist = false; + public boolean translucencySorting = false; + } + + public static class PerformanceSettings { + public int chunkBuilderThreads = 0; + public boolean alwaysDeferChunkUpdates = false; + } + + public static class QualitySettings { + public GraphicsQuality cloudQuality = GraphicsQuality.DEFAULT; + public GraphicsQuality weatherQuality = GraphicsQuality.DEFAULT; + public GraphicsQuality leavesQuality = GraphicsQuality.DEFAULT; + + public boolean enableVignette = true; + public boolean enableClouds = true; + + public LightingQuality smoothLighting = LightingQuality.HIGH; + } + + public static class NotificationSettings { + public boolean hideDonationButton = false; + } + + public enum GraphicsQuality { + DEFAULT("generator.default"), + FANCY("options.clouds.fancy"), + FAST("options.clouds.fast"); + + private final String name; + + GraphicsQuality(String name) { + this.name = name; + } + + } + + public enum LightingQuality { + HIGH("options.ao.max"), + LOW("options.ao.min"), + OFF("options.ao.off"); + + private final String name; + + LightingQuality(String name) { + this.name = name; + } + + public String getLocalizedName() { + return this.name; + } + } + + private static final Gson GSON = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .setPrettyPrinting() + .excludeFieldsWithModifiers(Modifier.PRIVATE) + .create(); + + public static SodiumGameOptions load(Path path) { + SodiumGameOptions config; + boolean resaveConfig = true; + + if (Files.exists(path)) { + try (FileReader reader = new FileReader(path.toFile())) { + config = GSON.fromJson(reader, SodiumGameOptions.class); + } catch (IOException e) { + throw new RuntimeException("Could not parse config", e); + } catch (JsonSyntaxException e) { + SodiumClientMod.logger().error("Could not parse config, will fallback to default settings", e); + config = new SodiumGameOptions(); + resaveConfig = false; + } + } else { + config = new SodiumGameOptions(); + } + + config.configPath = path; + + try { + if(resaveConfig) + config.writeChanges(); + } catch (IOException e) { + throw new RuntimeException("Couldn't update config file", e); + } + + return config; + } + + public void writeChanges() throws IOException { + Path dir = this.configPath.getParent(); + + if (!Files.exists(dir)) { + Files.createDirectories(dir); + } else if (!Files.isDirectory(dir)) { + throw new IOException("Not a directory: " + dir); + } + + Files.write(this.configPath, GSON.toJson(this) + .getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java index 1783b0c81..f2f9ff377 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java @@ -61,7 +61,8 @@ public static int getBlendedLight(EntityLightSampler light for (int bZ = bMinZ; bZ < bMaxZ; bZ++) { pos.set(bX, bY, bZ); - BlockState blockState = entity.worldObj.getBlockState(pos); + // TODO - Sodium - Blocks + BlockState blockState = null; /*entity.worldObj.getBlockState(pos);*/ // Do not consider light-blocking volumes if (blockState.isOpaqueFullCube(entity.worldObj, pos) && blockState.getLightValue(entity.worldObj, pos) <= 0) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java index 90da70f59..cf4b63f18 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java @@ -2,7 +2,7 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; - +import com.gtnewhorizons.angelica.compat.mojang.BlockState; public interface BlockColorSettings { /** @@ -14,13 +14,17 @@ public interface BlockColorSettings { */ boolean useSmoothColorBlending(BlockRenderView view, T state, BlockPos pos); +// @SuppressWarnings("unchecked") +// static boolean isSmoothBlendingEnabled(BlockRenderView world, State state, BlockPos pos) { +// if (state.owner instanceof BlockColorSettings) { +// BlockColorSettings> settings = (BlockColorSettings>) state.owner; +// return settings.useSmoothColorBlending(world, state, pos); +// } +// +// return false; +// } @SuppressWarnings("unchecked") - static boolean isSmoothBlendingEnabled(BlockRenderView world, State state, BlockPos pos) { - if (state.owner instanceof BlockColorSettings) { - BlockColorSettings> settings = (BlockColorSettings>) state.owner; - return settings.useSmoothColorBlending(world, state, pos); - } - + static boolean isSmoothBlendingEnabled(BlockRenderView world, BlockState state, BlockPos pos) { return false; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java index a407335ba..6905d72eb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java @@ -2,17 +2,21 @@ import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import org.joml.Matrix4f; +import org.lwjgl.BufferUtils; import java.nio.FloatBuffer; public class GameRendererContext { - private static Matrix4f PROJECTION_MATRIX; + private static Matrix4f PROJECTION_MATRIX = new Matrix4f().identity(); + // TODO: Sodium - projection matrix + // Sodium uses a mixin in `loadProjectionMatrix` to capture the matrix, unclear if this is available in 1.7.10 public static void captureProjectionMatrix(Matrix4f matrix) { PROJECTION_MATRIX.set(matrix); } /** + * TODO: Not accurate * Obtains a model-view-projection matrix by multiplying the projection matrix with the model-view matrix * from {@param matrices}. * @@ -21,16 +25,13 @@ public static void captureProjectionMatrix(Matrix4f matrix) { * @return A float-buffer on the stack containing the model-view-projection matrix in a format suitable for * uploading as uniform state */ - public static FloatBuffer getModelViewProjectionMatrix(MatrixStack.Entry matrices, MemoryStack memoryStack) { - if (PROJECTION_MATRIX == null) { - throw new IllegalStateException("Projection matrix has not been captured"); - } + public static FloatBuffer getModelViewProjectionMatrix(MatrixStack.Entry matrices) { + FloatBuffer bufModelViewProjection = BufferUtils.createFloatBuffer(16); + // TODO: Sodium - projection matrix + Matrix4f matrix = new Matrix4f(PROJECTION_MATRIX); + matrix.mul(matrices.getModel()); - FloatBuffer bufModelViewProjection = memoryStack.mallocFloat(16); - - Matrix4f matrix = PROJECTION_MATRIX.copy(); - matrix.multiply(matrices.getModel()); - matrix.writeRowFirst(bufModelViewProjection); + matrix.get(bufModelViewProjection); return bufModelViewProjection; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index dc77fdc16..f0b28e505 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -1,11 +1,17 @@ package me.jellysquid.mods.sodium.client.render; import cofh.lib.util.helpers.MathHelper; +import com.gtnewhorizons.angelica.compat.mojang.BlockBreakingInfo; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BufferBuilderStorage; import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.mojang.ModelLoader; +import com.gtnewhorizons.angelica.compat.mojang.OverlayVertexConsumer; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumerProvider; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.rwtema.extrautils.block.Box; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; @@ -13,6 +19,7 @@ import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderBackend; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderManager; @@ -287,7 +294,7 @@ private static ChunkRenderBackend createChunkRenderBackend(RenderDevice devic } private boolean checkBEVisibility(TileEntity entity) { - return frustum.isVisible(entity.getRenderBoundingBox()); + return frustum.isBoundingBoxInFrustum(entity.getRenderBoundingBox()); } public void renderTileEntities(MatrixStack matrices, BufferBuilderStorage bufferBuilders, Long2ObjectMap> blockBreakingProgressions, @@ -299,10 +306,10 @@ public void renderTileEntities(MatrixStack matrices, BufferBuilderStorage buffer double y = cameraPos.y; double z = cameraPos.z; - for (TileEntity blockEntity : this.chunkRenderManager.getVisibleBlockEntities()) { - if(blockEntity.isRemoved() || !checkBEVisibility(blockEntity)) + for (TileEntity tileEntity : this.chunkRenderManager.getVisibleBlockEntities()) { + if(tileEntity.isInvalid() || !checkBEVisibility(tileEntity)) continue; - BlockPos pos = blockEntity.getPos(); + BlockPos pos = new BlockPos(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); matrices.push(); matrices.translate((double) pos.x - x, (double) pos.y - y, (double) pos.z - z); @@ -320,7 +327,7 @@ public void renderTileEntities(MatrixStack matrices, BufferBuilderStorage buffer } } - BlockEntityRenderDispatcher.INSTANCE.render(blockEntity, tickDelta, matrices, consumer); + BlockEntityRenderDispatcher.INSTANCE.render(tileEntity, tickDelta, matrices, consumer); matrices.pop(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 9f1ecafbc..cf2b56dbc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk; import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.ints.IntList; @@ -35,6 +36,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraftforge.common.util.ForgeDirection; import org.joml.Vector3d; @@ -432,7 +434,7 @@ private ChunkRenderColumn getColumn(int x, int z) { private ChunkRenderContainer createChunkRender(ChunkRenderColumn column, int x, int y, int z) { ChunkRenderContainer render = new ChunkRenderContainer<>(this.backend, this.renderer, x, y, z, column); - if (ChunkSection.isEmpty(this.world.getChunk(x, z).getSectionArray()[y])) { + if (this.world.getChunkFromChunkCoords(x, z).getBlockStorageArray()[y].isEmpty()) { render.setData(ChunkRenderData.EMPTY); } else { render.scheduleRebuild(false); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java index bf2b42f45..cf4d886df 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java @@ -1,12 +1,10 @@ package me.jellysquid.mods.sodium.client.render.chunk.shader; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; -import com.gtnewhorizons.angelica.glsm.GLStateManager; import io.github.douira.glsl_transformer.ast.node.Identifier; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; import me.jellysquid.mods.sodium.client.render.GameRendererContext; -import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL20; import java.util.function.Function; @@ -47,8 +45,6 @@ public void setup(MatrixStack matrixStack, float modelScale, float textureScale) this.fogShader.setup(); - try (MemoryStack memoryStack = MemoryStack.stackPush()) { - GL20.glUniformMatrix4(this.uModelViewProjectionMatrix, false, GameRendererContext.getModelViewProjectionMatrix(matrixStack.peek(), memoryStack)); - } + GL20.glUniformMatrix4(this.uModelViewProjectionMatrix, false, GameRendererContext.getModelViewProjectionMatrix(matrixStack.peek())); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 8bce66b6b..200f2e280 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -1,11 +1,17 @@ package me.jellysquid.mods.sodium.client.render.chunk.tasks; +import com.gtnewhorizons.angelica.compat.forge.EmptyModelData; +import com.gtnewhorizons.angelica.compat.forge.ForgeHooksClientExt; import com.gtnewhorizons.angelica.compat.forge.IModelData; import com.gtnewhorizons.angelica.compat.mojang.BakedModel; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderType; import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionDataBuilder; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.FluidState; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayers; import com.rwtema.extrautils.ChunkPos; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; @@ -22,7 +28,6 @@ import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import net.minecraft.client.Minecraft; import net.minecraft.tileentity.TileEntity; -import net.minecraftforge.client.ForgeHooksClient; import org.joml.Vector3d; import java.util.Map; @@ -105,7 +110,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB continue; } - ForgeHooksClient.setRenderLayer(layer); + ForgeHooksClientExt.setRenderLayer(layer); IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); BakedModel model = cache.getBlockModels().getModel(blockState); @@ -127,7 +132,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB continue; } - ForgeHooksClient.setRenderLayer(layer); + ForgeHooksClientExt.setRenderLayer(layer); if (cache.getFluidRenderer().render(cache.getLocalSlice(), fluidState, pos, buffers.get(layer))) { bounds.addBlock(relX, relY, relZ); @@ -154,7 +159,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB } } - ForgeHooksClient.setRenderLayer(null); + ForgeHooksClientExt.setRenderLayer(null); render.setRebuildForTranslucents(false); for (BlockRenderPass pass : BlockRenderPass.VALUES) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java index 8671c0b22..a0999a108 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java @@ -1,9 +1,12 @@ package me.jellysquid.mods.sodium.client.render.pipeline; +import com.gtnewhorizons.angelica.compat.forge.ForgeHooksClientExt; import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.FluidState; +import com.gtnewhorizons.angelica.compat.mojang.SideShapeType; import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; import com.gtnewhorizons.angelica.compat.mojang.VoxelShapes; import me.jellysquid.mods.sodium.client.model.light.LightMode; @@ -24,7 +27,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.util.MathHelper; -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; import org.joml.Vector3d; @@ -37,7 +39,8 @@ public class FluidRenderer { private static final BlockColorProvider FLUID_COLOR_PROVIDER = (state, world, pos, tintIndex) -> { if (world == null) return 0xFFFFFFFF; - return state.getFluidState().getFluid().getAttributes().getColor(world, pos); + // TODO: Sodium - Fluids + return 0xFFFFFFFF; // state.getFluidState().getFluid().getAttributes().getColor(world, pos); }; private final BlockPos.Mutable scratchPos = new BlockPos.Mutable(); @@ -67,10 +70,10 @@ private boolean isFluidOccluded(BlockRenderView world, int x, int y, int z, Forg BlockPos adjPos = this.scratchPos.set(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); if (blockState.isOpaque()) { - return world.getFluidState(adjPos).getFluid().matchesType(fluid) || blockState.isSideSolid(world,pos,dir, SideShapeType.FULL); + return world.getFluidState(adjPos).getFluid().equals/*matchesType*/(fluid) || blockState.isSideSolid(world,pos,dir, SideShapeType.FULL); // fluidlogged or next to water, occlude sides that are solid or the same liquid } - return world.getFluidState(adjPos).getFluid().matchesType(fluid); + return world.getFluidState(adjPos).getFluid().equals/*matchesType*/(fluid); } private boolean isSideExposed(BlockRenderView world, int x, int y, int z, ForgeDirection dir, float height) { @@ -115,8 +118,9 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos return false; } - TextureAtlasSprite[] sprites = ForgeHooksClient.getFluidSprites(world, pos, fluidState); - boolean hc = fluidState.getFluid().getAttributes().getColor() != 0xffffffff; + TextureAtlasSprite[] sprites = ForgeHooksClientExt.getFluidSprites(world, pos, fluidState); + // TODO: Sodium - Fluids + boolean hc = true; //fluidState.getFluid().getAttributes().getColor() != 0xffffffff; boolean rendered = false; @@ -150,11 +154,11 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos if (velocity.x == 0.0D && velocity.z == 0.0D) { sprite = sprites[0]; facing = ModelQuadFacing.UP; - u1 = sprite.getFrameU(0.0D); - v1 = sprite.getFrameV(0.0D); + u1 = sprite.getInterpolatedU(0.0D); + v1 = sprite.getInterpolatedV(0.0D); u2 = u1; - v2 = sprite.getFrameV(16.0D); - u3 = sprite.getFrameU(16.0D); + v2 = sprite.getInterpolatedV(16.0D); + u3 = sprite.getInterpolatedU(16.0D); v3 = v2; u4 = u3; v4 = v1; @@ -164,14 +168,14 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos float dir = (float) Math.atan2(velocity.z, velocity.x) - (1.5707964f); float sin = MathHelper.sin(dir) * 0.25F; float cos = MathHelper.cos(dir) * 0.25F; - u1 = sprite.getFrameU(8.0F + (-cos - sin) * 16.0F); - v1 = sprite.getFrameV(8.0F + (-cos + sin) * 16.0F); - u2 = sprite.getFrameU(8.0F + (-cos + sin) * 16.0F); - v2 = sprite.getFrameV(8.0F + (cos + sin) * 16.0F); - u3 = sprite.getFrameU(8.0F + (cos + sin) * 16.0F); - v3 = sprite.getFrameV(8.0F + (cos - sin) * 16.0F); - u4 = sprite.getFrameU(8.0F + (cos - sin) * 16.0F); - v4 = sprite.getFrameV(8.0F + (-cos - sin) * 16.0F); + u1 = sprite.getInterpolatedU(8.0F + (-cos - sin) * 16.0F); + v1 = sprite.getInterpolatedV(8.0F + (-cos + sin) * 16.0F); + u2 = sprite.getInterpolatedU(8.0F + (-cos + sin) * 16.0F); + v2 = sprite.getInterpolatedV(8.0F + (cos + sin) * 16.0F); + u3 = sprite.getInterpolatedU(8.0F + (cos + sin) * 16.0F); + v3 = sprite.getInterpolatedV(8.0F + (cos - sin) * 16.0F); + u4 = sprite.getInterpolatedU(8.0F + (cos - sin) * 16.0F); + v4 = sprite.getInterpolatedV(8.0F + (-cos - sin) * 16.0F); } float uAvg = (u1 + u2 + u3 + u4) / 4.0F; @@ -313,11 +317,11 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos } } - float u1 = sprite.getFrameU(0.0D); - float u2 = sprite.getFrameU(8.0D); - float v1 = sprite.getFrameV((1.0F - c1) * 16.0F * 0.5F); - float v2 = sprite.getFrameV((1.0F - c2) * 16.0F * 0.5F); - float v3 = sprite.getFrameV(8.0D); + float u1 = sprite.getInterpolatedU(0.0D); + float u2 = sprite.getInterpolatedU(8.0D); + float v1 = sprite.getInterpolatedV((1.0F - c1) * 16.0F * 0.5F); + float v2 = sprite.getInterpolatedV((1.0F - c2) * 16.0F * 0.5F); + float v3 = sprite.getInterpolatedV(8.0D); quad.setSprite(sprite); @@ -326,7 +330,7 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos this.setVertex(quad, 2, x1, yOffset, z1, u1, v3); this.setVertex(quad, 3, x1, c1, z1, u1, v1); - float br = dir.getAxis() == ForgeDirection.Axis.Z ? 0.8F : 0.6F; + float br = dir.offsetZ != 0 ? 0.8F : 0.6F; ModelQuadFacing facing = ModelQuadFacing.fromDirection(dir); @@ -420,7 +424,8 @@ private float getCornerHeight(BlockRenderView world, int x, int y, int z, Fluid int x2 = x - (i & 1); int z2 = z - (i >> 1 & 1); - if (world.getFluidState(this.scratchPos.set(x2, y + 1, z2)).getFluid().matchesType(fluid)) { + + if (world.getFluidState(this.scratchPos.set(x2, y + 1, z2)).getFluid().equals/*matchesType*/(fluid)) { return 1.0F; } @@ -429,7 +434,7 @@ private float getCornerHeight(BlockRenderView world, int x, int y, int z, Fluid BlockState blockState = world.getBlockState(pos); FluidState fluidState = blockState.getFluidState(); - if (fluidState.getFluid().matchesType(fluid)) { + if (fluidState.getFluid().equals/*matchesType*/(fluid)) { float height = fluidState.getHeight(world, pos); if (height >= 0.8F) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java index b0ac6f345..1d7351a9f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.pipeline.context; +import com.gtnewhorizons.angelica.compat.mojang.BlockModels; import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache; import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; @@ -32,7 +33,8 @@ public ChunkRenderCacheLocal(Minecraft client, World world) { this.blockRenderer = new BlockRenderer(client, lightPipelineProvider, biomeColorBlender); this.fluidRenderer = new FluidRenderer(client, lightPipelineProvider, biomeColorBlender); - this.blockModels = client.getBakedModelManager().getBlockModels(); + // TODO: Sodium + this.blockModels = null; // client.getBakedModelManager().getBlockModels(); } public BlockModels getBlockModels() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix3fExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix3fExtended.java index 2e51631cb..d1480f766 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix3fExtended.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix3fExtended.java @@ -9,7 +9,7 @@ public interface Matrix3fExtended { * * @param quaternion The quaternion to rotate this matrix by */ - void rotate(Quaternion quaternion); +// void rotate(Quaternion quaternion); int computeNormal(ForgeDirection dir); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix4fExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix4fExtended.java index 35e468b3f..861ffa86f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix4fExtended.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/math/Matrix4fExtended.java @@ -7,7 +7,7 @@ public interface Matrix4fExtended { * * @param quaternion The quaternion to rotate this matrix by */ - void rotate(Quaternion quaternion); +// void rotate(Quaternion quaternion); /** * Applies the specified translation to this matrix in-place. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 324d159f2..db18556ca 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -1,13 +1,14 @@ package me.jellysquid.mods.sodium.client.world; -import com.gtnewhorizons.angelica.compat.mojang.Biome; import com.gtnewhorizons.angelica.compat.mojang.BiomeAccess; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import com.gtnewhorizons.angelica.compat.mojang.ColorResolver; +import com.gtnewhorizons.angelica.compat.mojang.FluidState; import com.gtnewhorizons.angelica.compat.mojang.LightType; +import com.gtnewhorizons.angelica.compat.mojang.LightingProvider; import com.gtnewhorizons.angelica.compat.mojang.PackedIntegerArray; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import me.jellysquid.mods.sodium.client.world.biome.BiomeCache; @@ -18,11 +19,12 @@ import me.jellysquid.mods.sodium.client.world.cloned.PackedIntegerArrayExtended; import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; import net.minecraft.client.Minecraft; -import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.MathHelper; import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraft.world.gen.structure.StructureBoundingBox; import net.minecraftforge.common.util.ForgeDirection; @@ -65,7 +67,7 @@ public class WorldSlice implements BlockRenderView, BiomeAccess.Storage { private static final int SECTION_TABLE_ARRAY_SIZE = TABLE_LENGTH * TABLE_LENGTH * TABLE_LENGTH; // Fallback BlockState to use if none were available in the array - private static final BlockState NULL_BLOCK_STATE = Blocks.air.getDefaultState(); + private static final BlockState NULL_BLOCK_STATE = null; //Blocks.air.getDefaultState(); // The world this slice has copied data from private final World world; @@ -98,12 +100,12 @@ public class WorldSlice implements BlockRenderView, BiomeAccess.Storage { public static ChunkRenderContext prepare(World world, ChunkSectionPos origin, ClonedChunkSectionCache sectionCache) { Chunk chunk = world.getChunkFromChunkCoords(origin.x, origin.z); - ChunkSection section = chunk.getSectionArray()[origin.y]; + ExtendedBlockStorage section = chunk.getBlockStorageArray()[origin.y]; // If the chunk section is absent or empty, simply terminate now. There will never be anything in this chunk // section to render, so we need to signal that a chunk render task shouldn't created. This saves a considerable // amount of time in queueing instant build tasks and greatly accelerates how quickly the world can be loaded. - if (ChunkSection.isEmpty(section)) { + if (section == null || section.isEmpty()) { return null; } @@ -322,7 +324,7 @@ public boolean isSkyVisible(BlockPos pos) { } @Override - public Biome getBiomeForNoiseGen(int x, int y, int z) { + public BiomeGenBase getBiomeForNoiseGen(int x, int y, int z) { int x2 = (x >> 2) - (this.baseX >> 4); int z2 = (z >> 2) - (this.baseZ >> 4); @@ -334,13 +336,13 @@ public Biome getBiomeForNoiseGen(int x, int y, int z) { return section.getBiomeForNoiseGen(x, y, z); } - return this.world.getGeneratorStoredBiome(x, y, z); + return this.world.getBiomeGenForCoords(x, z); } /** * Gets or computes the biome at the given global coordinates. */ - public Biome getBiome(int x, int y, int z) { + public BiomeGenBase getBiome(int x, int y, int z) { int relX = x - this.baseX; int relY = y - this.baseY; int relZ = z - this.baseZ; @@ -351,7 +353,7 @@ public Biome getBiome(int x, int y, int z) { BiomeCache cache = this.biomeCaches[index]; return cache != null ? cache - .getBiome(this, x, relY >> 4, z) : Minecraft.getMinecraft().theWorld.getBiome(new BlockPos(x, y, z)); + .getBiome(this, x, relY >> 4, z) : Minecraft.getMinecraft().theWorld.getBiomeGenForCoords(x, z); } public ChunkSectionPos getOrigin() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java index 9d6ac3ce0..d7b09a037 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java @@ -3,17 +3,15 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; -import com.rwtema.extrautils.block.Box; +import com.gtnewhorizons.angelica.compat.mojang.ColorResolver; +import com.gtnewhorizons.angelica.compat.mojang.FluidState; +import com.gtnewhorizons.angelica.compat.mojang.LightType; +import com.gtnewhorizons.angelica.compat.mojang.LightingProvider; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.common.util.ForgeDirection; -import org.joml.Vector3d; import javax.annotation.Nullable; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Stream; /** * Wrapper object used to defeat identity comparisons in mods. Since vanilla provides a unique object to them for each @@ -56,6 +54,11 @@ public boolean isSkyVisible(BlockPos pos) { return view.isSkyVisible(pos); } + @Override + public BiomeGenBase getBiomeForNoiseGen(int x, int y, int z) { + return null; + } + @Override @Nullable public TileEntity getBlockEntity(BlockPos pos) { @@ -72,48 +75,51 @@ public FluidState getFluidState(BlockPos pos) { return view.getFluidState(pos); } - @Override +// @Override public int getLuminance(BlockPos pos) { - return view.getLuminance(pos); + return 0; +// return view.getLuminance(pos); } - @Override +// @Override public int getMaxLightLevel() { - return view.getMaxLightLevel(); + return 15; +// return view.getMaxLightLevel(); } - @Override +// @Override public int getHeight() { - return view.getHeight(); - } - - @Override - public Stream method_29546(Box arg) { - return view.method_29546(arg); - } - - @Override - public BlockHitResult raycast(RaycastContext context) { - return view.raycast(context); - } - - @Override - @Nullable - public BlockHitResult raycastBlock(Vector3d start, Vector3d end, BlockPos pos, VoxelShape shape, BlockState state) { - return view.raycastBlock(start, end, pos, shape, state); - } - - @Override - public double getDismountHeight(VoxelShape blockCollisionShape, Supplier belowBlockCollisionShapeGetter) { - return view.getDismountHeight(blockCollisionShape, belowBlockCollisionShapeGetter); - } - - @Override - public double getDismountHeight(BlockPos pos) { - return view.getDismountHeight(pos); - } - - public static T raycast(RaycastContext arg, BiFunction context, Function blockRaycaster) { - return BlockView.raycast(arg, context, blockRaycaster); - } + return 255; +// return view.getHeight(); + } + +// @Override +// public Stream method_29546(Box arg) { +// return view.method_29546(arg); +// } +// +// @Override +// public BlockHitResult raycast(RaycastContext context) { +// return view.raycast(context); +// } +// +// @Override +// @Nullable +// public BlockHitResult raycastBlock(Vector3d start, Vector3d end, BlockPos pos, VoxelShape shape, BlockState state) { +// return view.raycastBlock(start, end, pos, shape, state); +// } +// +// @Override +// public double getDismountHeight(VoxelShape blockCollisionShape, Supplier belowBlockCollisionShapeGetter) { +// return view.getDismountHeight(blockCollisionShape, belowBlockCollisionShapeGetter); +// } +// +// @Override +// public double getDismountHeight(BlockPos pos) { +// return view.getDismountHeight(pos); +// } +// +// public static T raycast(RaycastContext arg, BiFunction context, Function blockRaycaster) { +// return BlockView.raycast(arg, context, blockRaycaster); +// } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java index a142c7f95..be0334e30 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.client.world.biome; -import com.gtnewhorizons.angelica.compat.mojang.Biome; import com.gtnewhorizons.angelica.compat.mojang.BiomeAccess; import com.gtnewhorizons.angelica.compat.mojang.BiomeAccessType; import me.jellysquid.mods.sodium.client.world.ClientWorldExtended; import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; import java.util.Arrays; @@ -12,19 +12,19 @@ public class BiomeCache { private final BiomeAccessType type; private final long seed; - private final Biome[] biomes; + private final BiomeGenBase[] biomes; public BiomeCache(World world) { this.type = world.getDimension().getBiomeAccessType(); this.seed = ((ClientWorldExtended) world).getBiomeSeed(); - this.biomes = new Biome[16 * 16]; + this.biomes = new BiomeGenBase[16 * 16]; } - public Biome getBiome(BiomeAccess.Storage storage, int x, int y, int z) { + public BiomeGenBase getBiome(BiomeAccess.Storage storage, int x, int y, int z) { int idx = ((z & 15) << 4) | (x & 15); - Biome biome = this.biomes[idx]; + BiomeGenBase biome = this.biomes[idx]; if (biome == null) { this.biomes[idx] = biome = this.type.getBiome(this.seed, x, y, z, storage); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java index 885f14cb0..4ee2f2674 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.world.biome; +import com.gtnewhorizons.angelica.compat.mojang.ItemColorProvider; import net.minecraft.item.ItemStack; public interface ItemColorsExtended { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 300453eac..879470564 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -1,11 +1,12 @@ package me.jellysquid.mods.sodium.client.world.cloned; -import com.gtnewhorizons.angelica.compat.mojang.Biome; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import com.gtnewhorizons.angelica.compat.mojang.LightType; import com.gtnewhorizons.angelica.compat.mojang.PackedIntegerArray; +import com.gtnewhorizons.angelica.compat.mojang.Palette; +import com.gtnewhorizons.angelica.compat.mojang.PalettedContainer; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; @@ -13,8 +14,12 @@ import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalleteArray; import net.minecraft.block.Block; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.ChunkPosition; import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.NibbleArray; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraft.world.gen.structure.StructureBoundingBox; import java.util.Map; @@ -22,13 +27,13 @@ public class ClonedChunkSection { private static final LightType[] LIGHT_TYPES = LightType.values(); - private static final ChunkSection EMPTY_SECTION = new ChunkSection(0); + private static final ExtendedBlockStorage EMPTY_SECTION = new ExtendedBlockStorage(0, false); private final AtomicInteger referenceCount = new AtomicInteger(0); private final ClonedChunkSectionCache backingCache; private final Short2ObjectMap blockEntities; - private final ChunkNibbleArray[] lightDataArrays; + private final NibbleArray[] lightDataArrays; private final World world; private ChunkSectionPos pos; @@ -36,7 +41,7 @@ public class ClonedChunkSection { private PackedIntegerArray blockStateData; private ClonedPalette blockStatePalette; - private BiomeArray biomeData; + private byte[] biomeData; private long lastUsedTimestamp = Long.MAX_VALUE; @@ -44,7 +49,7 @@ public class ClonedChunkSection { this.backingCache = backingCache; this.world = world; this.blockEntities = new Short2ObjectOpenHashMap<>(); - this.lightDataArrays = new ChunkNibbleArray[LIGHT_TYPES.length]; + this.lightDataArrays = new NibbleArray[LIGHT_TYPES.length]; } public void init(ChunkSectionPos pos) { @@ -54,23 +59,24 @@ public void init(ChunkSectionPos pos) { throw new RuntimeException("Couldn't retrieve chunk at " + pos.toChunkPos()); } - ChunkSection section = getChunkSection(chunk, pos); + ExtendedBlockStorage section = getChunkSection(chunk, pos); - if (section == WorldChunk.EMPTY_SECTION /*ChunkSection.isEmpty(section)*/) { + if (section == null /*WorldChunk.EMPTY_SECTION*/ /*ChunkSection.isEmpty(section)*/) { section = EMPTY_SECTION; } this.pos = pos; - PalettedContainerExtended container = PalettedContainerExtended.cast(section.getContainer());; + PalettedContainerExtended container = PalettedContainerExtended.cast(new PalettedContainer<>()/*section.getContainer()*/);; this.blockStateData = copyBlockData(container); this.blockStatePalette = copyPalette(container); for (LightType type : LIGHT_TYPES) { - this.lightDataArrays[type.ordinal()] = world.getLightingProvider() + // TODO: Sodium - Lighting + this.lightDataArrays[type.ordinal()] = null; /*world.getLightingProvider() .get(type) - .getLightSection(pos); + .getLightSection(pos);*/ } this.biomeData = chunk.getBiomeArray(); @@ -79,10 +85,11 @@ public void init(ChunkSectionPos pos) { this.blockEntities.clear(); - for (Map.Entry entry : chunk.getBlockEntities().entrySet()) { - BlockPos entityPos = entry.getKey(); + for (Map.Entry entry : chunk.chunkTileEntityMap.entrySet()) { + BlockPos entityPos = new BlockPos(entry.getKey()); - if (box.contains(entityPos)) { +// if (box.contains(entityPos)) { + if(box.isVecInside(entityPos.getX(), entityPos.getY(), entityPos.getZ())) { //this.blockEntities.put(BlockPos.asLong(entityPos.getX() & 15, entityPos.getY() & 15, entityPos.getZ() & 15), entry.getValue()); this.blockEntities.put(ChunkSectionPos.packLocal(entityPos), entry.getValue()); } @@ -94,7 +101,7 @@ public BlockState getBlockState(int x, int y, int z) { } public int getLightLevel(LightType type, int x, int y, int z) { - ChunkNibbleArray array = this.lightDataArrays[type.ordinal()]; + NibbleArray array = this.lightDataArrays[type.ordinal()]; if (array != null) { return array.get(x, y, z); @@ -103,8 +110,10 @@ public int getLightLevel(LightType type, int x, int y, int z) { return 0; } - public Biome getBiomeForNoiseGen(int x, int y, int z) { - return this.biomeData.getBiomeForNoiseGen(x, y, z); + public BiomeGenBase getBiomeForNoiseGen(int x, int y, int z) { + int k = this.biomeData[x << 4 | z] & 255; + return BiomeGenBase.getBiome(k); + } public TileEntity getBlockEntity(int x, int y, int z) { @@ -150,11 +159,15 @@ private static PackedIntegerArray copyBlockData(PalettedContainerExtended= 256; + } + + private static ExtendedBlockStorage getChunkSection(Chunk chunk, ChunkSectionPos pos) { + ExtendedBlockStorage section = null; - if (!World.isOutOfBuildLimitVertically(ChunkSectionPos.getBlockCoord(pos.getY()))) { - section = chunk.getSectionArray()[pos.y]; + if (!isOutOfBuildLimitVertically(ChunkSectionPos.getBlockCoord(pos.y()))) { + section = chunk.getBlockStorageArray()[pos.y]; } return section; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java index ffcb9690c..817a356a4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java @@ -1,6 +1,8 @@ package me.jellysquid.mods.sodium.client.world.cloned; - +import com.gtnewhorizons.angelica.compat.mojang.PackedIntegerArray; +import com.gtnewhorizons.angelica.compat.mojang.Palette; +import com.gtnewhorizons.angelica.compat.mojang.PalettedContainer; public interface PalettedContainerExtended { @SuppressWarnings("unchecked") diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java index 2fe1c33b4..0926269e0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.world.cloned.palette; +import com.gtnewhorizons.angelica.compat.mojang.IdList; public class ClonedPaletteFallback implements ClonedPalette { private final IdList idList; diff --git a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java index 7a2fcbdf3..6cbe4798d 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java @@ -83,7 +83,7 @@ public void renderSolid(MatrixStack poseStack, float tickDelta, Camera camera, G pipeline.setPhase(WorldRenderingPhase.HAND_SOLID); - poseStack.pushPose(); + poseStack.push(); Minecraft.getMinecraft().mcProfiler.startSection("iris_hand"); @@ -98,7 +98,7 @@ public void renderSolid(MatrixStack poseStack, float tickDelta, Camera camera, G // TODO: ProjectionMatrix // gameRenderer.resetProjectionMatrix(CapturedRenderingState.INSTANCE.getGbufferProjection()); - poseStack.popPose(); + poseStack.pop(); bufferSource.endBatch(); @@ -118,7 +118,7 @@ public void renderTranslucent(MatrixStack poseStack, float tickDelta, Camera cam pipeline.setPhase(WorldRenderingPhase.HAND_TRANSLUCENT); - poseStack.pushPose(); + poseStack.push(); Minecraft.getMinecraft().mcProfiler.startSection("iris_hand_translucent"); @@ -127,7 +127,7 @@ public void renderTranslucent(MatrixStack poseStack, float tickDelta, Camera cam // TODO: Hand // Minecraft.getMinecraft().getItemInHandRenderer().renderHandsWithItems(tickDelta, poseStack, bufferSource, Minecraft.getMinecraft().thePlayer, Minecraft.getMinecraft().getEntityRenderDispatcher().getPackedLightCoords(camera.getEntity(), tickDelta)); - poseStack.popPose(); + poseStack.pop(); Minecraft.getMinecraft().mcProfiler.endSection(); diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 8bead198d..5c87e666f 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -439,11 +439,11 @@ private void renderBlockEntities(BufferSource bufferSource, MatrixStack modelVie continue; } } - modelView.pushPose(); + modelView.push(); // TODO: Render modelView.translate(entity.xCoord - cameraX, entity.yCoord - cameraY, entity.zCoord - cameraZ); // BlockEntityRenderDispatcher.instance.render(entity, tickDelta, modelView, bufferSource); - modelView.popPose(); + modelView.pop(); shadowBlockEntities++; } From 2a3efc602236d07f58fb10e7a37dcb50012bdb48 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 7 Nov 2023 21:50:38 -0800 Subject: [PATCH 035/301] 1.7.10ify & Shims --- .../compat/forge/ModelDataManager.java | 27 ++++++ .../angelica/compat/mojang/Axis.java | 19 +++++ .../angelica/compat/mojang/BakedModel.java | 2 + .../angelica/compat/mojang/BlockState.java | 5 +- .../compat/mojang/BufferBuilderStorage.java | 9 ++ .../angelica/compat/mojang/Camera.java | 8 ++ .../mojang/ChunkOcclusionDataBuilder.java | 2 + .../angelica/compat/mojang/ChunkPos.java | 10 +++ .../compat/mojang/ChunkSectionPos.java | 4 + .../compat/mojang/CompatMathHelper.java | 27 ++++++ .../angelica/compat/mojang/IdListPalette.java | 9 ++ .../compat/mojang/PackedIntegerArray.java | 10 +++ .../angelica/compat/mojang/Palette.java | 1 + .../angelica/compat/mojang/RenderLayer.java | 38 +++++++-- .../angelica/compat/mojang/RenderPhase.java | 19 +++-- .../compat/mojang/VertexConsumer.java | 15 ++++ .../compat/mojang/VertexConsumerProvider.java | 84 +++++++++++++++++++ .../compat/mojang/VertexConsumers.java | 71 ++++++++++++++++ .../gtnewhorizons/angelica/mixins/Mixins.java | 2 +- .../mixins/early/sodium/MixinWorld.java | 10 +++ .../sodium/client/gui/SodiumGameOptions.java | 2 +- .../client/model/light/EntityLighter.java | 5 +- .../model/light/smooth/AoNeighborInfo.java | 2 +- .../blender/ConfigurableColorBlender.java | 4 +- .../blender/DefaultBlockColorSettings.java | 11 ++- .../model/quad/properties/ModelQuadFlags.java | 70 +++++----------- .../buffer/VertexBufferWriterUnsafe.java | 33 -------- .../vertex/formats/glyph/GlyphVertexType.java | 3 +- .../writer/GlyphVertexBufferWriterUnsafe.java | 28 ------- .../vertex/formats/line/LineVertexType.java | 3 +- .../writer/LineVertexBufferWriterUnsafe.java | 24 ------ .../formats/particle/ParticleVertexType.java | 3 +- .../ParticleVertexBufferWriterUnsafe.java | 27 ------ .../vertex/formats/quad/QuadVertexType.java | 3 +- .../writer/QuadVertexBufferWriterUnsafe.java | 29 ------- .../BasicScreenQuadVertexType.java | 3 +- ...sicScreenQuadVertexBufferWriterUnsafe.java | 24 ------ .../client/render/SodiumWorldRenderer.java | 60 ++++++------- .../render/chunk/ChunkRenderContainer.java | 2 +- .../render/chunk/ChunkRenderManager.java | 6 +- .../multidraw/ChunkDrawCallBatcher.java | 3 +- .../multidraw/ChunkDrawParamsVector.java | 2 +- .../IndirectCommandBufferVector.java | 2 +- .../chunk/compile/ChunkBuildBuffers.java | 3 +- .../chunk/cull/graph/ChunkGraphCuller.java | 7 +- .../hfp/HFPModelVertexBufferWriterUnsafe.java | 41 --------- .../chunk/format/hfp/HFPModelVertexType.java | 2 +- .../sfp/SFPModelVertexBufferWriterUnsafe.java | 49 ----------- .../chunk/format/sfp/SFPModelVertexType.java | 2 +- .../chunk/shader/ChunkShaderFogComponent.java | 11 ++- .../chunk/tasks/ChunkRenderRebuildTask.java | 18 ++-- .../ChunkRenderTranslucencySortTask.java | 3 +- .../client/render/pipeline/BlockRenderer.java | 16 ++-- .../context/ChunkRenderCacheShared.java | 9 +- .../sodium/client/util/ModelQuadUtil.java | 3 +- .../client/util/color/FastCubicSampler.java | 12 ++- .../mods/sodium/client/world/WorldSlice.java | 10 +-- .../sodium/client/world/biome/BiomeCache.java | 3 +- .../client/world/biome/BiomeColorCache.java | 3 +- .../world/cloned/ClonedChunkSection.java | 5 +- .../sodium/common/config/SodiumConfig.java | 13 ++- .../impl/BufferSegmentRenderer.java | 4 +- .../impl/FullyBufferedMultiBufferSource.java | 4 +- .../wrappers/TaggingRenderTypeWrapper.java | 2 +- .../iris/layer/OuterWrappedRenderType.java | 18 ++-- 65 files changed, 513 insertions(+), 446 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/CompatMathHelper.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdListPalette.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorld.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java new file mode 100644 index 000000000..dcc066988 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java @@ -0,0 +1,27 @@ +package com.gtnewhorizons.angelica.compat.forge; + +import com.google.common.base.Preconditions; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ModelDataManager { + private static final Map> modelDataCache = new ConcurrentHashMap<>(); + + public static @Nullable IModelData getModelData(World world, BlockPos pos) + { + return getModelData(world, new ChunkPos(pos)).get(pos); + } + + public static Map getModelData(World world, ChunkPos pos) + { + Preconditions.checkArgument(!world.isRemote, "Cannot request model data for server world"); +// refreshModelData(world, pos); + return modelDataCache.getOrDefault(pos, Collections.emptyMap()); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java new file mode 100644 index 000000000..1074e0a88 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java @@ -0,0 +1,19 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +import net.minecraftforge.common.util.ForgeDirection; + +public enum Axis { + X, + Y, + Z; + + public static Axis fromDirection(ForgeDirection dir) { + return switch (dir) { + case DOWN, UP -> Y; + case NORTH, SOUTH -> Z; + case WEST, EAST -> X; + default -> null; + }; + + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java index 50089a5fc..1565feb3c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java @@ -12,4 +12,6 @@ public interface BakedModel extends IForgeBakedModel { List getQuads(BlockState state, ForgeDirection face, Random random); IModelData getModelData(BlockRenderView world, BlockPos pos, BlockState state, IModelData modelData); + + boolean isAmbientOcclusion(BlockState state); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java index 0cc714bb5..84cca3e8c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java @@ -2,7 +2,6 @@ import com.gtnewhorizons.angelica.compat.forge.IForgeBlockState; import net.minecraft.block.material.Material; -import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import org.joml.Vector3d; @@ -20,7 +19,7 @@ public VoxelShape getCullingFace(BlockView view, BlockPos pos, ForgeDirection fa return null; } - public int getLightValue(World world, BlockPos pos) { return 15;} + public int getLightValue(BlockRenderView world, BlockPos pos) { return 15;} public float getAmbientOcclusionLightLevel(BlockRenderView world, BlockPos pos) { return 1.0f; } @@ -34,7 +33,7 @@ public int getOpacity(BlockRenderView world, BlockPos pos) { return 15; } - public boolean isOpaqueFullCube(World world, BlockPos pos) { + public boolean isOpaqueFullCube(BlockRenderView world, BlockPos pos) { return true; } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java index c1a87c4c7..22c02ebbc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java @@ -1,6 +1,15 @@ package com.gtnewhorizons.angelica.compat.mojang; +import java.util.SortedMap; + public class BufferBuilderStorage { + private final SortedMap entityBuilders = null; + private final VertexConsumerProvider.Immediate entityVertexConsumers; + + public BufferBuilderStorage() { + this.entityVertexConsumers = VertexConsumerProvider.immediate(this.entityBuilders, new BufferBuilder(256)); + } + public VertexConsumerProvider.Immediate getEntityVertexConsumers() { return null; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java index 8e0c9e03c..57d5f0155 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java @@ -19,4 +19,12 @@ public BlockPos getBlockPos() { public Vector3d getPos() { return new Vector3d(); } + + public float getPitch() { + return 0; + } + + public float getYaw() { + return 0; + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java index 1d3124b35..bfa4d420e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java @@ -5,4 +5,6 @@ public class ChunkOcclusionDataBuilder { public ChunkOcclusionData build() { return null; } + + public void markClosed(BlockPos.Mutable pos) {} } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java index 0654702d1..1ea2651c1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java @@ -2,6 +2,8 @@ // ChunkCoordIntPair public class ChunkPos { + public static long INT_MASK = (1L << Integer.SIZE) - 1; + public final int x; public final int z; @@ -20,6 +22,14 @@ public ChunkPos(long pos) { this.z = (int)(pos >> 32); } + public static int getPackedX(long pos) { + return (int)(pos & INT_MASK); + } + + public static int getPackedZ(long pos) { + return (int)(pos >>> 32 & INT_MASK); + } + public long toLong() { return toLong(this.x, this.z); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java index ff1180a71..0feb82473 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java @@ -46,6 +46,10 @@ public long asLong() { return asLong(this.x, this.y, this.z); } + public int getSectionX() { + return this.x; + } + public int getSectionY() { return this.y; } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/CompatMathHelper.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/CompatMathHelper.java new file mode 100644 index 000000000..1808502a3 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/CompatMathHelper.java @@ -0,0 +1,27 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class CompatMathHelper { + public static int smallestEncompassingPowerOfTwo(int value) { + int j = value - 1; + j |= j >> 1; + j |= j >> 2; + j |= j >> 4; + j |= j >> 8; + j |= j >> 16; + return j + 1; + } + public static int roundUpToMultiple(int value, int divisor) { + if (divisor == 0) { + return 0; + } else if (value == 0) { + return divisor; + } else { + if (value < 0) { + divisor *= -1; + } + + int k = value % divisor; + return k == 0 ? value : value + divisor - k; + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdListPalette.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdListPalette.java new file mode 100644 index 000000000..3429d07c6 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdListPalette.java @@ -0,0 +1,9 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class IdListPalette implements Palette { + + @Override + public T getByIndex(int i) { + return null; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java index a75fce68a..56115c5d4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java @@ -2,7 +2,17 @@ public class PackedIntegerArray { + public PackedIntegerArray(int paletteSize, int size, long[] storage) {} + public int get(int i) { return 0; } + + public long[] getStorage() { + return new long[0]; + } + + public int getSize() { + return 0; + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Palette.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Palette.java index 4e240590d..b6be6bf25 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Palette.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Palette.java @@ -2,4 +2,5 @@ public interface Palette { + T getByIndex(int i); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java index 30b7ec797..aa6d45820 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java @@ -1,12 +1,30 @@ package com.gtnewhorizons.angelica.compat.mojang; +import lombok.Getter; + import java.util.Collections; import java.util.List; import java.util.Optional; -public abstract class RenderLayer { // Aka: RenderType (Iris) - - public RenderLayer(String name, VertexFormat format, int mode, int i, Object o, boolean b, Runnable setupRenderState, Runnable clearRenderState) {} +public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris) + @Getter + private final VertexFormat vertexFormat; + @Getter + private final int drawMode; + @Getter + private final int expectedBufferSize; + private final boolean hasCrumbling; + private final boolean translucent; + private final Optional optionalThis; + public RenderLayer(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, Runnable startAction, Runnable endAction) { + super(name, startAction, endAction); + this.vertexFormat = vertexFormat; + this.drawMode = drawMode; + this.expectedBufferSize = expectedBufferSize; + this.hasCrumbling = hasCrumbling; + this.translucent = translucent; + this.optionalThis = Optional.of(this); + } public static RenderLayer solid() { return null; @@ -32,10 +50,6 @@ public static List getBlockLayers() { return Collections.emptyList(); } - public void setupRenderState() {} - - public void clearRenderState() {} - public int mode() { return 1; } @@ -54,8 +68,8 @@ public int bufferSize() { public void end(BufferBuilder buffer, int i, int i1, int i2) {} - public Object affectsCrumbling() { - return null; + public boolean hasCrumbling() { + return hasCrumbling; } public Optional outline() { @@ -66,5 +80,11 @@ public boolean isOutline() { return false; } + public Optional asOptional() { + return optionalThis; + } + + public void draw(BufferBuilder lv, int cameraX, int cameraY, int cameraZ) { + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index 7d0aae037..1030da8dd 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -4,13 +4,13 @@ public abstract class RenderPhase { protected final String name; - protected Runnable setupState; - protected final Runnable clearState; + protected Runnable beingAction; + protected final Runnable endAction; - public RenderPhase(String name, Runnable setupState, Runnable clearState) { + public RenderPhase(String name, Runnable beingAction, Runnable clearState) { this.name = name; - this.setupState = setupState; - this.clearState = clearState; + this.beingAction = beingAction; + this.endAction = clearState; } public boolean equals(@Nullable Object object) { @@ -31,11 +31,12 @@ public String toString() { return this.name; } - public void setupRenderState() { - this.setupState.run(); + public void startDrawing() { + this.beingAction.run(); } - public void clearRenderState() { - this.clearState.run(); + public void endDrawing() { + this.endAction.run(); } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java index ce0b3573b..7ec104359 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java @@ -32,4 +32,19 @@ default VertexConsumer overlay(int overlay) { default VertexConsumer light(int light) { return this.light(light & 0xFFFF, light >> 16 & 0xFFFF); } + + default VertexConsumer color(float red, float green, float blue, float alpha) { + return this.color((int)(red * 255.0F), (int)(green * 255.0F), (int)(blue * 255.0F), (int)(alpha * 255.0F)); + } + + default void vertex(float x, float y, float z, float red, float green, float blue, float alpha, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) { + this.vertex((double)x, (double)y, (double)z); + this.color(red, green, blue, alpha); + this.texture(u, v); + this.overlay(overlay); + this.light(light); + this.normal(normalX, normalY, normalZ); + this.next(); + } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java index fc0444221..138c5bebf 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java @@ -1,7 +1,91 @@ package com.gtnewhorizons.angelica.compat.mojang; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; + +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + public interface VertexConsumerProvider { + static Immediate immediate(BufferBuilder buffer) { + return immediate(ImmutableMap.of(), buffer); + } + + static Immediate immediate(Map layerBuffers, BufferBuilder fallbackBuffer) { + return new Immediate(fallbackBuffer, layerBuffers); + } + + VertexConsumer getBuffer(RenderLayer layer); + public static class Immediate implements VertexConsumerProvider { + protected final BufferBuilder fallbackBuffer; + protected final Map layerBuffers; + protected Optional currentLayer = Optional.empty(); + protected final Set activeConsumers = Sets.newHashSet(); + + protected Immediate(BufferBuilder fallbackBuffer, Map layerBuffers) { + this.fallbackBuffer = fallbackBuffer; + this.layerBuffers = layerBuffers; + } + + public VertexConsumer getBuffer(RenderLayer arg) { + Optional optional = arg.asOptional(); + BufferBuilder lv = this.getBufferInternal(arg); + if (!Objects.equals(this.currentLayer, optional)) { + if (this.currentLayer.isPresent()) { + RenderLayer lv2 = (RenderLayer)this.currentLayer.get(); + if (!this.layerBuffers.containsKey(lv2)) { + this.draw(lv2); + } + } + + if (this.activeConsumers.add(lv)) { + lv.begin(arg.getDrawMode(), arg.getVertexFormat()); + } + this.currentLayer = optional; + } + + return lv; + } + + private BufferBuilder getBufferInternal(RenderLayer layer) { + return (BufferBuilder)this.layerBuffers.getOrDefault(layer, this.fallbackBuffer); + } + + public void draw() { + this.currentLayer.ifPresent((arg) -> { + VertexConsumer lv = this.getBuffer(arg); + if (lv == this.fallbackBuffer) { + this.draw(arg); + } + + }); + Iterator var1 = this.layerBuffers.keySet().iterator(); + + while(var1.hasNext()) { + RenderLayer lv = (RenderLayer)var1.next(); + this.draw(lv); + } + + } + + public void draw(RenderLayer layer) { + BufferBuilder lv = this.getBufferInternal(layer); + boolean bl = Objects.equals(this.currentLayer, layer.asOptional()); + if (bl || lv != this.fallbackBuffer) { + if (this.activeConsumers.remove(lv)) { + layer.draw(lv, 0, 0, 0); + if (bl) { + this.currentLayer = Optional.empty(); + } + + } + } + } } } + diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java new file mode 100644 index 000000000..5d6f638b5 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java @@ -0,0 +1,71 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class VertexConsumers { + public static VertexConsumer union(VertexConsumer first, VertexConsumer second) { + return new Dual(first, second); + } + + static class Dual implements VertexConsumer { + private final VertexConsumer first; + private final VertexConsumer second; + + public Dual(VertexConsumer first, VertexConsumer second) { + if (first == second) { + throw new IllegalArgumentException("Duplicate delegates"); + } else { + this.first = first; + this.second = second; + } + } + @Override + public VertexConsumer vertex(double x, double y, double z) { + this.first.vertex(x, y, z); + this.second.vertex(x, y, z); + return this; + } + + @Override + public VertexConsumer color(int red, int green, int blue, int alpha) { + this.first.color(red, green, blue, alpha); + this.second.color(red, green, blue, alpha); + return this; + } + + @Override + public VertexConsumer texture(float u, float v) { + this.first.texture(u, v); + this.second.texture(u, v); + return this; + } + + @Override + public VertexConsumer overlay(int u, int v) { + this.first.overlay(u, v); + this.second.overlay(u, v); + return this; + } + + @Override + public VertexConsumer light(int u, int v) { + this.first.light(u, v); + this.second.light(u, v); + return this; + } + @Override + public VertexConsumer normal(float x, float y, float z) { + this.first.normal(x, y, z); + this.second.normal(x, y, z); + return this; + } + @Override + public void vertex(float x, float y, float z, float red, float green, float blue, float alpha, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) { + this.first.vertex(x, y, z, red, green, blue, alpha, u, v, overlay, light, normalX, normalY, normalZ); + this.second.vertex(x, y, z, red, green, blue, alpha, u, v, overlay, light, normalX, normalY, normalZ); + } + + public void next() { + this.first.next(); + this.second.next(); + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index fcb691fa0..abb1a846e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -18,7 +18,7 @@ public enum Mixins { ), IRIS_RENDERING(new Builder("Iris Shaders").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( - "shaders.startup.MixinFramebuffer", + "shaders.MixinFramebuffer", "shaders.MixinEntityRenderer", "shaders.MixinItem", "shaders.MixinOpenGlHelper" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorld.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorld.java new file mode 100644 index 000000000..af3f513eb --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorld.java @@ -0,0 +1,10 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(World.class) +public abstract class MixinWorld implements BlockRenderView { + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 1dda55a7d..de1b49cea 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -32,7 +32,7 @@ public static class AdvancedSettings { public boolean useFogOcclusion = true; public boolean useCompactVertexFormat = true; public boolean useBlockFaceCulling = true; - public boolean allowDirectMemoryAccess = true; + public boolean allowDirectMemoryAccess = false; public boolean ignoreDriverBlacklist = false; public boolean translucencySorting = false; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java index f2f9ff377..f18a0adf3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java @@ -2,6 +2,7 @@ import cofh.lib.util.helpers.MathHelper; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import me.jellysquid.mods.sodium.client.render.entity.EntityLightSampler; import net.minecraft.entity.Entity; @@ -15,7 +16,7 @@ public class EntityLighter { private static final double MAX_LIGHTMAP_COORD = 240.0D; public static int getBlendedLight(EntityLightSampler lighter, T entity, float tickDelta) { - boolean calcBlockLight = !entity.isOnFire(); + boolean calcBlockLight = !entity.isBurning(); // Find the interpolated position of the entity double x1 = lerp(tickDelta, entity.prevPosX, entity.posX); @@ -65,7 +66,7 @@ public static int getBlendedLight(EntityLightSampler light BlockState blockState = null; /*entity.worldObj.getBlockState(pos);*/ // Do not consider light-blocking volumes - if (blockState.isOpaqueFullCube(entity.worldObj, pos) && blockState.getLightValue(entity.worldObj, pos) <= 0) { + if (blockState.isOpaqueFullCube((BlockRenderView)entity.worldObj, pos) && blockState.getLightValue((BlockRenderView)entity.worldObj, pos) <= 0) { continue; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java index faf126614..f9ce5def4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/AoNeighborInfo.java @@ -244,6 +244,6 @@ public float getDepth(float x, float y, float z) { * @return Returns the {@link AoNeighborInfo} which corresponds with the specified direction */ public static AoNeighborInfo get(ForgeDirection direction) { - return VALUES[direction.getId()]; + return VALUES[direction.ordinal()]; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java index fa6890931..0104ad284 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java @@ -17,7 +17,9 @@ public ConfigurableColorBlender(Minecraft client) { } private static boolean isSmoothBlendingEnabled(Minecraft client) { - return client.options.biomeBlendRadius > 0; + return true; + // TODO: Sodium +// return client.options.biomeBlendRadius > 0; } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java index 46a505ad3..b3bb146e3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java @@ -3,14 +3,19 @@ import com.google.common.collect.Sets; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import net.minecraft.block.Block; +import net.minecraft.init.Blocks; import java.util.Set; public class DefaultBlockColorSettings { private static final Set BLENDED_BLOCKS = new ReferenceOpenHashSet<>(Sets.newHashSet( - Blocks.FERN, Blocks.LARGE_FERN, Blocks.POTTED_FERN, Blocks.GRASS, Blocks.TALL_GRASS, - Blocks.GRASS_BLOCK, Blocks.OAK_LEAVES, Blocks.JUNGLE_LEAVES, Blocks.ACACIA_LEAVES, Blocks.DARK_OAK_LEAVES, - Blocks.VINE, Blocks.WATER, Blocks.BUBBLE_COLUMN, Blocks.CAULDRON, Blocks.SUGAR_CANE)); + Blocks.grass, Blocks.leaves, Blocks.leaves2, Blocks.tallgrass, Blocks.water, + Blocks.cauldron, Blocks.reeds, Blocks.vine)); + +// private static final Set BLENDED_BLOCKS = new ReferenceOpenHashSet<>(Sets.newHashSet( +// Blocks.FERN, Blocks.LARGE_FERN, Blocks.POTTED_FERN, Blocks.GRASS, Blocks.TALL_GRASS, +// Blocks.GRASS_BLOCK, Blocks.OAK_LEAVES, Blocks.JUNGLE_LEAVES, Blocks.ACACIA_LEAVES, Blocks.DARK_OAK_LEAVES, +// Blocks.VINE, Blocks.WATER, Blocks.BUBBLE_COLUMN, Blocks.CAULDRON, Blocks.SUGAR_CANE)); public static boolean isSmoothBlendingAvailable(Block block) { return BLENDED_BLOCKS.contains(block); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java index fbd5629b0..6f082ce9f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.model.quad.properties; +import com.gtnewhorizons.angelica.compat.mojang.Axis; import com.gtnewhorizons.angelica.compat.mojang.BakedQuad; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import net.minecraftforge.common.util.ForgeDirection; @@ -33,8 +34,9 @@ public static boolean contains(int flags, int mask) { * certain optimizations. */ public static int getQuadFlags(BakedQuad bakedQuad) { - ModelQuadView quad = (ModelQuadView) bakedQuad; - ForgeDirection face = bakedQuad.getFace(); + final ModelQuadView quad = (ModelQuadView) bakedQuad; + final ForgeDirection face = bakedQuad.getFace(); + final Axis axis = Axis.fromDirection(face); float minX = 32.0F; float minY = 32.0F; @@ -57,59 +59,29 @@ public static int getQuadFlags(BakedQuad bakedQuad) { maxZ = Math.max(maxZ, z); } - boolean partial = false; - - switch (face.getAxis()) { - case X : - partial = minY >= 0.0001f || minZ >= 0.0001f || maxY <= 0.9999F || maxZ <= 0.9999F; - break; - case Y : - partial = minX >= 0.0001f || minZ >= 0.0001f || maxX <= 0.9999F || maxZ <= 0.9999F; - break; - case Z : - partial = minX >= 0.0001f || minY >= 0.0001f || maxX <= 0.9999F || maxY <= 0.9999F; - break; + boolean partial = switch (axis) { + case X -> minY >= 0.0001f || minZ >= 0.0001f || maxY <= 0.9999F || maxZ <= 0.9999F; + case Y -> minX >= 0.0001f || minZ >= 0.0001f || maxX <= 0.9999F || maxZ <= 0.9999F; + case Z -> minX >= 0.0001f || minY >= 0.0001f || maxX <= 0.9999F || maxY <= 0.9999F; }; - boolean parallel = false; - - switch(face.getAxis()) { - case X : - parallel = minX == maxX; - break; - case Y : - parallel = minY == maxY; - break; - case Z : - parallel = minZ == maxZ; - break; + boolean parallel = switch (axis) { + case X -> minX == maxX; + case Y -> minY == maxY; + case Z -> minZ == maxZ; }; - boolean aligned = false; - boolean flag = false; - - switch (face) { - case DOWN : - flag = minY < 0.0001f; - break; - case UP : - flag = maxY > 0.9999F; - break; - case NORTH : - flag = minZ < 0.0001f; - break; - case SOUTH : - flag = maxZ > 0.9999F; - break; - case WEST : - flag = minX < 0.0001f; - break; - case EAST : - flag = maxX > 0.9999F; - break; + boolean flag = switch (face) { + case DOWN -> minY < 0.0001f; + case UP -> maxY > 0.9999F; + case NORTH -> minZ < 0.0001f; + case SOUTH -> maxZ > 0.9999F; + case WEST -> minX < 0.0001f; + case EAST -> maxX > 0.9999F; + default -> false; }; - aligned = parallel && flag; + boolean aligned = parallel && flag; int flags = 0; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java deleted file mode 100644 index 22984520b..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java +++ /dev/null @@ -1,33 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.vertex.buffer; - -import me.jellysquid.mods.sodium.client.model.vertex.type.BufferVertexType; - -/** - * An unsafe {@link VertexBufferWriter} implementation which uses direct memory operations to enable fast blitting of - * data into memory buffers. Only available on JVMs which support {@link sun.misc.Unsafe}, but generally produces much - * better optimized code than other implementations. The implementation does not check for invalid memory accesses, - * meaning that errors can corrupt process memory. - */ -public abstract class VertexBufferWriterUnsafe extends VertexBufferWriter { - /** - * The write pointer into the buffer storage. This is advanced by the vertex stride every time - * {@link VertexBufferWriterUnsafe#advance()} is called. - */ - protected long writePointer; - - protected VertexBufferWriterUnsafe(VertexBufferView backingBuffer, BufferVertexType vertexType) { - super(backingBuffer, vertexType); - } - - @Override - protected void onBufferStorageChanged() { - this.writePointer = MemoryUtil.memAddress(this.backingBuffer.getDirectBuffer(), this.backingBuffer.getWriterPosition()); - } - - @Override - protected void advance() { - this.writePointer += this.vertexStride; - - super.advance(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java index 2be896c8a..b7291da9d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java @@ -4,7 +4,6 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer.GlyphVertexBufferWriterNio; -import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer.GlyphVertexBufferWriterUnsafe; 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; @@ -13,7 +12,7 @@ public class GlyphVertexType implements VanillaVertexType, BlittableVertexType { @Override public GlyphVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return direct ? new GlyphVertexBufferWriterUnsafe(buffer) : new GlyphVertexBufferWriterNio(buffer); + return new GlyphVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java deleted file mode 100644 index 6c39c4ff8..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java +++ /dev/null @@ -1,28 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer; - -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -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; - -public class GlyphVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements GlyphVertexSink { - public GlyphVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { - super(backingBuffer, VanillaVertexTypes.GLYPHS); - } - - @Override - public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) { - long i = this.writePointer; - - MemoryUtil.memPutFloat(i, x); - MemoryUtil.memPutFloat(i + 4, y); - MemoryUtil.memPutFloat(i + 8, z); - MemoryUtil.memPutInt(i + 12, color); - MemoryUtil.memPutFloat(i + 16, u); - MemoryUtil.memPutFloat(i + 20, v); - MemoryUtil.memPutInt(i + 24, light); - - this.advance(); - - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java index 5e2ca5f05..6170f686c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java @@ -4,7 +4,6 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexBufferWriterNio; -import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; @@ -13,7 +12,7 @@ public class LineVertexType implements VanillaVertexType, BlittableVertexType { @Override public LineVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return direct ? new LineVertexBufferWriterUnsafe(buffer) : new LineVertexBufferWriterNio(buffer); + return new LineVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java deleted file mode 100644 index 9b6290623..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java +++ /dev/null @@ -1,24 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer; - -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -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.line.LineVertexSink; - -public class LineVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements LineVertexSink { - public LineVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { - super(backingBuffer, VanillaVertexTypes.LINES); - } - - @Override - public void vertexLine(float x, float y, float z, int color) { - long i = this.writePointer; - - MemoryUtil.memPutFloat(i, x); - MemoryUtil.memPutFloat(i + 4, y); - MemoryUtil.memPutFloat(i + 8, z); - MemoryUtil.memPutInt(i + 12, color); - - this.advance(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java index cdaff0e62..c0a7ec15c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java @@ -4,7 +4,6 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexBufferWriterNio; -import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; @@ -12,7 +11,7 @@ public class ParticleVertexType implements VanillaVertexType, BlittableVertexType { @Override public ParticleVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return direct ? new ParticleVertexBufferWriterUnsafe(buffer) : new ParticleVertexBufferWriterNio(buffer); + return new ParticleVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java deleted file mode 100644 index 770c70655..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java +++ /dev/null @@ -1,27 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer; - -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -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.particle.ParticleVertexSink; - -public class ParticleVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ParticleVertexSink { - public ParticleVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { - super(backingBuffer, VanillaVertexTypes.PARTICLES); - } - - @Override - public void writeParticle(float x, float y, float z, float u, float v, int color, int light) { - long i = this.writePointer; - - MemoryUtil.memPutFloat(i, x); - MemoryUtil.memPutFloat(i + 4, y); - MemoryUtil.memPutFloat(i + 8, z); - MemoryUtil.memPutFloat(i + 12, u); - MemoryUtil.memPutFloat(i + 16, v); - MemoryUtil.memPutInt(i + 20, color); - MemoryUtil.memPutInt(i + 24, light); - - this.advance(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java index 094c9e9fe..9e16c989a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java @@ -4,7 +4,6 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer.QuadVertexBufferWriterNio; -import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer.QuadVertexBufferWriterUnsafe; 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; @@ -18,7 +17,7 @@ public QuadVertexSink createFallbackWriter(VertexConsumer consumer) { @Override public QuadVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return direct ? new QuadVertexBufferWriterUnsafe(buffer) : new QuadVertexBufferWriterNio(buffer); + return new QuadVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java deleted file mode 100644 index 104a6339e..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java +++ /dev/null @@ -1,29 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer; - -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -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.quad.QuadVertexSink; - -public class QuadVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements QuadVertexSink { - public QuadVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { - super(backingBuffer, VanillaVertexTypes.QUADS); - } - - @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; - - MemoryUtil.memPutFloat(i, x); - MemoryUtil.memPutFloat(i + 4, y); - MemoryUtil.memPutFloat(i + 8, z); - MemoryUtil.memPutInt(i + 12, color); - MemoryUtil.memPutFloat(i + 16, u); - MemoryUtil.memPutFloat(i + 20, v); - MemoryUtil.memPutInt(i + 24, overlay); - MemoryUtil.memPutInt(i + 28, light); - MemoryUtil.memPutInt(i + 32, normal); - - this.advance(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java index 796dd3e70..0d0070506 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java @@ -4,7 +4,6 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexBufferWriterNio; -import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; @@ -18,7 +17,7 @@ public BasicScreenQuadVertexSink createFallbackWriter(VertexConsumer consumer) { @Override public BasicScreenQuadVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return direct ? new BasicScreenQuadVertexBufferWriterUnsafe(buffer) : new BasicScreenQuadVertexBufferWriterNio(buffer); + return new BasicScreenQuadVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java deleted file mode 100644 index 6f5b93ec1..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java +++ /dev/null @@ -1,24 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer; - -import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; -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.screen_quad.BasicScreenQuadVertexSink; - -public class BasicScreenQuadVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements BasicScreenQuadVertexSink { - public BasicScreenQuadVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { - super(backingBuffer, VanillaVertexTypes.BASIC_SCREEN_QUADS); - } - - @Override - public void writeQuad(float x, float y, float z, int color) { - long i = this.writePointer; - - MemoryUtil.memPutFloat(i, x); - MemoryUtil.memPutFloat(i + 4, y); - MemoryUtil.memPutFloat(i + 8, z); - MemoryUtil.memPutInt(i + 12, color); - - this.advance(); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index f0b28e505..9d084bf0e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -3,6 +3,7 @@ import cofh.lib.util.helpers.MathHelper; import com.gtnewhorizons.angelica.compat.mojang.BlockBreakingInfo; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BufferBuilderStorage; import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; @@ -12,11 +13,12 @@ import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import com.gtnewhorizons.angelica.compat.mojang.VertexConsumerProvider; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumers; import com.gtnewhorizons.angelica.glsm.GLStateManager; -import com.rwtema.extrautils.block.Box; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import lombok.Getter; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; @@ -38,9 +40,11 @@ import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.profiler.Profiler; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; import org.joml.Vector3d; import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap; @@ -64,8 +68,14 @@ public class SodiumWorldRenderer implements ChunkStatusListener { private boolean useEntityCulling; private final LongSet loadedChunkPositions = new LongOpenHashSet(); - private final Set globalBlockEntities = new ObjectOpenHashSet<>(); + private final Set globalTileEntities = new ObjectOpenHashSet<>(); + /** + * -- GETTER -- + * + * @return The frustum of the current player's camera used to cull chunks + */ + @Getter private Frustrum frustum; private ChunkRenderManager chunkRenderManager; private BlockRenderPassManager renderPassManager; @@ -122,11 +132,11 @@ private void loadWorld(WorldClient world) { this.initRenderer(); - ((ChunkStatusListenerManager) world.getChunkManager()).setListener(this); + ((ChunkStatusListenerManager) world.getWorldChunkManager()).setListener(this); } private void unloadWorld() { - ChunkRenderCacheShared.destroyRenderContext(this.world); + ChunkRenderCacheShared.destroyRenderContext((BlockRenderView)this.world); if (this.chunkRenderManager != null) { this.chunkRenderManager.destroy(); @@ -139,7 +149,7 @@ private void unloadWorld() { } this.loadedChunkPositions.clear(); - this.globalBlockEntities.clear(); + this.globalTileEntities.clear(); this.world = null; } @@ -179,7 +189,7 @@ public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrust this.useEntityCulling = SodiumClientMod.options().advanced.useEntityCulling; - Profiler profiler = this.client.getProfiler(); + Profiler profiler = this.client.mcProfiler; profiler.startSection("camera_setup"); EntityPlayer player = this.client.thePlayer; @@ -224,7 +234,8 @@ public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrust profiler.endSection(); - Entity.setRenderDistanceMultiplier(MathHelper.clamp((double) this.client.options.viewDistance / 8.0D, 1.0D, 2.5D) * (double) this.client.options.entityDistanceScaling); + // TODO: Sodium RenderDistance +// Entity.setRenderDistanceMultiplier(MathHelper.clamp((double) this.client.options.viewDistance / 8.0D, 1.0D, 2.5D) * (double) 1.0F/*this.client.options.entityDistanceScaling*/); } /** @@ -277,13 +288,11 @@ private void initRenderer() { this.chunkRenderBackend = createChunkRenderBackend(device, opts, vertexFormat); this.chunkRenderBackend.createShaders(device); - this.chunkRenderManager = new ChunkRenderManager<>(this, this.chunkRenderBackend, this.renderPassManager, this.world, this.client.options.viewDistance); + this.chunkRenderManager = new ChunkRenderManager<>(this, this.chunkRenderBackend, this.renderPassManager, this.world, this.client.gameSettings.renderDistanceChunks); this.chunkRenderManager.restoreChunks(this.loadedChunkPositions); } - private static ChunkRenderBackend createChunkRenderBackend(RenderDevice device, - SodiumGameOptions options, - ChunkVertexType vertexFormat) { + private static ChunkRenderBackend createChunkRenderBackend(RenderDevice device, SodiumGameOptions options, ChunkVertexType vertexFormat) { boolean disableBlacklist = SodiumClientMod.options().advanced.ignoreDriverBlacklist; if (options.advanced.useChunkMultidraw && MultidrawChunkRenderBackend.isSupported(disableBlacklist)) { @@ -326,21 +335,22 @@ public void renderTileEntities(MatrixStack matrices, BufferBuilderStorage buffer consumer = (layer) -> layer.hasCrumbling() ? VertexConsumers.union(transformer, immediate.getBuffer(layer)) : immediate.getBuffer(layer); } } - - BlockEntityRenderDispatcher.INSTANCE.render(tileEntity, tickDelta, matrices, consumer); + // TODO: Sodium TileEntity Rendering Dispatcher +// BlockEntityRenderDispatcher.INSTANCE.render(tileEntity, tickDelta, matrices, consumer); matrices.pop(); } - for (TileEntity blockEntity : this.globalBlockEntities) { - if(!checkBEVisibility(blockEntity)) + for (TileEntity tileEntity : this.globalTileEntities) { + if(!checkBEVisibility(tileEntity)) continue; - BlockPos pos = blockEntity.getPos(); + BlockPos pos = new BlockPos(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); matrices.push(); matrices.translate((double) pos.x - x, (double) pos.y - y, (double) pos.z - z); - BlockEntityRenderDispatcher.INSTANCE.render(blockEntity, tickDelta, matrices, immediate); + // TODO: Sodium TileEntity Rendering Dispatcher +// BlockEntityRenderDispatcher.INSTANCE.render(tileEntity, tickDelta, matrices, immediate); matrices.pop(); } @@ -359,12 +369,12 @@ public void onChunkRemoved(int x, int z) { } public void onChunkRenderUpdated(int x, int y, int z, ChunkRenderData meshBefore, ChunkRenderData meshAfter) { - ListUtil.updateList(this.globalBlockEntities, meshBefore.getGlobalBlockEntities(), meshAfter.getGlobalBlockEntities()); + ListUtil.updateList(this.globalTileEntities, meshBefore.getGlobalBlockEntities(), meshAfter.getGlobalBlockEntities()); this.chunkRenderManager.onChunkRenderUpdates(x, y, z, meshAfter); } - private static boolean isInfiniteExtentsBox(Box box) { + private static boolean isInfiniteExtentsBox(AxisAlignedBB box) { return Double.isInfinite(box.minX) || Double.isInfinite(box.minY) || Double.isInfinite(box.minZ) || Double.isInfinite(box.maxX) || Double.isInfinite(box.maxY) || Double.isInfinite(box.maxZ); } @@ -378,7 +388,7 @@ public boolean isEntityVisible(Entity entity) { return true; } - Box box = entity.getVisibilityBoundingBox(); + AxisAlignedBB box = entity.getBoundingBox(); // Entities outside the valid world height will never map to a rendered chunk // Always render these entities or they'll be culled incorrectly! @@ -391,7 +401,8 @@ public boolean isEntityVisible(Entity entity) { } // Ensure entities with outlines or nametags are always visible - if (this.client.hasOutline(entity) || entity.shouldRenderName()) { + // TODO: Sodium - Outlines + if (/*this.client.hasOutline(entity) || */ (entity instanceof EntityLiving living && living.hasCustomNameTag())) { return true; } @@ -416,13 +427,6 @@ public boolean isEntityVisible(Entity entity) { return false; } - /** - * @return The frustum of the current player's camera used to cull chunks - */ - public Frustrum getFrustum() { - return this.frustum; - } - public String getChunksDebugString() { // C: visible/total // TODO: add dirty and queued counts diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java index cf688faf8..112382440 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java @@ -9,7 +9,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; - +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import java.lang.reflect.Array; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index cf2b56dbc..b3faacf3a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -33,10 +33,8 @@ import me.jellysquid.mods.sodium.common.util.DirectionUtil; import me.jellysquid.mods.sodium.common.util.IdTable; import me.jellysquid.mods.sodium.common.util.collections.FutureDequeDrain; -import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.tileentity.TileEntity; -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraftforge.common.util.ForgeDirection; import org.joml.Vector3d; @@ -572,7 +570,9 @@ public int getTotalSections() { } private void scheduleRebuildOffThread(int x, int y, int z, boolean important) { - Minecraft.getMinecraft().submit(() -> this.scheduleRebuild(x, y, z, important)); + // TODO: Sodium Threads + throw new RuntimeException("scheduleRebuildOffThread"); +// Minecraft.getMinecraft().submit(() -> this.scheduleRebuild(x, y, z, important)); } public void scheduleRebuild(int x, int y, int z, boolean important) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java index 33ba73a82..a4e2351d7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; +import com.gtnewhorizons.angelica.compat.mojang.CompatMathHelper; import java.nio.ByteBuffer; @@ -15,7 +16,7 @@ public abstract class ChunkDrawCallBatcher extends StructBuffer { protected int arrayLength; protected ChunkDrawCallBatcher(int capacity) { - super(MathHelper.smallestEncompassingPowerOfTwo(capacity), 16); + super(CompatMathHelper.smallestEncompassingPowerOfTwo(capacity), 16); this.capacity = capacity; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java index 2c993110f..f5c64cbbe 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java @@ -32,7 +32,7 @@ protected void growBuffer() { ByteBuffer oldBuffer = this.buffer; this.capacity = this.capacity * 2; this.buffer = BufferUtils.createByteBuffer(this.capacity * this.stride); - buffer.put(oldBuffer.rewind()); + buffer.put((ByteBuffer) oldBuffer.rewind()); } public static class NioChunkDrawCallVector extends ChunkDrawParamsVector { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java index 8e798b424..849a8d2a4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java @@ -34,6 +34,6 @@ public void pushCommandBuffer(ChunkDrawCallBatcher batcher) { protected void growBuffer(int n) { ByteBuffer oldBuffer = this.buffer; this.buffer = BufferUtils.createByteBuffer(Math.max(oldBuffer.capacity() * 2, oldBuffer.capacity() + n)); - buffer.put(oldBuffer.rewind()); + buffer.put((ByteBuffer) oldBuffer.rewind()); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java index b32ac0793..cce6b4c14 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java @@ -15,6 +15,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkModelOffset; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPassManager; +import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; import java.util.Map; @@ -101,7 +102,7 @@ public ChunkMeshData createMesh(BlockRenderPass pass, float x, float y, float z, return null; } - ByteBuffer buffer = GlAllocationUtils.allocateByteBuffer(bufferLen); + ByteBuffer buffer = BufferUtils.createByteBuffer(bufferLen); for (Map.Entry entry : meshData.getSlices()) { BufferSlice slice = entry.getValue(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java index e2e44599b..98120b13b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java @@ -2,6 +2,7 @@ import cofh.lib.util.helpers.MathHelper; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionData; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; @@ -11,7 +12,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.cull.ChunkCuller; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.client.Minecraft; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; @@ -73,7 +73,8 @@ private boolean isWithinRenderDistance(ChunkGraphNode adj) { private void initSearch(Camera camera, FrustumExtended frustum, int frame, boolean spectator) { this.activeFrame = frame; this.frustum = frustum; - this.useOcclusionCulling = Minecraft.getMinecraft().chunkCullingEnabled; + // TODO: Sodium Options + this.useOcclusionCulling = true; //Minecraft.getMinecraft().chunkCullingEnabled; this.visible.clear(); @@ -93,7 +94,7 @@ private void initSearch(Camera camera, FrustumExtended frustum, int frame, boole rootNode.resetCullingState(); rootNode.setLastVisibleFrame(frame); - if (spectator && this.world.getBlockState(origin).isOpaqueFullCube(this.world, origin)) { + if (spectator && ((BlockRenderView)this.world).getBlockState(origin).isOpaqueFullCube((BlockRenderView) this.world, origin)) { this.useOcclusionCulling = false; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java deleted file mode 100644 index 9dbc96bd1..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java +++ /dev/null @@ -1,41 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.format.hfp; - -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.render.chunk.format.DefaultModelVertexFormats; -import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; -import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexUtil; - -public class HFPModelVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ModelVertexSink { - public HFPModelVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { - super(backingBuffer, DefaultModelVertexFormats.MODEL_VERTEX_HFP); - } - - @Override - public void writeQuad(float x, float y, float z, int color, float u, float v, int light) { - this.writeQuadInternal( - ModelVertexUtil.denormalizeVertexPositionFloatAsShort(x), - ModelVertexUtil.denormalizeVertexPositionFloatAsShort(y), - ModelVertexUtil.denormalizeVertexPositionFloatAsShort(z), - color, - ModelVertexUtil.denormalizeVertexTextureFloatAsShort(u), - ModelVertexUtil.denormalizeVertexTextureFloatAsShort(v), - ModelVertexUtil.encodeLightMapTexCoord(light) - ); - } - - private void writeQuadInternal(short x, short y, short z, int color, short u, short v, int light) { - long i = this.writePointer; - - MemoryUtil.memPutShort(i, x); - MemoryUtil.memPutShort(i + 2, y); - MemoryUtil.memPutShort(i + 4, z); - MemoryUtil.memPutInt(i + 8, color); - MemoryUtil.memPutShort(i + 12, u); - MemoryUtil.memPutShort(i + 14, v); - MemoryUtil.memPutInt(i + 16, light); - - this.advance(); - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java index 22355e26f..fbf5c01b9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java @@ -35,7 +35,7 @@ public ModelVertexSink createFallbackWriter(VertexConsumer consumer) { @Override public ModelVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return direct ? new HFPModelVertexBufferWriterUnsafe(buffer) : new HFPModelVertexBufferWriterNio(buffer); + return new HFPModelVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java deleted file mode 100644 index 3e3944d21..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java +++ /dev/null @@ -1,49 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.format.sfp; - -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.render.chunk.format.DefaultModelVertexFormats; -import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; - -public class SFPModelVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ModelVertexSink { - public SFPModelVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { - super(backingBuffer, DefaultModelVertexFormats.MODEL_VERTEX_SFP); - } - - @Override - public void writeQuad(float x, float y, float z, int color, float u, float v, int light) { - long i = this.writePointer; - - MemoryUtil.memPutFloat(i, x); - MemoryUtil.memPutFloat(i + 4, y); - MemoryUtil.memPutFloat(i + 8, z); - MemoryUtil.memPutInt(i + 12, color); - MemoryUtil.memPutFloat(i + 16, u); - MemoryUtil.memPutFloat(i + 20, v); - MemoryUtil.memPutInt(i + 24, encodeLightMapTexCoord(light)); - - this.advance(); - } - - /** - * This moves some work out the shader code and simplifies things a bit. In vanilla, the game encodes light map - * texture coordinates as two un-normalized unsigned shorts in the range 0..255. Using the fixed-function pipeline, - * it then applies a matrix transformation which normalizes these coordinates and applies a centering offset. This - * operation has non-zero overhead and complicates shader code a bit. - * - * To work around the problem, this function instead normalizes these light map texture coordinates and applies the - * centering offset, allowing it to be baked into the vertex data itself. - * - * @param light The light map value - * @return The light map texture coordinates as two unsigned shorts with a center offset applied - */ - private static int encodeLightMapTexCoord(int light) { - int sl = (light >> 16) & 255; - sl = (sl << 8) + 2048; - - int bl = light & 255; - bl = (bl << 8) + 2048; - - return (sl << 16) | bl; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java index 984f1640d..3692e9e72 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java @@ -33,7 +33,7 @@ public ModelVertexSink createFallbackWriter(VertexConsumer consumer) { @Override public ModelVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return direct ? new SFPModelVertexBufferWriterUnsafe(buffer) : new SFPModelVertexBufferWriterNio(buffer); + return new SFPModelVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java index 42700d755..f32da240e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java @@ -1,7 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.shader; import me.jellysquid.mods.sodium.client.gl.compat.FogHelper; -import org.joml.Vector3f; import org.lwjgl.opengl.GL20; /** @@ -39,8 +38,8 @@ public Exp2(ChunkProgram program) { @Override public void setup() { - final Vector3f fogColor = FogHelper.getFogColor(); - GL20.glUniform4f(this.uFogColor, FogHelper.getFogColor()); + final float[] fc = FogHelper.getFogColor(); + GL20.glUniform4f(this.uFogColor, fc[0], fc[1], fc[2], fc[3]); GL20.glUniform1f(this.uFogDensity, FogHelper.getFogDensity()); } } @@ -62,9 +61,9 @@ public void setup() { float start = FogHelper.getFogStart(); float[] color = FogHelper.getFogColor(); - GL20C.glUniform4fv(this.uFogColor, color); - GL20C.glUniform1f(this.uFogLength, end - start); - GL20C.glUniform1f(this.uFogEnd, end); + GL20.glUniform4f(this.uFogColor, color[0], color[1], color[2], color[3]); + GL20.glUniform1f(this.uFogLength, end - start); + GL20.glUniform1f(this.uFogEnd, end); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 200f2e280..3a0b760b2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -3,16 +3,17 @@ import com.gtnewhorizons.angelica.compat.forge.EmptyModelData; import com.gtnewhorizons.angelica.compat.forge.ForgeHooksClientExt; import com.gtnewhorizons.angelica.compat.forge.IModelData; +import com.gtnewhorizons.angelica.compat.forge.ModelDataManager; import com.gtnewhorizons.angelica.compat.mojang.BakedModel; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderType; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionDataBuilder; +import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import com.gtnewhorizons.angelica.compat.mojang.FluidState; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.compat.mojang.RenderLayers; -import com.rwtema.extrautils.ChunkPos; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer; @@ -59,7 +60,9 @@ public ChunkRenderRebuildTask(ChunkRenderContainer render, ChunkRenderContext this.camera = new Vector3d(); this.translucencySorting = SodiumClientMod.options().advanced.translucencySorting; - this.modelDataMap = ModelDataManager.getModelData(Minecraft.getMinecraft().world, new ChunkPos(ChunkSectionPos.getSectionCoord(this.render.getOriginX()), ChunkSectionPos.getSectionCoord(this.render.getOriginZ()))); + this.modelDataMap = ModelDataManager.getModelData( + Minecraft.getMinecraft().theWorld, + new ChunkPos(ChunkSectionPos.getSectionCoord(this.render.getOriginX()), ChunkSectionPos.getSectionCoord(this.render.getOriginZ()))); } public ChunkRenderRebuildTask withCameraPosition(Vector3d camera) { @@ -144,11 +147,12 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB TileEntity entity = slice.getBlockEntity(pos); if (entity != null) { - BlockEntityRenderer renderer = BlockEntityRenderDispatcher.INSTANCE.get(entity); - - if (renderer != null) { - bounds.addBlock(relX, relY, relZ); - } + // TODO: Sodium TileEntity Rendering +// BlockEntityRenderer renderer = BlockEntityRenderDispatcher.INSTANCE.get(entity); +// +// if (renderer != null) { +// bounds.addBlock(relX, relY, relZ); +// } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java index 686083e6a..69a0cdc6e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderTranslucencySortTask.java @@ -15,6 +15,7 @@ import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheLocal; import me.jellysquid.mods.sodium.client.util.task.CancellationSource; import org.joml.Vector3d; +import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; import java.util.Arrays; @@ -58,7 +59,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB continue; // Make a snapshot of the translucency data to sort - ByteBuffer sortedData = GlAllocationUtils.allocateByteBuffer(translucencyData.capacity()); + ByteBuffer sortedData = BufferUtils.createByteBuffer(translucencyData.capacity()); synchronized (translucencyData) { sortedData.put(translucencyData); translucencyData.position(0); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index ac2079f0d..dc02d21d9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -28,6 +28,7 @@ import me.jellysquid.mods.sodium.client.world.biome.BlockColorsExtended; import me.jellysquid.mods.sodium.common.util.DirectionUtil; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraftforge.common.util.ForgeDirection; import org.joml.Vector3d; @@ -35,6 +36,7 @@ import java.util.Random; public class BlockRenderer { + public static Vector3d ZERO = new Vector3d(0, 0, 0); private static final MatrixStack EMPTY_STACK = new MatrixStack(); private final Random random = new XoRoShiRoRandom(); @@ -52,13 +54,15 @@ public class BlockRenderer { private final boolean useAmbientOcclusion; public BlockRenderer(Minecraft client, LightPipelineProvider lighters, BiomeColorBlender biomeColorBlender) { - this.blockColors = (BlockColorsExtended) client.getBlockColors(); + // TODO: Sodium - Block Colors + this.blockColors = (BlockColorsExtended) null; //client.getBlockColors(); this.biomeColorBlender = biomeColorBlender; this.lighters = lighters; this.occlusionCache = new BlockOcclusionCache(); - this.useAmbientOcclusion = MinecraftClient.isAmbientOcclusionEnabled(); + // TODO: Sodium - AO Setting + this.useAmbientOcclusion = Minecraft.getMinecraft().gameSettings.ambientOcclusion > 0; } public boolean renderModel(BlockRenderView world, BlockState state, BlockPos pos, BakedModel model, ChunkModelBuffers buffers, boolean cull, long seed, IModelData modelData) { @@ -72,7 +76,7 @@ public boolean renderModel(BlockRenderView world, BlockState state, BlockPos pos if(ForgeBlockRenderer.useForgeLightingPipeline()) { MatrixStack mStack; - if(offset != Vector3d.ZERO) { + if(!offset.equals(ZERO)) { mStack = new MatrixStack(); mStack.translate(offset.x, offset.y, offset.z); } else @@ -156,9 +160,9 @@ private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, M for (int dstIndex = 0; dstIndex < 4; dstIndex++) { int srcIndex = order.getVertexIndex(dstIndex); - float x = src.getX(srcIndex) + (float) offset.getX(); - float y = src.getY(srcIndex) + (float) offset.getY(); - float z = src.getZ(srcIndex) + (float) offset.getZ(); + float x = src.getX(srcIndex) + (float) offset.x; + float y = src.getY(srcIndex) + (float) offset.y; + float z = src.getZ(srcIndex) + (float) offset.z; int color = ColorABGR.mul(colors != null ? colors[srcIndex] : src.getColor(srcIndex), light.br[srcIndex]); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java index ada91f23c..fdd674b49 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java @@ -8,19 +8,20 @@ import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; import net.minecraft.client.Minecraft; +import net.minecraft.world.World; import java.util.Map; public class ChunkRenderCacheShared extends ChunkRenderCache { - private static final Map INSTANCES = new Reference2ObjectOpenHashMap<>(); + private static final Map INSTANCES = new Reference2ObjectOpenHashMap<>(); private final BlockRenderer blockRenderer; private final HashLightDataCache lightCache; - private ChunkRenderCacheShared(BlockRenderView world) { + private ChunkRenderCacheShared(World world) { Minecraft client = Minecraft.getMinecraft(); - this.lightCache = new HashLightDataCache(world); + this.lightCache = new HashLightDataCache((BlockRenderView)world); BiomeColorBlender biomeColorBlender = this.createBiomeColorBlender(); LightPipelineProvider lightPipelineProvider = new LightPipelineProvider(this.lightCache); @@ -52,7 +53,7 @@ public static void destroyRenderContext(BlockRenderView world) { } } - public static void createRenderContext(BlockRenderView world) { + public static void createRenderContext(World world) { if (INSTANCES.containsKey(world)) { throw new IllegalStateException("Render context already exists for world: " + world); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java index 71a6c2be0..c845a451c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java @@ -34,7 +34,8 @@ public class ModelQuadUtil { static { for (int i = 0; i < NORMALS.length; i++) { - NORMALS[i] = Norm3b.pack(DirectionUtil.ALL_DIRECTIONS[i].getVector()); + final ForgeDirection dir = DirectionUtil.ALL_DIRECTIONS[i]; + NORMALS[i] = Norm3b.pack(dir.offsetX, dir.offsetY, dir.offsetZ); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java index 7c5b757dc..e3ab5ae85 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java @@ -11,6 +11,10 @@ public class FastCubicSampler { private static final double[] DENSITY_CURVE = new double[] { 0.0D, 1.0D, 4.0D, 6.0D, 4.0D, 1.0D, 0.0D }; private static final int DIAMETER = 6; + private static Vector3d unpackRgb(int rgb) { + return new Vector3d((rgb >> 16 & 255) / 255.0, (rgb >> 8 & 255) / 255.0, (rgb & 255) / 255.0); + } + public static Vector3d sampleColor(Vector3d pos, ColorFetcher colorFetcher, Function transformer) { int intX = MathHelper.floor(pos.x); int intY = MathHelper.floor(pos.y); @@ -35,7 +39,7 @@ public static Vector3d sampleColor(Vector3d pos, ColorFetcher colorFetcher, Func // Fast path! Skip blending the colors if all inputs are the same if (isHomogenousArray(values)) { // Take the first color if it's homogenous (all elements are the same...) - return transformer.apply(Vector3d.unpackRgb(values[0])); + return transformer.apply(unpackRgb(values[0])); } double deltaX = pos.x - (double)intX; @@ -57,13 +61,13 @@ public static Vector3d sampleColor(Vector3d pos, ColorFetcher colorFetcher, Func double factor = densityX * densityY * densityZ; totalFactor += factor; - Vector3d color = transformer.apply(Vector3d.unpackRgb(values[index(x, y, z)])); - sum = sum.add(color.multiply(factor)); + Vector3d color = transformer.apply(unpackRgb(values[index(x, y, z)])); + sum.add(color.mul(factor)); } } } - sum = sum.multiply(1.0D / totalFactor); + sum.mul(1.0D / totalFactor); return sum; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index db18556ca..e340f42e7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -6,6 +6,7 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import com.gtnewhorizons.angelica.compat.mojang.ColorResolver; +import com.gtnewhorizons.angelica.compat.mojang.CompatMathHelper; import com.gtnewhorizons.angelica.compat.mojang.FluidState; import com.gtnewhorizons.angelica.compat.mojang.LightType; import com.gtnewhorizons.angelica.compat.mojang.LightingProvider; @@ -20,7 +21,6 @@ import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; import net.minecraft.client.Minecraft; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.chunk.Chunk; @@ -51,14 +51,14 @@ public class WorldSlice implements BlockRenderView, BiomeAccess.Storage { private static final int NEIGHBOR_BLOCK_RADIUS = 2; // The radius of chunks around the origin chunk that should be copied. - private static final int NEIGHBOR_CHUNK_RADIUS = MathHelper.roundUpToMultiple(NEIGHBOR_BLOCK_RADIUS, 16) >> 4; + private static final int NEIGHBOR_CHUNK_RADIUS = CompatMathHelper.roundUpToMultiple(NEIGHBOR_BLOCK_RADIUS, 16) >> 4; // The number of sections on each axis of this slice. private static final int SECTION_LENGTH = 1 + (NEIGHBOR_CHUNK_RADIUS * 2); // The size of the lookup tables used for mapping values to coordinate int pairs. The lookup table size is always // a power of two so that multiplications can be replaced with simple bit shifts in hot code paths. - private static final int TABLE_LENGTH = MathHelper.smallestEncompassingPowerOfTwo(SECTION_LENGTH); + private static final int TABLE_LENGTH = CompatMathHelper.smallestEncompassingPowerOfTwo(SECTION_LENGTH); // The number of bits needed for each X/Y/Z component in a lookup table. private static final int TABLE_BITS = Integer.bitCount(TABLE_LENGTH - 1); @@ -261,12 +261,12 @@ public FluidState getFluidState(BlockPos pos) { @Override public float getBrightness(ForgeDirection direction, boolean shaded) { - return this.world.getBrightness(direction, shaded); + return ((BlockRenderView)this.world).getBrightness(direction, shaded); } @Override public LightingProvider getLightingProvider() { - return this.world.getLightingProvider(); + return ((BlockRenderView)this.world).getLightingProvider(); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java index be0334e30..1e1d1a129 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java @@ -15,7 +15,8 @@ public class BiomeCache { private final BiomeGenBase[] biomes; public BiomeCache(World world) { - this.type = world.getDimension().getBiomeAccessType(); + // TODO: Sodium + this.type = null;//world.getDimension().getBiomeAccessType(); this.seed = ((ClientWorldExtended) world).getBiomeSeed(); this.biomes = new BiomeGenBase[16 * 16]; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java index 5e1d677cc..0d7b68e98 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java @@ -5,7 +5,6 @@ import com.gtnewhorizons.angelica.compat.mojang.ColorResolver; import me.jellysquid.mods.sodium.client.util.color.ColorARGB; import me.jellysquid.mods.sodium.client.world.WorldSlice; -import net.minecraft.client.Minecraft; import java.util.Arrays; @@ -30,7 +29,7 @@ public class BiomeColorCache { public BiomeColorCache(ColorResolver resolver, WorldSlice slice) { this.resolver = resolver; this.slice = slice; - this.radius = Minecraft.getMinecraft().options.biomeBlendRadius; + this.radius = 2; // Minecraft.getMinecraft().options.biomeBlendRadius; ChunkSectionPos origin = this.slice.getOrigin(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 879470564..5268abe30 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -3,6 +3,7 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.IdListPalette; import com.gtnewhorizons.angelica.compat.mojang.LightType; import com.gtnewhorizons.angelica.compat.mojang.PackedIntegerArray; import com.gtnewhorizons.angelica.compat.mojang.Palette; @@ -12,7 +13,6 @@ import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPaletteFallback; import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalleteArray; -import net.minecraft.block.Block; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.ChunkPosition; import net.minecraft.world.World; @@ -136,7 +136,8 @@ private static ClonedPalette copyPalette(PalettedContainerExtended palette = container.getPalette(); if (palette instanceof IdListPalette) { - return new ClonedPaletteFallback<>(Block.STATE_IDS); + // TODO: Sodium + return new ClonedPaletteFallback<>(null/*Block.STATE_IDS*/); } BlockState[] array = new BlockState[1 << container.getPaletteSize()]; diff --git a/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java b/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java index f8afb950b..552bc68ab 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java @@ -65,10 +65,6 @@ private SodiumConfig() { this.addMixinRule("features.world_ticking", true); this.addMixinRule("features.fast_biome_colors", true); - if(FMLLoader.getLoadingModList().getModFileById("seamless_loading_screen") != null) { this.options.get("mixin.features.gui.fast_loading_screen").addModOverride(false, "seamless_loading_screen"); } - - if(FMLLoader.getLoadingModList().getModFileById("abnormals_core") != null) { this.options.get("mixin.features.world_ticking").addModOverride(false, "abnormals_core"); } - } /** @@ -108,10 +104,11 @@ private void readProperties(Properties props) { continue; } - if(!enabled && FMLEnvironment.production && SYSTEM_OPTIONS.contains(key)) { - LOGGER.warn("Configuration key '{}' is a required option and cannot be disabled", key); - continue; - } + // TODO: Sodium Config +// if(!enabled && FMLEnvironment.production && SYSTEM_OPTIONS.contains(key)) { +// LOGGER.warn("Configuration key '{}' is a required option and cannot be disabled", key); +// continue; +// } option.setEnabled(enabled, true); } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java index b10e99510..3f11be082 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java @@ -15,9 +15,9 @@ public BufferSegmentRenderer() { * Sets up the render type, draws the buffer, and then tears down the render type. */ public void draw(BufferSegment segment) { - segment.getRenderType().setupRenderState(); + segment.getRenderType().startDrawing(); drawInner(segment); - segment.getRenderType().clearRenderState(); + segment.getRenderType().endDrawing(); } /** diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java index 870be16f5..40878c78c 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java @@ -110,7 +110,7 @@ public void endBatch() { profiler.endStartSection("draw buffers"); for (RenderLayer type : renderOrder) { - type.setupRenderState(); + type.startDrawing(); renderTypes += 1; @@ -119,7 +119,7 @@ public void endBatch() { drawCalls += 1; } - type.clearRenderState(); + type.endDrawing(); } profiler.endStartSection("reset"); diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java index 9a7be847d..02553ba5a 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java @@ -13,7 +13,7 @@ public class TaggingRenderTypeWrapper extends RenderLayer implements WrappableRe public TaggingRenderTypeWrapper(String name, RenderLayer wrapped, int tag) { super(name, wrapped.format(), wrapped.mode(), wrapped.bufferSize(), - wrapped.affectsCrumbling(), shouldSortOnUpload(wrapped), wrapped::setupRenderState, wrapped::clearRenderState); + wrapped.hasCrumbling(), shouldSortOnUpload(wrapped), wrapped::startDrawing, wrapped::endDrawing); this.tag = tag; this.wrapped = wrapped; diff --git a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java index c709e2a5e..798414c8b 100644 --- a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java +++ b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java @@ -14,32 +14,32 @@ public class OuterWrappedRenderType extends RenderLayer implements WrappableRend private OuterWrappedRenderType(String name, RenderLayer wrapped, RenderPhase extra) { super(name, wrapped.format(), wrapped.mode(), wrapped.bufferSize(), - wrapped.affectsCrumbling(), shouldSortOnUpload(wrapped), wrapped::setupRenderState, wrapped::clearRenderState); + wrapped.hasCrumbling(), shouldSortOnUpload(wrapped), wrapped::startDrawing, wrapped::endDrawing); this.extra = extra; this.wrapped = wrapped; } public static OuterWrappedRenderType wrapExactlyOnce(String name, RenderLayer wrapped, RenderPhase extra) { - if (wrapped instanceof OuterWrappedRenderType) { - wrapped = ((OuterWrappedRenderType) wrapped).unwrap(); + if (wrapped instanceof OuterWrappedRenderType outerWrappedRenderType) { + wrapped = outerWrappedRenderType.unwrap(); } return new OuterWrappedRenderType(name, wrapped, extra); } @Override - public void setupRenderState() { - extra.setupRenderState(); + public void startDrawing() { + extra.startDrawing(); - super.setupRenderState(); + super.startDrawing(); } @Override - public void clearRenderState() { - super.clearRenderState(); + public void endDrawing() { + super.endDrawing(); - extra.clearRenderState(); + extra.endDrawing(); } @Override From 98a9501f0df749eb8872f7e8dc7b314539f67685 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 8 Nov 2023 21:04:07 -0800 Subject: [PATCH 036/301] Client boots and logs into world * Mixins to start SodiumWorldRenderer & ChunkStatusListener * Disable Iris GLStateManager enhancements if not initialized; should move these to inject when Iris is enabled * Disable NF/AF mixins for now * Temporary RenderLayer/Phase * Switch up some mappings on some things * Swap out accidently cofh MathHelper import... --- .../compat/mojang/DefaultVertexFormat.java | 36 +- .../angelica/compat/mojang/RenderLayer.java | 427 +++++++++- .../angelica/compat/mojang/RenderPhase.java | 768 +++++++++++++++++- .../angelica/compat/mojang/WorldRenderer.java | 8 - .../compat/mojang/WorldRendererExt.java | 8 + .../angelica/glsm/GLStateManager.java | 218 +++-- .../angelica/loading/AngelicaLateMixins.java | 5 +- .../angelica/loading/AngelicaTweaker.java | 5 +- .../gtnewhorizons/angelica/mixins/Mixins.java | 49 +- .../sodium/MixinChunkProviderClient.java | 41 + .../early/sodium/MixinRenderGlobal.java | 33 + .../mixins/early/sodium/MixinWorld.java | 10 - .../mixins/early/sodium/MixinWorldClient.java | 19 + .../interfaces/IHasClientChunkProvider.java | 8 + .../mods/sodium/client/SodiumClientMod.java | 11 +- .../client/model/light/EntityLighter.java | 18 +- .../model/light/data/LightDataAccess.java | 4 +- .../vertex/formats/glyph/GlyphVertexSink.java | 2 +- .../formats/particle/ParticleVertexSink.java | 2 +- .../vertex/formats/quad/QuadVertexSink.java | 2 +- .../client/render/SodiumWorldRenderer.java | 22 +- .../render/chunk/ChunkRenderManager.java | 4 +- .../render/chunk/compile/ChunkBuilder.java | 4 +- .../chunk/cull/graph/ChunkGraphCuller.java | 4 +- .../context/ChunkRenderCacheShared.java | 5 +- .../mods/sodium/client/util/Norm3b.java | 4 +- .../client/util/color/FastCubicSampler.java | 8 +- .../sodium/client/world/biome/BiomeCache.java | 3 +- .../sodium/common/util/DirectionUtil.java | 3 +- src/main/java/net/coderbot/iris/Iris.java | 2 + .../postprocess/FullScreenQuadRenderer.java | 4 +- .../iris/vertices/IrisVertexFormats.java | 30 +- 32 files changed, 1535 insertions(+), 232 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRenderer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorld.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasClientChunkProvider.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java index 15cf10852..e93050691 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java @@ -6,25 +6,23 @@ public class DefaultVertexFormat { - public static final VertexFormatElement ELEMENT_POSITION = new VertexFormatElement(0, Type.FLOAT, Usage.POSITION, 3); - public static final VertexFormatElement ELEMENT_COLOR = new VertexFormatElement(0, Type.UBYTE, Usage.COLOR, 4); - public static final VertexFormatElement ELEMENT_UV0 = new VertexFormatElement(0, Type.FLOAT, Usage.UV, 2); - public static final VertexFormatElement ELEMENT_UV1 = new VertexFormatElement(1, Type.SHORT, Usage.UV, 2); - public static final VertexFormatElement ELEMENT_UV2 = new VertexFormatElement(2, Type.SHORT, Usage.UV, 2); - public static final VertexFormatElement ELEMENT_NORMAL = new VertexFormatElement(0, Type.BYTE, Usage.NORMAL, 3); - public static final VertexFormatElement ELEMENT_PADDING = new VertexFormatElement(0, Type.BYTE, Usage.PADDING, 1); - public static final VertexFormat BLOCK = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV0).add(ELEMENT_UV2).add(ELEMENT_NORMAL).add(ELEMENT_PADDING).build()); - public static final VertexFormat NEW_ENTITY = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV0).add(ELEMENT_UV1).add(ELEMENT_UV2).add(ELEMENT_NORMAL).add(ELEMENT_PADDING).build()); - public static final VertexFormat PARTICLE = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_UV0).add(ELEMENT_COLOR).add(ELEMENT_UV2).build()); - public static final VertexFormat POSITION = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).build()); - public static final VertexFormat POSITION_COLOR = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).build()); - public static final VertexFormat POSITION_COLOR_LIGHTMAP = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV2).build()); - public static final VertexFormat POSITION_TEX = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_UV0).build()); - public static final VertexFormat POSITION_COLOR_TEX = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV0).build()); - public static final VertexFormat POSITION_TEX_COLOR = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_UV0).add(ELEMENT_COLOR).build()); - public static final VertexFormat POSITION_COLOR_TEX_LIGHTMAP = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_COLOR).add(ELEMENT_UV0).add(ELEMENT_UV2).build()); - public static final VertexFormat POSITION_TEX_LIGHTMAP_COLOR = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_UV0).add(ELEMENT_UV2).add(ELEMENT_COLOR).build()); - public static final VertexFormat POSITION_TEX_COLOR_NORMAL = new VertexFormat(new ImmutableList.Builder().add(ELEMENT_POSITION).add(ELEMENT_UV0).add(ELEMENT_COLOR).add(ELEMENT_NORMAL).add(ELEMENT_PADDING).build()); + public static final VertexFormatElement POSITION_ELEMENT = new VertexFormatElement(0, Type.FLOAT, Usage.POSITION, 3); + public static final VertexFormatElement COLOR_ELEMENT = new VertexFormatElement(0, Type.UBYTE, Usage.COLOR, 4); + public static final VertexFormatElement TEXTURE_0_ELEMENT = new VertexFormatElement(0, Type.FLOAT, Usage.UV, 2); + public static final VertexFormatElement OVERLAY_ELEMENT = new VertexFormatElement(1, Type.SHORT, Usage.UV, 2); + public static final VertexFormatElement LIGHT_ELEMENT = new VertexFormatElement(2, Type.SHORT, Usage.UV, 2); + public static final VertexFormatElement NORMAL_ELEMENT = new VertexFormatElement(0, Type.BYTE, Usage.NORMAL, 3); + public static final VertexFormatElement PADDING_ELEMENT = new VertexFormatElement(0, Type.BYTE, Usage.PADDING, 1); + public static final VertexFormat POSITION_COLOR_TEXTURE_LIGHT_NORMAL = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).add(TEXTURE_0_ELEMENT).add(LIGHT_ELEMENT).add(NORMAL_ELEMENT).add(PADDING_ELEMENT).build()); + public static final VertexFormat POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).add(TEXTURE_0_ELEMENT).add(OVERLAY_ELEMENT).add(LIGHT_ELEMENT).add(NORMAL_ELEMENT).add(PADDING_ELEMENT).build()); + public static final VertexFormat POSITION_TEXTURE_COLOR_LIGHT = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(TEXTURE_0_ELEMENT).add(COLOR_ELEMENT).add(LIGHT_ELEMENT).build()); + public static final VertexFormat POSITION = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).build()), POSITION_COLOR = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).build()); + public static final VertexFormat POSITION_COLOR_LIGHT = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).add(LIGHT_ELEMENT).build()); + public static final VertexFormat POSITION_TEXTURE = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(TEXTURE_0_ELEMENT).build()); + public static final VertexFormat POSITION_COLOR_TEXTURE = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).add(TEXTURE_0_ELEMENT).build()); + public static final VertexFormat POSITION_TEXTURE_COLOR = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(TEXTURE_0_ELEMENT).add(COLOR_ELEMENT).build()), POSITION_COLOR_TEX_LIGHTMAP = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).add(TEXTURE_0_ELEMENT).add(LIGHT_ELEMENT).build()); + public static final VertexFormat POSITION_TEXTURE_LIGHT_COLOR = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(TEXTURE_0_ELEMENT).add(LIGHT_ELEMENT).add(COLOR_ELEMENT).build()); + public static final VertexFormat POSITION_TEXTURE_COLOR_NORMAL = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(TEXTURE_0_ELEMENT).add(COLOR_ELEMENT).add(NORMAL_ELEMENT).add(PADDING_ELEMENT).build()); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java index aa6d45820..ffc5d8d2b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java @@ -1,12 +1,38 @@ package com.gtnewhorizons.angelica.compat.mojang; +import com.google.common.collect.ImmutableList; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; import lombok.Getter; +import net.minecraft.util.ResourceLocation; +import javax.annotation.Nullable; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; +import java.util.OptionalDouble; public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris) + private static final RenderLayer SOLID = of("solid", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 2097152, true, false, RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).build(true)); + private static final RenderLayer CUTOUT_MIPPED = of("cutout_mipped", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 131072, true, false, RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).alpha(HALF_ALPHA).build(true)); + private static final RenderLayer CUTOUT = of("cutout", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 131072, true, false, RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(BLOCK_ATLAS_TEXTURE).alpha(HALF_ALPHA).build(true)); + private static final RenderLayer TRANSLUCENT = of("translucent", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 262144, true, true, createTranslucentPhaseData()); + private static final RenderLayer TRANSLUCENT_MOVING_BLOCK = of("translucent_moving_block", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 262144, false, true, getItemPhaseData()); + private static final RenderLayer TRANSLUCENT_NO_CRUMBLING = of("translucent_no_crumbling", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 262144, false, true, createTranslucentPhaseData()); + private static final RenderLayer LEASH = of("leash", DefaultVertexFormat.POSITION_COLOR_LIGHT, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(NO_TEXTURE).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).build(false)); + private static final RenderLayer WATER_MASK = of("water_mask", DefaultVertexFormat.POSITION, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(NO_TEXTURE).writeMaskState(DEPTH_MASK).build(false)); +// private static final RenderLayer ARMOR_GLINT = of("armor_glint", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(GLINT_TEXTURING).layering(VIEW_OFFSET_Z_LAYERING).build(false)); +// private static final RenderLayer ARMOR_ENTITY_GLINT = of("armor_entity_glint", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(ENTITY_GLINT_TEXTURING).layering(VIEW_OFFSET_Z_LAYERING).build(false)); +// private static final RenderLayer GLINT_TRANSLUCENT = of("glint_translucent", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(GLINT_TEXTURING).target(ITEM_TARGET).build(false)); +// private static final RenderLayer GLINT = of("glint", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(GLINT_TEXTURING).build(false)); +// private static final RenderLayer DIRECT_GLINT = of("glint_direct", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(GLINT_TEXTURING).build(false)); +// private static final RenderLayer ENTITY_GLINT = of("entity_glint", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).target(ITEM_TARGET).texturing(ENTITY_GLINT_TEXTURING).build(false)); +// private static final RenderLayer DIRECT_ENTITY_GLINT = of("entity_glint_direct", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(ENTITY_GLINT_TEXTURING).build(false)); + private static final RenderLayer LIGHTNING = of("lightning", DefaultVertexFormat.POSITION_COLOR, 7, 256, false, true, RenderLayer.MultiPhaseParameters.builder().writeMaskState(ALL_MASK).transparency(LIGHTNING_TRANSPARENCY).target(WEATHER_TARGET).shadeModel(SMOOTH_SHADE_MODEL).build(false)); +// private static final RenderLayer TRIPWIRE = of("tripwire", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 262144, true, true, getTripwirePhaseData()); + private static final RenderLayer LINES = of("lines", DefaultVertexFormat.POSITION_COLOR, 1, 256, RenderLayer.MultiPhaseParameters.builder().lineWidth(new RenderPhase.LineWidth(OptionalDouble.empty())).layering(VIEW_OFFSET_Z_LAYERING).transparency(TRANSLUCENT_TRANSPARENCY).target(ITEM_TARGET).writeMaskState(ALL_MASK).build(false)); + @Getter private final VertexFormat vertexFormat; @Getter @@ -26,22 +52,139 @@ public RenderLayer(String name, VertexFormat vertexFormat, int drawMode, int exp this.optionalThis = Optional.of(this); } + + public static MultiPhase of(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, MultiPhaseParameters phaseData) { + return of(name, vertexFormat, drawMode, expectedBufferSize, false, false, phaseData); + } + + public static MultiPhase of(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, MultiPhaseParameters phases) { + return RenderLayer.MultiPhase.of(name, vertexFormat, drawMode, expectedBufferSize, hasCrumbling, translucent, phases); + } + + public static RenderLayer solid() { - return null; + return SOLID; } public static RenderLayer cutout() { - return null; + return CUTOUT; } public static RenderLayer cutoutMipped() { - return null; + return CUTOUT_MIPPED; + } + private static MultiPhaseParameters createTranslucentPhaseData() { + return RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).transparency(TRANSLUCENT_TRANSPARENCY).target(TRANSLUCENT_TARGET).build(true); } public static RenderLayer translucent() { - return null; + return TRANSLUCENT; + } + + private static MultiPhaseParameters getItemPhaseData() { + return RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).transparency(TRANSLUCENT_TRANSPARENCY).target(ITEM_TARGET).build(true); + } + + public static RenderLayer getArmorCutoutNoCull(ResourceLocation texture) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(NO_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).layering(VIEW_OFFSET_Z_LAYERING).build(true); + return of("armor_cutout_no_cull", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, false, rendertype$state); + } + + public static RenderLayer getEntitySolid(ResourceLocation texture) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(NO_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(true); + return of("entity_solid", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, false, rendertype$state); + } + + public static RenderLayer getEntityCutout(ResourceLocation texture) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(NO_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(true); + return of("entity_cutout", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, false, rendertype$state); + } + + public static RenderLayer getEntityCutoutNoCull(ResourceLocation texture, boolean affectsOutline) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(NO_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(affectsOutline); + return of("entity_cutout_no_cull", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, false, rendertype$state); + } + + public static RenderLayer getEntityCutoutNoCull(ResourceLocation texture) { + return getEntityCutoutNoCull(texture, true); + } + + public static RenderLayer getEntityCutoutNoCullZOffset(ResourceLocation texture, boolean affectsOutline) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(NO_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).layering(VIEW_OFFSET_Z_LAYERING).build(affectsOutline); + return of("entity_cutout_no_cull_z_offset", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, false, rendertype$state); + } + + public static RenderLayer getEntityCutoutNoCullZOffset(ResourceLocation texture) { + return getEntityCutoutNoCullZOffset(texture, true); + } + + public static RenderLayer getItemEntityTranslucentCull(ResourceLocation texture) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(TRANSLUCENT_TRANSPARENCY).target(ITEM_TARGET).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).writeMaskState(RenderPhase.ALL_MASK).build(true); + return of("item_entity_translucent_cull", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, true, rendertype$state); + } + + public static RenderLayer getEntityTranslucentCull(ResourceLocation texture) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(TRANSLUCENT_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(true); + return of("entity_translucent_cull", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, true, rendertype$state); + } + + public static RenderLayer getEntityTranslucent(ResourceLocation texture, boolean affectsOutline) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(TRANSLUCENT_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(affectsOutline); + return of("entity_translucent", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, true, rendertype$state); + } + + public static RenderLayer getEntityTranslucent(ResourceLocation texture) { + return getEntityTranslucent(texture, true); + } + + public static RenderLayer getEntitySmoothCutout(ResourceLocation texture) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).alpha(HALF_ALPHA).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).shadeModel(SMOOTH_SHADE_MODEL).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).build(true); + return of("entity_smooth_cutout", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, rendertype$state); + } + + public static RenderLayer getBeaconBeam(ResourceLocation texture, boolean translucent) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(translucent ? TRANSLUCENT_TRANSPARENCY : NO_TRANSPARENCY).writeMaskState(translucent ? COLOR_MASK : ALL_MASK).fog(NO_FOG).build(false); + return of("beacon_beam", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 256, false, true, rendertype$state); + } + + public static RenderLayer getEntityDecal(ResourceLocation texture) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).depthTest(EQUAL_DEPTH_TEST).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(false); + return of("entity_decal", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, rendertype$state); + } + + public static RenderLayer getEntityNoOutline(ResourceLocation texture) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(TRANSLUCENT_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).writeMaskState(COLOR_MASK).build(false); + return of("entity_no_outline", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, false, true, rendertype$state); + } + + public static RenderLayer getEntityShadow(ResourceLocation texture) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(TRANSLUCENT_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(ENABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).writeMaskState(COLOR_MASK).depthTest(LEQUAL_DEPTH_TEST).layering(VIEW_OFFSET_Z_LAYERING).build(false); + return of("entity_shadow", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, false, false, rendertype$state); + } + + public static RenderLayer getEntityAlpha(ResourceLocation texture, float alpha) { + MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).alpha(new RenderPhase.Alpha(alpha)).cull(DISABLE_CULLING).build(true); + return of("entity_alpha", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, rendertype$state); + } + + public static RenderLayer getEyes(ResourceLocation texture) { + RenderPhase.Texture renderstate$texturestate = new RenderPhase.Texture(texture, false, false); + return of("eyes", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, false, true, RenderLayer.MultiPhaseParameters.builder().texture(renderstate$texturestate).transparency(ADDITIVE_TRANSPARENCY).writeMaskState(COLOR_MASK).fog(BLACK_FOG).build(false)); + } + + public static RenderLayer getEnergySwirl(ResourceLocation texture, float x, float y) { + return of("energy_swirl", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, false, true, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).texturing(new RenderPhase.OffsetTexturing(x, y)).fog(BLACK_FOG).transparency(ADDITIVE_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(false)); + } + + public static RenderLayer getOutline(ResourceLocation texture) { + return getOutline(texture, DISABLE_CULLING); + } + + public static RenderLayer getOutline(ResourceLocation texture, RenderPhase.Cull cull) { + return of("outline", DefaultVertexFormat.POSITION_COLOR_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).cull(cull).depthTest(ALWAYS_DEPTH_TEST).alpha(ONE_TENTH_ALPHA).texturing(OUTLINE_TEXTURING).fog(NO_FOG).target(OUTLINE_TARGET).build(RenderLayer.OutlineMode.IS_OUTLINE)); } + public static RenderLayer tripwire() { return null; } @@ -51,15 +194,15 @@ public static List getBlockLayers() { } public int mode() { - return 1; + return this.drawMode; } public VertexFormat format() { - return null; + return vertexFormat; } public boolean shouldSortOnUpload() { - return true; + return false; } public int bufferSize() { @@ -87,4 +230,274 @@ public Optional asOptional() { public void draw(BufferBuilder lv, int cameraX, int cameraY, int cameraZ) { } + + static final class MultiPhase extends RenderLayer { + private static final ObjectOpenCustomHashSet CACHE; + private final MultiPhaseParameters phases; + private final int hash; + private final Optional affectedOutline; + private final boolean outline; + + private MultiPhase(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, MultiPhaseParameters phases) { + super(name, vertexFormat, drawMode, expectedBufferSize, hasCrumbling, translucent, () -> { + phases.phases.forEach(RenderPhase::startDrawing); + }, () -> { + phases.phases.forEach(RenderPhase::endDrawing); + }); + this.phases = phases; + this.affectedOutline = phases.outlineMode == RenderLayer.OutlineMode.AFFECTS_OUTLINE ? phases.texture.getId().map((arg2) -> { + return getOutline(arg2, phases.cull); + }) : Optional.empty(); + this.outline = phases.outlineMode == RenderLayer.OutlineMode.IS_OUTLINE; + this.hash = Objects.hash(new Object[]{super.hashCode(), phases}); + } + + public static MultiPhase of(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, + MultiPhaseParameters phases) { + return (MultiPhase)CACHE.addOrGet(new MultiPhase(name, vertexFormat, drawMode, expectedBufferSize, hasCrumbling, translucent, phases)); + } + + public Optional getAffectedOutline() { + return this.affectedOutline; + } + + public boolean isOutline() { + return this.outline; + } + + public boolean equals(@Nullable Object object) { + return this == object; + } + + public int hashCode() { + return this.hash; + } + + public String toString() { + return "RenderType[" + this.phases + ']'; + } + + static { + CACHE = new ObjectOpenCustomHashSet(RenderLayer.MultiPhase.HashStrategy.INSTANCE); + } + + static enum HashStrategy implements Hash.Strategy { + INSTANCE; + + private HashStrategy() { + } + + public int hashCode(@Nullable MultiPhase arg) { + return arg == null ? 0 : arg.hash; + } + + public boolean equals(@Nullable MultiPhase arg, @Nullable MultiPhase arg2) { + if (arg == arg2) { + return true; + } else { + return arg != null && arg2 != null ? Objects.equals(arg.phases, arg2.phases) : false; + } + } + } + } + + public static final class MultiPhaseParameters { + private final RenderPhase.Texture texture; + private final RenderPhase.Transparency transparency; + private final RenderPhase.DiffuseLighting diffuseLighting; + private final RenderPhase.ShadeModel shadeModel; + private final RenderPhase.Alpha alpha; + private final RenderPhase.DepthTest depthTest; + private final RenderPhase.Cull cull; + private final RenderPhase.Lightmap lightmap; + private final RenderPhase.Overlay overlay; + private final RenderPhase.Fog fog; + private final RenderPhase.Layering layering; + private final RenderPhase.Target target; + private final RenderPhase.Texturing texturing; + private final RenderPhase.WriteMaskState writeMaskState; + private final RenderPhase.LineWidth lineWidth; + private final OutlineMode outlineMode; + private final ImmutableList phases; + + private MultiPhaseParameters(RenderPhase.Texture texture, RenderPhase.Transparency transparency, RenderPhase.DiffuseLighting diffuseLighting, RenderPhase.ShadeModel shadeModel, RenderPhase.Alpha alpha, RenderPhase.DepthTest depthTest, RenderPhase.Cull cull, RenderPhase.Lightmap lightmap, RenderPhase.Overlay overlay, RenderPhase.Fog fog, RenderPhase.Layering layering, RenderPhase.Target target, RenderPhase.Texturing texturing, RenderPhase.WriteMaskState writeMaskState, RenderPhase.LineWidth lineWidth, OutlineMode outlineMode) { + this.texture = texture; + this.transparency = transparency; + this.diffuseLighting = diffuseLighting; + this.shadeModel = shadeModel; + this.alpha = alpha; + this.depthTest = depthTest; + this.cull = cull; + this.lightmap = lightmap; + this.overlay = overlay; + this.fog = fog; + this.layering = layering; + this.target = target; + this.texturing = texturing; + this.writeMaskState = writeMaskState; + this.lineWidth = lineWidth; + this.outlineMode = outlineMode; + this.phases = ImmutableList.of(this.texture, this.transparency, this.diffuseLighting, this.shadeModel, this.alpha, this.depthTest, this.cull, this.lightmap, this.overlay, this.fog, this.layering, this.target, new RenderPhase[]{this.texturing, this.writeMaskState, this.lineWidth}); + } + + public boolean equals(Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + MultiPhaseParameters rendertype$state = (MultiPhaseParameters)object; + return this.outlineMode == rendertype$state.outlineMode && this.phases.equals(rendertype$state.phases); + } else { + return false; + } + } + + public int hashCode() { + return Objects.hash(new Object[]{this.phases, this.outlineMode}); + } + + public String toString() { + return "CompositeState[" + this.phases + ", outlineProperty=" + this.outlineMode + ']'; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private RenderPhase.Texture texture; + private RenderPhase.Transparency transparency; + private RenderPhase.DiffuseLighting diffuseLighting; + private RenderPhase.ShadeModel shadeModel; + private RenderPhase.Alpha alpha; + private RenderPhase.DepthTest depthTest; + private RenderPhase.Cull cull; + private RenderPhase.Lightmap lightmap; + private RenderPhase.Overlay overlay; + private RenderPhase.Fog fog; + private RenderPhase.Layering layering; + private RenderPhase.Target target; + private RenderPhase.Texturing texturing; + private RenderPhase.WriteMaskState writeMaskState; + private RenderPhase.LineWidth lineWidth; + + private Builder() { + this.texture = RenderPhase.NO_TEXTURE ; + this.transparency = RenderPhase.NO_TRANSPARENCY; + this.diffuseLighting = RenderPhase.DISABLE_DIFFUSE_LIGHTING; + this.shadeModel = RenderPhase.SHADE_MODEL; + this.alpha = RenderPhase.ZERO_ALPHA; + this.depthTest = RenderPhase.LEQUAL_DEPTH_TEST; + this.cull = RenderPhase.ENABLE_CULLING; + this.lightmap = RenderPhase.DISABLE_LIGHTMAP; + this.overlay = RenderPhase.DISABLE_OVERLAY_COLOR; + this.fog = RenderPhase.FOG; + this.layering = RenderPhase.NO_LAYERING; + this.target = RenderPhase.MAIN_TARGET; + this.texturing = RenderPhase.DEFAULT_TEXTURING; + this.writeMaskState = RenderPhase.ALL_MASK; + this.lineWidth = RenderPhase.FULL_LINE_WIDTH; + } + + public Builder texture(RenderPhase.Texture texture) { + this.texture = texture; + return this; + } + + public Builder transparency(RenderPhase.Transparency transparency) { + this.transparency = transparency; + return this; + } + + public Builder diffuseLighting(RenderPhase.DiffuseLighting diffuseLighting) { + this.diffuseLighting = diffuseLighting; + return this; + } + + public Builder shadeModel(RenderPhase.ShadeModel shadeModel) { + this.shadeModel = shadeModel; + return this; + } + + public Builder alpha(RenderPhase.Alpha alpha) { + this.alpha = alpha; + return this; + } + + public Builder depthTest(RenderPhase.DepthTest depthTest) { + this.depthTest = depthTest; + return this; + } + + public Builder cull(RenderPhase.Cull cull) { + this.cull = cull; + return this; + } + + public Builder lightmap(RenderPhase.Lightmap lightmap) { + this.lightmap = lightmap; + return this; + } + + public Builder overlay(RenderPhase.Overlay overlay) { + this.overlay = overlay; + return this; + } + + public Builder fog(RenderPhase.Fog fog) { + this.fog = fog; + return this; + } + + public Builder layering(RenderPhase.Layering layering) { + this.layering = layering; + return this; + } + + public Builder target(RenderPhase.Target target) { + this.target = target; + return this; + } + + public Builder texturing(RenderPhase.Texturing texturing) { + this.texturing = texturing; + return this; + } + + public Builder writeMaskState(RenderPhase.WriteMaskState writeMaskState) { + this.writeMaskState = writeMaskState; + return this; + } + + public Builder lineWidth(RenderPhase.LineWidth lineWidth) { + this.lineWidth = lineWidth; + return this; + } + + public MultiPhaseParameters build(boolean affectsOutline) { + return this.build(affectsOutline ? RenderLayer.OutlineMode.AFFECTS_OUTLINE : RenderLayer.OutlineMode.NONE); + } + + public MultiPhaseParameters build(OutlineMode outlineMode) { + return new MultiPhaseParameters(this.texture, this.transparency, this.diffuseLighting, this.shadeModel, this.alpha, this.depthTest, this.cull, this.lightmap, this.overlay, this.fog, this.layering, this.target, this.texturing, this.writeMaskState, this.lineWidth, outlineMode); + } + } + } + + static enum OutlineMode { + NONE("none"), + IS_OUTLINE("is_outline"), + AFFECTS_OUTLINE("affects_outline"); + + private final String name; + + private OutlineMode(String name) { + this.name = name; + } + + public String toString() { + return this.name; + } + } + + } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index 1030da8dd..5755a3f34 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -1,28 +1,125 @@ package com.gtnewhorizons.angelica.compat.mojang; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + import javax.annotation.Nullable; +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalDouble; + public abstract class RenderPhase { protected final String name; - protected Runnable beingAction; - protected final Runnable endAction; + protected Runnable beginAction; + private final Runnable endAction; + protected static final Transparency NO_TRANSPARENCY = new Transparency("no_transparency", GLStateManager::disableBlend, () -> { + }); + protected static final Transparency ADDITIVE_TRANSPARENCY = new Transparency("additive_transparency", () -> { + GLStateManager.enableBlend(); + GLStateManager.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE); + }, () -> { + GLStateManager.disableBlend(); + GLStateManager.defaultBlendFunc(); + GLStateManager.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + }); + protected static final Transparency LIGHTNING_TRANSPARENCY = new Transparency("lightning_transparency", () -> { + GLStateManager.disableBlend(); + GLStateManager.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); + }, () -> { + GLStateManager.disableBlend(); + GLStateManager.defaultBlendFunc(); + }); + protected static final Transparency GLINT_TRANSPARENCY = new Transparency("glint_transparency", () -> { + GLStateManager.disableBlend(); + GLStateManager.glBlendFuncSeparate(GL11.GL_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE); + }, () -> { + GLStateManager.disableBlend(); + GLStateManager.defaultBlendFunc(); + }); + protected static final Transparency CRUMBLING_TRANSPARENCY = new Transparency("crumbling_transparency", () -> { + GLStateManager.disableBlend(); + GLStateManager.glBlendFuncSeparate(GL11.GL_DST_COLOR, GL11.GL_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO); + }, () -> { + GLStateManager.disableBlend(); + GLStateManager.defaultBlendFunc(); + }); + protected static final Transparency TRANSLUCENT_TRANSPARENCY = new Transparency("translucent_transparency", () -> { + GLStateManager.disableBlend(); + GLStateManager.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + }, () -> { + GLStateManager.disableBlend(); + GLStateManager.defaultBlendFunc(); + }); + protected static final Alpha ZERO_ALPHA = new Alpha(0.0F); + protected static final Alpha ONE_TENTH_ALPHA = new Alpha(0.003921569F); + protected static final Alpha HALF_ALPHA = new Alpha(0.5F); + protected static final ShadeModel SHADE_MODEL = new ShadeModel(false); + protected static final ShadeModel SMOOTH_SHADE_MODEL = new ShadeModel(true); + protected static final Texture MIPMAP_BLOCK_ATLAS_TEXTURE; + protected static final Texture BLOCK_ATLAS_TEXTURE; + protected static final Texture NO_TEXTURE; + protected static final Texturing DEFAULT_TEXTURING; + protected static final Texturing OUTLINE_TEXTURING; + protected static final Texturing GLINT_TEXTURING; + protected static final Texturing ENTITY_GLINT_TEXTURING; + protected static final Lightmap ENABLE_LIGHTMAP; + protected static final Lightmap DISABLE_LIGHTMAP; + protected static final Overlay ENABLE_OVERLAY_COLOR; + protected static final Overlay DISABLE_OVERLAY_COLOR; + protected static final DiffuseLighting ENABLE_DIFFUSE_LIGHTING; + protected static final DiffuseLighting DISABLE_DIFFUSE_LIGHTING; + protected static final Cull ENABLE_CULLING; + protected static final Cull DISABLE_CULLING; + protected static final DepthTest ALWAYS_DEPTH_TEST; + protected static final DepthTest EQUAL_DEPTH_TEST; + protected static final DepthTest LEQUAL_DEPTH_TEST; + protected static final WriteMaskState ALL_MASK; + protected static final WriteMaskState COLOR_MASK; + protected static final WriteMaskState DEPTH_MASK; + protected static final Layering NO_LAYERING; + protected static final Layering POLYGON_OFFSET_LAYERING; + protected static final Layering VIEW_OFFSET_Z_LAYERING; + protected static final Fog NO_FOG; + protected static final Fog FOG; + protected static final Fog BLACK_FOG; + protected static final Target MAIN_TARGET; + protected static final Target OUTLINE_TARGET; + protected static final Target TRANSLUCENT_TARGET; + protected static final Target PARTICLES_TARGET; + protected static final Target WEATHER_TARGET; + protected static final Target CLOUDS_TARGET; + protected static final Target ITEM_TARGET; + protected static final LineWidth FULL_LINE_WIDTH; - public RenderPhase(String name, Runnable beingAction, Runnable clearState) { + public RenderPhase(String name, Runnable beginAction, Runnable endAction) { this.name = name; - this.beingAction = beingAction; - this.endAction = clearState; + this.beginAction = beginAction; + this.endAction = endAction; + } + + public void startDrawing() { + this.beginAction.run(); + } + + public void endDrawing() { + this.endAction.run(); } public boolean equals(@Nullable Object object) { if (this == object) { return true; } else if (object != null && this.getClass() == object.getClass()) { - final RenderPhase lv = (RenderPhase)object; + RenderPhase lv = (RenderPhase)object; return this.name.equals(lv.name); } else { return false; } } + public int hashCode() { return this.name.hashCode(); } @@ -31,12 +128,663 @@ public String toString() { return this.name; } - public void startDrawing() { - this.beingAction.run(); + private static void setupGlintTexturing(float scale) { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.matrixMode(5890); +// RenderSystem.pushMatrix(); +// RenderSystem.loadIdentity(); +// long l = Util.getMeasuringTimeMs() * 8L; +// float g = (float)(l % 110000L) / 110000.0F; +// float h = (float)(l % 30000L) / 30000.0F; +// RenderSystem.translatef(-g, h, 0.0F); +// RenderSystem.rotatef(10.0F, 0.0F, 0.0F, 1.0F); +// RenderSystem.scalef(scale, scale, scale); +// RenderSystem.matrixMode(5888); } - public void endDrawing() { - this.endAction.run(); + private static ResourceLocation UNKONWN_TEXTURE = new ResourceLocation("textures/misc/unknown_server.png"); + static { + // TODO: Sodium - SpriteAtlasTexture + MIPMAP_BLOCK_ATLAS_TEXTURE = new Texture( UNKONWN_TEXTURE/*SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE*/, false, true); + BLOCK_ATLAS_TEXTURE = new Texture(UNKONWN_TEXTURE /*SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE*/, false, false); + NO_TEXTURE = new Texture(); + DEFAULT_TEXTURING = new Texturing("default_texturing", () -> { + }, () -> { + }); + OUTLINE_TEXTURING = new Texturing("outline_texturing", () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.setupOutline(); + }, () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.teardownOutline(); + }); + GLINT_TEXTURING = new Texturing("glint_texturing", () -> { + setupGlintTexturing(8.0F); + }, () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.matrixMode(5890); +// RenderSystem.popMatrix(); +// RenderSystem.matrixMode(5888); + }); + ENTITY_GLINT_TEXTURING = new Texturing("entity_glint_texturing", () -> { + setupGlintTexturing(0.16F); + }, () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.matrixMode(5890); +// RenderSystem.popMatrix(); +// RenderSystem.matrixMode(5888); + }); + ENABLE_LIGHTMAP = new Lightmap(true); + DISABLE_LIGHTMAP = new Lightmap(false); + ENABLE_OVERLAY_COLOR = new Overlay(true); + DISABLE_OVERLAY_COLOR = new Overlay(false); + ENABLE_DIFFUSE_LIGHTING = new DiffuseLighting(true); + DISABLE_DIFFUSE_LIGHTING = new DiffuseLighting(false); + ENABLE_CULLING = new Cull(true); + DISABLE_CULLING = new Cull(false); + ALWAYS_DEPTH_TEST = new DepthTest("always", GL11.GL_ALWAYS); + EQUAL_DEPTH_TEST = new DepthTest("==", GL11.GL_EQUAL); + LEQUAL_DEPTH_TEST = new DepthTest("<=", GL11.GL_LEQUAL); + ALL_MASK = new WriteMaskState(true, true); + COLOR_MASK = new WriteMaskState(true, false); + DEPTH_MASK = new WriteMaskState(false, true); + NO_LAYERING = new Layering("no_layering", () -> { + }, () -> { + }); + POLYGON_OFFSET_LAYERING = new Layering("polygon_offset_layering", () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.polygonOffset(-1.0F, -10.0F); +// RenderSystem.enablePolygonOffset(); + }, () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.polygonOffset(0.0F, 0.0F); +// RenderSystem.disablePolygonOffset(); + }); + VIEW_OFFSET_Z_LAYERING = new Layering("view_offset_z_layering", () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.pushMatrix(); +// RenderSystem.scalef(0.99975586F, 0.99975586F, 0.99975586F); + }, () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem::popMatrix(); + }); + NO_FOG = new Fog("no_fog", () -> { + }, () -> { + }); + FOG = new Fog("fog", () -> { + throw new RuntimeException("Not Implemented Yet"); +// BackgroundRenderer.setFogBlack(); +// RenderSystem.enableFog(); + }, () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.disableFog(); + }); + BLACK_FOG = new Fog("black_fog", () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.fog(2918, 0.0F, 0.0F, 0.0F, 1.0F); +// RenderSystem.enableFog(); + }, () -> { + throw new RuntimeException("Not Implemented Yet"); +// BackgroundRenderer.setFogBlack(); +// RenderSystem.disableFog(); + }); + MAIN_TARGET = new Target("main_target", () -> { + }, () -> { + }); + OUTLINE_TARGET = new Target("outline_target", () -> { + throw new RuntimeException("Not Implemented Yet"); +// MinecraftClient.getInstance().worldRenderer.getEntityOutlinesFramebuffer().beginWrite(false); + }, () -> { + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + }); + TRANSLUCENT_TARGET = new Target("translucent_target", () -> { + if (Minecraft.isFancyGraphicsEnabled()) { + throw new RuntimeException("Not Implemented Yet"); +// MinecraftClient.getInstance().worldRenderer.getTranslucentFramebuffer().beginWrite(false); + } + + }, () -> { + if (Minecraft.isFancyGraphicsEnabled()) { + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + }); + PARTICLES_TARGET = new Target("particles_target", () -> { + if (Minecraft.isFancyGraphicsEnabled()) { + throw new RuntimeException("Not Implemented Yet"); +// MinecraftClient.getInstance().worldRenderer.getParticlesFramebuffer().beginWrite(false); + } + + }, () -> { + if (Minecraft.isFancyGraphicsEnabled()) { + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + }); + WEATHER_TARGET = new Target("weather_target", () -> { + if (Minecraft.isFancyGraphicsEnabled()) { + throw new RuntimeException("Not Implemented Yet"); +// MinecraftClient.getInstance().worldRenderer.getWeatherFramebuffer().beginWrite(false); + } + + }, () -> { + if (Minecraft.isFancyGraphicsEnabled()) { + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + }); + CLOUDS_TARGET = new Target("clouds_target", () -> { + if (Minecraft.isFancyGraphicsEnabled()) { + throw new RuntimeException("Not Implemented Yet"); +// MinecraftClient.getInstance().worldRenderer.getCloudsFramebuffer().beginWrite(false); + } + + }, () -> { + if (Minecraft.isFancyGraphicsEnabled()) { + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + }); + ITEM_TARGET = new Target("item_entity_target", () -> { + if (Minecraft.isFancyGraphicsEnabled()) { + throw new RuntimeException("Not Implemented Yet"); +// MinecraftClient.getInstance().worldRenderer.getEntityFramebuffer().beginWrite(false); + } + + }, () -> { + if (Minecraft.isFancyGraphicsEnabled()) { + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + }); + FULL_LINE_WIDTH = new LineWidth(OptionalDouble.of(1.0)); + } + + + public static class LineWidth extends RenderPhase { + private final OptionalDouble width; + + public LineWidth(OptionalDouble optionalDouble) { + super("line_width", () -> { + if (!Objects.equals(optionalDouble, OptionalDouble.of(1.0))) { + if (optionalDouble.isPresent()) { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.lineWidth((float)optionalDouble.getAsDouble()); + } else { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.lineWidth(Math.max(2.5F, (float)MinecraftClient.getInstance().getWindow().getFramebufferWidth() / 1920.0F * 2.5F)); + } + } + + }, () -> { + if (!Objects.equals(optionalDouble, OptionalDouble.of(1.0))) { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.lineWidth(1.0F); + } + + }); + this.width = optionalDouble; + } + + public boolean equals(@Nullable Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + return !super.equals(object) ? false : Objects.equals(this.width, ((LineWidth)object).width); + } else { + return false; + } + } + + public int hashCode() { + return Objects.hash(new Object[]{super.hashCode(), this.width}); + } + + public String toString() { + return this.name + '[' + (this.width.isPresent() ? this.width.getAsDouble() : "window_scale") + ']'; + } + } + + + public static class Target extends RenderPhase { + public Target(String string, Runnable runnable, Runnable runnable2) { + super(string, runnable, runnable2); + } + } + + + public static class Fog extends RenderPhase { + public Fog(String string, Runnable runnable, Runnable runnable2) { + super(string, runnable, runnable2); + } + } + + + public static class Layering extends RenderPhase { + public Layering(String string, Runnable runnable, Runnable runnable2) { + super(string, runnable, runnable2); + } + } + + + public static class WriteMaskState extends RenderPhase { + private final boolean color; + private final boolean depth; + + public WriteMaskState(boolean color, boolean depth) { + super("write_mask_state", () -> { + if (!depth) { + GLStateManager.glDepthMask(depth); + } + + if (!color) { + GLStateManager.glColorMask(color, color, color, color); + } + + }, () -> { + if (!depth) { + GLStateManager.glDepthMask(true); + } + + if (!color) { + GLStateManager.glColorMask(true, true, true, true); + } + + }); + this.color = color; + this.depth = depth; + } + + public boolean equals(Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + WriteMaskState lv = (WriteMaskState)object; + return this.color == lv.color && this.depth == lv.depth; + } else { + return false; + } + } + + public int hashCode() { + return Objects.hash(new Object[]{this.color, this.depth}); + } + + public String toString() { + return this.name + "[writeColor=" + this.color + ", writeDepth=" + this.depth + ']'; + } + } + + + public static class DepthTest extends RenderPhase { + private final String depthFunction; + private final int func; + + public DepthTest(String string, int i) { + super("depth_test", () -> { + if (i != GL11.GL_ALWAYS) { + GLStateManager.enableDepthTest(); + GLStateManager.glDepthFunc(i); + } + + }, () -> { + if (i != GL11.GL_ALWAYS) { + GLStateManager.disableDepthTest(); + GLStateManager.glDepthFunc(GL11.GL_LEQUAL); + } + + }); + this.depthFunction = string; + this.func = i; + } + + public boolean equals(Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + DepthTest lv = (DepthTest)object; + return this.func == lv.func; + } else { + return false; + } + } + + public int hashCode() { + return Integer.hashCode(this.func); + } + + public String toString() { + return this.name + '[' + this.depthFunction + ']'; + } + } + + + public static class Cull extends Toggleable { + public Cull(boolean culling) { + super("cull", () -> { + if (!culling) { + GLStateManager.disableCull(); + } + + }, () -> { + if (!culling) { + GLStateManager.enableCull(); + } + + }, culling); + } + } + + + public static class DiffuseLighting extends Toggleable { + public DiffuseLighting(boolean guiLighting) { + super("diffuse_lighting", () -> { + if (guiLighting) { + throw new RuntimeException("Not Implemented Yet"); +// net.minecraft.client.render.DiffuseLighting.enable(); + } + + }, () -> { + if (guiLighting) { + throw new RuntimeException("Not Implemented Yet"); +// net.minecraft.client.render.DiffuseLighting.disable(); + } + + }, guiLighting); + } } + + public static class Overlay extends Toggleable { + public Overlay(boolean overlayColor) { + super("overlay", () -> { + if (overlayColor) { + throw new RuntimeException("Not Implemented Yet"); +// MinecraftClient.getInstance().gameRenderer.getOverlayTexture().setupOverlayColor(); + } + + }, () -> { + if (overlayColor) { + throw new RuntimeException("Not Implemented Yet"); +// MinecraftClient.getInstance().gameRenderer.getOverlayTexture().teardownOverlayColor(); + } + + }, overlayColor); + } + } + + + public static class Lightmap extends Toggleable { + public Lightmap(boolean lightmap) { + super("lightmap", () -> { + if (lightmap) { + throw new RuntimeException("Not Implemented Yet"); +// MinecraftClient.getInstance().gameRenderer.getLightmapTextureManager().enable(); + } + + }, () -> { + if (lightmap) { + throw new RuntimeException("Not Implemented Yet"); +// MinecraftClient.getInstance().gameRenderer.getLightmapTextureManager().disable(); + } + + }, lightmap); + } + } + + + static class Toggleable extends RenderPhase { + private final boolean enabled; + + public Toggleable(String string, Runnable runnable, Runnable runnable2, boolean bl) { + super(string, runnable, runnable2); + this.enabled = bl; + } + + public boolean equals(Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + Toggleable lv = (Toggleable)object; + return this.enabled == lv.enabled; + } else { + return false; + } + } + + public int hashCode() { + return Boolean.hashCode(this.enabled); + } + + public String toString() { + return this.name + '[' + this.enabled + ']'; + } + } + + + public static final class PortalTexturing extends Texturing { + private final int layer; + + public PortalTexturing(int layer) { + super("portal_texturing", () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.matrixMode(5890); +// RenderSystem.pushMatrix(); +// RenderSystem.loadIdentity(); +// RenderSystem.translatef(0.5F, 0.5F, 0.0F); +// RenderSystem.scalef(0.5F, 0.5F, 1.0F); +// RenderSystem.translatef(17.0F / (float)layer, (2.0F + (float)layer / 1.5F) * ((float)(Util.getMeasuringTimeMs() % 800000L) / 800000.0F), 0.0F); +// RenderSystem.rotatef(((float)(layer * layer) * 4321.0F + (float)layer * 9.0F) * 2.0F, 0.0F, 0.0F, 1.0F); +// RenderSystem.scalef(4.5F - (float)layer / 4.0F, 4.5F - (float)layer / 4.0F, 1.0F); +// RenderSystem.mulTextureByProjModelView(); +// RenderSystem.matrixMode(5888); +// RenderSystem.setupEndPortalTexGen(); + }, () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.matrixMode(5890); +// RenderSystem.popMatrix(); +// RenderSystem.matrixMode(5888); +// RenderSystem.clearTexGen(); + }); + this.layer = layer; + } + + public boolean equals(Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + PortalTexturing lv = (PortalTexturing)object; + return this.layer == lv.layer; + } else { + return false; + } + } + + public int hashCode() { + return Integer.hashCode(this.layer); + } + } + + + public static final class OffsetTexturing extends Texturing { + private final float x; + private final float y; + + public OffsetTexturing(float x, float y) { + super("offset_texturing", () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.matrixMode(5890); +// RenderSystem.pushMatrix(); +// RenderSystem.loadIdentity(); +// RenderSystem.translatef(x, y, 0.0F); +// RenderSystem.matrixMode(5888); + }, () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.matrixMode(5890); +// RenderSystem.popMatrix(); +// RenderSystem.matrixMode(5888); + }); + this.x = x; + this.y = y; + } + + public boolean equals(Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + OffsetTexturing lv = (OffsetTexturing)object; + return Float.compare(lv.x, this.x) == 0 && Float.compare(lv.y, this.y) == 0; + } else { + return false; + } + } + + public int hashCode() { + return Objects.hash(new Object[]{this.x, this.y}); + } + } + + + public static class Texturing extends RenderPhase { + public Texturing(String string, Runnable runnable, Runnable runnable2) { + super(string, runnable, runnable2); + } + } + + + public static class Texture extends RenderPhase { + private final Optional id; + protected boolean bilinear; + protected boolean mipmap; + + public Texture(ResourceLocation id, boolean bilinear, boolean mipmap) { + super("texture", () -> { + GLStateManager.enableTexture(); + TextureManager lv = Minecraft.getMinecraft().getTextureManager(); + lv.bindTexture(id); + throw new RuntimeException("Not Implemented Yet"); +// lv.getTexture(id).setFilter(bilinear, mipmap); + }, () -> { + }); + this.id = Optional.of(id); + this.bilinear = bilinear; + this.mipmap = mipmap; + } + + public Texture() { + super("texture", GLStateManager::disableTexture, GLStateManager::enableTexture); + this.id = Optional.empty(); + this.bilinear = false; + this.mipmap = false; + } + + public boolean equals(Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + Texture lv = (Texture)object; + return this.id.equals(lv.id) && this.bilinear == lv.bilinear && this.mipmap == lv.mipmap; + } else { + return false; + } + } + + public int hashCode() { + return this.id.hashCode(); + } + + public String toString() { + return this.name + '[' + this.id + "(blur=" + this.bilinear + ", mipmap=" + this.mipmap + ")]"; + } + + protected Optional getId() { + return this.id; + } + } + + + public static class ShadeModel extends RenderPhase { + private final boolean smooth; + + public ShadeModel(boolean smooth) { + super("shade_model", () -> { + throw new RuntimeException("Not Implemented Yet"); +// RenderSystem.shadeModel(smooth ? 7425 : 7424); + }, () -> { +// RenderSystem.shadeModel(7424); + throw new RuntimeException("Not Implemented Yet"); + }); + this.smooth = smooth; + } + + public boolean equals(Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + ShadeModel lv = (ShadeModel)object; + return this.smooth == lv.smooth; + } else { + return false; + } + } + + public int hashCode() { + return Boolean.hashCode(this.smooth); + } + + public String toString() { + return this.name + '[' + (this.smooth ? "smooth" : "flat") + ']'; + } + } + + + public static class Alpha extends RenderPhase { + private final float alpha; + + public Alpha(float alpha) { + super("alpha", () -> { + if (alpha > 0.0F) { + + GLStateManager.enableAlphaTest(); + GLStateManager.glAlphaFunc(GL11.GL_GREATER, alpha); + } else { + GLStateManager.disableAlphaTest(); + } + + }, () -> { + GLStateManager.disableAlphaTest(); + GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.1F); + }); + this.alpha = alpha; + } + + public boolean equals(@Nullable Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + if (!super.equals(object)) { + return false; + } else { + return this.alpha == ((Alpha)object).alpha; + } + } else { + return false; + } + } + + public int hashCode() { + return Objects.hash(new Object[]{super.hashCode(), this.alpha}); + } + + public String toString() { + return this.name + '[' + this.alpha + ']'; + } + } + + + public static class Transparency extends RenderPhase { + public Transparency(String string, Runnable runnable, Runnable runnable2) { + super(string, runnable, runnable2); + } + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRenderer.java deleted file mode 100644 index b1102a7d7..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRenderer.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -public class WorldRenderer { - public static int getLightmapCoordinates(BlockRenderView world, BlockState state, BlockPos pos) { - return 15; - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java new file mode 100644 index 000000000..76e2da087 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java @@ -0,0 +1,8 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public interface WorldRendererExt { + static int getLightmapCoordinates(BlockRenderView world, BlockState state, BlockPos pos) { + return 15; + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 679a770b0..7dc4f1f30 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -49,11 +49,13 @@ public class GLStateManager { private static final BooleanState Cull = new BooleanState(GL11.GL_CULL_FACE); @Getter private static final AlphaState Alpha = new AlphaState(); + + // TODO: Maybe inject the iris stuff via mixins.... @Getter private static final TextureState[] Textures; // Iris Listeners - private static Runnable blendFuncListener; + private static Runnable blendFuncListener = null; static { StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener; @@ -66,8 +68,8 @@ public static void glEnable(int cap) { switch(cap) { case GL11.GL_ALPHA_TEST -> enableAlphaTest(); case GL11.GL_BLEND -> enableBlend(); - case GL11.GL_DEPTH_TEST -> Depth.mode.enable(); - case GL11.GL_CULL_FACE -> Cull.enable(); + case GL11.GL_DEPTH_TEST -> enableDepthTest(); + case GL11.GL_CULL_FACE -> enableCull(); case GL11.GL_TEXTURE_2D -> enableTexture(); default -> GL11.glEnable(cap); } @@ -78,8 +80,8 @@ public static void glDisable(int cap) { switch (cap) { case GL11.GL_ALPHA_TEST -> disableAlphaTest(); case GL11.GL_BLEND -> disableBlend(); - case GL11.GL_DEPTH_TEST -> Depth.mode.disable(); - case GL11.GL_CULL_FACE -> Cull.disable(); + case GL11.GL_DEPTH_TEST -> disableDepthTest(); + case GL11.GL_CULL_FACE -> disableCull(); case GL11.GL_TEXTURE_2D -> disableTexture(); default -> GL11.glDisable(cap); } @@ -87,29 +89,32 @@ public static void glDisable(int cap) { // GLStateManager Functions - private static void enableBlend() { - // Iris - if(BlendModeStorage.isBlendLocked()) { - BlendModeStorage.deferBlendModeToggle(true); - return; + public static void enableBlend() { + if (Iris.isInitialized()) { + if (BlendModeStorage.isBlendLocked()) { + BlendModeStorage.deferBlendModeToggle(true); + return; + } } Blend.mode.enable(); } public static void disableBlend() { - // Iris - if (BlendModeStorage.isBlendLocked()) { - BlendModeStorage.deferBlendModeToggle(false); - return; + if (Iris.isInitialized()) { + if (BlendModeStorage.isBlendLocked()) { + BlendModeStorage.deferBlendModeToggle(false); + return; + } } Blend.mode.disable(); } public static void glBlendFunc(int srcFactor, int dstFactor) { - // Iris - if(BlendModeStorage.isBlendLocked()) { - BlendModeStorage.deferBlendFunc(srcFactor, dstFactor, srcFactor, dstFactor); - return; + if (Iris.isInitialized()) { + if (BlendModeStorage.isBlendLocked()) { + BlendModeStorage.deferBlendFunc(srcFactor, dstFactor, srcFactor, dstFactor); + return; + } } Blend.srcRgb = srcFactor; Blend.dstRgb = dstFactor; @@ -120,10 +125,11 @@ public static void glBlendFunc(int srcFactor, int dstFactor) { } public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { - // Iris - if(BlendModeStorage.isBlendLocked()) { - BlendModeStorage.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); - return; + if (Iris.isInitialized()) { + if (BlendModeStorage.isBlendLocked()) { + BlendModeStorage.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); + return; + } } Blend.srcRgb = srcRgb; Blend.dstRgb = dstRgb; @@ -143,10 +149,11 @@ public static void glDepthFunc(int func) { } public static void glDepthMask(boolean mask) { - // Iris - if (DepthColorStorage.isDepthColorLocked()) { - DepthColorStorage.deferDepthEnable(mask); - return; + if (Iris.isInitialized()) { + if (DepthColorStorage.isDepthColorLocked()) { + DepthColorStorage.deferDepthEnable(mask); + return; + } } if(mask != Depth.mask) { @@ -172,10 +179,11 @@ public static void clearCurrentColor() { } public static void glColorMask(boolean red, boolean green, boolean blue, boolean alpha) { - // Iris - if (DepthColorStorage.isDepthColorLocked()) { - DepthColorStorage.deferColorMask(red, green, blue, alpha); - return; + if (Iris.isInitialized()) { + if (DepthColorStorage.isDepthColorLocked()) { + DepthColorStorage.deferColorMask(red, green, blue, alpha); + return; + } } if(red != ColorMask.red || green != ColorMask.green || blue != ColorMask.blue || alpha != ColorMask.alpha) { ColorMask.red = red; @@ -188,28 +196,31 @@ public static void glColorMask(boolean red, boolean green, boolean blue, boolean // ALPHA public static void enableAlphaTest() { - // Iris - if (AlphaTestStorage.isAlphaTestLocked()) { - AlphaTestStorage.deferAlphaTestToggle(true); - return; + if (Iris.isInitialized()) { + if (AlphaTestStorage.isAlphaTestLocked()) { + AlphaTestStorage.deferAlphaTestToggle(true); + return; + } } Alpha.mode.enable(); } public static void disableAlphaTest() { - // Iris - if (AlphaTestStorage.isAlphaTestLocked()) { - AlphaTestStorage.deferAlphaTestToggle(false); - return; + if (Iris.isInitialized()) { + if (AlphaTestStorage.isAlphaTestLocked()) { + AlphaTestStorage.deferAlphaTestToggle(false); + return; + } } Alpha.mode.disable(); } public static void glAlphaFunc(int function, float reference) { - // Iris - if (AlphaTestStorage.isAlphaTestLocked()) { - AlphaTestStorage.deferAlphaFunc(function, reference); - return; + if (Iris.isInitialized()) { + if (AlphaTestStorage.isAlphaTestLocked()) { + AlphaTestStorage.deferAlphaFunc(function, reference); + return; + } } Alpha.function = function; Alpha.reference = reference; @@ -236,74 +247,82 @@ public static void glBindTexture(int target, int texture) { if(Textures[activeTexture].binding != texture) { Textures[activeTexture].binding = texture; GL11.glBindTexture(target, texture); - TextureTracker.INSTANCE.onBindTexture(texture); + if (Iris.isInitialized()) { + TextureTracker.INSTANCE.onBindTexture(texture); + } } } public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, IntBuffer pixels) { - // Iris - TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + if (Iris.isInitialized()) { + // Iris + TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + } GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, ByteBuffer pixels) { - // Iris - TextureInfoCache.INSTANCE.onTexImage2D( - target, level, internalformat, width, height, border, format, type, - pixels != null ? pixels.asIntBuffer() : (IntBuffer) null - ); + if (Iris.isInitialized()) { + TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels != null ? pixels.asIntBuffer() : (IntBuffer) null); + } GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } public static void glDeleteTextures(int id) { - // Iris - iris$onDeleteTexture(id); + if (Iris.isInitialized()) { + iris$onDeleteTexture(id); + } GL11.glDeleteTextures(id); } public static void glDeleteTextures(IntBuffer ids) { - // Iris - for(int id: ids.array()) { - iris$onDeleteTexture(id); + if (Iris.isInitialized()) { + for (int id : ids.array()) { + iris$onDeleteTexture(id); + } } GL11.glDeleteTextures(ids); } public static void enableTexture() { - // Iris - boolean updatePipeline = false; - if (activeTexture == IrisSamplers.ALBEDO_TEXTURE_UNIT) { - StateTracker.INSTANCE.albedoSampler = true; - updatePipeline = true; - } else if (activeTexture == IrisSamplers.LIGHTMAP_TEXTURE_UNIT) { - StateTracker.INSTANCE.lightmapSampler = true; - updatePipeline = true; - } else if (activeTexture == IrisSamplers.OVERLAY_TEXTURE_UNIT) { - StateTracker.INSTANCE.overlaySampler = true; - updatePipeline = true; - } - - if(updatePipeline) { - Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setInputs(StateTracker.INSTANCE.getInputs())); + if (Iris.isInitialized()) { + // Iris + boolean updatePipeline = false; + if (activeTexture == IrisSamplers.ALBEDO_TEXTURE_UNIT) { + StateTracker.INSTANCE.albedoSampler = true; + updatePipeline = true; + } else if (activeTexture == IrisSamplers.LIGHTMAP_TEXTURE_UNIT) { + StateTracker.INSTANCE.lightmapSampler = true; + updatePipeline = true; + } else if (activeTexture == IrisSamplers.OVERLAY_TEXTURE_UNIT) { + StateTracker.INSTANCE.overlaySampler = true; + updatePipeline = true; + } + + if (updatePipeline) { + Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setInputs(StateTracker.INSTANCE.getInputs())); + } } Textures[activeTexture].mode.enable(); } public static void disableTexture() { - // Iris - boolean updatePipeline = false; - if (activeTexture == IrisSamplers.ALBEDO_TEXTURE_UNIT) { - StateTracker.INSTANCE.albedoSampler = false; - updatePipeline = true; - } else if (activeTexture == IrisSamplers.LIGHTMAP_TEXTURE_UNIT) { - StateTracker.INSTANCE.lightmapSampler = false; - updatePipeline = true; - } else if (activeTexture == IrisSamplers.OVERLAY_TEXTURE_UNIT) { - StateTracker.INSTANCE.overlaySampler = false; - updatePipeline = true; - } - - if(updatePipeline) { - Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setInputs(StateTracker.INSTANCE.getInputs())); + if (Iris.isInitialized()) { + // Iris + boolean updatePipeline = false; + if (activeTexture == IrisSamplers.ALBEDO_TEXTURE_UNIT) { + StateTracker.INSTANCE.albedoSampler = false; + updatePipeline = true; + } else if (activeTexture == IrisSamplers.LIGHTMAP_TEXTURE_UNIT) { + StateTracker.INSTANCE.lightmapSampler = false; + updatePipeline = true; + } else if (activeTexture == IrisSamplers.OVERLAY_TEXTURE_UNIT) { + StateTracker.INSTANCE.overlaySampler = false; + updatePipeline = true; + } + + if (updatePipeline) { + Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setInputs(StateTracker.INSTANCE.getInputs())); + } } Textures[activeTexture].mode.disable(); @@ -317,12 +336,33 @@ public static void glDrawArrays(int mode, int first, int count) { } - // Iris Functions + public static void defaultBlendFunc() { + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + } + + public static void enableCull() { + Cull.enable(); + } + + public static void disableCull() { + Cull.disable(); + } + + public static void enableDepthTest() { + Depth.mode.enable(); + } + public static void disableDepthTest() { + Depth.mode.disable(); + } + + // Iris Functions private static void iris$onDeleteTexture(int id) { - TextureTracker.INSTANCE.onDeleteTexture(id); - TextureInfoCache.INSTANCE.onDeleteTexture(id); - PBRTextureManager.INSTANCE.onDeleteTexture(id); + if (Iris.isInitialized()) { + TextureTracker.INSTANCE.onDeleteTexture(id); + TextureInfoCache.INSTANCE.onDeleteTexture(id); + PBRTextureManager.INSTANCE.onDeleteTexture(id); + } } } diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java index cd892a54f..65a6b86de 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java @@ -48,8 +48,9 @@ public List getMixins(Set loadedMods) { } } AngelicaTweaker.LOGGER.info("Not loading the following LATE mixins: {}", notLoading.toString()); - mixins.addAll(getNotFineMixins(loadedMods)); - mixins.addAll(getArchaicMixins(loadedMods)); + // TODO: Sodium +// mixins.addAll(getNotFineMixins(loadedMods)); +// mixins.addAll(getArchaicMixins(loadedMods)); return mixins; } diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index 29bf2662b..ef46f52f1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -99,8 +99,9 @@ public List getMixins(Set loadedCoreMods) { } } LOGGER.info("Not loading the following EARLY mixins: {}", notLoading); - mixins.addAll(getNotFineMixins(loadedCoreMods)); - mixins.addAll(getArchaicMixins(loadedCoreMods)); + // TODO: Sodium +// mixins.addAll(getNotFineMixins(loadedCoreMods)); +// mixins.addAll(getArchaicMixins(loadedCoreMods)); return mixins; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index abb1a846e..f3c5e1a21 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -11,33 +11,42 @@ public enum Mixins { IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses( - "shaders.startup.MixinGameSettings", - "shaders.startup.MixinGuiMainMenu", - "shaders.startup.MixinInitRenderer") - ), - IRIS_RENDERING(new Builder("Iris Shaders").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses( - "shaders.MixinFramebuffer", - "shaders.MixinEntityRenderer", - "shaders.MixinItem", - "shaders.MixinOpenGlHelper" - ) + .setPhase(Phase.EARLY).setApplyIf(() -> false).addMixinClasses( + "shaders.startup.MixinGameSettings", + "shaders.startup.MixinGuiMainMenu", + "shaders.startup.MixinInitRenderer") ), + SODIUM_STARTUP(new Builder("Start Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).addMixinClasses( + "sodium.MixinRenderGlobal" + ,"sodium.MixinWorldClient" + ,"sodium.MixinChunkProviderClient" + ) + ), + + IRIS_RENDERING(new Builder("Iris Shaders").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).setApplyIf(() -> false).addMixinClasses( + "shaders.MixinFramebuffer", + "shaders.MixinEntityRenderer", + "shaders.MixinItem", + "shaders.MixinOpenGlHelper" + ) + ), + IRIS_ACCESSORS(new Builder("Iris Accessors").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses( - "shaders.accessors.MinecraftAccessor", - "shaders.accessors.EntityRendererAccessor", - "shaders.accessors.SimpleTextureAccessor", - "shaders.accessors.TextureAtlasSpriteAccessor" - )), + .setPhase(Phase.EARLY).addMixinClasses( + "shaders.accessors.MinecraftAccessor", + "shaders.accessors.EntityRendererAccessor", + "shaders.accessors.SimpleTextureAccessor", + "shaders.accessors.TextureAtlasSpriteAccessor" + )), ANGELICA_TEXTURE(new Builder("Texture").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses( + .setPhase(Phase.EARLY).addMixinClasses( - )), + )), // TODO: Iris // SHADERSMOD_COMPAT_PR_ILLUMINATION( diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java new file mode 100644 index 000000000..55d2963a3 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java @@ -0,0 +1,41 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; +import me.jellysquid.mods.sodium.client.world.ChunkStatusListenerManager; +import net.minecraft.client.multiplayer.ChunkProviderClient; +import net.minecraft.world.chunk.Chunk; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ChunkProviderClient.class) +public class MixinChunkProviderClient implements ChunkStatusListenerManager { + private ChunkStatusListener listener; + private final LongOpenHashSet loadedChunks = new LongOpenHashSet(); + + @Override + public void setListener(ChunkStatusListener listener) { + this.listener = listener; + } + + @Inject(method="loadChunk", at = @At(value = "INVOKE", target="Lcpw/mods/fml/common/eventhandler/EventBus;post(Lcpw/mods/fml/common/eventhandler/Event;)Z", shift = At.Shift.BEFORE)) + private void sodium$loadChunk(int x, int z, CallbackInfoReturnable cir) { + if (this.listener != null) { + this.listener.onChunkAdded(x, z); + this.loadedChunks.add(ChunkPos.toLong(x, z)); + } + } + + @Inject(method="unloadChunk", at=@At("TAIL")) + private void sodium$unloadChunk(int x, int z, CallbackInfo ci) { + if (this.listener != null) { + this.listener.onChunkRemoved(x, z); + this.loadedChunks.remove(ChunkPos.toLong(x, z)); + } + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java new file mode 100644 index 000000000..f193ca058 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -0,0 +1,33 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.renderer.RenderGlobal; +import org.spongepowered.asm.mixin.Mixin; +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.CallbackInfo; + +@Mixin(RenderGlobal.class) +public class MixinRenderGlobal { + @Unique private SodiumWorldRenderer renderer; + + @Inject(method="", at=@At("RETURN")) + private void sodium$initRenderer(Minecraft mc, CallbackInfo ci) { + this.renderer = SodiumWorldRenderer.create(mc); + } + + @Inject(method="Lnet/minecraft/client/renderer/RenderGlobal;setWorldAndLoadRenderers(Lnet/minecraft/client/multiplayer/WorldClient;)V", at=@At("HEAD")) + private void sodium$setWorldAndLoadRenderers(WorldClient world, CallbackInfo ci) { + RenderDevice.enterManagedCode(); + try { + this.renderer.setWorld(world); + } finally { + RenderDevice.exitManagedCode(); + } + + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorld.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorld.java deleted file mode 100644 index af3f513eb..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorld.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.sodium; - -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; - -@Mixin(World.class) -public abstract class MixinWorld implements BlockRenderView { - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java new file mode 100644 index 000000000..208a82cc1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java @@ -0,0 +1,19 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; +import com.gtnewhorizons.angelica.mixins.interfaces.IHasClientChunkProvider; +import net.minecraft.client.multiplayer.ChunkProviderClient; +import net.minecraft.client.multiplayer.WorldClient; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(WorldClient.class) +public abstract class MixinWorldClient implements BlockRenderView, IHasClientChunkProvider { + @Shadow + private ChunkProviderClient clientChunkProvider; + + @Override + public ChunkProviderClient getClientChunkProvider() { + return clientChunkProvider; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasClientChunkProvider.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasClientChunkProvider.java new file mode 100644 index 000000000..dafe4e950 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasClientChunkProvider.java @@ -0,0 +1,8 @@ +package com.gtnewhorizons.angelica.mixins.interfaces; + +import net.minecraft.client.multiplayer.ChunkProviderClient; + +public interface IHasClientChunkProvider { + ChunkProviderClient getClientChunkProvider(); + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index 8cce75bd4..4fa03b12b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -2,8 +2,8 @@ import com.gtnewhorizons.angelica.Tags; import cpw.mods.fml.common.Mod; -import cpw.mods.fml.common.event.FMLInitializationEvent; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import net.minecraft.client.Minecraft; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -16,7 +16,7 @@ public class SodiumClientMod { private static SodiumGameOptions CONFIG; public static Logger LOGGER = LogManager.getLogger("Embeddium"); - private static String MOD_VERSION; + private static String MOD_VERSION = Tags.VERSION; public static final String MODID = "embeddium"; public static final String NAME = "Embeddium"; @@ -27,10 +27,6 @@ public SodiumClientMod() { // ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); } - public void onInitializeClient(final FMLInitializationEvent event) { - MOD_VERSION = Tags.VERSION; // ModList.get().getModContainerById(MODID).get().getModInfo().getVersion().toString(); - } - public static SodiumGameOptions options() { if (CONFIG == null) { CONFIG = loadConfig(); @@ -48,8 +44,7 @@ public static Logger logger() { } private static SodiumGameOptions loadConfig() { -// return SodiumGameOptions.load(FMLPaths.CONFIGDIR.get().resolve("rubidium-options.json")); - return null; + return SodiumGameOptions.load(Minecraft.getMinecraft().mcDataDir.toPath().resolve("config").resolve("rubidium-options.json")); } public static String getVersion() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java index f18a0adf3..93c0f64d1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java @@ -1,10 +1,10 @@ package me.jellysquid.mods.sodium.client.model.light; -import cofh.lib.util.helpers.MathHelper; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import me.jellysquid.mods.sodium.client.render.entity.EntityLightSampler; +import net.minecraft.util.MathHelper; import net.minecraft.entity.Entity; import static org.joml.Math.lerp; @@ -34,12 +34,12 @@ public static int getBlendedLight(EntityLightSampler light double z2 = z1 + width; // The sampling volume of blocks which could possibly contribute light to this entity - int bMinX = MathHelper.floor(x1); - int bMinY = MathHelper.floor(y1); - int bMinZ = MathHelper.floor(z1); - int bMaxX = MathHelper.ceil(x2); - int bMaxY = MathHelper.ceil(y2); - int bMaxZ = MathHelper.ceil(z2); + int bMinX = MathHelper.floor_double(x1); + int bMinY = MathHelper.floor_double(y1); + int bMinZ = MathHelper.floor_double(z1); + int bMaxX = MathHelper.ceiling_double_int(x2); + int bMaxY = MathHelper.ceiling_double_int(y2); + int bMaxZ = MathHelper.ceiling_double_int(z2); // The maximum amount of light that could be contributed double max = 0.0D; @@ -93,8 +93,8 @@ public static int getBlendedLight(EntityLightSampler light } // The final light value is calculated from the percentage of light contributed out of the total maximum - int bli = MathHelper.floor((bl / max) * MAX_LIGHTMAP_COORD); - int sli = MathHelper.floor((sl / max) * MAX_LIGHTMAP_COORD); + int bli = MathHelper.floor_double((bl / max) * MAX_LIGHTMAP_COORD); + int sli = MathHelper.floor_double((sl / max) * MAX_LIGHTMAP_COORD); return ((sli & 0xFFFF) << 16) | (bli & 0xFFFF); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java index e03114d24..38aff7de4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java @@ -3,7 +3,7 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import com.gtnewhorizons.angelica.compat.mojang.WorldRenderer; +import com.gtnewhorizons.angelica.compat.mojang.WorldRendererExt; import net.minecraftforge.common.util.ForgeDirection; /** @@ -70,7 +70,7 @@ protected long compute(int x, int y, int z) { // OPTIMIZE: Do not calculate lightmap data if the block is full and opaque. // FIX: Calculate lightmap data for light-emitting or emissive blocks, even though they are full and opaque. - int lm = (fo && !em) ? 0 : WorldRenderer.getLightmapCoordinates(world, state, pos); + int lm = (fo && !em) ? 0 : WorldRendererExt.getLightmapCoordinates(world, state, pos); return packAO(ao) | packLM(lm) | packOP(op) | packFO(fo) | packFC(fc) | (1L << 60); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java index 4503c8fcc..2e64f800c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java @@ -8,7 +8,7 @@ import org.joml.Matrix4f; public interface GlyphVertexSink extends VertexSink { - VertexFormat VERTEX_FORMAT = DefaultVertexFormat.PARTICLE; + VertexFormat VERTEX_FORMAT = DefaultVertexFormat.POSITION_TEXTURE_COLOR_LIGHT; /** * Writes a glyph vertex to the sink. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java index 4d111e608..c0f975818 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java @@ -6,7 +6,7 @@ public interface ParticleVertexSink extends VertexSink { - VertexFormat VERTEX_FORMAT = DefaultVertexFormat.PARTICLE; + VertexFormat VERTEX_FORMAT = DefaultVertexFormat.POSITION_TEXTURE_COLOR_LIGHT; /** * @param x The x-position of the vertex diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java index 07006063e..72c9e8a64 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java @@ -9,7 +9,7 @@ public interface QuadVertexSink extends VertexSink { - VertexFormat VERTEX_FORMAT = DefaultVertexFormat.BLOCK; // POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL + VertexFormat VERTEX_FORMAT = DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL; /** * Writes a quad vertex to this sink. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 9d084bf0e..3c57da1b6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.render; -import cofh.lib.util.helpers.MathHelper; import com.gtnewhorizons.angelica.compat.mojang.BlockBreakingInfo; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; @@ -15,6 +14,7 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexConsumerProvider; import com.gtnewhorizons.angelica.compat.mojang.VertexConsumers; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.mixins.interfaces.IHasClientChunkProvider; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; @@ -38,6 +38,7 @@ import me.jellysquid.mods.sodium.common.util.ListUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; @@ -45,6 +46,7 @@ import net.minecraft.profiler.Profiler; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MathHelper; import org.joml.Vector3d; import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap; @@ -84,9 +86,9 @@ public class SodiumWorldRenderer implements ChunkStatusListener { /** * Instantiates Sodium's world renderer. This should be called at the time of the world renderer initialization. */ - public static SodiumWorldRenderer create() { + public static SodiumWorldRenderer create(Minecraft mc) { if (instance == null) { - instance = new SodiumWorldRenderer(Minecraft.getMinecraft()); + instance = new SodiumWorldRenderer(mc); } return instance; @@ -132,7 +134,7 @@ private void loadWorld(WorldClient world) { this.initRenderer(); - ((ChunkStatusListenerManager) world.getWorldChunkManager()).setListener(this); + ((ChunkStatusListenerManager) ((IHasClientChunkProvider)world).getClientChunkProvider()).setListener(this); } private void unloadWorld() { @@ -406,13 +408,13 @@ public boolean isEntityVisible(Entity entity) { return true; } - int minX = MathHelper.floor(box.minX - 0.5D) >> 4; - int minY = MathHelper.floor(box.minY - 0.5D) >> 4; - int minZ = MathHelper.floor(box.minZ - 0.5D) >> 4; + int minX = MathHelper.floor_double(box.minX - 0.5D) >> 4; + int minY = MathHelper.floor_double(box.minY - 0.5D) >> 4; + int minZ = MathHelper.floor_double(box.minZ - 0.5D) >> 4; - int maxX = MathHelper.floor(box.maxX + 0.5D) >> 4; - int maxY = MathHelper.floor(box.maxY + 0.5D) >> 4; - int maxZ = MathHelper.floor(box.maxZ + 0.5D) >> 4; + int maxX = MathHelper.floor_double(box.maxX + 0.5D) >> 4; + int maxY = MathHelper.floor_double(box.maxY + 0.5D) >> 4; + int maxZ = MathHelper.floor_double(box.maxZ + 0.5D) >> 4; for (int x = minX; x <= maxX; x++) { for (int z = minZ; z <= maxZ; z++) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index b3faacf3a..da3f6acd4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -35,6 +35,7 @@ import me.jellysquid.mods.sodium.common.util.collections.FutureDequeDrain; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraftforge.common.util.ForgeDirection; import org.joml.Vector3d; @@ -431,8 +432,9 @@ private ChunkRenderColumn getColumn(int x, int z) { private ChunkRenderContainer createChunkRender(ChunkRenderColumn column, int x, int y, int z) { ChunkRenderContainer render = new ChunkRenderContainer<>(this.backend, this.renderer, x, y, z, column); + final ExtendedBlockStorage array = this.world.getChunkFromChunkCoords(x, z).getBlockStorageArray()[y]; - if (this.world.getChunkFromChunkCoords(x, z).getBlockStorageArray()[y].isEmpty()) { + if (array == null || array.isEmpty()) { render.setData(ChunkRenderData.EMPTY); } else { render.scheduleRebuild(false); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java index dccf77571..ba0d9fc88 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; -import cofh.lib.util.helpers.MathHelper; import com.gtnewhorizons.angelica.compat.forge.ForgeBlockRenderer; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; @@ -22,6 +21,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.world.World; +import net.minecraft.util.MathHelper; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.joml.Vector3d; @@ -231,7 +231,7 @@ public void init(WorldClient world, BlockRenderPassManager renderPassManager) { * but can be up to the number of available processor threads on the system. */ private static int getOptimalThreadCount() { - return MathHelper.clamp(Math.max(getMaxThreadCount() / 3, getMaxThreadCount() - 6), 1, 10); + return MathHelper.clamp_int(Math.max(getMaxThreadCount() / 3, getMaxThreadCount() - 6), 1, 10); } private static int getThreadCount() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java index 98120b13b..f7d1bc695 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.cull.graph; -import cofh.lib.util.helpers.MathHelper; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.Camera; @@ -14,6 +13,7 @@ import me.jellysquid.mods.sodium.common.util.DirectionUtil; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; +import net.minecraft.util.MathHelper; import java.util.ArrayList; import java.util.Comparator; @@ -100,7 +100,7 @@ private void initSearch(Camera camera, FrustumExtended frustum, int frame, boole this.visible.add(rootNode); } else { - chunkY = MathHelper.clamp(origin.getY() >> 4, 0, 15); + chunkY = MathHelper.clamp_int(origin.getY() >> 4, 0, 15); List bestNodes = new ArrayList<>(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java index fdd674b49..c906b58f4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java @@ -8,6 +8,7 @@ import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.world.World; import java.util.Map; @@ -18,7 +19,7 @@ public class ChunkRenderCacheShared extends ChunkRenderCache { private final BlockRenderer blockRenderer; private final HashLightDataCache lightCache; - private ChunkRenderCacheShared(World world) { + private ChunkRenderCacheShared(WorldClient world) { Minecraft client = Minecraft.getMinecraft(); this.lightCache = new HashLightDataCache((BlockRenderView)world); @@ -53,7 +54,7 @@ public static void destroyRenderContext(BlockRenderView world) { } } - public static void createRenderContext(World world) { + public static void createRenderContext(WorldClient world) { if (INSTANCES.containsKey(world)) { throw new IllegalStateException("Render context already exists for world: " + world); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java b/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java index 262504ec7..a2a014f9b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.util; -import cofh.lib.util.helpers.MathHelper; +import net.minecraft.util.MathHelper; import org.joml.Vector3f; import org.joml.Vector3i; @@ -53,7 +53,7 @@ public static int pack(float x, float y, float z) { */ private static int encode(float comp) { // TODO: is the clamp necessary here? our inputs should always be normalized vector components - return ((int) (MathHelper.clamp(comp, -1.0F, 1.0F) * COMPONENT_RANGE) & 255); + return ((int) (MathHelper.clamp_float(comp, -1.0F, 1.0F) * COMPONENT_RANGE) & 255); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java index e3ab5ae85..17ec2dc6e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.util.color; -import cofh.lib.util.helpers.MathHelper; +import net.minecraft.util.MathHelper; import org.joml.Vector3d; import java.util.function.Function; @@ -16,9 +16,9 @@ private static Vector3d unpackRgb(int rgb) { } public static Vector3d sampleColor(Vector3d pos, ColorFetcher colorFetcher, Function transformer) { - int intX = MathHelper.floor(pos.x); - int intY = MathHelper.floor(pos.y); - int intZ = MathHelper.floor(pos.z); + int intX = MathHelper.floor_double(pos.x); + int intY = MathHelper.floor_double(pos.y); + int intZ = MathHelper.floor_double(pos.z); int[] values = new int[DIAMETER * DIAMETER * DIAMETER]; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java index 1e1d1a129..9462cc8ad 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java @@ -2,7 +2,6 @@ import com.gtnewhorizons.angelica.compat.mojang.BiomeAccess; import com.gtnewhorizons.angelica.compat.mojang.BiomeAccessType; -import me.jellysquid.mods.sodium.client.world.ClientWorldExtended; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; @@ -17,7 +16,7 @@ public class BiomeCache { public BiomeCache(World world) { // TODO: Sodium this.type = null;//world.getDimension().getBiomeAccessType(); - this.seed = ((ClientWorldExtended) world).getBiomeSeed(); + this.seed = world.getSeed(); this.biomes = new BiomeGenBase[16 * 16]; } diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java b/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java index eac19d5a6..31839f915 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java @@ -14,7 +14,8 @@ * be cloned every time. */ public class DirectionUtil { - public static final ForgeDirection[] ALL_DIRECTIONS = ForgeDirection.values(); + public static final ForgeDirection[] ALL_DIRECTIONS = ForgeDirection.VALID_DIRECTIONS; + public static final int DIRECTION_COUNT = ALL_DIRECTIONS.length; // Provides the same order as enumerating ForgeDirection and checking the axis of each value diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 0bd9b4605..b063c1d3b 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -1,6 +1,7 @@ package net.coderbot.iris; import com.mojang.realmsclient.gui.ChatFormatting; +import lombok.Getter; import net.coderbot.iris.config.IrisConfig; import net.coderbot.iris.gl.GLDebug; import net.coderbot.iris.gl.shader.StandardMacros; @@ -65,6 +66,7 @@ public class Iris { private static String currentPackName; // TODO: Iris Backport - Tie this to archaicfix private static final boolean sodiumInstalled = true; // FMLLoader.getLoadingModList().getModFileById("rubidium") != null; + @Getter private static boolean initialized; private static PipelineManager pipelineManager; diff --git a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java index 383ae8ccc..f183630a6 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java @@ -47,7 +47,7 @@ public void begin() { GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, quadBuffer); - DefaultVertexFormat.POSITION_TEX.setupBufferState(0L); + DefaultVertexFormat.POSITION_TEXTURE.setupBufferState(0L); } public void renderQuad() { @@ -56,7 +56,7 @@ public void renderQuad() { @SuppressWarnings("deprecation") public static void end() { - DefaultVertexFormat.POSITION_TEX.clearBufferState(); + DefaultVertexFormat.POSITION_TEXTURE.clearBufferState(); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); GL11.glEnable(GL11.GL_DEPTH_TEST); diff --git a/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java b/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java index e531c0297..9d66a2ad5 100644 --- a/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java +++ b/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java @@ -23,25 +23,25 @@ public class IrisVertexFormats { ImmutableList.Builder terrainElements = ImmutableList.builder(); ImmutableList.Builder entityElements = ImmutableList.builder(); - terrainElements.add(DefaultVertexFormat.ELEMENT_POSITION); // 12 - terrainElements.add(DefaultVertexFormat.ELEMENT_COLOR); // 16 - terrainElements.add(DefaultVertexFormat.ELEMENT_UV0); // 24 - terrainElements.add(DefaultVertexFormat.ELEMENT_UV2); // 28 - terrainElements.add(DefaultVertexFormat.ELEMENT_NORMAL); // 31 - terrainElements.add(DefaultVertexFormat.ELEMENT_PADDING); // 32 + terrainElements.add(DefaultVertexFormat.POSITION_ELEMENT); // 12 + terrainElements.add(DefaultVertexFormat.COLOR_ELEMENT); // 16 + terrainElements.add(DefaultVertexFormat.TEXTURE_0_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.ELEMENT_PADDING); // 52 - - entityElements.add(DefaultVertexFormat.ELEMENT_POSITION); // 12 - entityElements.add(DefaultVertexFormat.ELEMENT_COLOR); // 16 - entityElements.add(DefaultVertexFormat.ELEMENT_UV0); // 24 - entityElements.add(DefaultVertexFormat.ELEMENT_UV1); // 28 - entityElements.add(DefaultVertexFormat.ELEMENT_UV2); // 32 - entityElements.add(DefaultVertexFormat.ELEMENT_NORMAL); // 35 - entityElements.add(DefaultVertexFormat.ELEMENT_PADDING); // 36 + terrainElements.add(DefaultVertexFormat.PADDING_ELEMENT); // 52 + + entityElements.add(DefaultVertexFormat.POSITION_ELEMENT); // 12 + entityElements.add(DefaultVertexFormat.COLOR_ELEMENT); // 16 + entityElements.add(DefaultVertexFormat.TEXTURE_0_ELEMENT); // 24 + entityElements.add(DefaultVertexFormat.OVERLAY_ELEMENT); // 28 + entityElements.add(DefaultVertexFormat.LIGHT_ELEMENT); // 32 + entityElements.add(DefaultVertexFormat.NORMAL_ELEMENT); // 35 + entityElements.add(DefaultVertexFormat.PADDING_ELEMENT); // 36 entityElements.add(MID_TEXTURE_ELEMENT); // 44 entityElements.add(TANGENT_ELEMENT); // 48 From 7dc36840296f4563b3360a11a2d93368bd730006 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 9 Nov 2023 00:01:21 -0800 Subject: [PATCH 037/301] Sodium Renderer * Add semi working Camera replacement * Start overriding SortAndRender (drawChunkLayer) and clipRenderersByFrustum (updateChunks) - obviously not working yet --- .../angelica/compat/mojang/Camera.java | 41 ++++++------ .../angelica/compat/mojang/RenderPhase.java | 19 ++---- .../angelica/glsm/GLStateManager.java | 23 +++++++ .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../sodium/MixinChunkProviderClient.java | 57 ++++++++++++++--- .../mixins/early/sodium/MixinFrustrum.java | 17 +++++ .../early/sodium/MixinRenderGlobal.java | 64 +++++++++++++++++++ .../transform/GLStateManagerTransformer.java | 2 +- .../coderbot/iris/pipeline/HandRenderer.java | 2 +- 9 files changed, 181 insertions(+), 45 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinFrustrum.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java index 57d5f0155..c35478e26 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java @@ -1,30 +1,29 @@ package com.gtnewhorizons.angelica.compat.mojang; +import lombok.Getter; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.EntityLivingBase; import org.joml.Vector3d; +@Getter public class Camera { + Vector3d pos = new Vector3d(); + BlockPos.Mutable blockPos = new BlockPos.Mutable(); + float pitch; + float yaw; + EntityLivingBase entity; + boolean thirdPerson; + + public Camera(EntityLivingBase entity, float partialTicks) { + final double camX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks; + final double camY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks; + final double camZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks; + pos.set(camX, camY, camZ); + blockPos.set((int)entity.posX, (int)entity.posY, (int)entity.posZ); + pitch = entity.cameraPitch; + yaw = entity.rotationYaw; + thirdPerson = Minecraft.getMinecraft().gameSettings.thirdPersonView == 1; - public boolean isDetached() { - return true; } - public Object getEntity() { - return null; - } - - public BlockPos getBlockPos() { - return new BlockPos(); - } - - public Vector3d getPos() { - return new Vector3d(); - } - - public float getPitch() { - return 0; - } - - public float getYaw() { - return 0; - } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index 5755a3f34..d1986866d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -142,11 +142,11 @@ private static void setupGlintTexturing(float scale) { // RenderSystem.matrixMode(5888); } - private static ResourceLocation UNKONWN_TEXTURE = new ResourceLocation("textures/misc/unknown_server.png"); + private static ResourceLocation ATLAS = new ResourceLocation("sodium", "textures/atlas.png"); static { // TODO: Sodium - SpriteAtlasTexture - MIPMAP_BLOCK_ATLAS_TEXTURE = new Texture( UNKONWN_TEXTURE/*SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE*/, false, true); - BLOCK_ATLAS_TEXTURE = new Texture(UNKONWN_TEXTURE /*SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE*/, false, false); + MIPMAP_BLOCK_ATLAS_TEXTURE = new Texture(ATLAS/*SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE*/, false, true); + BLOCK_ATLAS_TEXTURE = new Texture(ATLAS /*SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE*/, false, false); NO_TEXTURE = new Texture(); DEFAULT_TEXTURING = new Texturing("default_texturing", () -> { }, () -> { @@ -662,8 +662,7 @@ public Texture(ResourceLocation id, boolean bilinear, boolean mipmap) { GLStateManager.enableTexture(); TextureManager lv = Minecraft.getMinecraft().getTextureManager(); lv.bindTexture(id); - throw new RuntimeException("Not Implemented Yet"); -// lv.getTexture(id).setFilter(bilinear, mipmap); + GLStateManager.setFilter(bilinear, mipmap); }, () -> { }); this.id = Optional.of(id); @@ -707,13 +706,9 @@ public static class ShadeModel extends RenderPhase { private final boolean smooth; public ShadeModel(boolean smooth) { - super("shade_model", () -> { - throw new RuntimeException("Not Implemented Yet"); -// RenderSystem.shadeModel(smooth ? 7425 : 7424); - }, () -> { -// RenderSystem.shadeModel(7424); - throw new RuntimeException("Not Implemented Yet"); - }); + super("shade_model", + () -> GLStateManager.glShadeModel(smooth ? GL11.GL_SMOOTH : GL11.GL_FLAT), + () -> GLStateManager.glShadeModel(GL11.GL_FLAT)); this.smooth = smooth; } diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 7dc4f1f30..91b82b9b1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -50,6 +50,8 @@ public class GLStateManager { @Getter private static final AlphaState Alpha = new AlphaState(); + private static int modelShadeMode; + // TODO: Maybe inject the iris stuff via mixins.... @Getter private static final TextureState[] Textures; @@ -356,6 +358,27 @@ public static void disableDepthTest() { Depth.mode.disable(); } + public static void setFilter(boolean bilinear, boolean mipmap) { + int j; + int i; + if (bilinear) { + i = mipmap ? GL11.GL_LINEAR_MIPMAP_LINEAR : GL11.GL_LINEAR; + j = GL11.GL_LINEAR; + } else { + i = mipmap ? GL11.GL_NEAREST_MIPMAP_LINEAR : GL11.GL_NEAREST; + j = GL11.GL_NEAREST; + } + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, i); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, j); + } + + public static void glShadeModel(int mode) { + if (modelShadeMode != mode) { + modelShadeMode = mode; + GL11.glShadeModel(mode); + } + } + // Iris Functions private static void iris$onDeleteTexture(int id) { if (Iris.isInitialized()) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index f3c5e1a21..0934bb90e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -22,6 +22,7 @@ public enum Mixins { "sodium.MixinRenderGlobal" ,"sodium.MixinWorldClient" ,"sodium.MixinChunkProviderClient" + ,"sodium.MixinFrustrum" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java index 55d2963a3..7c150e6a6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java @@ -1,41 +1,78 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; +import it.unimi.dsi.fastutil.longs.LongIterator; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; import me.jellysquid.mods.sodium.client.world.ChunkStatusListenerManager; import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.world.chunk.Chunk; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +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.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(ChunkProviderClient.class) -public class MixinChunkProviderClient implements ChunkStatusListenerManager { - private ChunkStatusListener listener; - private final LongOpenHashSet loadedChunks = new LongOpenHashSet(); +public abstract class MixinChunkProviderClient implements ChunkStatusListenerManager { + private ChunkStatusListener sodium$listener; + private final LongOpenHashSet sodium$loadedChunks = new LongOpenHashSet(); + @Unique private boolean sodium$needsTrackingUpdate = false; + + @Shadow private Chunk blankChunk; + @Shadow public abstract Chunk provideChunk(int x, int z); @Override public void setListener(ChunkStatusListener listener) { - this.listener = listener; + this.sodium$listener = listener; } @Inject(method="loadChunk", at = @At(value = "INVOKE", target="Lcpw/mods/fml/common/eventhandler/EventBus;post(Lcpw/mods/fml/common/eventhandler/Event;)Z", shift = At.Shift.BEFORE)) private void sodium$loadChunk(int x, int z, CallbackInfoReturnable cir) { - if (this.listener != null) { - this.listener.onChunkAdded(x, z); - this.loadedChunks.add(ChunkPos.toLong(x, z)); + if (this.sodium$listener != null) { + this.sodium$listener.onChunkAdded(x, z); + this.sodium$loadedChunks.add(ChunkPos.toLong(x, z)); } } @Inject(method="unloadChunk", at=@At("TAIL")) private void sodium$unloadChunk(int x, int z, CallbackInfo ci) { - if (this.listener != null) { - this.listener.onChunkRemoved(x, z); - this.loadedChunks.remove(ChunkPos.toLong(x, z)); + if (this.sodium$listener != null) { + this.sodium$listener.onChunkRemoved(x, z); + this.sodium$loadedChunks.remove(ChunkPos.toLong(x, z)); } } + + @Inject(method="unloadQueuedChunks", at=@At("TAIL")) + private void afterTick(CallbackInfoReturnable cir) { + // TODO: sodium$needsTrackingUpdate - is it Relevant here? + // Gets set on Sodium by afterChunkMapCenterChanged & afterLoadDistanceChanged + if (!this.sodium$needsTrackingUpdate) { + return; + } + + LongIterator it = this.sodium$loadedChunks.iterator(); + + while (it.hasNext()) { + long pos = it.nextLong(); + + int x = ChunkPos.getPackedX(pos); + int z = ChunkPos.getPackedZ(pos); + + if (provideChunk(x, z) == blankChunk) { + it.remove(); + + if (this.sodium$listener != null) { + this.sodium$listener.onChunkRemoved(x, z); + } + } + } + + this.sodium$needsTrackingUpdate = false; + } + + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinFrustrum.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinFrustrum.java new file mode 100644 index 000000000..fc4bdf3c3 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinFrustrum.java @@ -0,0 +1,17 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; +import net.minecraft.client.renderer.culling.Frustrum; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(Frustrum.class) +public abstract class MixinFrustrum implements FrustumExtended { + @Shadow + public abstract boolean isBoxInFrustum(double p_78548_1_, double p_78548_3_, double p_78548_5_, double p_78548_7_, double p_78548_9_, double p_78548_11_); + + @Override + public boolean fastAabbTest(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + return isBoxInFrustum(minX, minY, minZ, maxX, maxY, maxZ); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index f193ca058..ef2ae45c7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -1,18 +1,32 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.culling.Frustrum; +import net.minecraft.client.renderer.culling.ICamera; +import net.minecraft.entity.EntityLivingBase; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; 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.CallbackInfo; +import java.util.List; + @Mixin(RenderGlobal.class) public class MixinRenderGlobal { + + @Shadow + public Minecraft mc; @Unique private SodiumWorldRenderer renderer; @Inject(method="", at=@At("RETURN")) @@ -28,6 +42,56 @@ public class MixinRenderGlobal { } finally { RenderDevice.exitManagedCode(); } + } + + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) { + RenderDevice.enterManagedCode(); + + final double x = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks; + final double y = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks; + final double z = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks; + + try { + MatrixStack matrixStack = new MatrixStack(); + final List renderLayers = switch(pass) { + case 0 -> ImmutableList.of(RenderLayer.solid(), RenderLayer.cutoutMipped(), RenderLayer.cutout()); + case 1 -> ImmutableList.of(RenderLayer.translucent()); + default -> throw new IllegalStateException("Unexpected value: " + pass); + }; + for (RenderLayer renderLayer : renderLayers) { + this.renderer.drawChunkLayer(renderLayer, matrixStack, x, y, z); + } + } finally { + RenderDevice.exitManagedCode(); + } + return 0; } + + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public void clipRenderersByFrustum(ICamera frustrum, float partialTicks) { + RenderDevice.enterManagedCode(); + + final Frustrum frustum = (Frustrum) frustrum; + boolean hasForcedFrustum = false; + int frame = 0; + boolean spectator = false; + Camera camera = new Camera(mc.renderViewEntity, partialTicks); + + try { + this.renderer.updateChunks(camera, frustum, hasForcedFrustum, frame, spectator); + } finally { + RenderDevice.exitManagedCode(); + } + } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index e554f0041..3bc0f9cb2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -33,7 +33,7 @@ public class GLStateManagerTransformer implements IClassTransformer { public static final Map> EnabledRedirects = ImmutableMap.of( GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", - "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor4f") + "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor4f", "glShadeModel") ,GL13, Sets.newHashSet("glActiveTexture") ,GL14, Sets.newHashSet("glBlendFuncSeparate") ,EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") diff --git a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java index 6cbe4798d..16690d66c 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java @@ -47,7 +47,7 @@ private void setupGlState(GameRenderer gameRenderer, Camera camera, MatrixStack private boolean canRender(Camera camera, GameRenderer gameRenderer) { return !(!gameRenderer.getRenderHand() - || camera.isDetached() + || camera.isThirdPerson() || !(camera.getEntity() instanceof EntityPlayer) || gameRenderer.getPanoramicMode() || Minecraft.getMinecraft().gameSettings.hideGUI From 435f9d54bf735c72c068a62a0c302c10c10afe07 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 9 Nov 2023 09:44:18 -0800 Subject: [PATCH 038/301] Client World Loads (doesn't properly render) * GLStateManager FogState & methods --- .../angelica/compat/mojang/RenderPhase.java | 44 ++++++----- .../angelica/glsm/GLStateManager.java | 74 ++++++++++++++++--- .../angelica/glsm/states/FogState.java | 6 ++ .../sodium/MixinChunkProviderClient.java | 2 +- .../transform/GLStateManagerTransformer.java | 2 +- .../IndirectCommandBufferVector.java | 4 +- 6 files changed, 99 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index d1986866d..5234dbb5f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.compat.mojang; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import me.jellysquid.mods.sodium.client.SodiumClientMod; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.util.ResourceLocation; @@ -212,35 +213,35 @@ private static void setupGlintTexturing(float scale) { }, () -> { }); FOG = new Fog("fog", () -> { - throw new RuntimeException("Not Implemented Yet"); -// BackgroundRenderer.setFogBlack(); -// RenderSystem.enableFog(); - }, () -> { - throw new RuntimeException("Not Implemented Yet"); -// RenderSystem.disableFog(); - }); + // Unclear what this should do + // BackgroundRenderer.setFogBlack(), also levelFogColor() + SodiumClientMod.LOGGER.debug("Fog - Not setting level fog color"); + GLStateManager.enableFog(); + }, GLStateManager::disableFog); BLACK_FOG = new Fog("black_fog", () -> { - throw new RuntimeException("Not Implemented Yet"); -// RenderSystem.fog(2918, 0.0F, 0.0F, 0.0F, 1.0F); -// RenderSystem.enableFog(); + GLStateManager.fogColor(0.0F, 0.0F, 0.0F, 1.0F); + GLStateManager.enableFog(); }, () -> { - throw new RuntimeException("Not Implemented Yet"); -// BackgroundRenderer.setFogBlack(); -// RenderSystem.disableFog(); + // Unclear what this should do + // BackgroundRenderer.setFogBlack(), also levelFogColor() + SodiumClientMod.LOGGER.debug("Fog - Not setting level fog color"); + GLStateManager.disableFog(); }); MAIN_TARGET = new Target("main_target", () -> { }, () -> { }); OUTLINE_TARGET = new Target("outline_target", () -> { - throw new RuntimeException("Not Implemented Yet"); -// MinecraftClient.getInstance().worldRenderer.getEntityOutlinesFramebuffer().beginWrite(false); + // TODO: Sodium + SodiumClientMod.LOGGER.debug("NOT enabling the entity outline framebuffer"); + //MinecraftClient.getInstance().worldRenderer.getEntityOutlinesFramebuffer().beginWrite(false); }, () -> { Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); }); TRANSLUCENT_TARGET = new Target("translucent_target", () -> { if (Minecraft.isFancyGraphicsEnabled()) { - throw new RuntimeException("Not Implemented Yet"); -// MinecraftClient.getInstance().worldRenderer.getTranslucentFramebuffer().beginWrite(false); + // TODO: Sodium + SodiumClientMod.LOGGER.debug("NOT enabling the translucent framebuffer"); + // MinecraftClient.getInstance().worldRenderer.getTranslucentFramebuffer().beginWrite(false); } }, () -> { @@ -518,13 +519,18 @@ public static class Lightmap extends Toggleable { public Lightmap(boolean lightmap) { super("lightmap", () -> { if (lightmap) { - throw new RuntimeException("Not Implemented Yet"); + // TODO: Sodium - LightmapTextureManager + SodiumClientMod.LOGGER.debug("Lightmap - enable (not implemented)"); +// throw new RuntimeException("Not Implemented Yet"); // MinecraftClient.getInstance().gameRenderer.getLightmapTextureManager().enable(); + } }, () -> { if (lightmap) { - throw new RuntimeException("Not Implemented Yet"); + // TODO: Sodium - LightmapTextureManager + SodiumClientMod.LOGGER.debug("Lightmap - disable (not implemented)"); +// throw new RuntimeException("Not Implemented Yet"); // MinecraftClient.getInstance().gameRenderer.getLightmapTextureManager().disable(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 91b82b9b1..2c5e46243 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -26,6 +26,7 @@ import org.lwjgl.opengl.GL14; import java.nio.ByteBuffer; +import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.stream.IntStream; @@ -330,6 +331,21 @@ public static void disableTexture() { Textures[activeTexture].mode.disable(); } + public static void setFilter(boolean bilinear, boolean mipmap) { + int j; + int i; + if (bilinear) { + i = mipmap ? GL11.GL_LINEAR_MIPMAP_LINEAR : GL11.GL_LINEAR; + j = GL11.GL_LINEAR; + } else { + i = mipmap ? GL11.GL_NEAREST_MIPMAP_LINEAR : GL11.GL_NEAREST; + j = GL11.GL_NEAREST; + } + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, i); + GL11.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() // Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram); @@ -358,18 +374,54 @@ public static void disableDepthTest() { Depth.mode.disable(); } - public static void setFilter(boolean bilinear, boolean mipmap) { - int j; - int i; - if (bilinear) { - i = mipmap ? GL11.GL_LINEAR_MIPMAP_LINEAR : GL11.GL_LINEAR; - j = GL11.GL_LINEAR; - } else { - i = mipmap ? GL11.GL_NEAREST_MIPMAP_LINEAR : GL11.GL_NEAREST; - j = GL11.GL_NEAREST; + public static void enableFog() { + Fog.mode.enable(); + } + + public static void disableFog() { + Fog.mode.disable(); + } + + public static void glFog(int pname, FloatBuffer param) { + // TODO: Iris Notifier + GL11.glFog(pname, param); + if(pname == GL11.GL_FOG_COLOR) { + Fog.fogColor.set(param.get(0), param.get(1), param.get(2)); + Fog.fogAlpha = param.get(3); + Fog.fogColorBuffer.clear(); + Fog.fogColorBuffer.put((FloatBuffer) param.position(0)).flip(); } - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, i); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, j); + } + public static void fogColor(float red, float green, float blue, float alpha) { + // TODO: Iris Notifier + if(red != Fog.fogColor.x || green != Fog.fogColor.y || blue != Fog.fogColor.z || alpha != Fog.fogAlpha) { + Fog.fogColor.set(red, green, blue); + Fog.fogAlpha = alpha; + Fog.fogColorBuffer.clear(); + Fog.fogColorBuffer.put(red).put(green).put(blue).put(alpha).flip(); + GL11.glFog(GL11.GL_FOG_COLOR, Fog.fogColorBuffer); + } + } + public static void glFogf(int pname, float param) { + // TODO: Iris Notifier + GL11.glFogf(pname, param); + switch(pname) { + case GL11.GL_FOG_DENSITY -> Fog.density = param; + case GL11.GL_FOG_START -> Fog.start = param; + case GL11.GL_FOG_END -> Fog.end = param; + } + } + public static void glFogi(int pname, int param) { + // TODO: Iris Notifier + GL11.glFogi(pname, param); + if(pname == GL11.GL_FOG_MODE) { + Fog.fogMode = param; + } + } + + public static void setFogBlack() { + GL11.glFogf(GL11.GL_FOG_COLOR, 0.0F); + } public static void glShadeModel(int mode) { diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java index cd2a24082..390099bc7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java @@ -1,10 +1,16 @@ package com.gtnewhorizons.angelica.glsm.states; +import org.joml.Vector3f; import org.lwjgl.opengl.GL11; +import java.nio.FloatBuffer; + public class FogState { public BooleanState mode = new BooleanState(GL11.GL_FOG); public int fogMode = GL11.GL_EXP; + public final Vector3f fogColor = new Vector3f(0.0F, 0.0F, 0.0F); + public float fogAlpha = 1.0F; + public final FloatBuffer fogColorBuffer = FloatBuffer.allocate(4); public float density = 1.0F; public float start; public float end = 1.0F; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java index 7c150e6a6..91955098e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java @@ -29,7 +29,7 @@ public void setListener(ChunkStatusListener listener) { this.sodium$listener = listener; } - @Inject(method="loadChunk", at = @At(value = "INVOKE", target="Lcpw/mods/fml/common/eventhandler/EventBus;post(Lcpw/mods/fml/common/eventhandler/Event;)Z", shift = At.Shift.BEFORE)) + @Inject(method="loadChunk", at = @At(value = "INVOKE", target="Lcpw/mods/fml/common/eventhandler/EventBus;post(Lcpw/mods/fml/common/eventhandler/Event;)Z", shift = At.Shift.BEFORE), remap = false) private void sodium$loadChunk(int x, int z, CallbackInfoReturnable cir) { if (this.sodium$listener != null) { this.sodium$listener.onChunkAdded(x, z); diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index 3bc0f9cb2..90537fb09 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -33,7 +33,7 @@ public class GLStateManagerTransformer implements IClassTransformer { public static final Map> EnabledRedirects = ImmutableMap.of( GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", - "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor4f", "glShadeModel") + "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor4f", "glShadeModel", "glFog", "glFogi", "glfFogf") ,GL13, Sets.newHashSet("glActiveTexture") ,GL14, Sets.newHashSet("glBlendFuncSeparate") ,EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java index 849a8d2a4..aa4751001 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java @@ -18,7 +18,9 @@ public void begin() { } public void end() { - this.buffer.flip(); + if(this.buffer.position() > 0) { + this.buffer.flip(); + } } public void pushCommandBuffer(ChunkDrawCallBatcher batcher) { From 8d590e1d6fdb6b9a5135a2e34d30899bb44d53b6 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 10 Nov 2023 08:24:13 -0800 Subject: [PATCH 039/301] Temporarily hijack the debug from Iris --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../early/sodium/startup/MixinInitDebug.java | 19 +++++++++++++++++++ src/main/java/net/coderbot/iris/Iris.java | 16 +++++++++------- 3 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/startup/MixinInitDebug.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 0934bb90e..01d9fecf9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -23,6 +23,7 @@ public enum Mixins { ,"sodium.MixinWorldClient" ,"sodium.MixinChunkProviderClient" ,"sodium.MixinFrustrum" + ,"sodium.startup.MixinInitDebug" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/startup/MixinInitDebug.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/startup/MixinInitDebug.java new file mode 100644 index 000000000..28cf0c229 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/startup/MixinInitDebug.java @@ -0,0 +1,19 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium.startup; + +import net.coderbot.iris.Iris; +import net.minecraft.client.renderer.OpenGlHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(OpenGlHelper.class) +public class MixinInitDebug { + @Inject(method = "initializeTextures", at = @At("RETURN")) + private static void sodium$initIrisDebug(CallbackInfo ci) { + // Temp -- move this into common debug code + Iris.identifyCapabilities(); + Iris.setDebug(true); + } + +} diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index b063c1d3b..b92fc908a 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -391,7 +391,8 @@ private static void setShadersDisabled() { logger.info("Shaders are disabled"); } - private static void setDebug(boolean enable) { + // Temp escalation + public static void setDebug(boolean enable) { int success; if (enable) { success = GLDebug.setupDebugMessageCallback(); @@ -407,12 +408,13 @@ private static void setDebug(boolean enable) { Minecraft.getMinecraft().thePlayer.sendChatMessage(I18n.format("iris.shaders.debug.restart")); } } - - try { - irisConfig.setDebugEnabled(enable); - irisConfig.save(); - } catch (IOException e) { - e.printStackTrace(); + if(Iris.isInitialized()) { + try { + irisConfig.setDebugEnabled(enable); + irisConfig.save(); + } catch (IOException e) { + e.printStackTrace(); + } } } From cf6486912cfa929cda956b8e8c8e8e3dc046a3af Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 11 Nov 2023 16:24:58 -0800 Subject: [PATCH 040/301] Progress * Starting migrating away from Sodium's usage of BlockState * Angelica mixin to grab Camera position, as well as projection & model view matricies in RenderingState.INSTANCE * Mixins to start running scheduleRebuildForBlockArea * Switch GLShader Identifier to ResourceLocation * Use RenderState's projection matrix for GameRendererContext * undo some javadoc refactor silly --- .../compat/forge/ModelDataManager.java | 2 +- .../angelica/compat/mojang/Camera.java | 5 +- .../angelica/compat/mojang/IdListPalette.java | 9 -- .../angelica/compat/mojang/Palette.java | 6 -- .../compat/mojang/PalettedContainer.java | 5 -- .../angelica/compat/mojang/RenderLayer.java | 14 ++- .../gtnewhorizons/angelica/mixins/Mixins.java | 6 +- .../early/angelica/MixinEntityRenderer.java | 28 ++++++ .../early/shaders/MixinEntityRenderer.java | 1 + .../early/sodium/MixinRenderGlobal.java | 31 +++++++ .../angelica/rendering/RenderingState.java | 40 +++++++++ .../sodium/client/gl/shader/GlShader.java | 8 +- .../sodium/client/gl/shader/ShaderLoader.java | 14 +-- .../client/model/quad/ModelQuadView.java | 2 +- .../model/quad/ModelQuadViewMutable.java | 2 +- .../client/model/vertex/VertexSink.java | 2 +- .../vertex/formats/quad/QuadVertexSink.java | 4 +- .../client/render/GameRendererContext.java | 14 +-- .../shader/ChunkRenderShaderBackend.java | 5 +- .../chunk/tasks/ChunkRenderRebuildTask.java | 3 +- .../sodium/client/util/ModelQuadUtil.java | 2 +- .../mods/sodium/client/util/Norm3b.java | 2 +- .../mods/sodium/client/world/WorldSlice.java | 15 ++-- .../world/cloned/ClonedChunkSection.java | 86 +++++++++---------- .../cloned/PackedIntegerArrayExtended.java | 7 -- .../cloned/PalettedContainerExtended.java | 20 ----- .../world/cloned/palette/ClonedPalette.java | 5 -- .../cloned/palette/ClonedPaletteFallback.java | 16 ---- .../cloned/palette/ClonedPalleteArray.java | 22 ----- .../iris/uniforms/CapturedRenderingState.java | 12 +-- .../occlusion/OcclusionRenderer.java | 4 +- 31 files changed, 201 insertions(+), 191 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdListPalette.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/Palette.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/PalettedContainer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinEntityRenderer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PackedIntegerArrayExtended.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalette.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalleteArray.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java index dcc066988..3b2313bea 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java @@ -20,7 +20,7 @@ public class ModelDataManager { public static Map getModelData(World world, ChunkPos pos) { - Preconditions.checkArgument(!world.isRemote, "Cannot request model data for server world"); + Preconditions.checkArgument(world.isRemote, "Cannot request model data for server world"); // refreshModelData(world, pos); return modelDataCache.getOrDefault(pos, Collections.emptyMap()); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java index c35478e26..497168006 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java @@ -7,8 +7,8 @@ @Getter public class Camera { - Vector3d pos = new Vector3d(); - BlockPos.Mutable blockPos = new BlockPos.Mutable(); + final Vector3d pos = new Vector3d(); + final BlockPos.Mutable blockPos = new BlockPos.Mutable(); float pitch; float yaw; EntityLivingBase entity; @@ -18,6 +18,7 @@ public Camera(EntityLivingBase entity, float partialTicks) { final double camX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks; final double camY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks; final double camZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks; + this.entity = entity; pos.set(camX, camY, camZ); blockPos.set((int)entity.posX, (int)entity.posY, (int)entity.posZ); pitch = entity.cameraPitch; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdListPalette.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdListPalette.java deleted file mode 100644 index 3429d07c6..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdListPalette.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -public class IdListPalette implements Palette { - - @Override - public T getByIndex(int i) { - return null; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Palette.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Palette.java deleted file mode 100644 index b6be6bf25..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Palette.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -public interface Palette { - - T getByIndex(int i); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PalettedContainer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PalettedContainer.java deleted file mode 100644 index 151215c31..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PalettedContainer.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -public class PalettedContainer { - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java index ffc5d8d2b..aadac15ff 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java @@ -7,7 +7,6 @@ import net.minecraft.util.ResourceLocation; import javax.annotation.Nullable; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -30,9 +29,11 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris // private static final RenderLayer ENTITY_GLINT = of("entity_glint", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).target(ITEM_TARGET).texturing(ENTITY_GLINT_TEXTURING).build(false)); // private static final RenderLayer DIRECT_ENTITY_GLINT = of("entity_glint_direct", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(ENTITY_GLINT_TEXTURING).build(false)); private static final RenderLayer LIGHTNING = of("lightning", DefaultVertexFormat.POSITION_COLOR, 7, 256, false, true, RenderLayer.MultiPhaseParameters.builder().writeMaskState(ALL_MASK).transparency(LIGHTNING_TRANSPARENCY).target(WEATHER_TARGET).shadeModel(SMOOTH_SHADE_MODEL).build(false)); -// private static final RenderLayer TRIPWIRE = of("tripwire", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 262144, true, true, getTripwirePhaseData()); + private static final RenderLayer TRIPWIRE = of("tripwire", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 262144, true, true, getTripwirePhaseData()); private static final RenderLayer LINES = of("lines", DefaultVertexFormat.POSITION_COLOR, 1, 256, RenderLayer.MultiPhaseParameters.builder().lineWidth(new RenderPhase.LineWidth(OptionalDouble.empty())).layering(VIEW_OFFSET_Z_LAYERING).transparency(TRANSLUCENT_TRANSPARENCY).target(ITEM_TARGET).writeMaskState(ALL_MASK).build(false)); + private static List BLOCK_LAYERS = ImmutableList.of(RenderLayer.solid(), RenderLayer.cutoutMipped(), RenderLayer.cutout(), RenderLayer.translucent(), RenderLayer.tripwire()); + @Getter private final VertexFormat vertexFormat; @Getter @@ -42,6 +43,11 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris private final boolean hasCrumbling; private final boolean translucent; private final Optional optionalThis; + + private static MultiPhaseParameters getTripwirePhaseData() { + return MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).transparency(TRANSLUCENT_TRANSPARENCY).target(WEATHER_TARGET).build(true); + } + public RenderLayer(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, Runnable startAction, Runnable endAction) { super(name, startAction, endAction); this.vertexFormat = vertexFormat; @@ -186,11 +192,11 @@ public static RenderLayer getOutline(ResourceLocation texture, RenderPhase.Cull public static RenderLayer tripwire() { - return null; + return TRIPWIRE; } public static List getBlockLayers() { - return Collections.emptyList(); + return BLOCK_LAYERS; } public int mode() { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 01d9fecf9..068b11689 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -9,7 +9,11 @@ import java.util.function.Supplier; public enum Mixins { - + ANGELICA(new Builder("Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).addMixinClasses( + "angelica.MixinEntityRenderer" + ) + ), IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> false).addMixinClasses( "shaders.startup.MixinGameSettings", diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinEntityRenderer.java new file mode 100644 index 000000000..39b918ef7 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinEntityRenderer.java @@ -0,0 +1,28 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica; + +import com.gtnewhorizons.angelica.rendering.RenderingState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.entity.EntityLivingBase; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityRenderer.class) +public abstract class MixinEntityRenderer { + @Inject(method = "setupCameraTransform", at = @At(value = "TAIL")) + private void angelica$captureCameraMatrix(float partialTicks, int startTime, CallbackInfo ci) { + final Minecraft mc = Minecraft.getMinecraft(); + final EntityLivingBase viewEntity = mc.renderViewEntity; + + RenderingState.INSTANCE.setCameraPosition( + viewEntity.lastTickPosX + (viewEntity.posX - viewEntity.lastTickPosX) * partialTicks, + viewEntity.lastTickPosY + (viewEntity.posY - viewEntity.lastTickPosY) * partialTicks, + viewEntity.lastTickPosZ + (viewEntity.posZ - viewEntity.lastTickPosZ) * partialTicks + ); + RenderingState.INSTANCE.captureProjectionMatrix(); + RenderingState.INSTANCE.captureModelViewMatrix(); + + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index 22bd9d07e..bfbfded28 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -64,6 +64,7 @@ private void sglFogi(int pname, int param) { @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/EntityRenderer;setupCameraTransform(FI)V", value = "INVOKE"), method = "renderWorld(FJ)V") private void iris$setCamera(float tickDelta, long startTime, CallbackInfo ci) { + // TODO: Grab from Angelica CapturedRenderingState.INSTANCE.setCamera(tickDelta); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index ef2ae45c7..f6d424502 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -50,6 +50,7 @@ public class MixinRenderGlobal { */ @Overwrite public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) { + // Roughly equivalent to `renderLayer` RenderDevice.enterManagedCode(); final double x = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks; @@ -79,6 +80,7 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) */ @Overwrite public void clipRenderersByFrustum(ICamera frustrum, float partialTicks) { + // Roughly equivalent to setupTerrain RenderDevice.enterManagedCode(); final Frustrum frustum = (Frustrum) frustrum; @@ -94,4 +96,33 @@ public void clipRenderersByFrustum(ICamera frustrum, float partialTicks) { } } + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public void markBlockForUpdate(int x, int y, int z) { + this.renderer.scheduleRebuildForBlockArea(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1, false); + } + + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public void markBlockForRenderUpdate(int x, int y, int z) { + // scheduleBlockRenders + this.renderer.scheduleRebuildForBlockArea(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1, false); + } + + + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public void markBlockRangeForRenderUpdate(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + // scheduleBlockRenders + this.renderer.scheduleRebuildForBlockArea(minX, minY, minZ, maxX, maxY, maxZ, false); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java b/src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java new file mode 100644 index 000000000..8f0ebaab2 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java @@ -0,0 +1,40 @@ +package com.gtnewhorizons.angelica.rendering; + +import lombok.Getter; +import org.joml.Matrix4f; +import org.joml.Vector3d; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; + +import java.nio.FloatBuffer; + +public class RenderingState { + public static final RenderingState INSTANCE = new RenderingState(); + @Getter + private final Vector3d cameraPosition = new Vector3d(); + @Getter + private final FloatBuffer projectionBuffer = BufferUtils.createFloatBuffer(16); + @Getter + private final FloatBuffer modelViewBuffer = BufferUtils.createFloatBuffer(16); + @Getter + private final Matrix4f projectionMatrix = new Matrix4f().identity(); + @Getter + private final Matrix4f modelViewMatrix = new Matrix4f().identity(); + + + public void setCameraPosition(double x, double y, double z) { + cameraPosition.set(x, y, z); + } + + public void captureProjectionMatrix() { + projectionBuffer.position(0); + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projectionBuffer); + projectionMatrix.set(projectionBuffer); + } + + public void captureModelViewMatrix() { + modelViewBuffer.position(0); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelViewBuffer); + modelViewMatrix.set(modelViewBuffer); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java index 36537d6ef..97a2ecc52 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlShader.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.gl.shader; -import io.github.douira.glsl_transformer.ast.node.Identifier; import me.jellysquid.mods.sodium.client.gl.GlObject; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import net.minecraft.util.ResourceLocation; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL11; @@ -18,9 +18,9 @@ public class GlShader extends GlObject { private static final Logger LOGGER = LogManager.getLogger(GlShader.class); - private final Identifier name; + private final ResourceLocation name; - public GlShader(RenderDevice owner, ShaderType type, Identifier name, String src, ShaderConstants constants) { + public GlShader(RenderDevice owner, ShaderType type, ResourceLocation name, String src, ShaderConstants constants) { super(owner); this.name = name; @@ -80,7 +80,7 @@ private static String processShader(String src, ShaderConstants constants) { return builder.toString(); } - public Identifier getName() { + public ResourceLocation getName() { return this.name; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java index 0486dc4b0..c637d5b81 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.gl.shader; -import io.github.douira.glsl_transformer.ast.node.Identifier; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import net.minecraft.util.ResourceLocation; import org.apache.commons.io.IOUtils; import java.io.IOException; @@ -18,24 +18,24 @@ public class ShaderLoader { * * @param device * @param type The type of shader to create - * @param name The identifier used to locate the shader source file + * @param name The ResourceLocation used to locate the shader source file * @param constants A list of constants for shader specialization * @return An OpenGL shader object compiled with the given user defines */ - public static GlShader loadShader(RenderDevice device, ShaderType type, Identifier name, ShaderConstants constants) { + public static GlShader loadShader(RenderDevice device, ShaderType type, ResourceLocation name, ShaderConstants constants) { return new GlShader(device, type, name, getShaderSource(getShaderPath(name, type)), constants); } /** - * Use {@link ShaderLoader#loadShader(RenderDevice, ShaderType, Identifier, ShaderConstants)} instead. This will be removed. + * Use {@link ShaderLoader#loadShader(RenderDevice, ShaderType, ResourceLocation, ShaderConstants)} instead. This will be removed. */ @Deprecated - public static GlShader loadShader(RenderDevice device, ShaderType type, Identifier name, List constants) { + public static GlShader loadShader(RenderDevice device, ShaderType type, ResourceLocation name, List constants) { return new GlShader(device, type, name, getShaderSource(getShaderPath(name, type)), ShaderConstants.fromStringList(constants)); } - private static String getShaderPath(Identifier name, ShaderType type) { - return String.format("/assets/sodium/shaders/%s.%s.glsl", name.getName(), type == ShaderType.VERTEX ? "v" : "f"); + private static String getShaderPath(ResourceLocation name, ShaderType type) { + return String.format("/assets/%s/shaders/%s.%s.glsl", name.getResourceDomain(), name.getResourcePath(), type == ShaderType.VERTEX ? "v" : "f"); } private static String getShaderSource(String path) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java index 8a2bc18cd..684339dd1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadView.java @@ -50,7 +50,7 @@ public interface ModelQuadView { int getLight(int idx); /** - * @return The integer-encoded getNormal vector for the vertex at index {@param idx} + * @return The integer-encoded normal vector for the vertex at index {@param idx} */ int getNormal(int idx); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java index df3efdb3d..42e2db755 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/ModelQuadViewMutable.java @@ -43,7 +43,7 @@ public interface ModelQuadViewMutable extends ModelQuadView { void setLight(int idx, int light); /** - * Sets the integer-encoded getNormal vector of the vertex at index {@param idx} to the value {@param light} + * Sets the integer-encoded normal vector of the vertex at index {@param idx} to the value {@param light} */ void setNormal(int idx, int norm); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java index b30e0c99f..4d932b365 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexSink.java @@ -26,7 +26,7 @@ public interface VertexSink { * Flushes any written vertex data to the {@link VertexDrain} this sink is connected to, ensuring it is actually * written to the backing storage. This should be called after vertex data has been written to this sink. * - * It is valid to flush a sink at any time. Only vertices that have been written since the peek flush will be + * It is valid to flush a sink at any time. Only vertices that have been written since the last flush will be * flushed when calling this method. If no vertices need to be flushed, this method does nothing. * * For optimal performance, callers should wait until they have written out as much vertex data as possible before diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java index 72c9e8a64..cea8c2d02 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java @@ -22,14 +22,14 @@ public interface QuadVertexSink extends VertexSink { * @param v The y-texture of the vertex * @param light The packed light-map coordinates of the vertex * @param overlay The packed overlay-map coordinates of the vertex - * @param normal The 3-byte packed getNormal vector of the vertex + * @param normal The 3-byte packed normal vector of the vertex */ void writeQuad(float x, float y, float z, int color, float u, float v, int light, int overlay, int normal); /** * Writes a quad vertex to the sink, transformed by the given matrices. * - * @param matrices The matrices to transform the vertex's position and getNormal vectors by + * @param matrices The matrices to transform the vertex's position and normal vectors by */ default void writeQuad(MatrixStack.Entry matrices, float x, float y, float z, int color, float u, float v, int light, int overlay, int normal) { Matrix4fExtended modelMatrix = MatrixUtil.getExtendedMatrix(matrices.getModel()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java index 6905d72eb..7bb288f67 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java @@ -1,20 +1,13 @@ package me.jellysquid.mods.sodium.client.render; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.rendering.RenderingState; import org.joml.Matrix4f; import org.lwjgl.BufferUtils; import java.nio.FloatBuffer; public class GameRendererContext { - private static Matrix4f PROJECTION_MATRIX = new Matrix4f().identity(); - - // TODO: Sodium - projection matrix - // Sodium uses a mixin in `loadProjectionMatrix` to capture the matrix, unclear if this is available in 1.7.10 - public static void captureProjectionMatrix(Matrix4f matrix) { - PROJECTION_MATRIX.set(matrix); - } - /** * TODO: Not accurate * Obtains a model-view-projection matrix by multiplying the projection matrix with the model-view matrix @@ -26,9 +19,8 @@ public static void captureProjectionMatrix(Matrix4f matrix) { * uploading as uniform state */ public static FloatBuffer getModelViewProjectionMatrix(MatrixStack.Entry matrices) { - FloatBuffer bufModelViewProjection = BufferUtils.createFloatBuffer(16); - // TODO: Sodium - projection matrix - Matrix4f matrix = new Matrix4f(PROJECTION_MATRIX); + final FloatBuffer bufModelViewProjection = BufferUtils.createFloatBuffer(16); + final Matrix4f matrix = new Matrix4f(RenderingState.INSTANCE.getProjectionMatrix()); matrix.mul(matrices.getModel()); matrix.get(bufModelViewProjection); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java index 2b3b294f5..4cabb257c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java @@ -13,6 +13,7 @@ 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.format.ChunkMeshAttribute; +import net.minecraft.util.ResourceLocation; import java.util.EnumMap; @@ -30,9 +31,9 @@ public ChunkRenderShaderBackend(ChunkVertexType vertexType) { } private ChunkProgram createShader(RenderDevice device, ChunkFogMode fogMode, GlVertexFormat vertexFormat) { - GlShader vertShader = ShaderLoader.loadShader(device, ShaderType.VERTEX, new Identifier("chunk_gl20"), fogMode.getDefines()); + GlShader vertShader = ShaderLoader.loadShader(device, ShaderType.VERTEX, new ResourceLocation("sodium", "chunk_gl20"), fogMode.getDefines()); - GlShader fragShader = ShaderLoader.loadShader(device, ShaderType.FRAGMENT, new Identifier("chunk_gl20"), fogMode.getDefines()); + GlShader fragShader = ShaderLoader.loadShader(device, ShaderType.FRAGMENT, new ResourceLocation("sodium", "chunk_gl20"), fogMode.getDefines()); try { return GlProgram.builder(new Identifier("chunk_shader")) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 3a0b760b2..4ad943efc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -99,7 +99,8 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB for (int relX = 0; relX < 16; relX++) { BlockState blockState = slice.getBlockStateRelative(relX + 16, relY + 16, relZ + 16); - if (blockState.isAir()) { + // TODO: Sodium - BlockState + if (blockState == null || blockState.isAir()) { continue; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java index c845a451c..460ae3469 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java @@ -40,7 +40,7 @@ public class ModelQuadUtil { } /** - * Returns the getNormal vector for a model quad with the given {@param facing}. + * Returns the normal vector for a model quad with the given {@param facing}. */ public static int getFacingNormal(ForgeDirection facing) { return NORMALS[facing.ordinal()]; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java b/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java index a2a014f9b..0e2ffbf28 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/Norm3b.java @@ -5,7 +5,7 @@ import org.joml.Vector3i; /** - * Provides some utilities for working with packed getNormal vectors. Each getNormal component provides 8 bits of + * Provides some utilities for working with packed normal vectors. Each getNormal component provides 8 bits of * precision in the range of [-1.0,1.0]. * * | 32 | 24 | 16 | 8 | diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index e340f42e7..07d646850 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -17,8 +17,6 @@ import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSection; import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSectionCache; -import me.jellysquid.mods.sodium.client.world.cloned.PackedIntegerArrayExtended; -import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; import net.minecraft.client.Minecraft; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; @@ -194,7 +192,7 @@ private void unpackBlockData(BlockState[] states, ClonedChunkSection section, St private void unpackBlockDataR(BlockState[] states, ClonedChunkSection section, StructureBoundingBox box) { PackedIntegerArray intArray = section.getBlockData(); - ClonedPalette palette = section.getBlockPalette(); +// ClonedPalette palette = section.getBlockPalette(); ChunkSectionPos pos = section.getPosition(); @@ -211,17 +209,18 @@ private void unpackBlockDataR(BlockState[] states, ClonedChunkSection section, S for (int z = minBlockZ; z <= maxBlockZ; z++) { for (int x = minBlockX; x <= maxBlockX; x++) { int blockIdx = getLocalBlockIndex(x & 15, y & 15, z & 15); - int value = intArray.get(blockIdx); - - states[blockIdx] = palette.get(value); + // TODO: Sodium - BlockState +// int value = intArray.get(blockIdx); +// states[blockIdx] = palette.get(value); } } } } private void unpackBlockDataZ(BlockState[] states, ClonedChunkSection section) { - ((PackedIntegerArrayExtended) section.getBlockData()) - .copyUsingPalette(states, section.getBlockPalette()); + // TODO: Sodium - BlockStates +// ((PackedIntegerArrayExtended) section.getBlockData()) +// .copyUsingPalette(states, section.getBlockPalette()); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 5268abe30..633355ed5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -3,16 +3,10 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; -import com.gtnewhorizons.angelica.compat.mojang.IdListPalette; import com.gtnewhorizons.angelica.compat.mojang.LightType; import com.gtnewhorizons.angelica.compat.mojang.PackedIntegerArray; -import com.gtnewhorizons.angelica.compat.mojang.Palette; -import com.gtnewhorizons.angelica.compat.mojang.PalettedContainer; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; -import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; -import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPaletteFallback; -import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalleteArray; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.ChunkPosition; import net.minecraft.world.World; @@ -37,9 +31,10 @@ public class ClonedChunkSection { private final World world; private ChunkSectionPos pos; - - private PackedIntegerArray blockStateData; - private ClonedPalette blockStatePalette; + // TODO: Sodium - BlockState - Replace with 1.7.10 equivalents from ExtendedBlockStorage + // Likely some combination of blockMetadataArray, blocklightArray, and skylightArray +// private PackedIntegerArray blockStateData; +// private ClonedPalette blockStatePalette; private byte[] biomeData; @@ -66,11 +61,10 @@ public void init(ChunkSectionPos pos) { } this.pos = pos; +// PalettedContainerExtended container = PalettedContainerExtended.cast(new PalettedContainer<>()/*section.getContainer()*/); - PalettedContainerExtended container = PalettedContainerExtended.cast(new PalettedContainer<>()/*section.getContainer()*/);; - - this.blockStateData = copyBlockData(container); - this.blockStatePalette = copyPalette(container); +// this.blockStateData = copyBlockData(container); +// this.blockStatePalette = copyPalette(container); for (LightType type : LIGHT_TYPES) { // TODO: Sodium - Lighting @@ -97,7 +91,8 @@ public void init(ChunkSectionPos pos) { } public BlockState getBlockState(int x, int y, int z) { - return this.blockStatePalette.get(this.blockStateData.get(y << 8 | z << 4 | x)); + return null; +// return this.blockStatePalette.get(this.blockStateData.get(y << 8 | z << 4 | x)); } public int getLightLevel(LightType type, int x, int y, int z) { @@ -121,44 +116,45 @@ public TileEntity getBlockEntity(int x, int y, int z) { } public PackedIntegerArray getBlockData() { - return this.blockStateData; + return null; +// return this.blockStateData; } - public ClonedPalette getBlockPalette() { - return this.blockStatePalette; - } +// public ClonedPalette getBlockPalette() { +// return this.blockStatePalette; +// } public ChunkSectionPos getPosition() { return this.pos; } - private static ClonedPalette copyPalette(PalettedContainerExtended container) { - Palette palette = container.getPalette(); - - if (palette instanceof IdListPalette) { - // TODO: Sodium - return new ClonedPaletteFallback<>(null/*Block.STATE_IDS*/); - } - - BlockState[] array = new BlockState[1 << container.getPaletteSize()]; - - for (int i = 0; i < array.length; i++) { - array[i] = palette.getByIndex(i); - - if (array[i] == null) { - break; - } - } - - return new ClonedPalleteArray<>(array, container.getDefaultValue()); - } - - private static PackedIntegerArray copyBlockData(PalettedContainerExtended container) { - PackedIntegerArray array = container.getDataArray(); - long[] storage = array.getStorage(); - - return new PackedIntegerArray(container.getPaletteSize(), array.getSize(), storage.clone()); - } +// private static ClonedPalette copyPalette(PalettedContainerExtended container) { +// Palette palette = container.getPalette(); +// +// if (palette instanceof IdListPalette) { +// // TODO: Sodium +// return new ClonedPaletteFallback<>(null/*Block.STATE_IDS*/); +// } +// +// BlockState[] array = new BlockState[1 << container.getPaletteSize()]; +// +// for (int i = 0; i < array.length; i++) { +// array[i] = palette.getByIndex(i); +// +// if (array[i] == null) { +// break; +// } +// } +// +// return new ClonedPalleteArray<>(array, container.getDefaultValue()); +// } + +// private static PackedIntegerArray copyBlockData(PalettedContainerExtended container) { +// PackedIntegerArray array = container.getDataArray(); +// long[] storage = array.getStorage(); +// +// return new PackedIntegerArray(container.getPaletteSize(), array.getSize(), storage.clone()); +// } public static boolean isOutOfBuildLimitVertically(int y) { return y < 0 || y >= 256; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PackedIntegerArrayExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PackedIntegerArrayExtended.java deleted file mode 100644 index a7a5bc2ce..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PackedIntegerArrayExtended.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.world.cloned; - -import me.jellysquid.mods.sodium.client.world.cloned.palette.ClonedPalette; - -public interface PackedIntegerArrayExtended { - void copyUsingPalette(T[] out, ClonedPalette palette); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java deleted file mode 100644 index 817a356a4..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/PalettedContainerExtended.java +++ /dev/null @@ -1,20 +0,0 @@ -package me.jellysquid.mods.sodium.client.world.cloned; - -import com.gtnewhorizons.angelica.compat.mojang.PackedIntegerArray; -import com.gtnewhorizons.angelica.compat.mojang.Palette; -import com.gtnewhorizons.angelica.compat.mojang.PalettedContainer; - -public interface PalettedContainerExtended { - @SuppressWarnings("unchecked") - static PalettedContainerExtended cast(PalettedContainer container) { - return (PalettedContainerExtended) container; - } - - PackedIntegerArray getDataArray(); - - Palette getPalette(); - - T getDefaultValue(); - - int getPaletteSize(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalette.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalette.java deleted file mode 100644 index 8944da988..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalette.java +++ /dev/null @@ -1,5 +0,0 @@ -package me.jellysquid.mods.sodium.client.world.cloned.palette; - -public interface ClonedPalette { - K get(int id); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java deleted file mode 100644 index 0926269e0..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPaletteFallback.java +++ /dev/null @@ -1,16 +0,0 @@ -package me.jellysquid.mods.sodium.client.world.cloned.palette; - -import com.gtnewhorizons.angelica.compat.mojang.IdList; - -public class ClonedPaletteFallback implements ClonedPalette { - private final IdList idList; - - public ClonedPaletteFallback(IdList idList) { - this.idList = idList; - } - - @Override - public K get(int id) { - return this.idList.get(id); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalleteArray.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalleteArray.java deleted file mode 100644 index af0cbfc3e..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/palette/ClonedPalleteArray.java +++ /dev/null @@ -1,22 +0,0 @@ -package me.jellysquid.mods.sodium.client.world.cloned.palette; - -public class ClonedPalleteArray implements ClonedPalette { - private final K[] array; - private final K defaultValue; - - public ClonedPalleteArray(K[] array, K defaultValue) { - this.array = array; - this.defaultValue = defaultValue; - } - - @Override - public K get(int id) { - K value = this.array[id]; - - if (value == null) { - return this.defaultValue; - } - - return value; - } -} diff --git a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java index 4ed8bffc8..033fd6a63 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java +++ b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java @@ -18,18 +18,18 @@ public class CapturedRenderingState { private static final Vector3d ZERO_VECTOR_3d = new Vector3d(); private final FloatBuffer modelViewBuffer = BufferUtils.createFloatBuffer(16); - private Matrix4f gbufferModelView; + private final Matrix4f gbufferModelView = new Matrix4f(); private final FloatBuffer shadowModelViewBuffer = BufferUtils.createFloatBuffer(16); private Matrix4f shadowModelView; private final FloatBuffer projectionBuffer = BufferUtils.createFloatBuffer(16); - private Matrix4f gbufferProjection; + private final Matrix4f gbufferProjection = new Matrix4f(); private final FloatBuffer shadowProjectionBuffer = BufferUtils.createFloatBuffer(16); private Matrix4f shadowProjection; private Vector3d fogColor; private Vector4d clearColor; @Getter - private Vector3d cameraPosition = new Vector3d(); + private final Vector3d cameraPosition = new Vector3d(); private float tickDelta; private int currentRenderedBlockEntity; @@ -112,13 +112,13 @@ public void setCamera(float tickDelta) { final double x = viewEntity.lastTickPosX + (viewEntity.posX - viewEntity.lastTickPosX) * tickDelta; final double y = viewEntity.lastTickPosY + (viewEntity.posY - viewEntity.lastTickPosY) * tickDelta; final double z = viewEntity.lastTickPosZ + (viewEntity.posZ - viewEntity.lastTickPosZ) * tickDelta; - cameraPosition = new Vector3d(x, y, z); + cameraPosition.set(x, y, z); GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, (FloatBuffer) projectionBuffer.position(0)); - gbufferProjection = new Matrix4f((FloatBuffer)projectionBuffer.position(0)); + gbufferProjection.set((FloatBuffer)projectionBuffer.position(0)); GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, (FloatBuffer) modelViewBuffer.position(0)); - gbufferModelView = new Matrix4f((FloatBuffer)modelViewBuffer.position(0)); + gbufferModelView.set((FloatBuffer)modelViewBuffer.position(0)); } public void setCameraShadow(float tickDelta) { diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java index 7093f7c83..b53ec2b2f 100644 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java +++ b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java @@ -536,13 +536,13 @@ public int sortAndRender(int start, int end, int pass, double tick) { return glListsRendered; } - public void clipRenderersByFrustum(ICamera p_72729_1_, float p_72729_2_) { + public void clipRenderersByFrustum(ICamera cam, float p_72729_2_) { for (int i = 0; i < rg.worldRenderers.length; ++i) { if((i + rg.frustumCheckOffset & 15) == 0) { WorldRenderer wr = rg.worldRenderers[i]; IWorldRenderer iwr = (IWorldRenderer) wr; if (wr.isInFrustum && iwr.arch$getCullInfo().isFrustumCheckPending) { - wr.updateInFrustum(p_72729_1_); + wr.updateInFrustum(cam); iwr.arch$getCullInfo().isFrustumCheckPending = false; if (!wr.isInFrustum) { OcclusionHelpers.worker.dirtyFrustumRenderers++; From d68c0644a9a46ff8df66330cfc966a7b15fca0ad Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 11 Nov 2023 16:43:08 -0800 Subject: [PATCH 041/301] TE Rendering - TileEntityRendererDispatcher --- .../render/chunk/tasks/ChunkRenderRebuildTask.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 4ad943efc..6245e5b2a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -28,6 +28,7 @@ import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.tileentity.TileEntity; import org.joml.Vector3d; @@ -147,13 +148,8 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB if (blockState.hasTileEntity()) { TileEntity entity = slice.getBlockEntity(pos); - if (entity != null) { - // TODO: Sodium TileEntity Rendering -// BlockEntityRenderer renderer = BlockEntityRenderDispatcher.INSTANCE.get(entity); -// -// if (renderer != null) { -// bounds.addBlock(relX, relY, relZ); -// } + if (entity != null && (TileEntityRendererDispatcher.instance.hasSpecialRenderer(entity))) { + bounds.addBlock(relX, relY, relZ); } } From d5461eea796916794340c55f4593087ca3608b95 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 11 Nov 2023 17:12:33 -0800 Subject: [PATCH 042/301] Add back renderData.addBlockEntity() --- .../client/render/chunk/tasks/ChunkRenderRebuildTask.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 6245e5b2a..fcda9b17f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -29,6 +29,7 @@ import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.tileentity.TileEntity; import org.joml.Vector3d; @@ -148,7 +149,12 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB if (blockState.hasTileEntity()) { TileEntity entity = slice.getBlockEntity(pos); - if (entity != null && (TileEntityRendererDispatcher.instance.hasSpecialRenderer(entity))) { + final TileEntitySpecialRenderer renderer = TileEntityRendererDispatcher.instance.getSpecialRenderer(entity); + if (entity != null && renderer != null) { + // TODO: Sodium - Per-chunk tile entities + // !rendersOutsideBoundingBox(entity) in sodium + // entity.getRenderBoundingBox() != TileEntity.INFINITE_EXTENT_AABB rough equivalent in 1.7.10 + renderData.addBlockEntity(entity, false); bounds.addBlock(relX, relY, relZ); } } From e11519f06f758b204dc045a1a3e655bd9f2dfbbd Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 12 Nov 2023 10:30:27 -0800 Subject: [PATCH 043/301] ClonedChunkSection work * Clone the relevant ExtendedBlockStorage bits * Fix multiDrawArraysIndirect --- .../gtnewhorizons/angelica/mixins/Mixins.java | 11 ++- .../sodium/MixinExtendedBlockStorage.java | 18 ++++ .../mixins/early/sodium/MixinNibbleArray.java | 28 ++++++ .../interfaces/ExtendedBlockStorageExt.java | 12 +++ .../interfaces/ExtendedNibbleArray.java | 7 ++ .../client/gl/device/DrawCommandList.java | 3 +- .../client/gl/device/GLRenderDevice.java | 4 +- .../gl/func/GlIndirectMultiDrawFunctions.java | 14 ++- .../MultidrawChunkRenderBackend.java | 5 +- .../backends/multidraw/StructBuffer.java | 6 +- .../world/cloned/ClonedChunkSection.java | 96 ++++++++++--------- 11 files changed, 139 insertions(+), 65 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNibbleArray.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ExtendedBlockStorageExt.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ExtendedNibbleArray.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 068b11689..7e1c8462b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -11,7 +11,7 @@ public enum Mixins { ANGELICA(new Builder("Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( - "angelica.MixinEntityRenderer" + "angelica.MixinEntityRenderer" ) ), IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) @@ -22,12 +22,19 @@ public enum Mixins { ), SODIUM_STARTUP(new Builder("Start Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).addMixinClasses( + "sodium.startup.MixinInitDebug" + ) + ), + + SODIUM(new Builder("Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( "sodium.MixinRenderGlobal" ,"sodium.MixinWorldClient" ,"sodium.MixinChunkProviderClient" ,"sodium.MixinFrustrum" - ,"sodium.startup.MixinInitDebug" + ,"sodium.MixinExtendedBlockStorage" + ,"sodium.MixinNibbleArray" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java new file mode 100644 index 000000000..e3f5a337b --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java @@ -0,0 +1,18 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedBlockStorageExt; +import lombok.Getter; +import net.minecraft.world.chunk.NibbleArray; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Getter +@Mixin(ExtendedBlockStorage.class) +public abstract class MixinExtendedBlockStorage implements ExtendedBlockStorageExt { + @Shadow private byte[] blockLSBArray; + @Shadow private NibbleArray blockMSBArray; + @Shadow private NibbleArray blockMetadataArray; + @Shadow private NibbleArray blocklightArray; + @Shadow private NibbleArray skylightArray; +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNibbleArray.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNibbleArray.java new file mode 100644 index 000000000..dcc980a46 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNibbleArray.java @@ -0,0 +1,28 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedNibbleArray; +import net.minecraft.world.chunk.NibbleArray; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(NibbleArray.class) +public abstract class MixinNibbleArray implements ExtendedNibbleArray { + @Shadow public byte[] data; + @Shadow private int depthBits; + @Shadow private int depthBitsPlusFour; + + @Override + public byte[] getData() { + return data; + } + + @Override + public int getDepthBits() { + return depthBits; + } + + @Override + public int getDepthBitsPlusFour() { + return depthBitsPlusFour; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ExtendedBlockStorageExt.java new file mode 100644 index 000000000..5cbce6ac8 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ExtendedBlockStorageExt.java @@ -0,0 +1,12 @@ +package com.gtnewhorizons.angelica.mixins.interfaces; + +import net.minecraft.world.chunk.NibbleArray; + +public interface ExtendedBlockStorageExt { + byte[] getBlockLSBArray(); + NibbleArray getBlockMSBArray(); + NibbleArray getBlockMetadataArray(); + NibbleArray getBlocklightArray(); + NibbleArray getSkylightArray(); + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ExtendedNibbleArray.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ExtendedNibbleArray.java new file mode 100644 index 000000000..591b43633 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ExtendedNibbleArray.java @@ -0,0 +1,7 @@ +package com.gtnewhorizons.angelica.mixins.interfaces; + +public interface ExtendedNibbleArray { + public byte[] getData(); + public int getDepthBits(); + public int getDepthBitsPlusFour(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java index b6a186a30..cc6b2e7bc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/DrawCommandList.java @@ -1,12 +1,11 @@ package me.jellysquid.mods.sodium.client.gl.device; -import java.nio.ByteBuffer; import java.nio.IntBuffer; public interface DrawCommandList extends AutoCloseable { void multiDrawArrays(IntBuffer first, IntBuffer count); - void multiDrawArraysIndirect(ByteBuffer buffer, int count, int stride); + void multiDrawArraysIndirect(long pointer, int count, int stride); void endTessellating(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java index 092a750ff..d7158596c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/device/GLRenderDevice.java @@ -198,9 +198,9 @@ public void multiDrawArrays(IntBuffer first, IntBuffer count) { } @Override - public void multiDrawArraysIndirect(ByteBuffer buffer, int count, int stride) { + public void multiDrawArraysIndirect(long pointer, int count, int stride) { GlPrimitiveType primitiveType = GLRenderDevice.this.activeTessellation.getPrimitiveType(); - GlFunctions.INDIRECT_DRAW.glMultiDrawArraysIndirect(primitiveType.getId(), buffer, count, stride); + GlFunctions.INDIRECT_DRAW.glMultiDrawArraysIndirect(primitiveType.getId(), pointer, count, stride); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java index 7c3157a8e..d706c3d15 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/func/GlIndirectMultiDrawFunctions.java @@ -4,24 +4,22 @@ import org.lwjgl.opengl.ContextCapabilities; import org.lwjgl.opengl.GL43; -import java.nio.ByteBuffer; - public enum GlIndirectMultiDrawFunctions { CORE { @Override - public void glMultiDrawArraysIndirect(int mode, ByteBuffer buffer, int primcount, int stride) { - GL43.glMultiDrawArraysIndirect(mode, buffer, primcount, stride); + public void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride) { + GL43.glMultiDrawArraysIndirect(mode, indirect, primcount, stride); } }, ARB { @Override - public void glMultiDrawArraysIndirect(int mode, ByteBuffer buffer, int primcount, int stride) { - ARBMultiDrawIndirect.glMultiDrawArraysIndirect(mode, buffer, primcount, stride); + public void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride) { + ARBMultiDrawIndirect.glMultiDrawArraysIndirect(mode, indirect, primcount, stride); } }, UNSUPPORTED { @Override - public void glMultiDrawArraysIndirect(int mode, ByteBuffer buffer, int primcount, int stride) { + public void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride) { throw new UnsupportedOperationException(); } }; @@ -36,5 +34,5 @@ public static GlIndirectMultiDrawFunctions load(ContextCapabilities capabilities } } - public abstract void glMultiDrawArraysIndirect(int mode, ByteBuffer buffer, int primcount, int stride); + public abstract void glMultiDrawArraysIndirect(int mode, long indirect, int primcount, int stride); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java index 5cfdf2c35..5490c4e8f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java @@ -38,7 +38,6 @@ import net.minecraft.util.Util; import org.lwjgl.opengl.GL11; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; @@ -220,14 +219,14 @@ public void render(CommandList commandList, ChunkRenderListIterator region : this.pendingBatches) { ChunkDrawCallBatcher batch = region.getDrawBatcher(); if (!batch.isEmpty()) { try (DrawCommandList drawCommandList = commandList.beginTessellating(region.getTessellation())) { - drawCommandList.multiDrawArraysIndirect(buffer, batch.getCount(), 0 /* tightly packed */); + drawCommandList.multiDrawArraysIndirect(pointer, batch.getCount(), 0 /* tightly packed */); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java index 69f75a732..691d832d3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/StructBuffer.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; import org.lwjgl.BufferUtils; - +import org.lwjgl.MemoryUtil; import java.nio.ByteBuffer; @@ -19,6 +19,10 @@ public ByteBuffer getBuffer() { return this.buffer; } + public long getBufferAddress() { + return MemoryUtil.getAddress(this.buffer); + } + public void delete() { this.buffer.clear(); this.buffer = null; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 633355ed5..60777b2a1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -1,10 +1,11 @@ package me.jellysquid.mods.sodium.client.world.cloned; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import com.gtnewhorizons.angelica.compat.mojang.LightType; import com.gtnewhorizons.angelica.compat.mojang.PackedIntegerArray; +import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedBlockStorageExt; +import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedNibbleArray; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import net.minecraft.tileentity.TileEntity; @@ -25,16 +26,23 @@ public class ClonedChunkSection { private final AtomicInteger referenceCount = new AtomicInteger(0); private final ClonedChunkSectionCache backingCache; - - private final Short2ObjectMap blockEntities; + private boolean hasSky = false; + private final Short2ObjectMap tileEntities; private final NibbleArray[] lightDataArrays; + /** Contains the least significant 8 bits of each block ID belonging to this block storage's parent Chunk. */ + private byte[] blockLSBArray; + /** Contains the most significant 4 bits of each block ID belonging to this block storage's parent Chunk. */ + private NibbleArray blockMSBArray; + /** Stores the metadata associated with blocks in this ExtendedBlockStorage. */ + private NibbleArray blockMetadataArray; + /** The NibbleArray containing a block of Block-light data. */ + private NibbleArray blocklightArray; + /** The NibbleArray containing a block of Sky-light data. */ + private NibbleArray skylightArray; + private final World world; private ChunkSectionPos pos; - // TODO: Sodium - BlockState - Replace with 1.7.10 equivalents from ExtendedBlockStorage - // Likely some combination of blockMetadataArray, blocklightArray, and skylightArray -// private PackedIntegerArray blockStateData; -// private ClonedPalette blockStatePalette; private byte[] biomeData; @@ -43,8 +51,15 @@ public class ClonedChunkSection { ClonedChunkSection(ClonedChunkSectionCache backingCache, World world) { this.backingCache = backingCache; this.world = world; - this.blockEntities = new Short2ObjectOpenHashMap<>(); + this.tileEntities = new Short2ObjectOpenHashMap<>(); this.lightDataArrays = new NibbleArray[LIGHT_TYPES.length]; + this.blockLSBArray = new byte[4096]; + this.blockMetadataArray = new NibbleArray(this.blockLSBArray.length, 4); + this.blocklightArray = new NibbleArray(this.blockLSBArray.length, 4); + this.hasSky = !world.provider.hasNoSky; + if (hasSky) { + this.skylightArray = new NibbleArray(this.blockLSBArray.length, 4); + } } public void init(ChunkSectionPos pos) { @@ -54,17 +69,28 @@ public void init(ChunkSectionPos pos) { throw new RuntimeException("Couldn't retrieve chunk at " + pos.toChunkPos()); } - ExtendedBlockStorage section = getChunkSection(chunk, pos); + ExtendedBlockStorageExt section = (ExtendedBlockStorageExt)getChunkSection(chunk, pos); if (section == null /*WorldChunk.EMPTY_SECTION*/ /*ChunkSection.isEmpty(section)*/) { - section = EMPTY_SECTION; + section = (ExtendedBlockStorageExt)EMPTY_SECTION; } this.pos = pos; -// PalettedContainerExtended container = PalettedContainerExtended.cast(new PalettedContainer<>()/*section.getContainer()*/); -// this.blockStateData = copyBlockData(container); -// this.blockStatePalette = copyPalette(container); + System.arraycopy(section.getBlockLSBArray(), 0, this.blockLSBArray, 0, this.blockLSBArray.length); + if(section.getBlockMSBArray() != null) { + this.blockMSBArray = new NibbleArray(this.blockLSBArray.length, 4); + copyNibbleArray((ExtendedNibbleArray) section.getBlockMSBArray(), (ExtendedNibbleArray) this.blockMSBArray); + } + copyNibbleArray((ExtendedNibbleArray) section.getBlockMetadataArray(), (ExtendedNibbleArray)this.blockMetadataArray); + copyNibbleArray((ExtendedNibbleArray) section.getBlocklightArray(), (ExtendedNibbleArray)this.blocklightArray); + if(section.getSkylightArray() != null) { + if(this.skylightArray == null) { + hasSky = true; + this.skylightArray = new NibbleArray(this.blockLSBArray.length, 4); + } + copyNibbleArray((ExtendedNibbleArray) section.getSkylightArray(), (ExtendedNibbleArray) this.skylightArray); + } for (LightType type : LIGHT_TYPES) { // TODO: Sodium - Lighting @@ -77,7 +103,7 @@ public void init(ChunkSectionPos pos) { StructureBoundingBox box = new StructureBoundingBox(pos.getMinX(), pos.getMinY(), pos.getMinZ(), pos.getMaxX(), pos.getMaxY(), pos.getMaxZ()); - this.blockEntities.clear(); + this.tileEntities.clear(); for (Map.Entry entry : chunk.chunkTileEntityMap.entrySet()) { BlockPos entityPos = new BlockPos(entry.getKey()); @@ -85,16 +111,20 @@ public void init(ChunkSectionPos pos) { // if (box.contains(entityPos)) { if(box.isVecInside(entityPos.getX(), entityPos.getY(), entityPos.getZ())) { //this.blockEntities.put(BlockPos.asLong(entityPos.getX() & 15, entityPos.getY() & 15, entityPos.getZ() & 15), entry.getValue()); - this.blockEntities.put(ChunkSectionPos.packLocal(entityPos), entry.getValue()); + this.tileEntities.put(ChunkSectionPos.packLocal(entityPos), entry.getValue()); } } } - public BlockState getBlockState(int x, int y, int z) { - return null; -// return this.blockStatePalette.get(this.blockStateData.get(y << 8 | z << 4 | x)); + private static void copyNibbleArray(ExtendedNibbleArray srcArray, ExtendedNibbleArray dstArray) { + if(srcArray == null || dstArray == null) { + throw new RuntimeException("NibbleArray is null src: " + (srcArray==null) + " dst: " + (dstArray==null)); + } + final byte[] data = srcArray.getData(); + System.arraycopy(data, 0, dstArray.getData(), 0, data.length); } + public int getLightLevel(LightType type, int x, int y, int z) { NibbleArray array = this.lightDataArrays[type.ordinal()]; @@ -112,7 +142,7 @@ public BiomeGenBase getBiomeForNoiseGen(int x, int y, int z) { } public TileEntity getBlockEntity(int x, int y, int z) { - return this.blockEntities.get(packLocal(x, y, z)); + return this.tileEntities.get(packLocal(x, y, z)); } public PackedIntegerArray getBlockData() { @@ -128,34 +158,6 @@ public ChunkSectionPos getPosition() { return this.pos; } -// private static ClonedPalette copyPalette(PalettedContainerExtended container) { -// Palette palette = container.getPalette(); -// -// if (palette instanceof IdListPalette) { -// // TODO: Sodium -// return new ClonedPaletteFallback<>(null/*Block.STATE_IDS*/); -// } -// -// BlockState[] array = new BlockState[1 << container.getPaletteSize()]; -// -// for (int i = 0; i < array.length; i++) { -// array[i] = palette.getByIndex(i); -// -// if (array[i] == null) { -// break; -// } -// } -// -// return new ClonedPalleteArray<>(array, container.getDefaultValue()); -// } - -// private static PackedIntegerArray copyBlockData(PalettedContainerExtended container) { -// PackedIntegerArray array = container.getDataArray(); -// long[] storage = array.getStorage(); -// -// return new PackedIntegerArray(container.getPaletteSize(), array.getSize(), storage.clone()); -// } - public static boolean isOutOfBuildLimitVertically(int y) { return y < 0 || y >= 256; } From 96e4c681fd6856923f1b250ddec668e610d8c83a Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 12 Nov 2023 14:13:35 -0800 Subject: [PATCH 044/301] Improvements to ClonedChunkSection * Use ExtendedBlockStorageExt instead of copying the internals --- .../compat/ExtendedBlockStorageExt.java | 42 +++++++++++++ .../sodium/MixinExtendedBlockStorage.java | 21 ++++--- .../early/sodium/MixinRenderGlobal.java | 16 ++++- ...Ext.java => IExtendedBlockStorageExt.java} | 7 ++- .../render/chunk/shader/ChunkProgram.java | 7 ++- .../mods/sodium/client/world/WorldSlice.java | 7 +-- .../world/cloned/ClonedChunkSection.java | 60 ++----------------- .../world/cloned/ClonedChunkSectionCache.java | 3 +- 8 files changed, 87 insertions(+), 76 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java rename src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/{ExtendedBlockStorageExt.java => IExtendedBlockStorageExt.java} (66%) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java new file mode 100644 index 000000000..524adaaec --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java @@ -0,0 +1,42 @@ +package com.gtnewhorizons.angelica.compat; + +import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedNibbleArray; +import com.gtnewhorizons.angelica.mixins.interfaces.IExtendedBlockStorageExt; +import net.minecraft.world.chunk.NibbleArray; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; + +public class ExtendedBlockStorageExt extends ExtendedBlockStorage { + + public ExtendedBlockStorageExt(int yBase, boolean hasSky) { + super(yBase, hasSky); + } + + public ExtendedBlockStorageExt(IExtendedBlockStorageExt storage) { + super(storage.getYBase(), storage.hasSky()); + + final byte[] blockLSBArray = storage.getBlockLSBArray(); + + System.arraycopy(storage.getBlockLSBArray(), 0, blockLSBArray, 0, blockLSBArray.length); + if(storage.getBlockMSBArray() != null) { + this.setBlockMSBArray(new NibbleArray(blockLSBArray.length, 4)); + copyNibbleArray((ExtendedNibbleArray) storage.getBlockMSBArray(), (ExtendedNibbleArray) this.getBlockMSBArray()); + } + copyNibbleArray((ExtendedNibbleArray) storage.getMetadataArray(), (ExtendedNibbleArray)this.getMetadataArray()); + copyNibbleArray((ExtendedNibbleArray) storage.getBlocklightArray(), (ExtendedNibbleArray)this.getBlocklightArray()); + if(storage.getSkylightArray() != null) { + if(this.getSkylightArray() == null) { + this.setSkylightArray(new NibbleArray(blockLSBArray.length, 4)); + } + copyNibbleArray((ExtendedNibbleArray) storage.getSkylightArray(), (ExtendedNibbleArray) this.getSkylightArray()); + } + } + + + private static void copyNibbleArray(ExtendedNibbleArray srcArray, ExtendedNibbleArray dstArray) { + if(srcArray == null || dstArray == null) { + throw new RuntimeException("NibbleArray is null src: " + (srcArray==null) + " dst: " + (dstArray==null)); + } + final byte[] data = srcArray.getData(); + System.arraycopy(data, 0, dstArray.getData(), 0, data.length); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java index e3f5a337b..86d9335d5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java @@ -1,18 +1,23 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; -import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedBlockStorageExt; +import com.gtnewhorizons.angelica.mixins.interfaces.IExtendedBlockStorageExt; import lombok.Getter; import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -@Getter @Mixin(ExtendedBlockStorage.class) -public abstract class MixinExtendedBlockStorage implements ExtendedBlockStorageExt { - @Shadow private byte[] blockLSBArray; - @Shadow private NibbleArray blockMSBArray; - @Shadow private NibbleArray blockMetadataArray; - @Shadow private NibbleArray blocklightArray; - @Shadow private NibbleArray skylightArray; +public abstract class MixinExtendedBlockStorage implements IExtendedBlockStorageExt { + @Shadow public abstract NibbleArray getSkylightArray(); + @Shadow public abstract NibbleArray getBlocklightArray(); + @Shadow public abstract NibbleArray getMetadataArray(); + @Shadow public abstract byte[] getBlockLSBArray(); + + @Getter @Shadow private int yBase; + + @Override + public boolean hasSky() { + return getSkylightArray() != null; + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index f6d424502..e57c41760 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -29,6 +29,8 @@ public class MixinRenderGlobal { public Minecraft mc; @Unique private SodiumWorldRenderer renderer; + private int sodium$frame; + @Inject(method="", at=@At("RETURN")) private void sodium$initRenderer(Minecraft mc, CallbackInfo ci) { this.renderer = SodiumWorldRenderer.create(mc); @@ -85,12 +87,11 @@ public void clipRenderersByFrustum(ICamera frustrum, float partialTicks) { final Frustrum frustum = (Frustrum) frustrum; boolean hasForcedFrustum = false; - int frame = 0; boolean spectator = false; Camera camera = new Camera(mc.renderViewEntity, partialTicks); try { - this.renderer.updateChunks(camera, frustum, hasForcedFrustum, frame, spectator); + this.renderer.updateChunks(camera, frustum, hasForcedFrustum, sodium$frame++, spectator); } finally { RenderDevice.exitManagedCode(); } @@ -125,4 +126,15 @@ public void markBlockRangeForRenderUpdate(int minX, int minY, int minZ, int maxX // scheduleBlockRenders this.renderer.scheduleRebuildForBlockArea(minX, minY, minZ, maxX, maxY, maxZ, false); } + + @Inject(method = "loadRenderers", at = @At("RETURN")) + private void onReload(CallbackInfo ci) { + RenderDevice.enterManagedCode(); + + try { + this.renderer.reload(); + } finally { + RenderDevice.exitManagedCode(); + } + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IExtendedBlockStorageExt.java similarity index 66% rename from src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ExtendedBlockStorageExt.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IExtendedBlockStorageExt.java index 5cbce6ac8..8edd195d0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ExtendedBlockStorageExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IExtendedBlockStorageExt.java @@ -2,11 +2,14 @@ import net.minecraft.world.chunk.NibbleArray; -public interface ExtendedBlockStorageExt { +public interface IExtendedBlockStorageExt { byte[] getBlockLSBArray(); NibbleArray getBlockMSBArray(); - NibbleArray getBlockMetadataArray(); + NibbleArray getMetadataArray(); NibbleArray getBlocklightArray(); NibbleArray getSkylightArray(); + int getYBase(); + + boolean hasSky(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java index cf4d886df..99062857d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java @@ -5,6 +5,9 @@ import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; import me.jellysquid.mods.sodium.client.render.GameRendererContext; +import net.minecraft.client.renderer.OpenGlHelper; + +import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; import java.util.function.Function; @@ -37,8 +40,8 @@ protected ChunkProgram(RenderDevice owner, Identifier name, int handle, Function } public void setup(MatrixStack matrixStack, float modelScale, float textureScale) { - GL20.glUniform1i(this.uBlockTex, 0); - GL20.glUniform1i(this.uLightTex, 2); + GL20.glUniform1i(this.uBlockTex, OpenGlHelper.defaultTexUnit - GL13.GL_TEXTURE0); + GL20.glUniform1i(this.uLightTex, OpenGlHelper.lightmapTexUnit - GL13.GL_TEXTURE0); GL20.glUniform3f(this.uModelScale, modelScale, modelScale, modelScale); GL20.glUniform2f(this.uTextureScale, textureScale, textureScale); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 07d646850..050dc02c0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -10,7 +10,6 @@ import com.gtnewhorizons.angelica.compat.mojang.FluidState; import com.gtnewhorizons.angelica.compat.mojang.LightType; import com.gtnewhorizons.angelica.compat.mojang.LightingProvider; -import com.gtnewhorizons.angelica.compat.mojang.PackedIntegerArray; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import me.jellysquid.mods.sodium.client.world.biome.BiomeCache; import me.jellysquid.mods.sodium.client.world.biome.BiomeColorCache; @@ -191,9 +190,6 @@ private void unpackBlockData(BlockState[] states, ClonedChunkSection section, St } private void unpackBlockDataR(BlockState[] states, ClonedChunkSection section, StructureBoundingBox box) { - PackedIntegerArray intArray = section.getBlockData(); -// ClonedPalette palette = section.getBlockPalette(); - ChunkSectionPos pos = section.getPosition(); int minBlockX = Math.max(box.minX, pos.getMinX()); @@ -249,8 +245,7 @@ public BlockState getBlockState(int x, int y, int z) { } public BlockState getBlockStateRelative(int x, int y, int z) { - return nullableState(this.blockStatesArrays[getLocalSectionIndex(x >> 4, y >> 4, z >> 4)] - [getLocalBlockIndex(x & 15, y & 15, z & 15)]); + return nullableState(this.blockStatesArrays[getLocalSectionIndex(x >> 4, y >> 4, z >> 4)][getLocalBlockIndex(x & 15, y & 15, z & 15)]); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 60777b2a1..fa1c7234e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -1,11 +1,10 @@ package me.jellysquid.mods.sodium.client.world.cloned; +import com.gtnewhorizons.angelica.compat.ExtendedBlockStorageExt; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import com.gtnewhorizons.angelica.compat.mojang.LightType; -import com.gtnewhorizons.angelica.compat.mojang.PackedIntegerArray; -import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedBlockStorageExt; -import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedNibbleArray; +import com.gtnewhorizons.angelica.mixins.interfaces.IExtendedBlockStorageExt; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import net.minecraft.tileentity.TileEntity; @@ -29,17 +28,8 @@ public class ClonedChunkSection { private boolean hasSky = false; private final Short2ObjectMap tileEntities; private final NibbleArray[] lightDataArrays; - /** Contains the least significant 8 bits of each block ID belonging to this block storage's parent Chunk. */ - private byte[] blockLSBArray; - /** Contains the most significant 4 bits of each block ID belonging to this block storage's parent Chunk. */ - private NibbleArray blockMSBArray; - /** Stores the metadata associated with blocks in this ExtendedBlockStorage. */ - private NibbleArray blockMetadataArray; - /** The NibbleArray containing a block of Block-light data. */ - private NibbleArray blocklightArray; - /** The NibbleArray containing a block of Sky-light data. */ - private NibbleArray skylightArray; + private ExtendedBlockStorageExt data; private final World world; private ChunkSectionPos pos; @@ -53,13 +43,6 @@ public class ClonedChunkSection { this.world = world; this.tileEntities = new Short2ObjectOpenHashMap<>(); this.lightDataArrays = new NibbleArray[LIGHT_TYPES.length]; - this.blockLSBArray = new byte[4096]; - this.blockMetadataArray = new NibbleArray(this.blockLSBArray.length, 4); - this.blocklightArray = new NibbleArray(this.blockLSBArray.length, 4); - this.hasSky = !world.provider.hasNoSky; - if (hasSky) { - this.skylightArray = new NibbleArray(this.blockLSBArray.length, 4); - } } public void init(ChunkSectionPos pos) { @@ -69,28 +52,15 @@ public void init(ChunkSectionPos pos) { throw new RuntimeException("Couldn't retrieve chunk at " + pos.toChunkPos()); } - ExtendedBlockStorageExt section = (ExtendedBlockStorageExt)getChunkSection(chunk, pos); + IExtendedBlockStorageExt section = (IExtendedBlockStorageExt)getChunkSection(chunk, pos); if (section == null /*WorldChunk.EMPTY_SECTION*/ /*ChunkSection.isEmpty(section)*/) { - section = (ExtendedBlockStorageExt)EMPTY_SECTION; + section = (IExtendedBlockStorageExt)EMPTY_SECTION; } this.pos = pos; + this.data = new ExtendedBlockStorageExt(section); - System.arraycopy(section.getBlockLSBArray(), 0, this.blockLSBArray, 0, this.blockLSBArray.length); - if(section.getBlockMSBArray() != null) { - this.blockMSBArray = new NibbleArray(this.blockLSBArray.length, 4); - copyNibbleArray((ExtendedNibbleArray) section.getBlockMSBArray(), (ExtendedNibbleArray) this.blockMSBArray); - } - copyNibbleArray((ExtendedNibbleArray) section.getBlockMetadataArray(), (ExtendedNibbleArray)this.blockMetadataArray); - copyNibbleArray((ExtendedNibbleArray) section.getBlocklightArray(), (ExtendedNibbleArray)this.blocklightArray); - if(section.getSkylightArray() != null) { - if(this.skylightArray == null) { - hasSky = true; - this.skylightArray = new NibbleArray(this.blockLSBArray.length, 4); - } - copyNibbleArray((ExtendedNibbleArray) section.getSkylightArray(), (ExtendedNibbleArray) this.skylightArray); - } for (LightType type : LIGHT_TYPES) { // TODO: Sodium - Lighting @@ -116,15 +86,6 @@ public void init(ChunkSectionPos pos) { } } - private static void copyNibbleArray(ExtendedNibbleArray srcArray, ExtendedNibbleArray dstArray) { - if(srcArray == null || dstArray == null) { - throw new RuntimeException("NibbleArray is null src: " + (srcArray==null) + " dst: " + (dstArray==null)); - } - final byte[] data = srcArray.getData(); - System.arraycopy(data, 0, dstArray.getData(), 0, data.length); - } - - public int getLightLevel(LightType type, int x, int y, int z) { NibbleArray array = this.lightDataArrays[type.ordinal()]; @@ -145,15 +106,6 @@ public TileEntity getBlockEntity(int x, int y, int z) { return this.tileEntities.get(packLocal(x, y, z)); } - public PackedIntegerArray getBlockData() { - return null; -// return this.blockStateData; - } - -// public ClonedPalette getBlockPalette() { -// return this.blockStatePalette; -// } - public ChunkSectionPos getPosition() { return this.pos; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java index 08424bfb2..3d2866520 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java @@ -22,8 +22,7 @@ public ClonedChunkSectionCache(World world) { public synchronized void cleanup() { this.time = getMonotonicTimeSource(); - this.byPosition.values() - .removeIf(entry -> this.time > (entry.getLastUsedTimestamp() + MAX_CACHE_DURATION)); + this.byPosition.values().removeIf(entry -> this.time > (entry.getLastUsedTimestamp() + MAX_CACHE_DURATION)); } public synchronized ClonedChunkSection acquire(int x, int y, int z) { From fcb9ca3835bff0426a31d2ef091bff276d9c101b Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 12 Nov 2023 19:30:10 -0800 Subject: [PATCH 045/301] misc blockstate --- .../angelica/compat/mojang/BlockState.java | 17 ++++++++-- .../angelica/compat/mojang/RenderPhase.java | 5 +-- .../chunk/tasks/ChunkRenderRebuildTask.java | 34 ++++++------------- .../mods/sodium/client/world/WorldSlice.java | 31 +++++------------ .../world/cloned/ClonedChunkSection.java | 21 ++++++++---- 5 files changed, 51 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java index 84cca3e8c..eb19bbec2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java @@ -1,11 +1,22 @@ package com.gtnewhorizons.angelica.compat.mojang; import com.gtnewhorizons.angelica.compat.forge.IForgeBlockState; +import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraftforge.common.util.ForgeDirection; import org.joml.Vector3d; public class BlockState implements IForgeBlockState { + private final Block block; + private final int meta; + + public BlockState(Block block, int meta) { + this.block = block; + this.meta = meta; + } + public Block getBlock() { + return block; + } public boolean isSideInvisible(BlockState adjState, ForgeDirection facing) { return false; @@ -44,7 +55,7 @@ public Vector3d getModelOffset(BlockRenderView world, BlockPos pos) { } public boolean isAir() { - return false; + return(block != null && block.isAir( null, 0, 0, 0)); } public BlockRenderType getRenderType() { @@ -52,7 +63,7 @@ public BlockRenderType getRenderType() { } public boolean hasTileEntity() { - return true; + return block.hasTileEntity(meta); } public long getRenderingSeed(BlockPos.Mutable pos) { @@ -68,7 +79,7 @@ public boolean shouldDisplayFluidOverlay(BlockRenderView world, BlockPos adjPos, } public Material getMaterial() { - return null; + return block.getMaterial(); } public boolean isSideSolid(BlockRenderView world, BlockPos pos, ForgeDirection dir, SideShapeType sideShapeType) { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index 5234dbb5f..4881cf51c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -4,6 +4,7 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL11; @@ -143,7 +144,7 @@ private static void setupGlintTexturing(float scale) { // RenderSystem.matrixMode(5888); } - private static ResourceLocation ATLAS = new ResourceLocation("sodium", "textures/atlas.png"); + private static ResourceLocation ATLAS = TextureMap.locationBlocksTexture; static { // TODO: Sodium - SpriteAtlasTexture MIPMAP_BLOCK_ATLAS_TEXTURE = new Texture(ATLAS/*SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE*/, false, true); @@ -668,7 +669,7 @@ public Texture(ResourceLocation id, boolean bilinear, boolean mipmap) { GLStateManager.enableTexture(); TextureManager lv = Minecraft.getMinecraft().getTextureManager(); lv.bindTexture(id); - GLStateManager.setFilter(bilinear, mipmap); + GLStateManager.setFilter(bilinear, mipmap); // breaks textures. TODO find out why }, () -> { }); this.id = Optional.of(id); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index fcda9b17f..c09752a8b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -1,16 +1,10 @@ package me.jellysquid.mods.sodium.client.render.chunk.tasks; -import com.gtnewhorizons.angelica.compat.forge.EmptyModelData; import com.gtnewhorizons.angelica.compat.forge.ForgeHooksClientExt; -import com.gtnewhorizons.angelica.compat.forge.IModelData; -import com.gtnewhorizons.angelica.compat.forge.ModelDataManager; -import com.gtnewhorizons.angelica.compat.mojang.BakedModel; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderType; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionDataBuilder; -import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; -import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import com.gtnewhorizons.angelica.compat.mojang.FluidState; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.compat.mojang.RenderLayers; @@ -27,14 +21,11 @@ import me.jellysquid.mods.sodium.client.util.task.CancellationSource; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.tileentity.TileEntity; import org.joml.Vector3d; -import java.util.Map; - /** * Rebuilds all the meshes of a chunk for each given render pass with non-occluded blocks. The result is then uploaded * to graphics memory on the main thread. @@ -49,8 +40,6 @@ public class ChunkRenderRebuildTask extends ChunkR private final ChunkRenderContext context; - private final Map modelDataMap; - private Vector3d camera; private final boolean translucencySorting; @@ -62,9 +51,6 @@ public ChunkRenderRebuildTask(ChunkRenderContainer render, ChunkRenderContext this.camera = new Vector3d(); this.translucencySorting = SodiumClientMod.options().advanced.translucencySorting; - this.modelDataMap = ModelDataManager.getModelData( - Minecraft.getMinecraft().theWorld, - new ChunkPos(ChunkSectionPos.getSectionCoord(this.render.getOriginX()), ChunkSectionPos.getSectionCoord(this.render.getOriginZ()))); } public ChunkRenderRebuildTask withCameraPosition(Vector3d camera) { @@ -117,15 +103,17 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB } ForgeHooksClientExt.setRenderLayer(layer); - IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); - - BakedModel model = cache.getBlockModels().getModel(blockState); - - long seed = blockState.getRenderingSeed(pos); - - if (cache.getBlockRenderer().renderModel(cache.getLocalSlice(), blockState, pos, model, buffers.get(layer), true, seed, modelData)) { - bounds.addBlock(relX, relY, relZ); - } + // TODO: RenderBlocks & capture tesselator state into quads + +// IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); +// +// BakedModel model = cache.getBlockModels().getModel(blockState); +// +// long seed = blockState.getRenderingSeed(pos); +// +// if (cache.getBlockRenderer().renderModel(cache.getLocalSlice(), blockState, pos, model, buffers.get(layer), true, seed, modelData)) { +// bounds.addBlock(relX, relY, relZ); +// } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 050dc02c0..eeda5ff69 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -63,9 +63,6 @@ public class WorldSlice implements BlockRenderView, BiomeAccess.Storage { // The array size for the section lookup table. private static final int SECTION_TABLE_ARRAY_SIZE = TABLE_LENGTH * TABLE_LENGTH * TABLE_LENGTH; - // Fallback BlockState to use if none were available in the array - private static final BlockState NULL_BLOCK_STATE = null; //Blocks.air.getDefaultState(); - // The world this slice has copied data from private final World world; @@ -127,8 +124,7 @@ public static ChunkRenderContext prepare(World world, ChunkSectionPos origin, Cl for (int chunkX = minChunkX; chunkX <= maxChunkX; chunkX++) { for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; chunkZ++) { for (int chunkY = minChunkY; chunkY <= maxChunkY; chunkY++) { - sections[getLocalSectionIndex(chunkX - minChunkX, chunkY - minChunkY, chunkZ - minChunkZ)] = - sectionCache.acquire(chunkX, chunkY, chunkZ); + sections[getLocalSectionIndex(chunkX - minChunkX, chunkY - minChunkY, chunkZ - minChunkZ)] = sectionCache.acquire(chunkX, chunkY, chunkZ); } } } @@ -205,9 +201,7 @@ private void unpackBlockDataR(BlockState[] states, ClonedChunkSection section, S for (int z = minBlockZ; z <= maxBlockZ; z++) { for (int x = minBlockX; x <= maxBlockX; x++) { int blockIdx = getLocalBlockIndex(x & 15, y & 15, z & 15); - // TODO: Sodium - BlockState -// int value = intArray.get(blockIdx); -// states[blockIdx] = palette.get(value); + states[blockIdx] = section.getBlockState(x & 15, y & 15, z & 15); } } } @@ -215,8 +209,7 @@ private void unpackBlockDataR(BlockState[] states, ClonedChunkSection section, S private void unpackBlockDataZ(BlockState[] states, ClonedChunkSection section) { // TODO: Sodium - BlockStates -// ((PackedIntegerArrayExtended) section.getBlockData()) -// .copyUsingPalette(states, section.getBlockPalette()); +// ((PackedIntegerArrayExtended) section.getBlockData()).copyUsingPalette(states, section.getBlockPalette()); } /** @@ -224,10 +217,7 @@ private void unpackBlockDataZ(BlockState[] states, ClonedChunkSection section) { * in place of null). */ private static BlockState nullableState(BlockState state) { - if(state != null) { - return state; - } else - return NULL_BLOCK_STATE; + return state != null ? state : ClonedChunkSection.DEFAULT_BLOCK_STATE; } @Override @@ -240,8 +230,7 @@ public BlockState getBlockState(int x, int y, int z) { int relY = y - this.baseY; int relZ = z - this.baseZ; - return nullableState(this.blockStatesArrays[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] - [getLocalBlockIndex(relX & 15, relY & 15, relZ & 15)]); + return nullableState(this.blockStatesArrays[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)][getLocalBlockIndex(relX & 15, relY & 15, relZ & 15)]); } public BlockState getBlockStateRelative(int x, int y, int z) { @@ -273,8 +262,7 @@ public TileEntity getBlockEntity(int x, int y, int z) { int relY = y - this.baseY; int relZ = z - this.baseZ; - return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] - .getBlockEntity(relX & 15, relY & 15, relZ & 15); + return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)].getBlockEntity(relX & 15, relY & 15, relZ & 15); } @Override @@ -303,8 +291,7 @@ public int getLightLevel(LightType type, BlockPos pos) { int relY = pos.y - this.baseY; int relZ = pos.z - this.baseZ; - return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] - .getLightLevel(type, relX & 15, relY & 15, relZ & 15); + return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)].getLightLevel(type, relX & 15, relY & 15, relZ & 15); } @Override @@ -346,15 +333,13 @@ public BiomeGenBase getBiome(int x, int y, int z) { index = index >= biomeCaches.length ? biomeCaches.length - 1 : index; BiomeCache cache = this.biomeCaches[index]; - return cache != null ? cache - .getBiome(this, x, relY >> 4, z) : Minecraft.getMinecraft().theWorld.getBiomeGenForCoords(x, z); + return cache != null ? cache.getBiome(this, x, relY >> 4, z) : Minecraft.getMinecraft().theWorld.getBiomeGenForCoords(x, z); } public ChunkSectionPos getOrigin() { return this.origin; } - // [VanillaCopy] PalettedContainer#toIndex public static int getLocalBlockIndex(int x, int y, int z) { return y << 8 | z << 4 | x; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index fa1c7234e..fa21cdd82 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -2,11 +2,14 @@ import com.gtnewhorizons.angelica.compat.ExtendedBlockStorageExt; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import com.gtnewhorizons.angelica.compat.mojang.LightType; import com.gtnewhorizons.angelica.mixins.interfaces.IExtendedBlockStorageExt; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.ChunkPosition; import net.minecraft.world.World; @@ -20,12 +23,13 @@ import java.util.concurrent.atomic.AtomicInteger; public class ClonedChunkSection { + public static final BlockState DEFAULT_BLOCK_STATE = new BlockState(Blocks.air, 0); private static final LightType[] LIGHT_TYPES = LightType.values(); private static final ExtendedBlockStorage EMPTY_SECTION = new ExtendedBlockStorage(0, false); private final AtomicInteger referenceCount = new AtomicInteger(0); private final ClonedChunkSectionCache backingCache; - private boolean hasSky = false; + private final Short2ObjectMap tileEntities; private final NibbleArray[] lightDataArrays; @@ -46,7 +50,7 @@ public class ClonedChunkSection { } public void init(ChunkSectionPos pos) { - Chunk chunk = world.getChunkFromChunkCoords(pos.x, pos.z); + final Chunk chunk = world.getChunkFromChunkCoords(pos.x, pos.z); if (chunk == null) { throw new RuntimeException("Couldn't retrieve chunk at " + pos.toChunkPos()); @@ -86,6 +90,13 @@ public void init(ChunkSectionPos pos) { } } + public BlockState getBlockState(int x, int y, int z) { + final Block block = data.getBlockByExtId(x, y, z); + if(block.isAir(world, x, y, z)) { + return DEFAULT_BLOCK_STATE; + } + return new BlockState(data.getBlockByExtId(x, y, z), data.getExtBlockMetadata(x, y, z)); + } public int getLightLevel(LightType type, int x, int y, int z) { NibbleArray array = this.lightDataArrays[type.ordinal()]; @@ -115,13 +126,11 @@ public static boolean isOutOfBuildLimitVertically(int y) { } private static ExtendedBlockStorage getChunkSection(Chunk chunk, ChunkSectionPos pos) { - ExtendedBlockStorage section = null; - if (!isOutOfBuildLimitVertically(ChunkSectionPos.getBlockCoord(pos.y()))) { - section = chunk.getBlockStorageArray()[pos.y]; + return chunk.getBlockStorageArray()[pos.y]; } - return section; + return null; } public void acquireReference() { From de768ad42762b9ec7c503c07b63610aa6a23659a Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 16 Nov 2023 19:30:16 -0800 Subject: [PATCH 046/301] Progress - "Something" renders! * Borrow some tesselator -> Quad code from Neodymium - Still todo - adapt properly and give credit * Fix copying chunk data... stop copying LSBArray from itself, to itself :facepalm: * Add Threaded Tesselator support (heavily inspired/borrowed from ArchaicFix). Still a WIP * Not sure if it's necessary, but do a postLoadChunk instead of loadChunk (which on later versions is loadChunkFromPacket) * Copy blockRefCount so a chunk section doesn't think it's empty. Could also rebuild, but this. * Use renderBlocks(), capture tesselator data, and attempt to convert it to quads for use in sodium rendering --- .../gtnewhorizons/angelica/AngelicaMod.java | 7 +- .../compat/ExtendedBlockStorageExt.java | 3 +- .../angelica/compat/mojang/BlockState.java | 3 +- .../angelica/compat/nd/BufferWriter.java | 63 +++ .../angelica/compat/nd/Quad.java | 490 ++++++++++++++++++ .../angelica/compat/nd/QuadNormal.java | 35 ++ .../angelica/compat/nd/RecyclingList.java | 49 ++ .../gtnewhorizons/angelica/mixins/Mixins.java | 11 +- .../early/angelica/MixinRenderBlocks.java | 18 + .../threadedupdates/MixinRenderBlocks.java | 7 +- .../sodium/MixinChunkProviderClient.java | 8 +- .../sodium/MixinExtendedBlockStorage.java | 3 + .../mixins/early/sodium/MixinMinecraft.java | 24 + .../sodium/MixinNetHandlerPlayClient.java | 27 + .../early/sodium/MixinRenderGlobal.java | 8 +- .../mixins/early/sodium/MixinWorldClient.java | 9 +- .../interfaces/IExtendedBlockStorageExt.java | 3 + .../mixins/interfaces/IRenderGlobalExt.java | 6 + .../mixins/interfaces/IWorldClientExt.java | 5 + .../angelica/proxy/ClientProxy.java | 7 + .../angelica/proxy/CommonProxy.java | 3 + .../rendering/ThreadedTesselatorHelper.java | 22 + .../quad/blender/FlatBiomeColorBlender.java | 6 +- .../client/render/SodiumWorldRenderer.java | 4 +- .../render/chunk/compile/ChunkBuilder.java | 5 + .../chunk/tasks/ChunkRenderRebuildTask.java | 64 ++- .../client/render/pipeline/BlockRenderer.java | 210 ++++++-- ...ager.java => IChunkProviderClientExt.java} | 3 +- .../mods/sodium/client/world/WorldSlice.java | 56 +- .../world/cloned/ChunkRenderContext.java | 3 +- .../world/cloned/ClonedChunkSection.java | 2 +- .../util/collections/FutureDequeDrain.java | 2 +- 32 files changed, 1068 insertions(+), 98 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/nd/BufferWriter.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNetHandlerPlayClient.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IRenderGlobalExt.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IWorldClientExt.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/rendering/ThreadedTesselatorHelper.java rename src/main/java/me/jellysquid/mods/sodium/client/world/{ChunkStatusListenerManager.java => IChunkProviderClientExt.java} (66%) diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index e7f4def6f..16e82aa82 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -3,9 +3,9 @@ import com.gtnewhorizons.angelica.proxy.CommonProxy; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; - @Mod( modid = "angelica", name = "Angelica", @@ -21,4 +21,9 @@ public class AngelicaMod { public void preInit(FMLPreInitializationEvent event) { proxy.preInit(event); } + + @Mod.EventHandler + public void init(FMLInitializationEvent event) { + proxy.init(event); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java index 524adaaec..842b34875 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java @@ -14,7 +14,7 @@ public ExtendedBlockStorageExt(int yBase, boolean hasSky) { public ExtendedBlockStorageExt(IExtendedBlockStorageExt storage) { super(storage.getYBase(), storage.hasSky()); - final byte[] blockLSBArray = storage.getBlockLSBArray(); + final byte[] blockLSBArray = this.getBlockLSBArray(); System.arraycopy(storage.getBlockLSBArray(), 0, blockLSBArray, 0, blockLSBArray.length); if(storage.getBlockMSBArray() != null) { @@ -29,6 +29,7 @@ public ExtendedBlockStorageExt(IExtendedBlockStorageExt storage) { } copyNibbleArray((ExtendedNibbleArray) storage.getSkylightArray(), (ExtendedNibbleArray) this.getSkylightArray()); } + ((IExtendedBlockStorageExt)this).setBlockRefCount(storage.getBlockRefCount()); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java index eb19bbec2..243f7520e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java @@ -7,6 +7,7 @@ import org.joml.Vector3d; public class BlockState implements IForgeBlockState { + private final static Vector3d ZERO = new Vector3d(0, 0, 0); private final Block block; private final int meta; @@ -51,7 +52,7 @@ public boolean isOpaqueFullCube(BlockRenderView world, BlockPos pos) { public boolean isFullCube(BlockRenderView world, BlockPos pos) { return true; } public Vector3d getModelOffset(BlockRenderView world, BlockPos pos) { - return null; + return ZERO; } public boolean isAir() { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/BufferWriter.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/BufferWriter.java new file mode 100644 index 000000000..2fbf3c3af --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/BufferWriter.java @@ -0,0 +1,63 @@ +package com.gtnewhorizons.angelica.compat.nd; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; + +public class BufferWriter { + // Temporarily borrowed from Neodymium + + private final ByteBuffer buf; + + private final FloatBuffer floatBuffer; + private final ShortBuffer shortBuffer; + private final IntBuffer intBuffer; + + public BufferWriter(ByteBuffer buf) { + this.buf = buf; + this.floatBuffer = buf.asFloatBuffer(); + this.shortBuffer = buf.asShortBuffer(); + this.intBuffer = buf.asIntBuffer(); + } + + private void incrementPosition(int add) { + buf.position(buf.position() + add); + floatBuffer.position(buf.position() / 4); + shortBuffer.position(buf.position() / 2); + intBuffer.position(buf.position() / 4); + } + + public void writeFloat(float x) { + try { + floatBuffer.put(x); + + incrementPosition(4); + } catch(Exception e){ + e.printStackTrace(); + } + } + + public void writeInt(int x) { + intBuffer.put(x); + + incrementPosition(4); + } + + public void writeByte(byte x) { + buf.put(x); // this increments the buffer position by 1 + + incrementPosition(0); + } + + public int position() { + return buf.position(); + } + + public void writeShort(short s) { + shortBuffer.put(s); + + incrementPosition(2); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java new file mode 100644 index 000000000..91007f4dc --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java @@ -0,0 +1,490 @@ +package com.gtnewhorizons.angelica.compat.nd; + +import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraftforge.common.util.ForgeDirection; +import org.joml.Vector3f; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Locale; + +public class Quad implements ModelQuadView { + // Temporarily borrowed from Neodymium + + private final static int DEFAULT_BRIGHTNESS = 15 << 20 | 15 << 4; + private final static int DEFAULT_COLOR = 0xFFFFFFFF; + + public float[] xs = new float[4]; + public float[] ys = new float[4]; + public float[] zs = new float[4]; + public float minX = Float.POSITIVE_INFINITY; + public float minY = Float.POSITIVE_INFINITY; + public float minZ = Float.POSITIVE_INFINITY; + public float maxX = Float.NEGATIVE_INFINITY; + public float maxY = Float.NEGATIVE_INFINITY; + public float maxZ = Float.NEGATIVE_INFINITY; + public float[] us = new float[4]; + public float[] vs = new float[4]; + public int[] bs = new int[4]; + public int[] cs = new int[4]; + // TODO normals? + public boolean deleted; + public boolean noMerge; + + public QuadNormal normal; + public int offset; + public BlockRenderer.Flags flags; + + // Is positive U direction parallel to edge 0-1? + public boolean uDirectionIs01; + + public boolean isRectangle; + + // 0: quads glued together on edge 1-2 or 3-0 ("megaquad row length") + // 1: quads glued together on edge 0-1 or 2-3 ("megaquad column length") + private int[] quadCountByDirection = {1, 1}; + public static int[] totalMergeCountByPlane = new int[3]; + + // When we merge with another quad, we forget what we used to be like. + // Keep a reference to the quad we first merged with, and use it as a reminder. + public Quad mergeReference; + + private static final Vector3f vectorA = new Vector3f(); + private static final Vector3f vectorB = new Vector3f(); + private static final Vector3f vectorC = new Vector3f(); + private boolean hasColor; + private boolean hasShade; + + public boolean hasColor() { + return this.hasColor; + } + + public boolean hasShade() { + return this.hasShade; + } + + public ForgeDirection getFace() { + // TODO: Sodium/Quad Facing + return ForgeDirection.UP; + } + + @Override + public float getX(int idx) { + return xs[idx]; + } + + @Override + public float getY(int idx) { + return ys[idx]; + } + + @Override + public float getZ(int idx) { + return zs[idx]; + } + + @Override + public int getColor(int idx) { + return cs[idx]; + } + + @Override + public float getTexU(int idx) { + return us[idx]; + } + + @Override + public float getTexV(int idx) { + return vs[idx]; + } + + @Override + public int getFlags() { + return 0; + } + + @Override + public int getLight(int idx) { + return bs[idx]; + } + + @Override + public int getNormal(int idx) { + return 0; + } + + @Override + public int getColorIndex() { + return 0; + } + + @Override + public TextureAtlasSprite rubidium$getSprite() { + return null; + } + + private void read(int[] rawBuffer, int offset, float offsetX, float offsetY, float offsetZ, int drawMode, BlockRenderer.Flags flags) { + int vertices = drawMode == GL11.GL_TRIANGLES ? 3 : 4; + for(int vi = 0; vi < vertices; vi++) { + int i = offset + vi * 8; + + xs[vi] = Float.intBitsToFloat(rawBuffer[i + 0]) + offsetX; + ys[vi] = Float.intBitsToFloat(rawBuffer[i + 1]) + offsetY; + zs[vi] = Float.intBitsToFloat(rawBuffer[i + 2]) + offsetZ; + + us[vi] = Float.intBitsToFloat(rawBuffer[i + 3]); + vs[vi] = Float.intBitsToFloat(rawBuffer[i + 4]); + + bs[vi] = flags.hasBrightness ? rawBuffer[i + 7] : DEFAULT_BRIGHTNESS; + cs[vi] = flags.hasColor ? rawBuffer[i + 5] : DEFAULT_COLOR; + this.hasColor |= flags.hasColor; + this.hasShade |= flags.hasBrightness; + + i += 8; + } + + if(vertices == 3) { + // Quadrangulate! + xs[3] = xs[2]; + ys[3] = ys[2]; + zs[3] = zs[2]; + + us[3] = us[2]; + vs[3] = vs[2]; + + bs[3] = bs[2]; + cs[3] = cs[2]; + } + } + + public void setState(int[] rawBuffer, int offset, BlockRenderer.Flags flags, int drawMode, float offsetX, float offsetY, float offsetZ) { + resetState(); + + read(rawBuffer, offset, offsetX, offsetY, offsetZ, drawMode, flags); + + if(xs[0] == xs[1] && xs[1] == xs[2] && xs[2] == xs[3] && ys[0] == ys[1] && ys[1] == ys[2] && ys[2] == ys[3]) { + // ignore empty quads (e.g. alpha pass of EnderIO item conduits) + deleted = true; + return; + } + + uDirectionIs01 = us[0] != us[1]; + + updateMinMaxXYZ(); + updateIsRectangle(); + if(!isRectangle) { + // merging non-rectangles (e.g. Carpenter's Blocks wedge) is buggy, don't do it + noMerge = true; + } + + vectorA.set(xs[1] - xs[0], ys[1] - ys[0], zs[1] - zs[0]); + vectorB.set(xs[2] - xs[1], ys[2] - ys[1], zs[2] - zs[1]); + vectorA.cross(vectorB, vectorA); + + normal = QuadNormal.fromVector(vectorC); + } + + private void resetState() { + Arrays.fill(xs, 0); + Arrays.fill(ys, 0); + Arrays.fill(zs, 0); + Arrays.fill(us, 0); + Arrays.fill(vs, 0); + Arrays.fill(bs, 0); + Arrays.fill(cs, 0); + + minX = Float.POSITIVE_INFINITY; + minY = Float.POSITIVE_INFINITY; + minZ = Float.POSITIVE_INFINITY; + maxX = Float.NEGATIVE_INFINITY; + maxY = Float.NEGATIVE_INFINITY; + maxZ = Float.NEGATIVE_INFINITY; + + deleted = noMerge = false; + normal = null; + offset = 0; + flags = null; + uDirectionIs01 = false; + Arrays.fill(quadCountByDirection, 1); + Arrays.fill(totalMergeCountByPlane, 0); + mergeReference = null; + } + + public void writeToBuffer(BufferWriter out) throws IOException { + for(int vertexI = 0; vertexI < 4; vertexI++) { + int vi = vertexI; + int provokingI = 3; + + float x = xs[vi]; + float y = ys[vi]; + float z = zs[vi]; + + out.writeFloat(x); + out.writeFloat(y); + out.writeFloat(z); + + float u = us[vi]; + float v = vs[vi]; + + if(false/*Config.shortUV*/) { + out.writeShort((short)(Math.round(u * 32768f))); + out.writeShort((short)(Math.round(v * 32768f))); + } else { + out.writeFloat(u); + out.writeFloat(v); + } + + int b = bs[vi]; + + out.writeInt(b); + + int c = cs[vi]; + + out.writeInt(c); + + if(false/*Config.simplifyChunkMeshes*/) { + if((quadCountByUVDirection(false) == 1 && quadCountByUVDirection(true) == 1)) { + // let the fragment shader know this is not a megaquad + out.writeByte((byte)255); + out.writeByte((byte)255); + out.writeByte((byte)255); + out.writeByte((byte)255); + } else { + out.writeByte(us[vi] == us[provokingI] ? 0 : (byte)quadCountByUVDirection(false)); + out.writeByte(vs[vi] == vs[provokingI] ? 0 : (byte)quadCountByUVDirection(true)); + out.writeByte(us[vi] == us[provokingI] ? (byte)0 : 1); + out.writeByte(vs[vi] == vs[provokingI] ? (byte)0 : 1); + } + } + + assert out.position() % getStride() == 0; + + //System.out.println("[" + vertexI + "] x: " + x + ", y: " + y + " z: " + z + ", u: " + u + ", v: " + v + ", b: " + b + ", c: " + c); + } + } + + public int quadCountByUVDirection(boolean v) { + if(v) { + return quadCountByDirection[uDirectionIs01 ? 0 : 1]; + } else { + return quadCountByDirection[uDirectionIs01 ? 1 : 0]; + } + } + + public static int getStride() { + return + 3 * 4 // XYZ (float) + + 2 * (/*Config.shortUV*/false ? 2 : 4) // UV (float) + + 4 // B (int) + + 4 // C (int) + + (/*Config.simplifyChunkMeshes*/ false ? 4 : 0) // megaquad XY (byte) + ; + } + + private boolean isTranslatedCopyOf(Quad o, boolean checkValid) { + if((!isValid(this) && checkValid) || !isValid(o) || normal != o.normal) return false; + + if(mergeReference != null) { + return mergeReference.isTranslatedCopyOf(o, false); + } + + for(int i = 1; i < 4; i++) { + double relX = xs[i] - xs[0]; + double relY = ys[i] - ys[0]; + double relZ = zs[i] - zs[0]; + + if(o.xs[i] != o.xs[0] + relX || o.ys[i] != o.ys[0] + relY || o.zs[i] != o.zs[0] + relZ) { + return false; + } + } + + for(int i = 0; i < 4; i++) { + if(us[i] != o.us[i] || vs[i] != o.vs[i] || bs[i] != o.bs[i] || cs[i] != o.cs[i]) { + return false; + } + } + + return true; + } + + public void tryToMerge(Quad o) { + if(noMerge || o.noMerge) return; + + if(isTranslatedCopyOf(o, true)) { + int numVerticesTouching = 0; + boolean[] verticesTouching = new boolean[4]; + for(int i = 0; i < 4; i++) { + for(int j = 0; j < 4; j++) { + if(xs[i] == o.xs[j] && ys[i] == o.ys[j] && zs[i] == o.zs[j]) { + verticesTouching[i] = true; + numVerticesTouching++; + } + } + } + if(numVerticesTouching == 2) { + for(int i = 0; i < 4; i++) { + if(verticesTouching[i]) { + copyVertexFrom(o, i, i); + } + } + + if((verticesTouching[0] && verticesTouching[1]) || (verticesTouching[2] && verticesTouching[3])) { + quadCountByDirection[0] += o.quadCountByDirection[0]; + } + if((verticesTouching[1] && verticesTouching[2]) || (verticesTouching[3] && verticesTouching[0])) { + quadCountByDirection[1] += o.quadCountByDirection[1]; + } + + totalMergeCountByPlane[getPlane().ordinal() - 1]++; + + mergeReference = o; + + o.deleted = true; + } + } + } + + private void copyVertexFrom(Quad o, int src, int dest) { + xs[dest] = o.xs[src]; + ys[dest] = o.ys[src]; + zs[dest] = o.zs[src]; + us[dest] = o.us[src]; + vs[dest] = o.vs[src]; + bs[dest] = o.bs[src]; + cs[dest] = o.cs[src]; + + updateMinMaxXYZ(); // TODO isn't doing this a waste? I should get rid of the min/maxXYZ variables entirely. + } + + private void updateMinMaxXYZ() { + for(int i = 0; i < 4; i++) { + minX = Math.min(minX, xs[i]); + minY = Math.min(minY, ys[i]); + minZ = Math.min(minZ, zs[i]); + maxX = Math.max(maxX, xs[i]); + maxY = Math.max(maxY, ys[i]); + maxZ = Math.max(maxZ, zs[i]); + } + } + + private void updateIsRectangle() { + isRectangle = + vertexExists(minX, minY, minZ) && + vertexExists(minX, minY, maxZ) && + vertexExists(minX, maxY, minZ) && + vertexExists(minX, maxY, maxZ) && + vertexExists(maxX, minY, minZ) && + vertexExists(maxX, minY, maxZ) && + vertexExists(maxX, maxY, minZ) && + vertexExists(maxX, maxY, maxZ); + } + + private boolean vertexExists(float x, float y, float z) { + for(int i = 0; i < 4; i++) { + if(xs[i] == x && ys[i] == y && zs[i] == z) { + return true; + } + } + return false; + } + + // maybe minXYZ and maxXYZ should be arrays instead + public double getMin(int coord) { + return coord == 0 ? minX : coord == 1 ? minY : coord == 2 ? minZ : -1; + } + + public double getMax(int coord) { + return coord == 0 ? maxX : coord == 1 ? maxY : coord == 2 ? maxZ : -1; + } + + public boolean onSamePlaneAs(Quad o) { + return isValid(this) && isValid(o) && getPlane() == o.getPlane() && + ((getPlane() == Plane.XY && minZ == o.minZ) || + (getPlane() == Plane.XZ && minY == o.minY) || + (getPlane() == Plane.YZ && minX == o.minX)); + } + + public Plane getPlane() { + return Plane.fromNormal(normal); + } + + public static boolean isValid(Quad q) { + return q != null && !q.deleted; + } + + public boolean isClockwiseXZ() { + return (xs[1] - xs[0]) * (zs[2] - zs[0]) - (xs[2] - xs[0]) * (zs[1] - zs[0]) < 0; + } + + @Override + public String toString() { + return String.format(Locale.ENGLISH, "%s(%.1f, %.1f, %.1f -- %.1f, %.1f, %.1f)", deleted ? "XXX " : "", minX, minY, minZ, maxX, maxY, maxZ); + //return String.format(Locale.ENGLISH, "%s[(%.1f, %.1f, %.1f), (%.1f, %.1f, %.1f), (%.1f, %.1f, %.1f), (%.1f, %.1f, %.1f)]", deleted ? "XXX " : "", xs[0], ys[0], zs[0], xs[1], ys[1], zs[1], xs[2], ys[2], zs[2], xs[3], ys[3], zs[3]); + } + + public static class QuadPlaneComparator implements Comparator { + + public static final QuadPlaneComparator[] quadPlaneComparators = new QuadPlaneComparator[]{ + new QuadPlaneComparator(2, 1, 0), // PLANE_XY -> ZYX + new QuadPlaneComparator(1, 2, 0), // PLANE_XZ -> YZX + new QuadPlaneComparator(0, 2, 1) // PLANE_YZ -> XZY + }; + + private final int c0; + private final int c1; + private final int c2; + + public QuadPlaneComparator(int firstCoordToCompare, int secondCoordToCompare, int thirdCoordToCompare) { + this.c0 = firstCoordToCompare; + this.c1 = secondCoordToCompare; + this.c2 = thirdCoordToCompare; + } + + @Override + public int compare(Quad a, Quad b) { + if(a.getMin(c0) < b.getMin(c0)) { + return -1; + } else if(a.getMin(c0) > b.getMin(c0)) { + return 1; + } else { + if(a.getMin(c1) < b.getMin(c1)) { + return -1; + } else if(a.getMin(c1) > b.getMin(c1)) { + return 1; + } else { + if(a.getMin(c2) < b.getMin(c2)) { + return -1; + } else if(a.getMin(c2) > b.getMin(c2)) { + return 1; + } else { + return (int)Math.signum(a.offset - b.offset); + } + } + } + } + } + + public static enum Plane { + NONE, + XY, + XZ, + YZ; + + public static Plane fromNormal(QuadNormal normal) { + return switch (normal) { + case POSITIVE_X, NEGATIVE_X -> YZ; + case POSITIVE_Y, NEGATIVE_Y -> XZ; + case POSITIVE_Z, NEGATIVE_Z -> XY; + default -> NONE; + }; + } + } + + public boolean isPosEqual(Quad b) { + return Arrays.equals(xs, b.xs) && Arrays.equals(ys, b.ys) && Arrays.equals(zs, b.zs); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java new file mode 100644 index 000000000..a640ae50e --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java @@ -0,0 +1,35 @@ +package com.gtnewhorizons.angelica.compat.nd; + +import org.joml.Vector3f; + +public enum QuadNormal { + // Temporarily borrowed from Neodymium + NONE, POSITIVE_X, NEGATIVE_X, POSITIVE_Y, NEGATIVE_Y, POSITIVE_Z, NEGATIVE_Z; + + public static QuadNormal fromVector(Vector3f normal) { + if(normal.x == 0f) { + if(normal.y == 0f) { + if(normal.z > 0) { + return POSITIVE_Z; + } else if(normal.z < 0) { + return NEGATIVE_Z; + } + } else if(normal.z == 0f) { + if(normal.y > 0) { + return POSITIVE_Y; + } else if(normal.y < 0) { + return NEGATIVE_Y; + } + } + } else if(normal.y == 0f) { + if(normal.z == 0f) { + if(normal.x > 0) { + return POSITIVE_X; + } else if(normal.x < 0) { + return NEGATIVE_X; + } + } + } + return NONE; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java new file mode 100644 index 000000000..ba5bd851d --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java @@ -0,0 +1,49 @@ +package com.gtnewhorizons.angelica.compat.nd; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +public class RecyclingList { + // Temporarily borrowed from Neodymium + + private Supplier constructor; + + int nextIndex; + private List list; + + public RecyclingList(Supplier constructor) { + this.constructor = constructor; + this.list = new ArrayList(); + } + + public T get(int i) { + while(list.size() <= i) { + list.add(constructor.get()); + } + return list.get(i); + } + + public T next() { + return get(nextIndex++); + } + + public void remove() { + if(nextIndex == 0) { + throw new IllegalStateException("Tried to remove from empty list"); + } + nextIndex--; + } + + public boolean isEmpty() { + return nextIndex == 0; + } + + public void reset() { + nextIndex = 0; + } + + public List getAsList() { + return list.subList(0, nextIndex); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 7e1c8462b..9b1fdecba 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -12,6 +12,7 @@ public enum Mixins { ANGELICA(new Builder("Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( "angelica.MixinEntityRenderer" + ,"angelica.MixinRenderBlocks" ) ), IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) @@ -29,12 +30,14 @@ public enum Mixins { SODIUM(new Builder("Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( - "sodium.MixinRenderGlobal" - ,"sodium.MixinWorldClient" - ,"sodium.MixinChunkProviderClient" - ,"sodium.MixinFrustrum" + "sodium.MixinChunkProviderClient" ,"sodium.MixinExtendedBlockStorage" + ,"sodium.MixinFrustrum" + ,"sodium.MixinMinecraft" + ,"sodium.MixinNetHandlerPlayClient" ,"sodium.MixinNibbleArray" + ,"sodium.MixinRenderGlobal" + ,"sodium.MixinWorldClient" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java new file mode 100644 index 000000000..6d68b52e2 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java @@ -0,0 +1,18 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica; + +import com.gtnewhorizons.angelica.rendering.ThreadedTesselatorHelper; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(RenderBlocks.class) +public class MixinRenderBlocks { + + @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;instance:Lnet/minecraft/client/renderer/Tessellator;")) + private Tessellator modifyTessellatorAccess() { + return ThreadedTesselatorHelper.instance.getThreadTessellator(); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinRenderBlocks.java index 7bb976ed7..d2013cd98 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinRenderBlocks.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinRenderBlocks.java @@ -22,13 +22,10 @@ private void cancelRenderDelegatedToDifferentThread(Block block, int x, int y, i int pass = ForgeHooksClient.getWorldRenderPass(); boolean mainThread = Thread.currentThread() == ThreadedChunkUpdateHelper.MAIN_THREAD; - ThreadedChunkUpdateHelper.UpdateTask task = mainThread - ? ((IRendererUpdateResultHolder)ThreadedChunkUpdateHelper.lastWorldRenderer).arch$getRendererUpdateTask() - : null; + ThreadedChunkUpdateHelper.UpdateTask task = mainThread ? ((IRendererUpdateResultHolder)ThreadedChunkUpdateHelper.lastWorldRenderer).arch$getRendererUpdateTask() : null; boolean offThreadBlock = ThreadedChunkUpdateHelper.canBlockBeRenderedOffThread(block, pass, renderType) - && !(task != null && task.cancelled) - && (!mainThread || ThreadedChunkUpdateHelper.renderBlocksStack.getLevel() == 1); + && !(task != null && task.cancelled) && (!mainThread || ThreadedChunkUpdateHelper.renderBlocksStack.getLevel() == 1); if ((mainThread ? pass >= 0 : true) && (mainThread ? offThreadBlock : !offThreadBlock)) { // Cancel rendering block if it's delegated to a different thread. cir.setReturnValue(mainThread ? task.result[pass].renderedSomething : false); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java index 91955098e..5af74436b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java @@ -4,7 +4,7 @@ import it.unimi.dsi.fastutil.longs.LongIterator; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; -import me.jellysquid.mods.sodium.client.world.ChunkStatusListenerManager; +import me.jellysquid.mods.sodium.client.world.IChunkProviderClientExt; import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.world.chunk.Chunk; import org.spongepowered.asm.mixin.Mixin; @@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(ChunkProviderClient.class) -public abstract class MixinChunkProviderClient implements ChunkStatusListenerManager { +public abstract class MixinChunkProviderClient implements IChunkProviderClientExt { private ChunkStatusListener sodium$listener; private final LongOpenHashSet sodium$loadedChunks = new LongOpenHashSet(); @Unique private boolean sodium$needsTrackingUpdate = false; @@ -29,8 +29,8 @@ public void setListener(ChunkStatusListener listener) { this.sodium$listener = listener; } - @Inject(method="loadChunk", at = @At(value = "INVOKE", target="Lcpw/mods/fml/common/eventhandler/EventBus;post(Lcpw/mods/fml/common/eventhandler/Event;)Z", shift = At.Shift.BEFORE), remap = false) - private void sodium$loadChunk(int x, int z, CallbackInfoReturnable cir) { + + public void doPostChunk(int x, int z) { if (this.sodium$listener != null) { this.sodium$listener.onChunkAdded(x, z); this.sodium$loadedChunks.add(ChunkPos.toLong(x, z)); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java index 86d9335d5..a305f2748 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java @@ -2,6 +2,7 @@ import com.gtnewhorizons.angelica.mixins.interfaces.IExtendedBlockStorageExt; import lombok.Getter; +import lombok.Setter; import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import org.spongepowered.asm.mixin.Mixin; @@ -15,6 +16,8 @@ public abstract class MixinExtendedBlockStorage implements IExtendedBlockStorage @Shadow public abstract byte[] getBlockLSBArray(); @Getter @Shadow private int yBase; + @Getter @Setter @Shadow private int blockRefCount; + @Getter @Setter @Shadow private int tickRefCount; @Override public boolean hasSky() { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java new file mode 100644 index 000000000..550468014 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java @@ -0,0 +1,24 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderGlobal; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +public class MixinMinecraft { + @Shadow + public RenderGlobal renderGlobal; + + @Inject(method="resize", at=@At("TAIL")) + private void sodium$resize(int width, int height, CallbackInfo ci) { + if(this.renderGlobal != null) { + ((IRenderGlobalExt)this.renderGlobal).scheduleTerrainUpdate(); + } + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNetHandlerPlayClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNetHandlerPlayClient.java new file mode 100644 index 000000000..5bdf9e14c --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNetHandlerPlayClient.java @@ -0,0 +1,27 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.mixins.interfaces.IWorldClientExt; +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.network.play.server.S21PacketChunkData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(NetHandlerPlayClient.class) +public class MixinNetHandlerPlayClient { + @Shadow private WorldClient clientWorldController; + + @Inject(method = "handleChunkData", at= @At(value="INVOKE", target="Lnet/minecraft/client/multiplayer/WorldClient;markBlockRangeForRenderUpdate(IIIIII)V", shift = At.Shift.AFTER)) + private void sodium$afterChunkData(S21PacketChunkData packetIn, CallbackInfo ci) { + ((IWorldClientExt)this.clientWorldController).doPostChunk(packetIn.func_149273_e(), packetIn.func_149271_f()); + } + + @Inject(method = "handleMapChunkBulk", at= @At(value="INVOKE", target="Lnet/minecraft/client/multiplayer/WorldClient;markBlockRangeForRenderUpdate(IIIIII)V", shift = At.Shift.AFTER)) + private void sodium$afterMapChunkBulk(CallbackInfo ci, @Local(name = "j") int x, @Local(name = "k") int z) { + ((IWorldClientExt)this.clientWorldController).doPostChunk(x, z); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index e57c41760..fbcc3e979 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import net.minecraft.client.Minecraft; @@ -23,7 +24,7 @@ import java.util.List; @Mixin(RenderGlobal.class) -public class MixinRenderGlobal { +public class MixinRenderGlobal implements IRenderGlobalExt { @Shadow public Minecraft mc; @@ -31,6 +32,11 @@ public class MixinRenderGlobal { private int sodium$frame; + @Override + public void scheduleTerrainUpdate() { + this.renderer.scheduleTerrainUpdate(); + } + @Inject(method="", at=@At("RETURN")) private void sodium$initRenderer(Minecraft mc, CallbackInfo ci) { this.renderer = SodiumWorldRenderer.create(mc); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java index 208a82cc1..0189adf4c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java @@ -2,13 +2,15 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.mixins.interfaces.IHasClientChunkProvider; +import com.gtnewhorizons.angelica.mixins.interfaces.IWorldClientExt; +import me.jellysquid.mods.sodium.client.world.IChunkProviderClientExt; import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.client.multiplayer.WorldClient; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @Mixin(WorldClient.class) -public abstract class MixinWorldClient implements BlockRenderView, IHasClientChunkProvider { +public abstract class MixinWorldClient implements BlockRenderView, IHasClientChunkProvider, IWorldClientExt { @Shadow private ChunkProviderClient clientChunkProvider; @@ -16,4 +18,9 @@ public abstract class MixinWorldClient implements BlockRenderView, IHasClientChu public ChunkProviderClient getClientChunkProvider() { return clientChunkProvider; } + + @Override + public void doPostChunk(int x, int z) { + ((IChunkProviderClientExt)this.clientChunkProvider).doPostChunk(x, z); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IExtendedBlockStorageExt.java index 8edd195d0..58ae8231f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IExtendedBlockStorageExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IExtendedBlockStorageExt.java @@ -12,4 +12,7 @@ public interface IExtendedBlockStorageExt { boolean hasSky(); + int getBlockRefCount(); + void setBlockRefCount(int blockRefCount); + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IRenderGlobalExt.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IRenderGlobalExt.java new file mode 100644 index 000000000..43133d0c7 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IRenderGlobalExt.java @@ -0,0 +1,6 @@ +package com.gtnewhorizons.angelica.mixins.interfaces; + +public interface IRenderGlobalExt { + void scheduleTerrainUpdate(); + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IWorldClientExt.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IWorldClientExt.java new file mode 100644 index 000000000..e52d7ec27 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IWorldClientExt.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.mixins.interfaces; + +public interface IWorldClientExt { + void doPostChunk(int x, int z); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index 273a43a6a..6865ca26f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -1,6 +1,8 @@ package com.gtnewhorizons.angelica.proxy; import com.gtnewhorizons.angelica.client.gui.AngelicaVideoSettings; +import com.gtnewhorizons.angelica.rendering.ThreadedTesselatorHelper; +import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import jss.notfine.gui.GuiCustomMenu; import jss.notfine.gui.ISettingsEnum; @@ -16,4 +18,9 @@ public void preInit(FMLPreInitializationEvent event) { return settingsEnum.createButton(xPosition, yPosition, setting); }); } + + @Override + public void init(FMLInitializationEvent event) { + ThreadedTesselatorHelper.instance.init(); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java index 02ae873da..e7ca18f7a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.proxy; +import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; public class CommonProxy { @@ -7,4 +8,6 @@ public class CommonProxy { public void preInit(FMLPreInitializationEvent event) { } + + public void init(FMLInitializationEvent event) {} } diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/ThreadedTesselatorHelper.java b/src/main/java/com/gtnewhorizons/angelica/rendering/ThreadedTesselatorHelper.java new file mode 100644 index 000000000..b5db67d4c --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/rendering/ThreadedTesselatorHelper.java @@ -0,0 +1,22 @@ +package com.gtnewhorizons.angelica.rendering; + +import net.minecraft.client.renderer.Tessellator; + +public class ThreadedTesselatorHelper { + public static ThreadedTesselatorHelper instance = new ThreadedTesselatorHelper(); + public static Thread MAIN_THREAD; + public ThreadLocal threadTessellator = ThreadLocal.withInitial(Tessellator::new); + + public void init() { + MAIN_THREAD = Thread.currentThread(); + } + + public Tessellator getThreadTessellator() { + if(Thread.currentThread() == MAIN_THREAD) { + return Tessellator.instance; + } else { + return threadTessellator.get(); + } + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java index ffb16f19c..14d389884 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java @@ -5,9 +5,6 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.util.color.ColorARGB; - -import java.util.Arrays; /** * A simple colorizer which performs no blending between adjacent blocks. @@ -18,7 +15,8 @@ public class FlatBiomeColorBlender implements BiomeColorBlender { @Override public int[] getColors(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, ModelQuadView quad) { - Arrays.fill(this.cachedRet, ColorARGB.toABGR(colorizer.getColor(state, world, origin, quad.getColorIndex()))); + // TODO: Sodium - Colorizer +// Arrays.fill(this.cachedRet, ColorARGB.toABGR(colorizer.getColor(state, world, origin, quad.getColorIndex()))); return this.cachedRet; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 3c57da1b6..06ab5f6cf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -34,7 +34,7 @@ import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheShared; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; -import me.jellysquid.mods.sodium.client.world.ChunkStatusListenerManager; +import me.jellysquid.mods.sodium.client.world.IChunkProviderClientExt; import me.jellysquid.mods.sodium.common.util.ListUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; @@ -134,7 +134,7 @@ private void loadWorld(WorldClient world) { this.initRenderer(); - ((ChunkStatusListenerManager) ((IHasClientChunkProvider)world).getClientChunkProvider()).setListener(this); + ((IChunkProviderClientExt) ((IHasClientChunkProvider)world).getClientChunkProvider()).setListener(this); } private void unloadWorld() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java index ba0d9fc88..3109a23c5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java @@ -394,6 +394,11 @@ private static class WrappedTask implements Cancel private WrappedTask(ChunkRenderBuildTask task) { this.task = task; this.future = new CompletableFuture<>(); + this.future.exceptionally(e -> { + LOGGER.info("Exception thrown while building chunk", e); +// e.printStackTrace(); + return null; + }); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index c09752a8b..1704c962b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -8,6 +8,7 @@ import com.gtnewhorizons.angelica.compat.mojang.FluidState; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.compat.mojang.RenderLayers; +import com.gtnewhorizons.angelica.rendering.ThreadedTesselatorHelper; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer; @@ -21,8 +22,11 @@ import me.jellysquid.mods.sodium.client.util.task.CancellationSource; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import org.joml.Vector3d; @@ -69,7 +73,10 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB cache.init(this.context); + // TODO: Sodium - WorldSlice probably needs to implement IWorldAccess and redirect to the slice/chunk cache WorldSlice slice = cache.getWorldSlice(); + // Gross + RenderBlocks renderBlocks = new RenderBlocks(slice.getWorld()); int baseX = this.render.getOriginX(); int baseY = this.render.getOriginY(); @@ -77,6 +84,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB BlockPos.Mutable pos = new BlockPos.Mutable(); BlockPos renderOffset = this.offset; + final Tessellator tessellator = ThreadedTesselatorHelper.instance.getThreadTessellator(); for (int relY = 0; relY < 16; relY++) { if (cancellationSource.isCancelled()) { @@ -86,9 +94,8 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB for (int relZ = 0; relZ < 16; relZ++) { for (int relX = 0; relX < 16; relX++) { BlockState blockState = slice.getBlockStateRelative(relX + 16, relY + 16, relZ + 16); - // TODO: Sodium - BlockState - if (blockState == null || blockState.isAir()) { + if (blockState == null || blockState.getBlock() == Blocks.air /* || blockState.isAir()*/) { continue; } @@ -97,30 +104,69 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB buffers.setRenderOffset(pos.x - renderOffset.getX(), pos.y - renderOffset.getY(), pos.z - renderOffset.getZ()); if (blockState.getRenderType() == BlockRenderType.MODEL) { - for (RenderLayer layer : RenderLayer.getBlockLayers()) { + for (RenderLayer layer : RenderLayer.getBlockLayers()) { if (!RenderLayers.canRenderInLayer(blockState, layer)) { continue; } + // Need an equivalent renderpass check + // if (!block.canRenderInPass(pass)) continue; + +// boolean rendered = renderBlocks.renderBlockByRenderType(block, pos.x, pos.y, pos.z); + + ForgeHooksClientExt.setRenderLayer(layer); + if(!(relX == 0 && relZ == 0)) { + continue; + } + /* Test quads from Makamys + if(relX == 0 && relZ == 0) { + // test quad + ChunkModelBuffers buf = buffers.get(RenderLayer.solid()); + ModelVertexSink sink = buf.getSink(ModelQuadFacing.UP); + int x = 0; + int y = 0; + int z = 0; + int color = 0xFFFFFFFF; + int light = 15728640; + float u0 = 0; + float v0 = 0; + float u1 = 1; + float v1 = 1; + sink.writeQuad(x + 0, y + 0, z + 1, color, u0, v1, light); + sink.writeQuad(x + 1, y + 0, z + 1, color, u1, v1, light); + sink.writeQuad(x + 1, y + 0, z + 0, color, u1, v0, light); + sink.writeQuad(x + 0, y + 0, z + 0, color, u0, v0, light); + + sink.flush(); + } + */ // TODO: RenderBlocks & capture tesselator state into quads // IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); // // BakedModel model = cache.getBlockModels().getModel(blockState); // -// long seed = blockState.getRenderingSeed(pos); -// -// if (cache.getBlockRenderer().renderModel(cache.getLocalSlice(), blockState, pos, model, buffers.get(layer), true, seed, modelData)) { -// bounds.addBlock(relX, relY, relZ); -// } + long seed = blockState.getRenderingSeed(pos); + // hax -- why is the reset needed here? + tessellator.isDrawing = false; + tessellator.reset(); + tessellator.startDrawingQuads(); + + if (cache.getBlockRenderer().renderModel(cache.getLocalSlice(), tessellator, renderBlocks, blockState, pos, buffers.get(layer), true, seed)) { + bounds.addBlock(relX, relY, relZ); + } + + tessellator.isDrawing = false; + tessellator.reset(); } } + FluidState fluidState = blockState.getFluidState(); - if (!fluidState.isEmpty()) { + if (fluidState != null && !fluidState.isEmpty()) { for (RenderLayer layer : RenderLayer.getBlockLayers()) { if (!RenderLayers.canRenderInLayer(fluidState, layer)) { continue; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index dc02d21d9..322f204e6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -1,15 +1,13 @@ package me.jellysquid.mods.sodium.client.render.pipeline; +import com.gtnewhorizons.angelica.compat.nd.Quad; import com.gtnewhorizons.angelica.compat.forge.ForgeBlockRenderer; -import com.gtnewhorizons.angelica.compat.forge.IModelData; -import com.gtnewhorizons.angelica.compat.forge.SinkingVertexBuilder; -import com.gtnewhorizons.angelica.compat.mojang.BakedModel; -import com.gtnewhorizons.angelica.compat.mojang.BakedQuad; import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.nd.RecyclingList; import me.jellysquid.mods.sodium.client.model.light.LightMode; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; @@ -26,12 +24,16 @@ import me.jellysquid.mods.sodium.client.util.color.ColorABGR; import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; import me.jellysquid.mods.sodium.client.world.biome.BlockColorsExtended; -import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.block.Block; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraftforge.common.util.ForgeDirection; import org.joml.Vector3d; +import org.lwjgl.opengl.GL11; +import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -65,60 +67,133 @@ public BlockRenderer(Minecraft client, LightPipelineProvider lighters, BiomeColo this.useAmbientOcclusion = Minecraft.getMinecraft().gameSettings.ambientOcclusion > 0; } - public boolean renderModel(BlockRenderView world, BlockState state, BlockPos pos, BakedModel model, ChunkModelBuffers buffers, boolean cull, long seed, IModelData modelData) { - LightMode mode = this.getLightingMode(state, model, world, pos); - LightPipeline lighter = this.lighters.getLighter(mode); + public boolean renderModel(BlockRenderView world, Tessellator tessellator, RenderBlocks renderBlocks, BlockState state, BlockPos pos, ChunkModelBuffers buffers, boolean cull, long seed) { + final LightMode mode = this.getLightingMode(state, world, pos); + final LightPipeline lighter = this.lighters.getLighter(mode); Vector3d offset = state.getModelOffset(world, pos); boolean rendered = false; - modelData = model.getModelData(world, pos, state, modelData); - - if(ForgeBlockRenderer.useForgeLightingPipeline()) { - MatrixStack mStack; - if(!offset.equals(ZERO)) { - mStack = new MatrixStack(); - mStack.translate(offset.x, offset.y, offset.z); - } else - mStack = EMPTY_STACK; - final SinkingVertexBuilder builder = SinkingVertexBuilder.getInstance(); - builder.reset(); - rendered = forgeBlockRenderer.renderBlock(mode, state, pos, world, model, mStack, builder, random, seed, modelData, cull, this.occlusionCache, buffers.getRenderData()); - builder.flush(buffers); - return rendered; - } +// modelData = model.getModelData(world, pos, state, modelData); +// +// if(ForgeBlockRenderer.useForgeLightingPipeline()) { +// MatrixStack mStack; +// if(!offset.equals(ZERO)) { +// mStack = new MatrixStack(); +// mStack.translate(offset.x, offset.y, offset.z); +// } else +// mStack = EMPTY_STACK; +// final SinkingVertexBuilder builder = SinkingVertexBuilder.getInstance(); +// builder.reset(); +// rendered = forgeBlockRenderer.renderBlock(mode, state, pos, world, model, mStack, builder, random, seed, modelData, cull, this.occlusionCache, buffers.getRenderData()); +// builder.flush(buffers); +// return rendered; +// } + final Block block = state.getBlock(); + // TODO: Occlusion by side... needs to break apart or invasively modify renderBlockByRenderType + // Or figure out the facing of the quad... + rendered = renderBlocks.renderBlockByRenderType(block, pos.x, pos.y, pos.z); + +// for (ForgeDirection dir : DirectionUtil.ALL_DIRECTIONS) { +// this.random.setSeed(seed); +// +// List sided = model.getQuads(state, dir, this.random, modelData); +// +// if (sided.isEmpty()) { +// continue; +// } +// +// if (!cull || this.occlusionCache.shouldDrawSide(state, world, pos, dir)) { +// this.renderQuadList(world, state, pos, lighter, offset, buffers, sided, dir); +// +// rendered = true; +// } +// } - for (ForgeDirection dir : DirectionUtil.ALL_DIRECTIONS) { - this.random.setSeed(seed); + this.random.setSeed(seed); + List all = tesselatorToBakedQuadList(tessellator); - List sided = model.getQuads(state, dir, this.random, modelData); - if (sided.isEmpty()) { - continue; - } +// List all = model.getQuads(state, null, this.random, modelData); - if (!cull || this.occlusionCache.shouldDrawSide(state, world, pos, dir)) { - this.renderQuadList(world, state, pos, lighter, offset, buffers, sided, dir); + if (!all.isEmpty()) { + this.renderQuadList(world, state, pos, lighter, offset, buffers, all, null); - rendered = true; - } + rendered = true; } - this.random.setSeed(seed); + return rendered; + } - List all = model.getQuads(state, null, this.random, modelData); + private static final Flags FLAGS = new Flags(true, true, true, false); + private static RecyclingList quadBuf = new RecyclingList<>(Quad::new); + private int tesselatorDataCount; + private List tesselatorToBakedQuadList(Tessellator t) { + // Temporarily borrowed/badly adapted from Neodymium + tesselatorDataCount++; + + List errors = new ArrayList<>(); + List warnings = new ArrayList<>(); + if(t.drawMode != GL11.GL_QUADS && t.drawMode != GL11.GL_TRIANGLES) { + errors.add("Unsupported draw mode: " + t.drawMode); + } + if(!t.hasTexture) { + errors.add("Texture data is missing."); + } + if(!t.hasBrightness) { + warnings.add("Brightness data is missing"); + } + if(!t.hasColor) { + warnings.add("Color data is missing"); + } + if(t.hasNormals && GL11.glIsEnabled(GL11.GL_LIGHTING)) { + errors.add("Chunk uses GL lighting, this is not implemented."); + } + FLAGS.hasBrightness = t.hasBrightness; + FLAGS.hasColor = t.hasColor; - if (!all.isEmpty()) { - this.renderQuadList(world, state, pos, lighter, offset, buffers, all, null); + int verticesPerPrimitive = t.drawMode == GL11.GL_QUADS ? 4 : 3; - rendered = true; + for(int quadI = 0; quadI < t.vertexCount / verticesPerPrimitive; quadI++) { + Quad quad = quadBuf.next(); + quad.setState(t.rawBuffer, quadI * (verticesPerPrimitive * 8), FLAGS, t.drawMode, (float)-t.xOffset, (float)-t.yOffset, (float)-t.zOffset); + if(quad.deleted) { + quadBuf.remove(); + } } - return rendered; +// if(!quadBuf.isEmpty()) { +// // Only show errors if we're actually supposed to be drawing something +// if(!errors.isEmpty() || !warnings.isEmpty()) { +// if(/*!Config.silenceErrors*/true ) { +// if(!errors.isEmpty()) { +// for(String error : errors) { +// LOGGER.error("Error: " + error); +// } +// for(String warning : warnings) { +// LOGGER.error("Warning: " + warning); +// } +// LOGGER.error("(Tessellator pos: ({}, {}, {}), Tessellation count: {}", t.xOffset, t.yOffset, t.zOffset, tesselatorDataCount); +// LOGGER.error("Stack trace:"); +// try { +// // Generate a stack trace +// throw new IllegalArgumentException(); +// } catch(IllegalArgumentException e) { +// e.printStackTrace(); +// } +// LOGGER.error("Skipping chunk due to errors."); +// quadBuf.reset(); +// } +// } +// } +// } + final List quads = quadBuf.getAsList(); + quadBuf.reset(); + return quads; } private void renderQuadList(BlockRenderView world, BlockState state, BlockPos pos, LightPipeline lighter, Vector3d offset, - ChunkModelBuffers buffers, List quads, ForgeDirection cullFace) { + ChunkModelBuffers buffers, List quads, ForgeDirection cullFace) { ModelQuadFacing facing = cullFace == null ? ModelQuadFacing.UNASSIGNED : ModelQuadFacing.fromDirection(cullFace); BlockColorProvider colorizer = null; @@ -130,12 +205,13 @@ private void renderQuadList(BlockRenderView world, BlockState state, BlockPos po // This is a very hot allocation, iterate over it manually // noinspection ForLoopReplaceableByForEach for (int i = 0, quadsSize = quads.size(); i < quadsSize; i++) { - BakedQuad quad = quads.get(i); + Quad quad = quads.get(i); QuadLightData light = this.cachedQuadLightData; lighter.calculate((ModelQuadView) quad, pos, light, cullFace, quad.getFace(), quad.hasShade()); - if (quad.hasColor() && colorizer == null) { + // TODO: Sodium - BlockColors + if (quad.hasColor() && colorizer == null && this.blockColors != null) { colorizer = this.blockColors.getColorProvider(state); } @@ -146,14 +222,14 @@ private void renderQuadList(BlockRenderView world, BlockState state, BlockPos po } private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, ModelVertexSink sink, Vector3d offset, - BlockColorProvider colorProvider, BakedQuad bakedQuad, QuadLightData light, ChunkRenderData.Builder renderData) { - ModelQuadView src = (ModelQuadView) bakedQuad; + BlockColorProvider colorProvider, Quad quad, QuadLightData light, ChunkRenderData.Builder renderData) { + ModelQuadView src = (ModelQuadView) quad; ModelQuadOrientation order = ModelQuadOrientation.orient(light.br); int[] colors = null; - if (bakedQuad.hasColor()) { + if (quad.hasColor()) { colors = this.biomeColorBlender.getColors(colorProvider, world, state, pos, src); } @@ -181,11 +257,51 @@ private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, M } } - private LightMode getLightingMode(BlockState state, BakedModel model, BlockRenderView world, BlockPos pos) { - if (this.useAmbientOcclusion && model.isAmbientOcclusion(state) && state.getLightValue(world, pos) == 0) { + private LightMode getLightingMode(BlockState state, BlockRenderView world, BlockPos pos) { + // TODO: Sodium: Ambient Occlusion + final Block block = state.getBlock(); + if (this.useAmbientOcclusion && block.getLightValue() == 0 && /*model.isAmbientOcclusion(state) &&*/ state.getLightValue(world, pos) == 0) { return LightMode.SMOOTH; } else { return LightMode.FLAT; } } + + public static class Flags { + boolean hasTexture; + public boolean hasBrightness; + public boolean hasColor; + boolean hasNormals; + + public Flags(byte flags) { + hasTexture = (flags & 1) != 0; + hasBrightness = (flags & 2) != 0; + hasColor = (flags & 4) != 0; + hasNormals = (flags & 8) != 0; + } + + public Flags(boolean hasTexture, boolean hasBrightness, boolean hasColor, boolean hasNormals) { + this.hasTexture = hasTexture; + this.hasBrightness = hasBrightness; + this.hasColor = hasColor; + this.hasNormals = hasNormals; + } + + public byte toByte() { + byte flags = 0; + if(hasTexture) { + flags |= 1; + } + if(hasBrightness) { + flags |= 2; + } + if(hasColor) { + flags |= 4; + } + if(hasNormals) { + flags |= 8; + } + return flags; + } + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/ChunkStatusListenerManager.java b/src/main/java/me/jellysquid/mods/sodium/client/world/IChunkProviderClientExt.java similarity index 66% rename from src/main/java/me/jellysquid/mods/sodium/client/world/ChunkStatusListenerManager.java rename to src/main/java/me/jellysquid/mods/sodium/client/world/IChunkProviderClientExt.java index 826e4ecc5..fca2d2440 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/ChunkStatusListenerManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/IChunkProviderClientExt.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.world; -public interface ChunkStatusListenerManager { +public interface IChunkProviderClientExt { // TODO: allow multiple listeners to be added? void setListener(ChunkStatusListener listener); + void doPostChunk(int x, int z); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index eeda5ff69..4e359a3dc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -11,6 +11,7 @@ import com.gtnewhorizons.angelica.compat.mojang.LightType; import com.gtnewhorizons.angelica.compat.mojang.LightingProvider; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; +import lombok.Getter; import me.jellysquid.mods.sodium.client.world.biome.BiomeCache; import me.jellysquid.mods.sodium.client.world.biome.BiomeColorCache; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; @@ -64,6 +65,7 @@ public class WorldSlice implements BlockRenderView, BiomeAccess.Storage { private static final int SECTION_TABLE_ARRAY_SIZE = TABLE_LENGTH * TABLE_LENGTH * TABLE_LENGTH; // The world this slice has copied data from + @Getter // Temp private final World world; // Local Section->BlockState table. @@ -93,8 +95,8 @@ public class WorldSlice implements BlockRenderView, BiomeAccess.Storage { private ChunkSectionPos origin; public static ChunkRenderContext prepare(World world, ChunkSectionPos origin, ClonedChunkSectionCache sectionCache) { - Chunk chunk = world.getChunkFromChunkCoords(origin.x, origin.z); - ExtendedBlockStorage section = chunk.getBlockStorageArray()[origin.y]; + final Chunk chunk = world.getChunkFromChunkCoords(origin.x, origin.z); + final ExtendedBlockStorage section = chunk.getBlockStorageArray()[origin.y]; // If the chunk section is absent or empty, simply terminate now. There will never be anything in this chunk // section to render, so we need to signal that a chunk render task shouldn't created. This saves a considerable @@ -185,6 +187,19 @@ private void unpackBlockData(BlockState[] states, ClonedChunkSection section, St } } + + private static void copyBlocks(BlockState[] states, ClonedChunkSection section, int minBlockY, int maxBlockY, int minBlockZ, int maxBlockZ, int minBlockX, int maxBlockX) { + for (int y = minBlockY; y <= maxBlockY; y++) { + for (int z = minBlockZ; z <= maxBlockZ; z++) { + for (int x = minBlockX; x <= maxBlockX; x++) { + final int blockIdx = getLocalBlockIndex(x & 15, y & 15, z & 15); + // TODO: Optimize Allocations - shared block states? get rid of block states? + states[blockIdx] = section.getBlockState(x & 15, y & 15, z & 15); + } + } + } + } + private void unpackBlockDataR(BlockState[] states, ClonedChunkSection section, StructureBoundingBox box) { ChunkSectionPos pos = section.getPosition(); @@ -197,19 +212,24 @@ private void unpackBlockDataR(BlockState[] states, ClonedChunkSection section, S int minBlockZ = Math.max(box.minZ, pos.getMinZ()); int maxBlockZ = Math.min(box.maxZ, pos.getMaxZ()); - for (int y = minBlockY; y <= maxBlockY; y++) { - for (int z = minBlockZ; z <= maxBlockZ; z++) { - for (int x = minBlockX; x <= maxBlockX; x++) { - int blockIdx = getLocalBlockIndex(x & 15, y & 15, z & 15); - states[blockIdx] = section.getBlockState(x & 15, y & 15, z & 15); - } - } - } + copyBlocks(states, section, minBlockY, maxBlockY, minBlockZ, maxBlockZ, minBlockX, maxBlockX); } private void unpackBlockDataZ(BlockState[] states, ClonedChunkSection section) { - // TODO: Sodium - BlockStates -// ((PackedIntegerArrayExtended) section.getBlockData()).copyUsingPalette(states, section.getBlockPalette()); + // TODO: Look into a faster copy for this? + final ChunkSectionPos pos = section.getPosition(); + + int minBlockX = pos.getMinX(); + int maxBlockX = pos.getMaxX(); + + int minBlockY = pos.getMinY(); + int maxBlockY = pos.getMaxY(); + + int minBlockZ = pos.getMinZ(); + int maxBlockZ = pos.getMaxZ(); + + // TODO: Can this be optimized? + copyBlocks(states, section, minBlockY, maxBlockY, minBlockZ, maxBlockZ, minBlockX, maxBlockX); } /** @@ -244,7 +264,17 @@ public FluidState getFluidState(BlockPos pos) { @Override public float getBrightness(ForgeDirection direction, boolean shaded) { - return ((BlockRenderView)this.world).getBrightness(direction, shaded); + boolean darkened = false; //this.getSkyProperties().isDarkened(); + if (!shaded) { + return darkened ? 0.9f : 1.0f; + } + return switch (direction) { + case DOWN -> darkened ? 0.9f : 0.5f; + case UP -> darkened ? 0.9f : 1.0f; + case NORTH, SOUTH -> 0.8f; + case WEST, EAST -> 0.6f; + default -> 1.0f; + }; } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java index 9b44abfb5..19dfd8d01 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java @@ -29,8 +29,7 @@ public StructureBoundingBox getVolume() { public void releaseResources() { for (ClonedChunkSection section : sections) { if (section != null) { - section.getBackingCache() - .release(section); + section.getBackingCache().release(section); } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index fa21cdd82..945548565 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -92,7 +92,7 @@ public void init(ChunkSectionPos pos) { public BlockState getBlockState(int x, int y, int z) { final Block block = data.getBlockByExtId(x, y, z); - if(block.isAir(world, x, y, z)) { + if(block.isAir(null, 0, 0, 0)) /* dumb api */ { return DEFAULT_BLOCK_STATE; } return new BlockState(data.getBlockByExtId(x, y, z), data.getExtBlockMetadata(x, y, z)); diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java b/src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java index c24c039d4..69c5e72fd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java @@ -37,7 +37,7 @@ private void findNext() { } } } - + @Override public T next() { if (!hasNext()) { From cf14a867df96d45dd9352a5919511098e3318419 Mon Sep 17 00:00:00 2001 From: makamys Date: Sun, 12 Nov 2023 06:23:43 +0100 Subject: [PATCH 047/301] Apply model-view matrix (fixes camera transform) --- .../mods/sodium/client/render/GameRendererContext.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java index 7bb288f67..a2c2d4236 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java @@ -9,18 +9,16 @@ public class GameRendererContext { /** - * TODO: Not accurate - * Obtains a model-view-projection matrix by multiplying the projection matrix with the model-view matrix - * from {@param matrices}. - * - * The returned buffer is only valid for the lifetime of {@param stack}. + * Obtains a model-view-projection matrix by multiplying the projection matrix with the model-view matrix. * * @return A float-buffer on the stack containing the model-view-projection matrix in a format suitable for * uploading as uniform state */ + // TODO get rid of matrices, it's unnecessary in 1.7 public static FloatBuffer getModelViewProjectionMatrix(MatrixStack.Entry matrices) { final FloatBuffer bufModelViewProjection = BufferUtils.createFloatBuffer(16); final Matrix4f matrix = new Matrix4f(RenderingState.INSTANCE.getProjectionMatrix()); + matrix.mul(RenderingState.INSTANCE.getModelViewMatrix()); matrix.mul(matrices.getModel()); matrix.get(bufModelViewProjection); From 62bbdf48b96ae72692e9d4847cfbc9d828105778 Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 17 Nov 2023 08:26:52 +0100 Subject: [PATCH 048/301] Fix quad coordinate offsets --- .../mods/sodium/client/render/pipeline/BlockRenderer.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index 322f204e6..e120de2d3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -111,7 +111,7 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende // } this.random.setSeed(seed); - List all = tesselatorToBakedQuadList(tessellator); + List all = tesselatorToBakedQuadList(tessellator, pos); // List all = model.getQuads(state, null, this.random, modelData); @@ -128,7 +128,7 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende private static final Flags FLAGS = new Flags(true, true, true, false); private static RecyclingList quadBuf = new RecyclingList<>(Quad::new); private int tesselatorDataCount; - private List tesselatorToBakedQuadList(Tessellator t) { + private List tesselatorToBakedQuadList(Tessellator t, BlockPos pos) { // Temporarily borrowed/badly adapted from Neodymium tesselatorDataCount++; @@ -156,7 +156,8 @@ private List tesselatorToBakedQuadList(Tessellator t) { for(int quadI = 0; quadI < t.vertexCount / verticesPerPrimitive; quadI++) { Quad quad = quadBuf.next(); - quad.setState(t.rawBuffer, quadI * (verticesPerPrimitive * 8), FLAGS, t.drawMode, (float)-t.xOffset, (float)-t.yOffset, (float)-t.zOffset); + // RenderBlocks adds the subchunk-relative coordinates as the offset, cancel it out here + quad.setState(t.rawBuffer, quadI * (verticesPerPrimitive * 8), FLAGS, t.drawMode, -pos.x, -pos.y, -pos.z); if(quad.deleted) { quadBuf.remove(); } From c71bfe6055f64d82bd3f4afe20a0feb6b652cb3f Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 17 Nov 2023 08:31:35 +0100 Subject: [PATCH 049/301] Enable rendering of all columns --- .../client/render/chunk/tasks/ChunkRenderRebuildTask.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 1704c962b..8c2d5928d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -116,9 +116,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB ForgeHooksClientExt.setRenderLayer(layer); - if(!(relX == 0 && relZ == 0)) { - continue; - } + /* Test quads from Makamys if(relX == 0 && relZ == 0) { // test quad From 52d43578dccba39ebe412631ba37502bfbc08647 Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 17 Nov 2023 08:52:09 +0100 Subject: [PATCH 050/301] Fix textures not rendering --- .../com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java | 2 +- .../me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index 4881cf51c..b2ff9dbfc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -669,7 +669,7 @@ public Texture(ResourceLocation id, boolean bilinear, boolean mipmap) { GLStateManager.enableTexture(); TextureManager lv = Minecraft.getMinecraft().getTextureManager(); lv.bindTexture(id); - GLStateManager.setFilter(bilinear, mipmap); // breaks textures. TODO find out why + //GLStateManager.setFilter(bilinear, mipmap); // breaks textures. TODO find out why }, () -> { }); this.id = Optional.of(id); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java index d0afedee0..90530ca6c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java @@ -24,7 +24,7 @@ public static float getFogDensity() { * Retrieves the current fog mode from the fixed-function pipeline. */ public static ChunkFogMode getFogMode() { - int mode = GLStateManager.getFog().fogMode; + int mode = 0; //GLStateManager.getFog().fogMode; // TODO fix fog if(mode == 0 || !GLStateManager.getFog().mode.isEnabled()) return ChunkFogMode.NONE; From 7a2bcfb624e6605b49a7f25090ee4396a985dd13 Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 17 Nov 2023 08:54:23 +0100 Subject: [PATCH 051/301] Use quad colors --- .../client/model/quad/blender/FlatBiomeColorBlender.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java index 14d389884..58bf6b98f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java @@ -18,6 +18,8 @@ public int[] getColors(BlockColorProvider colorizer, BlockRenderView world, Bloc // TODO: Sodium - Colorizer // Arrays.fill(this.cachedRet, ColorARGB.toABGR(colorizer.getColor(state, world, origin, quad.getColorIndex()))); - return this.cachedRet; +// return this.cachedRet; + + return new int[] {quad.getColor(0), quad.getColor(1), quad.getColor(2), quad.getColor(3)}; } } From 52b82080f9da2c676dc03cd5fd9316b80573d88c Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 17 Nov 2023 09:21:14 -0800 Subject: [PATCH 052/301] ThreadedTessellator -> RenderBlocks instance Tessellator * Plus a CME workaround until I can figure out why it's happening --- .../angelica/compat/nd/RecyclingList.java | 7 +- .../early/angelica/MixinRenderBlocks.java | 24 +++++- .../mixins/interfaces/IHasTessellator.java | 8 ++ .../angelica/proxy/ClientProxy.java | 3 +- .../rendering/ThreadedTesselatorHelper.java | 22 ------ .../chunk/tasks/ChunkRenderRebuildTask.java | 12 +-- .../client/render/pipeline/BlockRenderer.java | 78 +++++++++---------- 7 files changed, 75 insertions(+), 79 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasTessellator.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/rendering/ThreadedTesselatorHelper.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java index ba5bd851d..02168341d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java @@ -10,11 +10,11 @@ public class RecyclingList { private Supplier constructor; int nextIndex; - private List list; + private final List list; public RecyclingList(Supplier constructor) { this.constructor = constructor; - this.list = new ArrayList(); + this.list = new ArrayList<>(); } public T get(int i) { @@ -44,6 +44,7 @@ public void reset() { } public List getAsList() { - return list.subList(0, nextIndex); + // CME workaround.. + return new ArrayList<>(list.subList(0, nextIndex)); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java index 6d68b52e2..08520f5e5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java @@ -1,18 +1,36 @@ package com.gtnewhorizons.angelica.mixins.early.angelica; -import com.gtnewhorizons.angelica.rendering.ThreadedTesselatorHelper; +import com.gtnewhorizons.angelica.mixins.interfaces.IHasTessellator; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.Tessellator; +import net.minecraft.world.IBlockAccess; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(RenderBlocks.class) -public class MixinRenderBlocks { +public class MixinRenderBlocks implements IHasTessellator { + private Tessellator sodium$tessellator; + + @Override + public Tessellator getTessellator() { + return sodium$tessellator; + } + + @Inject(method = "(Lnet/minecraft/world/IBlockAccess;)V", at = @At("TAIL")) + private void initTessellator(IBlockAccess world, CallbackInfo ci) { + sodium$tessellator = new Tessellator(); + } + @Inject(method = "()V", at = @At("TAIL")) + private void initTessellator(CallbackInfo ci) { + sodium$tessellator = new Tessellator(); + } @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;instance:Lnet/minecraft/client/renderer/Tessellator;")) private Tessellator modifyTessellatorAccess() { - return ThreadedTesselatorHelper.instance.getThreadTessellator(); + return sodium$tessellator; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasTessellator.java new file mode 100644 index 000000000..03c764e40 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasTessellator.java @@ -0,0 +1,8 @@ +package com.gtnewhorizons.angelica.mixins.interfaces; + +import net.minecraft.client.renderer.Tessellator; + +public interface IHasTessellator { + Tessellator getTessellator(); + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index 6865ca26f..dcf2931df 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -1,7 +1,6 @@ package com.gtnewhorizons.angelica.proxy; import com.gtnewhorizons.angelica.client.gui.AngelicaVideoSettings; -import com.gtnewhorizons.angelica.rendering.ThreadedTesselatorHelper; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import jss.notfine.gui.GuiCustomMenu; @@ -21,6 +20,6 @@ public void preInit(FMLPreInitializationEvent event) { @Override public void init(FMLInitializationEvent event) { - ThreadedTesselatorHelper.instance.init(); + // Nothing to do here (yet) } } diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/ThreadedTesselatorHelper.java b/src/main/java/com/gtnewhorizons/angelica/rendering/ThreadedTesselatorHelper.java deleted file mode 100644 index b5db67d4c..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/rendering/ThreadedTesselatorHelper.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gtnewhorizons.angelica.rendering; - -import net.minecraft.client.renderer.Tessellator; - -public class ThreadedTesselatorHelper { - public static ThreadedTesselatorHelper instance = new ThreadedTesselatorHelper(); - public static Thread MAIN_THREAD; - public ThreadLocal threadTessellator = ThreadLocal.withInitial(Tessellator::new); - - public void init() { - MAIN_THREAD = Thread.currentThread(); - } - - public Tessellator getThreadTessellator() { - if(Thread.currentThread() == MAIN_THREAD) { - return Tessellator.instance; - } else { - return threadTessellator.get(); - } - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 8c2d5928d..e65462c1f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -8,7 +8,7 @@ import com.gtnewhorizons.angelica.compat.mojang.FluidState; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.compat.mojang.RenderLayers; -import com.gtnewhorizons.angelica.rendering.ThreadedTesselatorHelper; +import com.gtnewhorizons.angelica.mixins.interfaces.IHasTessellator; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer; @@ -76,7 +76,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB // TODO: Sodium - WorldSlice probably needs to implement IWorldAccess and redirect to the slice/chunk cache WorldSlice slice = cache.getWorldSlice(); // Gross - RenderBlocks renderBlocks = new RenderBlocks(slice.getWorld()); + final RenderBlocks renderBlocks = new RenderBlocks(slice.getWorld()); int baseX = this.render.getOriginX(); int baseY = this.render.getOriginY(); @@ -84,7 +84,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB BlockPos.Mutable pos = new BlockPos.Mutable(); BlockPos renderOffset = this.offset; - final Tessellator tessellator = ThreadedTesselatorHelper.instance.getThreadTessellator(); + final Tessellator tessellator = ((IHasTessellator)renderBlocks).getTessellator(); for (int relY = 0; relY < 16; relY++) { if (cancellationSource.isCancelled()) { @@ -146,9 +146,9 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB // BakedModel model = cache.getBlockModels().getModel(blockState); // long seed = blockState.getRenderingSeed(pos); - // hax -- why is the reset needed here? - tessellator.isDrawing = false; - tessellator.reset(); +// // hax -- why is the reset needed here? +// tessellator.isDrawing = false; +// tessellator.reset(); tessellator.startDrawingQuads(); if (cache.getBlockRenderer().renderModel(cache.getLocalSlice(), tessellator, renderBlocks, blockState, pos, buffers.get(layer), true, seed)) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index e120de2d3..fe7a417c2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -1,12 +1,12 @@ package me.jellysquid.mods.sodium.client.render.pipeline; -import com.gtnewhorizons.angelica.compat.nd.Quad; import com.gtnewhorizons.angelica.compat.forge.ForgeBlockRenderer; import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.nd.Quad; import com.gtnewhorizons.angelica.compat.nd.RecyclingList; import me.jellysquid.mods.sodium.client.model.light.LightMode; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; @@ -33,7 +33,6 @@ import org.joml.Vector3d; import org.lwjgl.opengl.GL11; -import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -132,23 +131,23 @@ private List tesselatorToBakedQuadList(Tessellator t, BlockPos pos) { // Temporarily borrowed/badly adapted from Neodymium tesselatorDataCount++; - List errors = new ArrayList<>(); - List warnings = new ArrayList<>(); - if(t.drawMode != GL11.GL_QUADS && t.drawMode != GL11.GL_TRIANGLES) { - errors.add("Unsupported draw mode: " + t.drawMode); - } - if(!t.hasTexture) { - errors.add("Texture data is missing."); - } - if(!t.hasBrightness) { - warnings.add("Brightness data is missing"); - } - if(!t.hasColor) { - warnings.add("Color data is missing"); - } - if(t.hasNormals && GL11.glIsEnabled(GL11.GL_LIGHTING)) { - errors.add("Chunk uses GL lighting, this is not implemented."); - } +// List errors = new ArrayList<>(); +// List warnings = new ArrayList<>(); +// if(t.drawMode != GL11.GL_QUADS && t.drawMode != GL11.GL_TRIANGLES) { +// errors.add("Unsupported draw mode: " + t.drawMode); +// } +// if(!t.hasTexture) { +// errors.add("Texture data is missing."); +// } +// if(!t.hasBrightness) { +// warnings.add("Brightness data is missing"); +// } +// if(!t.hasColor) { +// warnings.add("Color data is missing"); +// } +// if(t.hasNormals && GL11.glIsEnabled(GL11.GL_LIGHTING)) { +// errors.add("Chunk uses GL lighting, this is not implemented."); +// } FLAGS.hasBrightness = t.hasBrightness; FLAGS.hasColor = t.hasColor; @@ -162,30 +161,22 @@ private List tesselatorToBakedQuadList(Tessellator t, BlockPos pos) { quadBuf.remove(); } } - -// if(!quadBuf.isEmpty()) { -// // Only show errors if we're actually supposed to be drawing something -// if(!errors.isEmpty() || !warnings.isEmpty()) { -// if(/*!Config.silenceErrors*/true ) { -// if(!errors.isEmpty()) { -// for(String error : errors) { -// LOGGER.error("Error: " + error); -// } -// for(String warning : warnings) { -// LOGGER.error("Warning: " + warning); -// } -// LOGGER.error("(Tessellator pos: ({}, {}, {}), Tessellation count: {}", t.xOffset, t.yOffset, t.zOffset, tesselatorDataCount); -// LOGGER.error("Stack trace:"); -// try { -// // Generate a stack trace -// throw new IllegalArgumentException(); -// } catch(IllegalArgumentException e) { -// e.printStackTrace(); -// } -// LOGGER.error("Skipping chunk due to errors."); -// quadBuf.reset(); -// } -// } +// final boolean silenceErrors = false; +// +// if(!quadBuf.isEmpty() && (!errors.isEmpty() || !warnings.isEmpty()) && /*!Config.silenceErrors*/!silenceErrors) { +// for(String error : errors) { +// LOGGER.error("Error: " + error); +// } +// for(String warning : warnings) { +// LOGGER.error("Warning: " + warning); +// } +// LOGGER.error("(Tessellator pos: ({}, {}, {}), Tessellation count: {}", t.xOffset, t.yOffset, t.zOffset, tesselatorDataCount); +// LOGGER.error("Stack trace:"); +// try { +// // Generate a stack trace +// throw new IllegalArgumentException(); +// } catch(IllegalArgumentException e) { +// e.printStackTrace(); // } // } final List quads = quadBuf.getAsList(); @@ -206,6 +197,7 @@ private void renderQuadList(BlockRenderView world, BlockState state, BlockPos po // This is a very hot allocation, iterate over it manually // noinspection ForLoopReplaceableByForEach for (int i = 0, quadsSize = quads.size(); i < quadsSize; i++) { + // CME here if we don't return a copy.... why... Quad quad = quads.get(i); QuadLightData light = this.cachedQuadLightData; From 7b4141d7e09bbe341445feb7a46e7d2ff86829dc Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 17 Nov 2023 09:43:39 -0800 Subject: [PATCH 053/301] One inject with multiple methods instead of two injects --- .../angelica/mixins/early/angelica/MixinRenderBlocks.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java index 08520f5e5..42ecdfa2f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java @@ -3,7 +3,6 @@ import com.gtnewhorizons.angelica.mixins.interfaces.IHasTessellator; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.Tessellator; -import net.minecraft.world.IBlockAccess; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -19,11 +18,7 @@ public Tessellator getTessellator() { return sodium$tessellator; } - @Inject(method = "(Lnet/minecraft/world/IBlockAccess;)V", at = @At("TAIL")) - private void initTessellator(IBlockAccess world, CallbackInfo ci) { - sodium$tessellator = new Tessellator(); - } - @Inject(method = "()V", at = @At("TAIL")) + @Inject(method = {"()V","(Lnet/minecraft/world/IBlockAccess;)V"}, at = @At("TAIL")) private void initTessellator(CallbackInfo ci) { sodium$tessellator = new Tessellator(); } From 6c292abe96fff5252c4883d4ca9e5bd5ab0b0534 Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 17 Nov 2023 22:12:36 +0100 Subject: [PATCH 054/301] Add AF's Tessellator#reset mixin Fixes screen flashing when chunks are being built --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../early/angelica/MixinTessellator.java | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinTessellator.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 9b1fdecba..43bfc1b1c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -13,6 +13,7 @@ public enum Mixins { .setPhase(Phase.EARLY).addMixinClasses( "angelica.MixinEntityRenderer" ,"angelica.MixinRenderBlocks" + ,"angelica.MixinTessellator" ) ), IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinTessellator.java new file mode 100644 index 000000000..8c6fb0b9f --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinTessellator.java @@ -0,0 +1,23 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica; + +import java.nio.Buffer; +import java.nio.ByteBuffer; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.client.renderer.Tessellator; + +@Mixin(Tessellator.class) +abstract class MixinTessellator { + /** @reason Allow using multiple tessellator instances concurrently by removing static field access in alternate + * instances. */ + @Redirect(method = "reset", at = @At(value = "INVOKE", target = "Ljava/nio/ByteBuffer;clear()Ljava/nio/Buffer;")) + private Buffer removeStaticBufferAccessOutsideSingleton(ByteBuffer buffer) { + if(((Object)this) == Tessellator.instance) { + return buffer.clear(); + } + return buffer; + } +} From 06328cce7bbc73d5a68895122d9f3d6b3f68bb4c Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 17 Nov 2023 13:59:21 -0800 Subject: [PATCH 055/301] Thread Saftey * Make each tesselator use its own ByteBuffer * Don't make RecyclingList a static variable :facepalm: * Add some additions via ITessellatorInstance --- .../angelica/compat/nd/RecyclingList.java | 3 +- .../gtnewhorizons/angelica/mixins/Mixins.java | 2 +- .../early/angelica/MixinTessellator.java | 23 --- .../mixins/early/sodium/MixinTessellator.java | 131 ++++++++++++++++++ .../interfaces/ITessellatorInstance.java | 13 ++ .../chunk/tasks/ChunkRenderRebuildTask.java | 34 +---- .../client/render/pipeline/BlockRenderer.java | 6 +- 7 files changed, 151 insertions(+), 61 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinTessellator.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ITessellatorInstance.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java index 02168341d..0bb37785b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java @@ -44,7 +44,6 @@ public void reset() { } public List getAsList() { - // CME workaround.. - return new ArrayList<>(list.subList(0, nextIndex)); + return list.subList(0, nextIndex); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 43bfc1b1c..5baaca721 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -13,7 +13,6 @@ public enum Mixins { .setPhase(Phase.EARLY).addMixinClasses( "angelica.MixinEntityRenderer" ,"angelica.MixinRenderBlocks" - ,"angelica.MixinTessellator" ) ), IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) @@ -38,6 +37,7 @@ public enum Mixins { ,"sodium.MixinNetHandlerPlayClient" ,"sodium.MixinNibbleArray" ,"sodium.MixinRenderGlobal" + ,"sodium.MixinTessellator" ,"sodium.MixinWorldClient" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinTessellator.java deleted file mode 100644 index 8c6fb0b9f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinTessellator.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.angelica; - -import java.nio.Buffer; -import java.nio.ByteBuffer; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import net.minecraft.client.renderer.Tessellator; - -@Mixin(Tessellator.class) -abstract class MixinTessellator { - /** @reason Allow using multiple tessellator instances concurrently by removing static field access in alternate - * instances. */ - @Redirect(method = "reset", at = @At(value = "INVOKE", target = "Ljava/nio/ByteBuffer;clear()Ljava/nio/Buffer;")) - private Buffer removeStaticBufferAccessOutsideSingleton(ByteBuffer buffer) { - if(((Object)this) == Tessellator.instance) { - return buffer.clear(); - } - return buffer; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java new file mode 100644 index 000000000..91c80b253 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java @@ -0,0 +1,131 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.mixins.interfaces.ITessellatorInstance; +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.client.renderer.Tessellator; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; + +@Mixin(Tessellator.class) +public abstract class MixinTessellator implements ITessellatorInstance { + @Shadow public int[] rawBuffer; + @Shadow public int vertexCount; + @Shadow public boolean isDrawing; + @Shadow(remap = false) public boolean defaultTexture; + @Shadow(remap = false) private int rawBufferSize; + @Shadow(remap = false) public int textureID; + @Shadow static ByteBuffer byteBuffer; + @Shadow private static IntBuffer intBuffer; + @Shadow private static FloatBuffer floatBuffer; + @Shadow private static ShortBuffer shortBuffer; + + private ByteBuffer angelica$byteBuffer; + private IntBuffer angelica$intBuffer; + private FloatBuffer angelica$floatBuffer; + private ShortBuffer angelica$shortBuffer; + public float[] angelica$vertexPos; + public float angelica$normalX; + public float angelica$normalY; + public float angelica$normalZ; + public float angelica$midTextureU; + public float angelica$midTextureV; + + @Shadow public abstract void reset(); + @Inject(method = "", at = @At("TAIL")) + private static void killStaticBuffer(CallbackInfo ci) { + byteBuffer = null; + intBuffer = null; + floatBuffer = null; + shortBuffer = null; + } + + @Inject(method = "(I)V", at = @At("TAIL")) + private void angelica$extendBufferConstructor(int bufferSize, CallbackInfo ci) { + angelica$byteBuffer = GLAllocation.createDirectByteBuffer(bufferSize * 4); + angelica$intBuffer = angelica$byteBuffer.asIntBuffer(); + angelica$floatBuffer = angelica$byteBuffer.asFloatBuffer(); + angelica$shortBuffer = angelica$byteBuffer.asShortBuffer(); + rawBuffer = new int[bufferSize]; + vertexCount = 0; + angelica$vertexPos = new float[16]; + } + + @Inject(method = "()V", at = @At("TAIL")) + private void angelica$extendEmptyConstructor(CallbackInfo ci) { + this.angelica$extendBufferConstructor(65536, null); + this.defaultTexture = false; + this.rawBufferSize = 0; + this.textureID = 0; + } + + @Inject(method = "setNormal(FFF)V", at = @At("HEAD")) + private void angelica$captureNormalComponents(float x, float y, float z, CallbackInfo ci) { + this.angelica$normalX = x; + this.angelica$normalY = y; + this.angelica$normalZ = z; + } + + // Redirect static buffer access to the instance buffers + @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;byteBuffer:Ljava/nio/ByteBuffer;")) + private ByteBuffer modifyByteBufferAccess() { + return this.angelica$byteBuffer; + } + @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;intBuffer:Ljava/nio/IntBuffer;")) + private IntBuffer modifyIntBufferAccess() { + return this.angelica$intBuffer; + } + @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;floatBuffer:Ljava/nio/FloatBuffer;")) + private FloatBuffer modifyFloatBufferAccess() { + return this.angelica$floatBuffer; + } + @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;shortBuffer:Ljava/nio/ShortBuffer;")) + private ShortBuffer modifyShortBufferAccess() { + return this.angelica$shortBuffer; + } + + + // New methods from ITesselatorInstance + + @Override + public float getNormalX() { + return angelica$normalX; + } + + @Override + public float getNormalY() { + return angelica$normalY; + } + + @Override + public float getNormalZ() { + return angelica$normalZ; + } + + @Override + public void discard() { + isDrawing = false; + reset(); + } + + @Override + public float getMidTextureU() { + return angelica$midTextureU; + } + + @Override + public float getMidTextureV() { + return angelica$midTextureV; + } + + + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ITessellatorInstance.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ITessellatorInstance.java new file mode 100644 index 000000000..983870a3c --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ITessellatorInstance.java @@ -0,0 +1,13 @@ +package com.gtnewhorizons.angelica.mixins.interfaces; + +public interface ITessellatorInstance { + float getNormalX(); + float getNormalY(); + float getNormalZ(); + + float getMidTextureU(); + + float getMidTextureV(); + + void discard(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index e65462c1f..ad94f2791 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -9,6 +9,7 @@ import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.compat.mojang.RenderLayers; import com.gtnewhorizons.angelica.mixins.interfaces.IHasTessellator; +import com.gtnewhorizons.angelica.mixins.interfaces.ITessellatorInstance; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer; @@ -112,51 +113,20 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB // Need an equivalent renderpass check // if (!block.canRenderInPass(pass)) continue; -// boolean rendered = renderBlocks.renderBlockByRenderType(block, pos.x, pos.y, pos.z); - - ForgeHooksClientExt.setRenderLayer(layer); - /* Test quads from Makamys - if(relX == 0 && relZ == 0) { - // test quad - ChunkModelBuffers buf = buffers.get(RenderLayer.solid()); - ModelVertexSink sink = buf.getSink(ModelQuadFacing.UP); - int x = 0; - int y = 0; - int z = 0; - int color = 0xFFFFFFFF; - int light = 15728640; - float u0 = 0; - float v0 = 0; - float u1 = 1; - float v1 = 1; - sink.writeQuad(x + 0, y + 0, z + 1, color, u0, v1, light); - sink.writeQuad(x + 1, y + 0, z + 1, color, u1, v1, light); - sink.writeQuad(x + 1, y + 0, z + 0, color, u1, v0, light); - sink.writeQuad(x + 0, y + 0, z + 0, color, u0, v0, light); - - sink.flush(); - } - */ - // TODO: RenderBlocks & capture tesselator state into quads // IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); // // BakedModel model = cache.getBlockModels().getModel(blockState); // long seed = blockState.getRenderingSeed(pos); -// // hax -- why is the reset needed here? -// tessellator.isDrawing = false; -// tessellator.reset(); tessellator.startDrawingQuads(); if (cache.getBlockRenderer().renderModel(cache.getLocalSlice(), tessellator, renderBlocks, blockState, pos, buffers.get(layer), true, seed)) { bounds.addBlock(relX, relY, relZ); } - - tessellator.isDrawing = false; - tessellator.reset(); + ((ITessellatorInstance) tessellator).discard(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index fe7a417c2..9b8589df0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -54,6 +54,9 @@ public class BlockRenderer { private final boolean useAmbientOcclusion; + private final Flags FLAGS = new Flags(true, true, true, false); + private final RecyclingList quadBuf = new RecyclingList<>(Quad::new); + public BlockRenderer(Minecraft client, LightPipelineProvider lighters, BiomeColorBlender biomeColorBlender) { // TODO: Sodium - Block Colors this.blockColors = (BlockColorsExtended) null; //client.getBlockColors(); @@ -124,8 +127,6 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende return rendered; } - private static final Flags FLAGS = new Flags(true, true, true, false); - private static RecyclingList quadBuf = new RecyclingList<>(Quad::new); private int tesselatorDataCount; private List tesselatorToBakedQuadList(Tessellator t, BlockPos pos) { // Temporarily borrowed/badly adapted from Neodymium @@ -197,7 +198,6 @@ private void renderQuadList(BlockRenderView world, BlockState state, BlockPos po // This is a very hot allocation, iterate over it manually // noinspection ForLoopReplaceableByForEach for (int i = 0, quadsSize = quads.size(); i < quadsSize; i++) { - // CME here if we don't return a copy.... why... Quad quad = quads.get(i); QuadLightData light = this.cachedQuadLightData; From ef292167fdc191d69a28c11ce53ed10e66e8ac02 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 17 Nov 2023 14:51:04 -0800 Subject: [PATCH 056/301] Small fixes * Stop using builtin updateRenderers * Remove a few unused things in MixinTessellator * Remove useless casting due to implementing the interface --- .../early/sodium/MixinRenderGlobal.java | 9 +++++++++ .../mixins/early/sodium/MixinTessellator.java | 15 +++------------ .../client/render/pipeline/BlockRenderer.java | 19 +++++++++---------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index fbcc3e979..d097f62cc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -52,6 +52,15 @@ public void scheduleTerrainUpdate() { } } + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public boolean updateRenderers(EntityLivingBase e, boolean b){ + return true; + } + /** * @author Sodium * @reason Redirect to our renderer diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java index 91c80b253..425ea5786 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java @@ -17,12 +17,9 @@ @Mixin(Tessellator.class) public abstract class MixinTessellator implements ITessellatorInstance { - @Shadow public int[] rawBuffer; + @Shadow private static int nativeBufferSize; @Shadow public int vertexCount; @Shadow public boolean isDrawing; - @Shadow(remap = false) public boolean defaultTexture; - @Shadow(remap = false) private int rawBufferSize; - @Shadow(remap = false) public int textureID; @Shadow static ByteBuffer byteBuffer; @Shadow private static IntBuffer intBuffer; @Shadow private static FloatBuffer floatBuffer; @@ -32,7 +29,6 @@ public abstract class MixinTessellator implements ITessellatorInstance { private IntBuffer angelica$intBuffer; private FloatBuffer angelica$floatBuffer; private ShortBuffer angelica$shortBuffer; - public float[] angelica$vertexPos; public float angelica$normalX; public float angelica$normalY; public float angelica$normalZ; @@ -54,17 +50,12 @@ private static void killStaticBuffer(CallbackInfo ci) { angelica$intBuffer = angelica$byteBuffer.asIntBuffer(); angelica$floatBuffer = angelica$byteBuffer.asFloatBuffer(); angelica$shortBuffer = angelica$byteBuffer.asShortBuffer(); - rawBuffer = new int[bufferSize]; - vertexCount = 0; - angelica$vertexPos = new float[16]; + this.isDrawing = false; } @Inject(method = "()V", at = @At("TAIL")) private void angelica$extendEmptyConstructor(CallbackInfo ci) { - this.angelica$extendBufferConstructor(65536, null); - this.defaultTexture = false; - this.rawBufferSize = 0; - this.textureID = 0; + this.angelica$extendBufferConstructor(nativeBufferSize, null); } @Inject(method = "setNormal(FFF)V", at = @At("HEAD")) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index 9b8589df0..f22e1ec26 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -216,34 +216,33 @@ private void renderQuadList(BlockRenderView world, BlockState state, BlockPos po private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, ModelVertexSink sink, Vector3d offset, BlockColorProvider colorProvider, Quad quad, QuadLightData light, ChunkRenderData.Builder renderData) { - ModelQuadView src = (ModelQuadView) quad; ModelQuadOrientation order = ModelQuadOrientation.orient(light.br); int[] colors = null; if (quad.hasColor()) { - colors = this.biomeColorBlender.getColors(colorProvider, world, state, pos, src); + colors = this.biomeColorBlender.getColors(colorProvider, world, state, pos, quad); } for (int dstIndex = 0; dstIndex < 4; dstIndex++) { int srcIndex = order.getVertexIndex(dstIndex); - float x = src.getX(srcIndex) + (float) offset.x; - float y = src.getY(srcIndex) + (float) offset.y; - float z = src.getZ(srcIndex) + (float) offset.z; + float x = quad.getX(srcIndex) + (float) offset.x; + float y = quad.getY(srcIndex) + (float) offset.y; + float z = quad.getZ(srcIndex) + (float) offset.z; - int color = ColorABGR.mul(colors != null ? colors[srcIndex] : src.getColor(srcIndex), light.br[srcIndex]); + int color = ColorABGR.mul(colors != null ? colors[srcIndex] : quad.getColor(srcIndex), light.br[srcIndex]); - float u = src.getTexU(srcIndex); - float v = src.getTexV(srcIndex); + float u = quad.getTexU(srcIndex); + float v = quad.getTexV(srcIndex); - int lm = ModelQuadUtil.mergeBakedLight(src.getLight(srcIndex), light.lm[srcIndex]); + int lm = ModelQuadUtil.mergeBakedLight(quad.getLight(srcIndex), light.lm[srcIndex]); sink.writeQuad(x, y, z, color, u, v, lm); } - TextureAtlasSprite sprite = src.rubidium$getSprite(); + TextureAtlasSprite sprite = quad.rubidium$getSprite(); if (sprite != null) { renderData.addSprite(sprite); From ca1ea0b02749ede1a5462a1666b22c37c84a8f5c Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 17 Nov 2023 16:13:51 -0800 Subject: [PATCH 057/301] Overwrite some more rendering methods to ensure they're not used --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../early/sodium/MixinRenderGlobal.java | 47 +++++++++++++++++-- .../mixins/early/sodium/MixinTessellator.java | 2 +- .../early/sodium/MixinWorldRenderer.java | 30 ++++++++++++ 4 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldRenderer.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 5baaca721..9e86e1b8a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -39,6 +39,7 @@ public enum Mixins { ,"sodium.MixinRenderGlobal" ,"sodium.MixinTessellator" ,"sodium.MixinWorldClient" + ,"sodium.MixinWorldRenderer" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index d097f62cc..9065d948d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -10,9 +10,11 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.client.renderer.culling.ICamera; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.Blocks; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; @@ -23,11 +25,18 @@ import java.util.List; -@Mixin(RenderGlobal.class) +// Let other mixins apply, and then overwrite them +@Mixin(value = RenderGlobal.class, priority = 2000) public class MixinRenderGlobal implements IRenderGlobalExt { + @Shadow public int renderChunksWide; + @Shadow public int renderChunksTall; + @Shadow public int renderChunksDeep; + @Shadow public WorldClient theWorld; + @Shadow public Minecraft mc; + @Shadow public int renderDistanceChunks; + @Shadow public WorldRenderer[] worldRenderers; + @Shadow public WorldRenderer[] sortedWorldRenderers; - @Shadow - public Minecraft mc; @Unique private SodiumWorldRenderer renderer; private int sodium$frame; @@ -52,7 +61,7 @@ public void scheduleTerrainUpdate() { } } - /** + /** * @author Sodium * @reason Redirect to our renderer */ @@ -112,6 +121,17 @@ public void clipRenderersByFrustum(ICamera frustrum, float partialTicks) { } } + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public void markBlocksForUpdate(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + // scheduleBlockRenders + this.renderer.scheduleRebuildForBlockArea(minX, minY, minZ, maxX, maxY, maxZ, false); + } + + /** * @author Sodium * @reason Redirect to our renderer @@ -152,4 +172,23 @@ private void onReload(CallbackInfo ci) { RenderDevice.exitManagedCode(); } } + + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public void loadRenderers() { + if (this.theWorld == null) return; + Blocks.leaves.setGraphicsLevel(this.mc.gameSettings.fancyGraphics); + Blocks.leaves2.setGraphicsLevel(this.mc.gameSettings.fancyGraphics); + this.renderDistanceChunks = this.mc.gameSettings.renderDistanceChunks; + this.worldRenderers = null; + this.sortedWorldRenderers = null; + + this.renderChunksWide = 0; + this.renderChunksTall = 0; + this.renderChunksDeep = 0; + } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java index 425ea5786..37dc48a4b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java @@ -17,7 +17,7 @@ @Mixin(Tessellator.class) public abstract class MixinTessellator implements ITessellatorInstance { - @Shadow private static int nativeBufferSize; + @Shadow(remap=false) private static int nativeBufferSize; @Shadow public int vertexCount; @Shadow public boolean isDrawing; @Shadow static ByteBuffer byteBuffer; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldRenderer.java new file mode 100644 index 000000000..fa5a18453 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldRenderer.java @@ -0,0 +1,30 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.entity.EntityLivingBase; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +// Let other mixins apply, and then overwrite them +@Mixin(value=WorldRenderer.class, priority = 2000) +public class MixinWorldRenderer { + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public void updateRenderer(EntityLivingBase e){ + // Do nothing + } + + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public void updateRendererSort(EntityLivingBase e){ + // Do nothing + } + + +} From bd42a0acf1ced994c540b68d59ebb820e83075fe Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 17 Nov 2023 16:23:03 -0800 Subject: [PATCH 058/301] Overwrite some more rendering methods to ensure they're not used --- .../early/sodium/MixinRenderGlobal.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 9065d948d..c8319db03 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -61,6 +61,42 @@ public void scheduleTerrainUpdate() { } } + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public int renderSortedRenderers(int x, int z, int pass, double partialTicks) { + // Do nothing + return 0; + } + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public void renderAllRenderLists(int pass, double partialTicks) { + // Do nothing + } + + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + private void checkOcclusionQueryResult(int x, int z) { + // Do nothing + } + + /** + * @author Sodium + * @reason Redirect to our renderer + */ + @Overwrite + public void markRenderersForNewPosition(int p_72722_1_, int p_72722_2_, int p_72722_3_) { + // Do nothing + } + /** * @author Sodium * @reason Redirect to our renderer From 8655b23de0108180d5b4a09b0c479a5e806cac76 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 17 Nov 2023 17:13:49 -0800 Subject: [PATCH 059/301] Implement IBlockAccess on WorldSlice * Currently just proxies to the World... need to get it to use the local cache --- .../angelica/compat/mojang/BlockState.java | 4 ++ .../render/chunk/compile/ChunkBuilder.java | 3 +- .../chunk/tasks/ChunkRenderRebuildTask.java | 6 +- .../context/ChunkRenderCacheLocal.java | 4 +- .../mods/sodium/client/world/WorldSlice.java | 69 ++++++++++++++++++- .../sodium/client/world/biome/BiomeCache.java | 4 +- 6 files changed, 77 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java index 243f7520e..25b2482a1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java @@ -19,6 +19,10 @@ public Block getBlock() { return block; } + public int getMetadata() { + return meta; + } + public boolean isSideInvisible(BlockState adjState, ForgeDirection facing) { return false; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java index 3109a23c5..5148c9a90 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java @@ -20,7 +20,6 @@ import me.jellysquid.mods.sodium.common.util.collections.DequeDrain; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; -import net.minecraft.world.World; import net.minecraft.util.MathHelper; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -51,7 +50,7 @@ public class ChunkBuilder { private ClonedChunkSectionCache sectionCache; - private World world; + private WorldClient world; private Vector3d cameraPosition = new Vector3d(); private BlockRenderPassManager renderPassManager; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index ad94f2791..261c5fa29 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -74,10 +74,8 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB cache.init(this.context); - // TODO: Sodium - WorldSlice probably needs to implement IWorldAccess and redirect to the slice/chunk cache - WorldSlice slice = cache.getWorldSlice(); - // Gross - final RenderBlocks renderBlocks = new RenderBlocks(slice.getWorld()); + final WorldSlice slice = cache.getWorldSlice(); + final RenderBlocks renderBlocks = new RenderBlocks(slice); int baseX = this.render.getOriginX(); int baseY = this.render.getOriginY(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java index 1d7351a9f..6708bfc71 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java @@ -11,7 +11,7 @@ import me.jellysquid.mods.sodium.client.world.WorldSliceLocal; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import net.minecraft.client.Minecraft; -import net.minecraft.world.World; +import net.minecraft.client.multiplayer.WorldClient; public class ChunkRenderCacheLocal extends ChunkRenderCache { private final ArrayLightDataCache lightDataCache; @@ -23,7 +23,7 @@ public class ChunkRenderCacheLocal extends ChunkRenderCache { private final WorldSlice worldSlice; private WorldSliceLocal localSlice; - public ChunkRenderCacheLocal(Minecraft client, World world) { + public ChunkRenderCacheLocal(Minecraft client, WorldClient world) { this.worldSlice = new WorldSlice(world); this.lightDataCache = new ArrayLightDataCache(this.worldSlice); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 4e359a3dc..7d6112b8f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -17,8 +17,11 @@ import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSection; import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSectionCache; +import net.minecraft.block.Block; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.chunk.Chunk; @@ -38,7 +41,7 @@ * * Object pooling should be used to avoid huge allocations as this class contains many large arrays. */ -public class WorldSlice implements BlockRenderView, BiomeAccess.Storage { +public class WorldSlice implements BlockRenderView, BiomeAccess.Storage, IBlockAccess { // The number of blocks on each axis in a section. private static final int SECTION_BLOCK_LENGTH = 16; @@ -66,7 +69,7 @@ public class WorldSlice implements BlockRenderView, BiomeAccess.Storage { // The world this slice has copied data from @Getter // Temp - private final World world; + private final WorldClient world; // Local Section->BlockState table. private final BlockState[][] blockStatesArrays; @@ -134,7 +137,7 @@ public static ChunkRenderContext prepare(World world, ChunkSectionPos origin, Cl return new ChunkRenderContext(origin, sections, volume); } - public WorldSlice(World world) { + public WorldSlice(WorldClient world) { this.world = world; this.sections = new ClonedChunkSection[SECTION_TABLE_ARRAY_SIZE]; @@ -179,6 +182,66 @@ public void copyData(ChunkRenderContext context) { } } + @Override + public Block getBlock(int x, int y, int z) { + // TODO: Use local cache +// final BlockState state = this.getBlockState(x, y, z); +// return state == null ? Blocks.air : state.getBlock(); + return this.world.getBlock(x, y, z); + } + + @Override + public TileEntity getTileEntity(int x, int y, int z) { + // TODO + return null; + } + + @Override + public int getLightBrightnessForSkyBlocks(int x, int y, int z, int min) { + // TODO - avoid calling the world here + return this.world.getLightBrightnessForSkyBlocks(x, y, z, min); + } + + @Override + public int getBlockMetadata(int x, int y, int z) { + // TODO: Use local cache +// final BlockState state = this.getBlockState(x, y, z); +// return state == null ? 0 : state.getMetadata(); + return this.world.getBlockMetadata(x, y, z); + } + + @Override + public int isBlockProvidingPowerTo(int x, int y, int z, int directionIn) { + return this.getBlock(x, y, z).isProvidingStrongPower(this, x, y, z, directionIn); + } + + @Override + public boolean isAirBlock(int x, int y, int z) { + return this.getBlock(x, y, z).isAir(this, x, y, z); + } + + @Override + public BiomeGenBase getBiomeGenForCoords(int x, int z) { + // TODO: Use local cache +// return this.getBiome(x, 0, z); + return this.world.getBiomeGenForCoords(x, z); + } + + @Override + public int getHeight() { + return this.world.provider.getActualHeight(); + } + + @Override + public boolean extendedLevelsInChunkCache() { + return false; + } + + @Override + public boolean isSideSolid(int x, int y, int z, ForgeDirection side, boolean _default) { + return getBlock(x, y, z).isSideSolid(this, x, y, z, side); + } + private void unpackBlockData(BlockState[] states, ClonedChunkSection section, StructureBoundingBox box) { if (this.origin.equals(section.getPosition())) { this.unpackBlockDataZ(states, section); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java index 9462cc8ad..55b92b146 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java @@ -15,7 +15,7 @@ public class BiomeCache { public BiomeCache(World world) { // TODO: Sodium - this.type = null;//world.getDimension().getBiomeAccessType(); + this.type = null;//world.getDimension().getBiomeAccessType(); // Provider? this.seed = world.getSeed(); this.biomes = new BiomeGenBase[16 * 16]; @@ -26,7 +26,7 @@ public BiomeGenBase getBiome(BiomeAccess.Storage storage, int x, int y, int z) { BiomeGenBase biome = this.biomes[idx]; - if (biome == null) { + if (biome == null && this.type != null) { this.biomes[idx] = biome = this.type.getBiome(this.seed, x, y, z, storage); } From b267df4fdef831dc4c8ff5218934c6d9f8ff08f5 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 17 Nov 2023 23:05:25 -0800 Subject: [PATCH 060/301] Make WorldSlice use its copied values instead of using the world * block, meta, and light. Still need TODO biome * Start removing unused items from BlockRenderView --- .../compat/ExtendedBlockStorageExt.java | 3 + .../compat/mojang/BlockRenderView.java | 7 +- .../angelica/compat/mojang/LightType.java | 12 ---- .../client/render/pipeline/BlockRenderer.java | 4 +- .../mods/sodium/client/world/WorldSlice.java | 67 ++++++++++++------- .../sodium/client/world/WorldSliceLocal.java | 14 +--- .../world/cloned/ClonedChunkSection.java | 26 ++----- 7 files changed, 58 insertions(+), 75 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightType.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java index 842b34875..8458e4e66 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java @@ -6,9 +6,11 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage; public class ExtendedBlockStorageExt extends ExtendedBlockStorage { + public boolean hasSky; public ExtendedBlockStorageExt(int yBase, boolean hasSky) { super(yBase, hasSky); + this.hasSky = hasSky; } public ExtendedBlockStorageExt(IExtendedBlockStorageExt storage) { @@ -24,6 +26,7 @@ public ExtendedBlockStorageExt(IExtendedBlockStorageExt storage) { copyNibbleArray((ExtendedNibbleArray) storage.getMetadataArray(), (ExtendedNibbleArray)this.getMetadataArray()); copyNibbleArray((ExtendedNibbleArray) storage.getBlocklightArray(), (ExtendedNibbleArray)this.getBlocklightArray()); if(storage.getSkylightArray() != null) { + hasSky = true; if(this.getSkylightArray() == null) { this.setSkylightArray(new NibbleArray(blockLSBArray.length, 4)); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java index 0b8277ec1..75a7e948b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.compat.mojang; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.common.util.ForgeDirection; @@ -14,11 +15,7 @@ public interface BlockRenderView extends BlockView { int getColor(BlockPos pos, ColorResolver resolver); - int getLightLevel(LightType type, BlockPos pos); - - int getBaseLightLevel(BlockPos pos, int ambientDarkness); - - boolean isSkyVisible(BlockPos pos); + int getLightLevel(EnumSkyBlock type, BlockPos pos); BiomeGenBase getBiomeForNoiseGen(int x, int y, int z); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightType.java deleted file mode 100644 index ced4e7ef5..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightType.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -public enum LightType { - SKY(15), - BLOCK(0); - - public final int value; - - LightType(int value) { - this.value = value; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index f22e1ec26..e70c045df 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -74,7 +74,7 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende final LightPipeline lighter = this.lighters.getLighter(mode); Vector3d offset = state.getModelOffset(world, pos); - boolean rendered = false; + boolean rendered; // modelData = model.getModelData(world, pos, state, modelData); // @@ -113,7 +113,7 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende // } this.random.setSeed(seed); - List all = tesselatorToBakedQuadList(tessellator, pos); + final List all = tesselatorToBakedQuadList(tessellator, pos); // List all = model.getQuads(state, null, this.random, modelData); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 7d6112b8f..5a7a8ccbb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -8,7 +8,6 @@ import com.gtnewhorizons.angelica.compat.mojang.ColorResolver; import com.gtnewhorizons.angelica.compat.mojang.CompatMathHelper; import com.gtnewhorizons.angelica.compat.mojang.FluidState; -import com.gtnewhorizons.angelica.compat.mojang.LightType; import com.gtnewhorizons.angelica.compat.mojang.LightingProvider; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import lombok.Getter; @@ -21,6 +20,8 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MathHelper; +import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; @@ -184,10 +185,7 @@ public void copyData(ChunkRenderContext context) { @Override public Block getBlock(int x, int y, int z) { - // TODO: Use local cache -// final BlockState state = this.getBlockState(x, y, z); -// return state == null ? Blocks.air : state.getBlock(); - return this.world.getBlock(x, y, z); + return this.getBlockState(x, y, z).getBlock(); } @Override @@ -198,16 +196,41 @@ public TileEntity getTileEntity(int x, int y, int z) { @Override public int getLightBrightnessForSkyBlocks(int x, int y, int z, int min) { - // TODO - avoid calling the world here - return this.world.getLightBrightnessForSkyBlocks(x, y, z, min); + int skyBrightness = this.getSkyBlockTypeBrightness(net.minecraft.world.EnumSkyBlock.Sky, x, y, z); + int blockBrightness = this.getSkyBlockTypeBrightness(net.minecraft.world.EnumSkyBlock.Block, x, y, z); + + if (blockBrightness < min) { + blockBrightness = min; + } + + return skyBrightness << 20 | blockBrightness << 4; + } + public int getSkyBlockTypeBrightness(EnumSkyBlock skyBlock, int x, int y, int z) { + y = MathHelper.clamp_int(y, 0, 255); + if (y < 0 || y >= 256 || x < -30000000 || z < -30000000 || x >= 30000000 || z > 30000000) { + return skyBlock.defaultLightValue; + } + if (this.getBlock(x, y, z).getUseNeighborBrightness()) { + int yp = this.getLightLevel(skyBlock, x, y + 1, z); + int xp = this.getLightLevel(skyBlock, x + 1, y, z); + int xm = this.getLightLevel(skyBlock, x - 1, y, z); + int zp = this.getLightLevel(skyBlock, x, y, z + 1); + int zm = this.getLightLevel(skyBlock, x, y, z - 1); + + if (xp > yp) yp = xp; + if (xm > yp) yp = xm; + if (zp > yp) yp = zp; + if (zm > yp) yp = zm; + + return yp; + } + + return this.getLightLevel(skyBlock, x, y, z); } @Override public int getBlockMetadata(int x, int y, int z) { - // TODO: Use local cache -// final BlockState state = this.getBlockState(x, y, z); -// return state == null ? 0 : state.getMetadata(); - return this.world.getBlockMetadata(x, y, z); + return this.getBlockState(x, y, z).getMetadata(); } @Override @@ -379,22 +402,18 @@ public int getColor(BlockPos pos, ColorResolver resolver) { } @Override - public int getLightLevel(LightType type, BlockPos pos) { - int relX = pos.x - this.baseX; - int relY = pos.y - this.baseY; - int relZ = pos.z - this.baseZ; - - return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)].getLightLevel(type, relX & 15, relY & 15, relZ & 15); + public int getLightLevel(EnumSkyBlock type, BlockPos pos) { + return getLightLevel(type, pos.x, pos.y, pos.z); } - @Override - public int getBaseLightLevel(BlockPos pos, int ambientDarkness) { - return 0; - } + public int getLightLevel(EnumSkyBlock type, int x, int y, int z) { + y = MathHelper.clamp_int(y, 0, 255); - @Override - public boolean isSkyVisible(BlockPos pos) { - return false; + int relX = x - this.baseX; + int relY = y - this.baseY; + int relZ = z - this.baseZ; + + return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)].getLightLevel(type, relX & 15, relY & 15, relZ & 15); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java index d7b09a037..a7cb87818 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java @@ -5,9 +5,9 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ColorResolver; import com.gtnewhorizons.angelica.compat.mojang.FluidState; -import com.gtnewhorizons.angelica.compat.mojang.LightType; import com.gtnewhorizons.angelica.compat.mojang.LightingProvider; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.common.util.ForgeDirection; @@ -40,20 +40,10 @@ public int getColor(BlockPos pos, ColorResolver colorResolver) { } @Override - public int getLightLevel(LightType type, BlockPos pos) { + public int getLightLevel(EnumSkyBlock type, BlockPos pos) { return view.getLightLevel(type, pos); } - @Override - public int getBaseLightLevel(BlockPos pos, int ambientDarkness) { - return view.getBaseLightLevel(pos, ambientDarkness); - } - - @Override - public boolean isSkyVisible(BlockPos pos) { - return view.isSkyVisible(pos); - } - @Override public BiomeGenBase getBiomeForNoiseGen(int x, int y, int z) { return null; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 945548565..41a7a962b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -4,7 +4,6 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; -import com.gtnewhorizons.angelica.compat.mojang.LightType; import com.gtnewhorizons.angelica.mixins.interfaces.IExtendedBlockStorageExt; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; @@ -12,10 +11,10 @@ import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.ChunkPosition; +import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraft.world.gen.structure.StructureBoundingBox; @@ -24,14 +23,13 @@ public class ClonedChunkSection { public static final BlockState DEFAULT_BLOCK_STATE = new BlockState(Blocks.air, 0); - private static final LightType[] LIGHT_TYPES = LightType.values(); + private static final EnumSkyBlock[] LIGHT_TYPES = EnumSkyBlock.values(); private static final ExtendedBlockStorage EMPTY_SECTION = new ExtendedBlockStorage(0, false); private final AtomicInteger referenceCount = new AtomicInteger(0); private final ClonedChunkSectionCache backingCache; private final Short2ObjectMap tileEntities; - private final NibbleArray[] lightDataArrays; private ExtendedBlockStorageExt data; private final World world; @@ -46,7 +44,6 @@ public class ClonedChunkSection { this.backingCache = backingCache; this.world = world; this.tileEntities = new Short2ObjectOpenHashMap<>(); - this.lightDataArrays = new NibbleArray[LIGHT_TYPES.length]; } public void init(ChunkSectionPos pos) { @@ -65,14 +62,6 @@ public void init(ChunkSectionPos pos) { this.pos = pos; this.data = new ExtendedBlockStorageExt(section); - - for (LightType type : LIGHT_TYPES) { - // TODO: Sodium - Lighting - this.lightDataArrays[type.ordinal()] = null; /*world.getLightingProvider() - .get(type) - .getLightSection(pos);*/ - } - this.biomeData = chunk.getBiomeArray(); StructureBoundingBox box = new StructureBoundingBox(pos.getMinX(), pos.getMinY(), pos.getMinZ(), pos.getMaxX(), pos.getMaxY(), pos.getMaxZ()); @@ -97,14 +86,11 @@ public BlockState getBlockState(int x, int y, int z) { } return new BlockState(data.getBlockByExtId(x, y, z), data.getExtBlockMetadata(x, y, z)); } - public int getLightLevel(LightType type, int x, int y, int z) { - NibbleArray array = this.lightDataArrays[type.ordinal()]; - - if (array != null) { - return array.get(x, y, z); + public int getLightLevel(EnumSkyBlock type, int x, int y, int z) { + if(type == EnumSkyBlock.Sky) { + return data.hasSky ? data.getExtSkylightValue(x, y, z) : 0; } - - return 0; + return data.getExtBlocklightValue(x, y, z); } public BiomeGenBase getBiomeForNoiseGen(int x, int y, int z) { From 24d2c254d56eb1dfa6650d92ff9f35a312a4ae68 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 18 Nov 2023 11:25:24 -0800 Subject: [PATCH 061/301] Finish making WorldSlice thread safe * Remove last unsafe this.world accesses * Copy biomeData * Implement getTileEntity(), and getBiomeGenForCoords() * Remove unused 1.16+ classes - Biome, Colorizer, and ColorBlender related --- .../compat/forge/ForgeBlockRenderer.java | 106 --------------- .../compat/forge/VertexLighterFlat.java | 3 - .../compat/forge/VertexLighterSmoothAo.java | 11 -- .../angelica/compat/mojang/BiomeAccess.java | 9 -- .../compat/mojang/BiomeAccessType.java | 8 -- .../compat/mojang/BlockColorProvider.java | 7 - .../angelica/compat/mojang/BlockColors.java | 5 - .../compat/mojang/BlockRenderView.java | 9 +- .../angelica/compat/nd/Quad.java | 4 + .../model/quad/blender/BiomeColorBlender.java | 29 ---- .../quad/blender/BlockColorSettings.java | 30 ----- .../blender/ConfigurableColorBlender.java | 39 ------ .../blender/DefaultBlockColorSettings.java | 23 ---- .../quad/blender/FlatBiomeColorBlender.java | 25 ---- .../quad/blender/SmoothBiomeColorBlender.java | 117 ----------------- .../render/chunk/compile/ChunkBuilder.java | 3 - .../chunk/tasks/ChunkRenderRebuildTask.java | 2 +- .../client/render/pipeline/BlockRenderer.java | 29 +--- .../render/pipeline/ChunkRenderCache.java | 7 +- .../client/render/pipeline/FluidRenderer.java | 14 +- .../context/ChunkRenderCacheLocal.java | 6 +- .../context/ChunkRenderCacheShared.java | 4 +- .../mods/sodium/client/world/WorldSlice.java | 124 +++--------------- .../sodium/client/world/WorldSliceLocal.java | 22 +--- .../sodium/client/world/biome/BiomeCache.java | 39 ------ .../client/world/biome/BiomeColorCache.java | 111 ---------------- .../world/biome/BlockColorsExtended.java | 8 -- .../world/biome/ItemColorsExtended.java | 8 -- .../world/cloned/ClonedChunkSection.java | 3 +- 29 files changed, 38 insertions(+), 767 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeBlockRenderer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterSmoothAo.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColors.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeBlockRenderer.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeBlockRenderer.java deleted file mode 100644 index d7a4149f7..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeBlockRenderer.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -import com.gtnewhorizons.angelica.compat.mojang.BakedModel; -import com.gtnewhorizons.angelica.compat.mojang.BakedQuad; -import com.gtnewhorizons.angelica.compat.mojang.BlockColors; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; -import me.jellysquid.mods.sodium.client.model.light.LightMode; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; -import me.jellysquid.mods.sodium.client.render.occlusion.BlockOcclusionCache; -import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraftforge.common.util.ForgeDirection; - -import java.util.List; -import java.util.Random; - -/** - * Utility class for BlockRenderer, that uses the Forge lighting pipeline. - * - * This class is derived from Forge's renderer, and is licensed under LGPL-2.1. As the class is a standalone class file, - * it may be replaced in an existing copy of Embeddium with an alternate LGPL-2.1 implementation. - */ -public class ForgeBlockRenderer { - // TODO: Sodium - private final BlockColors colors = null; //Minecraft.getMinecraft().getBlockColors(); - private final ThreadLocal lighterFlat = ThreadLocal.withInitial(() -> new VertexLighterFlat(colors)); - private final ThreadLocal lighterSmooth = ThreadLocal.withInitial(() -> new VertexLighterSmoothAo(colors)); - private final ThreadLocal consumerFlat = ThreadLocal.withInitial(VertexBufferConsumer::new); - private final ThreadLocal consumerSmooth = ThreadLocal.withInitial(VertexBufferConsumer::new); - - - private static boolean useForgeLightingPipeline = false; - - public static void init() { - useForgeLightingPipeline = true;//ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.get(); - } - - public static boolean useForgeLightingPipeline() { - return useForgeLightingPipeline; - } - - private void processQuad(ChunkRenderData.Builder renderData, BakedQuad quad) { - ModelQuadView src = (ModelQuadView)quad; - TextureAtlasSprite sprite = src.rubidium$getSprite(); - - if (sprite != null) { - renderData.addSprite(sprite); - } - } - - public boolean renderBlock(LightMode mode, BlockState state, BlockPos pos, BlockRenderView world, BakedModel model, MatrixStack stack, - VertexConsumer buffer, Random random, long seed, IModelData data, boolean checkSides, BlockOcclusionCache sideCache, - ChunkRenderData.Builder renderData) { - VertexBufferConsumer consumer = mode == LightMode.FLAT ? this.consumerFlat.get() : this.consumerSmooth.get(); - consumer.setBuffer(buffer); - VertexLighterFlat lighter = mode == LightMode.FLAT ? this.lighterFlat.get() : this.lighterSmooth.get(); - lighter.setParent(consumer); - lighter.setTransform(stack.peek()); - - // render - lighter.setWorld(world); - lighter.setState(state); - lighter.setBlockPos(pos); - boolean empty = true; - random.setSeed(seed); - - List quads = model.getQuads(state, null, random, data); - if(!quads.isEmpty()) { - lighter.updateBlockInfo(); - empty = false; - // noinspection ForLoopReplaceableByForEach - for(int i = 0; i < quads.size(); i++) { - BakedQuad quad = quads.get(i); - quad.pipe(lighter); - processQuad(renderData, quad); - } - } - - for(ForgeDirection side : DirectionUtil.ALL_DIRECTIONS) - { - random.setSeed(seed); - quads = model.getQuads(state, side, random, data); - if(!quads.isEmpty()) - { - if(!checkSides || sideCache.shouldDrawSide(state, world, pos, side)) - { - if(empty) lighter.updateBlockInfo(); - empty = false; - // noinspection ForLoopReplaceableByForEach - for(int i = 0; i < quads.size(); i++) { - BakedQuad quad = quads.get(i); - quad.pipe(lighter); - processQuad(renderData, quad); - } - } - } - } - lighter.resetBlockInfo(); - return !empty; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java index 34a303342..4a216853a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java @@ -1,6 +1,5 @@ package com.gtnewhorizons.angelica.compat.forge; -import com.gtnewhorizons.angelica.compat.mojang.BlockColors; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; @@ -8,8 +7,6 @@ public class VertexLighterFlat { - public VertexLighterFlat(BlockColors colors) {} - public void setParent(VertexBufferConsumer consumer) {} public void setTransform(MatrixStack.Entry peek) {} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterSmoothAo.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterSmoothAo.java deleted file mode 100644 index b1eba3495..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterSmoothAo.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -import com.gtnewhorizons.angelica.compat.mojang.BlockColors; - -public class VertexLighterSmoothAo extends VertexLighterFlat { - - public VertexLighterSmoothAo(BlockColors colors) { - super(colors); - - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java deleted file mode 100644 index 638f10620..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccess.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import net.minecraft.world.biome.BiomeGenBase; - -public class BiomeAccess { - public interface Storage { - BiomeGenBase getBiomeForNoiseGen(int biomeX, int biomeY, int biomeZ); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java deleted file mode 100644 index 81d699bd6..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BiomeAccessType.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import net.minecraft.world.biome.BiomeGenBase; - -public interface BiomeAccessType { - - BiomeGenBase getBiome(long seed, int x, int y, int z, BiomeAccess.Storage storage); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java deleted file mode 100644 index 3993b64c0..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColorProvider.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import javax.annotation.Nullable; - -public interface BlockColorProvider { - int getColor(BlockState state, @Nullable BlockRenderView world, @Nullable BlockPos pos, int tintIndex); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColors.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColors.java deleted file mode 100644 index f2f9cca47..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockColors.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -public class BlockColors { - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java index 75a7e948b..7a7f32840 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java @@ -2,22 +2,15 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.world.EnumSkyBlock; -import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.common.util.ForgeDirection; public interface BlockRenderView extends BlockView { float getBrightness(ForgeDirection face, boolean shade); - LightingProvider getLightingProvider(); - - TileEntity getBlockEntity(BlockPos pos); - - int getColor(BlockPos pos, ColorResolver resolver); + TileEntity getTileEntity(BlockPos pos); int getLightLevel(EnumSkyBlock type, BlockPos pos); - BiomeGenBase getBiomeForNoiseGen(int x, int y, int z); - FluidState getFluidState(BlockPos set); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java index 91007f4dc..b1e857588 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java @@ -63,6 +63,10 @@ public boolean hasColor() { return this.hasColor; } + public int[] getColors() { + return this.cs; + } + public boolean hasShade() { return this.hasShade; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java deleted file mode 100644 index 3472db75b..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BiomeColorBlender.java +++ /dev/null @@ -1,29 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.quad.blender; - -import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import net.minecraft.client.Minecraft; - -public interface BiomeColorBlender { - /** - * Computes the blended biome colors and returns an an array containing the integer-encoded colors for each vertex. - * The array returned by this method may be re-used in subsequent calls in order to reduce memory allocations, and - * as such, the contents of an array returned by this method is undefined after a subsequent call. - * - * @param colorizer The color sampling source - * @param world The world to sample biomes (and as a result, colors) from - * @param state The block state being rendered - * @param origin The position of the block being rendered - * @param quad The quad which will be colorized - * @return An array of integer colors in ABGR format - */ - int[] getColors(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, - ModelQuadView quad); - - static BiomeColorBlender create(Minecraft client) { - return new ConfigurableColorBlender(client); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java deleted file mode 100644 index cf4b63f18..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/BlockColorSettings.java +++ /dev/null @@ -1,30 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.quad.blender; - -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; - -public interface BlockColorSettings { - /** - * Configures whether biome colors from a color provider will be interpolated for this block. You should only - * enable this functionality if your color provider returns values based upon a pair of coordinates in the world, - * and not if it needs access to the block state itself. - * - * @return True if interpolation should be used, otherwise false. - */ - boolean useSmoothColorBlending(BlockRenderView view, T state, BlockPos pos); - -// @SuppressWarnings("unchecked") -// static boolean isSmoothBlendingEnabled(BlockRenderView world, State state, BlockPos pos) { -// if (state.owner instanceof BlockColorSettings) { -// BlockColorSettings> settings = (BlockColorSettings>) state.owner; -// return settings.useSmoothColorBlending(world, state, pos); -// } -// -// return false; -// } - @SuppressWarnings("unchecked") - static boolean isSmoothBlendingEnabled(BlockRenderView world, BlockState state, BlockPos pos) { - return false; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java deleted file mode 100644 index 0104ad284..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/ConfigurableColorBlender.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.quad.blender; - -import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import net.minecraft.client.Minecraft; - -class ConfigurableColorBlender implements BiomeColorBlender { - private final BiomeColorBlender defaultBlender; - private final BiomeColorBlender smoothBlender; - - public ConfigurableColorBlender(Minecraft client) { - this.defaultBlender = new FlatBiomeColorBlender(); - this.smoothBlender = isSmoothBlendingEnabled(client) ? new SmoothBiomeColorBlender() : this.defaultBlender; - } - - private static boolean isSmoothBlendingEnabled(Minecraft client) { - return true; - // TODO: Sodium -// return client.options.biomeBlendRadius > 0; - } - - @Override - public int[] getColors(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, - ModelQuadView quad) { - BiomeColorBlender blender; - - if (BlockColorSettings.isSmoothBlendingEnabled(world, state, origin)) { - blender = this.smoothBlender; - } else { - blender = this.defaultBlender; - } - - return blender.getColors(colorizer, world, state, origin, quad); - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java deleted file mode 100644 index b3bb146e3..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/DefaultBlockColorSettings.java +++ /dev/null @@ -1,23 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.quad.blender; - -import com.google.common.collect.Sets; -import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; -import net.minecraft.block.Block; -import net.minecraft.init.Blocks; - -import java.util.Set; - -public class DefaultBlockColorSettings { - private static final Set BLENDED_BLOCKS = new ReferenceOpenHashSet<>(Sets.newHashSet( - Blocks.grass, Blocks.leaves, Blocks.leaves2, Blocks.tallgrass, Blocks.water, - Blocks.cauldron, Blocks.reeds, Blocks.vine)); - -// private static final Set BLENDED_BLOCKS = new ReferenceOpenHashSet<>(Sets.newHashSet( -// Blocks.FERN, Blocks.LARGE_FERN, Blocks.POTTED_FERN, Blocks.GRASS, Blocks.TALL_GRASS, -// Blocks.GRASS_BLOCK, Blocks.OAK_LEAVES, Blocks.JUNGLE_LEAVES, Blocks.ACACIA_LEAVES, Blocks.DARK_OAK_LEAVES, -// Blocks.VINE, Blocks.WATER, Blocks.BUBBLE_COLUMN, Blocks.CAULDRON, Blocks.SUGAR_CANE)); - - public static boolean isSmoothBlendingAvailable(Block block) { - return BLENDED_BLOCKS.contains(block); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java deleted file mode 100644 index 58bf6b98f..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/FlatBiomeColorBlender.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.quad.blender; - -import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; - -/** - * A simple colorizer which performs no blending between adjacent blocks. - */ -public class FlatBiomeColorBlender implements BiomeColorBlender { - private final int[] cachedRet = new int[4]; - - @Override - public int[] getColors(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, - ModelQuadView quad) { - // TODO: Sodium - Colorizer -// Arrays.fill(this.cachedRet, ColorARGB.toABGR(colorizer.getColor(state, world, origin, quad.getColorIndex()))); - -// return this.cachedRet; - - return new int[] {quad.getColor(0), quad.getColor(1), quad.getColor(2), quad.getColor(3)}; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java deleted file mode 100644 index 820887bc1..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/blender/SmoothBiomeColorBlender.java +++ /dev/null @@ -1,117 +0,0 @@ -package me.jellysquid.mods.sodium.client.model.quad.blender; - -import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import me.jellysquid.mods.sodium.client.util.color.ColorABGR; -import me.jellysquid.mods.sodium.client.util.color.ColorARGB; -import me.jellysquid.mods.sodium.client.util.color.ColorU8; - -public class SmoothBiomeColorBlender implements BiomeColorBlender { - private final int[] cachedRet = new int[4]; - - private final BlockPos.Mutable mpos = new BlockPos.Mutable(); - - @Override - public int[] getColors(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, - ModelQuadView quad) { - final int[] colors = this.cachedRet; - - boolean aligned = ModelQuadFlags.contains(quad.getFlags(), ModelQuadFlags.IS_ALIGNED); - - for (int i = 0; i < 4; i++) { - // If the vertex is aligned to the block grid, we do not need to interpolate - if (aligned) { - colors[i] = this.getVertexColor(colorizer, world, state, origin, quad, i); - } else { - colors[i] = this.getInterpolatedVertexColor(colorizer, world, state, origin, quad, i); - } - } - - return colors; - } - - private int getVertexColor(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, - ModelQuadView quad, int vertexIdx) { - final int x = origin.getX() + (int) quad.getX(vertexIdx); - final int z = origin.getZ() + (int) quad.getZ(vertexIdx); - - final int color = this.getBlockColor(colorizer, world, state, origin, x, z, quad.getColorIndex()); - - return ColorARGB.toABGR(color); - } - - private int getBlockColor(BlockColorProvider colorizer, BlockRenderView world, BlockState state, BlockPos origin, - int x, int z, int colorIdx) { - return colorizer.getColor(state, world, this.mpos.set(x, origin.getY(), z), colorIdx); - } - - private int getInterpolatedVertexColor(BlockColorProvider colorizer, BlockRenderView world, BlockState state, - BlockPos origin, ModelQuadView quad, int vertexIdx) { - final float x = quad.getX(vertexIdx); - final float z = quad.getZ(vertexIdx); - - final int intX = (int) x; - final int intZ = (int) z; - - // Integer component of position vector - final int originX = origin.getX() + intX; - final int originZ = origin.getZ() + intZ; - - // Fraction component of position vector - final float fracX = x - intX; - final float fracZ = z - intZ; - - // Retrieve the color values for each neighbor - final int c1 = this.getBlockColor(colorizer, world, state, origin, originX, originZ, quad.getColorIndex()); - final int c2 = this.getBlockColor(colorizer, world, state, origin, originX, originZ + 1, quad.getColorIndex()); - final int c3 = this.getBlockColor(colorizer, world, state, origin, originX + 1, originZ, quad.getColorIndex()); - final int c4 = this.getBlockColor(colorizer, world, state, origin, originX + 1, originZ + 1, quad.getColorIndex()); - - final float fr, fg, fb; - - // All the colors are the same, so the results of interpolation will be useless. - if (c1 == c2 && c2 == c3 && c3 == c4) { - fr = ColorARGB.unpackRed(c1); - fg = ColorARGB.unpackGreen(c1); - fb = ColorARGB.unpackBlue(c1); - } else { - // TODO: avoid float conversions here - // RGB components for each corner's color - final float c1r = ColorARGB.unpackRed(c1); - final float c1g = ColorARGB.unpackGreen(c1); - final float c1b = ColorARGB.unpackBlue(c1); - - final float c2r = ColorARGB.unpackRed(c2); - final float c2g = ColorARGB.unpackGreen(c2); - final float c2b = ColorARGB.unpackBlue(c2); - - final float c3r = ColorARGB.unpackRed(c3); - final float c3g = ColorARGB.unpackGreen(c3); - final float c3b = ColorARGB.unpackBlue(c3); - - final float c4r = ColorARGB.unpackRed(c4); - final float c4g = ColorARGB.unpackGreen(c4); - final float c4b = ColorARGB.unpackBlue(c4); - - // Compute the final color values across the Z axis - final float r1r = c1r + ((c2r - c1r) * fracZ); - final float r1g = c1g + ((c2g - c1g) * fracZ); - final float r1b = c1b + ((c2b - c1b) * fracZ); - - final float r2r = c3r + ((c4r - c3r) * fracZ); - final float r2g = c3g + ((c4g - c3g) * fracZ); - final float r2b = c3b + ((c4b - c3b) * fracZ); - - // Compute the final color values across the X axis - fr = r1r + ((r2r - r1r) * fracX); - fg = r1g + ((r2g - r1g) * fracX); - fb = r1b + ((r2b - r1b) * fracX); - } - - return ColorABGR.pack(ColorU8.normalize(fr), ColorU8.normalize(fg), ColorU8.normalize(fb)); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java index 5148c9a90..3ff9a6704 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; -import com.gtnewhorizons.angelica.compat.forge.ForgeBlockRenderer; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; @@ -220,8 +219,6 @@ public void init(WorldClient world, BlockRenderPassManager renderPassManager) { this.renderPassManager = renderPassManager; this.sectionCache = new ClonedChunkSectionCache(this.world); - ForgeBlockRenderer.init(); - this.startWorkers(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 261c5fa29..645475c72 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -147,7 +147,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB } if (blockState.hasTileEntity()) { - TileEntity entity = slice.getBlockEntity(pos); + TileEntity entity = slice.getTileEntity(pos); final TileEntitySpecialRenderer renderer = TileEntityRendererDispatcher.instance.getSpecialRenderer(entity); if (entity != null && renderer != null) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index e70c045df..9f91ee06a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -1,7 +1,5 @@ package me.jellysquid.mods.sodium.client.render.pipeline; -import com.gtnewhorizons.angelica.compat.forge.ForgeBlockRenderer; -import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; @@ -12,8 +10,6 @@ import me.jellysquid.mods.sodium.client.model.light.LightPipeline; import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; -import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadOrientation; import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; @@ -23,7 +19,6 @@ import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; -import me.jellysquid.mods.sodium.client.world.biome.BlockColorsExtended; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderBlocks; @@ -42,14 +37,10 @@ public class BlockRenderer { private final Random random = new XoRoShiRoRandom(); - private final BlockColorsExtended blockColors; private final BlockOcclusionCache occlusionCache; private final QuadLightData cachedQuadLightData = new QuadLightData(); - private final ForgeBlockRenderer forgeBlockRenderer = new ForgeBlockRenderer(); - - private final BiomeColorBlender biomeColorBlender; private final LightPipelineProvider lighters; private final boolean useAmbientOcclusion; @@ -57,11 +48,7 @@ public class BlockRenderer { private final Flags FLAGS = new Flags(true, true, true, false); private final RecyclingList quadBuf = new RecyclingList<>(Quad::new); - public BlockRenderer(Minecraft client, LightPipelineProvider lighters, BiomeColorBlender biomeColorBlender) { - // TODO: Sodium - Block Colors - this.blockColors = (BlockColorsExtended) null; //client.getBlockColors(); - this.biomeColorBlender = biomeColorBlender; - + public BlockRenderer(Minecraft client, LightPipelineProvider lighters) { this.lighters = lighters; this.occlusionCache = new BlockOcclusionCache(); @@ -188,7 +175,6 @@ private List tesselatorToBakedQuadList(Tessellator t, BlockPos pos) { private void renderQuadList(BlockRenderView world, BlockState state, BlockPos pos, LightPipeline lighter, Vector3d offset, ChunkModelBuffers buffers, List quads, ForgeDirection cullFace) { ModelQuadFacing facing = cullFace == null ? ModelQuadFacing.UNASSIGNED : ModelQuadFacing.fromDirection(cullFace); - BlockColorProvider colorizer = null; ModelVertexSink sink = buffers.getSink(facing); sink.ensureCapacity(quads.size() * 4); @@ -201,28 +187,23 @@ private void renderQuadList(BlockRenderView world, BlockState state, BlockPos po Quad quad = quads.get(i); QuadLightData light = this.cachedQuadLightData; - lighter.calculate((ModelQuadView) quad, pos, light, cullFace, quad.getFace(), quad.hasShade()); - - // TODO: Sodium - BlockColors - if (quad.hasColor() && colorizer == null && this.blockColors != null) { - colorizer = this.blockColors.getColorProvider(state); - } + lighter.calculate(quad, pos, light, cullFace, quad.getFace(), quad.hasShade()); - this.renderQuad(world, state, pos, sink, offset, colorizer, quad, light, renderData); + this.renderQuad(world, state, pos, sink, offset, quad, light, renderData); } sink.flush(); } private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, ModelVertexSink sink, Vector3d offset, - BlockColorProvider colorProvider, Quad quad, QuadLightData light, ChunkRenderData.Builder renderData) { + Quad quad, QuadLightData light, ChunkRenderData.Builder renderData) { ModelQuadOrientation order = ModelQuadOrientation.orient(light.br); int[] colors = null; if (quad.hasColor()) { - colors = this.biomeColorBlender.getColors(colorProvider, world, state, pos, quad); + colors = quad.getColors(); } for (int dstIndex = 0; dstIndex < 4; dstIndex++) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java index 2cf785800..feec0c4b8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/ChunkRenderCache.java @@ -1,10 +1,5 @@ package me.jellysquid.mods.sodium.client.render.pipeline; -import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; -import net.minecraft.client.Minecraft; - public class ChunkRenderCache { - protected BiomeColorBlender createBiomeColorBlender() { - return BiomeColorBlender.create(Minecraft.getMinecraft()); - } + } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java index a0999a108..d93f32c1a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java @@ -1,7 +1,6 @@ package me.jellysquid.mods.sodium.client.render.pipeline; import com.gtnewhorizons.angelica.compat.forge.ForgeHooksClientExt; -import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; @@ -16,7 +15,6 @@ import me.jellysquid.mods.sodium.client.model.quad.ModelQuad; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadViewMutable; -import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; @@ -37,23 +35,16 @@ public class FluidRenderer { private static final float EPSILON = 0.001f; - private static final BlockColorProvider FLUID_COLOR_PROVIDER = (state, world, pos, tintIndex) -> { - if (world == null) return 0xFFFFFFFF; - // TODO: Sodium - Fluids - return 0xFFFFFFFF; // state.getFluidState().getFluid().getAttributes().getColor(world, pos); - }; - private final BlockPos.Mutable scratchPos = new BlockPos.Mutable(); private final ModelQuadViewMutable quad = new ModelQuad(); private final LightPipelineProvider lighters; - private final BiomeColorBlender biomeColorBlender; private final QuadLightData quadLightData = new QuadLightData(); private final int[] quadColors = new int[4]; - public FluidRenderer(Minecraft client, LightPipelineProvider lighters, BiomeColorBlender biomeColorBlender) { + public FluidRenderer(Minecraft client, LightPipelineProvider lighters) { int normal = Norm3b.pack(0.0f, 1.0f, 0.0f); for (int i = 0; i < 4; i++) { @@ -61,7 +52,6 @@ public FluidRenderer(Minecraft client, LightPipelineProvider lighters, BiomeColo } this.lighters = lighters; - this.biomeColorBlender = biomeColorBlender; } private boolean isFluidOccluded(BlockRenderView world, int x, int y, int z, ForgeDirection dir, Fluid fluid) { @@ -360,7 +350,7 @@ private void calculateQuadColors(ModelQuadView quad, BlockRenderView world, Blo int[] biomeColors = null; if (colorized) { - biomeColors = this.biomeColorBlender.getColors(FLUID_COLOR_PROVIDER, world, world.getBlockState(pos), pos, quad); + // TODO: Sodium - Colorizer } for (int i = 0; i < 4; i++) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java index 6708bfc71..a5173ec49 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java @@ -3,7 +3,6 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockModels; import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache; -import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; import me.jellysquid.mods.sodium.client.render.pipeline.FluidRenderer; @@ -28,10 +27,9 @@ public ChunkRenderCacheLocal(Minecraft client, WorldClient world) { this.lightDataCache = new ArrayLightDataCache(this.worldSlice); LightPipelineProvider lightPipelineProvider = new LightPipelineProvider(this.lightDataCache); - BiomeColorBlender biomeColorBlender = this.createBiomeColorBlender(); - this.blockRenderer = new BlockRenderer(client, lightPipelineProvider, biomeColorBlender); - this.fluidRenderer = new FluidRenderer(client, lightPipelineProvider, biomeColorBlender); + this.blockRenderer = new BlockRenderer(client, lightPipelineProvider); + this.fluidRenderer = new FluidRenderer(client, lightPipelineProvider); // TODO: Sodium this.blockModels = null; // client.getBakedModelManager().getBlockModels(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java index c906b58f4..88dafe515 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java @@ -4,7 +4,6 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.cache.HashLightDataCache; -import me.jellysquid.mods.sodium.client.model.quad.blender.BiomeColorBlender; import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; import net.minecraft.client.Minecraft; @@ -24,10 +23,9 @@ private ChunkRenderCacheShared(WorldClient world) { this.lightCache = new HashLightDataCache((BlockRenderView)world); - BiomeColorBlender biomeColorBlender = this.createBiomeColorBlender(); LightPipelineProvider lightPipelineProvider = new LightPipelineProvider(this.lightCache); - this.blockRenderer = new BlockRenderer(client, lightPipelineProvider, biomeColorBlender); + this.blockRenderer = new BlockRenderer(client, lightPipelineProvider); } public BlockRenderer getBlockRenderer() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 5a7a8ccbb..1157c82b9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -1,23 +1,16 @@ package me.jellysquid.mods.sodium.client.world; -import com.gtnewhorizons.angelica.compat.mojang.BiomeAccess; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; -import com.gtnewhorizons.angelica.compat.mojang.ColorResolver; import com.gtnewhorizons.angelica.compat.mojang.CompatMathHelper; import com.gtnewhorizons.angelica.compat.mojang.FluidState; -import com.gtnewhorizons.angelica.compat.mojang.LightingProvider; -import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import lombok.Getter; -import me.jellysquid.mods.sodium.client.world.biome.BiomeCache; -import me.jellysquid.mods.sodium.client.world.biome.BiomeColorCache; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSection; import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSectionCache; import net.minecraft.block.Block; -import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.MathHelper; @@ -30,8 +23,6 @@ import net.minecraft.world.gen.structure.StructureBoundingBox; import net.minecraftforge.common.util.ForgeDirection; -import java.util.Map; - /** * Takes a slice of world state (block states, biome and light data arrays) and copies the data for use in off-thread * operations. This allows chunk build tasks to see a consistent snapshot of chunk data at the exact moment the task was @@ -42,7 +33,7 @@ * * Object pooling should be used to avoid huge allocations as this class contains many large arrays. */ -public class WorldSlice implements BlockRenderView, BiomeAccess.Storage, IBlockAccess { +public class WorldSlice implements BlockRenderView, IBlockAccess { // The number of blocks on each axis in a section. private static final int SECTION_BLOCK_LENGTH = 16; @@ -69,7 +60,6 @@ public class WorldSlice implements BlockRenderView, BiomeAccess.Storage, IBlockA private static final int SECTION_TABLE_ARRAY_SIZE = TABLE_LENGTH * TABLE_LENGTH * TABLE_LENGTH; // The world this slice has copied data from - @Getter // Temp private final WorldClient world; // Local Section->BlockState table. @@ -78,24 +68,14 @@ public class WorldSlice implements BlockRenderView, BiomeAccess.Storage, IBlockA // Local section copies. Read-only. private ClonedChunkSection[] sections; - // Biome caches for each chunk section - private BiomeCache[] biomeCaches; - - // The biome blend caches for each color resolver type - // This map is always re-initialized, but the caches themselves are taken from an object pool - private final Map biomeColorCaches = new Reference2ObjectOpenHashMap<>(); - - // The previously accessed and cached color resolver, used in conjunction with the cached color cache field - private ColorResolver prevColorResolver; - - // The cached lookup result for the previously accessed color resolver to avoid excess hash table accesses - // for vertex color blending - private BiomeColorCache prevColorCache; + // Biome data -- todo - each chunk column? + private byte[] biomeData; // The starting point from which this slice captures blocks private int baseX, baseY, baseZ; // The chunk origin of this slice + @Getter private ChunkSectionPos origin; public static ChunkRenderContext prepare(World world, ChunkSectionPos origin, ClonedChunkSectionCache sectionCache) { @@ -143,15 +123,12 @@ public WorldSlice(WorldClient world) { this.sections = new ClonedChunkSection[SECTION_TABLE_ARRAY_SIZE]; this.blockStatesArrays = new BlockState[SECTION_TABLE_ARRAY_SIZE][]; - this.biomeCaches = new BiomeCache[SECTION_TABLE_ARRAY_SIZE]; for (int x = 0; x < SECTION_LENGTH; x++) { for (int y = 0; y < SECTION_LENGTH; y++) { for (int z = 0; z < SECTION_LENGTH; z++) { - int i = getLocalSectionIndex(x, y, z); - + final int i = getLocalSectionIndex(x, y, z); this.blockStatesArrays[i] = new BlockState[SECTION_BLOCK_COUNT]; - this.biomeCaches[i] = new BiomeCache(this.world); } } } @@ -161,21 +138,15 @@ public void copyData(ChunkRenderContext context) { this.origin = context.getOrigin(); this.sections = context.getSections(); - this.prevColorCache = null; - this.prevColorResolver = null; - - this.biomeColorCaches.clear(); - this.baseX = (this.origin.x - NEIGHBOR_CHUNK_RADIUS) << 4; this.baseY = (this.origin.y - NEIGHBOR_CHUNK_RADIUS) << 4; this.baseZ = (this.origin.z - NEIGHBOR_CHUNK_RADIUS) << 4; + this.biomeData = null; for (int x = 0; x < SECTION_LENGTH; x++) { for (int y = 0; y < SECTION_LENGTH; y++) { for (int z = 0; z < SECTION_LENGTH; z++) { - int idx = getLocalSectionIndex(x, y, z); - - this.biomeCaches[idx].reset(); + final int idx = getLocalSectionIndex(x, y, z); this.unpackBlockData(this.blockStatesArrays[idx], this.sections[idx], context.getVolume()); } @@ -188,11 +159,6 @@ public Block getBlock(int x, int y, int z) { return this.getBlockState(x, y, z).getBlock(); } - @Override - public TileEntity getTileEntity(int x, int y, int z) { - // TODO - return null; - } @Override public int getLightBrightnessForSkyBlocks(int x, int y, int z, int min) { @@ -245,9 +211,9 @@ public boolean isAirBlock(int x, int y, int z) { @Override public BiomeGenBase getBiomeGenForCoords(int x, int z) { - // TODO: Use local cache -// return this.getBiome(x, 0, z); - return this.world.getBiomeGenForCoords(x, z); + // TODO: Do we need to handle neighboring chunk columns or is this sufficient? + final int k = this.biomeData[(x & 15) << 4 | (z & 15)] & 255; + return BiomeGenBase.getBiome(k); } @Override @@ -314,6 +280,9 @@ private void unpackBlockDataZ(BlockState[] states, ClonedChunkSection section) { int minBlockZ = pos.getMinZ(); int maxBlockZ = pos.getMaxZ(); + // Copy biome data from the origin sub-chunk. In 1.7.10 it's the same on every sub-chunk. + this.biomeData = section.getBiomeData(); + // TODO: Can this be optimized? copyBlocks(states, section, minBlockY, maxBlockY, minBlockZ, maxBlockZ, minBlockX, maxBlockX); } @@ -363,17 +332,14 @@ public float getBrightness(ForgeDirection direction, boolean shaded) { }; } - @Override - public LightingProvider getLightingProvider() { - return ((BlockRenderView)this.world).getLightingProvider(); - } @Override - public TileEntity getBlockEntity(BlockPos pos) { - return this.getBlockEntity(pos.x, pos.y, pos.z); + public TileEntity getTileEntity(BlockPos pos) { + return this.getTileEntity(pos.x, pos.y, pos.z); } - public TileEntity getBlockEntity(int x, int y, int z) { + @Override + public TileEntity getTileEntity(int x, int y, int z) { int relX = x - this.baseX; int relY = y - this.baseY; int relZ = z - this.baseZ; @@ -381,26 +347,6 @@ public TileEntity getBlockEntity(int x, int y, int z) { return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)].getBlockEntity(relX & 15, relY & 15, relZ & 15); } - @Override - public int getColor(BlockPos pos, ColorResolver resolver) { - BiomeColorCache cache; - - if (this.prevColorResolver == resolver) { - cache = this.prevColorCache; - } else { - cache = this.biomeColorCaches.get(resolver); - - if (cache == null) { - this.biomeColorCaches.put(resolver, cache = new BiomeColorCache(resolver, this)); - } - - this.prevColorResolver = resolver; - this.prevColorCache = cache; - } - - return cache.getBlendedColor(pos); - } - @Override public int getLightLevel(EnumSkyBlock type, BlockPos pos) { return getLightLevel(type, pos.x, pos.y, pos.z); @@ -416,42 +362,6 @@ public int getLightLevel(EnumSkyBlock type, int x, int y, int z) { return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)].getLightLevel(type, relX & 15, relY & 15, relZ & 15); } - @Override - public BiomeGenBase getBiomeForNoiseGen(int x, int y, int z) { - int x2 = (x >> 2) - (this.baseX >> 4); - int z2 = (z >> 2) - (this.baseZ >> 4); - - // Coordinates are in biome space! - // [VanillaCopy] WorldView#getBiomeForNoiseGen(int, int, int) - ClonedChunkSection section = this.sections[getLocalChunkIndex(x2, z2)]; - - if (section != null ) { - return section.getBiomeForNoiseGen(x, y, z); - } - - return this.world.getBiomeGenForCoords(x, z); - } - - /** - * Gets or computes the biome at the given global coordinates. - */ - public BiomeGenBase getBiome(int x, int y, int z) { - int relX = x - this.baseX; - int relY = y - this.baseY; - int relZ = z - this.baseZ; - - int index = getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4); - - index = index >= biomeCaches.length ? biomeCaches.length - 1 : index; - - BiomeCache cache = this.biomeCaches[index]; - return cache != null ? cache.getBiome(this, x, relY >> 4, z) : Minecraft.getMinecraft().theWorld.getBiomeGenForCoords(x, z); - } - - public ChunkSectionPos getOrigin() { - return this.origin; - } - public static int getLocalBlockIndex(int x, int y, int z) { return y << 8 | z << 4 | x; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java index a7cb87818..3b9b651a9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java @@ -3,12 +3,9 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import com.gtnewhorizons.angelica.compat.mojang.ColorResolver; import com.gtnewhorizons.angelica.compat.mojang.FluidState; -import com.gtnewhorizons.angelica.compat.mojang.LightingProvider; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.EnumSkyBlock; -import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.common.util.ForgeDirection; import javax.annotation.Nullable; @@ -29,30 +26,15 @@ public float getBrightness(ForgeDirection direction, boolean shaded) { return view.getBrightness(direction, shaded); } - @Override - public LightingProvider getLightingProvider() { - return view.getLightingProvider(); - } - - @Override - public int getColor(BlockPos pos, ColorResolver colorResolver) { - return view.getColor(pos, colorResolver); - } - @Override public int getLightLevel(EnumSkyBlock type, BlockPos pos) { return view.getLightLevel(type, pos); } - @Override - public BiomeGenBase getBiomeForNoiseGen(int x, int y, int z) { - return null; - } - @Override @Nullable - public TileEntity getBlockEntity(BlockPos pos) { - return view.getBlockEntity(pos); + public TileEntity getTileEntity(BlockPos pos) { + return view.getTileEntity(pos); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java deleted file mode 100644 index 55b92b146..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeCache.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.jellysquid.mods.sodium.client.world.biome; - -import com.gtnewhorizons.angelica.compat.mojang.BiomeAccess; -import com.gtnewhorizons.angelica.compat.mojang.BiomeAccessType; -import net.minecraft.world.World; -import net.minecraft.world.biome.BiomeGenBase; - -import java.util.Arrays; - -public class BiomeCache { - private final BiomeAccessType type; - private final long seed; - - private final BiomeGenBase[] biomes; - - public BiomeCache(World world) { - // TODO: Sodium - this.type = null;//world.getDimension().getBiomeAccessType(); // Provider? - this.seed = world.getSeed(); - - this.biomes = new BiomeGenBase[16 * 16]; - } - - public BiomeGenBase getBiome(BiomeAccess.Storage storage, int x, int y, int z) { - int idx = ((z & 15) << 4) | (x & 15); - - BiomeGenBase biome = this.biomes[idx]; - - if (biome == null && this.type != null) { - this.biomes[idx] = biome = this.type.getBiome(this.seed, x, y, z, storage); - } - - return biome; - } - - public void reset() { - Arrays.fill(this.biomes, null); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java deleted file mode 100644 index 0d7b68e98..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BiomeColorCache.java +++ /dev/null @@ -1,111 +0,0 @@ -package me.jellysquid.mods.sodium.client.world.biome; - -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; -import com.gtnewhorizons.angelica.compat.mojang.ColorResolver; -import me.jellysquid.mods.sodium.client.util.color.ColorARGB; -import me.jellysquid.mods.sodium.client.world.WorldSlice; - -import java.util.Arrays; - -public class BiomeColorCache { - private static final int BLENDED_COLORS_DIM = 16 + 2 * 2; - - private final ColorResolver resolver; - private final WorldSlice slice; - - private final int[] blendedColors; - private final int[] cache; - - private final int radius; - private final int dim; - private final int minX, minZ; - - private final int height; - - private final int blendedColorsMinX; - private final int blendedColorsMinZ; - - public BiomeColorCache(ColorResolver resolver, WorldSlice slice) { - this.resolver = resolver; - this.slice = slice; - this.radius = 2; // Minecraft.getMinecraft().options.biomeBlendRadius; - - ChunkSectionPos origin = this.slice.getOrigin(); - - this.minX = origin.getMinX() - (this.radius + 2); - this.minZ = origin.getMinZ() - (this.radius + 2); - - this.height = origin.getMinY(); - this.dim = 16 + ((this.radius + 2) * 2); - - this.blendedColorsMinX = origin.getMinX() - 2; - this.blendedColorsMinZ = origin.getMinZ() - 2; - - this.cache = new int[this.dim * this.dim]; - this.blendedColors = new int[BLENDED_COLORS_DIM * BLENDED_COLORS_DIM]; - - Arrays.fill(this.cache, -1); - Arrays.fill(this.blendedColors, -1); - } - - public int getBlendedColor(BlockPos pos) { - int x2 = pos.x - this.blendedColorsMinX; - int z2 = pos.z - this.blendedColorsMinZ; - - int index = (x2 * BLENDED_COLORS_DIM) + z2; - int color = this.blendedColors[index]; - - if (color == -1) { - this.blendedColors[index] = color = this.calculateBlendedColor(pos.x, pos.getZ()); - } - - return color; - } - - private int calculateBlendedColor(int posX, int posZ) { - if (this.radius == 0) { - return this.getColor(posX, posZ); - } - - int diameter = (this.radius * 2) + 1; - int area = diameter * diameter; - - int r = 0; - int g = 0; - int b = 0; - - int minX = posX - this.radius; - int minZ = posZ - this.radius; - - int maxX = posX + this.radius; - int maxZ = posZ + this.radius; - - for (int x2 = minX; x2 <= maxX; x2++) { - for (int z2 = minZ; z2 <= maxZ; z2++) { - int color = this.getColor(x2, z2); - - r += ColorARGB.unpackRed(color); - g += ColorARGB.unpackGreen(color); - b += ColorARGB.unpackBlue(color); - } - } - - return ColorARGB.pack(r / area, g / area, b / area, 255); - } - - private int getColor(int x, int z) { - int index = ((x - this.minX) * this.dim) + (z - this.minZ); - int color = this.cache[index]; - - if (color == -1) { - this.cache[index] = color = this.calculateColor(x, z); - } - - return color; - } - - private int calculateColor(int x, int z) { - return this.resolver.getColor(this.slice.getBiome(x, this.height, z), x, z); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java deleted file mode 100644 index d863808b2..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/BlockColorsExtended.java +++ /dev/null @@ -1,8 +0,0 @@ -package me.jellysquid.mods.sodium.client.world.biome; - -import com.gtnewhorizons.angelica.compat.mojang.BlockColorProvider; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; - -public interface BlockColorsExtended { - BlockColorProvider getColorProvider(BlockState state); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java b/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java deleted file mode 100644 index 4ee2f2674..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/biome/ItemColorsExtended.java +++ /dev/null @@ -1,8 +0,0 @@ -package me.jellysquid.mods.sodium.client.world.biome; - -import com.gtnewhorizons.angelica.compat.mojang.ItemColorProvider; -import net.minecraft.item.ItemStack; - -public interface ItemColorsExtended { - ItemColorProvider getColorProvider(ItemStack stack); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 41a7a962b..799f11040 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -7,6 +7,7 @@ import com.gtnewhorizons.angelica.mixins.interfaces.IExtendedBlockStorageExt; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; +import lombok.Getter; import net.minecraft.block.Block; import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; @@ -36,6 +37,7 @@ public class ClonedChunkSection { private ChunkSectionPos pos; + @Getter private byte[] biomeData; private long lastUsedTimestamp = Long.MAX_VALUE; @@ -71,7 +73,6 @@ public void init(ChunkSectionPos pos) { for (Map.Entry entry : chunk.chunkTileEntityMap.entrySet()) { BlockPos entityPos = new BlockPos(entry.getKey()); -// if (box.contains(entityPos)) { if(box.isVecInside(entityPos.getX(), entityPos.getY(), entityPos.getZ())) { //this.blockEntities.put(BlockPos.asLong(entityPos.getX() & 15, entityPos.getY() & 15, entityPos.getZ() & 15), entry.getValue()); this.tileEntities.put(ChunkSectionPos.packLocal(entityPos), entry.getValue()); From d15de6dd956317189545a4c51a17d1c464fdb3c3 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 18 Nov 2023 12:01:04 -0800 Subject: [PATCH 062/301] Cache worldHeight instead of asking the provider every time --- .../me/jellysquid/mods/sodium/client/world/WorldSlice.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 1157c82b9..c1b1ef7ee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -74,6 +74,8 @@ public class WorldSlice implements BlockRenderView, IBlockAccess { // The starting point from which this slice captures blocks private int baseX, baseY, baseZ; + private final int worldHeight; + // The chunk origin of this slice @Getter private ChunkSectionPos origin; @@ -120,6 +122,7 @@ public static ChunkRenderContext prepare(World world, ChunkSectionPos origin, Cl public WorldSlice(WorldClient world) { this.world = world; + this.worldHeight = world.getHeight(); this.sections = new ClonedChunkSection[SECTION_TABLE_ARRAY_SIZE]; this.blockStatesArrays = new BlockState[SECTION_TABLE_ARRAY_SIZE][]; @@ -218,7 +221,7 @@ public BiomeGenBase getBiomeGenForCoords(int x, int z) { @Override public int getHeight() { - return this.world.provider.getActualHeight(); + return this.worldHeight; } @Override From 2418abcff85430b1188757594f884b293b76cee5 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 18 Nov 2023 14:02:35 -0800 Subject: [PATCH 063/301] Debug Screen updates --- .../gtnewhorizons/angelica/AngelicaMod.java | 5 +++ .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../early/sodium/MixinFMLClientHandler.java | 22 ++++++++++++ .../mixins/early/sodium/MixinMinecraft.java | 5 +++ .../early/sodium/MixinRenderGlobal.java | 15 ++++++++ .../mixins/interfaces/IRenderGlobalExt.java | 1 + .../angelica/proxy/ClientProxy.java | 8 +++++ .../angelica/proxy/CommonProxy.java | 2 ++ .../client/SodiumDebugScreenHandler.java | 36 +++++++++++++++++++ .../client/render/SodiumWorldRenderer.java | 7 ++-- .../render/chunk/ChunkRenderManager.java | 28 ++++++++++++--- 11 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinFMLClientHandler.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/SodiumDebugScreenHandler.java diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index 16e82aa82..7bfdaa969 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -26,4 +26,9 @@ public void preInit(FMLPreInitializationEvent event) { public void init(FMLInitializationEvent event) { proxy.init(event); } + + @Mod.EventHandler + public void postInit(FMLInitializationEvent event) { + proxy.postInit(event); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 9e86e1b8a..8daf96c38 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -32,6 +32,7 @@ public enum Mixins { .setPhase(Phase.EARLY).addMixinClasses( "sodium.MixinChunkProviderClient" ,"sodium.MixinExtendedBlockStorage" + ,"sodium.MixinFMLClientHandler" ,"sodium.MixinFrustrum" ,"sodium.MixinMinecraft" ,"sodium.MixinNetHandlerPlayClient" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinFMLClientHandler.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinFMLClientHandler.java new file mode 100644 index 000000000..3abf6ad7f --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinFMLClientHandler.java @@ -0,0 +1,22 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.Tags; +import cpw.mods.fml.client.FMLClientHandler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +import java.util.Collections; +import java.util.List; + +@Mixin(value=FMLClientHandler.class, remap=false) +public class MixinFMLClientHandler { + /** + * @author mitchej123 + * @reason Hack in Additional FML Branding + */ + @Overwrite + public List getAdditionalBrandingInformation() { + return Collections.singletonList(String.format("Angelica %s", Tags.VERSION)); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java index 550468014..b4087f17a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java @@ -7,6 +7,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Minecraft.class) @@ -21,4 +22,8 @@ public class MixinMinecraft { } } + @Redirect(method="runGameLoop", at=@At(value="FIELD", target="Lnet/minecraft/client/renderer/WorldRenderer;chunksUpdated:I", ordinal=0)) + private int sodium$chunksUpdated() { + return ((IRenderGlobalExt)this.renderGlobal).getChunksSubmitted(); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index c8319db03..a4f630806 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -46,6 +46,11 @@ public void scheduleTerrainUpdate() { this.renderer.scheduleTerrainUpdate(); } + @Override + public int getChunksSubmitted() { + return this.renderer.getChunksSubmitted(); + } + @Inject(method="", at=@At("RETURN")) private void sodium$initRenderer(Minecraft mc, CallbackInfo ci) { this.renderer = SodiumWorldRenderer.create(mc); @@ -61,6 +66,16 @@ public void scheduleTerrainUpdate() { } } + /** + * @author mitchej123, sodium + * @reason Redirect to our renderer + */ + @Overwrite + public String getDebugInfoRenders() { + return this.renderer.getChunksDebugString(); + // + ". F: " + this.renderersBeingClipped + ", O: " + this.renderersBeingOccluded + ", E: " + this.renderersSkippingRenderPass; + } + /** * @author Sodium * @reason Redirect to our renderer diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IRenderGlobalExt.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IRenderGlobalExt.java index 43133d0c7..fc262db3d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IRenderGlobalExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IRenderGlobalExt.java @@ -2,5 +2,6 @@ public interface IRenderGlobalExt { void scheduleTerrainUpdate(); + int getChunksSubmitted(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index dcf2931df..fe041809e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -6,6 +6,8 @@ import jss.notfine.gui.GuiCustomMenu; import jss.notfine.gui.ISettingsEnum; import jss.notfine.gui.MenuButtonLists; +import me.jellysquid.mods.sodium.client.SodiumDebugScreenHandler; +import net.minecraftforge.common.MinecraftForge; public class ClientProxy extends CommonProxy { @@ -22,4 +24,10 @@ public void preInit(FMLPreInitializationEvent event) { public void init(FMLInitializationEvent event) { // Nothing to do here (yet) } + + @Override + public void postInit(FMLInitializationEvent event) { + /// TODO: If Sodium is active/loaded + MinecraftForge.EVENT_BUS.register(SodiumDebugScreenHandler.INSTANCE); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java index e7ca18f7a..8810f5758 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java @@ -10,4 +10,6 @@ public void preInit(FMLPreInitializationEvent event) { } public void init(FMLInitializationEvent event) {} + + public void postInit(FMLInitializationEvent event) {} } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumDebugScreenHandler.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumDebugScreenHandler.java new file mode 100644 index 000000000..7e9560f4d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumDebugScreenHandler.java @@ -0,0 +1,36 @@ +package me.jellysquid.mods.sodium.client; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderBackend; +import net.minecraft.client.Minecraft; +import net.minecraftforge.client.event.RenderGameOverlayEvent; + +import java.util.ArrayList; +import java.util.List; + +public class SodiumDebugScreenHandler { + public static final SodiumDebugScreenHandler INSTANCE = new SodiumDebugScreenHandler(); + @SubscribeEvent + public void onRenderGameOverlayTextEvent(RenderGameOverlayEvent.Text event) { + final Minecraft mc = Minecraft.getMinecraft(); + if (mc.gameSettings.showDebugInfo) { + event.right.add(""); + event.right.add("Sodium (Embeddium) Renderer"); + event.right.addAll(getChunkRendererDebugStrings()); + + } + } + + private static List getChunkRendererDebugStrings() { + ChunkRenderBackend backend = SodiumWorldRenderer.getInstance().getChunkRenderer(); + + List strings = new ArrayList<>(5); + strings.add("Chunk Renderer: " + backend.getRendererName()); + strings.add("Block Renderer: " + "Sodium"); + strings.addAll(backend.getDebugStrings()); + + return strings; + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 06ab5f6cf..89db34c2a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -127,6 +127,10 @@ public void setWorld(WorldClient world) { } } + public int getChunksSubmitted() { + return this.chunkRenderManager != null ? this.chunkRenderManager.getAndResetSubmitted() : 0; + } + private void loadWorld(WorldClient world) { this.world = world; @@ -167,7 +171,6 @@ public int getVisibleChunkCount() { * Notifies the chunk renderer that the graph scene has changed and should be re-computed. */ public void scheduleTerrainUpdate() { - // BUG: seems to be called before init if (this.chunkRenderManager != null) { this.chunkRenderManager.markDirty(); } @@ -432,7 +435,7 @@ public boolean isEntityVisible(Entity entity) { public String getChunksDebugString() { // C: visible/total // TODO: add dirty and queued counts - return String.format("C: %s/%s", this.chunkRenderManager.getVisibleChunkCount(), this.chunkRenderManager.getTotalSections()); + return String.format("C: %s/%s S: %s Q: %s+%si ", this.chunkRenderManager.getVisibleChunkCount(), this.chunkRenderManager.getTotalSections(), this.chunkRenderManager.getSubmitted(), this.chunkRenderManager.getRebuildQueueSize(), this.chunkRenderManager.getImportantRebuildQueueSize()); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index da3f6acd4..68bb85442 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -11,6 +11,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayFIFOQueue; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectList; +import lombok.Getter; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.compat.FogHelper; import me.jellysquid.mods.sodium.client.gl.device.CommandList; @@ -92,8 +93,13 @@ public class ChunkRenderManager implements ChunkSt private float cameraX, cameraY, cameraZ; private boolean dirty; + @Getter + private int submitted; + private int totalSubmitted; + private final boolean translucencySorting; + @Getter private int visibleChunkCount; private boolean useFogCulling; @@ -134,6 +140,14 @@ public void update(Camera camera, FrustumExtended frustum, int frame, boolean sp this.dirty = false; } + public int getRebuildQueueSize() { + return this.rebuildQueue.size(); + } + + public int getImportantRebuildQueueSize() { + return this.importantRebuildQueue.size(); + } + private void setup(Camera camera) { Vector3d cameraPos = camera.getPos(); @@ -479,7 +493,7 @@ public void updateChunks() { Deque>> futures = new ArrayDeque<>(); int budget = this.builder.getSchedulingBudget(); - int submitted = 0; + submitted = 0; while (!this.importantRebuildQueue.isEmpty()) { ChunkRenderContainer render = this.importantRebuildQueue.dequeue(); @@ -518,6 +532,7 @@ public void updateChunks() { sortedAnything = true; submitted++; } + totalSubmitted += submitted; this.dirty |= submitted > 0; @@ -529,6 +544,13 @@ public void updateChunks() { } } + public int getAndResetSubmitted() { + // Return how many chunks were submitted since the last call to this method + final int submitted = totalSubmitted; + totalSubmitted = 0; + return submitted; + } + public void markDirty() { this.dirty = true; } @@ -615,10 +637,6 @@ public boolean isChunkPrioritized(ChunkRenderContainer render) { return render != null ? render.getSquaredDistance(this.cameraX, this.cameraY, this.cameraZ) <= NEARBY_CHUNK_DISTANCE : false; } - public int getVisibleChunkCount() { - return this.visibleChunkCount; - } - public void onChunkRenderUpdates(int x, int y, int z, ChunkRenderData data) { this.culler.onSectionStateChanged(x, y, z, data.getOcclusionData()); } From 868e33877c3ea377f3c1ffd1c5ffd465f67446a1 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 18 Nov 2023 14:14:45 -0800 Subject: [PATCH 064/301] Disable Culling for now (until it works) --- .../mods/sodium/client/render/chunk/ChunkRenderManager.java | 6 ++++-- .../client/render/chunk/cull/graph/ChunkGraphCuller.java | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 68bb85442..e4b6b6074 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -127,7 +127,8 @@ public ChunkRenderManager(SodiumWorldRenderer renderer, ChunkRenderBackend ba this.translucencySorting = SodiumClientMod.options().advanced.translucencySorting; this.translucencyBlockRenderDistance = Math.min(9216, (renderDistance << 4) * (renderDistance << 4)); - this.useBlockFaceCulling = SodiumClientMod.options().advanced.useBlockFaceCulling; + // TODO: Sodium - Culling + this.useBlockFaceCulling = false; //SodiumClientMod.options().advanced.useBlockFaceCulling; } public void update(Camera camera, FrustumExtended frustum, int frame, boolean spectator) { @@ -162,7 +163,8 @@ private void setup(Camera camera) { float dist = FogHelper.getFogCutoff() + FOG_PLANE_OFFSET; if (dist != 0.0f) { - this.useFogCulling = true; + // TODO: Sodium - Culling + //this.useFogCulling = true; // TODO fix fog this.fogRenderCutoff = Math.max(FOG_PLANE_MIN_DISTANCE, dist * dist); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java index f7d1bc695..46a62d611 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java @@ -74,7 +74,8 @@ private void initSearch(Camera camera, FrustumExtended frustum, int frame, boole this.activeFrame = frame; this.frustum = frustum; // TODO: Sodium Options - this.useOcclusionCulling = true; //Minecraft.getMinecraft().chunkCullingEnabled; + // TODO: Sodium - Culling + this.useOcclusionCulling = false; //Minecraft.getMinecraft().chunkCullingEnabled; this.visible.clear(); From 4d0b0f2fa34488cdd60299c020a4eb0df5d706d3 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 18 Nov 2023 14:52:10 -0800 Subject: [PATCH 065/301] Tessellator Updates * Use one instance on the main thread, and individual instances on every other thread * Prevent draw() and buffer.reset() on non singleton instance --- .../gtnewhorizons/angelica/mixins/Mixins.java | 2 +- .../MixinRenderBlocks.java | 12 ++-- .../early/sodium/MixinRenderGlobal.java | 1 - .../mixins/early/sodium/MixinTessellator.java | 65 +++++-------------- .../mods/sodium/client/SodiumClientMod.java | 5 ++ .../chunk/tasks/ChunkRenderRebuildTask.java | 5 +- .../client/render/pipeline/BlockRenderer.java | 5 +- 7 files changed, 36 insertions(+), 59 deletions(-) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{angelica => sodium}/MixinRenderBlocks.java (68%) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 8daf96c38..d139ff753 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -12,7 +12,6 @@ public enum Mixins { ANGELICA(new Builder("Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( "angelica.MixinEntityRenderer" - ,"angelica.MixinRenderBlocks" ) ), IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) @@ -37,6 +36,7 @@ public enum Mixins { ,"sodium.MixinMinecraft" ,"sodium.MixinNetHandlerPlayClient" ,"sodium.MixinNibbleArray" + ,"sodium.MixinRenderBlocks" ,"sodium.MixinRenderGlobal" ,"sodium.MixinTessellator" ,"sodium.MixinWorldClient" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java similarity index 68% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java index 42ecdfa2f..f0f48b452 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinRenderBlocks.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java @@ -1,6 +1,7 @@ -package com.gtnewhorizons.angelica.mixins.early.angelica; +package com.gtnewhorizons.angelica.mixins.early.sodium; import com.gtnewhorizons.angelica.mixins.interfaces.IHasTessellator; +import me.jellysquid.mods.sodium.client.SodiumClientMod; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.Tessellator; import org.spongepowered.asm.mixin.Mixin; @@ -11,7 +12,8 @@ @Mixin(RenderBlocks.class) public class MixinRenderBlocks implements IHasTessellator { - private Tessellator sodium$tessellator; + // Sodium Tesselator will be non null if we are not on the main thread + private Tessellator sodium$tessellator = null; @Override public Tessellator getTessellator() { @@ -20,12 +22,14 @@ public Tessellator getTessellator() { @Inject(method = {"()V","(Lnet/minecraft/world/IBlockAccess;)V"}, at = @At("TAIL")) private void initTessellator(CallbackInfo ci) { - sodium$tessellator = new Tessellator(); + if(Thread.currentThread() != SodiumClientMod.getMainThread()) { + sodium$tessellator = new Tessellator(); + } } @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;instance:Lnet/minecraft/client/renderer/Tessellator;")) private Tessellator modifyTessellatorAccess() { - return sodium$tessellator; + return sodium$tessellator != null ? sodium$tessellator : Tessellator.instance; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index a4f630806..759add6ce 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -73,7 +73,6 @@ public int getChunksSubmitted() { @Overwrite public String getDebugInfoRenders() { return this.renderer.getChunksDebugString(); - // + ". F: " + this.renderersBeingClipped + ", O: " + this.renderersBeingOccluded + ", E: " + this.renderersSkippingRenderPass; } /** diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java index 37dc48a4b..a5cf6f58e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java @@ -1,7 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; import com.gtnewhorizons.angelica.mixins.interfaces.ITessellatorInstance; -import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.Tessellator; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -9,26 +8,15 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.nio.Buffer; import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; @Mixin(Tessellator.class) public abstract class MixinTessellator implements ITessellatorInstance { - @Shadow(remap=false) private static int nativeBufferSize; @Shadow public int vertexCount; @Shadow public boolean isDrawing; - @Shadow static ByteBuffer byteBuffer; - @Shadow private static IntBuffer intBuffer; - @Shadow private static FloatBuffer floatBuffer; - @Shadow private static ShortBuffer shortBuffer; - - private ByteBuffer angelica$byteBuffer; - private IntBuffer angelica$intBuffer; - private FloatBuffer angelica$floatBuffer; - private ShortBuffer angelica$shortBuffer; public float angelica$normalX; public float angelica$normalY; public float angelica$normalZ; @@ -36,26 +24,23 @@ public abstract class MixinTessellator implements ITessellatorInstance { public float angelica$midTextureV; @Shadow public abstract void reset(); - @Inject(method = "", at = @At("TAIL")) - private static void killStaticBuffer(CallbackInfo ci) { - byteBuffer = null; - intBuffer = null; - floatBuffer = null; - shortBuffer = null; - } - @Inject(method = "(I)V", at = @At("TAIL")) - private void angelica$extendBufferConstructor(int bufferSize, CallbackInfo ci) { - angelica$byteBuffer = GLAllocation.createDirectByteBuffer(bufferSize * 4); - angelica$intBuffer = angelica$byteBuffer.asIntBuffer(); - angelica$floatBuffer = angelica$byteBuffer.asFloatBuffer(); - angelica$shortBuffer = angelica$byteBuffer.asShortBuffer(); - this.isDrawing = false; + /** + * @reason Allow using multiple tessellator instances concurrently by removing static field access in alternate instances. + **/ + @Redirect(method = "reset", at = @At(value = "INVOKE", target = "Ljava/nio/ByteBuffer;clear()Ljava/nio/Buffer;")) + private Buffer removeStaticBufferResetOutsideSingleton(ByteBuffer buffer) { + if(((Object)this) == Tessellator.instance) { + return buffer.clear(); + } + return buffer; } - @Inject(method = "()V", at = @At("TAIL")) - private void angelica$extendEmptyConstructor(CallbackInfo ci) { - this.angelica$extendBufferConstructor(nativeBufferSize, null); + @Inject(method="draw", at=@At("HEAD")) + private void preventOffMainThreadDrawing(CallbackInfoReturnable cir) { + if(((Object)this) != Tessellator.instance) { + throw new RuntimeException("Tried to draw on a tessellator that isn't on the main thread!"); + } } @Inject(method = "setNormal(FFF)V", at = @At("HEAD")) @@ -65,24 +50,6 @@ private static void killStaticBuffer(CallbackInfo ci) { this.angelica$normalZ = z; } - // Redirect static buffer access to the instance buffers - @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;byteBuffer:Ljava/nio/ByteBuffer;")) - private ByteBuffer modifyByteBufferAccess() { - return this.angelica$byteBuffer; - } - @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;intBuffer:Ljava/nio/IntBuffer;")) - private IntBuffer modifyIntBufferAccess() { - return this.angelica$intBuffer; - } - @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;floatBuffer:Ljava/nio/FloatBuffer;")) - private FloatBuffer modifyFloatBufferAccess() { - return this.angelica$floatBuffer; - } - @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;shortBuffer:Ljava/nio/ShortBuffer;")) - private ShortBuffer modifyShortBufferAccess() { - return this.angelica$shortBuffer; - } - // New methods from ITesselatorInstance diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index 4fa03b12b..1dd6665fe 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -2,6 +2,7 @@ import com.gtnewhorizons.angelica.Tags; import cpw.mods.fml.common.Mod; +import lombok.Getter; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; import net.minecraft.client.Minecraft; import org.apache.logging.log4j.LogManager; @@ -21,7 +22,11 @@ public class SodiumClientMod { public static final String MODID = "embeddium"; public static final String NAME = "Embeddium"; + @Getter + private static Thread MainThread; + public SodiumClientMod() { + MainThread = Thread.currentThread(); // FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onInitializeClient); // // ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 645475c72..f25143e0e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -9,7 +9,6 @@ import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.compat.mojang.RenderLayers; import com.gtnewhorizons.angelica.mixins.interfaces.IHasTessellator; -import com.gtnewhorizons.angelica.mixins.interfaces.ITessellatorInstance; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer; @@ -119,12 +118,12 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB // BakedModel model = cache.getBlockModels().getModel(blockState); // long seed = blockState.getRenderingSeed(pos); - tessellator.startDrawingQuads(); + if (cache.getBlockRenderer().renderModel(cache.getLocalSlice(), tessellator, renderBlocks, blockState, pos, buffers.get(layer), true, seed)) { bounds.addBlock(relX, relY, relZ); } - ((ITessellatorInstance) tessellator).discard(); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index 9f91ee06a..10b39ca71 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -6,6 +6,7 @@ import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.compat.nd.Quad; import com.gtnewhorizons.angelica.compat.nd.RecyclingList; +import com.gtnewhorizons.angelica.mixins.interfaces.ITessellatorInstance; import me.jellysquid.mods.sodium.client.model.light.LightMode; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; @@ -81,6 +82,8 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende final Block block = state.getBlock(); // TODO: Occlusion by side... needs to break apart or invasively modify renderBlockByRenderType // Or figure out the facing of the quad... + + tessellator.startDrawingQuads(); rendered = renderBlocks.renderBlockByRenderType(block, pos.x, pos.y, pos.z); // for (ForgeDirection dir : DirectionUtil.ALL_DIRECTIONS) { @@ -101,7 +104,7 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende this.random.setSeed(seed); final List all = tesselatorToBakedQuadList(tessellator, pos); - + ((ITessellatorInstance) tessellator).discard(); // List all = model.getQuads(state, null, this.random, modelData); From c0f068482a8dae5c2359f937c73bb04e382e2a86 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 18 Nov 2023 15:49:38 -0800 Subject: [PATCH 066/301] Misc cleanup --- .../angelica/compat/nd/QuadNormal.java | 16 +++---- .../client/render/SodiumWorldRenderer.java | 2 +- .../render/chunk/ChunkRenderContainer.java | 41 ++++++------------ .../render/chunk/ChunkRenderManager.java | 2 +- .../render/chunk/data/ChunkRenderData.java | 43 +++++++------------ .../client/render/pipeline/BlockRenderer.java | 24 +++-------- 6 files changed, 43 insertions(+), 85 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java index a640ae50e..5c92870f0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java @@ -3,9 +3,11 @@ import org.joml.Vector3f; public enum QuadNormal { - // Temporarily borrowed from Neodymium + // Adapted from Neodymium NONE, POSITIVE_X, NEGATIVE_X, POSITIVE_Y, NEGATIVE_Y, POSITIVE_Z, NEGATIVE_Z; + private static final QuadNormal[] NORMAL_ORDER = new QuadNormal[] {QuadNormal.NONE, QuadNormal.POSITIVE_Y, QuadNormal.POSITIVE_X, QuadNormal.POSITIVE_Z, QuadNormal.NEGATIVE_X, QuadNormal.NEGATIVE_Z, QuadNormal.NEGATIVE_Y}; + public static QuadNormal fromVector(Vector3f normal) { if(normal.x == 0f) { if(normal.y == 0f) { @@ -21,13 +23,11 @@ public static QuadNormal fromVector(Vector3f normal) { return NEGATIVE_Y; } } - } else if(normal.y == 0f) { - if(normal.z == 0f) { - if(normal.x > 0) { - return POSITIVE_X; - } else if(normal.x < 0) { - return NEGATIVE_X; - } + } else if(normal.y == 0f && (normal.z == 0f)) { + if(normal.x > 0) { + return POSITIVE_X; + } else if(normal.x < 0) { + return NEGATIVE_X; } } return NONE; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 89db34c2a..10a6e4fef 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -374,7 +374,7 @@ public void onChunkRemoved(int x, int z) { } public void onChunkRenderUpdated(int x, int y, int z, ChunkRenderData meshBefore, ChunkRenderData meshAfter) { - ListUtil.updateList(this.globalTileEntities, meshBefore.getGlobalBlockEntities(), meshAfter.getGlobalBlockEntities()); + ListUtil.updateList(this.globalTileEntities, meshBefore.getGlobalTileEntities(), meshAfter.getGlobalTileEntities()); this.chunkRenderManager.onChunkRenderUpdates(x, y, z, meshAfter); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java index 112382440..3c9e1684e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java @@ -2,6 +2,7 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import lombok.Getter; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderBounds; @@ -20,11 +21,18 @@ */ public class ChunkRenderContainer { private final SodiumWorldRenderer worldRenderer; - private final int chunkX, chunkY, chunkZ; - + @Getter + private final int chunkX; + @Getter + private final int chunkY; + @Getter + private final int chunkZ; + + @Getter private final T[] graphicsStates; private final ChunkRenderColumn column; + @Getter private ChunkRenderData data = ChunkRenderData.ABSENT; private CompletableFuture rebuildTask = null; @@ -33,7 +41,9 @@ public class ChunkRenderContainer { private boolean needsSort; + @Getter private boolean tickable; + @Getter private int id; private boolean rebuildableForTranslucents; @@ -66,10 +76,6 @@ public void cancelRebuildTask() { } } - public ChunkRenderData getData() { - return this.data; - } - /** * @return True if the render's state is out of date with the world state */ @@ -263,10 +269,6 @@ public BlockPos getRenderOrigin() { return new BlockPos(this.getRenderX(), this.getRenderY(), this.getRenderZ()); } - public T[] getGraphicsStates() { - return this.graphicsStates; - } - public void setGraphicsState(BlockRenderPass pass, T state) { this.graphicsStates[pass.ordinal()] = state; } @@ -281,18 +283,6 @@ public double getSquaredDistanceXZ(double x, double z) { return (xDist * xDist) + (zDist * zDist); } - public int getChunkX() { - return this.chunkX; - } - - public int getChunkY() { - return this.chunkY; - } - - public int getChunkZ() { - return this.chunkZ; - } - public ChunkRenderBounds getBounds() { return this.data.getBounds(); } @@ -301,10 +291,6 @@ public T getGraphicsState(BlockRenderPass pass) { return this.graphicsStates[pass.ordinal()]; } - public boolean isTickable() { - return this.tickable; - } - public int getFacesWithData() { return this.data.getFacesWithData(); } @@ -317,7 +303,4 @@ public void setId(int id) { this.id = id; } - public int getId() { - return this.id; - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index e4b6b6074..6a0a74e27 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -305,7 +305,7 @@ private int computeVisibleFaces(ChunkRenderContainer render) { } private void addEntitiesToRenderLists(ChunkRenderContainer render) { - Collection blockEntities = render.getData().getBlockEntities(); + Collection blockEntities = render.getData().getTileEntities(); if (!blockEntities.isEmpty()) { this.visibleBlockEntities.addAll(blockEntities); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java index 9a95d571f..1f9840786 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.mixins.early.textures.ISpriteExt; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import lombok.Getter; import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; @@ -28,18 +29,22 @@ public class ChunkRenderData { .build(); public static final ChunkRenderData EMPTY = createEmptyData(); - private List globalBlockEntities; - private List blockEntities; + private List globalTileEntities; + private List tileEntities; private EnumMap meshes; + @Getter private ChunkOcclusionData occlusionData; + @Getter private ChunkRenderBounds bounds; + @Getter private List animatedSprites; private boolean isEmpty; private int meshByteSize; + @Getter private int facesWithData; /** @@ -49,31 +54,19 @@ public boolean isEmpty() { return this.isEmpty; } - public ChunkRenderBounds getBounds() { - return this.bounds; - } - - public ChunkOcclusionData getOcclusionData() { - return this.occlusionData; - } - - public List getAnimatedSprites() { - return this.animatedSprites; - } - /** * The collection of block entities contained by this rendered chunk. */ - public Collection getBlockEntities() { - return this.blockEntities; + public Collection getTileEntities() { + return this.tileEntities; } /** * The collection of block entities contained by this rendered chunk section which are not part of its culling * volume. These entities should always be rendered regardless of the render being visible in the frustum. */ - public Collection getGlobalBlockEntities() { - return this.globalBlockEntities; + public Collection getGlobalTileEntities() { + return this.globalTileEntities; } /** @@ -93,14 +86,10 @@ public int getMeshSize() { return this.meshByteSize; } - public int getFacesWithData() { - return this.facesWithData; - } - public ChunkRenderData copyAndReplaceMesh(Map replacements) { ChunkRenderData data = new ChunkRenderData(); - data.globalBlockEntities = this.globalBlockEntities; - data.blockEntities = this.blockEntities; + data.globalTileEntities = this.globalTileEntities; + data.tileEntities = this.tileEntities; data.occlusionData = this.occlusionData; data.meshes = new EnumMap<>(this.meshes); data.bounds = this.bounds; @@ -118,7 +107,7 @@ public ChunkRenderData copyAndReplaceMesh(Map re } } - data.isEmpty = this.globalBlockEntities.isEmpty() && this.blockEntities.isEmpty() && facesWithData == 0; + data.isEmpty = this.globalTileEntities.isEmpty() && this.tileEntities.isEmpty() && facesWithData == 0; data.meshByteSize = size; data.facesWithData = facesWithData; return data; @@ -174,8 +163,8 @@ public void addBlockEntity(TileEntity entity, boolean cull) { public ChunkRenderData build() { ChunkRenderData data = new ChunkRenderData(); - data.globalBlockEntities = this.globalBlockEntities; - data.blockEntities = this.blockEntities; + data.globalTileEntities = this.globalBlockEntities; + data.tileEntities = this.blockEntities; data.occlusionData = this.occlusionData; data.meshes = this.meshes; data.bounds = this.bounds; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index 10b39ca71..2cc950d21 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -62,29 +62,14 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende final LightPipeline lighter = this.lighters.getLighter(mode); Vector3d offset = state.getModelOffset(world, pos); - boolean rendered; + boolean rendered = false; // modelData = model.getModelData(world, pos, state, modelData); -// -// if(ForgeBlockRenderer.useForgeLightingPipeline()) { -// MatrixStack mStack; -// if(!offset.equals(ZERO)) { -// mStack = new MatrixStack(); -// mStack.translate(offset.x, offset.y, offset.z); -// } else -// mStack = EMPTY_STACK; -// final SinkingVertexBuilder builder = SinkingVertexBuilder.getInstance(); -// builder.reset(); -// rendered = forgeBlockRenderer.renderBlock(mode, state, pos, world, model, mStack, builder, random, seed, modelData, cull, this.occlusionCache, buffers.getRenderData()); -// builder.flush(buffers); -// return rendered; -// } + final Block block = state.getBlock(); - // TODO: Occlusion by side... needs to break apart or invasively modify renderBlockByRenderType - // Or figure out the facing of the quad... tessellator.startDrawingQuads(); - rendered = renderBlocks.renderBlockByRenderType(block, pos.x, pos.y, pos.z); + renderBlocks.renderBlockByRenderType(block, pos.x, pos.y, pos.z); // for (ForgeDirection dir : DirectionUtil.ALL_DIRECTIONS) { // this.random.setSeed(seed); @@ -103,6 +88,7 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende // } this.random.setSeed(seed); + // TODO: Occlusion by side... Potentially adapt the logic from Neodyium... final List all = tesselatorToBakedQuadList(tessellator, pos); ((ITessellatorInstance) tessellator).discard(); @@ -119,7 +105,7 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende private int tesselatorDataCount; private List tesselatorToBakedQuadList(Tessellator t, BlockPos pos) { - // Temporarily borrowed/badly adapted from Neodymium + // Adapted from Neodymium tesselatorDataCount++; // List errors = new ArrayList<>(); From d8302361806411eb366955dd34669b48702a3a4d Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 19 Nov 2023 13:12:24 -0500 Subject: [PATCH 067/301] Disable multidraw --- .../mods/sodium/client/render/SodiumWorldRenderer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 10a6e4fef..f0eee352b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -300,7 +300,8 @@ private void initRenderer() { private static ChunkRenderBackend createChunkRenderBackend(RenderDevice device, SodiumGameOptions options, ChunkVertexType vertexFormat) { boolean disableBlacklist = SodiumClientMod.options().advanced.ignoreDriverBlacklist; - if (options.advanced.useChunkMultidraw && MultidrawChunkRenderBackend.isSupported(disableBlacklist)) { + // TODO: Re-enable multidraw + if (false && options.advanced.useChunkMultidraw && MultidrawChunkRenderBackend.isSupported(disableBlacklist)) { return new MultidrawChunkRenderBackend(device, vertexFormat); } else { return new ChunkRenderBackendOneshot(vertexFormat); From 8fb5d6ae131bc50f93c6ac4badeb00082cba1d7a Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 19 Nov 2023 22:20:36 -0800 Subject: [PATCH 068/301] Misc cleanup, maybe better growBuffer? --- .../angelica/compat/forge/EmptyModelData.java | 7 ----- .../compat/forge/ModelDataManager.java | 27 ------------------- .../notfine/settings/MixinGameSettings.java | 2 +- .../renderer/MixinLayeredTexture.java | 2 +- .../IndirectCommandBufferVector.java | 8 +++--- 5 files changed, 7 insertions(+), 39 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/EmptyModelData.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/EmptyModelData.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/EmptyModelData.java deleted file mode 100644 index 273d59019..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/EmptyModelData.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -public enum EmptyModelData implements IModelData { - INSTANCE; - - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java deleted file mode 100644 index 3b2313bea..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/ModelDataManager.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -import com.google.common.base.Preconditions; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; -import net.minecraft.world.World; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class ModelDataManager { - private static final Map> modelDataCache = new ConcurrentHashMap<>(); - - public static @Nullable IModelData getModelData(World world, BlockPos pos) - { - return getModelData(world, new ChunkPos(pos)).get(pos); - } - - public static Map getModelData(World world, ChunkPos pos) - { - Preconditions.checkArgument(world.isRemote, "Cannot request model data for server world"); -// refreshModelData(world, pos); - return modelDataCache.getOrDefault(pos, Collections.emptyMap()); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java index 1f693654e..39e89d25b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java @@ -18,7 +18,7 @@ public abstract class MixinGameSettings { private static String[] GUISCALES = new String[] { "options.guiScale.auto", "options.guiScale.small", - "options.guiScale.getNormal", + "options.guiScale.normal", "options.guiScale.large", "options.guiScale.massive" }; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java index 0b9587c02..3bb04399f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java @@ -20,7 +20,7 @@ public class MixinLayeredTexture { /** * @author glowredman - * @reason must take getNormal and specular maps into account + * @reason must take normal and specular maps into account */ @Overwrite public void loadTexture(IResourceManager p_110551_1_) throws IOException { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java index aa4751001..8fc8af0ac 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java @@ -34,8 +34,10 @@ public void pushCommandBuffer(ChunkDrawCallBatcher batcher) { } protected void growBuffer(int n) { - ByteBuffer oldBuffer = this.buffer; - this.buffer = BufferUtils.createByteBuffer(Math.max(oldBuffer.capacity() * 2, oldBuffer.capacity() + n)); - buffer.put((ByteBuffer) oldBuffer.rewind()); + ByteBuffer buffer = BufferUtils.createByteBuffer(Math.max(this.buffer.capacity() * 2, this.buffer.capacity() + n)); + buffer.put(this.buffer); + buffer.position(0); + + this.buffer = buffer; } } From 7d501d2f3a830146a812edac690e1fa87460c1e7 Mon Sep 17 00:00:00 2001 From: rjnasers Date: Mon, 20 Nov 2023 23:14:22 -0600 Subject: [PATCH 069/301] Fixing splash screen and GUI issues by excluding SplashProgress from GLStateManager transformer --- .../angelica/transform/GLStateManagerTransformer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index 90537fb09..c03ddd778 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -42,7 +42,7 @@ public class GLStateManagerTransformer implements IClassTransformer { private static final List TransformerExclusions = new ArrayList<>(Arrays.asList( - "org.lwjgl", "com.gtnewhorizons.angelica.glsm.", "com.gtnewhorizons.angelica.transform", "me.eigenraven.lwjgl3ify") + "org.lwjgl", "com.gtnewhorizons.angelica.glsm.", "com.gtnewhorizons.angelica.transform", "me.eigenraven.lwjgl3ify", "cpw.mods.fml.client.SplashProgress") ); public static int remaps = 0, calls = 0; From 988135712a633474ead66b4c461bc3b022188182 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 21 Nov 2023 08:30:19 -0800 Subject: [PATCH 070/301] Update docs --- .../angelica/transform/GLStateManagerTransformer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index c03ddd778..6c24c4a02 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -51,7 +51,8 @@ public byte[] transform(final String className, String transformedName, byte[] b if (basicClass == null) return null; - // Ignore classes that are excluded from transformation - Doesn't seem to fully work without the TransformerExclusions + // Ignore classes that are excluded from transformation - Doesn't fully work without the + // TransformerExclusions due to some nested classes for (String exclusion : TransformerExclusions) { if (className.startsWith(exclusion)) { return basicClass; @@ -84,6 +85,7 @@ public void visitMethodInsn(int opcode, String owner, String name, String desc, owner = GLStateTracker; remaps++; } + // TODO: Add an optional (if DEBUG) inject to assert we're on the main thread. super.visitMethodInsn(opcode, owner, name, desc, itf); } }; From 55e0ffb1d29f7bef3f2d9d5a0b672cb54ceb85bd Mon Sep 17 00:00:00 2001 From: rjnasers Date: Wed, 22 Nov 2023 00:30:34 -0600 Subject: [PATCH 071/301] Fixing a one line in SodiumWorldRenderer that allows the game setting for the distance at which entities will render. Hope it's not too bad mitch :) --- .../AngelicaEntityRenderDistanceSetting.java | 31 +++++++++++++++++++ .../gui/GuiEntityRenderDistanceSlider.java | 11 +++++++ .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../mixins/early/sodium/MixinEntity.java | 24 ++++++++++++++ .../angelica/proxy/ClientProxy.java | 8 +++++ src/main/java/jss/notfine/core/Settings.java | 7 ++++- .../jss/notfine/core/SettingsManager.java | 5 +++ .../sodium/client/gui/SodiumGameOptions.java | 10 ++++++ .../client/render/SodiumWorldRenderer.java | 6 ++-- .../mods/sodium/client/util/MathUtil.java | 16 ++++++++++ .../resources/assets/notfine/lang/en_US.lang | 1 + 11 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaEntityRenderDistanceSetting.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/client/gui/GuiEntityRenderDistanceSlider.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntity.java diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaEntityRenderDistanceSetting.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaEntityRenderDistanceSetting.java new file mode 100644 index 000000000..52307d84d --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaEntityRenderDistanceSetting.java @@ -0,0 +1,31 @@ +package com.gtnewhorizons.angelica.client.gui; + +import cpw.mods.fml.client.config.GuiSlider; +import jss.notfine.gui.ISettingsEnum; +import net.minecraft.client.resources.I18n; + +import static jss.notfine.core.Settings.RENDER_DISTANCE_ENTITIES; + +public enum AngelicaEntityRenderDistanceSetting implements ISettingsEnum { + + ENTITY_RENDER_DISTANCE("options.button.entityRenderDistance"); + private final String unlocalizedButton; + + AngelicaEntityRenderDistanceSetting(String unlocalizedButton) { + this.unlocalizedButton = unlocalizedButton; + } + + @Override + public java.lang.String getButtonLabel() { + return I18n.format(unlocalizedButton); + } + + @Override + public String getTitleLabel() { + return null; + } + + public GuiEntityRenderDistanceSlider createButton(int xPosition, int yPosition, Object setting) { + return new GuiEntityRenderDistanceSlider(xPosition, yPosition, RENDER_DISTANCE_ENTITIES); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiEntityRenderDistanceSlider.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiEntityRenderDistanceSlider.java new file mode 100644 index 000000000..abb058202 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiEntityRenderDistanceSlider.java @@ -0,0 +1,11 @@ +package com.gtnewhorizons.angelica.client.gui; + +import jss.notfine.core.Settings; +import jss.notfine.gui.GuiCustomSettingSlider; + +public class GuiEntityRenderDistanceSlider extends GuiCustomSettingSlider { + + public GuiEntityRenderDistanceSlider(int xPosition, int yPosition, Settings setting) { + super(xPosition, yPosition, setting); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index d139ff753..da74ace68 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -41,6 +41,7 @@ public enum Mixins { ,"sodium.MixinTessellator" ,"sodium.MixinWorldClient" ,"sodium.MixinWorldRenderer" + ,"sodium.MixinEntity" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntity.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntity.java new file mode 100644 index 000000000..4cbc969a9 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntity.java @@ -0,0 +1,24 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.llamalad7.mixinextras.sugar.Local; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Entity.class) +public abstract class MixinEntity { + + @Shadow + public abstract boolean isInRangeToRenderDist(double dist); + + @Inject(method ="isInRangeToRender3d", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;isInRangeToRenderDist(D)Z"), cancellable = true) + private void sodium$afterDistCalc(CallbackInfoReturnable ci, @Local(ordinal = 6) double d6) { + ci.setReturnValue(this.isInRangeToRenderDist(d6/(SodiumGameOptions.EntityRenderDistance.entityRenderDistanceMultiplier * SodiumGameOptions.EntityRenderDistance.entityRenderDistanceMultiplier))); + } + + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index fe041809e..ca4623608 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.proxy; +import com.gtnewhorizons.angelica.client.gui.AngelicaEntityRenderDistanceSetting; import com.gtnewhorizons.angelica.client.gui.AngelicaVideoSettings; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; @@ -9,6 +10,8 @@ import me.jellysquid.mods.sodium.client.SodiumDebugScreenHandler; import net.minecraftforge.common.MinecraftForge; +import java.awt.*; + public class ClientProxy extends CommonProxy { @Override @@ -18,6 +21,11 @@ public void preInit(FMLPreInitializationEvent event) { ISettingsEnum settingsEnum = (ISettingsEnum) setting; return settingsEnum.createButton(xPosition, yPosition, setting); }); + MenuButtonLists.addAdditionalEntry(MenuButtonLists.VIDEO, AngelicaEntityRenderDistanceSetting.ENTITY_RENDER_DISTANCE); + GuiCustomMenu.addButtonHandler(AngelicaEntityRenderDistanceSetting.class, (xPosition, yPosition, setting) ->{ + ISettingsEnum settingsEnum = (ISettingsEnum) setting; + return settingsEnum.createButton(xPosition, yPosition, setting); + }); } @Override diff --git a/src/main/java/jss/notfine/core/Settings.java b/src/main/java/jss/notfine/core/Settings.java index d937d8181..e425c1f13 100644 --- a/src/main/java/jss/notfine/core/Settings.java +++ b/src/main/java/jss/notfine/core/Settings.java @@ -79,8 +79,13 @@ public void updateSetting() { public void updateSetting() { RenderStars.reloadStarRenderList(Minecraft.getMinecraft().renderGlobal); } + }, + RENDER_DISTANCE_ENTITIES(true, 100f, 50f, 500f, 25f) { + @Override + public void updateSetting() { + SettingsManager.entityRenderDistanceUpdated(); + } }; - public final boolean slider; public final float base; public final float minimum; diff --git a/src/main/java/jss/notfine/core/SettingsManager.java b/src/main/java/jss/notfine/core/SettingsManager.java index a2369ef22..1ab0afc67 100644 --- a/src/main/java/jss/notfine/core/SettingsManager.java +++ b/src/main/java/jss/notfine/core/SettingsManager.java @@ -24,6 +24,7 @@ public class SettingsManager { public static boolean leavesOpaque; public static boolean waterDetail; public static boolean vignette; + public static double entityRenderScaleFactor = 1.0; public static ResourceLocation defaultBackground = Gui.optionsBackground; public static ResourceLocation[] extraBackgrounds = new ResourceLocation[] { @@ -129,6 +130,10 @@ public static void vignetteUpdated() { } } + public static void entityRenderDistanceUpdated() { + entityRenderScaleFactor = Settings.RENDER_DISTANCE_ENTITIES.getValue(); + } + public static void graphicsUpdated() { leavesUpdated(); shadowsUpdated(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index de1b49cea..0989e8707 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -42,6 +42,16 @@ public static class PerformanceSettings { public boolean alwaysDeferChunkUpdates = false; } + public static class EntityRenderDistance { + public static double entityRenderDistanceMultiplier = 1.0; + + public static double getRenderDistanceMult() { + return entityRenderDistanceMultiplier; + } + public static void setRenderDistanceMult(double value) { + entityRenderDistanceMultiplier = value; + } + } public static class QualitySettings { public GraphicsQuality cloudQuality = GraphicsQuality.DEFAULT; public GraphicsQuality weatherQuality = GraphicsQuality.DEFAULT; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index f0eee352b..6f12e92a2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -14,10 +14,12 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexConsumerProvider; import com.gtnewhorizons.angelica.compat.mojang.VertexConsumers; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.mixins.early.sodium.MixinEntity; import com.gtnewhorizons.angelica.mixins.interfaces.IHasClientChunkProvider; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import jss.notfine.core.SettingsManager; import lombok.Getter; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; @@ -32,6 +34,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPassManager; import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheShared; +import me.jellysquid.mods.sodium.client.util.MathUtil; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; import me.jellysquid.mods.sodium.client.world.IChunkProviderClientExt; @@ -239,8 +242,7 @@ public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrust profiler.endSection(); - // TODO: Sodium RenderDistance -// Entity.setRenderDistanceMultiplier(MathHelper.clamp((double) this.client.options.viewDistance / 8.0D, 1.0D, 2.5D) * (double) 1.0F/*this.client.options.entityDistanceScaling*/); + SodiumGameOptions.EntityRenderDistance.setRenderDistanceMult(MathUtil.clamp((double) this.client.gameSettings.renderDistanceChunks / 8.0D, 1.0D, 2.5D) * (double) 1.0F * (SettingsManager.entityRenderScaleFactor/100)); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java index 49056712e..71a4273e1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java @@ -7,4 +7,20 @@ public class MathUtil { public static boolean isPowerOfTwo(int n) { return ((n & (n - 1)) == 0); } + + /** + * @param value The value to be clamped + * @param min minimum that the value will be clamped to + * @param max maximum that the value will be clamped to + * @return If the value is within the rand (min -> max) then it returns value, otherwise returns + * minimum if value is smaller than minimum and maximum if value is larger than maximum. + */ + public static double clamp(double value, double min, double max) { + if (value < min) { + return min; + } else { + return value > max ? max : value; + } + } + } diff --git a/src/main/resources/assets/notfine/lang/en_US.lang b/src/main/resources/assets/notfine/lang/en_US.lang index 205d02009..b394bde54 100644 --- a/src/main/resources/assets/notfine/lang/en_US.lang +++ b/src/main/resources/assets/notfine/lang/en_US.lang @@ -60,3 +60,4 @@ options.title.particle=Particle Settings | NotFine alpha options.title.sky=Atmosphere Settings | NotFine alpha options.title.video=Video Settings | NotFine alpha options.total_stars=Star Density +options.render_distance_entities=Entity Render Mult From c87640477fe76aa7bea771f1c4cc95c53ba36b44 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 21 Nov 2023 20:05:46 -0800 Subject: [PATCH 072/301] TileEntites now render --- .../early/sodium/MixinRenderGlobal.java | 6 ++ .../client/render/SodiumWorldRenderer.java | 68 ++++++++++--------- .../render/chunk/ChunkRenderManager.java | 6 +- .../render/chunk/data/ChunkRenderData.java | 14 ++-- .../chunk/tasks/ChunkRenderRebuildTask.java | 2 +- .../world/cloned/ClonedChunkSection.java | 5 +- 6 files changed, 56 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 759add6ce..7f8f6b3a1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -241,4 +241,10 @@ public void loadRenderers() { this.renderChunksDeep = 0; } + @Inject(method="renderEntities", at=@At(value="INVOKE", target="Lnet/minecraft/client/renderer/RenderHelper;enableStandardItemLighting()V", shift = At.Shift.AFTER)) + public void sodium$renderTileEntities(EntityLivingBase entity, ICamera camera, float partialTicks, CallbackInfo ci) { + this.renderer.renderTileEntities(entity, camera, partialTicks); + } + + } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 6f12e92a2..54aab46d6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -43,8 +43,11 @@ import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.culling.Frustrum; +import net.minecraft.client.renderer.culling.ICamera; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.profiler.Profiler; import net.minecraft.tileentity.TileEntity; @@ -314,53 +317,54 @@ private boolean checkBEVisibility(TileEntity entity) { return frustum.isBoundingBoxInFrustum(entity.getRenderBoundingBox()); } - public void renderTileEntities(MatrixStack matrices, BufferBuilderStorage bufferBuilders, Long2ObjectMap> blockBreakingProgressions, - Camera camera, float tickDelta) { - VertexConsumerProvider.Immediate immediate = bufferBuilders.getEntityVertexConsumers(); - - Vector3d cameraPos = camera.getPos(); - double x = cameraPos.x; - double y = cameraPos.y; - double z = cameraPos.z; - + public void renderTileEntities(EntityLivingBase entity, ICamera camera, float partialTicks) { +// VertexConsumerProvider.Immediate immediate = bufferBuilders.getEntityVertexConsumers(); +// +// Vector3d cameraPos = camera.getPos(); +// double x = cameraPos.x; +// double y = cameraPos.y; +// double z = cameraPos.z; +// for (TileEntity tileEntity : this.chunkRenderManager.getVisibleBlockEntities()) { if(tileEntity.isInvalid() || !checkBEVisibility(tileEntity)) continue; - BlockPos pos = new BlockPos(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); - - matrices.push(); - matrices.translate((double) pos.x - x, (double) pos.y - y, (double) pos.z - z); - - VertexConsumerProvider consumer = immediate; - SortedSet breakingInfos = blockBreakingProgressions.get(pos.asLong()); - - if (breakingInfos != null && !breakingInfos.isEmpty()) { - int stage = breakingInfos.last().getStage(); - - if (stage >= 0) { - MatrixStack.Entry entry = matrices.peek(); - VertexConsumer transformer = new OverlayVertexConsumer(bufferBuilders.getEffectVertexConsumers().getBuffer(ModelLoader.BLOCK_DESTRUCTION_RENDER_LAYERS.get(stage)), entry.getModel(), entry.getNormal()); - consumer = (layer) -> layer.hasCrumbling() ? VertexConsumers.union(transformer, immediate.getBuffer(layer)) : immediate.getBuffer(layer); - } - } +// BlockPos pos = new BlockPos(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); +// +// matrices.push(); +// matrices.translate((double) pos.x - x, (double) pos.y - y, (double) pos.z - z); +// +// VertexConsumerProvider consumer = immediate; +// SortedSet breakingInfos = blockBreakingProgressions.get(pos.asLong()); +// +// if (breakingInfos != null && !breakingInfos.isEmpty()) { +// int stage = breakingInfos.last().getStage(); +// +// if (stage >= 0) { +// MatrixStack.Entry entry = matrices.peek(); +// VertexConsumer transformer = new OverlayVertexConsumer(bufferBuilders.getEffectVertexConsumers().getBuffer(ModelLoader.BLOCK_DESTRUCTION_RENDER_LAYERS.get(stage)), entry.getModel(), entry.getNormal()); +// consumer = (layer) -> layer.hasCrumbling() ? VertexConsumers.union(transformer, immediate.getBuffer(layer)) : immediate.getBuffer(layer); +// } +// } // TODO: Sodium TileEntity Rendering Dispatcher + TileEntityRendererDispatcher.instance.renderTileEntity(tileEntity, partialTicks); // BlockEntityRenderDispatcher.INSTANCE.render(tileEntity, tickDelta, matrices, consumer); - matrices.pop(); +// matrices.pop(); } for (TileEntity tileEntity : this.globalTileEntities) { if(!checkBEVisibility(tileEntity)) continue; - BlockPos pos = new BlockPos(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); - - matrices.push(); - matrices.translate((double) pos.x - x, (double) pos.y - y, (double) pos.z - z); +// BlockPos pos = new BlockPos(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); +// +// matrices.push(); +// matrices.translate((double) pos.x - x, (double) pos.y - y, (double) pos.z - z); // TODO: Sodium TileEntity Rendering Dispatcher + TileEntityRendererDispatcher.instance.renderTileEntity(tileEntity, partialTicks); // BlockEntityRenderDispatcher.INSTANCE.render(tileEntity, tickDelta, matrices, immediate); - matrices.pop(); +// matrices.pop(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 6a0a74e27..76bc85dab 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -305,10 +305,10 @@ private int computeVisibleFaces(ChunkRenderContainer render) { } private void addEntitiesToRenderLists(ChunkRenderContainer render) { - Collection blockEntities = render.getData().getTileEntities(); + Collection tileEntities = render.getData().getTileEntities(); - if (!blockEntities.isEmpty()) { - this.visibleBlockEntities.addAll(blockEntities); + if (!tileEntities.isEmpty()) { + this.visibleBlockEntities.addAll(tileEntities); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java index 1f9840786..f53d9b125 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java @@ -114,8 +114,8 @@ public ChunkRenderData copyAndReplaceMesh(Map re } public static class Builder { - private final List globalBlockEntities = new ArrayList<>(); - private final List blockEntities = new ArrayList<>(); + private final List globalTileEntities = new ArrayList<>(); + private final List tileEntities = new ArrayList<>(); private final Set animatedSprites = new ObjectOpenHashSet<>(); private final EnumMap meshes = new EnumMap<>(BlockRenderPass.class); @@ -157,14 +157,14 @@ public void setMesh(BlockRenderPass pass, ChunkMeshData data) { * @param entity The block entity itself * @param cull True if the block entity can be culled to this chunk render's volume, otherwise false */ - public void addBlockEntity(TileEntity entity, boolean cull) { - (cull ? this.blockEntities : this.globalBlockEntities).add(entity); + public void addTileEntity(TileEntity entity, boolean cull) { + (cull ? this.tileEntities : this.globalTileEntities).add(entity); } public ChunkRenderData build() { ChunkRenderData data = new ChunkRenderData(); - data.globalTileEntities = this.globalBlockEntities; - data.tileEntities = this.blockEntities; + data.globalTileEntities = this.globalTileEntities; + data.tileEntities = this.tileEntities; data.occlusionData = this.occlusionData; data.meshes = this.meshes; data.bounds = this.bounds; @@ -181,7 +181,7 @@ public ChunkRenderData build() { } } - data.isEmpty = this.globalBlockEntities.isEmpty() && this.blockEntities.isEmpty() && facesWithData == 0; + data.isEmpty = this.globalTileEntities.isEmpty() && this.tileEntities.isEmpty() && facesWithData == 0; data.meshByteSize = size; data.facesWithData = facesWithData; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index f25143e0e..ec4595a57 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -153,7 +153,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB // TODO: Sodium - Per-chunk tile entities // !rendersOutsideBoundingBox(entity) in sodium // entity.getRenderBoundingBox() != TileEntity.INFINITE_EXTENT_AABB rough equivalent in 1.7.10 - renderData.addBlockEntity(entity, false); + renderData.addTileEntity(entity, false); bounds.addBlock(relX, relY, relZ); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 799f11040..e5e29ad11 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -71,9 +71,10 @@ public void init(ChunkSectionPos pos) { this.tileEntities.clear(); for (Map.Entry entry : chunk.chunkTileEntityMap.entrySet()) { - BlockPos entityPos = new BlockPos(entry.getKey()); + final TileEntity tile = entry.getValue(); + final BlockPos entityPos = new BlockPos(tile.xCoord, tile.yCoord, tile.zCoord); - if(box.isVecInside(entityPos.getX(), entityPos.getY(), entityPos.getZ())) { + if(box.isVecInside(tile.xCoord, tile.yCoord, tile.zCoord)) { //this.blockEntities.put(BlockPos.asLong(entityPos.getX() & 15, entityPos.getY() & 15, entityPos.getZ() & 15), entry.getValue()); this.tileEntities.put(ChunkSectionPos.packLocal(entityPos), entry.getValue()); } From d22522787a5362ea9be2360645d7e164900ae342 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Tue, 21 Nov 2023 20:53:10 -0500 Subject: [PATCH 073/301] Update deps --- build.gradle | 5 ++--- dependencies.gradle | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 5c5ffe63e..85a8520ee 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -//version: 1698936026 +//version: 1699290261 /* DO NOT CHANGE THIS FILE! Also, you may replace this file at any time if there is an update available. @@ -1187,9 +1187,8 @@ publishing { version = System.getenv("RELEASE_VERSION") ?: identifiedVersion } } - repositories { - if (usesMavenPublishing.toBoolean()) { + if (usesMavenPublishing.toBoolean() && System.getenv("MAVEN_USER") != null) { maven { url = mavenPublishUrl allowInsecureProtocol = mavenPublishUrl.startsWith("http://") // Mostly for the GTNH maven diff --git a/dependencies.gradle b/dependencies.gradle index e7a47bc18..f37662745 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -38,6 +38,8 @@ dependencies { compileOnly(sourceSets.compileStubs.output) compileStubs(sourceSets.compileStubsStubs.output) + api("com.github.GTNewHorizons:Hodgepodge:2.3.32") + // Iris Shaders implementation('org.jetbrains:annotations:24.0.1') implementation("it.unimi.dsi:fastutil:8.2.1") From d3a8e2ab6205ab00640a953feec28e2b25ba908e Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 21 Nov 2023 21:19:50 -0800 Subject: [PATCH 074/301] Less silly transparency --- .../angelica/compat/mojang/RenderPhase.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index b2ff9dbfc..d6a81ca68 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -26,31 +26,30 @@ public abstract class RenderPhase { }, () -> { GLStateManager.disableBlend(); GLStateManager.defaultBlendFunc(); - GLStateManager.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); }); protected static final Transparency LIGHTNING_TRANSPARENCY = new Transparency("lightning_transparency", () -> { - GLStateManager.disableBlend(); + GLStateManager.enableBlend(); GLStateManager.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); }, () -> { GLStateManager.disableBlend(); GLStateManager.defaultBlendFunc(); }); protected static final Transparency GLINT_TRANSPARENCY = new Transparency("glint_transparency", () -> { - GLStateManager.disableBlend(); + GLStateManager.enableBlend(); GLStateManager.glBlendFuncSeparate(GL11.GL_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE); }, () -> { GLStateManager.disableBlend(); GLStateManager.defaultBlendFunc(); }); protected static final Transparency CRUMBLING_TRANSPARENCY = new Transparency("crumbling_transparency", () -> { - GLStateManager.disableBlend(); + GLStateManager.enableBlend(); GLStateManager.glBlendFuncSeparate(GL11.GL_DST_COLOR, GL11.GL_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO); }, () -> { GLStateManager.disableBlend(); GLStateManager.defaultBlendFunc(); }); protected static final Transparency TRANSLUCENT_TRANSPARENCY = new Transparency("translucent_transparency", () -> { - GLStateManager.disableBlend(); + GLStateManager.enableBlend(); GLStateManager.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); }, () -> { GLStateManager.disableBlend(); From 05530f317be79d943e16c1e057149e7fa10d9727 Mon Sep 17 00:00:00 2001 From: rjnasers Date: Wed, 22 Nov 2023 00:39:33 -0600 Subject: [PATCH 075/301] Removing clamp implementation because I missed the one in mathhelper --- .../client/render/SodiumWorldRenderer.java | 3 +-- .../mods/sodium/client/util/MathUtil.java | 16 ---------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 54aab46d6..0f929a281 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -34,7 +34,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPassManager; import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheShared; -import me.jellysquid.mods.sodium.client.util.MathUtil; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; import me.jellysquid.mods.sodium.client.world.IChunkProviderClientExt; @@ -245,7 +244,7 @@ public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrust profiler.endSection(); - SodiumGameOptions.EntityRenderDistance.setRenderDistanceMult(MathUtil.clamp((double) this.client.gameSettings.renderDistanceChunks / 8.0D, 1.0D, 2.5D) * (double) 1.0F * (SettingsManager.entityRenderScaleFactor/100)); + SodiumGameOptions.EntityRenderDistance.setRenderDistanceMult(MathHelper.clamp_double((double) this.client.gameSettings.renderDistanceChunks / 8.0D, 1.0D, 2.5D) * (double) 1.0F * (SettingsManager.entityRenderScaleFactor/100)); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java index 71a4273e1..49056712e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java @@ -7,20 +7,4 @@ public class MathUtil { public static boolean isPowerOfTwo(int n) { return ((n & (n - 1)) == 0); } - - /** - * @param value The value to be clamped - * @param min minimum that the value will be clamped to - * @param max maximum that the value will be clamped to - * @return If the value is within the rand (min -> max) then it returns value, otherwise returns - * minimum if value is smaller than minimum and maximum if value is larger than maximum. - */ - public static double clamp(double value, double min, double max) { - if (value < min) { - return min; - } else { - return value > max ? max : value; - } - } - } From 9c7fded20188493929ccfb64c1293a7fba71f042 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 22 Nov 2023 14:30:27 -0800 Subject: [PATCH 076/301] misc cleanup --- .../angelica/compat/mojang/RenderPhase.java | 37 ++++++++++++++++--- .../early/sodium/MixinRenderGlobal.java | 12 +++--- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index d6a81ca68..397328803 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -146,8 +146,8 @@ private static void setupGlintTexturing(float scale) { private static ResourceLocation ATLAS = TextureMap.locationBlocksTexture; static { // TODO: Sodium - SpriteAtlasTexture - MIPMAP_BLOCK_ATLAS_TEXTURE = new Texture(ATLAS/*SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE*/, false, true); - BLOCK_ATLAS_TEXTURE = new Texture(ATLAS /*SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE*/, false, false); + MIPMAP_BLOCK_ATLAS_TEXTURE = new Texture(ATLAS, false, true); + BLOCK_ATLAS_TEXTURE = new Texture(ATLAS, false, false); NO_TEXTURE = new Texture(); DEFAULT_TEXTURING = new Texturing("default_texturing", () -> { }, () -> { @@ -327,6 +327,7 @@ public LineWidth(OptionalDouble optionalDouble) { this.width = optionalDouble; } + @Override public boolean equals(@Nullable Object object) { if (this == object) { return true; @@ -337,10 +338,12 @@ public boolean equals(@Nullable Object object) { } } + @Override public int hashCode() { - return Objects.hash(new Object[]{super.hashCode(), this.width}); + return Objects.hash(super.hashCode(), this.width); } + @Override public String toString() { return this.name + '[' + (this.width.isPresent() ? this.width.getAsDouble() : "window_scale") + ']'; } @@ -396,6 +399,7 @@ public WriteMaskState(boolean color, boolean depth) { this.depth = depth; } + @Override public boolean equals(Object object) { if (this == object) { return true; @@ -407,10 +411,12 @@ public boolean equals(Object object) { } } + @Override public int hashCode() { - return Objects.hash(new Object[]{this.color, this.depth}); + return Objects.hash(this.color, this.depth); } + @Override public String toString() { return this.name + "[writeColor=" + this.color + ", writeDepth=" + this.depth + ']'; } @@ -439,6 +445,7 @@ public DepthTest(String string, int i) { this.func = i; } + @Override public boolean equals(Object object) { if (this == object) { return true; @@ -450,10 +457,12 @@ public boolean equals(Object object) { } } + @Override public int hashCode() { return Integer.hashCode(this.func); } + @Override public String toString() { return this.name + '[' + this.depthFunction + ']'; } @@ -547,6 +556,7 @@ public Toggleable(String string, Runnable runnable, Runnable runnable2, boolean this.enabled = bl; } + @Override public boolean equals(Object object) { if (this == object) { return true; @@ -558,10 +568,12 @@ public boolean equals(Object object) { } } + @Override public int hashCode() { return Boolean.hashCode(this.enabled); } + @Override public String toString() { return this.name + '[' + this.enabled + ']'; } @@ -595,6 +607,7 @@ public PortalTexturing(int layer) { this.layer = layer; } + @Override public boolean equals(Object object) { if (this == object) { return true; @@ -606,6 +619,7 @@ public boolean equals(Object object) { } } + @Override public int hashCode() { return Integer.hashCode(this.layer); } @@ -634,6 +648,7 @@ public OffsetTexturing(float x, float y) { this.y = y; } + @Override public boolean equals(Object object) { if (this == object) { return true; @@ -645,8 +660,9 @@ public boolean equals(Object object) { } } + @Override public int hashCode() { - return Objects.hash(new Object[]{this.x, this.y}); + return Objects.hash(this.x, this.y); } } @@ -683,6 +699,7 @@ public Texture() { this.mipmap = false; } + @Override public boolean equals(Object object) { if (this == object) { return true; @@ -694,10 +711,12 @@ public boolean equals(Object object) { } } + @Override public int hashCode() { return this.id.hashCode(); } + @Override public String toString() { return this.name + '[' + this.id + "(blur=" + this.bilinear + ", mipmap=" + this.mipmap + ")]"; } @@ -718,6 +737,7 @@ public ShadeModel(boolean smooth) { this.smooth = smooth; } + @Override public boolean equals(Object object) { if (this == object) { return true; @@ -729,10 +749,12 @@ public boolean equals(Object object) { } } + @Override public int hashCode() { return Boolean.hashCode(this.smooth); } + @Override public String toString() { return this.name + '[' + (this.smooth ? "smooth" : "flat") + ']'; } @@ -759,6 +781,7 @@ public Alpha(float alpha) { this.alpha = alpha; } + @Override public boolean equals(@Nullable Object object) { if (this == object) { return true; @@ -773,10 +796,12 @@ public boolean equals(@Nullable Object object) { } } + @Override public int hashCode() { - return Objects.hash(new Object[]{super.hashCode(), this.alpha}); + return Objects.hash(super.hashCode(), this.alpha); } + @Override public String toString() { return this.name + '[' + this.alpha + ']'; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 7f8f6b3a1..66c00aa89 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -75,16 +75,16 @@ public String getDebugInfoRenders() { return this.renderer.getChunksDebugString(); } - /** + /** * @author Sodium * @reason Redirect to our renderer - */ + */ @Overwrite public int renderSortedRenderers(int x, int z, int pass, double partialTicks) { // Do nothing return 0; } - /** + /** * @author Sodium * @reason Redirect to our renderer */ @@ -93,7 +93,7 @@ public void renderAllRenderLists(int pass, double partialTicks) { // Do nothing } - /** + /** * @author Sodium * @reason Redirect to our renderer */ @@ -102,7 +102,7 @@ private void checkOcclusionQueryResult(int x, int z) { // Do nothing } - /** + /** * @author Sodium * @reason Redirect to our renderer */ @@ -111,7 +111,7 @@ public void markRenderersForNewPosition(int p_72722_1_, int p_72722_2_, int p_72 // Do nothing } - /** + /** * @author Sodium * @reason Redirect to our renderer */ From 3ef5934c98894727de0e5eb01d38e15b1a5ccb06 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Wed, 22 Nov 2023 15:43:20 -0500 Subject: [PATCH 077/301] Initial sodium entity smooth lighting --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../early/sodium/MixinRenderManager.java | 28 +++++++++++++++++++ .../client/model/light/EntityLighter.java | 24 ++++++++++------ 3 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index da74ace68..76fa3a394 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -42,6 +42,7 @@ public enum Mixins { ,"sodium.MixinWorldClient" ,"sodium.MixinWorldRenderer" ,"sodium.MixinEntity" + ,"sodium.MixinRenderManager" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java new file mode 100644 index 000000000..4268b7cf7 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java @@ -0,0 +1,28 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import me.jellysquid.mods.sodium.client.model.light.EntityLighter; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(RenderManager.class) +public class MixinRenderManager { + + /** + * Sodium: Use Sodium smooth entity light if enabled. + */ + @Redirect(method = "renderEntityStatic", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getBrightnessForRender(F)I")) + private int sodium$getBrightnessForRender(Entity self, float partialTicks) { + + if (SodiumClientMod.options().quality.smoothLighting == SodiumGameOptions.LightingQuality.HIGH) { + + return EntityLighter.getBlendedLight(self, partialTicks); + } + + return self.getBrightnessForRender(partialTicks); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java index 93c0f64d1..0e8150a69 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; import me.jellysquid.mods.sodium.client.render.entity.EntityLightSampler; +import net.minecraft.block.Block; import net.minecraft.util.MathHelper; import net.minecraft.entity.Entity; @@ -15,13 +16,13 @@ public class EntityLighter { private static final double MAX_LIGHT_VAL = 15.0; private static final double MAX_LIGHTMAP_COORD = 240.0D; - public static int getBlendedLight(EntityLightSampler lighter, T entity, float tickDelta) { + public static int getBlendedLight(Entity entity, float tickDelta) { boolean calcBlockLight = !entity.isBurning(); // Find the interpolated position of the entity - double x1 = lerp(tickDelta, entity.prevPosX, entity.posX); - double y1 = lerp(tickDelta, entity.prevPosY, entity.posY); - double z1 = lerp(tickDelta, entity.prevPosZ, entity.posZ); + double x1 = lerp(entity.prevPosX, entity.posX, tickDelta); + double y1 = lerp(entity.prevPosY, entity.posY, tickDelta); + double z1 = lerp(entity.prevPosZ, entity.posZ, tickDelta); // Bounding boxes with no volume cause issues, ensure they're non-zero // Notably, armor stands in "Marker" mode decide this is a cute thing to do @@ -63,10 +64,10 @@ public static int getBlendedLight(EntityLightSampler light pos.set(bX, bY, bZ); // TODO - Sodium - Blocks - BlockState blockState = null; /*entity.worldObj.getBlockState(pos);*/ + Block block = entity.worldObj.getBlock(pos.x, pos.y, pos.z); // Do not consider light-blocking volumes - if (blockState.isOpaqueFullCube((BlockRenderView)entity.worldObj, pos) && blockState.getLightValue((BlockRenderView)entity.worldObj, pos) <= 0) { + if (block.isOpaqueCube() && entity.worldObj.getBlockLightValue(pos.x, pos.y, pos.z) <= 0) { continue; } @@ -80,11 +81,18 @@ public static int getBlendedLight(EntityLightSampler light // Keep count of how much light could've been contributed max += weight; + // lighter.bridge$getSkyLight(entity, pos) and lighter.bridge$getBlockLight(entity, pos) replaced + // get the sky light at that block pos + // x, y, z, block light to add + double skylight = entity.worldObj.getLightBrightnessForSkyBlocks(pos.x, pos.y, pos.z, 0); + // Ditto for block light, BUT it's always 15 if the entity is on fire + double blklight = (entity.isBurning()) ? 15 : entity.worldObj.getBlockLightValue(pos.x, pos.y, pos.z); + // Sum the light actually contributed by this volume - sl += weight * (lighter.bridge$getSkyLight(entity, pos) / MAX_LIGHT_VAL); + sl += weight * (skylight / MAX_LIGHT_VAL); if (calcBlockLight) { - bl += weight * (lighter.bridge$getBlockLight(entity, pos) / MAX_LIGHT_VAL); + bl += weight * (blklight / MAX_LIGHT_VAL); } else { bl += weight; } From 6ed1ed91d3bcd92e82887e781831b8f59c8b0280 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Wed, 22 Nov 2023 18:36:42 -0500 Subject: [PATCH 078/301] Fix entity smooth lighting --- .../client/model/light/EntityLighter.java | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java index 0e8150a69..0832ecec9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java @@ -1,12 +1,9 @@ package me.jellysquid.mods.sodium.client.model.light; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import me.jellysquid.mods.sodium.client.render.entity.EntityLightSampler; -import net.minecraft.block.Block; import net.minecraft.util.MathHelper; import net.minecraft.entity.Entity; +import net.minecraft.world.EnumSkyBlock; import static org.joml.Math.lerp; @@ -63,11 +60,9 @@ public static int getBlendedLight(Entity entity, float tickDelta) { for (int bZ = bMinZ; bZ < bMaxZ; bZ++) { pos.set(bX, bY, bZ); - // TODO - Sodium - Blocks - Block block = entity.worldObj.getBlock(pos.x, pos.y, pos.z); - // Do not consider light-blocking volumes - if (block.isOpaqueCube() && entity.worldObj.getBlockLightValue(pos.x, pos.y, pos.z) <= 0) { + if (entity.worldObj.getBlock(pos.x, pos.y, pos.z).isOpaqueCube() + && entity.worldObj.getBlockLightValue(pos.x, pos.y, pos.z) <= 0) { continue; } @@ -81,18 +76,15 @@ public static int getBlendedLight(Entity entity, float tickDelta) { // Keep count of how much light could've been contributed max += weight; - // lighter.bridge$getSkyLight(entity, pos) and lighter.bridge$getBlockLight(entity, pos) replaced - // get the sky light at that block pos - // x, y, z, block light to add - double skylight = entity.worldObj.getLightBrightnessForSkyBlocks(pos.x, pos.y, pos.z, 0); - // Ditto for block light, BUT it's always 15 if the entity is on fire - double blklight = (entity.isBurning()) ? 15 : entity.worldObj.getBlockLightValue(pos.x, pos.y, pos.z); + // note: lighter.bridge$getSkyLight(entity, pos) and lighter.bridge$getBlockLight(entity, pos) + // were replaced, mixin+this method de-generified. as far as I can tell they only existed because + // Sodium had a weird setup just for paintings, don't think we need it. // Sum the light actually contributed by this volume - sl += weight * (skylight / MAX_LIGHT_VAL); + sl += weight * (entity.worldObj.getSkyBlockTypeBrightness(EnumSkyBlock.Sky, pos.x, pos.y, pos.z) / MAX_LIGHT_VAL); if (calcBlockLight) { - bl += weight * (blklight / MAX_LIGHT_VAL); + bl += weight * (entity.worldObj.getBlockLightValue(pos.x, pos.y, pos.z) / MAX_LIGHT_VAL); } else { bl += weight; } From 92a58b41bce99f89ed90442979260aaa58ac363d Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 22 Nov 2023 16:45:45 -0800 Subject: [PATCH 079/301] Better grow buffer --- .../chunk/backends/multidraw/ChunkDrawParamsVector.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java index f5c64cbbe..5ca15edfc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java @@ -29,10 +29,11 @@ public void reset() { } protected void growBuffer() { - ByteBuffer oldBuffer = this.buffer; this.capacity = this.capacity * 2; - this.buffer = BufferUtils.createByteBuffer(this.capacity * this.stride); - buffer.put((ByteBuffer) oldBuffer.rewind()); + ByteBuffer buffer = BufferUtils.createByteBuffer(this.capacity * this.stride); + buffer.put(this.buffer); + buffer.position(0); + this.buffer = buffer; } public static class NioChunkDrawCallVector extends ChunkDrawParamsVector { From fcb57bb891716d317fc1a15207f9bb3330ac002a Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 22 Nov 2023 19:32:21 -0800 Subject: [PATCH 080/301] Update README.MD --- README.MD | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/README.MD b/README.MD index d3ca9e77d..bcf51b294 100644 --- a/README.MD +++ b/README.MD @@ -4,10 +4,20 @@ The little Angle that supports shaders while saving your fps from a certain deat Not yet in an usable state # Credits -* Original ShaderMods: karyonix, sonic ether, id_miner, daxnitro -* Includes graphic enhancements from ArchaicFix by embeddedt - https://github.com/embeddedt/ArchaicFix under the [LGPL and other licenses](https://github.com/embeddedt/ArchaicFix/blob/main/LICENSE.md) -* Includes modified version of Notfine by jss2a98aj - https://github.com/jss2a98aj/NotFine under the LGPL -* Includes backported code from [Occulus](https://github.com/Asek3/Oculus) and [Iris](https://github.com/IrisShaders/Iris) under the LGPL -* eigenraven and vlaetansky for getting the original ShaderMod compiling again -* eigenraven, Caedis, glowredman, and mitchej123 for the conversion of ASM to Mixin -* JellySquid & the CaffeineMC team, for making Sodium in the first place and embeddedt for [Embeddium](https://github.com/embeddedt/embeddium/commit/dc59ca357c25beefd6288f0d1d40b4cd8e670ab8) under the [LGPL 3.0](https://github.com/embeddedt/embeddium/blob/16.x/forge/LICENSE) and select files under the LGPL-2.1 +* ShadersMod + * Original ShaderMods: karyonix, sonic ether, id_miner, daxnitro + * eigenraven, Caedis, glowredman, and mitchej123 for the conversion of ASM to Mixin + * eigenraven and vlaetansky for getting the original ShaderMod compiling again +* Archaicfix + * Includes graphic enhancements from ArchaicFix by embeddedt - https://github.com/embeddedt/ArchaicFix under the [LGPL and other licenses](https://github.com/embeddedt/ArchaicFix/blob/main/LICENSE.md) +* NotFine + * Includes modified version of Notfine by jss2a98aj - https://github.com/jss2a98aj/NotFine under the LGPL +* Iris Shaders + * Includes backported code from [Occulus](https://github.com/Asek3/Oculus) and [Iris](https://github.com/IrisShaders/Iris) under the LGPL +* Sodium + * JellySquid & the CaffeineMC team, for making Sodium in the first place + * Embeddedt for [Embeddium](https://github.com/embeddedt/embeddium/commit/dc59ca357c25beefd6288f0d1d40b4cd8e670ab8) under the [LGPL 3.0](https://github.com/embeddedt/embeddium/blob/16.x/forge/LICENSE) +* Neodymium + * Makamys for [Neodymium](https://github.com/makamys/Neodymium) - Various Tessellator -> Quad functionality taken under the LGPL 3 +* Angelica + * [Insert your name here] for helping get Angelica up and running! From 4e289a25ce7a07287b1c7460cddbfaa2b544cbcc Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Thu, 23 Nov 2023 10:59:15 -0500 Subject: [PATCH 081/301] Fix lerp uses and use render layers properly (#17) * Remove some uses of blockstate + patch FluidState * Fix lerp * Update FluidRenderer.java * Enable Sodium fluid rendering * Update FluidRenderer.java * Temporarily disable Sodium fluid rendering --- .../client/renderer/texture/TextureMap.java | 4 ++ .../early => client}/textures/ISpriteExt.java | 2 +- .../angelica/compat/mojang/BlockState.java | 7 ++- .../angelica/compat/mojang/FluidState.java | 13 +++++- .../angelica/compat/mojang/RenderLayers.java | 44 +++++++++++++++++-- .../gtnewhorizons/angelica/mixins/Mixins.java | 3 +- .../mixins/early/sodium/MixinMaterial.java | 12 +++++ .../early/sodium/MixinRenderGlobal.java | 9 ++-- .../textures/MixinTextureAtlasSprite.java | 3 +- .../render/chunk/data/ChunkRenderData.java | 4 +- .../chunk/tasks/ChunkRenderRebuildTask.java | 35 ++++++++++----- .../client/render/pipeline/BlockRenderer.java | 11 +++-- .../client/render/pipeline/FluidRenderer.java | 41 ++++++++++------- .../mods/sodium/client/util/MathUtil.java | 16 +++++++ .../client/util/color/FastCubicSampler.java | 6 +-- 15 files changed, 161 insertions(+), 49 deletions(-) rename src/main/java/com/gtnewhorizons/angelica/{mixins/early => client}/textures/ISpriteExt.java (80%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMaterial.java diff --git a/src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java b/src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java index 1aa78f013..c9b2c03df 100644 --- a/src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java +++ b/src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java @@ -3,6 +3,8 @@ import net.minecraft.client.resources.IResourceManager; import net.minecraft.util.ResourceLocation; +import java.util.Map; + public class TextureMap extends AbstractTexture { public static ResourceLocation locationBlocksTexture; @@ -24,4 +26,6 @@ public void setMipmapLevels(int p_147633_1_) {} public int getTextureType() { return 0; } + + public Object getTextureEntry(String iconName) { return null; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/ISpriteExt.java b/src/main/java/com/gtnewhorizons/angelica/client/textures/ISpriteExt.java similarity index 80% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/ISpriteExt.java rename to src/main/java/com/gtnewhorizons/angelica/client/textures/ISpriteExt.java index 238496054..1a1db51a1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/ISpriteExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/textures/ISpriteExt.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.textures; +package com.gtnewhorizons.angelica.client.textures; import net.minecraft.client.resources.data.AnimationMetadataSection; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java index 25b2482a1..0075dcf87 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java @@ -2,8 +2,11 @@ import com.gtnewhorizons.angelica.compat.forge.IForgeBlockState; import net.minecraft.block.Block; +import net.minecraft.block.BlockLiquid; import net.minecraft.block.material.Material; import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.BlockFluidBase; +import net.minecraftforge.fluids.FluidRegistry; import org.joml.Vector3d; public class BlockState implements IForgeBlockState { @@ -28,7 +31,7 @@ public boolean isSideInvisible(BlockState adjState, ForgeDirection facing) { } public boolean isOpaque() { - return true; + return block.getMaterial().isOpaque(); } public VoxelShape getCullingFace(BlockView view, BlockPos pos, ForgeDirection facing) { @@ -76,7 +79,7 @@ public long getRenderingSeed(BlockPos.Mutable pos) { } public FluidState getFluidState() { - return null; + return new FluidState(FluidRegistry.lookupFluidForBlock(block), meta); } public boolean shouldDisplayFluidOverlay(BlockRenderView world, BlockPos adjPos, FluidState fluidState) { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java index 1d2475b85..5d7d81960 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java @@ -1,16 +1,25 @@ package com.gtnewhorizons.angelica.compat.mojang; +import net.minecraft.block.Block; import net.minecraftforge.fluids.Fluid; import org.joml.Vector3d; public class FluidState { + private final Fluid fluid; + private final int meta; + + public FluidState(Fluid fluid, int meta) { + this.fluid = fluid; + this.meta = meta; + } + public boolean isEmpty() { - return false; + return fluid == null; } public Fluid getFluid() { - return null; + return fluid; } public Vector3d getVelocity(BlockRenderView world, BlockPos pos) { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java index ce5eab0d4..8583fb0a4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java @@ -1,11 +1,49 @@ package com.gtnewhorizons.angelica.compat.mojang; +import com.gtnewhorizons.angelica.mixins.early.sodium.MixinMaterial; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.block.material.MaterialLiquid; +import net.minecraftforge.fluids.Fluid; + public class RenderLayers { - public static boolean canRenderInLayer(BlockState state, RenderLayer type) { - return true; + public static boolean canRenderInLayer(BlockState state, RenderLayer layer) { + + return canRenderInLayer(state.getBlock(), layer); + } + + public static boolean canRenderInLayer(Block block, RenderLayer layer) { + + // Translucent blocks + if (((MixinMaterial) block.getMaterial()).getIsTranslucent()) + return layer == RenderLayer.translucent(); + + // TODO: use Sodium rendering for fluids. This if can be removed once that's done + if(block.getMaterial() == Material.water) + return layer == RenderLayer.translucent(); + + // Make all full, opaque blocks SOLID + // This misses things like fences and walls, but it doesn't matter too much + if (block.isOpaqueCube()) + return layer == RenderLayer.solid(); + + // TODO: CUTOUT is more performant, but this is fine for testing + return layer == RenderLayer.cutoutMipped(); } public static boolean canRenderInLayer(FluidState fluidState, RenderLayer layer) { - return true; + return canRenderFluidInLayer(fluidState.getFluid().getBlock(), layer); + } + + public static boolean canRenderFluidInLayer(Block block, RenderLayer layer) { + + // Make all water-type fluids translucent, and all others solid + // This may be revisited later, but it *should* be fine for now + // Translucent fluids + if (block.getMaterial() == Material.water) { + return layer == RenderLayer.solid(); + } + + return layer == RenderLayer.solid(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 76fa3a394..292a44fd2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -43,6 +43,7 @@ public enum Mixins { ,"sodium.MixinWorldRenderer" ,"sodium.MixinEntity" ,"sodium.MixinRenderManager" + ,"sodium.MixinMaterial" ) ), @@ -66,7 +67,7 @@ public enum Mixins { ANGELICA_TEXTURE(new Builder("Texture").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( - + "textures.MixinTextureAtlasSprite" )), // TODO: Iris diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMaterial.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMaterial.java new file mode 100644 index 000000000..0f0b1dc94 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMaterial.java @@ -0,0 +1,12 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import net.minecraft.block.material.Material; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Material.class) +public interface MixinMaterial { + + @Accessor("isTranslucent") + boolean getIsTranslucent(); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 66c00aa89..20cd831bc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -25,6 +25,8 @@ import java.util.List; +import static org.joml.Math.lerp; + // Let other mixins apply, and then overwrite them @Mixin(value = RenderGlobal.class, priority = 2000) public class MixinRenderGlobal implements IRenderGlobalExt { @@ -129,10 +131,9 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) // Roughly equivalent to `renderLayer` RenderDevice.enterManagedCode(); - final double x = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks; - final double y = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks; - final double z = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks; - + final double x = lerp(entity.lastTickPosX, entity.posX, partialTicks); + final double y = lerp(entity.lastTickPosY, entity.posY, partialTicks); + final double z = lerp(entity.lastTickPosZ, entity.posZ, partialTicks); try { MatrixStack matrixStack = new MatrixStack(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java index a93dc8472..c99efaa2a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java @@ -1,12 +1,13 @@ package com.gtnewhorizons.angelica.mixins.early.textures; +import com.gtnewhorizons.angelica.client.textures.ISpriteExt; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.data.AnimationMetadataSection; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @Mixin(TextureAtlasSprite.class) -public abstract class MixinTextureAtlasSprite implements ISpriteExt { +public abstract class MixinTextureAtlasSprite implements ISpriteExt { @Shadow private AnimationMetadataSection animationMetadata; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java index f53d9b125..e23695f15 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.data; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionData; -import com.gtnewhorizons.angelica.mixins.early.textures.ISpriteExt; +import com.gtnewhorizons.angelica.client.textures.ISpriteExt; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.Getter; @@ -143,7 +143,7 @@ public void setOcclusionData(ChunkOcclusionData data) { * @param sprite The sprite */ public void addSprite(TextureAtlasSprite sprite) { - if (((ISpriteExt)sprite).isAnimation()) { + if (((ISpriteExt) sprite).isAnimation()) { this.animatedSprites.add(sprite); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index ec4595a57..3ac9c429f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -19,15 +19,19 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheLocal; +import me.jellysquid.mods.sodium.client.util.MathUtil; import me.jellysquid.mods.sodium.client.util.task.CancellationSource; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; +import net.minecraft.block.Block; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MathHelper; +import net.minecraftforge.fluids.FluidRegistry; import org.joml.Vector3d; /** @@ -91,9 +95,16 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB for (int relZ = 0; relZ < 16; relZ++) { for (int relX = 0; relX < 16; relX++) { + BlockState blockState = slice.getBlockStateRelative(relX + 16, relY + 16, relZ + 16); + + // Can be replaced by slice.getBlockStateRelative if BlockState gets yeeted + Block block = blockState.getBlock(); + + boolean isFluid = FluidRegistry.lookupFluidForBlock(block) != null; + // TODO: Sodium - BlockState - if (blockState == null || blockState.getBlock() == Blocks.air /* || blockState.isAir()*/) { + if (block == Blocks.air) { continue; } @@ -101,9 +112,13 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB pos.set(baseX + relX, baseY + relY, baseZ + relZ); buffers.setRenderOffset(pos.x - renderOffset.getX(), pos.y - renderOffset.getY(), pos.z - renderOffset.getZ()); - if (blockState.getRenderType() == BlockRenderType.MODEL) { + // 1.7.10 has -1 (air, INVISIBLE), 0, (normal cubes), and 1+ (everything else) + // We don't actually use models, we have normal blocks and TEs + // TODO: use Sodium rendering for fluids + if (!block.hasTileEntity(blockState.getMetadata()) /*&& !isFluid*/) { for (RenderLayer layer : RenderLayer.getBlockLayers()) { - if (!RenderLayers.canRenderInLayer(blockState, layer)) { + + if (!RenderLayers.canRenderInLayer(block, layer)) { continue; } @@ -112,28 +127,26 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB ForgeHooksClientExt.setRenderLayer(layer); - -// IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); +// IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); // // BakedModel model = cache.getBlockModels().getModel(blockState); // - long seed = blockState.getRenderingSeed(pos); - + // This method calls block.getRenderingSeed, which just hashes the position + long seed = MathUtil.hashPos(pos.x, pos.y, pos.z); //blockState.getRenderingSeed(pos); if (cache.getBlockRenderer().renderModel(cache.getLocalSlice(), tessellator, renderBlocks, blockState, pos, buffers.get(layer), true, seed)) { bounds.addBlock(relX, relY, relZ); } - - } } FluidState fluidState = blockState.getFluidState(); - if (fluidState != null && !fluidState.isEmpty()) { + // TODO: use Sodium rendering for fluids + if (isFluid && false) { for (RenderLayer layer : RenderLayer.getBlockLayers()) { - if (!RenderLayers.canRenderInLayer(fluidState, layer)) { + if (!RenderLayers.canRenderFluidInLayer(block, layer)) { continue; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index 2cc950d21..39a6d0b8f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -58,6 +58,8 @@ public BlockRenderer(Minecraft client, LightPipelineProvider lighters) { } public boolean renderModel(BlockRenderView world, Tessellator tessellator, RenderBlocks renderBlocks, BlockState state, BlockPos pos, ChunkModelBuffers buffers, boolean cull, long seed) { + + final Block block = state.getBlock(); final LightMode mode = this.getLightingMode(state, world, pos); final LightPipeline lighter = this.lighters.getLighter(mode); Vector3d offset = state.getModelOffset(world, pos); @@ -66,8 +68,6 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende // modelData = model.getModelData(world, pos, state, modelData); - final Block block = state.getBlock(); - tessellator.startDrawingQuads(); renderBlocks.renderBlockByRenderType(block, pos.x, pos.y, pos.z); @@ -220,9 +220,12 @@ private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, M } private LightMode getLightingMode(BlockState state, BlockRenderView world, BlockPos pos) { + return getLightingMode(state.getBlock(), world, pos); + } + + private LightMode getLightingMode(Block block, BlockRenderView world, BlockPos pos) { // TODO: Sodium: Ambient Occlusion - final Block block = state.getBlock(); - if (this.useAmbientOcclusion && block.getLightValue() == 0 && /*model.isAmbientOcclusion(state) &&*/ state.getLightValue(world, pos) == 0) { + if (this.useAmbientOcclusion && /* model.isAmbientOcclusion(state) &&*/ block.getLightValue() == 0) { return LightMode.SMOOTH; } else { return LightMode.FLAT; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java index d93f32c1a..68533567d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java @@ -23,12 +23,15 @@ import me.jellysquid.mods.sodium.client.util.color.ColorABGR; import me.jellysquid.mods.sodium.common.util.DirectionUtil; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.util.MathHelper; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; import org.joml.Vector3d; +import java.util.Objects; + import static org.joml.Math.lerp; public class FluidRenderer { @@ -60,10 +63,11 @@ private boolean isFluidOccluded(BlockRenderView world, int x, int y, int z, Forg BlockPos adjPos = this.scratchPos.set(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); if (blockState.isOpaque()) { - return world.getFluidState(adjPos).getFluid().equals/*matchesType*/(fluid) || blockState.isSideSolid(world,pos,dir, SideShapeType.FULL); + return world.getFluidState(adjPos).getFluid() == fluid || blockState.isSideSolid(world, pos, dir, SideShapeType.FULL); // fluidlogged or next to water, occlude sides that are solid or the same liquid + // For a liquid block that's always } - return world.getFluidState(adjPos).getFluid().equals/*matchesType*/(fluid); + return world.getFluidState(adjPos).getFluid() == fluid; } private boolean isSideExposed(BlockRenderView world, int x, int y, int z, ForgeDirection dir, float height) { @@ -90,12 +94,14 @@ private boolean isSideExposed(BlockRenderView world, int x, int y, int z, ForgeD } public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos, ChunkModelBuffers buffers) { + int posX = pos.x; int posY = pos.y; int posZ = pos.z; Fluid fluid = fluidState.getFluid(); + // Check for occluded sides; if everything is occluded, don't render boolean sfUp = this.isFluidOccluded(world, posX, posY, posZ, ForgeDirection.UP, fluid); boolean sfDown = this.isFluidOccluded(world, posX, posY, posZ, ForgeDirection.DOWN, fluid) || !this.isSideExposed(world, posX, posY, posZ, ForgeDirection.DOWN, 0.8888889F); @@ -108,9 +114,14 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos return false; } - TextureAtlasSprite[] sprites = ForgeHooksClientExt.getFluidSprites(world, pos, fluidState); - // TODO: Sodium - Fluids - boolean hc = true; //fluidState.getFluid().getAttributes().getColor() != 0xffffffff; + // sprites[0] should be the still frames, [1] the flowing, [2] the overlay + // Sides 0 and 1 (top and bottom) are still, 2+ flowing. Overlay is null because I can't find it used anywhere + TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{ + (TextureAtlasSprite) RenderBlocks.getInstance().getBlockIconFromSide(fluid.getBlock(), 1), + (TextureAtlasSprite) RenderBlocks.getInstance().getBlockIconFromSide(fluid.getBlock(), 2), + null + };//ForgeHooksClientExt.getFluidSprites(world, pos, fluidState); + boolean hc = fluidState.getFluid().getColor() != 0xffffffff; //fluidState.getFluid().getAttributes().getColor() != 0xffffffff; boolean rendered = false; @@ -174,14 +185,14 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos float s2 = (float) sprites[0].getIconHeight() / (sprites[0].getMaxV() - sprites[0].getMinV()); float s3 = 4.0F / Math.max(s2, s1); - u1 = lerp(s3, u1, uAvg); - u2 = lerp(s3, u2, uAvg); - u3 = lerp(s3, u3, uAvg); - u4 = lerp(s3, u4, uAvg); - v1 = lerp(s3, v1, vAvg); - v2 = lerp(s3, v2, vAvg); - v3 = lerp(s3, v3, vAvg); - v4 = lerp(s3, v4, vAvg); + u1 = lerp(u1, uAvg, s3); + u2 = lerp(u2, uAvg, s3); + u3 = lerp(u3, uAvg, s3); + u4 = lerp(u4, uAvg, s3); + v1 = lerp(v1, vAvg, s3); + v2 = lerp(v2, vAvg, s3); + v3 = lerp(v3, vAvg, s3); + v4 = lerp(v4, vAvg, s3); quad.setSprite(sprite); @@ -415,7 +426,7 @@ private float getCornerHeight(BlockRenderView world, int x, int y, int z, Fluid int z2 = z - (i >> 1 & 1); - if (world.getFluidState(this.scratchPos.set(x2, y + 1, z2)).getFluid().equals/*matchesType*/(fluid)) { + if (world.getFluidState(this.scratchPos.set(x2, y + 1, z2)).getFluid() == fluid) { return 1.0F; } @@ -424,7 +435,7 @@ private float getCornerHeight(BlockRenderView world, int x, int y, int z, Fluid BlockState blockState = world.getBlockState(pos); FluidState fluidState = blockState.getFluidState(); - if (fluidState.getFluid().equals/*matchesType*/(fluid)) { + if (fluidState.getFluid() == fluid) { float height = fluidState.getHeight(world, pos); if (height >= 0.8F) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java index 49056712e..980058068 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/MathUtil.java @@ -7,4 +7,20 @@ public class MathUtil { public static boolean isPowerOfTwo(int n) { return ((n & (n - 1)) == 0); } + + /** + * @return Hash of the position, replaces a similar method from modern. It's almost certainly not exactly + * equivalent, but I'll be very concerned if it matters + */ + public static long hashPos(int x, int y, int z) { + return cantor(x, cantor(y, z)); + } + + /** + * Maps every positive a and b to a unique int, barring overflow + * Source on Stack Overflow + */ + private static long cantor(long a, long b) { + return (a + b + 1) * (a + b) / 2 + b; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java index 17ec2dc6e..8bbc0e535 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/color/FastCubicSampler.java @@ -50,13 +50,13 @@ public static Vector3d sampleColor(Vector3d pos, ColorFetcher colorFetcher, Func double totalFactor = 0.0D; for(int x = 0; x < DIAMETER; ++x) { - double densityX = lerp(deltaX, DENSITY_CURVE[x + 1], DENSITY_CURVE[x]); + double densityX = lerp(DENSITY_CURVE[x + 1], DENSITY_CURVE[x], deltaX); for(int y = 0; y < DIAMETER; ++y) { - double densityY = lerp(deltaY, DENSITY_CURVE[y + 1], DENSITY_CURVE[y]); + double densityY = lerp(DENSITY_CURVE[y + 1], DENSITY_CURVE[y], deltaY); for(int z = 0; z < DIAMETER; ++z) { - double densityZ = lerp(deltaZ, DENSITY_CURVE[z + 1], DENSITY_CURVE[z]); + double densityZ = lerp(DENSITY_CURVE[z + 1], DENSITY_CURVE[z], deltaZ); double factor = densityX * densityY * densityZ; totalFactor += factor; From 4c263225e1c537de08318353a145959097dc81e1 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:03:37 -0500 Subject: [PATCH 082/301] Rewind buffers when copying --- .../sodium/client/model/vertex/buffer/VertexBufferBuilder.java | 1 + .../render/chunk/backends/multidraw/ChunkDrawParamsVector.java | 1 + .../chunk/backends/multidraw/IndirectCommandBufferVector.java | 1 + 3 files changed, 3 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java index 7d589050f..d1bd26fec 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferBuilder.java @@ -26,6 +26,7 @@ private void grow(int len) { // Allocate a new buffer and copy the old buffer's contents into it ByteBuffer buffer = BufferUtils.createByteBuffer(cap); + this.buffer.rewind(); buffer.put(this.buffer); buffer.position(0); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java index 5ca15edfc..0892e7716 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java @@ -31,6 +31,7 @@ public void reset() { protected void growBuffer() { this.capacity = this.capacity * 2; ByteBuffer buffer = BufferUtils.createByteBuffer(this.capacity * this.stride); + this.buffer.rewind(); buffer.put(this.buffer); buffer.position(0); this.buffer = buffer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java index 8fc8af0ac..2fde0d9ad 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java @@ -35,6 +35,7 @@ public void pushCommandBuffer(ChunkDrawCallBatcher batcher) { protected void growBuffer(int n) { ByteBuffer buffer = BufferUtils.createByteBuffer(Math.max(this.buffer.capacity() * 2, this.buffer.capacity() + n)); + this.buffer.rewind(); buffer.put(this.buffer); buffer.position(0); From d5aa42f9b123643afde23ced29a70633e068df04 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:21:08 -0500 Subject: [PATCH 083/301] Fix multidraw --- .../angelica/compat/lwjgl/CompatMemoryUtil.java | 15 +++++++++++++++ .../backends/multidraw/ChunkDrawParamsVector.java | 7 ++----- .../multidraw/IndirectCommandBufferVector.java | 12 +++--------- .../multidraw/MultidrawChunkRenderBackend.java | 1 + .../chunk/backends/multidraw/StructBuffer.java | 3 +-- 5 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java new file mode 100644 index 000000000..8703ec32f --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java @@ -0,0 +1,15 @@ +package com.gtnewhorizons.angelica.compat.lwjgl; + +import org.lwjgl.BufferUtils; + +import java.nio.ByteBuffer; + +public class CompatMemoryUtil { + public static ByteBuffer memReallocDirect(ByteBuffer old, int capacity) { + ByteBuffer newBuf = BufferUtils.createByteBuffer(capacity); + old.rewind(); + newBuf.put(old); + newBuf.position(0); + return newBuf; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java index 0892e7716..f6bc96e36 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; @@ -30,11 +31,7 @@ public void reset() { protected void growBuffer() { this.capacity = this.capacity * 2; - ByteBuffer buffer = BufferUtils.createByteBuffer(this.capacity * this.stride); - this.buffer.rewind(); - buffer.put(this.buffer); - buffer.position(0); - this.buffer = buffer; + this.buffer = CompatMemoryUtil.memReallocDirect(this.buffer, this.capacity * this.stride); } public static class NioChunkDrawCallVector extends ChunkDrawParamsVector { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java index 2fde0d9ad..66ac725de 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; @@ -18,9 +19,7 @@ public void begin() { } public void end() { - if(this.buffer.position() > 0) { - this.buffer.flip(); - } + this.buffer.flip(); } public void pushCommandBuffer(ChunkDrawCallBatcher batcher) { @@ -34,11 +33,6 @@ public void pushCommandBuffer(ChunkDrawCallBatcher batcher) { } protected void growBuffer(int n) { - ByteBuffer buffer = BufferUtils.createByteBuffer(Math.max(this.buffer.capacity() * 2, this.buffer.capacity() + n)); - this.buffer.rewind(); - buffer.put(this.buffer); - buffer.position(0); - - this.buffer = buffer; + this.buffer = CompatMemoryUtil.memReallocDirect(this.buffer, Math.max(this.buffer.capacity() * 2, this.buffer.capacity() + n)); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java index 5490c4e8f..41d02175c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java @@ -230,6 +230,7 @@ public void render(CommandList commandList, ChunkRenderListIterator Date: Thu, 23 Nov 2023 13:28:10 -0500 Subject: [PATCH 084/301] Force cutout on all non-translucent blocks Matches vanilla --- .../gtnewhorizons/angelica/compat/mojang/RenderLayers.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java index 8583fb0a4..d1c6f53e9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java @@ -22,10 +22,10 @@ public static boolean canRenderInLayer(Block block, RenderLayer layer) { if(block.getMaterial() == Material.water) return layer == RenderLayer.translucent(); - // Make all full, opaque blocks SOLID + // TODO: Make all full, opaque blocks SOLID, or remove SOLID entirely // This misses things like fences and walls, but it doesn't matter too much - if (block.isOpaqueCube()) - return layer == RenderLayer.solid(); + //if (block.isOpaqueCube()) + // return layer == RenderLayer.solid(); // TODO: CUTOUT is more performant, but this is fine for testing return layer == RenderLayer.cutoutMipped(); From 29b4d1176bcae8e0bf21918f4a572c72b23d5e24 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:34:51 -0500 Subject: [PATCH 085/301] Revert "Disable multidraw" This reverts commit bbe1aba8f830e37361a6ac2f3f57ad118705ecdb. --- .../mods/sodium/client/render/SodiumWorldRenderer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 0f929a281..b40e655a0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -304,8 +304,7 @@ private void initRenderer() { private static ChunkRenderBackend createChunkRenderBackend(RenderDevice device, SodiumGameOptions options, ChunkVertexType vertexFormat) { boolean disableBlacklist = SodiumClientMod.options().advanced.ignoreDriverBlacklist; - // TODO: Re-enable multidraw - if (false && options.advanced.useChunkMultidraw && MultidrawChunkRenderBackend.isSupported(disableBlacklist)) { + if (options.advanced.useChunkMultidraw && MultidrawChunkRenderBackend.isSupported(disableBlacklist)) { return new MultidrawChunkRenderBackend(device, vertexFormat); } else { return new ChunkRenderBackendOneshot(vertexFormat); From 7cf1e827d8f5e73f1d21ebe16a74d051064f9681 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:46:04 -0500 Subject: [PATCH 086/301] Let vanilla handle render pass state --- .../angelica/mixins/early/sodium/MixinRenderGlobal.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 20cd831bc..3e949fd85 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -15,6 +15,7 @@ import net.minecraft.client.renderer.culling.ICamera; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Blocks; +import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; @@ -145,6 +146,7 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) for (RenderLayer renderLayer : renderLayers) { this.renderer.drawChunkLayer(renderLayer, matrixStack, x, y, z); } + GL11.glDepthMask(true); } finally { RenderDevice.exitManagedCode(); } From 0cbe90f42938862735c8b2bc052a591d76b7e81e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:46:30 -0500 Subject: [PATCH 087/301] Things --- .../mods/sodium/client/render/SodiumWorldRenderer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index b40e655a0..e1497e14b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -252,11 +252,12 @@ public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrust */ public void drawChunkLayer(RenderLayer renderLayer, MatrixStack matrixStack, double x, double y, double z) { BlockRenderPass pass = this.renderPassManager.getRenderPassForLayer(renderLayer); - pass.startDrawing(); + // startDrawing/endDrawing are handled by 1.7 already + //pass.startDrawing(); this.chunkRenderManager.renderLayer(matrixStack, pass, x, y, z); - pass.endDrawing(); + //pass.endDrawing(); GLStateManager.clearCurrentColor(); } From 1e739c9f5bc1f0a4e1f99cf1936c4faeaa86d213 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:53:30 -0500 Subject: [PATCH 088/301] Rewrite render layer check to use Forge 1.7 hook --- .../angelica/compat/mojang/RenderLayers.java | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java index d1c6f53e9..13734edee 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java @@ -13,22 +13,12 @@ public static boolean canRenderInLayer(BlockState state, RenderLayer layer) { } public static boolean canRenderInLayer(Block block, RenderLayer layer) { + if(layer == RenderLayer.translucent()) + return block.canRenderInPass(1); + else if(layer == RenderLayer.cutoutMipped()) + return block.canRenderInPass(0); - // Translucent blocks - if (((MixinMaterial) block.getMaterial()).getIsTranslucent()) - return layer == RenderLayer.translucent(); - - // TODO: use Sodium rendering for fluids. This if can be removed once that's done - if(block.getMaterial() == Material.water) - return layer == RenderLayer.translucent(); - - // TODO: Make all full, opaque blocks SOLID, or remove SOLID entirely - // This misses things like fences and walls, but it doesn't matter too much - //if (block.isOpaqueCube()) - // return layer == RenderLayer.solid(); - - // TODO: CUTOUT is more performant, but this is fine for testing - return layer == RenderLayer.cutoutMipped(); + return false; } public static boolean canRenderInLayer(FluidState fluidState, RenderLayer layer) { @@ -36,7 +26,6 @@ public static boolean canRenderInLayer(FluidState fluidState, RenderLayer layer) } public static boolean canRenderFluidInLayer(Block block, RenderLayer layer) { - // Make all water-type fluids translucent, and all others solid // This may be revisited later, but it *should* be fine for now // Translucent fluids From b9d34ec0d62f38693c8d514a500c08d2bb8ebe53 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 14:01:18 -0500 Subject: [PATCH 089/301] Fix skylight handling --- .../mods/sodium/client/world/cloned/ClonedChunkSection.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index e5e29ad11..29576ff13 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -90,7 +90,9 @@ public BlockState getBlockState(int x, int y, int z) { } public int getLightLevel(EnumSkyBlock type, int x, int y, int z) { if(type == EnumSkyBlock.Sky) { - return data.hasSky ? data.getExtSkylightValue(x, y, z) : 0; + if(world.provider.hasNoSky) + return 0; + return data.hasSky ? data.getExtSkylightValue(x, y, z) : type.defaultLightValue; } return data.getExtBlocklightValue(x, y, z); } From 74de832a0f83ad1e833c93388f835f7c18ca8f72 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 14:23:53 -0500 Subject: [PATCH 090/301] Fix flickering --- .../angelica/mixins/early/sodium/MixinRenderGlobal.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 3e949fd85..7ec623087 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -10,6 +10,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.client.renderer.culling.ICamera; @@ -129,6 +130,8 @@ public boolean updateRenderers(EntityLivingBase e, boolean b){ */ @Overwrite public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) { + RenderHelper.disableStandardItemLighting(); + this.mc.entityRenderer.enableLightmap(partialTicks); // Roughly equivalent to `renderLayer` RenderDevice.enterManagedCode(); @@ -139,16 +142,16 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) try { MatrixStack matrixStack = new MatrixStack(); final List renderLayers = switch(pass) { - case 0 -> ImmutableList.of(RenderLayer.solid(), RenderLayer.cutoutMipped(), RenderLayer.cutout()); + case 0 -> ImmutableList.of(RenderLayer.cutoutMipped()); case 1 -> ImmutableList.of(RenderLayer.translucent()); default -> throw new IllegalStateException("Unexpected value: " + pass); }; for (RenderLayer renderLayer : renderLayers) { this.renderer.drawChunkLayer(renderLayer, matrixStack, x, y, z); } - GL11.glDepthMask(true); } finally { RenderDevice.exitManagedCode(); + this.mc.entityRenderer.disableLightmap(partialTicks); } return 0; } From ec8074b3dab7dbadc2812a561b66eab6a4ff8c4e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 15:08:11 -0500 Subject: [PATCH 091/301] Clone TEs correctly --- .../world/cloned/ClonedChunkSection.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 29576ff13..8fc41721a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import lombok.Getter; import net.minecraft.block.Block; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.ChunkPosition; @@ -70,13 +71,24 @@ public void init(ChunkSectionPos pos) { this.tileEntities.clear(); - for (Map.Entry entry : chunk.chunkTileEntityMap.entrySet()) { - final TileEntity tile = entry.getValue(); - final BlockPos entityPos = new BlockPos(tile.xCoord, tile.yCoord, tile.zCoord); - - if(box.isVecInside(tile.xCoord, tile.yCoord, tile.zCoord)) { - //this.blockEntities.put(BlockPos.asLong(entityPos.getX() & 15, entityPos.getY() & 15, entityPos.getZ() & 15), entry.getValue()); - this.tileEntities.put(ChunkSectionPos.packLocal(entityPos), entry.getValue()); + // Check for tile entities + for(int y = pos.getMinY(); y <= pos.getMaxY(); y++) { + for(int z = pos.getMinZ(); z <= pos.getMaxZ(); z++) { + for(int x = pos.getMinX(); x <= pos.getMaxX(); x++) { + int lX = x & 15, lY = y & 15, lZ = z & 15; + // We have to use this insanity because in 1.7 the tile entity isn't guaranteed to be created + // when the chunk gets scheduled for rendering. So we might have to create it. + // Cloning is done on the main thread so this will not introduce threading issues + Block block = data.getBlockByExtId(lX, lY, lZ); + if(block.hasTileEntity(data.getExtBlockMetadata(lX, lY, lZ))) { + TileEntity tileentity = chunk.func_150806_e(x & 15, y, z & 15); + + if (TileEntityRendererDispatcher.instance.hasSpecialRenderer(tileentity)) + { + this.tileEntities.put(ChunkSectionPos.packLocal(new BlockPos(tileentity.xCoord, tileentity.yCoord, tileentity.zCoord)), tileentity); + } + } + } } } } From 671fcde0a28bb727d20854b00c7ea2b90d70ac33 Mon Sep 17 00:00:00 2001 From: Ryan Nasers Date: Thu, 23 Nov 2023 14:24:48 -0600 Subject: [PATCH 092/301] Fixing entityDistMulti (I think) --- src/main/java/jss/notfine/core/Settings.java | 2 +- src/main/java/jss/notfine/core/SettingsManager.java | 2 +- .../mods/sodium/client/render/SodiumWorldRenderer.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/jss/notfine/core/Settings.java b/src/main/java/jss/notfine/core/Settings.java index e425c1f13..36106a7e9 100644 --- a/src/main/java/jss/notfine/core/Settings.java +++ b/src/main/java/jss/notfine/core/Settings.java @@ -80,7 +80,7 @@ public void updateSetting() { RenderStars.reloadStarRenderList(Minecraft.getMinecraft().renderGlobal); } }, - RENDER_DISTANCE_ENTITIES(true, 100f, 50f, 500f, 25f) { + RENDER_DISTANCE_ENTITIES(true, 1.0f, 0.5f, 5.0f, 0.25f) { @Override public void updateSetting() { SettingsManager.entityRenderDistanceUpdated(); diff --git a/src/main/java/jss/notfine/core/SettingsManager.java b/src/main/java/jss/notfine/core/SettingsManager.java index 1ab0afc67..b85419e60 100644 --- a/src/main/java/jss/notfine/core/SettingsManager.java +++ b/src/main/java/jss/notfine/core/SettingsManager.java @@ -24,7 +24,7 @@ public class SettingsManager { public static boolean leavesOpaque; public static boolean waterDetail; public static boolean vignette; - public static double entityRenderScaleFactor = 1.0; + public static double entityRenderScaleFactor; public static ResourceLocation defaultBackground = Gui.optionsBackground; public static ResourceLocation[] extraBackgrounds = new ResourceLocation[] { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index e1497e14b..9c3f653d9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -244,7 +244,7 @@ public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrust profiler.endSection(); - SodiumGameOptions.EntityRenderDistance.setRenderDistanceMult(MathHelper.clamp_double((double) this.client.gameSettings.renderDistanceChunks / 8.0D, 1.0D, 2.5D) * (double) 1.0F * (SettingsManager.entityRenderScaleFactor/100)); + SodiumGameOptions.EntityRenderDistance.setRenderDistanceMult(MathHelper.clamp_double((double) this.client.gameSettings.renderDistanceChunks / 8.0D, 1.0D, 2.5D) * (double) 1.0F * (SettingsManager.entityRenderScaleFactor)); } /** From ad24e637e4c2a0a69a8da3c9376bf265bae4c64a Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 23 Nov 2023 13:07:10 -0800 Subject: [PATCH 093/301] Use lwjgl3ify 1.5.3 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 85a8520ee..16efd2fbd 100644 --- a/build.gradle +++ b/build.gradle @@ -793,7 +793,7 @@ ext.java17PatchDependenciesCfg = configurations.create("java17PatchDependencies" } dependencies { - def lwjgl3ifyVersion = '1.5.3-pre' + def lwjgl3ifyVersion = '1.5.3' if (modId != 'lwjgl3ify') { java17Dependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}") } From 024b34bdab5196af415024480417c611b4b97fb3 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 17:33:06 -0500 Subject: [PATCH 094/301] Fix TEs rendering on the wrong pass --- .../mods/sodium/client/render/SodiumWorldRenderer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 9c3f653d9..17eb5897d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -52,6 +52,7 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.MathHelper; +import net.minecraftforge.client.MinecraftForgeClient; import org.joml.Vector3d; import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap; @@ -324,8 +325,9 @@ public void renderTileEntities(EntityLivingBase entity, ICamera camera, float pa // double y = cameraPos.y; // double z = cameraPos.z; // + int pass = MinecraftForgeClient.getRenderPass(); for (TileEntity tileEntity : this.chunkRenderManager.getVisibleBlockEntities()) { - if(tileEntity.isInvalid() || !checkBEVisibility(tileEntity)) + if(tileEntity.isInvalid() || !tileEntity.shouldRenderInPass(pass) || !checkBEVisibility(tileEntity)) continue; // BlockPos pos = new BlockPos(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); // @@ -352,7 +354,7 @@ public void renderTileEntities(EntityLivingBase entity, ICamera camera, float pa } for (TileEntity tileEntity : this.globalTileEntities) { - if(!checkBEVisibility(tileEntity)) + if(!tileEntity.shouldRenderInPass(pass) || !checkBEVisibility(tileEntity)) continue; // BlockPos pos = new BlockPos(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); // From ffb77b0e1c2083664efecbc4bf3a3aba46ec3b4b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 18:18:00 -0500 Subject: [PATCH 095/301] Buff max render distance to 32 Pretty useless since the integrated server stalls instantly, but our renderer supports it --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../mixins/early/sodium/MixinGameSettings.java | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGameSettings.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 292a44fd2..a2966916a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -44,6 +44,7 @@ public enum Mixins { ,"sodium.MixinEntity" ,"sodium.MixinRenderManager" ,"sodium.MixinMaterial" + ,"sodium.MixinGameSettings" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGameSettings.java new file mode 100644 index 000000000..c948017e4 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGameSettings.java @@ -0,0 +1,18 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import net.minecraft.client.settings.GameSettings; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(GameSettings.class) +public class MixinGameSettings { + /** + * @author embeddedt + * @reason Sodium Renderer supports up to 32 chunks + */ + @ModifyConstant(method = "(Lnet/minecraft/client/Minecraft;Ljava/io/File;)V", constant = @Constant(floatValue = 16.0f)) + private float increaseMaxDistance(float old) { + return 32.0f; + } +} From 73503ec70fead57efc232bb4893504864fdbc011 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 18:42:56 -0500 Subject: [PATCH 096/301] Fix fog --- .../angelica/glsm/GLStateManager.java | 2 ++ .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../early/sodium/MixinEntityRenderer.java | 21 +++++++++++++++++++ .../early/sodium/MixinRenderGlobal.java | 3 +++ .../transform/GLStateManagerTransformer.java | 2 +- .../sodium/client/gl/compat/FogHelper.java | 6 ++++-- 6 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityRenderer.java diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 2c5e46243..efa6eb5cd 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -74,6 +74,7 @@ public static void glEnable(int cap) { case GL11.GL_DEPTH_TEST -> enableDepthTest(); case GL11.GL_CULL_FACE -> enableCull(); case GL11.GL_TEXTURE_2D -> enableTexture(); + case GL11.GL_FOG -> enableFog(); default -> GL11.glEnable(cap); } } @@ -86,6 +87,7 @@ public static void glDisable(int cap) { case GL11.GL_DEPTH_TEST -> disableDepthTest(); case GL11.GL_CULL_FACE -> disableCull(); case GL11.GL_TEXTURE_2D -> disableTexture(); + case GL11.GL_FOG -> disableFog(); default -> GL11.glDisable(cap); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index a2966916a..13a049e8c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -31,6 +31,7 @@ public enum Mixins { .setPhase(Phase.EARLY).addMixinClasses( "sodium.MixinChunkProviderClient" ,"sodium.MixinExtendedBlockStorage" + ,"sodium.MixinEntityRenderer" ,"sodium.MixinFMLClientHandler" ,"sodium.MixinFrustrum" ,"sodium.MixinMinecraft" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityRenderer.java new file mode 100644 index 000000000..5245d6673 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityRenderer.java @@ -0,0 +1,21 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import me.jellysquid.mods.sodium.client.gl.compat.FogHelper; +import net.minecraft.client.renderer.EntityRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityRenderer.class) +public class MixinEntityRenderer { + @Shadow + float fogColorRed, fogColorGreen, fogColorBlue; + @Inject(method = "updateFogColor", at = @At("RETURN")) + private void storeFog(CallbackInfo ci) { + FogHelper.red = fogColorRed; + FogHelper.green = fogColorGreen; + FogHelper.blue = fogColorBlue; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 7ec623087..292334de0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -131,6 +131,9 @@ public boolean updateRenderers(EntityLivingBase e, boolean b){ @Overwrite public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) { RenderHelper.disableStandardItemLighting(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glEnable(GL11.GL_FOG); this.mc.entityRenderer.enableLightmap(partialTicks); // Roughly equivalent to `renderLayer` RenderDevice.enterManagedCode(); diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index 6c24c4a02..21fadc88e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -33,7 +33,7 @@ public class GLStateManagerTransformer implements IClassTransformer { public static final Map> EnabledRedirects = ImmutableMap.of( GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", - "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor4f", "glShadeModel", "glFog", "glFogi", "glfFogf") + "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor4f", "glShadeModel", "glFog", "glFogi", "glFogf") ,GL13, Sets.newHashSet("glActiveTexture") ,GL14, Sets.newHashSet("glBlendFuncSeparate") ,EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java index 90530ca6c..f325e9c1f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java @@ -8,6 +8,8 @@ public class FogHelper { private static final float FAR_PLANE_THRESHOLD_EXP = (float) Math.log(1.0f / 0.0019f); private static final float FAR_PLANE_THRESHOLD_EXP2 = (float) Math.sqrt(FAR_PLANE_THRESHOLD_EXP); + public static float red, green, blue; + public static float getFogEnd() { return GLStateManager.getFog().end; } @@ -24,7 +26,7 @@ public static float getFogDensity() { * Retrieves the current fog mode from the fixed-function pipeline. */ public static ChunkFogMode getFogMode() { - int mode = 0; //GLStateManager.getFog().fogMode; // TODO fix fog + int mode = GLStateManager.getFog().fogMode; if(mode == 0 || !GLStateManager.getFog().mode.isEnabled()) return ChunkFogMode.NONE; @@ -50,6 +52,6 @@ public static float getFogCutoff() { public static float[] getFogColor() { // TODO: Sodium // return new float[]{BackgroundRenderer.red, BackgroundRenderer.green, BackgroundRenderer.blue, 1.0F}; - return new float[]{0.0F, 0.0F, 0.0F, 1.0F}; + return new float[]{red, green, blue, 1.0F}; } } From 7cb7bf772cf817547b32ac046405ad31ffbc1a4e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 18:46:28 -0500 Subject: [PATCH 097/301] Fix render distance changes being ignored --- .../angelica/mixins/early/sodium/MixinRenderGlobal.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 292334de0..31ee4a6bb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -130,6 +130,11 @@ public boolean updateRenderers(EntityLivingBase e, boolean b){ */ @Overwrite public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) { + // Handle view distance change + if(this.renderDistanceChunks != this.mc.gameSettings.renderDistanceChunks) { + this.loadRenderers(); + } + RenderHelper.disableStandardItemLighting(); GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glEnable(GL11.GL_ALPHA_TEST); From 36182564e00888d73a58735227111e56363bcef6 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 18:59:23 -0500 Subject: [PATCH 098/301] Implement entity culling --- .../angelica/mixins/early/sodium/MixinRenderGlobal.java | 8 ++++++++ .../mods/sodium/client/render/SodiumWorldRenderer.java | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 31ee4a6bb..6e9201285 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -14,6 +14,7 @@ import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.client.renderer.culling.ICamera; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Blocks; import org.lwjgl.opengl.GL11; @@ -23,6 +24,7 @@ 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.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.List; @@ -260,5 +262,11 @@ public void loadRenderers() { this.renderer.renderTileEntities(entity, camera, partialTicks); } + @Redirect(method="renderEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;isInRangeToRender3d(DDD)Z")) + private boolean isInRange(Entity e, double x, double y, double z) { + // TODO: this check is done slightly earlier than Sodium does it, make sure it doesn't cull too much + return e.isInRangeToRender3d(x, y, z) && SodiumWorldRenderer.getInstance().isEntityVisible(e); + } + } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 17eb5897d..c23c6d514 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -397,11 +397,11 @@ private static boolean isInfiniteExtentsBox(AxisAlignedBB box) { * @return True if the entity is visible, otherwise false */ public boolean isEntityVisible(Entity entity) { - if (!this.useEntityCulling) { + if (!this.useEntityCulling || entity.ignoreFrustumCheck) { return true; } - AxisAlignedBB box = entity.getBoundingBox(); + AxisAlignedBB box = entity.boundingBox; // Entities outside the valid world height will never map to a rendered chunk // Always render these entities or they'll be culled incorrectly! From d2e2b5f3d88be9dcda9f18bf9ec57fe25db80faf Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 19:22:23 -0500 Subject: [PATCH 099/301] Block face culling --- .../angelica/compat/nd/Quad.java | 133 +----------------- .../angelica/compat/nd/QuadNormal.java | 35 ----- .../quad/properties/ModelQuadFacing.java | 26 ++++ .../render/chunk/ChunkRenderManager.java | 3 +- .../client/render/pipeline/BlockRenderer.java | 24 ++-- 5 files changed, 47 insertions(+), 174 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java index b1e857588..951f1a9f3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.compat.nd; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraftforge.common.util.ForgeDirection; @@ -35,7 +36,7 @@ public class Quad implements ModelQuadView { public boolean deleted; public boolean noMerge; - public QuadNormal normal; + public ModelQuadFacing normal; public int offset; public BlockRenderer.Flags flags; @@ -47,15 +48,13 @@ public class Quad implements ModelQuadView { // 0: quads glued together on edge 1-2 or 3-0 ("megaquad row length") // 1: quads glued together on edge 0-1 or 2-3 ("megaquad column length") private int[] quadCountByDirection = {1, 1}; - public static int[] totalMergeCountByPlane = new int[3]; // When we merge with another quad, we forget what we used to be like. // Keep a reference to the quad we first merged with, and use it as a reminder. public Quad mergeReference; - private static final Vector3f vectorA = new Vector3f(); - private static final Vector3f vectorB = new Vector3f(); - private static final Vector3f vectorC = new Vector3f(); + private final Vector3f vectorA = new Vector3f(), vectorB = new Vector3f(), vectorC = new Vector3f(); + private boolean hasColor; private boolean hasShade; @@ -187,9 +186,9 @@ public void setState(int[] rawBuffer, int offset, BlockRenderer.Flags flags, int vectorA.set(xs[1] - xs[0], ys[1] - ys[0], zs[1] - zs[0]); vectorB.set(xs[2] - xs[1], ys[2] - ys[1], zs[2] - zs[1]); - vectorA.cross(vectorB, vectorA); + vectorA.cross(vectorB, vectorC); - normal = QuadNormal.fromVector(vectorC); + normal = ModelQuadFacing.fromVector(vectorC); } private void resetState() { @@ -214,7 +213,6 @@ private void resetState() { flags = null; uDirectionIs01 = false; Arrays.fill(quadCountByDirection, 1); - Arrays.fill(totalMergeCountByPlane, 0); mergeReference = null; } @@ -315,43 +313,6 @@ private boolean isTranslatedCopyOf(Quad o, boolean checkValid) { return true; } - public void tryToMerge(Quad o) { - if(noMerge || o.noMerge) return; - - if(isTranslatedCopyOf(o, true)) { - int numVerticesTouching = 0; - boolean[] verticesTouching = new boolean[4]; - for(int i = 0; i < 4; i++) { - for(int j = 0; j < 4; j++) { - if(xs[i] == o.xs[j] && ys[i] == o.ys[j] && zs[i] == o.zs[j]) { - verticesTouching[i] = true; - numVerticesTouching++; - } - } - } - if(numVerticesTouching == 2) { - for(int i = 0; i < 4; i++) { - if(verticesTouching[i]) { - copyVertexFrom(o, i, i); - } - } - - if((verticesTouching[0] && verticesTouching[1]) || (verticesTouching[2] && verticesTouching[3])) { - quadCountByDirection[0] += o.quadCountByDirection[0]; - } - if((verticesTouching[1] && verticesTouching[2]) || (verticesTouching[3] && verticesTouching[0])) { - quadCountByDirection[1] += o.quadCountByDirection[1]; - } - - totalMergeCountByPlane[getPlane().ordinal() - 1]++; - - mergeReference = o; - - o.deleted = true; - } - } - } - private void copyVertexFrom(Quad o, int src, int dest) { xs[dest] = o.xs[src]; ys[dest] = o.ys[src]; @@ -396,26 +357,6 @@ private boolean vertexExists(float x, float y, float z) { return false; } - // maybe minXYZ and maxXYZ should be arrays instead - public double getMin(int coord) { - return coord == 0 ? minX : coord == 1 ? minY : coord == 2 ? minZ : -1; - } - - public double getMax(int coord) { - return coord == 0 ? maxX : coord == 1 ? maxY : coord == 2 ? maxZ : -1; - } - - public boolean onSamePlaneAs(Quad o) { - return isValid(this) && isValid(o) && getPlane() == o.getPlane() && - ((getPlane() == Plane.XY && minZ == o.minZ) || - (getPlane() == Plane.XZ && minY == o.minY) || - (getPlane() == Plane.YZ && minX == o.minX)); - } - - public Plane getPlane() { - return Plane.fromNormal(normal); - } - public static boolean isValid(Quad q) { return q != null && !q.deleted; } @@ -429,66 +370,4 @@ public String toString() { return String.format(Locale.ENGLISH, "%s(%.1f, %.1f, %.1f -- %.1f, %.1f, %.1f)", deleted ? "XXX " : "", minX, minY, minZ, maxX, maxY, maxZ); //return String.format(Locale.ENGLISH, "%s[(%.1f, %.1f, %.1f), (%.1f, %.1f, %.1f), (%.1f, %.1f, %.1f), (%.1f, %.1f, %.1f)]", deleted ? "XXX " : "", xs[0], ys[0], zs[0], xs[1], ys[1], zs[1], xs[2], ys[2], zs[2], xs[3], ys[3], zs[3]); } - - public static class QuadPlaneComparator implements Comparator { - - public static final QuadPlaneComparator[] quadPlaneComparators = new QuadPlaneComparator[]{ - new QuadPlaneComparator(2, 1, 0), // PLANE_XY -> ZYX - new QuadPlaneComparator(1, 2, 0), // PLANE_XZ -> YZX - new QuadPlaneComparator(0, 2, 1) // PLANE_YZ -> XZY - }; - - private final int c0; - private final int c1; - private final int c2; - - public QuadPlaneComparator(int firstCoordToCompare, int secondCoordToCompare, int thirdCoordToCompare) { - this.c0 = firstCoordToCompare; - this.c1 = secondCoordToCompare; - this.c2 = thirdCoordToCompare; - } - - @Override - public int compare(Quad a, Quad b) { - if(a.getMin(c0) < b.getMin(c0)) { - return -1; - } else if(a.getMin(c0) > b.getMin(c0)) { - return 1; - } else { - if(a.getMin(c1) < b.getMin(c1)) { - return -1; - } else if(a.getMin(c1) > b.getMin(c1)) { - return 1; - } else { - if(a.getMin(c2) < b.getMin(c2)) { - return -1; - } else if(a.getMin(c2) > b.getMin(c2)) { - return 1; - } else { - return (int)Math.signum(a.offset - b.offset); - } - } - } - } - } - - public static enum Plane { - NONE, - XY, - XZ, - YZ; - - public static Plane fromNormal(QuadNormal normal) { - return switch (normal) { - case POSITIVE_X, NEGATIVE_X -> YZ; - case POSITIVE_Y, NEGATIVE_Y -> XZ; - case POSITIVE_Z, NEGATIVE_Z -> XY; - default -> NONE; - }; - } - } - - public boolean isPosEqual(Quad b) { - return Arrays.equals(xs, b.xs) && Arrays.equals(ys, b.ys) && Arrays.equals(zs, b.zs); - } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java deleted file mode 100644 index 5c92870f0..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/nd/QuadNormal.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.gtnewhorizons.angelica.compat.nd; - -import org.joml.Vector3f; - -public enum QuadNormal { - // Adapted from Neodymium - NONE, POSITIVE_X, NEGATIVE_X, POSITIVE_Y, NEGATIVE_Y, POSITIVE_Z, NEGATIVE_Z; - - private static final QuadNormal[] NORMAL_ORDER = new QuadNormal[] {QuadNormal.NONE, QuadNormal.POSITIVE_Y, QuadNormal.POSITIVE_X, QuadNormal.POSITIVE_Z, QuadNormal.NEGATIVE_X, QuadNormal.NEGATIVE_Z, QuadNormal.NEGATIVE_Y}; - - public static QuadNormal fromVector(Vector3f normal) { - if(normal.x == 0f) { - if(normal.y == 0f) { - if(normal.z > 0) { - return POSITIVE_Z; - } else if(normal.z < 0) { - return NEGATIVE_Z; - } - } else if(normal.z == 0f) { - if(normal.y > 0) { - return POSITIVE_Y; - } else if(normal.y < 0) { - return NEGATIVE_Y; - } - } - } else if(normal.y == 0f && (normal.z == 0f)) { - if(normal.x > 0) { - return POSITIVE_X; - } else if(normal.x < 0) { - return NEGATIVE_X; - } - } - return NONE; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index af809f805..c2d04f5ab 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.model.quad.properties; import net.minecraftforge.common.util.ForgeDirection; +import org.joml.Vector3f; public enum ModelQuadFacing { UP, @@ -33,6 +34,31 @@ public static ModelQuadFacing fromDirection(ForgeDirection dir) { } } + public static ModelQuadFacing fromVector(Vector3f normal) { + if(normal.x == 0f) { + if(normal.y == 0f) { + if(normal.z > 0) { + return SOUTH; + } else if(normal.z < 0) { + return NORTH; + } + } else if(normal.z == 0f) { + if(normal.y > 0) { + return UP; + } else if(normal.y < 0) { + return DOWN; + } + } + } else if(normal.y == 0f && (normal.z == 0f)) { + if(normal.x > 0) { + return EAST; + } else if(normal.x < 0) { + return WEST; + } + } + return UNASSIGNED; + } + public ModelQuadFacing getOpposite() { switch (this) { case UP: diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 76bc85dab..6efd0d50c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -127,8 +127,7 @@ public ChunkRenderManager(SodiumWorldRenderer renderer, ChunkRenderBackend ba this.translucencySorting = SodiumClientMod.options().advanced.translucencySorting; this.translucencyBlockRenderDistance = Math.min(9216, (renderDistance << 4) * (renderDistance << 4)); - // TODO: Sodium - Culling - this.useBlockFaceCulling = false; //SodiumClientMod.options().advanced.useBlockFaceCulling; + this.useBlockFaceCulling = SodiumClientMod.options().advanced.useBlockFaceCulling; } public void update(Camera camera, FrustumExtended frustum, int frame, boolean spectator) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index 39a6d0b8f..c48f1123f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -88,17 +88,17 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende // } this.random.setSeed(seed); - // TODO: Occlusion by side... Potentially adapt the logic from Neodyium... - final List all = tesselatorToBakedQuadList(tessellator, pos); - ((ITessellatorInstance) tessellator).discard(); -// List all = model.getQuads(state, null, this.random, modelData); + final List all = tesselatorToBakedQuadList(tessellator, pos); - if (!all.isEmpty()) { - this.renderQuadList(world, state, pos, lighter, offset, buffers, all, null); + for(ModelQuadFacing facing : ModelQuadFacing.VALUES) { + this.renderQuadList(world, state, pos, lighter, offset, buffers, all, facing); + } + if(!all.isEmpty()) rendered = true; - } + + ((ITessellatorInstance) tessellator).discard(); return rendered; } @@ -134,6 +134,7 @@ private List tesselatorToBakedQuadList(Tessellator t, BlockPos pos) { Quad quad = quadBuf.next(); // RenderBlocks adds the subchunk-relative coordinates as the offset, cancel it out here quad.setState(t.rawBuffer, quadI * (verticesPerPrimitive * 8), FLAGS, t.drawMode, -pos.x, -pos.y, -pos.z); + if(quad.deleted) { quadBuf.remove(); } @@ -162,8 +163,7 @@ private List tesselatorToBakedQuadList(Tessellator t, BlockPos pos) { } private void renderQuadList(BlockRenderView world, BlockState state, BlockPos pos, LightPipeline lighter, Vector3d offset, - ChunkModelBuffers buffers, List quads, ForgeDirection cullFace) { - ModelQuadFacing facing = cullFace == null ? ModelQuadFacing.UNASSIGNED : ModelQuadFacing.fromDirection(cullFace); + ChunkModelBuffers buffers, List quads, ModelQuadFacing facing) { ModelVertexSink sink = buffers.getSink(facing); sink.ensureCapacity(quads.size() * 4); @@ -175,8 +175,12 @@ private void renderQuadList(BlockRenderView world, BlockState state, BlockPos po for (int i = 0, quadsSize = quads.size(); i < quadsSize; i++) { Quad quad = quads.get(i); + if(quad.normal != facing) + continue; + QuadLightData light = this.cachedQuadLightData; - lighter.calculate(quad, pos, light, cullFace, quad.getFace(), quad.hasShade()); + // TODO: maybe make non-null? + lighter.calculate(quad, pos, light, null, quad.getFace(), quad.hasShade()); this.renderQuad(world, state, pos, sink, offset, quad, light, renderData); } From f4477d1cf6bf8d62d817ff773156e2f716926177 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 23 Nov 2023 19:37:08 -0500 Subject: [PATCH 100/301] Re-enable occlusion culling --- .../compat/mojang/ChunkOcclusionData.java | 7 +- .../mojang/ChunkOcclusionDataBuilder.java | 152 +++++++++++++++++- .../early/sodium/MixinRenderGlobal.java | 10 +- .../chunk/cull/graph/ChunkGraphCuller.java | 14 +- .../chunk/tasks/ChunkRenderRebuildTask.java | 2 +- 5 files changed, 175 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java index 4e138ef84..34478aa08 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java @@ -4,6 +4,7 @@ import java.util.BitSet; import java.util.EnumSet; +import java.util.Set; public class ChunkOcclusionData { private static final int DIRECTION_COUNT = ForgeDirection.values().length; @@ -13,7 +14,7 @@ public ChunkOcclusionData() { this.visibility = new BitSet(DIRECTION_COUNT * DIRECTION_COUNT); } - public void addOpenEdgeFaces(EnumSet faces) { + public void addOpenEdgeFaces(Set faces) { for (ForgeDirection dirFrom : faces) { for (ForgeDirection dirTo : faces) { this.setVisibleThrough(dirFrom, dirTo, true); @@ -32,4 +33,8 @@ public void setVisibleThrough(ForgeDirection from, ForgeDirection to, boolean vi public boolean isVisibleThrough(ForgeDirection from, ForgeDirection to) { return this.visibility.get(from.ordinal() + to.ordinal() * DIRECTION_COUNT); } + + public void fill(boolean visible) { + this.visibility.set(0, this.visibility.size(), visible); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java index bfa4d420e..f338b42cf 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java @@ -1,10 +1,158 @@ package com.gtnewhorizons.angelica.compat.mojang; +import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue; +import it.unimi.dsi.fastutil.ints.IntPriorityQueue; +import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.util.Util; +import net.minecraftforge.common.util.ForgeDirection; + +import java.util.BitSet; +import java.util.EnumSet; +import java.util.Set; + +/** + * WARNING: Minecraft 1.16 code rip!! + */ public class ChunkOcclusionDataBuilder { + private static final int STEP_X = (int)Math.pow(16.0, 0.0); + private static final int STEP_Z = (int)Math.pow(16.0, 1.0); + private static final int STEP_Y = (int)Math.pow(16.0, 2.0); + private static final ForgeDirection[] DIRECTIONS = DirectionUtil.ALL_DIRECTIONS; + private final BitSet closed = new BitSet(4096); + private static final int[] EDGE_POINTS = new int[1352]; + + static { + int i = 0; + int j = 15; + int k = 0; + + for(int l = 0; l < 16; ++l) { + for(int m = 0; m < 16; ++m) { + for(int n = 0; n < 16; ++n) { + if (l == 0 || l == 15 || m == 0 || m == 15 || n == 0 || n == 15) { + EDGE_POINTS[k++] = pack(l, m, n); + } + } + } + } + } + private int openCount = 4096; + + public void markClosed(BlockPos pos) { + this.closed.set(pack(pos), true); + --this.openCount; + } + + private static int pack(BlockPos pos) { + return pack(pos.getX() & 15, pos.getY() & 15, pos.getZ() & 15); + } + + private static int pack(int x, int y, int z) { + return x << 0 | y << 8 | z << 4; + } public ChunkOcclusionData build() { - return null; + ChunkOcclusionData lv = new ChunkOcclusionData(); + if (4096 - this.openCount < 256) { + lv.fill(true); + } else if (this.openCount == 0) { + lv.fill(false); + } else { + for(int i : EDGE_POINTS) { + if (!this.closed.get(i)) { + lv.addOpenEdgeFaces(this.getOpenFaces(i)); + } + } + } + + return lv; + } + + private Set getOpenFaces(int pos) { + Set set = EnumSet.noneOf(ForgeDirection.class); + IntPriorityQueue intPriorityQueue = new IntArrayFIFOQueue(); + intPriorityQueue.enqueue(pos); + this.closed.set(pos, true); + + while(!intPriorityQueue.isEmpty()) { + int j = intPriorityQueue.dequeueInt(); + this.addEdgeFaces(j, set); + + for(ForgeDirection lv : DIRECTIONS) { + int k = this.offset(j, lv); + if (k >= 0 && !this.closed.get(k)) { + this.closed.set(k, true); + intPriorityQueue.enqueue(k); + } + } + } + + return set; + } + + private void addEdgeFaces(int pos, Set openFaces) { + int j = pos >> 0 & 15; + if (j == 0) { + openFaces.add(ForgeDirection.WEST); + } else if (j == 15) { + openFaces.add(ForgeDirection.EAST); + } + + int k = pos >> 8 & 15; + if (k == 0) { + openFaces.add(ForgeDirection.DOWN); + } else if (k == 15) { + openFaces.add(ForgeDirection.UP); + } + + int l = pos >> 4 & 15; + if (l == 0) { + openFaces.add(ForgeDirection.NORTH); + } else if (l == 15) { + openFaces.add(ForgeDirection.SOUTH); + } } - public void markClosed(BlockPos.Mutable pos) {} + private int offset(int pos, ForgeDirection arg) { + switch(arg) { + case DOWN: + if ((pos >> 8 & 15) == 0) { + return -1; + } + + return pos - STEP_Y; + case UP: + if ((pos >> 8 & 15) == 15) { + return -1; + } + + return pos + STEP_Y; + case NORTH: + if ((pos >> 4 & 15) == 0) { + return -1; + } + + return pos - STEP_Z; + case SOUTH: + if ((pos >> 4 & 15) == 15) { + return -1; + } + + return pos + STEP_Z; + case WEST: + if ((pos >> 0 & 15) == 0) { + return -1; + } + + return pos - STEP_X; + case EAST: + if ((pos >> 0 & 15) == 15) { + return -1; + } + + return pos + STEP_X; + default: + return -1; + } + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 6e9201285..0e8a83fa4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -8,6 +8,7 @@ import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; 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; @@ -166,6 +167,13 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) return 0; } + private boolean isSpectatorMode() { + PlayerControllerMP controller = Minecraft.getMinecraft().playerController; + if(controller == null) + return false; + return controller.currentGameType.getID() == 3; + } + /** * @author Sodium * @reason Redirect to our renderer @@ -177,7 +185,7 @@ public void clipRenderersByFrustum(ICamera frustrum, float partialTicks) { final Frustrum frustum = (Frustrum) frustrum; boolean hasForcedFrustum = false; - boolean spectator = false; + boolean spectator = isSpectatorMode(); Camera camera = new Camera(mc.renderViewEntity, partialTicks); try { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java index 46a62d611..876c34402 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java @@ -11,6 +11,9 @@ import me.jellysquid.mods.sodium.client.render.chunk.cull.ChunkCuller; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import net.minecraft.util.MathHelper; @@ -73,9 +76,7 @@ private boolean isWithinRenderDistance(ChunkGraphNode adj) { private void initSearch(Camera camera, FrustumExtended frustum, int frame, boolean spectator) { this.activeFrame = frame; this.frustum = frustum; - // TODO: Sodium Options - // TODO: Sodium - Culling - this.useOcclusionCulling = false; //Minecraft.getMinecraft().chunkCullingEnabled; + this.useOcclusionCulling = true; this.visible.clear(); @@ -95,8 +96,11 @@ private void initSearch(Camera camera, FrustumExtended frustum, int frame, boole rootNode.resetCullingState(); rootNode.setLastVisibleFrame(frame); - if (spectator && ((BlockRenderView)this.world).getBlockState(origin).isOpaqueFullCube((BlockRenderView) this.world, origin)) { - this.useOcclusionCulling = false; + if (spectator) { + Block block = this.world.getBlock(origin.getX(), origin.getY(), origin.getZ()); + if(block.isOpaqueCube()) { + this.useOcclusionCulling = false; + } } this.visible.add(rootNode); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 3ac9c429f..fd7629253 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -171,7 +171,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB } } - if (blockState.isOpaqueFullCube(slice, pos)) { + if (block.isOpaqueCube()) { occluder.markClosed(pos); } } From 0d27fdea950adddec21870c58d2155d5798227db Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 24 Nov 2023 07:43:27 +0100 Subject: [PATCH 101/301] Fix x/z coordinate mixup when indexing biome arrays Partially fixes wrong biome colors, but at chunk edges it's still wrong because neighboring chunks aren't accessed --- .../me/jellysquid/mods/sodium/client/world/WorldSlice.java | 5 +++-- .../mods/sodium/client/world/cloned/ClonedChunkSection.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index c1b1ef7ee..8eaf7b023 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -214,8 +214,9 @@ public boolean isAirBlock(int x, int y, int z) { @Override public BiomeGenBase getBiomeGenForCoords(int x, int z) { - // TODO: Do we need to handle neighboring chunk columns or is this sufficient? - final int k = this.biomeData[(x & 15) << 4 | (z & 15)] & 255; + // TODO: We need to handle neighboring chunk columns + // (see BlockLiquid#colorMultiplier for example) + final int k = this.biomeData[(x & 15) | (z & 15) << 4] & 255; return BiomeGenBase.getBiome(k); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 8fc41721a..efa648323 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -110,7 +110,7 @@ public int getLightLevel(EnumSkyBlock type, int x, int y, int z) { } public BiomeGenBase getBiomeForNoiseGen(int x, int y, int z) { - int k = this.biomeData[x << 4 | z] & 255; + int k = this.biomeData[x | z << 4] & 255; return BiomeGenBase.getBiome(k); } From 3f6fa1bd3b84b2a83e7befba7521a33c85969160 Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 24 Nov 2023 07:44:05 +0100 Subject: [PATCH 102/301] Make a copy of biome data The old code seemed to work fine but this should be safer --- .../mods/sodium/client/world/cloned/ClonedChunkSection.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index efa648323..679215928 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -20,6 +20,7 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraft.world.gen.structure.StructureBoundingBox; +import java.util.Arrays; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -65,7 +66,7 @@ public void init(ChunkSectionPos pos) { this.pos = pos; this.data = new ExtendedBlockStorageExt(section); - this.biomeData = chunk.getBiomeArray(); + this.biomeData = Arrays.copyOf(chunk.getBiomeArray(), chunk.getBiomeArray().length); StructureBoundingBox box = new StructureBoundingBox(pos.getMinX(), pos.getMinY(), pos.getMinZ(), pos.getMaxX(), pos.getMaxY(), pos.getMaxZ()); From edaa3eaf59bf4d0eb04bb0d7579178f178cc7c7a Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 24 Nov 2023 08:14:46 +0100 Subject: [PATCH 103/301] Make CompatMemoryUtil#memReallocDirect preserve buffer position LWJGL3's MemoryUtil#memRealloc does this, see its javadoc. Fixes screen flashing and this error getting printed when indirect buffer grows: GL_INVALID_OPERATION error generated. Bound draw indirect buffer is not large enough. --- .../gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java index 8703ec32f..e4b93a441 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java @@ -7,9 +7,10 @@ public class CompatMemoryUtil { public static ByteBuffer memReallocDirect(ByteBuffer old, int capacity) { ByteBuffer newBuf = BufferUtils.createByteBuffer(capacity); + int oldPos = old.position(); old.rewind(); newBuf.put(old); - newBuf.position(0); + newBuf.position(Math.min(capacity, oldPos)); return newBuf; } } From a97eecff1e22cdc792986cfe059fdc0da5ea25ec Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 24 Nov 2023 10:17:34 +0100 Subject: [PATCH 104/301] Use biome data of neighboring chunk sections Fixes wrong colors at chunk edges --- .../mods/sodium/client/world/WorldSlice.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 8eaf7b023..fcad721ab 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -1,5 +1,7 @@ package me.jellysquid.mods.sodium.client.world; +import java.util.Arrays; + import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; @@ -68,8 +70,8 @@ public class WorldSlice implements BlockRenderView, IBlockAccess { // Local section copies. Read-only. private ClonedChunkSection[] sections; - // Biome data -- todo - each chunk column? - private byte[] biomeData; + // Biome data for each chunk section + private byte[][] biomeData; // The starting point from which this slice captures blocks private int baseX, baseY, baseZ; @@ -126,6 +128,7 @@ public WorldSlice(WorldClient world) { this.sections = new ClonedChunkSection[SECTION_TABLE_ARRAY_SIZE]; this.blockStatesArrays = new BlockState[SECTION_TABLE_ARRAY_SIZE][]; + this.biomeData = new byte[SECTION_TABLE_ARRAY_SIZE][]; for (int x = 0; x < SECTION_LENGTH; x++) { for (int y = 0; y < SECTION_LENGTH; y++) { @@ -144,7 +147,7 @@ public void copyData(ChunkRenderContext context) { this.baseX = (this.origin.x - NEIGHBOR_CHUNK_RADIUS) << 4; this.baseY = (this.origin.y - NEIGHBOR_CHUNK_RADIUS) << 4; this.baseZ = (this.origin.z - NEIGHBOR_CHUNK_RADIUS) << 4; - this.biomeData = null; + Arrays.fill(this.biomeData, null); for (int x = 0; x < SECTION_LENGTH; x++) { for (int y = 0; y < SECTION_LENGTH; y++) { @@ -152,6 +155,7 @@ public void copyData(ChunkRenderContext context) { final int idx = getLocalSectionIndex(x, y, z); this.unpackBlockData(this.blockStatesArrays[idx], this.sections[idx], context.getVolume()); + this.biomeData[idx] = this.sections[idx].getBiomeData(); } } } @@ -214,9 +218,12 @@ public boolean isAirBlock(int x, int y, int z) { @Override public BiomeGenBase getBiomeGenForCoords(int x, int z) { - // TODO: We need to handle neighboring chunk columns - // (see BlockLiquid#colorMultiplier for example) - final int k = this.biomeData[(x & 15) | (z & 15) << 4] & 255; + int relX = x - this.baseX; + int relY = 0; + int relZ = z - this.baseZ; + + final int k = this.biomeData[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] + [(x & 15) | (z & 15) << 4] & 255; return BiomeGenBase.getBiome(k); } @@ -284,9 +291,6 @@ private void unpackBlockDataZ(BlockState[] states, ClonedChunkSection section) { int minBlockZ = pos.getMinZ(); int maxBlockZ = pos.getMaxZ(); - // Copy biome data from the origin sub-chunk. In 1.7.10 it's the same on every sub-chunk. - this.biomeData = section.getBiomeData(); - // TODO: Can this be optimized? copyBlocks(states, section, minBlockY, maxBlockY, minBlockZ, maxBlockZ, minBlockX, maxBlockX); } From 7bd5ba3f0ca8a1713f7ec1c481a11309068fb4fa Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 24 Nov 2023 09:11:38 -0500 Subject: [PATCH 105/301] Re-enable fog culling --- .../mods/sodium/client/render/chunk/ChunkRenderManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 6efd0d50c..408c3b7ac 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -162,8 +162,7 @@ private void setup(Camera camera) { float dist = FogHelper.getFogCutoff() + FOG_PLANE_OFFSET; if (dist != 0.0f) { - // TODO: Sodium - Culling - //this.useFogCulling = true; // TODO fix fog + this.useFogCulling = true; this.fogRenderCutoff = Math.max(FOG_PLANE_MIN_DISTANCE, dist * dist); } } From ad63b950687ef2edc56eefde0545cc2bb951e1f7 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 24 Nov 2023 09:11:47 -0500 Subject: [PATCH 106/301] Tile entity culling --- .../chunk/tasks/ChunkRenderRebuildTask.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index fd7629253..358c89efe 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -30,6 +30,7 @@ import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.MathHelper; import net.minecraftforge.fluids.FluidRegistry; import org.joml.Vector3d; @@ -66,6 +67,25 @@ public ChunkRenderRebuildTask withCameraPosition(Vector3d camera) { return this; } + private boolean rendersOutsideBoundingBox(TileEntity entity, int baseX, int baseY, int baseZ) { + AxisAlignedBB box = entity.getRenderBoundingBox(); + + // Check if it's explictly infinite + if(box == TileEntity.INFINITE_EXTENT_AABB) + return true; + + // Check if it extends outside our minimums + if(box.minX < baseX || box.minY < baseY || box.minZ < baseZ) + return true; + + // Check if it extends outside our maximums + if(box.maxX > (baseX + 16) || box.maxY > (baseY + 16) || box.maxZ > (baseZ + 16)) + return true; + + // So it's within the chunk + return false; + } + @Override public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildBuffers buffers, CancellationSource cancellationSource) { // COMPATIBLITY NOTE: Oculus relies on the LVT of this method being unchanged, at least in 16.5 @@ -163,10 +183,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB final TileEntitySpecialRenderer renderer = TileEntityRendererDispatcher.instance.getSpecialRenderer(entity); if (entity != null && renderer != null) { - // TODO: Sodium - Per-chunk tile entities - // !rendersOutsideBoundingBox(entity) in sodium - // entity.getRenderBoundingBox() != TileEntity.INFINITE_EXTENT_AABB rough equivalent in 1.7.10 - renderData.addTileEntity(entity, false); + renderData.addTileEntity(entity, !rendersOutsideBoundingBox(entity, baseX, baseY, baseZ)); bounds.addBlock(relX, relY, relZ); } } From 19ff8ee57729a9e14453737879ad9052bcbb281e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 24 Nov 2023 09:38:16 -0500 Subject: [PATCH 107/301] Remove some unneeded Sodium code --- .../compat/forge/SinkingVertexBuilder.java | 189 ------------------ .../client/buffer/ExtendedVertexFormat.java | 19 -- .../sodium/common/util/DirectionUtil.java | 14 -- 3 files changed, 222 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/SinkingVertexBuilder.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/SinkingVertexBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/SinkingVertexBuilder.java deleted file mode 100644 index 90943951e..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/SinkingVertexBuilder.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; -import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; -import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraftforge.common.util.ForgeDirection; - -import javax.annotation.Nonnull; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Arrays; - -/** - * A allocation-free {@link IVertexBuilder} implementation - * which pipes vertices into a {@link ModelVertexSink}. - * - * @author KitsuneAlex - */ - -public final class SinkingVertexBuilder implements VertexConsumer { - private final ByteBuffer buffer = ByteBuffer.allocateDirect(2097152).order(ByteOrder.nativeOrder()); - private final int[] sideCount = new int[ModelQuadFacing.VALUES.length]; - private int currentVertex; - - private float x; - private float y; - private float z; - private float nx; - private float ny; - private float nz; - private float u; - private float v; - private int color; - private int light; - - private static final ThreadLocal instance = ThreadLocal.withInitial(SinkingVertexBuilder::new); - - @Nonnull - public static SinkingVertexBuilder getInstance() { - return instance.get(); - } - - @Nonnull - @Override - public VertexConsumer vertex(double x, double y, double z) { - this.x = (float) x; - this.y = (float) y; - this.z = (float) z; - return this; - } - - @Nonnull - @Override - public VertexConsumer color(int r, int g, int b, int a) { - color = ((a & 255) << 24) | ((b & 255) << 16) | ((g & 255) << 8) | (r & 255); - // Colour.flipABGR(Colour.packRGBA(r, g, b, a)); // We need ABGR so we compose it on the fly - return this; - } - - @Nonnull - @Override - public VertexConsumer texture(float u, float v) { - this.u = u; - this.v = v; - return this; - } - - @Nonnull - @Override - public VertexConsumer overlay(int u, int v) { - return this; - } - - @Nonnull - @Override - public VertexConsumer light(int u, int v) { - light = (v << 16) | u; // Compose lightmap coords into raw light value 0xVVVV_UUUU - return this; - } - - @Nonnull - @Override - public VertexConsumer normal(float x, float y, float z) { - nx = x; - ny = y; - nz = z; - return this; - } - - @Override - public void next() { - final ForgeDirection dir = DirectionUtil.fromVector((int) nx, (int) ny, (int) nz); - final int normal = dir != null ? dir.ordinal() : -1; - - // Write the current quad vertex's normal, position, UVs, color and raw light values - buffer.putInt(normal); - buffer.putFloat(x); - buffer.putFloat(y); - buffer.putFloat(z); - buffer.putFloat(u); - buffer.putFloat(v); - buffer.putInt(color); - buffer.putInt(light); - // We store 32 bytes per vertex - - resetCurrentVertex(); // Reset the current vertex values - currentVertex++; - } - - public void reset() { - buffer.rewind(); - currentVertex = 0; - Arrays.fill(sideCount, 0); - resetCurrentVertex(); - } - - public void flush(@Nonnull ChunkModelBuffers buffers) { - final int numQuads = currentVertex >> 2; - - for (int quadIdx = 0; quadIdx < numQuads; quadIdx++) { - final int normal = buffer.getInt((quadIdx << 2) << 5); - final ForgeDirection dir = normal != -1 ? DirectionUtil.ALL_DIRECTIONS[normal] : null; - final ModelQuadFacing facing = dir != null ? ModelQuadFacing.fromDirection(dir) : ModelQuadFacing.UNASSIGNED; - sideCount[facing.ordinal()]++; - } - - for (final ModelQuadFacing facing : ModelQuadFacing.VALUES) { - final int count = sideCount[facing.ordinal()]; - if (count == 0) { - continue; - } - buffers.getSink(facing).ensureCapacity(count << 2); - } - - final int byteSize = currentVertex << 5; - byte sideMask = 0; - - buffer.rewind(); - - while (buffer.position() < byteSize) { - final int normal = buffer.getInt(); // Fetch first normal for pre-selecting the vertex sink - final ForgeDirection dir = normal != -1 ? DirectionUtil.ALL_DIRECTIONS[normal] : null; - final ModelQuadFacing facing = dir != null ? ModelQuadFacing.fromDirection(dir) : ModelQuadFacing.UNASSIGNED; - final int facingIdx = facing.ordinal(); - - final ModelVertexSink sink = buffers.getSink(facing); - - writeQuadVertex(sink); - buffer.getInt(); - writeQuadVertex(sink); - buffer.getInt(); - writeQuadVertex(sink); - buffer.getInt(); - writeQuadVertex(sink); - - sideMask |= 1 << facingIdx; - } - - for (final ModelQuadFacing facing : ModelQuadFacing.VALUES) { - if (((sideMask >> facing.ordinal()) & 1) == 0) { - continue; - } - - buffers.getSink(facing).flush(); - } - } - - private void writeQuadVertex(@Nonnull ModelVertexSink sink) { - final float x = buffer.getFloat(); - final float y = buffer.getFloat(); - final float z = buffer.getFloat(); - final float u = buffer.getFloat(); - final float v = buffer.getFloat(); - final int color = buffer.getInt(); - final int light = buffer.getInt(); - - sink.writeQuad(x, y, z, color, u, v, light); - } - - private void resetCurrentVertex() { - x = y = z = 0F; - nx = ny = nz = 0F; - u = v = 0F; - color = 0xFFFF_FFFF; - light = 0; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java deleted file mode 100644 index 6f64f7bc6..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/buffer/ExtendedVertexFormat.java +++ /dev/null @@ -1,19 +0,0 @@ -package me.jellysquid.mods.sodium.client.buffer; - -import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement; - -public interface ExtendedVertexFormat { - Element[] embeddium$getExtendedElements(); - - class Element { - public final VertexFormatElement actual; - public final int increment; - public final int byteLength; - - public Element(VertexFormatElement actual, int increment, int byteLength) { - this.actual = actual; - this.increment = increment; - this.byteLength = byteLength; - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java b/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java index 31839f915..84c709f58 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.common.util; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraftforge.common.util.ForgeDirection; @@ -21,17 +20,4 @@ public class DirectionUtil { // Provides the same order as enumerating ForgeDirection and checking the axis of each value public static final ForgeDirection[] HORIZONTAL_DIRECTIONS = new ForgeDirection[] { ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST }; - private static final Long2ObjectMap VECTOR_TO_DIRECTION = (Long2ObjectMap) Arrays.stream(ALL_DIRECTIONS).collect(Collectors.toMap((arg) -> { - return (new BlockPos(arg.offsetX, arg.offsetY, arg.offsetZ)).asLong(); - }, (arg) -> { - return arg; - }, (arg, arg2) -> { - throw new IllegalArgumentException("Duplicate keys"); - }, Long2ObjectOpenHashMap::new)); - - @Nullable - public static ForgeDirection fromVector(int x, int y, int z) { - return (ForgeDirection)VECTOR_TO_DIRECTION.get(BlockPos.asLong(x, y, z)); - } - } From e8d6441503fcce11932ec2f93b5271eb2337175a Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:27:38 -0500 Subject: [PATCH 108/301] Massive code cleanup --- .../compat/forge/ForgeHooksClientExt.java | 20 --- .../early/sodium/MixinRenderGlobal.java | 10 +- .../light/cache/ArrayLightDataCache.java | 1 + .../client/render/SodiumWorldRenderer.java | 20 +-- .../render/chunk/ChunkRenderManager.java | 5 +- .../chunk/compile/ChunkBuildBuffers.java | 20 ++- .../render/chunk/compile/ChunkBuilder.java | 8 +- .../render/chunk/passes/BlockRenderPass.java | 24 +--- .../chunk/passes/BlockRenderPassManager.java | 55 ------- .../chunk/tasks/ChunkRenderRebuildTask.java | 77 ++-------- .../render/occlusion/BlockOcclusionCache.java | 136 ------------------ .../client/render/pipeline/BlockRenderer.java | 60 ++------ .../client/render/pipeline/FluidRenderer.java | 3 - .../context/ChunkRenderCacheLocal.java | 19 +-- .../context/ChunkRenderCacheShared.java | 4 +- .../mods/sodium/client/world/WorldSlice.java | 101 +++++-------- .../sodium/client/world/WorldSliceLocal.java | 97 ------------- .../world/cloned/ClonedChunkSection.java | 15 +- 18 files changed, 91 insertions(+), 584 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeHooksClientExt.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeHooksClientExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeHooksClientExt.java deleted file mode 100644 index 31732fe12..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/ForgeHooksClientExt.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.FluidState; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; - -public class ForgeHooksClientExt { - - static final ThreadLocal renderLayer = new ThreadLocal<>(); - - public static void setRenderLayer(RenderLayer layer) { - renderLayer.set(layer); - } - - public static TextureAtlasSprite[] getFluidSprites(BlockRenderView world, BlockPos pos, FluidState fluidState) { - return new TextureAtlasSprite[0]; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 0e8a83fa4..74f12785b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -7,6 +7,7 @@ import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.client.multiplayer.WorldClient; @@ -152,14 +153,7 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) try { MatrixStack matrixStack = new MatrixStack(); - final List renderLayers = switch(pass) { - case 0 -> ImmutableList.of(RenderLayer.cutoutMipped()); - case 1 -> ImmutableList.of(RenderLayer.translucent()); - default -> throw new IllegalStateException("Unexpected value: " + pass); - }; - for (RenderLayer renderLayer : renderLayers) { - this.renderer.drawChunkLayer(renderLayer, matrixStack, x, y, z); - } + this.renderer.drawChunkLayer(BlockRenderPass.VALUES[pass], matrixStack, x, y, z); } finally { RenderDevice.exitManagedCode(); this.mc.entityRenderer.disableLightmap(partialTicks); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java index 78d5b125b..429986e21 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; import me.jellysquid.mods.sodium.client.world.WorldSlice; +import net.minecraft.world.IBlockAccess; import java.util.Arrays; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index c23c6d514..2568a6caa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -1,20 +1,11 @@ package me.jellysquid.mods.sodium.client.render; -import com.gtnewhorizons.angelica.compat.mojang.BlockBreakingInfo; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BufferBuilderStorage; import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; -import com.gtnewhorizons.angelica.compat.mojang.ModelLoader; -import com.gtnewhorizons.angelica.compat.mojang.OverlayVertexConsumer; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumerProvider; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumers; import com.gtnewhorizons.angelica.glsm.GLStateManager; -import com.gtnewhorizons.angelica.mixins.early.sodium.MixinEntity; import com.gtnewhorizons.angelica.mixins.interfaces.IHasClientChunkProvider; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; @@ -32,7 +23,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; import me.jellysquid.mods.sodium.client.render.chunk.format.DefaultModelVertexFormats; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPassManager; import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheShared; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; @@ -54,10 +44,8 @@ import net.minecraft.util.MathHelper; import net.minecraftforge.client.MinecraftForgeClient; import org.joml.Vector3d; -import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap; import java.util.Set; -import java.util.SortedSet; /** * Provides an extension to vanilla's {@link WorldRenderer}. @@ -86,7 +74,6 @@ public class SodiumWorldRenderer implements ChunkStatusListener { @Getter private Frustrum frustum; private ChunkRenderManager chunkRenderManager; - private BlockRenderPassManager renderPassManager; private ChunkRenderBackend chunkRenderBackend; /** @@ -251,8 +238,7 @@ public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrust /** * Performs a render pass for the given {@link RenderLayer} and draws all visible chunks for it. */ - public void drawChunkLayer(RenderLayer renderLayer, MatrixStack matrixStack, double x, double y, double z) { - BlockRenderPass pass = this.renderPassManager.getRenderPassForLayer(renderLayer); + public void drawChunkLayer(BlockRenderPass pass, MatrixStack matrixStack, double x, double y, double z) { // startDrawing/endDrawing are handled by 1.7 already //pass.startDrawing(); @@ -286,8 +272,6 @@ private void initRenderer() { SodiumGameOptions opts = SodiumClientMod.options(); - this.renderPassManager = BlockRenderPassManager.createDefaultMappings(); - final ChunkVertexType vertexFormat; if (opts.advanced.useCompactVertexFormat) { @@ -299,7 +283,7 @@ private void initRenderer() { this.chunkRenderBackend = createChunkRenderBackend(device, opts, vertexFormat); this.chunkRenderBackend.createShaders(device); - this.chunkRenderManager = new ChunkRenderManager<>(this, this.chunkRenderBackend, this.renderPassManager, this.world, this.client.gameSettings.renderDistanceChunks); + this.chunkRenderManager = new ChunkRenderManager<>(this, this.chunkRenderBackend, this.world, this.client.gameSettings.renderDistanceChunks); this.chunkRenderManager.restoreChunks(this.loadedChunkPositions); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 408c3b7ac..a38d3e147 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -28,7 +28,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderList; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterator; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPassManager; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; import me.jellysquid.mods.sodium.common.util.DirectionUtil; @@ -109,13 +108,13 @@ public class ChunkRenderManager implements ChunkSt private boolean alwaysDeferChunkUpdates; - public ChunkRenderManager(SodiumWorldRenderer renderer, ChunkRenderBackend backend, BlockRenderPassManager renderPassManager, WorldClient world, int renderDistance) { + public ChunkRenderManager(SodiumWorldRenderer renderer, ChunkRenderBackend backend, WorldClient world, int renderDistance) { this.backend = backend; this.renderer = renderer; this.world = world; this.builder = new ChunkBuilder<>(backend.getVertexType(), this.backend); - this.builder.init(world, renderPassManager); + this.builder.init(world); this.dirty = true; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java index cce6b4c14..c3c206c7e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.buffer.VertexData; import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; @@ -14,7 +13,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkModelOffset; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; -import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPassManager; import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; @@ -30,25 +28,25 @@ public class ChunkBuildBuffers { private final VertexBufferBuilder[][] buffersByLayer; private final ChunkVertexType vertexType; - private final BlockRenderPassManager renderPassManager; private final ChunkModelOffset offset; - public ChunkBuildBuffers(ChunkVertexType vertexType, BlockRenderPassManager renderPassManager) { + private static final int EXPECTED_BUFFER_SIZE = 2097152; + + public ChunkBuildBuffers(ChunkVertexType vertexType) { this.vertexType = vertexType; - this.renderPassManager = renderPassManager; this.delegates = new ChunkModelBuffers[BlockRenderPass.COUNT]; this.buffersByLayer = new VertexBufferBuilder[BlockRenderPass.COUNT][ModelQuadFacing.COUNT]; this.offset = new ChunkModelOffset(); - for (RenderLayer layer : RenderLayer.getBlockLayers()) { - int passId = this.renderPassManager.getRenderPassId(layer); + for (BlockRenderPass pass : BlockRenderPass.VALUES) { + int passId = pass.ordinal(); VertexBufferBuilder[] buffers = this.buffersByLayer[passId]; for (ModelQuadFacing facing : ModelQuadFacing.VALUES) { - buffers[facing.ordinal()] = new VertexBufferBuilder(vertexType.getBufferVertexFormat(), layer.getExpectedBufferSize() / ModelQuadFacing.COUNT); + buffers[facing.ordinal()] = new VertexBufferBuilder(vertexType.getBufferVertexFormat(), EXPECTED_BUFFER_SIZE / ModelQuadFacing.COUNT); } } } @@ -66,11 +64,11 @@ public void init(ChunkRenderData.Builder renderData) { } /** - * Return the {@link ChunkModelVertexTransformer} for the given {@link RenderLayer} as mapped by the + * Return the {@link ChunkModelVertexTransformer} for the given {@link BlockRenderPass} as mapped by the * {@link BlockRenderPassManager} for this render context. */ - public ChunkModelBuffers get(RenderLayer layer) { - return this.delegates[this.renderPassManager.getRenderPassId(layer)]; + public ChunkModelBuffers get(BlockRenderPass pass) { + return this.delegates[pass.ordinal()]; } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java index 3ff9a6704..5e99fc6cc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java @@ -6,7 +6,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.passes.BlockRenderPassManager; 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; @@ -51,7 +50,6 @@ public class ChunkBuilder { private WorldClient world; private Vector3d cameraPosition = new Vector3d(); - private BlockRenderPassManager renderPassManager; private final int limitThreads; private final ChunkVertexType vertexType; @@ -87,7 +85,7 @@ public void startWorkers() { Minecraft client = Minecraft.getMinecraft(); for (int i = 0; i < this.limitThreads; i++) { - ChunkBuildBuffers buffers = new ChunkBuildBuffers(this.vertexType, this.renderPassManager); + ChunkBuildBuffers buffers = new ChunkBuildBuffers(this.vertexType); ChunkRenderCacheLocal pipeline = new ChunkRenderCacheLocal(client, this.world); WorkerRunnable worker = new WorkerRunnable(buffers, pipeline); @@ -206,9 +204,8 @@ public boolean isBuildQueueEmpty() { * a world teleportation event), the worker threads will first be stopped and all pending tasks will be discarded * before being started again. * @param world The world instance - * @param renderPassManager The render pass manager used for the world */ - public void init(WorldClient world, BlockRenderPassManager renderPassManager) { + public void init(WorldClient world) { if (world == null) { throw new NullPointerException("World is null"); } @@ -216,7 +213,6 @@ public void init(WorldClient world, BlockRenderPassManager renderPassManager) { this.stopWorkers(); this.world = world; - this.renderPassManager = renderPassManager; this.sectionCache = new ClonedChunkSectionCache(this.world); this.startWorkers(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java index 14bbeb93e..ca92580ed 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass.java @@ -1,35 +1,23 @@ package me.jellysquid.mods.sodium.client.render.chunk.passes; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; -// TODO: Move away from using an enum, make this extensible +/** + * The order of these enums must match the passes used by vanilla. + */ public enum BlockRenderPass { - SOLID(RenderLayer.solid(), false), - CUTOUT(RenderLayer.cutout(), false), - CUTOUT_MIPPED(RenderLayer.cutoutMipped(), false), - TRANSLUCENT(RenderLayer.translucent(), true), - TRIPWIRE(RenderLayer.tripwire(), true); + CUTOUT_MIPPED(false), + TRANSLUCENT(true); public static final BlockRenderPass[] VALUES = BlockRenderPass.values(); public static final int COUNT = VALUES.length; - private final RenderLayer layer; private final boolean translucent; - BlockRenderPass(RenderLayer layer, boolean translucent) { - this.layer = layer; + BlockRenderPass(boolean translucent) { this.translucent = translucent; } public boolean isTranslucent() { return this.translucent; } - - public void endDrawing() { - this.layer.endDrawing(); - } - - public void startDrawing() { - this.layer.startDrawing(); - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java deleted file mode 100644 index 8cbfc865c..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPassManager.java +++ /dev/null @@ -1,55 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.chunk.passes; - -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; -import it.unimi.dsi.fastutil.objects.Reference2IntArrayMap; - - -/** - * Maps vanilla render layers to render passes used by Sodium. This provides compatibility with the render layers already - * used by the base game. - */ -public class BlockRenderPassManager { - private final Reference2IntArrayMap mappingsId = new Reference2IntArrayMap<>(); - - public BlockRenderPassManager() { - this.mappingsId.defaultReturnValue(-1); - } - - public int getRenderPassId(RenderLayer layer) { - int pass = this.mappingsId.getInt(layer); - - if (pass < 0) { - throw new NullPointerException("No render pass exists for layer: " + layer); - } - - return pass; - } - - private void addMapping(RenderLayer layer, BlockRenderPass type) { - if (this.mappingsId.put(layer, type.ordinal()) >= 0) { - throw new IllegalArgumentException("Layer target already defined for " + layer); - } - } - - /** - * Creates a set of render pass mappings to vanilla render layers which closely mirrors the rendering - * behavior of vanilla. - */ - public static BlockRenderPassManager createDefaultMappings() { - BlockRenderPassManager mapper = new BlockRenderPassManager(); - mapper.addMapping(RenderLayer.solid(), BlockRenderPass.SOLID); - mapper.addMapping(RenderLayer.cutoutMipped(), BlockRenderPass.CUTOUT_MIPPED); - mapper.addMapping(RenderLayer.cutout(), BlockRenderPass.CUTOUT); - mapper.addMapping(RenderLayer.translucent(), BlockRenderPass.TRANSLUCENT); - mapper.addMapping(RenderLayer.tripwire(), BlockRenderPass.TRIPWIRE); - - return mapper; - } - public BlockRenderPass getRenderPassForLayer(RenderLayer layer) { - return this.getRenderPass(this.getRenderPassId(layer)); - } - - public BlockRenderPass getRenderPass(int i) { - return BlockRenderPass.VALUES[i]; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 358c89efe..a5abf5b78 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -1,13 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.tasks; -import com.gtnewhorizons.angelica.compat.forge.ForgeHooksClientExt; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderType; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionDataBuilder; -import com.gtnewhorizons.angelica.compat.mojang.FluidState; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayers; import com.gtnewhorizons.angelica.mixins.interfaces.IHasTessellator; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; @@ -28,11 +22,8 @@ import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; -import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; -import net.minecraft.util.MathHelper; -import net.minecraftforge.fluids.FluidRegistry; import org.joml.Vector3d; /** @@ -115,71 +106,25 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB for (int relZ = 0; relZ < 16; relZ++) { for (int relX = 0; relX < 16; relX++) { + Block block = slice.getBlockRelative(relX + 16, relY + 16, relZ + 16); + int meta = slice.getBlockMetadataRelative(relX + 16, relY + 16, relZ + 16); - BlockState blockState = slice.getBlockStateRelative(relX + 16, relY + 16, relZ + 16); - - // Can be replaced by slice.getBlockStateRelative if BlockState gets yeeted - Block block = blockState.getBlock(); - - boolean isFluid = FluidRegistry.lookupFluidForBlock(block) != null; - - // TODO: Sodium - BlockState - if (block == Blocks.air) { - continue; - } - - // TODO: commit this separately pos.set(baseX + relX, baseY + relY, baseZ + relZ); buffers.setRenderOffset(pos.x - renderOffset.getX(), pos.y - renderOffset.getY(), pos.z - renderOffset.getZ()); - // 1.7.10 has -1 (air, INVISIBLE), 0, (normal cubes), and 1+ (everything else) - // We don't actually use models, we have normal blocks and TEs - // TODO: use Sodium rendering for fluids - if (!block.hasTileEntity(blockState.getMetadata()) /*&& !isFluid*/) { - for (RenderLayer layer : RenderLayer.getBlockLayers()) { - - if (!RenderLayers.canRenderInLayer(block, layer)) { - continue; - } - - // Need an equivalent renderpass check - // if (!block.canRenderInPass(pass)) continue; - - ForgeHooksClientExt.setRenderLayer(layer); - -// IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); -// -// BakedModel model = cache.getBlockModels().getModel(blockState); -// - // This method calls block.getRenderingSeed, which just hashes the position - long seed = MathUtil.hashPos(pos.x, pos.y, pos.z); //blockState.getRenderingSeed(pos); + // Do regular block rendering + for(BlockRenderPass pass : BlockRenderPass.VALUES) { + if(block.canRenderInPass(pass.ordinal())) { + long seed = MathUtil.hashPos(pos.x, pos.y, pos.z); - if (cache.getBlockRenderer().renderModel(cache.getLocalSlice(), tessellator, renderBlocks, blockState, pos, buffers.get(layer), true, seed)) { - bounds.addBlock(relX, relY, relZ); - } - } - } - - - FluidState fluidState = blockState.getFluidState(); - - // TODO: use Sodium rendering for fluids - if (isFluid && false) { - for (RenderLayer layer : RenderLayer.getBlockLayers()) { - if (!RenderLayers.canRenderFluidInLayer(block, layer)) { - continue; + if (cache.getBlockRenderer().renderModel(cache.getWorldSlice(), tessellator, renderBlocks, block, meta, pos, buffers.get(pass), true, seed)) { + bounds.addBlock(relX, relY, relZ); } - - ForgeHooksClientExt.setRenderLayer(layer); - - if (cache.getFluidRenderer().render(cache.getLocalSlice(), fluidState, pos, buffers.get(layer))) { - bounds.addBlock(relX, relY, relZ); - } } } - if (blockState.hasTileEntity()) { - TileEntity entity = slice.getTileEntity(pos); + if (block.hasTileEntity(meta)) { + TileEntity entity = slice.getTileEntity(pos.x, pos.y, pos.z); final TileEntitySpecialRenderer renderer = TileEntityRendererDispatcher.instance.getSpecialRenderer(entity); if (entity != null && renderer != null) { @@ -195,8 +140,6 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB } } - ForgeHooksClientExt.setRenderLayer(null); - render.setRebuildForTranslucents(false); for (BlockRenderPass pass : BlockRenderPass.VALUES) { ChunkMeshData mesh = buffers.createMesh(pass, (float)camera.x - offset.getX(), (float)camera.y - offset.getY(), (float)camera.z - offset.getZ(), this.translucencySorting); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java b/src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java deleted file mode 100644 index 663c227dc..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/occlusion/BlockOcclusionCache.java +++ /dev/null @@ -1,136 +0,0 @@ -package me.jellysquid.mods.sodium.client.render.occlusion; - -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import com.gtnewhorizons.angelica.compat.mojang.BlockView; -import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; -import com.gtnewhorizons.angelica.compat.mojang.VoxelShapes; -import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap; -import net.minecraftforge.common.util.ForgeDirection; - -public class BlockOcclusionCache { - private static final byte UNCACHED_VALUE = (byte) 127; - - private final Object2ByteLinkedOpenHashMap map; - private final CachedOcclusionShapeTest cachedTest = new CachedOcclusionShapeTest(); - private final BlockPos.Mutable cpos = new BlockPos.Mutable(); - - public BlockOcclusionCache() { - this.map = new Object2ByteLinkedOpenHashMap<>(2048, 0.5F); - this.map.defaultReturnValue(UNCACHED_VALUE); - } - - /** - * @param selfState The state of the block in the world - * @param view The world view for this render context - * @param pos The position of the block - * @param facing The facing direction of the side to check - * @return True if the block side facing {@param dir} is not occluded, otherwise false - */ - public boolean shouldDrawSide(BlockState selfState, BlockView view, BlockPos pos, ForgeDirection facing) { - BlockPos.Mutable adjPos = this.cpos; - adjPos.set(pos.x + facing.offsetX, pos.y + facing.offsetY, pos.z + facing.offsetZ); - - BlockState adjState = view.getBlockState(adjPos); - - if (selfState.isSideInvisible(adjState, facing)) { - return false; - } else if (adjState.isOpaque()) { - VoxelShape selfShape = selfState.getCullingFace(view, pos, facing); - VoxelShape adjShape = adjState.getCullingFace(view, adjPos, facing.getOpposite()); - - if (selfShape == VoxelShapes.fullCube() && adjShape == VoxelShapes.fullCube()) { - return false; - } - - if (selfShape.isEmpty()) { - // Upstream Sodium only returns true under stricter conditions than this, in order to cull faces in - // unusual block arrangements like a potted cacti under a solid block. - // However, that fix has the side effect of causing block models with improperly specified cullfaces - // to not render sometimes, and also breaks powder snow culling on 1.17+. - // It's not clear that the stricter check provides a significant performance uplift, so we err - // on the side of compatibility and use the same weaker check as vanilla. - return true; - /* - if (adjShape.isEmpty()){ - return true; //example: top face of potted plants if top slab is placed above - } - else if (!adjState.isSideSolid(view,adjPos,facing.getOpposite(), SideShapeType.FULL)){ - return true; //example: face of potted plants rendered if top stair placed above - } - */ - } - - return this.calculate(selfShape, adjShape); - } else { - return true; - } - } - - private boolean calculate(VoxelShape selfShape, VoxelShape adjShape) { - CachedOcclusionShapeTest cache = this.cachedTest; - cache.a = selfShape; - cache.b = adjShape; - cache.updateHash(); - - byte cached = this.map.getByte(cache); - - if (cached != UNCACHED_VALUE) { - return cached == 1; - } - - // TODO: Sodium - boolean ret = VoxelShapes.matchesAnywhere(selfShape, adjShape, null /*BooleanBiFunction.ONLY_FIRST*/); - - this.map.put(cache.copy(), (byte) (ret ? 1 : 0)); - - if (this.map.size() > 2048) { - this.map.removeLastByte(); - } - - return ret; - } - - private static final class CachedOcclusionShapeTest { - private VoxelShape a, b; - private int hashCode; - - private CachedOcclusionShapeTest() { - - } - - private CachedOcclusionShapeTest(VoxelShape a, VoxelShape b, int hashCode) { - this.a = a; - this.b = b; - this.hashCode = hashCode; - } - - public void updateHash() { - int result = System.identityHashCode(this.a); - result = 31 * result + System.identityHashCode(this.b); - - this.hashCode = result; - } - - public CachedOcclusionShapeTest copy() { - return new CachedOcclusionShapeTest(this.a, this.b, this.hashCode); - } - - @Override - public boolean equals(Object o) { - if (o instanceof CachedOcclusionShapeTest) { - CachedOcclusionShapeTest that = (CachedOcclusionShapeTest) o; - - return this.a == that.a && - this.b == that.b; - } - - return false; - } - - @Override - public int hashCode() { - return this.hashCode; - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index c48f1123f..f69af446b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -2,7 +2,6 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.compat.nd.Quad; import com.gtnewhorizons.angelica.compat.nd.RecyclingList; @@ -16,7 +15,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; -import me.jellysquid.mods.sodium.client.render.occlusion.BlockOcclusionCache; import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; @@ -25,7 +23,7 @@ import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraftforge.common.util.ForgeDirection; +import net.minecraft.world.IBlockAccess; import org.joml.Vector3d; import org.lwjgl.opengl.GL11; @@ -38,31 +36,19 @@ public class BlockRenderer { private final Random random = new XoRoShiRoRandom(); - private final BlockOcclusionCache occlusionCache; - private final QuadLightData cachedQuadLightData = new QuadLightData(); - private final LightPipelineProvider lighters; - private final boolean useAmbientOcclusion; private final Flags FLAGS = new Flags(true, true, true, false); private final RecyclingList quadBuf = new RecyclingList<>(Quad::new); - public BlockRenderer(Minecraft client, LightPipelineProvider lighters) { - this.lighters = lighters; - - this.occlusionCache = new BlockOcclusionCache(); + public BlockRenderer(Minecraft client) { // TODO: Sodium - AO Setting this.useAmbientOcclusion = Minecraft.getMinecraft().gameSettings.ambientOcclusion > 0; } - public boolean renderModel(BlockRenderView world, Tessellator tessellator, RenderBlocks renderBlocks, BlockState state, BlockPos pos, ChunkModelBuffers buffers, boolean cull, long seed) { - - final Block block = state.getBlock(); - final LightMode mode = this.getLightingMode(state, world, pos); - final LightPipeline lighter = this.lighters.getLighter(mode); - Vector3d offset = state.getModelOffset(world, pos); + public boolean renderModel(IBlockAccess world, Tessellator tessellator, RenderBlocks renderBlocks, Block block, int meta, BlockPos pos, ChunkModelBuffers buffers, boolean cull, long seed) { boolean rendered = false; @@ -92,7 +78,7 @@ public boolean renderModel(BlockRenderView world, Tessellator tessellator, Rende final List all = tesselatorToBakedQuadList(tessellator, pos); for(ModelQuadFacing facing : ModelQuadFacing.VALUES) { - this.renderQuadList(world, state, pos, lighter, offset, buffers, all, facing); + this.renderQuadList(pos, buffers, all, facing); } if(!all.isEmpty()) @@ -162,7 +148,7 @@ private List tesselatorToBakedQuadList(Tessellator t, BlockPos pos) { return quads; } - private void renderQuadList(BlockRenderView world, BlockState state, BlockPos pos, LightPipeline lighter, Vector3d offset, + private void renderQuadList(BlockPos pos, ChunkModelBuffers buffers, List quads, ModelQuadFacing facing) { ModelVertexSink sink = buffers.getSink(facing); @@ -178,20 +164,17 @@ private void renderQuadList(BlockRenderView world, BlockState state, BlockPos po if(quad.normal != facing) continue; - QuadLightData light = this.cachedQuadLightData; - // TODO: maybe make non-null? - lighter.calculate(quad, pos, light, null, quad.getFace(), quad.hasShade()); - - this.renderQuad(world, state, pos, sink, offset, quad, light, renderData); + this.renderQuad(sink, quad, renderData); } sink.flush(); } - private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, ModelVertexSink sink, Vector3d offset, - Quad quad, QuadLightData light, ChunkRenderData.Builder renderData) { + private void renderQuad(ModelVertexSink sink, + Quad quad, ChunkRenderData.Builder renderData) { - ModelQuadOrientation order = ModelQuadOrientation.orient(light.br); + // TODO reorder using packed light + ModelQuadOrientation order = ModelQuadOrientation.NORMAL; int[] colors = null; @@ -202,16 +185,16 @@ private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, M for (int dstIndex = 0; dstIndex < 4; dstIndex++) { int srcIndex = order.getVertexIndex(dstIndex); - float x = quad.getX(srcIndex) + (float) offset.x; - float y = quad.getY(srcIndex) + (float) offset.y; - float z = quad.getZ(srcIndex) + (float) offset.z; + float x = quad.getX(srcIndex); + float y = quad.getY(srcIndex); + float z = quad.getZ(srcIndex); - int color = ColorABGR.mul(colors != null ? colors[srcIndex] : quad.getColor(srcIndex), light.br[srcIndex]); + int color = quad.getColor(srcIndex); float u = quad.getTexU(srcIndex); float v = quad.getTexV(srcIndex); - int lm = ModelQuadUtil.mergeBakedLight(quad.getLight(srcIndex), light.lm[srcIndex]); + int lm = quad.getLight(srcIndex); sink.writeQuad(x, y, z, color, u, v, lm); } @@ -223,19 +206,6 @@ private void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, M } } - private LightMode getLightingMode(BlockState state, BlockRenderView world, BlockPos pos) { - return getLightingMode(state.getBlock(), world, pos); - } - - private LightMode getLightingMode(Block block, BlockRenderView world, BlockPos pos) { - // TODO: Sodium: Ambient Occlusion - if (this.useAmbientOcclusion && /* model.isAmbientOcclusion(state) &&*/ block.getLightValue() == 0) { - return LightMode.SMOOTH; - } else { - return LightMode.FLAT; - } - } - public static class Flags { boolean hasTexture; public boolean hasBrightness; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java index 68533567d..332004846 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.render.pipeline; -import com.gtnewhorizons.angelica.compat.forge.ForgeHooksClientExt; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; @@ -30,8 +29,6 @@ import net.minecraftforge.fluids.Fluid; import org.joml.Vector3d; -import java.util.Objects; - import static org.joml.Math.lerp; public class FluidRenderer { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java index a5173ec49..b5246a2b8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java @@ -7,29 +7,22 @@ import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; import me.jellysquid.mods.sodium.client.render.pipeline.FluidRenderer; import me.jellysquid.mods.sodium.client.world.WorldSlice; -import me.jellysquid.mods.sodium.client.world.WorldSliceLocal; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; public class ChunkRenderCacheLocal extends ChunkRenderCache { - private final ArrayLightDataCache lightDataCache; - private final BlockRenderer blockRenderer; private final FluidRenderer fluidRenderer; private final BlockModels blockModels; private final WorldSlice worldSlice; - private WorldSliceLocal localSlice; public ChunkRenderCacheLocal(Minecraft client, WorldClient world) { this.worldSlice = new WorldSlice(world); - this.lightDataCache = new ArrayLightDataCache(this.worldSlice); - - LightPipelineProvider lightPipelineProvider = new LightPipelineProvider(this.lightDataCache); - this.blockRenderer = new BlockRenderer(client, lightPipelineProvider); - this.fluidRenderer = new FluidRenderer(client, lightPipelineProvider); + this.blockRenderer = new BlockRenderer(client); + this.fluidRenderer = new FluidRenderer(client, null); // TODO: Sodium this.blockModels = null; // client.getBakedModelManager().getBlockModels(); @@ -48,18 +41,10 @@ public FluidRenderer getFluidRenderer() { } public void init(ChunkRenderContext context) { - this.lightDataCache.reset(context.getOrigin()); this.worldSlice.copyData(context); - // create the new local slice here so that it's unique whenever we copy new data - // this is passed into mod code, since some depend on the provided BlockRenderView object being unique each time - this.localSlice = new WorldSliceLocal(this.worldSlice); } public WorldSlice getWorldSlice() { return this.worldSlice; } - - public WorldSliceLocal getLocalSlice() { - return this.localSlice; - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java index 88dafe515..ed6447236 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java @@ -23,9 +23,7 @@ private ChunkRenderCacheShared(WorldClient world) { this.lightCache = new HashLightDataCache((BlockRenderView)world); - LightPipelineProvider lightPipelineProvider = new LightPipelineProvider(this.lightCache); - - this.blockRenderer = new BlockRenderer(client, lightPipelineProvider); + this.blockRenderer = new BlockRenderer(client); } public BlockRenderer getBlockRenderer() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index fcad721ab..4ce4f920c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -35,7 +35,7 @@ * * Object pooling should be used to avoid huge allocations as this class contains many large arrays. */ -public class WorldSlice implements BlockRenderView, IBlockAccess { +public class WorldSlice implements IBlockAccess { // The number of blocks on each axis in a section. private static final int SECTION_BLOCK_LENGTH = 16; @@ -65,7 +65,8 @@ public class WorldSlice implements BlockRenderView, IBlockAccess { private final WorldClient world; // Local Section->BlockState table. - private final BlockState[][] blockStatesArrays; + private final Block[][] blockArrays; + private final int[][] metadataArrays; // Local section copies. Read-only. private ClonedChunkSection[] sections; @@ -127,14 +128,16 @@ public WorldSlice(WorldClient world) { this.worldHeight = world.getHeight(); this.sections = new ClonedChunkSection[SECTION_TABLE_ARRAY_SIZE]; - this.blockStatesArrays = new BlockState[SECTION_TABLE_ARRAY_SIZE][]; + this.blockArrays = new Block[SECTION_TABLE_ARRAY_SIZE][]; + this.metadataArrays = new int[SECTION_TABLE_ARRAY_SIZE][]; this.biomeData = new byte[SECTION_TABLE_ARRAY_SIZE][]; for (int x = 0; x < SECTION_LENGTH; x++) { for (int y = 0; y < SECTION_LENGTH; y++) { for (int z = 0; z < SECTION_LENGTH; z++) { final int i = getLocalSectionIndex(x, y, z); - this.blockStatesArrays[i] = new BlockState[SECTION_BLOCK_COUNT]; + this.blockArrays[i] = new Block[SECTION_BLOCK_COUNT]; + this.metadataArrays[i] = new int[SECTION_BLOCK_COUNT]; } } } @@ -154,19 +157,13 @@ public void copyData(ChunkRenderContext context) { for (int z = 0; z < SECTION_LENGTH; z++) { final int idx = getLocalSectionIndex(x, y, z); - this.unpackBlockData(this.blockStatesArrays[idx], this.sections[idx], context.getVolume()); + this.unpackBlockData(this.blockArrays[idx], this.metadataArrays[idx], this.sections[idx], context.getVolume()); this.biomeData[idx] = this.sections[idx].getBiomeData(); } } } } - @Override - public Block getBlock(int x, int y, int z) { - return this.getBlockState(x, y, z).getBlock(); - } - - @Override public int getLightBrightnessForSkyBlocks(int x, int y, int z, int min) { int skyBrightness = this.getSkyBlockTypeBrightness(net.minecraft.world.EnumSkyBlock.Sky, x, y, z); @@ -201,11 +198,6 @@ public int getSkyBlockTypeBrightness(EnumSkyBlock skyBlock, int x, int y, int z) return this.getLightLevel(skyBlock, x, y, z); } - @Override - public int getBlockMetadata(int x, int y, int z) { - return this.getBlockState(x, y, z).getMetadata(); - } - @Override public int isBlockProvidingPowerTo(int x, int y, int z, int directionIn) { return this.getBlock(x, y, z).isProvidingStrongPower(this, x, y, z, directionIn); @@ -224,7 +216,9 @@ public BiomeGenBase getBiomeGenForCoords(int x, int z) { final int k = this.biomeData[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] [(x & 15) | (z & 15) << 4] & 255; - return BiomeGenBase.getBiome(k); + BiomeGenBase biome = BiomeGenBase.getBiome(k); + // can be null if biome wasn't generated yet + return biome == null ? BiomeGenBase.plains : biome; } @Override @@ -242,28 +236,28 @@ public boolean isSideSolid(int x, int y, int z, ForgeDirection side, boolean _de return getBlock(x, y, z).isSideSolid(this, x, y, z, side); } - private void unpackBlockData(BlockState[] states, ClonedChunkSection section, StructureBoundingBox box) { + private void unpackBlockData(Block[] blocks, int[] metas, ClonedChunkSection section, StructureBoundingBox box) { if (this.origin.equals(section.getPosition())) { - this.unpackBlockDataZ(states, section); + this.unpackBlockDataZ(blocks, metas, section); } else { - this.unpackBlockDataR(states, section, box); + this.unpackBlockDataR(blocks, metas, section, box); } } - private static void copyBlocks(BlockState[] states, ClonedChunkSection section, int minBlockY, int maxBlockY, int minBlockZ, int maxBlockZ, int minBlockX, int maxBlockX) { + private static void copyBlocks(Block[] blocks, int[] metas, ClonedChunkSection section, int minBlockY, int maxBlockY, int minBlockZ, int maxBlockZ, int minBlockX, int maxBlockX) { for (int y = minBlockY; y <= maxBlockY; y++) { for (int z = minBlockZ; z <= maxBlockZ; z++) { for (int x = minBlockX; x <= maxBlockX; x++) { final int blockIdx = getLocalBlockIndex(x & 15, y & 15, z & 15); - // TODO: Optimize Allocations - shared block states? get rid of block states? - states[blockIdx] = section.getBlockState(x & 15, y & 15, z & 15); + blocks[blockIdx] = section.getBlock(x & 15, y & 15, z & 15); + metas[blockIdx] = section.getBlockMetadata(x & 15, y & 15, z & 15); } } } } - private void unpackBlockDataR(BlockState[] states, ClonedChunkSection section, StructureBoundingBox box) { + private void unpackBlockDataR(Block[] blocks, int metas[], ClonedChunkSection section, StructureBoundingBox box) { ChunkSectionPos pos = section.getPosition(); int minBlockX = Math.max(box.minX, pos.getMinX()); @@ -275,10 +269,10 @@ private void unpackBlockDataR(BlockState[] states, ClonedChunkSection section, S int minBlockZ = Math.max(box.minZ, pos.getMinZ()); int maxBlockZ = Math.min(box.maxZ, pos.getMaxZ()); - copyBlocks(states, section, minBlockY, maxBlockY, minBlockZ, maxBlockZ, minBlockX, maxBlockX); + copyBlocks(blocks, metas, section, minBlockY, maxBlockY, minBlockZ, maxBlockZ, minBlockX, maxBlockX); } - private void unpackBlockDataZ(BlockState[] states, ClonedChunkSection section) { + private void unpackBlockDataZ(Block[] blocks, int[] metas, ClonedChunkSection section) { // TODO: Look into a faster copy for this? final ChunkSectionPos pos = section.getPosition(); @@ -292,58 +286,32 @@ private void unpackBlockDataZ(BlockState[] states, ClonedChunkSection section) { int maxBlockZ = pos.getMaxZ(); // TODO: Can this be optimized? - copyBlocks(states, section, minBlockY, maxBlockY, minBlockZ, maxBlockZ, minBlockX, maxBlockX); - } - - /** - * Helper function to ensure a valid BlockState is always returned (air is returned - * in place of null). - */ - private static BlockState nullableState(BlockState state) { - return state != null ? state : ClonedChunkSection.DEFAULT_BLOCK_STATE; - } - - @Override - public BlockState getBlockState(BlockPos pos) { - return this.getBlockState(pos.x, pos.y, pos.z); + copyBlocks(blocks, metas, section, minBlockY, maxBlockY, minBlockZ, maxBlockZ, minBlockX, maxBlockX); } - public BlockState getBlockState(int x, int y, int z) { + public Block getBlock(int x, int y, int z) { int relX = x - this.baseX; int relY = y - this.baseY; int relZ = z - this.baseZ; - return nullableState(this.blockStatesArrays[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)][getLocalBlockIndex(relX & 15, relY & 15, relZ & 15)]); + return this.blockArrays[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)][getLocalBlockIndex(relX & 15, relY & 15, relZ & 15)]; } - public BlockState getBlockStateRelative(int x, int y, int z) { - return nullableState(this.blockStatesArrays[getLocalSectionIndex(x >> 4, y >> 4, z >> 4)][getLocalBlockIndex(x & 15, y & 15, z & 15)]); + public Block getBlockRelative(int x, int y, int z) { + return this.blockArrays[getLocalSectionIndex(x >> 4, y >> 4, z >> 4)][getLocalBlockIndex(x & 15, y & 15, z & 15)]; } - @Override - public FluidState getFluidState(BlockPos pos) { - return this.getBlockState(pos).getFluidState(); + public int getBlockMetadataRelative(int x, int y, int z) { + return this.metadataArrays[getLocalSectionIndex(x >> 4, y >> 4, z >> 4)][getLocalBlockIndex(x & 15, y & 15, z & 15)]; } @Override - public float getBrightness(ForgeDirection direction, boolean shaded) { - boolean darkened = false; //this.getSkyProperties().isDarkened(); - if (!shaded) { - return darkened ? 0.9f : 1.0f; - } - return switch (direction) { - case DOWN -> darkened ? 0.9f : 0.5f; - case UP -> darkened ? 0.9f : 1.0f; - case NORTH, SOUTH -> 0.8f; - case WEST, EAST -> 0.6f; - default -> 1.0f; - }; - } - + public int getBlockMetadata(int x, int y, int z) { + int relX = x - this.baseX; + int relY = y - this.baseY; + int relZ = z - this.baseZ; - @Override - public TileEntity getTileEntity(BlockPos pos) { - return this.getTileEntity(pos.x, pos.y, pos.z); + return this.metadataArrays[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)][getLocalBlockIndex(relX & 15, relY & 15, relZ & 15)]; } @Override @@ -355,11 +323,6 @@ public TileEntity getTileEntity(int x, int y, int z) { return this.sections[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)].getBlockEntity(relX & 15, relY & 15, relZ & 15); } - @Override - public int getLightLevel(EnumSkyBlock type, BlockPos pos) { - return getLightLevel(type, pos.x, pos.y, pos.z); - } - public int getLightLevel(EnumSkyBlock type, int x, int y, int z) { y = MathHelper.clamp_int(y, 0, 255); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java deleted file mode 100644 index 3b9b651a9..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSliceLocal.java +++ /dev/null @@ -1,97 +0,0 @@ -package me.jellysquid.mods.sodium.client.world; - -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import com.gtnewhorizons.angelica.compat.mojang.FluidState; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.world.EnumSkyBlock; -import net.minecraftforge.common.util.ForgeDirection; - -import javax.annotation.Nullable; - -/** - * Wrapper object used to defeat identity comparisons in mods. Since vanilla provides a unique object to them for each - * subchunk, we do the same. - */ -public class WorldSliceLocal implements BlockRenderView { - private final BlockRenderView view; - - public WorldSliceLocal(BlockRenderView view) { - this.view = view; - } - - @Override - public float getBrightness(ForgeDirection direction, boolean shaded) { - return view.getBrightness(direction, shaded); - } - - @Override - public int getLightLevel(EnumSkyBlock type, BlockPos pos) { - return view.getLightLevel(type, pos); - } - - @Override - @Nullable - public TileEntity getTileEntity(BlockPos pos) { - return view.getTileEntity(pos); - } - - @Override - public BlockState getBlockState(BlockPos pos) { - return view.getBlockState(pos); - } - - @Override - public FluidState getFluidState(BlockPos pos) { - return view.getFluidState(pos); - } - -// @Override - public int getLuminance(BlockPos pos) { - return 0; -// return view.getLuminance(pos); - } - -// @Override - public int getMaxLightLevel() { - return 15; -// return view.getMaxLightLevel(); - } - -// @Override - public int getHeight() { - return 255; -// return view.getHeight(); - } - -// @Override -// public Stream method_29546(Box arg) { -// return view.method_29546(arg); -// } -// -// @Override -// public BlockHitResult raycast(RaycastContext context) { -// return view.raycast(context); -// } -// -// @Override -// @Nullable -// public BlockHitResult raycastBlock(Vector3d start, Vector3d end, BlockPos pos, VoxelShape shape, BlockState state) { -// return view.raycastBlock(start, end, pos, shape, state); -// } -// -// @Override -// public double getDismountHeight(VoxelShape blockCollisionShape, Supplier belowBlockCollisionShapeGetter) { -// return view.getDismountHeight(blockCollisionShape, belowBlockCollisionShapeGetter); -// } -// -// @Override -// public double getDismountHeight(BlockPos pos) { -// return view.getDismountHeight(pos); -// } -// -// public static T raycast(RaycastContext arg, BiFunction context, Function blockRaycaster) { -// return BlockView.raycast(arg, context, blockRaycaster); -// } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 679215928..b84732844 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -2,7 +2,6 @@ import com.gtnewhorizons.angelica.compat.ExtendedBlockStorageExt; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import com.gtnewhorizons.angelica.mixins.interfaces.IExtendedBlockStorageExt; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; @@ -25,7 +24,6 @@ import java.util.concurrent.atomic.AtomicInteger; public class ClonedChunkSection { - public static final BlockState DEFAULT_BLOCK_STATE = new BlockState(Blocks.air, 0); private static final EnumSkyBlock[] LIGHT_TYPES = EnumSkyBlock.values(); private static final ExtendedBlockStorage EMPTY_SECTION = new ExtendedBlockStorage(0, false); @@ -94,13 +92,14 @@ public void init(ChunkSectionPos pos) { } } - public BlockState getBlockState(int x, int y, int z) { - final Block block = data.getBlockByExtId(x, y, z); - if(block.isAir(null, 0, 0, 0)) /* dumb api */ { - return DEFAULT_BLOCK_STATE; - } - return new BlockState(data.getBlockByExtId(x, y, z), data.getExtBlockMetadata(x, y, z)); + public Block getBlock(int x, int y, int z) { + return data.getBlockByExtId(x, y, z); + } + + public int getBlockMetadata(int x, int y, int z) { + return data.getExtBlockMetadata(x, y, z); } + public int getLightLevel(EnumSkyBlock type, int x, int y, int z) { if(type == EnumSkyBlock.Sky) { if(world.provider.hasNoSky) From 0625f15c8aace7ca6e30e9bc84f73b71b0dbde31 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:23:54 -0500 Subject: [PATCH 109/301] Fix BS + AbstractMethodError (#18) --- build.gradle | 2 +- dependencies.gradle | 12 ++++----- gradle.properties | 4 +-- .../compat/ExtendedBlockStorageExt.java | 12 ++++----- .../sodium/MixinExtendedBlockStorage.java | 26 ++++++------------- .../interfaces/IExtendedBlockStorageExt.java | 18 ------------- .../world/cloned/ClonedChunkSection.java | 8 ++---- 7 files changed, 25 insertions(+), 57 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IExtendedBlockStorageExt.java diff --git a/build.gradle b/build.gradle index 16efd2fbd..80f4b8ba5 100644 --- a/build.gradle +++ b/build.gradle @@ -302,7 +302,7 @@ if (apiPackage) { } if (accessTransformersFile) { - for (atFile in accessTransformersFile.split(",")) { + for (atFile in accessTransformersFile.split(" ")) { String targetFile = "src/main/resources/META-INF/" + atFile.trim() if (!getFile(targetFile).exists()) { throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile) diff --git a/dependencies.gradle b/dependencies.gradle index f37662745..0b13e5e00 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -41,11 +41,11 @@ dependencies { api("com.github.GTNewHorizons:Hodgepodge:2.3.32") // Iris Shaders - implementation('org.jetbrains:annotations:24.0.1') - implementation("it.unimi.dsi:fastutil:8.2.1") - implementation("org.joml:joml:1.10.5") - implementation("org.anarres:jcpp:1.4.14") - implementation("io.github.douira:glsl-transformer:1.0.0") + shadowImplementation('org.jetbrains:annotations:24.0.1') // Apache 2.0 + shadowImplementation("it.unimi.dsi:fastutil:8.2.1") // Apache 2.0 + shadowImplementation("org.joml:joml:1.10.5") // MIT + shadowImplementation("org.anarres:jcpp:1.4.14") // Apache 2.0 + shadowImplementation("io.github.douira:glsl-transformer:1.0.0") // glsl-transformer Noncommercial License 1.0.0 compileOnly "org.apache.ant:ant:1.8.2" @@ -63,7 +63,7 @@ dependencies { // ArchaicFix Deps - implementation("com.github.Speiger:Primitive-Collections:0.9.0") + shadowImplementation("com.github.Speiger:Primitive-Collections:0.9.0") // Apache 2.0 compileOnly("codechicken:ChickenChunks:1.7.10-1.3.4.19:dev") compileOnly "thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev" compileOnly('curse.maven:cofh-core-69162:2388751') diff --git a/gradle.properties b/gradle.properties index a8c90c187..0a4da1cc3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -62,7 +62,7 @@ apiPackage = # Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/ # There can be multiple files in a comma-separated list. # Example value: mymodid_at.cfg,nei_at.cfg -accessTransformersFile = angelica_at.cfg,notfine_at.cfg,archaicfix_at.cfg +accessTransformersFile = angelica_at.cfg notfine_at.cfg archaicfix_at.cfg # Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! usesMixins = true @@ -85,7 +85,7 @@ forceEnableMixins = false # If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your # responsibility check the licence and request permission for distribution, if required. -usesShadowedDependencies = false +usesShadowedDependencies = true # If disabled, won't remove unused classes from shaded dependencies. Some libraries use reflection to access # their own classes, making the minimization unreliable. minimizeShadowedDependencies = true diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java index 8458e4e66..99129cf2d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java @@ -1,7 +1,7 @@ package com.gtnewhorizons.angelica.compat; +import com.gtnewhorizons.angelica.mixins.early.sodium.MixinExtendedBlockStorage; import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedNibbleArray; -import com.gtnewhorizons.angelica.mixins.interfaces.IExtendedBlockStorageExt; import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; @@ -13,8 +13,8 @@ public ExtendedBlockStorageExt(int yBase, boolean hasSky) { this.hasSky = hasSky; } - public ExtendedBlockStorageExt(IExtendedBlockStorageExt storage) { - super(storage.getYBase(), storage.hasSky()); + public ExtendedBlockStorageExt(ExtendedBlockStorage storage) { + super(((MixinExtendedBlockStorage) storage).getYBase(), storage.getSkylightArray() != null); final byte[] blockLSBArray = this.getBlockLSBArray(); @@ -32,13 +32,13 @@ public ExtendedBlockStorageExt(IExtendedBlockStorageExt storage) { } copyNibbleArray((ExtendedNibbleArray) storage.getSkylightArray(), (ExtendedNibbleArray) this.getSkylightArray()); } - ((IExtendedBlockStorageExt)this).setBlockRefCount(storage.getBlockRefCount()); + ((MixinExtendedBlockStorage) this).setBlockRefCount(((MixinExtendedBlockStorage) storage).getBlockRefCount()); } private static void copyNibbleArray(ExtendedNibbleArray srcArray, ExtendedNibbleArray dstArray) { - if(srcArray == null || dstArray == null) { - throw new RuntimeException("NibbleArray is null src: " + (srcArray==null) + " dst: " + (dstArray==null)); + if (srcArray == null || dstArray == null) { + throw new RuntimeException("NibbleArray is null src: " + (srcArray == null) + " dst: " + (dstArray == null)); } final byte[] data = srcArray.getData(); System.arraycopy(data, 0, dstArray.getData(), 0, data.length); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java index a305f2748..e444e7843 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinExtendedBlockStorage.java @@ -1,26 +1,16 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; -import com.gtnewhorizons.angelica.mixins.interfaces.IExtendedBlockStorageExt; -import lombok.Getter; -import lombok.Setter; -import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(ExtendedBlockStorage.class) -public abstract class MixinExtendedBlockStorage implements IExtendedBlockStorageExt { - @Shadow public abstract NibbleArray getSkylightArray(); - @Shadow public abstract NibbleArray getBlocklightArray(); - @Shadow public abstract NibbleArray getMetadataArray(); - @Shadow public abstract byte[] getBlockLSBArray(); +public interface MixinExtendedBlockStorage { - @Getter @Shadow private int yBase; - @Getter @Setter @Shadow private int blockRefCount; - @Getter @Setter @Shadow private int tickRefCount; - - @Override - public boolean hasSky() { - return getSkylightArray() != null; - } + @Accessor("yBase") + int getYBase(); + @Accessor("blockRefCount") + int getBlockRefCount(); + @Accessor("blockRefCount") + void setBlockRefCount(int blockRefCount); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IExtendedBlockStorageExt.java deleted file mode 100644 index 58ae8231f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IExtendedBlockStorageExt.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.interfaces; - -import net.minecraft.world.chunk.NibbleArray; - -public interface IExtendedBlockStorageExt { - byte[] getBlockLSBArray(); - NibbleArray getBlockMSBArray(); - NibbleArray getMetadataArray(); - NibbleArray getBlocklightArray(); - NibbleArray getSkylightArray(); - int getYBase(); - - boolean hasSky(); - - int getBlockRefCount(); - void setBlockRefCount(int blockRefCount); - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index b84732844..98b4dafba 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -3,15 +3,12 @@ import com.gtnewhorizons.angelica.compat.ExtendedBlockStorageExt; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; -import com.gtnewhorizons.angelica.mixins.interfaces.IExtendedBlockStorageExt; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import lombok.Getter; import net.minecraft.block.Block; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; -import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; -import net.minecraft.world.ChunkPosition; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; @@ -20,7 +17,6 @@ import net.minecraft.world.gen.structure.StructureBoundingBox; import java.util.Arrays; -import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; public class ClonedChunkSection { @@ -55,10 +51,10 @@ public void init(ChunkSectionPos pos) { throw new RuntimeException("Couldn't retrieve chunk at " + pos.toChunkPos()); } - IExtendedBlockStorageExt section = (IExtendedBlockStorageExt)getChunkSection(chunk, pos); + ExtendedBlockStorage section = getChunkSection(chunk, pos); if (section == null /*WorldChunk.EMPTY_SECTION*/ /*ChunkSection.isEmpty(section)*/) { - section = (IExtendedBlockStorageExt)EMPTY_SECTION; + section = EMPTY_SECTION; } this.pos = pos; From 761ef3a44c0e8b53810f87388f16677a06ac9b3f Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 24 Nov 2023 08:32:33 -0800 Subject: [PATCH 110/301] Add back flip check * Avoids errors when usin lwjglxdebug --- .../backends/multidraw/IndirectCommandBufferVector.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java index 66ac725de..37cf45484 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/IndirectCommandBufferVector.java @@ -1,9 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; -import org.lwjgl.BufferUtils; - -import java.nio.ByteBuffer; public class IndirectCommandBufferVector extends StructBuffer { protected IndirectCommandBufferVector(int capacity) { @@ -19,7 +16,9 @@ public void begin() { } public void end() { - this.buffer.flip(); + if(this.buffer.position() > 0) { + this.buffer.flip(); + } } public void pushCommandBuffer(ChunkDrawCallBatcher batcher) { From 0b2a1c1f25cc4314e13983d79389d118b2dccc0d Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 24 Nov 2023 08:32:56 -0800 Subject: [PATCH 111/301] Bump hodgepodge dep --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 0b13e5e00..d3e99b7f1 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -38,7 +38,7 @@ dependencies { compileOnly(sourceSets.compileStubs.output) compileStubs(sourceSets.compileStubsStubs.output) - api("com.github.GTNewHorizons:Hodgepodge:2.3.32") + api("com.github.GTNewHorizons:Hodgepodge:2.3.34") // Iris Shaders shadowImplementation('org.jetbrains:annotations:24.0.1') // Apache 2.0 From 58c209e1bff79a5a6c7d16513fbc9e2bfdb1da66 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 24 Nov 2023 09:09:43 -0800 Subject: [PATCH 112/301] Bump hodgepodge dep --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index d3e99b7f1..ef026e051 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -38,7 +38,7 @@ dependencies { compileOnly(sourceSets.compileStubs.output) compileStubs(sourceSets.compileStubsStubs.output) - api("com.github.GTNewHorizons:Hodgepodge:2.3.34") + api("com.github.GTNewHorizons:Hodgepodge:2.3.35") // Iris Shaders shadowImplementation('org.jetbrains:annotations:24.0.1') // Apache 2.0 From 4fc02d611d85cbecb62803c1e1d8a2d2dacbf904 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 24 Nov 2023 10:29:51 -0800 Subject: [PATCH 113/301] Add AngelicaConfig * Add Mixin to disable MC's builtin checkGLError * Add configs for iris/sodium --- .../angelica/config/AngelicaConfig.java | 22 ++++++++++ .../angelica/loading/AngelicaTweaker.java | 3 ++ .../gtnewhorizons/angelica/mixins/Mixins.java | 44 ++++++++++--------- .../mixins/early/angelica/MixinMinecraft.java | 17 +++++++ .../textures/MixinTextureAtlasSprite.java | 2 +- .../angelica/proxy/ClientProxy.java | 7 ++- .../iris/texture/pbr/PBRAtlasTexture.java | 2 +- 7 files changed, 71 insertions(+), 26 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinMinecraft.java rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{ => shaders}/textures/MixinTextureAtlasSprite.java (93%) diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java new file mode 100644 index 000000000..e64da07ba --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -0,0 +1,22 @@ +package com.gtnewhorizons.angelica.config; + +import org.embeddedt.archaicfix.config.Config; + +@Config(modid = "angelica") +public class AngelicaConfig { + @Config.Comment("Disable Minecraft's check for OpenGL errors. Minor speedup.") + @Config.DefaultBoolean(true) + public static boolean disableMinecraftCheckGLErrors; + + @Config.Comment("Enable Sodium rendering") + @Config.DefaultBoolean(true) + @Config.RequiresMcRestart + public static boolean enableSodium; + + @Config.Comment("Enable Iris Shaders") + @Config.DefaultBoolean(false) + @Config.RequiresMcRestart + public static boolean enableIris; + + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index ef46f52f1..03b01d5c8 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -2,6 +2,7 @@ import com.google.common.collect.ImmutableMap; import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.mixins.ArchaicMixins; import com.gtnewhorizons.angelica.mixins.Mixins; import com.gtnewhorizons.angelica.mixins.TargetedMod; @@ -36,6 +37,8 @@ public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader { static { try { + // Angelica Config + ConfigurationManager.registerConfig(AngelicaConfig.class); // ArchaicFix Config ConfigurationManager.registerConfig(ArchaicConfig.class); LoggerContext ctx = (LoggerContext) LogManager.getContext(false); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 13a049e8c..6259dad4b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.mixins; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import cpw.mods.fml.relauncher.FMLLaunchHandler; import java.util.ArrayList; @@ -12,23 +13,25 @@ public enum Mixins { ANGELICA(new Builder("Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( "angelica.MixinEntityRenderer" + ,"angelica.MixinMinecraft" ) ), IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).setApplyIf(() -> false).addMixinClasses( - "shaders.startup.MixinGameSettings", - "shaders.startup.MixinGuiMainMenu", - "shaders.startup.MixinInitRenderer") + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses( + "shaders.startup.MixinGameSettings" + ,"shaders.startup.MixinGuiMainMenu" + ,"shaders.startup.MixinInitRenderer" + ) ), SODIUM_STARTUP(new Builder("Start Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses( + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodium).addMixinClasses( "sodium.startup.MixinInitDebug" ) ), SODIUM(new Builder("Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses( + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodium).addMixinClasses( "sodium.MixinChunkProviderClient" ,"sodium.MixinExtendedBlockStorage" ,"sodium.MixinEntityRenderer" @@ -50,26 +53,27 @@ public enum Mixins { ), IRIS_RENDERING(new Builder("Iris Shaders").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).setApplyIf(() -> false).addMixinClasses( - "shaders.MixinFramebuffer", - "shaders.MixinEntityRenderer", - "shaders.MixinItem", - "shaders.MixinOpenGlHelper" + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses( + "shaders.MixinFramebuffer" + ,"shaders.MixinEntityRenderer" + ,"shaders.MixinItem" + ,"shaders.MixinOpenGlHelper" ) ), IRIS_ACCESSORS(new Builder("Iris Accessors").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses( - "shaders.accessors.MinecraftAccessor", - "shaders.accessors.EntityRendererAccessor", - "shaders.accessors.SimpleTextureAccessor", - "shaders.accessors.TextureAtlasSpriteAccessor" - )), + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses( + "shaders.accessors.MinecraftAccessor" + ,"shaders.accessors.EntityRendererAccessor" + ,"shaders.accessors.SimpleTextureAccessor" + ,"shaders.accessors.TextureAtlasSpriteAccessor" + ) + ), - ANGELICA_TEXTURE(new Builder("Texture").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).addMixinClasses( - "textures.MixinTextureAtlasSprite" + ANGELICA_TEXTURE(new Builder("Iris Textures").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses( + "shaders.textures.MixinTextureAtlasSprite" )), // TODO: Iris diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinMinecraft.java new file mode 100644 index 000000000..068d75be1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinMinecraft.java @@ -0,0 +1,17 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica; + +import com.gtnewhorizons.angelica.config.AngelicaConfig; +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +public class MixinMinecraft { + @Inject(method = "checkGLError", at = @At(value = "HEAD"), cancellable = true) + private void angelica$checkGLError(CallbackInfo ci) { + if(AngelicaConfig.disableMinecraftCheckGLErrors) + ci.cancel(); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/textures/MixinTextureAtlasSprite.java similarity index 93% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/textures/MixinTextureAtlasSprite.java index c99efaa2a..d14d8a05c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/textures/MixinTextureAtlasSprite.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/textures/MixinTextureAtlasSprite.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.textures; +package com.gtnewhorizons.angelica.mixins.early.shaders.textures; import com.gtnewhorizons.angelica.client.textures.ISpriteExt; import net.minecraft.client.renderer.texture.TextureAtlasSprite; diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index ca4623608..d5d2a1891 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -2,6 +2,7 @@ import com.gtnewhorizons.angelica.client.gui.AngelicaEntityRenderDistanceSetting; import com.gtnewhorizons.angelica.client.gui.AngelicaVideoSettings; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import jss.notfine.gui.GuiCustomMenu; @@ -10,8 +11,6 @@ import me.jellysquid.mods.sodium.client.SodiumDebugScreenHandler; import net.minecraftforge.common.MinecraftForge; -import java.awt.*; - public class ClientProxy extends CommonProxy { @Override @@ -35,7 +34,7 @@ public void init(FMLInitializationEvent event) { @Override public void postInit(FMLInitializationEvent event) { - /// TODO: If Sodium is active/loaded - MinecraftForge.EVENT_BUS.register(SodiumDebugScreenHandler.INSTANCE); + if(AngelicaConfig.enableSodium) + MinecraftForge.EVENT_BUS.register(SodiumDebugScreenHandler.INSTANCE); } } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java index e1e3a8ef9..623438651 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.pbr; -import com.gtnewhorizons.angelica.mixins.early.textures.MixinTextureAtlasSprite; +import com.gtnewhorizons.angelica.mixins.early.shaders.textures.MixinTextureAtlasSprite; import com.gtnewhorizons.angelica.compat.mojang.AutoClosableAbstractTexture; import com.gtnewhorizons.angelica.compat.mojang.TextureAtlas; import net.coderbot.iris.texture.util.TextureExporter; From dc503d31d6511a41246e0d5625b408fc5fc87468 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 24 Nov 2023 12:04:21 -0800 Subject: [PATCH 114/301] Bump lwjgl3ify & Update README credits * Add the commits where code was used from --- README.MD | 8 +++++--- build.gradle | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.MD b/README.MD index bcf51b294..903884be0 100644 --- a/README.MD +++ b/README.MD @@ -9,11 +9,13 @@ Not yet in an usable state * eigenraven, Caedis, glowredman, and mitchej123 for the conversion of ASM to Mixin * eigenraven and vlaetansky for getting the original ShaderMod compiling again * Archaicfix - * Includes graphic enhancements from ArchaicFix by embeddedt - https://github.com/embeddedt/ArchaicFix under the [LGPL and other licenses](https://github.com/embeddedt/ArchaicFix/blob/main/LICENSE.md) + * Includes graphic enhancements from [ArchaicFix](https://github.com/embeddedt/ArchaicFix/commit/4afb943751883b27a1f0aa7c5ba71698bc897e95) by embeddedt under the [LGPL](https://github.com/embeddedt/ArchaicFix/blob/main/LICENSE.md) * NotFine - * Includes modified version of Notfine by jss2a98aj - https://github.com/jss2a98aj/NotFine under the LGPL + * Includes modified version of [Notfine](https://github.com/jss2a98aj/NotFine/commit/a2652e24b5654f437fb7138f6d1f5e947a7d7125) by jss2a98aj under the LGPL * Iris Shaders - * Includes backported code from [Occulus](https://github.com/Asek3/Oculus) and [Iris](https://github.com/IrisShaders/Iris) under the LGPL + * The [Iris](https://github.com/IrisShaders/Iris) Team: coderbot, IMS212, Justsnoopy30, FoundationGames + * Asek3 for the Iris forge port [Occulus](https://github.com/Asek3/Oculus/commit/839ce8eca8cf0c4f6b7a1322b906e5c99125ca69) + * Backported code under the LGPL * Sodium * JellySquid & the CaffeineMC team, for making Sodium in the first place * Embeddedt for [Embeddium](https://github.com/embeddedt/embeddium/commit/dc59ca357c25beefd6288f0d1d40b4cd8e670ab8) under the [LGPL 3.0](https://github.com/embeddedt/embeddium/blob/16.x/forge/LICENSE) diff --git a/build.gradle b/build.gradle index 80f4b8ba5..394d31cb3 100644 --- a/build.gradle +++ b/build.gradle @@ -793,7 +793,7 @@ ext.java17PatchDependenciesCfg = configurations.create("java17PatchDependencies" } dependencies { - def lwjgl3ifyVersion = '1.5.3' + def lwjgl3ifyVersion = '1.5.4' if (modId != 'lwjgl3ify') { java17Dependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}") } From 34db4c05f2e3482760f73a3df86b60240b75f4b0 Mon Sep 17 00:00:00 2001 From: Rad Date: Fri, 24 Nov 2023 22:37:16 +0100 Subject: [PATCH 115/301] A few (minor) README adjustments (#19) * Update README.MD --- README.MD | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.MD b/README.MD index 903884be0..0f438079f 100644 --- a/README.MD +++ b/README.MD @@ -5,16 +5,16 @@ Not yet in an usable state # Credits * ShadersMod - * Original ShaderMods: karyonix, sonic ether, id_miner, daxnitro + * Original ShadersMods: karyonix, sonic ether, id_miner, daxnitro * eigenraven, Caedis, glowredman, and mitchej123 for the conversion of ASM to Mixin - * eigenraven and vlaetansky for getting the original ShaderMod compiling again -* Archaicfix + * eigenraven and vlaetansky for getting the original ShadersMod compiling again +* ArchaicFix * Includes graphic enhancements from [ArchaicFix](https://github.com/embeddedt/ArchaicFix/commit/4afb943751883b27a1f0aa7c5ba71698bc897e95) by embeddedt under the [LGPL](https://github.com/embeddedt/ArchaicFix/blob/main/LICENSE.md) * NotFine - * Includes modified version of [Notfine](https://github.com/jss2a98aj/NotFine/commit/a2652e24b5654f437fb7138f6d1f5e947a7d7125) by jss2a98aj under the LGPL + * Includes modified version of [NotFine](https://github.com/jss2a98aj/NotFine/commit/a2652e24b5654f437fb7138f6d1f5e947a7d7125) by jss2a98aj under the LGPL * Iris Shaders * The [Iris](https://github.com/IrisShaders/Iris) Team: coderbot, IMS212, Justsnoopy30, FoundationGames - * Asek3 for the Iris forge port [Occulus](https://github.com/Asek3/Oculus/commit/839ce8eca8cf0c4f6b7a1322b906e5c99125ca69) + * Asek3 for the Iris Forge port [Oculus](https://github.com/Asek3/Oculus/commit/839ce8eca8cf0c4f6b7a1322b906e5c99125ca69) * Backported code under the LGPL * Sodium * JellySquid & the CaffeineMC team, for making Sodium in the first place From ad69d26e688bade1ef2c812429bef3a15463a5ed Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 24 Nov 2023 15:18:59 -0800 Subject: [PATCH 116/301] Iris work * Move some StateNotifiers to GLStateManager * Remove some redundant mixins based on sodium/angelica work and rendering state captures * Add Iris DebugScreenHandler --- .../angelica/glsm/GLStateManager.java | 111 ++++++++++++++---- .../angelica/glsm/states/FogState.java | 4 +- .../gtnewhorizons/angelica/mixins/Mixins.java | 20 ++-- .../textures/MixinTextureAtlasSprite.java | 2 +- .../early/shaders/MixinEntityRenderer.java | 96 +-------------- .../shaders/startup/MixinGameSettings.java | 12 +- .../angelica/proxy/ClientProxy.java | 7 +- .../angelica/rendering/RenderingState.java | 1 + .../transform/GLStateManagerTransformer.java | 2 +- .../client/SodiumDebugScreenHandler.java | 6 +- .../iris/client/IrisDebugScreenHandler.java | 68 +++++++++++ .../DeferredWorldRenderingPipeline.java | 12 +- .../iris/pipeline/ShadowRenderer.java | 5 +- .../iris/texture/pbr/PBRAtlasTexture.java | 2 +- .../iris/uniforms/CameraUniforms.java | 3 +- .../iris/uniforms/CapturedRenderingState.java | 103 ++-------------- .../iris/uniforms/CelestialUniforms.java | 10 +- .../iris/uniforms/CommonUniforms.java | 4 +- .../iris/uniforms/MatrixUniforms.java | 5 +- 19 files changed, 218 insertions(+), 255 deletions(-) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{shaders => angelica}/textures/MixinTextureAtlasSprite.java (92%) create mode 100644 src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index efa6eb5cd..f31543bd0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.glsm; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.glsm.states.AlphaState; import com.gtnewhorizons.angelica.glsm.states.BlendState; import com.gtnewhorizons.angelica.glsm.states.BooleanState; @@ -20,6 +21,7 @@ import net.coderbot.iris.texture.TextureInfoCache; import net.coderbot.iris.texture.TextureTracker; import net.coderbot.iris.texture.pbr.PBRTextureManager; +import org.joml.Vector3d; import org.lwjgl.opengl.ARBMultitexture; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; @@ -45,6 +47,8 @@ public class GLStateManager { @Getter private static final Color4 Color = new Color4(); @Getter + private static final Color4 ClearColor = new Color4(); + @Getter private static final GLColorMask ColorMask = new GLColorMask(); @Getter private static final BooleanState Cull = new BooleanState(GL11.GL_CULL_FACE); @@ -60,8 +64,21 @@ public class GLStateManager { // Iris Listeners private static Runnable blendFuncListener = null; + private static Runnable fogToggleListener = null; + private static Runnable fogModeListener = null; + private static Runnable fogStartListener = null; + private static Runnable fogEndListener = null; + private static Runnable fogDensityListener = null; + static { - StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener; + if(AngelicaConfig.enableIris) { + StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener; + StateUpdateNotifiers.fogToggleNotifier = listener -> fogToggleListener = listener; + StateUpdateNotifiers.fogModeNotifier = listener -> fogModeListener = listener; + StateUpdateNotifiers.fogStartNotifier = listener -> fogStartListener = listener; + StateUpdateNotifiers.fogEndNotifier = listener -> fogEndListener = listener; + StateUpdateNotifiers.fogDensityNotifier = listener -> fogDensityListener = listener; + } Textures = (TextureState[]) IntStream.range(0, SamplerLimits.get().getMaxTextureUnits()).mapToObj(i -> new TextureState()).toArray(TextureState[]::new); } @@ -95,7 +112,7 @@ public static void glDisable(int cap) { // GLStateManager Functions public static void enableBlend() { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendModeToggle(true); return; @@ -105,7 +122,7 @@ public static void enableBlend() { } public static void disableBlend() { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendModeToggle(false); return; @@ -115,7 +132,7 @@ public static void disableBlend() { } public static void glBlendFunc(int srcFactor, int dstFactor) { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendFunc(srcFactor, dstFactor, srcFactor, dstFactor); return; @@ -130,7 +147,7 @@ public static void glBlendFunc(int srcFactor, int dstFactor) { } public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); return; @@ -154,7 +171,7 @@ public static void glDepthFunc(int func) { } public static void glDepthMask(boolean mask) { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { if (DepthColorStorage.isDepthColorLocked()) { DepthColorStorage.deferDepthEnable(mask); return; @@ -184,7 +201,7 @@ public static void clearCurrentColor() { } public static void glColorMask(boolean red, boolean green, boolean blue, boolean alpha) { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { if (DepthColorStorage.isDepthColorLocked()) { DepthColorStorage.deferColorMask(red, green, blue, alpha); return; @@ -199,9 +216,20 @@ public static void glColorMask(boolean red, boolean green, boolean blue, boolean } } + // Clear Color + public static void glClearColor(float red, float green, float blue, float alpha) { + if(red != ClearColor.red || green != ClearColor.green || blue != ClearColor.blue || alpha != ClearColor.alpha) { + ClearColor.red = red; + ClearColor.green = green; + ClearColor.blue = blue; + ClearColor.alpha = alpha; + GL11.glClearColor(red, green, blue, alpha); + } + } + // ALPHA public static void enableAlphaTest() { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { if (AlphaTestStorage.isAlphaTestLocked()) { AlphaTestStorage.deferAlphaTestToggle(true); return; @@ -211,7 +239,7 @@ public static void enableAlphaTest() { } public static void disableAlphaTest() { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { if (AlphaTestStorage.isAlphaTestLocked()) { AlphaTestStorage.deferAlphaTestToggle(false); return; @@ -221,7 +249,7 @@ public static void disableAlphaTest() { } public static void glAlphaFunc(int function, float reference) { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { if (AlphaTestStorage.isAlphaTestLocked()) { AlphaTestStorage.deferAlphaFunc(function, reference); return; @@ -252,34 +280,34 @@ public static void glBindTexture(int target, int texture) { if(Textures[activeTexture].binding != texture) { Textures[activeTexture].binding = texture; GL11.glBindTexture(target, texture); - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { TextureTracker.INSTANCE.onBindTexture(texture); } } } public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, IntBuffer pixels) { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { // Iris TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, ByteBuffer pixels) { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels != null ? pixels.asIntBuffer() : (IntBuffer) null); } GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } public static void glDeleteTextures(int id) { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { iris$onDeleteTexture(id); } GL11.glDeleteTextures(id); } public static void glDeleteTextures(IntBuffer ids) { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { for (int id : ids.array()) { iris$onDeleteTexture(id); } @@ -288,7 +316,7 @@ public static void glDeleteTextures(IntBuffer ids) { } public static void enableTexture() { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { // Iris boolean updatePipeline = false; if (activeTexture == IrisSamplers.ALBEDO_TEXTURE_UNIT) { @@ -311,7 +339,7 @@ public static void enableTexture() { } public static void disableTexture() { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { // Iris boolean updatePipeline = false; if (activeTexture == IrisSamplers.ALBEDO_TEXTURE_UNIT) { @@ -378,24 +406,39 @@ public static void disableDepthTest() { public static void enableFog() { Fog.mode.enable(); + if (fogToggleListener != null) { + fogToggleListener.run(); + } } public static void disableFog() { Fog.mode.disable(); + if (fogToggleListener != null) { + fogToggleListener.run(); + } } public static void glFog(int pname, FloatBuffer param) { // TODO: Iris Notifier GL11.glFog(pname, param); if(pname == GL11.GL_FOG_COLOR) { - Fog.fogColor.set(param.get(0), param.get(1), param.get(2)); + final float red = param.get(0); + final float green = param.get(1); + final float blue = param.get(2); + + Fog.fogColor.set(red, green, blue); Fog.fogAlpha = param.get(3); Fog.fogColorBuffer.clear(); Fog.fogColorBuffer.put((FloatBuffer) param.position(0)).flip(); } } + + public static Vector3d getFogColor() { + return Fog.fogColor; + } + + public static void fogColor(float red, float green, float blue, float alpha) { - // TODO: Iris Notifier if(red != Fog.fogColor.x || green != Fog.fogColor.y || blue != Fog.fogColor.z || alpha != Fog.fogAlpha) { Fog.fogColor.set(red, green, blue); Fog.fogAlpha = alpha; @@ -405,24 +448,40 @@ public static void fogColor(float red, float green, float blue, float alpha) { } } public static void glFogf(int pname, float param) { - // TODO: Iris Notifier GL11.glFogf(pname, param); switch(pname) { - case GL11.GL_FOG_DENSITY -> Fog.density = param; - case GL11.GL_FOG_START -> Fog.start = param; - case GL11.GL_FOG_END -> Fog.end = param; + case GL11.GL_FOG_DENSITY -> { + Fog.density = param; + if (fogDensityListener != null) { + fogDensityListener.run(); + } + } + case GL11.GL_FOG_START -> { + Fog.start = param; + if (fogStartListener != null) { + fogStartListener.run(); + } + } + case GL11.GL_FOG_END -> { + Fog.end = param; + if (fogEndListener != null) { + fogEndListener.run(); + } + } } } public static void glFogi(int pname, int param) { - // TODO: Iris Notifier GL11.glFogi(pname, param); if(pname == GL11.GL_FOG_MODE) { Fog.fogMode = param; + if (fogModeListener != null) { + fogModeListener.run(); + } } } public static void setFogBlack() { - GL11.glFogf(GL11.GL_FOG_COLOR, 0.0F); + glFogf(GL11.GL_FOG_COLOR, 0.0F); } @@ -435,7 +494,7 @@ public static void glShadeModel(int mode) { // Iris Functions private static void iris$onDeleteTexture(int id) { - if (Iris.isInitialized()) { + if (AngelicaConfig.enableIris) { TextureTracker.INSTANCE.onDeleteTexture(id); TextureInfoCache.INSTANCE.onDeleteTexture(id); PBRTextureManager.INSTANCE.onDeleteTexture(id); diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java index 390099bc7..a2618f38c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/FogState.java @@ -1,6 +1,6 @@ package com.gtnewhorizons.angelica.glsm.states; -import org.joml.Vector3f; +import org.joml.Vector3d; import org.lwjgl.opengl.GL11; import java.nio.FloatBuffer; @@ -8,7 +8,7 @@ public class FogState { public BooleanState mode = new BooleanState(GL11.GL_FOG); public int fogMode = GL11.GL_EXP; - public final Vector3f fogColor = new Vector3f(0.0F, 0.0F, 0.0F); + public final Vector3d fogColor = new Vector3d(0.0F, 0.0F, 0.0F); public float fogAlpha = 1.0F; public final FloatBuffer fogColorBuffer = FloatBuffer.allocate(4); public float density = 1.0F; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 6259dad4b..267bb3060 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -25,7 +25,7 @@ public enum Mixins { ), SODIUM_STARTUP(new Builder("Start Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodium).addMixinClasses( + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodium && !AngelicaConfig.enableIris).addMixinClasses( "sodium.startup.MixinInitDebug" ) ), @@ -33,10 +33,14 @@ public enum Mixins { SODIUM(new Builder("Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodium).addMixinClasses( "sodium.MixinChunkProviderClient" + ,"sodium.MixinEntity" + ,"sodium.MixinRenderManager" ,"sodium.MixinExtendedBlockStorage" ,"sodium.MixinEntityRenderer" ,"sodium.MixinFMLClientHandler" + ,"sodium.MixinGameSettings" ,"sodium.MixinFrustrum" + ,"sodium.MixinMaterial" ,"sodium.MixinMinecraft" ,"sodium.MixinNetHandlerPlayClient" ,"sodium.MixinNibbleArray" @@ -45,17 +49,13 @@ public enum Mixins { ,"sodium.MixinTessellator" ,"sodium.MixinWorldClient" ,"sodium.MixinWorldRenderer" - ,"sodium.MixinEntity" - ,"sodium.MixinRenderManager" - ,"sodium.MixinMaterial" - ,"sodium.MixinGameSettings" ) ), IRIS_RENDERING(new Builder("Iris Shaders").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses( - "shaders.MixinFramebuffer" - ,"shaders.MixinEntityRenderer" + "shaders.MixinEntityRenderer" + ,"shaders.MixinFramebuffer" ,"shaders.MixinItem" ,"shaders.MixinOpenGlHelper" ) @@ -71,9 +71,9 @@ public enum Mixins { ), - ANGELICA_TEXTURE(new Builder("Iris Textures").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses( - "shaders.textures.MixinTextureAtlasSprite" + ANGELICA_TEXTURE(new Builder("Textures").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris || AngelicaConfig.enableSodium).addMixinClasses( + "angelica.textures.MixinTextureAtlasSprite" )), // TODO: Iris diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/textures/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureAtlasSprite.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/textures/MixinTextureAtlasSprite.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureAtlasSprite.java index d14d8a05c..ce6ca4a2f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/textures/MixinTextureAtlasSprite.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureAtlasSprite.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.shaders.textures; +package com.gtnewhorizons.angelica.mixins.early.angelica.textures; import com.gtnewhorizons.angelica.client.textures.ISpriteExt; import net.minecraft.client.renderer.texture.TextureAtlasSprite; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index bfbfded28..7e44c7877 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -1,74 +1,21 @@ package com.gtnewhorizons.angelica.mixins.early.shaders; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; import net.coderbot.iris.Iris; import net.coderbot.iris.gl.program.Program; -import net.coderbot.iris.gl.state.StateUpdateNotifiers; import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.coderbot.iris.uniforms.CapturedRenderingState; import net.coderbot.iris.uniforms.SystemTimeUniforms; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.EntityRenderer; -import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; -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.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import com.llamalad7.mixinextras.sugar.Share; -import com.llamalad7.mixinextras.sugar.ref.LocalRef; - -import java.nio.FloatBuffer; @Mixin(EntityRenderer.class) public class MixinEntityRenderer { - @Unique private static Runnable fogToggleListener; - @Unique private static Runnable fogModeListener; - @Unique private static Runnable fogStartListener; - @Unique private static Runnable fogEndListener; - @Unique private static Runnable fogDensityListener; - - - private void sglFogf(int pname, float param) { - GL11.glFogf(pname, param); - switch (pname) { - case GL11.GL_FOG_DENSITY: - if (fogDensityListener != null) { - fogDensityListener.run(); - } - break; - case GL11.GL_FOG_START: - if (fogStartListener != null) { - fogStartListener.run(); - } - break; - case GL11.GL_FOG_END: - if (fogEndListener != null) { - fogEndListener.run(); - } - break; - } - } - - private void sglFogi(int pname, int param) { - GL11.glFogi(pname, param); - if (pname == GL11.GL_FOG_MODE) { - if (fogModeListener != null) { - fogModeListener.run(); - } - } - } - - - @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/EntityRenderer;setupCameraTransform(FI)V", value = "INVOKE"), method = "renderWorld(FJ)V") - private void iris$setCamera(float tickDelta, long startTime, CallbackInfo ci) { - // TODO: Grab from Angelica - CapturedRenderingState.INSTANCE.setCamera(tickDelta); - } - - @Inject(at = @At("HEAD"), method = "renderWorld(FJ)V") private void iris$beginRender(float tickDelta, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { CapturedRenderingState.INSTANCE.setTickDelta(tickDelta); @@ -92,43 +39,4 @@ private void sglFogi(int pname, int param) { Program.unbind(); } - // setFogColorBuffer - @Inject(at = @At("HEAD"), method = "setFogColorBuffer(FFFF)Ljava/nio/FloatBuffer;") - private void iris$setFogColor(float red, float green, float blue, float alpha, CallbackInfoReturnable cir) { - CapturedRenderingState.INSTANCE.setFogColor(red, green, blue); - } - - // updateFogColor - - @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glClearColor(FFFF)V", value = "INVOKE"), method = "updateFogColor(F)V") - private void iris$setClearColor(float red, float green, float blue, float alpha) { - CapturedRenderingState.INSTANCE.setClearColor(red, green, blue, alpha); - } - - - - - // setupFog - - @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glFogi(II)V", value = "INVOKE"), method = "setupFog(IF)V") - private void iris$sglFogi(int pname, int param) { - sglFogi(pname, param); - } - - @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glFogf(IF)V", value = "INVOKE"), method = "setupFog(IF)V") - private void iris$sglFogf(int pname, float param) { - sglFogf(pname, param); - } - - - - - static { - StateUpdateNotifiers.fogToggleNotifier = listener -> fogToggleListener = listener; - StateUpdateNotifiers.fogModeNotifier = listener -> fogModeListener = listener; - StateUpdateNotifiers.fogStartNotifier = listener -> fogStartListener = listener; - StateUpdateNotifiers.fogEndNotifier = listener -> fogEndListener = listener; - StateUpdateNotifiers.fogDensityNotifier = listener -> fogDensityListener = listener; - } - } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGameSettings.java index 83e07781a..d465a800e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGameSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGameSettings.java @@ -11,17 +11,19 @@ @Mixin(GameSettings.class) public abstract class MixinGameSettings { @Unique - private static boolean angelica$shadersInitialized; + private static boolean iris$shadersInitialized; + + private static Iris iris$Instance; @Inject(method="Lnet/minecraft/client/settings/GameSettings;loadOptions()V", at=@At("HEAD")) private void angelica$InitializeShaders(CallbackInfo ci) { - if (angelica$shadersInitialized) { + if (iris$shadersInitialized) { return; } - angelica$shadersInitialized = true; - // TODO: Should this be static, or a new var? - new Iris().onEarlyInitialize(); + iris$shadersInitialized = true; + iris$Instance =new Iris(); + iris$Instance.onEarlyInitialize(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index d5d2a1891..3d50bb31c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -9,6 +9,7 @@ import jss.notfine.gui.ISettingsEnum; import jss.notfine.gui.MenuButtonLists; import me.jellysquid.mods.sodium.client.SodiumDebugScreenHandler; +import net.coderbot.iris.client.IrisDebugScreenHandler; import net.minecraftforge.common.MinecraftForge; public class ClientProxy extends CommonProxy { @@ -34,7 +35,11 @@ public void init(FMLInitializationEvent event) { @Override public void postInit(FMLInitializationEvent event) { - if(AngelicaConfig.enableSodium) + if(AngelicaConfig.enableSodium) { MinecraftForge.EVENT_BUS.register(SodiumDebugScreenHandler.INSTANCE); + } + if(AngelicaConfig.enableIris) { + MinecraftForge.EVENT_BUS.register(IrisDebugScreenHandler.INSTANCE); + } } } diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java b/src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java index 8f0ebaab2..fdcfb291e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java +++ b/src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java @@ -37,4 +37,5 @@ public void captureModelViewMatrix() { GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelViewBuffer); modelViewMatrix.set(modelViewBuffer); } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index 21fadc88e..cfbd40382 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -33,7 +33,7 @@ public class GLStateManagerTransformer implements IClassTransformer { public static final Map> EnabledRedirects = ImmutableMap.of( GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", - "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor4f", "glShadeModel", "glFog", "glFogi", "glFogf") + "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor4f", "glShadeModel", "glFog", "glFogi", "glFogf", "glClearColor") ,GL13, Sets.newHashSet("glActiveTexture") ,GL14, Sets.newHashSet("glBlendFuncSeparate") ,EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumDebugScreenHandler.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumDebugScreenHandler.java index 7e9560f4d..2d9b9484b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumDebugScreenHandler.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumDebugScreenHandler.java @@ -1,20 +1,24 @@ package me.jellysquid.mods.sodium.client; +import cpw.mods.fml.common.eventhandler.EventPriority; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderBackend; import net.minecraft.client.Minecraft; import net.minecraftforge.client.event.RenderGameOverlayEvent; +import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.List; public class SodiumDebugScreenHandler { public static final SodiumDebugScreenHandler INSTANCE = new SodiumDebugScreenHandler(); - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.LOW) public void onRenderGameOverlayTextEvent(RenderGameOverlayEvent.Text event) { final Minecraft mc = Minecraft.getMinecraft(); if (mc.gameSettings.showDebugInfo) { + event.right.add(2, "Off-Heap: +" + ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getUsed() / 1024L / 1024L + "MB"); + event.right.add(""); event.right.add("Sodium (Embeddium) Renderer"); event.right.addAll(getChunkRendererDebugStrings()); diff --git a/src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java b/src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java new file mode 100644 index 000000000..e430bed01 --- /dev/null +++ b/src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java @@ -0,0 +1,68 @@ +package net.coderbot.iris.client; + +import cpw.mods.fml.common.eventhandler.EventPriority; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import net.coderbot.iris.Iris; +import net.minecraft.client.Minecraft; +import net.minecraftforge.client.event.RenderGameOverlayEvent; + +import java.lang.management.BufferPoolMXBean; +import java.lang.management.ManagementFactory; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.List; +import java.util.Objects; + +public class IrisDebugScreenHandler { + public static final IrisDebugScreenHandler INSTANCE = new IrisDebugScreenHandler(); + private static final List iris$pools = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class); + + private static final BufferPoolMXBean iris$directPool; + + static { + BufferPoolMXBean found = null; + + for (BufferPoolMXBean pool : iris$pools) { + if (pool.getName().equals("direct")) { + found = pool; + break; + } + } + + iris$directPool = Objects.requireNonNull(found); + } + + @SubscribeEvent(priority = EventPriority.LOW) + public void onRenderGameOverlayTextEvent(RenderGameOverlayEvent.Text event) { + final Minecraft mc = Minecraft.getMinecraft(); + if (mc.gameSettings.showDebugInfo) { + event.right.add(2, "Direct Buffers: +" + iris$humanReadableByteCountBin(iris$directPool.getMemoryUsed())); + + event.right.add(""); + + if (Iris.getIrisConfig().areShadersEnabled()) { + event.right.add("[Iris] Shaderpack: " + Iris.getCurrentPackName() + (Iris.isFallback() ? " (fallback)" : "")); + Iris.getCurrentPack().ifPresent(pack -> event.right.add("[Iris] " + pack.getProfileInfo())); + } else { + event.right.add("[Iris] Shaders are disabled"); + } + + } + } + + private static String iris$humanReadableByteCountBin(long bytes) { + long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes); + if (absB < 1024) { + return bytes + " B"; + } + long value = absB; + CharacterIterator ci = new StringCharacterIterator("KMGTPE"); + for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) { + value >>= 10; + ci.next(); + } + value *= Long.signum(bytes); + return String.format("%.3f %ciB", value / 1024.0, ci.current()); + } + +} diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index ce0712ac4..63b5e9d69 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -3,12 +3,13 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Ints; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.LevelRenderer; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.Iris; import net.coderbot.iris.block_rendering.BlockMaterialMapping; import net.coderbot.iris.block_rendering.BlockRenderingSettings; -import com.gtnewhorizons.angelica.compat.mojang.Camera; -import com.gtnewhorizons.angelica.compat.mojang.LevelRenderer; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.ProgramTable; import net.coderbot.iris.gbuffer_overrides.matching.RenderCondition; @@ -54,7 +55,6 @@ import net.coderbot.iris.texture.pbr.PBRTextureHolder; import net.coderbot.iris.texture.pbr.PBRTextureManager; import net.coderbot.iris.texture.pbr.PBRType; -import net.coderbot.iris.uniforms.CapturedRenderingState; import net.coderbot.iris.uniforms.CommonUniforms; import net.coderbot.iris.uniforms.FrameUpdateNotifier; import net.minecraft.client.Minecraft; @@ -915,7 +915,7 @@ private void prepareRenderTargets() { passes = clearPasses; } - final Vector3d fogColor3 = CapturedRenderingState.INSTANCE.getFogColor(); + final Vector3d fogColor3 = GLStateManager.getFogColor(); // NB: The alpha value must be 1.0 here, or else you will get a bunch of bugs. Sildur's Vibrant Shaders // will give you pink reflections and other weirdness if this is zero. @@ -1106,10 +1106,10 @@ public void beginLevelRendering() { GL11.glDisable(GL11.GL_TEXTURE_2D); GL11.glDepthMask(false); - Vector3d fogColor = CapturedRenderingState.INSTANCE.getFogColor(); + final Vector3d fogColor = GLStateManager.getFogColor(); GL11.glColor4f((float) fogColor.x, (float) fogColor.y, (float) fogColor.z, 1.0F); - horizonRenderer.renderHorizon(CapturedRenderingState.INSTANCE.getGbufferModelView()); + horizonRenderer.renderHorizon(RenderingState.INSTANCE.getModelViewMatrix()); GL11.glDepthMask(true); GL11.glEnable(GL11.GL_TEXTURE_2D); diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 5c87e666f..d9d918e69 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -2,6 +2,7 @@ import com.google.common.collect.ImmutableList; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.batchedentityrendering.impl.BatchingDebugMessageHelper; import net.coderbot.batchedentityrendering.impl.DrawCallTrackingRenderBuffers; import net.coderbot.batchedentityrendering.impl.RenderBuffersExt; @@ -311,8 +312,8 @@ private FrustumHolder createShadowFrustum(float renderMultiplier, FrustumHolder shadowLightVectorFromOrigin.normalize(); - return holder.setInfo(new AdvancedShadowCullingFrustum(((Matrix4fAccess) (Object) CapturedRenderingState.INSTANCE.getGbufferModelView()).convertToJOML(), - ((Matrix4fAccess) (Object) CapturedRenderingState.INSTANCE.getGbufferProjection()).convertToJOML(), shadowLightVectorFromOrigin, boxCuller), distanceInfo, cullingInfo); + return holder.setInfo(new AdvancedShadowCullingFrustum(RenderingState.INSTANCE.getModelViewMatrix(), RenderingState.INSTANCE.getProjectionMatrix(), + shadowLightVectorFromOrigin, boxCuller), distanceInfo, cullingInfo); } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java index 623438651..8907a6466 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.pbr; -import com.gtnewhorizons.angelica.mixins.early.shaders.textures.MixinTextureAtlasSprite; +import com.gtnewhorizons.angelica.mixins.early.angelica.textures.MixinTextureAtlasSprite; import com.gtnewhorizons.angelica.compat.mojang.AutoClosableAbstractTexture; import com.gtnewhorizons.angelica.compat.mojang.TextureAtlas; import net.coderbot.iris.texture.util.TextureExporter; diff --git a/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java index a9a2f8c58..17267919e 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java @@ -1,5 +1,6 @@ package net.coderbot.iris.uniforms; +import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.gl.uniform.UniformHolder; import net.minecraft.client.Minecraft; import org.joml.Vector3d; @@ -32,7 +33,7 @@ private static int getRenderDistanceInBlocks() { } public static Vector3d getUnshiftedCameraPosition() { - return CapturedRenderingState.INSTANCE.getCameraPosition(); + return RenderingState.INSTANCE.getCameraPosition(); } static class CameraPositionTracker { diff --git a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java index 033fd6a63..dd9699e3b 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java +++ b/src/main/java/net/coderbot/iris/uniforms/CapturedRenderingState.java @@ -2,78 +2,28 @@ import lombok.Getter; import net.coderbot.iris.gl.state.ValueUpdateNotifier; -import net.minecraft.client.Minecraft; -import net.minecraft.entity.EntityLivingBase; -import org.joml.Matrix4f; -import org.joml.Vector3d; -import org.joml.Vector4d; -import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.GL11; - -import java.nio.FloatBuffer; public class CapturedRenderingState { public static final CapturedRenderingState INSTANCE = new CapturedRenderingState(); - private static final Vector3d ZERO_VECTOR_3d = new Vector3d(); - - private final FloatBuffer modelViewBuffer = BufferUtils.createFloatBuffer(16); - private final Matrix4f gbufferModelView = new Matrix4f(); - private final FloatBuffer shadowModelViewBuffer = BufferUtils.createFloatBuffer(16); - private Matrix4f shadowModelView; - private final FloatBuffer projectionBuffer = BufferUtils.createFloatBuffer(16); - private final Matrix4f gbufferProjection = new Matrix4f(); - private final FloatBuffer shadowProjectionBuffer = BufferUtils.createFloatBuffer(16); - private Matrix4f shadowProjection; - private Vector3d fogColor; - private Vector4d clearColor; - - @Getter - private final Vector3d cameraPosition = new Vector3d(); - - private float tickDelta; - private int currentRenderedBlockEntity; + @Getter + private float tickDelta; + @Getter + private int currentRenderedBlockEntity; private Runnable blockEntityIdListener = null; - private int currentRenderedEntity = -1; + @Getter + private int currentRenderedEntity = -1; private Runnable entityIdListener = null; private CapturedRenderingState() { } - public Matrix4f getGbufferModelView() { - return gbufferModelView; - } - - public Matrix4f getGbufferProjection() { - return gbufferProjection; - } - - public Vector3d getFogColor() { - if (Minecraft.getMinecraft().theWorld == null || fogColor == null) { - return ZERO_VECTOR_3d; - } - - return fogColor; - } - - public void setFogColor(float red, float green, float blue) { - fogColor = new Vector3d(red, green, blue); - } - - public void setClearColor(float red, float green, float blue, float alpha) { - clearColor = new Vector4d(red, green, blue, alpha); - } - public void setTickDelta(float tickDelta) { this.tickDelta = tickDelta; } - public float getTickDelta() { - return tickDelta; - } - - public void setCurrentBlockEntity(int entity) { + public void setCurrentBlockEntity(int entity) { this.currentRenderedBlockEntity = entity; if (this.blockEntityIdListener != null) { @@ -81,11 +31,7 @@ public void setCurrentBlockEntity(int entity) { } } - public int getCurrentRenderedBlockEntity() { - return currentRenderedBlockEntity; - } - - public void setCurrentEntity(int entity) { + public void setCurrentEntity(int entity) { this.currentRenderedEntity = entity; if (this.entityIdListener != null) { @@ -100,37 +46,4 @@ public ValueUpdateNotifier getEntityIdNotifier() { public ValueUpdateNotifier getBlockEntityIdNotifier() { return listener -> this.blockEntityIdListener = listener; } - - public int getCurrentRenderedEntity() { - return currentRenderedEntity; - } - - public void setCamera(float tickDelta) { - final Minecraft mc = Minecraft.getMinecraft(); - final EntityLivingBase viewEntity = mc.renderViewEntity; - - final double x = viewEntity.lastTickPosX + (viewEntity.posX - viewEntity.lastTickPosX) * tickDelta; - final double y = viewEntity.lastTickPosY + (viewEntity.posY - viewEntity.lastTickPosY) * tickDelta; - final double z = viewEntity.lastTickPosZ + (viewEntity.posZ - viewEntity.lastTickPosZ) * tickDelta; - cameraPosition.set(x, y, z); - - GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, (FloatBuffer) projectionBuffer.position(0)); - gbufferProjection.set((FloatBuffer)projectionBuffer.position(0)); - - GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, (FloatBuffer) modelViewBuffer.position(0)); - gbufferModelView.set((FloatBuffer)modelViewBuffer.position(0)); - } - - public void setCameraShadow(float tickDelta) { - final Minecraft mc = Minecraft.getMinecraft(); - setCamera(tickDelta); - - GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, (FloatBuffer) shadowProjectionBuffer.position(0)); - shadowProjection = new Matrix4f((FloatBuffer)shadowProjectionBuffer.position(0)); - - GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, (FloatBuffer) shadowModelViewBuffer.position(0)); - shadowModelView = new Matrix4f((FloatBuffer)shadowModelViewBuffer.position(0)); - - - } } diff --git a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java index e3ed628d3..68db63e00 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java @@ -1,6 +1,7 @@ package net.coderbot.iris.uniforms; import com.gtnewhorizons.angelica.compat.mojang.Constants; +import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.gl.uniform.UniformHolder; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; @@ -72,8 +73,7 @@ private Vector4f getCelestialPositionInWorldSpace(float y) { Vector4f position = new Vector4f(0.0F, y, 0.0F, 0.0F); // TODO: Deduplicate / remove this function. - Matrix4f celestial = new Matrix4f(); - celestial.identity(); + Matrix4f celestial = new Matrix4f().identity(); // This is the same transformation applied by renderSky, however, it's been moved to here. // This is because we need the result of it before it's actually performed in vanilla. @@ -89,7 +89,7 @@ private Vector4f getCelestialPositionInWorldSpace(float y) { private Vector4f getCelestialPosition(float y) { Vector4f position = new Vector4f(0.0F, y, 0.0F, 0.0F); - Matrix4f celestial = new Matrix4f(CapturedRenderingState.INSTANCE.getGbufferModelView()); + Matrix4f celestial = new Matrix4f(RenderingState.INSTANCE.getModelViewMatrix()); // This is the same transformation applied by renderSky, however, it's been moved to here. // This is because we need the result of it before it's actually performed in vanilla. celestial.rotateY(-90.F * Constants.DEGREES_TO_RADIANS); @@ -104,8 +104,8 @@ private Vector4f getCelestialPosition(float y) { private static Vector4f getUpPosition() { Vector4f upVector = new Vector4f(0.0F, 100.0F, 0.0F, 0.0F); - // Get the current GBuffer model view matrix, since that is the basis of the celestial model view matrix - Matrix4f preCelestial = new Matrix4f(CapturedRenderingState.INSTANCE.getGbufferModelView()); + // Get the current model view matrix, since that is the basis of the celestial model view matrix + Matrix4f preCelestial = new Matrix4f(RenderingState.INSTANCE.getModelViewMatrix()); // Apply the fixed -90.0F degrees rotation to mirror the same transformation in renderSky. // But, notably, skip the rotation by the skyAngle. diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index d2169e51f..9a1775217 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -1,8 +1,8 @@ package net.coderbot.iris.uniforms; import com.gtnewhorizons.angelica.client.Shaders; -import com.gtnewhorizons.angelica.glsm.states.BlendState; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.glsm.states.BlendState; import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.EntityRendererAccessor; import net.coderbot.iris.gl.state.StateUpdateNotifiers; import net.coderbot.iris.gl.uniform.DynamicUniformHolder; @@ -124,7 +124,7 @@ public static void generalCommonUniforms(UniformHolder uniforms, FrameUpdateNoti .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", CapturedRenderingState.INSTANCE::getFogColor); + .uniform3d(PER_FRAME, "fogColor", GLStateManager::getFogColor); } private static boolean isOnGround() { diff --git a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java index 5f7a8b153..94e49f012 100644 --- a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java @@ -1,5 +1,6 @@ package net.coderbot.iris.uniforms; +import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.gl.uniform.UniformHolder; import net.coderbot.iris.pipeline.ShadowRenderer; import net.coderbot.iris.shaderpack.PackDirectives; @@ -16,10 +17,10 @@ private MatrixUniforms() { } public static void addMatrixUniforms(UniformHolder uniforms, PackDirectives directives) { - addMatrix(uniforms, "ModelView", CapturedRenderingState.INSTANCE::getGbufferModelView); + addMatrix(uniforms, "ModelView", RenderingState.INSTANCE::getModelViewMatrix); // TODO: In some cases, gbufferProjectionInverse takes on a value much different than OptiFine... // We need to audit Mojang's linear algebra. - addMatrix(uniforms, "Projection", CapturedRenderingState.INSTANCE::getGbufferProjection); + addMatrix(uniforms, "Projection", RenderingState.INSTANCE::getProjectionMatrix); addShadowMatrix(uniforms, "ModelView", () -> ShadowRenderer.createShadowModelView(directives.getSunPathRotation(), directives.getShadowDirectives().getIntervalSize()).peek().getModel()); addShadowArrayMatrix(uniforms, "Projection", () -> ShadowMatrices.createOrthoMatrix(directives.getShadowDirectives().getDistance())); } From 4b3d5dfea52c56ac350dc669125ea31cdad315f2 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 24 Nov 2023 15:38:47 -0800 Subject: [PATCH 117/301] rm archaicfix's occlusion renderer and threaded updates --- .../angelica/mixins/ArchaicMixins.java | 14 - .../archaic/client/occlusion/MixinChunk.java | 89 --- .../client/occlusion/MixinEntityRenderer.java | 22 - .../occlusion/MixinGuiVideoSettings.java | 14 - .../client/occlusion/MixinRenderGlobal.java | 138 ---- .../client/occlusion/MixinWorldRenderer.java | 86 --- .../threadedupdates/MixinRenderBlocks.java | 50 -- .../threadedupdates/MixinTessellator.java | 86 --- .../MixinTessellator_Debug.java | 34 - .../threadedupdates/MixinWorldRenderer.java | 58 -- .../org/embeddedt/archaicfix/ArchaicFix.java | 7 - .../archaicfix/config/ArchaicConfig.java | 20 - .../occlusion/BasicDistanceSorter.java | 20 - .../archaicfix/occlusion/CameraInfo.java | 36 - .../archaicfix/occlusion/ChunkThread.java | 55 -- .../DefaultRendererUpdateOrderProvider.java | 32 - .../embeddedt/archaicfix/occlusion/LICENSE | 51 -- .../occlusion/OcclusionHelpers.java | 43 -- .../occlusion/OcclusionRenderer.java | 577 --------------- .../archaicfix/occlusion/OcclusionWorker.java | 419 ----------- .../occlusion/PreviousActiveRenderInfo.java | 26 - .../archaicfix/occlusion/SetVisibility.java | 86 --- .../archaicfix/occlusion/VisGraph.java | 215 ------ .../occlusion/interfaces/ICulledChunk.java | 9 - .../interfaces/IRenderGlobalListener.java | 10 - .../IRendererUpdateOrderProvider.java | 21 - .../occlusion/interfaces/IWorldRenderer.java | 12 - .../occlusion/util/ArrayHashList.java | 626 ---------------- .../util/IdentityLinkedHashList.java | 48 -- .../archaicfix/occlusion/util/IntStack.java | 282 -------- .../archaicfix/occlusion/util/IntVector.java | 403 ----------- .../occlusion/util/LinkedHashList.java | 675 ------------------ .../SynchronizedIdentityLinkedHashList.java | 137 ---- .../archaicfix/proxy/ClientProxy.java | 3 - .../ICapturableTessellator.java | 16 - .../IRendererUpdateResultHolder.java | 7 - .../threadedupdates/RenderBlocksStack.java | 34 - .../ThreadedChunkUpdateHelper.java | 329 --------- .../api/ThreadedChunkUpdates.java | 17 - 39 files changed, 4807 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinChunk.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinEntityRenderer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinGuiVideoSettings.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinRenderGlobal.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinRenderBlocks.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator_Debug.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinWorldRenderer.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/BasicDistanceSorter.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/LICENSE delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/PreviousActiveRenderInfo.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/ICulledChunk.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRenderGlobalListener.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRendererUpdateOrderProvider.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IWorldRenderer.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/ArrayHashList.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/IdentityLinkedHashList.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/IntStack.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/IntVector.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/occlusion/util/SynchronizedIdentityLinkedHashList.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/threadedupdates/ICapturableTessellator.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/threadedupdates/IRendererUpdateResultHolder.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/threadedupdates/RenderBlocksStack.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/threadedupdates/api/ThreadedChunkUpdates.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java index 472fa5824..f5670d1fa 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java @@ -90,25 +90,11 @@ public enum ArchaicMixins { "lighting.MixinSPacketChunkData", "lighting.MixinWorld_Lighting"), - client_occlusion(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.enableOcclusionTweaks, - "occlusion.MixinChunk", - "occlusion.MixinEntityRenderer", - "occlusion.MixinRenderGlobal", - "occlusion.MixinGuiVideoSettings", - "occlusion.MixinWorldRenderer"), - client_renderdistance(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.raiseMaxRenderDistance, "renderdistance.MixinGameSettings", "renderdistance.MixinRenderGlobal", "renderdistance.MixinPlayerManager"), - client_threadedupdates(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks, - "threadedupdates.MixinRenderBlocks", - "threadedupdates.MixinWorldRenderer", - "threadedupdates.MixinTessellator"), - client_threadedupdates_MixinTessellator_Debug(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks && Boolean.parseBoolean(System.getProperty("archaicfix.debug.verifyTessellatorAccessThread")), "threadedupdates.MixinTessellator_Debug"), - - common_botania_MixinBlockSpecialFlower(Side.COMMON, Phase.LATE, require(TargetedMod.BOTANIA), "botania.MixinBlockSpecialFlower"), common_extrautils(Side.COMMON, Phase.LATE, require(TargetedMod.EXTRAUTILS), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinChunk.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinChunk.java deleted file mode 100644 index 31f00e9dd..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinChunk.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.occlusion; - -import net.minecraft.block.Block; -import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; -import org.embeddedt.archaicfix.occlusion.ChunkThread; -import org.embeddedt.archaicfix.occlusion.interfaces.ICulledChunk; -import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; -import org.embeddedt.archaicfix.occlusion.VisGraph; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -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.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(Chunk.class) -public abstract class MixinChunk implements ICulledChunk { - @Shadow public abstract Block getBlock(int p_150810_1_, int p_150810_2_, int p_150810_3_); - - @Shadow public World worldObj; - @Shadow @Final public int xPosition; - @Shadow @Final public int zPosition; - @Unique private VisGraph[] visibility; - - @Unique private static final ChunkThread worker = new ChunkThread(); - static { - worker.start(); - } - - public Chunk buildCulledSides() { - if (!this.worldObj.getChunkProvider().chunkExists(xPosition, zPosition)) { - return null; - } - for (int i = 0; i < 16; ++i) { - for (int j = 0; j < 16; ++j) { - for (int y = 0; y < 256; ++y) { - checkPosSolid(i, y, j, null); - } - } - } - OcclusionHelpers.updateArea(xPosition * 16 - 1, 0, zPosition * 16 - 1, xPosition * 16 + 16, 255, zPosition * 16 + 16); - return (Chunk)(Object)this; - } - - - @Inject(method = "(Lnet/minecraft/world/World;II)V", at = @At("RETURN")) - private void onInit(World p_i1995_1_, int p_i1995_2_, int p_i1995_3_, CallbackInfo ci) { - visibility = new VisGraph[16]; - for (int i = 0; i < 16; ++i) { - visibility[i] = new VisGraph(); - } - } - - @Override - public VisGraph[] getVisibility() { - return visibility; - } - - @Unique - boolean checkPosSolid(int x, int y, int z, Block block) { - - if (y > 255 || y < 0) - return false; - if (block == null) { - block = getBlock(x, y, z); - } - VisGraph chunk = this.visibility[y >> 4]; - y &= 15; - - chunk.setOpaque(x, y, z, block.isOpaqueCube()); - return chunk.isDirty(); - } - - @Inject(method = "func_150807_a", at = @At("RETURN")) - private void onSetBlock(int x, int y, int z, Block block, int meta, CallbackInfoReturnable cir) { - if(cir.getReturnValue() && this.worldObj.isRemote && checkPosSolid(x & 15, y, z & 15, block)) { - worker.modified.add((Chunk)(Object)this); - } - } - - @Inject(method = "fillChunk", at = @At("RETURN")) - private void onFillChunk(byte[] p_76607_1_, int p_76607_2_, int p_76607_3_, boolean p_76607_4_, CallbackInfo ci) { - worker.loaded.add((Chunk)(Object)this); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinEntityRenderer.java deleted file mode 100644 index 8f23d95ea..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinEntityRenderer.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.occlusion; - -import net.minecraft.client.renderer.EntityRenderer; -import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(value = EntityRenderer.class) -public class MixinEntityRenderer { - - /** - * @reason MixinRenderGlobal#performCullingUpdates needs to know the chunk update deadline and the partial tick time - */ - @Inject(method = "renderWorld", at = @At("HEAD")) - private void getRendererUpdateDeadline(float partialTickTime, long chunkUpdateDeadline, CallbackInfo ci) { - OcclusionHelpers.chunkUpdateDeadline = chunkUpdateDeadline; - OcclusionHelpers.partialTickTime = partialTickTime; - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinGuiVideoSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinGuiVideoSettings.java deleted file mode 100644 index 360f8b57b..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinGuiVideoSettings.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.occlusion; - -import net.minecraft.client.gui.GuiVideoSettings; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(GuiVideoSettings.class) -public class MixinGuiVideoSettings { - @Redirect(method = "initGui", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/OpenGlHelper;field_153197_d:Z")) - private boolean neverUseAdvancedGl() { - return false; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinRenderGlobal.java deleted file mode 100644 index 7cef7b010..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinRenderGlobal.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.occlusion; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.WorldClient; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.renderer.culling.ICamera; -import net.minecraft.client.renderer.entity.RenderManager; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; -import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; -import org.embeddedt.archaicfix.occlusion.OcclusionRenderer; -import org.embeddedt.archaicfix.occlusion.OcclusionWorker; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.Comparator; -import java.util.List; - -@Mixin(value = RenderGlobal.class, priority = -2) -public abstract class MixinRenderGlobal { - /** - * Queue a renderer to be updated. - */ - @Inject(method = "markBlocksForUpdate", at = @At("HEAD"), cancellable = true) - private void handleOffthreadUpdate(int x1, int y1, int z1, int x2, int y2, int z2, CallbackInfo ci) { - ci.cancel(); - OcclusionHelpers.renderer.handleOffthreadUpdate(x1, y1, z1, x2, y2, z2); - } - - @Redirect(method = "renderEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)Z")) - private boolean skipRenderingIfNotVisible(RenderManager instance, Entity entity, float tick) { - return OcclusionHelpers.renderer.skipRenderingIfNotVisible(instance, entity, tick); - } - - /** - * @author skyboy, embeddedt - * @reason Include information on occlusion - */ - @Overwrite - public String getDebugInfoRenders() { - return OcclusionHelpers.renderer.getDebugInfoRenders(); - } - - @Inject(method = "", at = @At("RETURN")) - private void initBetterLists(Minecraft p_i1249_1_, CallbackInfo ci) { - OcclusionHelpers.renderer = new OcclusionRenderer((RenderGlobal)(Object)this); - OcclusionHelpers.renderer.initBetterLists(); - } - - @Redirect(method = "loadRenderers", at = @At(value = "INVOKE", target = "Ljava/util/List;clear()V", ordinal = 0)) - private void clearRendererUpdateQueue(List instance) { - OcclusionHelpers.renderer.clearRendererUpdateQueue(instance); - } - - @Redirect(method = { "loadRenderers", "markRenderersForNewPosition" }, at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", ordinal = 0)) - private boolean sortAndAddRendererUpdateQueue(List instance, Object renderer) { - return OcclusionHelpers.renderer.sortAndAddRendererUpdateQueue(instance, renderer); - } - - @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/OpenGlCapsChecker;checkARBOcclusion()Z")) - private boolean neverEnableOcclusion() { - return false; - } - - @Inject(method = "updateRenderers", at = @At("HEAD"), cancellable = true) - private void performCullingUpdates(EntityLivingBase view, boolean p_72716_2_, CallbackInfoReturnable cir) { - OcclusionHelpers.renderer.performCullingUpdates(view, p_72716_2_); - cir.setReturnValue(true); - } - - @Inject(method = "setWorldAndLoadRenderers", at = @At("HEAD")) - private void setWorkerWorld(WorldClient world, CallbackInfo ci) { - OcclusionHelpers.worker.setWorld((RenderGlobal)(Object)this, world); - } - - @Inject(method = "loadRenderers", at = @At("HEAD")) - private void resetLoadedRenderers(CallbackInfo ci) { - OcclusionHelpers.renderer.resetLoadedRenderers(); - } - - @Inject(method = "loadRenderers", at = @At("TAIL")) - private void resetOcclusionWorker(CallbackInfo ci) { - OcclusionHelpers.renderer.resetOcclusionWorker(); - } - - @Redirect(method = "loadRenderers", at = @At(value = "INVOKE", target = "Ljava/util/Arrays;sort([Ljava/lang/Object;Ljava/util/Comparator;)V", ordinal = 0)) - private void skipSort2(Object[] ts, Comparator comparator) { - - } - - @Redirect(method = "loadRenderers", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/WorldRenderer;markDirty()V", ordinal = 0)) - private void markRendererInvisible(WorldRenderer instance) { - OcclusionHelpers.renderer.markRendererInvisible(instance); - } - - @Redirect(method = "markRenderersForNewPosition", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/WorldRenderer;setPosition(III)V")) - private void setPositionAndMarkInvisible(WorldRenderer wr, int x, int y, int z) { - OcclusionHelpers.renderer.setPositionAndMarkInvisible(wr, x, y, z); - } - - @Inject(method = "markRenderersForNewPosition", at = @At("TAIL")) - private void runWorker(int p_72722_1_, int p_72722_2_, int p_72722_3_, CallbackInfo ci) { - OcclusionHelpers.renderer.runWorker(p_72722_1_, p_72722_2_, p_72722_3_); - } - - /** - * @author skyboy, embeddedt - * @reason Update logic - */ - @Overwrite - public int sortAndRender(EntityLivingBase view, int pass, double tick) { - return OcclusionHelpers.renderer.sortAndRender(view, pass, tick); - } - - /** - * @author embeddedt, skyboy - * @reason occlusion culling - */ - @Overwrite - public int renderSortedRenderers(int start, int end, int pass, double tick) { - return OcclusionHelpers.renderer.sortAndRender(start, end, pass, tick); - } - - /** - * @author makamys - * @reason Integrate with the logic in {@link OcclusionWorker#run(boolean)}. - */ - @Overwrite - public void clipRenderersByFrustum(ICamera p_72729_1_, float p_72729_2_) { - OcclusionHelpers.renderer.clipRenderersByFrustum(p_72729_1_, p_72729_2_); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java deleted file mode 100644 index b61799bb1..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/occlusion/MixinWorldRenderer.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.occlusion; - -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.shader.TesselatorVertexState; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.world.World; -import net.minecraft.world.chunk.EmptyChunk; -import org.embeddedt.archaicfix.occlusion.interfaces.IWorldRenderer; -import org.embeddedt.archaicfix.occlusion.OcclusionWorker; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -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.CallbackInfo; - -import java.util.List; - -@Mixin(WorldRenderer.class) -public class MixinWorldRenderer implements IWorldRenderer { - @Shadow public boolean isWaitingOnOcclusionQuery; - - @Shadow public World worldObj; - - @Shadow public int posX; - - @Shadow public int posZ; - - @Shadow public List tileEntityRenderers; - - @Shadow private List tileEntities; - - @Shadow public boolean needsUpdate; - - @Shadow public boolean isInitialized; - - @Shadow private int bytesDrawn; - - @Shadow private TesselatorVertexState vertexState; - - @Unique private boolean arch$isInUpdateList; - - @Unique private OcclusionWorker.CullInfo arch$cullInfo; - - @Inject(method = "*", at = @At("RETURN")) - private void init(CallbackInfo ci) { - this.arch$cullInfo = new OcclusionWorker.CullInfo(); - } - - @Inject(method = "markDirty", at = @At("TAIL")) - private void resetOcclusionFlag(CallbackInfo ci) { - this.isWaitingOnOcclusionQuery = false; - } - - @Inject(method = "updateRenderer", at = @At(value = "FIELD", opcode = Opcodes.PUTSTATIC, target = "Lnet/minecraft/world/chunk/Chunk;isLit:Z", ordinal = 0), cancellable = true) - private void bailOnEmptyChunk(EntityLivingBase view, CallbackInfo ci) { - if(worldObj.getChunkFromBlockCoords(posX, posZ) instanceof EmptyChunk) { - if (!tileEntityRenderers.isEmpty()) { - tileEntities.removeAll(tileEntityRenderers); - tileEntityRenderers.clear(); - } - needsUpdate = true; - isInitialized = false; - bytesDrawn = 0; - vertexState = null; - ci.cancel(); - } - } - - @Override - public boolean arch$isInUpdateList() { - return arch$isInUpdateList; - } - - @Override - public void arch$setInUpdateList(boolean b) { - arch$isInUpdateList = b; - } - - @Override - public OcclusionWorker.CullInfo arch$getCullInfo() { - return arch$cullInfo; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinRenderBlocks.java deleted file mode 100644 index d2013cd98..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinRenderBlocks.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.threadedupdates; - -import net.minecraft.block.Block; -import net.minecraft.client.renderer.RenderBlocks; -import net.minecraft.client.renderer.Tessellator; -import net.minecraftforge.client.ForgeHooksClient; -import org.embeddedt.archaicfix.threadedupdates.IRendererUpdateResultHolder; -import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; -import org.embeddedt.archaicfix.threadedupdates.api.ThreadedChunkUpdates; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -@Mixin(RenderBlocks.class) -public class MixinRenderBlocks { - - @Inject(method = "renderBlockByRenderType", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;setBlockBoundsBasedOnState(Lnet/minecraft/world/IBlockAccess;III)V"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) - private void cancelRenderDelegatedToDifferentThread(Block block, int x, int y, int z, CallbackInfoReturnable cir, int renderType) { - int pass = ForgeHooksClient.getWorldRenderPass(); - boolean mainThread = Thread.currentThread() == ThreadedChunkUpdateHelper.MAIN_THREAD; - - ThreadedChunkUpdateHelper.UpdateTask task = mainThread ? ((IRendererUpdateResultHolder)ThreadedChunkUpdateHelper.lastWorldRenderer).arch$getRendererUpdateTask() : null; - - boolean offThreadBlock = ThreadedChunkUpdateHelper.canBlockBeRenderedOffThread(block, pass, renderType) - && !(task != null && task.cancelled) && (!mainThread || ThreadedChunkUpdateHelper.renderBlocksStack.getLevel() == 1); - if ((mainThread ? pass >= 0 : true) && (mainThread ? offThreadBlock : !offThreadBlock)) { - // Cancel rendering block if it's delegated to a different thread. - cir.setReturnValue(mainThread ? task.result[pass].renderedSomething : false); - } - } - - @Inject(method = "renderBlockByRenderType", at = @At("HEAD")) - private void pushStack(CallbackInfoReturnable cir) { - ThreadedChunkUpdateHelper.renderBlocksStack.push(); - } - - @Inject(method = "renderBlockByRenderType", at = @At("RETURN")) - private void popStack(CallbackInfoReturnable cir) { - ThreadedChunkUpdateHelper.renderBlocksStack.pop(); - } - - @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;instance:Lnet/minecraft/client/renderer/Tessellator;")) - private Tessellator modifyTessellatorAccess() { - return ThreadedChunkUpdates.getThreadTessellator(); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator.java deleted file mode 100644 index 0f445c800..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.threadedupdates; - -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.shader.TesselatorVertexState; -import org.embeddedt.archaicfix.threadedupdates.ICapturableTessellator; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.util.Arrays; - -@Mixin(value = Tessellator.class, priority = 1001) -public abstract class MixinTessellator implements ICapturableTessellator { - - @Shadow - private int[] rawBuffer; - - @Shadow - private int rawBufferIndex; - - @Shadow - private int vertexCount; - - @Shadow protected abstract void reset(); - - @Shadow private boolean isDrawing; - - @Shadow(remap = false) private int rawBufferSize; - - @Shadow private boolean hasTexture; - - @Shadow private boolean hasBrightness; - - @Shadow private boolean hasColor; - - @Shadow private boolean hasNormals; - - @Override - public TesselatorVertexState arch$getUnsortedVertexState() { - if(vertexCount < 1) { - return null; - } - return new TesselatorVertexState(Arrays.copyOf(rawBuffer, rawBufferIndex), this.rawBufferIndex, this.vertexCount, this.hasTexture, this.hasBrightness, this.hasNormals, this.hasColor); - } - - @Override - public void arch$addTessellatorVertexState(TesselatorVertexState state) throws IllegalStateException { - if(state == null) return; - // TODO check if draw mode is the same - - hasTexture |= state.getHasTexture(); - hasBrightness |= state.getHasBrightness(); - hasColor |= state.getHasColor(); - hasNormals |= state.getHasNormals(); - - while(rawBufferSize < rawBufferIndex + state.getRawBuffer().length) { - rawBufferSize *= 2; - } - if(rawBufferSize > rawBuffer.length) { - rawBuffer = Arrays.copyOf(rawBuffer, rawBufferSize); - } - - System.arraycopy(state.getRawBuffer(), 0, rawBuffer, rawBufferIndex, state.getRawBufferIndex()); - rawBufferIndex += state.getRawBufferIndex(); - vertexCount += state.getVertexCount(); - } - - @Override - public void discard() { - isDrawing = false; - reset(); - } - - /** @reason Allow using multiple tessellator instances concurrently by removing static field access in alternate - * instances. */ - @Redirect(method = "reset", at = @At(value = "INVOKE", target = "Ljava/nio/ByteBuffer;clear()Ljava/nio/Buffer;")) - private Buffer removeStaticBufferAccessOutsideSingleton(ByteBuffer buffer) { - if(((Object)this) == Tessellator.instance) { - return buffer.clear(); - } - return buffer; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator_Debug.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator_Debug.java deleted file mode 100644 index b6f37933d..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinTessellator_Debug.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.threadedupdates; - -import net.minecraft.client.renderer.Tessellator; -import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; -import org.spongepowered.asm.mixin.Mixin; -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.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(value = Tessellator.class) -public abstract class MixinTessellator_Debug { - - @Inject(method = {"setVertexState", "func_154352_a", "setColorRGBA_F", "setColorRGBA", "startDrawing", "addTranslation", "setTranslation", "addVertexWithUV", "setNormal", "setColorOpaque", "addVertex", "setColorOpaque_I", "reset", "setBrightness", "startDrawingQuads", "disableColor", "setColorRGBA_I", "setTextureUV", "setColorOpaque_F"}, at = @At("HEAD")) - private void verifyThreadIsCorrect(CallbackInfo ci) { - verifyThreadIsCorrect(); - } - - @Inject(method = {"getVertexState", "draw"}, at = @At("HEAD")) - private void verifyThreadIsCorrect(CallbackInfoReturnable cir) { - verifyThreadIsCorrect(); - } - - @Unique - private void verifyThreadIsCorrect() { - if(((Object)this) == Tessellator.instance) { - if(ThreadedChunkUpdateHelper.MAIN_THREAD != null && Thread.currentThread() != ThreadedChunkUpdateHelper.MAIN_THREAD) { - throw new IllegalStateException("Tried to access main tessellator from non-main thread " + Thread.currentThread().getName()); - } - } - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinWorldRenderer.java deleted file mode 100644 index 62ab94486..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/threadedupdates/MixinWorldRenderer.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.threadedupdates; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.RenderBlocks; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.world.ChunkCache; -import org.embeddedt.archaicfix.threadedupdates.ICapturableTessellator; -import org.embeddedt.archaicfix.threadedupdates.IRendererUpdateResultHolder; -import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import java.util.HashSet; - -@Mixin(WorldRenderer.class) -public class MixinWorldRenderer implements IRendererUpdateResultHolder { - - private ThreadedChunkUpdateHelper.UpdateTask arch$updateTask; - - @Inject(method = "updateRenderer", at = @At("HEAD")) - private void setLastWorldRendererSingleton(CallbackInfo ci) { - ThreadedChunkUpdateHelper.lastWorldRenderer = ((WorldRenderer)(Object)this); - } - - @Inject(method = "updateRenderer", at = @At(value="INVOKE", target = "Lnet/minecraft/client/renderer/WorldRenderer;postRenderBlocks(ILnet/minecraft/entity/EntityLivingBase;)V"), locals=LocalCapture.CAPTURE_FAILHARD) - private void loadTessellationResult(EntityLivingBase cameraEntity, CallbackInfo ci, int i, int j, int k, int l, int i1, int j1, HashSet hashset, Minecraft minecraft, EntityLivingBase entitylivingbase1, int l1, int i2, int j2, byte b0, ChunkCache chunkcache, RenderBlocks renderblocks, int k2) { - int pass = k2; - if(!arch$getRendererUpdateTask().cancelled) { - ((ICapturableTessellator) Tessellator.instance).arch$addTessellatorVertexState(arch$getRendererUpdateTask().result[pass].renderedQuads); - } - } - - @Inject(method = "updateRenderer", at = @At(value="INVOKE", target = "Lnet/minecraft/client/renderer/RenderBlocks;renderBlockByRenderType(Lnet/minecraft/block/Block;III)Z")) - private void resetStack(CallbackInfo ci) { - // Make sure the stack doesn't leak - ThreadedChunkUpdateHelper.renderBlocksStack.reset(); - } - - @Override - public ThreadedChunkUpdateHelper.UpdateTask arch$getRendererUpdateTask() { - if(arch$updateTask == null) { - arch$updateTask = new ThreadedChunkUpdateHelper.UpdateTask(); - } - return arch$updateTask; - } - - @Inject(method = "markDirty", at = @At("RETURN")) - private void notifyDirty(CallbackInfo ci) { - ThreadedChunkUpdateHelper.instance.onWorldRendererDirty((WorldRenderer)(Object)this); - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java b/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java index c7fd92506..4f4c1b323 100644 --- a/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java +++ b/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java @@ -11,11 +11,8 @@ import cpw.mods.fml.common.event.FMLServerStartingEvent; import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper; -import cpw.mods.fml.relauncher.Side; import net.minecraftforge.common.MinecraftForge; -import org.embeddedt.archaicfix.config.ArchaicConfig; import org.embeddedt.archaicfix.proxy.CommonProxy; -import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; @Mod(modid = ArchaicFix.MODID, version = ArchaicFix.VERSION, dependencies = "required-after:gtnhmixins@[2.0.0,);", guiFactory = "org.embeddedt.archaicfix.config.ArchaicGuiConfigFactory") public class ArchaicFix @@ -51,10 +48,6 @@ public void preinit(FMLPreInitializationEvent event) { @EventHandler public void init(FMLInitializationEvent event) { - if(event.getSide() == Side.CLIENT && (ArchaicConfig.enableThreadedChunkUpdates && ArchaicConfig.enableOcclusionTweaks)) { - ThreadedChunkUpdateHelper.instance = new ThreadedChunkUpdateHelper(); - ThreadedChunkUpdateHelper.instance.init(); - } } @EventHandler diff --git a/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java b/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java index eb771862e..bf820bb46 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java +++ b/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java @@ -2,26 +2,6 @@ @Config(modid = "archaicfix") public class ArchaicConfig { - @Config.Comment("Enables the 1.8-style occlusion culling originally developed by CoFHTweaks.") - @Config.DefaultBoolean(true) - @Config.RequiresMcRestart - public static boolean enableOcclusionTweaks; - - @Config.Comment("EXPERIMENTAL: Enables multi-threaded chunk updating. At the moment it only works if enableOcclusionTweaks is turned on. Doesn't currently work with Shaders") - @Config.DefaultBoolean(false) - @Config.RequiresMcRestart - public static boolean enableThreadedChunkUpdates; - - @Config.Comment("The number of threads to use for chunk building. The default is 1, which shouldn't be any laggier than vanilla but will reduce stutter. If you have a lot of cores increasing this may be beneficial.") - @Config.DefaultInt(1) - @Config.RangeInt(min = 1) - @Config.RequiresMcRestart - public static int numChunkUpdateThreads; - - @Config.Comment("Changes the enableThreadedChunkUpdates option to never wait for chunk updates. Improves framerate when blocks are placed or destroyed, at the cost of introducing visual delay. This is analogous to 1.18's 'Chunk Builder' option, false meaning 'Fully Blocking', and true meaning 'Threaded'.") - @Config.DefaultBoolean(false) - public static boolean disableBlockingChunkUpdates; - @Config.DefaultBoolean(true) public static boolean hideDownloadingTerrainScreen; diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/BasicDistanceSorter.java b/src/main/java/org/embeddedt/archaicfix/occlusion/BasicDistanceSorter.java deleted file mode 100644 index 44d3eac7a..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/BasicDistanceSorter.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.embeddedt.archaicfix.occlusion; - -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.entity.EntityLivingBase; -import org.embeddedt.archaicfix.helpers.WorldRendererDistanceHelper; - -import java.util.Comparator; - -public class BasicDistanceSorter implements Comparator { - private final EntityLivingBase renderViewEntity; - - public BasicDistanceSorter(EntityLivingBase renderViewEntity) { - this.renderViewEntity = renderViewEntity; - } - - @Override - public int compare(WorldRenderer wr1, WorldRenderer wr2) { - return (int)((WorldRendererDistanceHelper.betterDistanceSquared(renderViewEntity, wr1) - WorldRendererDistanceHelper.betterDistanceSquared(renderViewEntity, wr2)) * 1024D); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java b/src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java deleted file mode 100644 index 88345d111..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/CameraInfo.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.embeddedt.archaicfix.occlusion; - -import lombok.Getter; -import net.minecraft.client.renderer.ActiveRenderInfo; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.util.MathHelper; - -public class CameraInfo { - - @Getter - private static final CameraInfo instance = new CameraInfo(); - - /** The transformed eye position, which takes the third person camera offset into account. */ - @Getter - private double x, y, z; - /** The untransformed eye position, which is not affected by the third person camera. It's always at the player character's eyes. */ - @Getter - private double eyeX, eyeY, eyeZ; - /** The chunk coordinates of the transformed eye position, which takes the third person camera offset into account. */ - @Getter - private int chunkCoordX, chunkCoordY, chunkCoordZ; - - public void update(EntityLivingBase view, double tick) { - eyeX = view.lastTickPosX + (view.posX - view.lastTickPosX) * tick; - eyeY = view.lastTickPosY + (view.posY - view.lastTickPosY) * tick; - eyeZ = view.lastTickPosZ + (view.posZ - view.lastTickPosZ) * tick; - - x = eyeX + ActiveRenderInfo.objectX; - y = eyeY + ActiveRenderInfo.objectY; - z = eyeZ + ActiveRenderInfo.objectZ; - - chunkCoordX = MathHelper.floor_double(x / 16.0); - chunkCoordY = MathHelper.floor_double(y / 16.0); - chunkCoordZ = MathHelper.floor_double(z / 16.0); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java b/src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java deleted file mode 100644 index b8e8d55b1..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/ChunkThread.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.embeddedt.archaicfix.occlusion; - -import net.minecraft.world.chunk.Chunk; -import org.embeddedt.archaicfix.occlusion.interfaces.ICulledChunk; -import org.embeddedt.archaicfix.occlusion.util.LinkedHashList; -import org.embeddedt.archaicfix.occlusion.util.SynchronizedIdentityLinkedHashList; - -public class ChunkThread extends Thread { - - public ChunkThread() { - super("Chunk Worker"); - } - - public LinkedHashList loaded = new SynchronizedIdentityLinkedHashList<>(); - public LinkedHashList modified = new SynchronizedIdentityLinkedHashList<>(); - - @Override - public void run() { - - for (;;) { - int i = 0; - boolean work = false; - for (; !loaded.isEmpty(); ++i) { - Chunk chunk = ((ICulledChunk)loaded.shift()).buildCulledSides(); - if (chunk != null) { - modified.add(chunk); - work = true; - } - if ((i & 3) == 0) { - Thread.yield(); - } - } - for (i = 0; !modified.isEmpty(); ++i) { - Chunk chunk = modified.shift(); - if (loaded.contains(chunk)) { - continue; - } - for (VisGraph graph : ((ICulledChunk)chunk).getVisibility()) { - if (graph.isDirty()) { - long a = graph.getVisibility(); - graph.computeVisibility(); - work |= a != graph.getVisibility(); - } - } - if ((i & 7) == 0) { - Thread.yield(); - } - } - OcclusionHelpers.worker.dirty = work; - try { - Thread.sleep(30); - } catch (InterruptedException ignored) {} - } - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java b/src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java deleted file mode 100644 index 7e91f0c50..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/DefaultRendererUpdateOrderProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.embeddedt.archaicfix.occlusion; - -import net.minecraft.client.renderer.WorldRenderer; -import org.embeddedt.archaicfix.occlusion.interfaces.IRendererUpdateOrderProvider; - -import java.util.List; - -public class DefaultRendererUpdateOrderProvider implements IRendererUpdateOrderProvider { - - private int lastUpdatedIndex = 0; - - @Override - public void prepare(List worldRenderersToUpdateList) { - lastUpdatedIndex = 0; - } - - @Override - public boolean hasNext(List worldRenderersToUpdateList) { - return lastUpdatedIndex < worldRenderersToUpdateList.size(); - } - - @Override - public WorldRenderer next(List worldRenderersToUpdateList) { - return worldRenderersToUpdateList.get(lastUpdatedIndex++); - } - - @Override - public void cleanup(List worldRenderersToUpdateList) { - worldRenderersToUpdateList.subList(0, lastUpdatedIndex).clear(); - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/LICENSE b/src/main/java/org/embeddedt/archaicfix/occlusion/LICENSE deleted file mode 100644 index b31b92c8b..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/LICENSE +++ /dev/null @@ -1,51 +0,0 @@ -CoFH "Don't Be a Jerk" License -==================================== -#### Okay, so here's the deal. - -You'll notice that this repository does not have a license! By default, that means "All Rights Reserved." - -That is indeed the case. All rights reserved, as far as the code is concerned. - -Art and sound assets are released under the Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0), a summary of which can be found at: https://creativecommons.org/licenses/by-sa/4.0/ - -©2012-2015 Cult of the Full Hub / Team CoFH / CoFH - -#### Homepage - -[TeamCoFH Home Page](http://teamcofh.com/) - -[IRC #ThermalExpansion on esper.net](http://webchat.esper.net/?nick=ThermalWiki....&channels=ThermalExpansion) - -#### Notice - -Contribution to this repository means that you are granting us rights over the code that you choose to contribute. If you do not agree with that, do not contribute. - -So, why is this here? Well, the rights are reserved, but what that really means is that we choose what to do with the rights. So here you go. - -#### You CAN -- Fork and modify the code. -- Submit Pull Requests to this repository. -- Copy portions of this code for use in other projects. -- Write your own code that uses this code as a dependency. (addon mods!) - -#### You CANNOT -- Redistribute this in its entirety as source or compiled code. -- Create or distribute code which contains 50% or more Functionally Equivalent Statements* from this repository. - -#### You MUST -- Maintain a visible repository of your code which is inspired by, derived from, or copied from this code. Basically, if you use it, pay it forward. You keep rights to your OWN code, but you still must make your source visible. -- Not be a jerk**. Seriously, if you're a jerk, you can't use this code. That's part of the agreement. - -#### Notes, License & Copyright - -*A Functionally Equivalent Statement is a code fragment which, regardless of whitespace and object names, achieves the same result. Basically you can't copy the code, rename the variables, add whitespace and say it's different. It's not. - -**A jerk is anyone who attempts to or intends to claim partial or total ownership of the original or repackaged code and/or attempts to or intends to redistribute original or repackaged code without prior express written permission from the owners (CoFH). - -Essentially, take this and learn from it! Create addon mods that depend on it! If you see something we can improve, tell us. Submit a Pull Request. The one catch: don't steal! A lot of effort has gone into this, and if you were to take this and call it your own, you'd basically be a big jerk. - -Don't be a jerk. - -See LICENSE-CODE.txt and LICENSE-ART.txt for license information. - -©2012-2015 Cult of the Full Hub / Team CoFH / CoFH \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java deleted file mode 100644 index f437a239c..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionHelpers.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.embeddedt.archaicfix.occlusion; - -import org.embeddedt.archaicfix.occlusion.util.IntStack; - -public class OcclusionHelpers { - public static OcclusionWorker worker; - public static OcclusionRenderer renderer; - public static long chunkUpdateDeadline; - public static float partialTickTime; - - public static final boolean DEBUG_ALWAYS_RUN_OCCLUSION = Boolean.parseBoolean(System.getProperty("archaicfix.debug.alwaysRunOcclusion", "false")); - public static final boolean DEBUG_PRINT_QUEUE_ITERATIONS = Boolean.parseBoolean(System.getProperty("archaicfix.debug.printQueueIterations", "false")); - /** Update up to 1 chunk per frame when the framerate is uncapped, vanilla-style. */ - public static final boolean DEBUG_LAZY_CHUNK_UPDATES = Boolean.parseBoolean(System.getProperty("archaicfix.debug.lazyChunkUpdates", "false")); - /** Disable speeding up chunk updates when the camera is static. */ - public static final boolean DEBUG_NO_UPDATE_ACCELERATION = Boolean.parseBoolean(System.getProperty("archaicfix.debug.noUpdateAcceleration", "false")); - - public static void init() { - worker = new OcclusionWorker(); - } - - public static IntStack deferredAreas = new IntStack(6 * 1024); - - public static synchronized void updateArea(int x, int y, int z, int x2, int y2, int z2) { - // backwards so it's more logical to extract - deferredAreas.add(z2); - deferredAreas.add(y2); - deferredAreas.add(x2); - deferredAreas.add(z); - deferredAreas.add(y); - deferredAreas.add(x); - } - - public static synchronized void processUpdate(OcclusionRenderer render) { - if (deferredAreas.isEmpty()) { - return; // guard against multiple instances (no compatibility with mods that do this to us) - } - - int x = deferredAreas.pop(), y = deferredAreas.pop(), z = deferredAreas.pop(); - int x2 = deferredAreas.pop(), y2 = deferredAreas.pop(), z2 = deferredAreas.pop(); - render.internalMarkBlockUpdate(x, y, z, x2, y2, z2); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java deleted file mode 100644 index b53ec2b2f..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionRenderer.java +++ /dev/null @@ -1,577 +0,0 @@ -package org.embeddedt.archaicfix.occlusion; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiVideoSettings; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.RenderList; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.renderer.culling.ICamera; -import net.minecraft.client.renderer.entity.RenderManager; -import net.minecraft.client.util.RenderDistanceSorter; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.MathHelper; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.EmptyChunk; -import org.embeddedt.archaicfix.helpers.WorldRendererDistanceHelper; -import org.embeddedt.archaicfix.occlusion.interfaces.ICulledChunk; -import org.embeddedt.archaicfix.occlusion.interfaces.IRenderGlobalListener; -import org.embeddedt.archaicfix.occlusion.interfaces.IRendererUpdateOrderProvider; -import org.embeddedt.archaicfix.occlusion.interfaces.IWorldRenderer; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public class OcclusionRenderer { - - private final Minecraft mc; - private final RenderGlobal rg; - - private Thread clientThread; - - private ArrayList worldRenderersToUpdateList; - - private double prevRenderX, prevRenderY, prevRenderZ; - private int cameraStaticTime; - - private short alphaSortProgress = 0; - private byte frameCounter, frameTarget; - - private int renderersNeedUpdate; - - private boolean resortUpdateList; - - private IRendererUpdateOrderProvider rendererUpdateOrderProvider; - private List eventListeners; - - /* Make sure other threads can see changes to this */ - private volatile boolean deferNewRenderUpdates; - - public OcclusionRenderer(RenderGlobal renderGlobal) { - this.rg = renderGlobal; - this.mc = renderGlobal.mc; - } - - public RenderGlobal getRenderGlobal() { - return rg; - } - - /** - * If the update list is not queued for a full resort (e.g. when the player moves or renderers have their positions - * changed), uses binary search to add the renderer in the update queue at the appropriate place. Otherwise, - * the renderer is just added to the end of the list. - * @param wr renderer to add to the list - */ - private void addRendererToUpdateQueue(WorldRenderer wr) { - if(!((IWorldRenderer)wr).arch$isInUpdateList()) { - ((IWorldRenderer)wr).arch$setInUpdateList(true); - if(mc.renderViewEntity == null || resortUpdateList) { - worldRenderersToUpdateList.add(wr); - resortUpdateList = true; - return; - } - if(!worldRenderersToUpdateList.isEmpty()) { - double targetDistance = WorldRendererDistanceHelper.betterDistanceSquared(mc.renderViewEntity, wr); - int low = 0; - int high = worldRenderersToUpdateList.size() - 1; - int finalIndex = -1; - while(low <= high) { - int mid = low + (high - low) / 2; - WorldRenderer other = worldRenderersToUpdateList.get(mid); - double otherDistance = WorldRendererDistanceHelper.betterDistanceSquared(mc.renderViewEntity, other); - if(otherDistance < targetDistance) { - low = mid + 1; - } else if(otherDistance > targetDistance) { - high = mid - 1; - } else { - finalIndex = mid; - break; - } - } - if(finalIndex == -1) - finalIndex = high; - worldRenderersToUpdateList.add(finalIndex+1, wr); - } else { - worldRenderersToUpdateList.add(wr); - } - } - } - - public void handleOffthreadUpdate(int x1, int y1, int z1, int x2, int y2, int z2) { - if(deferNewRenderUpdates || Thread.currentThread() != clientThread) { - OcclusionHelpers.updateArea(x1, y1, z1, x2, y2, z2); - } else { - internalMarkBlockUpdate(x1, y1, z1, x2, y2, z2); - } - } - - public void internalMarkBlockUpdate(int x1, int y1, int z1, int x2, int y2, int z2) { - int xStart = MathHelper.bucketInt(x1, 16); - int yStart = MathHelper.bucketInt(y1, 16); - int zStart = MathHelper.bucketInt(z1, 16); - int xEnd = MathHelper.bucketInt(x2, 16); - int yEnd = MathHelper.bucketInt(y2, 16); - int zEnd = MathHelper.bucketInt(z2, 16); - - final int width = rg.renderChunksWide; - final int height = rg.renderChunksTall; - final int depth = rg.renderChunksDeep; - final WorldRenderer[] worldRenderers = rg.worldRenderers; - boolean rebuild = false; - - for (int i = xStart; i <= xEnd; ++i) { - int x = i % width; - x += width & (x >> 31); - - for (int j = yStart; j <= yEnd; ++j) { - int y = j % height; - y += height & (y >> 31); - - for (int k = zStart; k <= zEnd; ++k) { - int z = k % depth; - z += depth & (z >> 31); - - int k4 = (z * height + y) * width + x; - WorldRenderer worldrenderer = worldRenderers[k4]; - - if (!worldrenderer.needsUpdate || (worldrenderer.isVisible && !((IWorldRenderer)worldrenderer).arch$isInUpdateList())) { - worldrenderer.markDirty(); - Chunk chunk = rg.theWorld.getChunkFromBlockCoords(worldrenderer.posX, worldrenderer.posZ); - if (((ICulledChunk) chunk).getVisibility()[worldrenderer.posY >> 4].isRenderDirty()) { - rebuild = true; - } - addRendererToUpdateQueue(worldrenderer); - } else { - for(IRenderGlobalListener l : eventListeners) l.onDirtyRendererChanged(worldrenderer); - } - } - } - } - - if (rebuild) { - OcclusionHelpers.worker.dirty = true; - } - } - - public boolean skipRenderingIfNotVisible(RenderManager instance, Entity entity, float tick) { - WorldRenderer rend = getRenderer(entity.posX, entity.posY, entity.posZ); - if (rend != null && !rend.isVisible) { - --rg.countEntitiesRendered; - ++rg.countEntitiesHidden; - return false; - } - return RenderManager.instance.renderEntitySimple(entity, tick); - } - - public String getDebugInfoRenders() { - return "C: " + rg.renderersBeingRendered + '/' + rg.renderersLoaded + '/' + rg.worldRenderers.length - + ". F: " + rg.renderersBeingClipped - + ", O: " + rg.renderersBeingOccluded - + ", E: " + rg.renderersSkippingRenderPass - + ", I: " + rg.dummyRenderInt - + "; U: " + renderersNeedUpdate - + ", N: " + rg.worldRenderersToUpdate.size(); - } - - public void initBetterLists() { - worldRenderersToUpdateList = new ArrayList<>(); - /* Make sure any vanilla code modifying the update queue crashes */ - rg.worldRenderersToUpdate = Collections.unmodifiableList(worldRenderersToUpdateList); - clientThread = Thread.currentThread(); - rendererUpdateOrderProvider = new DefaultRendererUpdateOrderProvider(); - eventListeners = new ArrayList<>(); - } - - public void clearRendererUpdateQueue(List instance) { - if(instance == rg.worldRenderersToUpdate) { - for(WorldRenderer wr : worldRenderersToUpdateList) { - ((IWorldRenderer)wr).arch$setInUpdateList(false); - } - worldRenderersToUpdateList.clear(); - } else { - throw new AssertionError("Transformer applied to the wrong List.clear method"); - } - } - - public boolean sortAndAddRendererUpdateQueue(List instance, Object renderer) { - if(instance == rg.worldRenderersToUpdate) { - addRendererToUpdateQueue((WorldRenderer)renderer); - return true; - } else { - throw new AssertionError("Transformer applied to the wrong List.clear method"); - } - } - - private static int fixPos(int pos, int amt) { - int r = Math.floorDiv(pos, 16) % amt; - if(r < 0) { - r += amt; - } - return r; - } - - public WorldRenderer getRenderer(int x, int y, int z) { - if ((y - 15) > rg.maxBlockY || y < rg.minBlockY || (x - 15) > rg.maxBlockX || x < rg.minBlockX || (z - 15) > rg.maxBlockZ || z < rg.minBlockZ) - return null; - - x = fixPos(x, rg.renderChunksWide); - y = fixPos(y, rg.renderChunksTall); - z = fixPos(z, rg.renderChunksDeep); - - return rg.worldRenderers[(z * rg.renderChunksTall + y) * rg.renderChunksWide + x]; - } - - public WorldRenderer getRenderer(double x, double y, double z) { - int X = MathHelper.floor_double(x); - int Y = MathHelper.floor_double(y); - int Z = MathHelper.floor_double(z); - return getRenderer(X, Y, Z); - } - - private boolean rebuildChunks(EntityLivingBase view, long deadline) { - int updateLimit = deadline == 0 ? 5 : Integer.MAX_VALUE; - int updates = 0; - - boolean spareTime = true; - deferNewRenderUpdates = true; - rendererUpdateOrderProvider.prepare(worldRenderersToUpdateList); - for (int c = 0; updates < updateLimit && rendererUpdateOrderProvider.hasNext(worldRenderersToUpdateList); ++c) { - WorldRenderer worldrenderer = rendererUpdateOrderProvider.next(worldRenderersToUpdateList); - - ((IWorldRenderer)worldrenderer).arch$setInUpdateList(false); - - if (!(worldrenderer.isInFrustum & worldrenderer.isVisible) && !OcclusionHelpers.DEBUG_LAZY_CHUNK_UPDATES) { - continue; - } - - boolean e = worldrenderer.isWaitingOnOcclusionQuery; - worldrenderer.updateRenderer(view); - worldrenderer.isVisible &= !e; - worldrenderer.isWaitingOnOcclusionQuery = worldrenderer.skipAllRenderPasses() || (mc.theWorld.getChunkFromBlockCoords(worldrenderer.posX, worldrenderer.posZ) instanceof EmptyChunk); - // can't add fields, re-use - - if(worldrenderer.distanceToEntitySquared(view) > 272f) { - updates++; - if(!worldrenderer.isWaitingOnOcclusionQuery || deadline != 0 || OcclusionHelpers.DEBUG_LAZY_CHUNK_UPDATES) { - long t = System.nanoTime(); - if (t > deadline) { - spareTime = false; - break; - } - } - } - } - rendererUpdateOrderProvider.cleanup(worldRenderersToUpdateList); - deferNewRenderUpdates = false; - return spareTime; - } - - public void performCullingUpdates(EntityLivingBase view, boolean p_72716_2_) { - rg.theWorld.theProfiler.startSection("deferred_updates"); - while(!OcclusionHelpers.deferredAreas.isEmpty()) { - OcclusionHelpers.processUpdate(this); - } - rg.theWorld.theProfiler.endStartSection("rebuild"); - - CameraInfo cam = CameraInfo.getInstance(); - - boolean cameraMoved = cam.getEyeX() != prevRenderX || cam.getEyeY() != prevRenderY || cam.getEyeZ() != prevRenderZ; - - prevRenderX = cam.getEyeX(); - prevRenderY = cam.getEyeY(); - prevRenderZ = cam.getEyeZ(); - - boolean cameraRotated = PreviousActiveRenderInfo.changed(); - - if(!cameraRotated && !cameraMoved) { - cameraStaticTime++; - } else { - cameraStaticTime = 0; - } - - /* - * Under certain scenarios (such as renderer.setPosition being called, or the player moving), renderers will] - * have their distance from the player change. We address that here by sorting the list. - */ - if(resortUpdateList) { - worldRenderersToUpdateList.sort(new BasicDistanceSorter(mc.renderViewEntity)); - resortUpdateList = false; - } - if (!rg.worldRenderersToUpdate.isEmpty()) { - ++frameCounter; - boolean doUpdateAcceleration = cameraStaticTime > 2 && !OcclusionHelpers.DEBUG_LAZY_CHUNK_UPDATES - && !OcclusionHelpers.DEBUG_NO_UPDATE_ACCELERATION; - /* If the camera is not moving, assume a deadline of 30 FPS. */ - rebuildChunks(view, !doUpdateAcceleration ? OcclusionHelpers.chunkUpdateDeadline - : mc.entityRenderer.renderEndNanoTime + (1_000_000_000L / 30L)); - } - - rg.theWorld.theProfiler.endStartSection("scan"); -// int yaw = MathHelper.floor_float(view.rotationYaw + 45) >> 4; -// int pitch = MathHelper.floor_float(view.rotationPitch + 45) >> 4; - if (OcclusionHelpers.worker.dirty || cameraRotated || OcclusionHelpers.DEBUG_ALWAYS_RUN_OCCLUSION) { - OcclusionHelpers.worker.run(true); - PreviousActiveRenderInfo.update(); - } - rg.theWorld.theProfiler.endSection(); - } - - public void resetLoadedRenderers() { - if(rg.theWorld != null) { - rg.renderersLoaded = 0; - } - } - - public void resetOcclusionWorker() { - updateRendererNeighbors(); - if(OcclusionHelpers.worker != null) { - OcclusionHelpers.worker.dirty = true; - } - } - - public void updateRendererNeighbors() { - if(rg.worldRenderers == null) return; - for(int i = 0; i < rg.worldRenderers.length; i++) { - WorldRenderer rend = rg.worldRenderers[i]; - OcclusionWorker.CullInfo ci = ((IWorldRenderer) rend).arch$getCullInfo(); - ci.wrIdx = i; - Chunk o = rend.worldObj.getChunkFromBlockCoords(rend.posX, rend.posZ); - VisGraph oSides = isChunkEmpty(o) ? OcclusionWorker.DUMMY : ((ICulledChunk)o).getVisibility()[rend.posY >> 4]; - ci.visGraph = oSides; - ci.vis = oSides.getVisibilityArray(); - for(EnumFacing dir : EnumFacing.values()) { - WorldRenderer neighbor = getRenderer( - rend.posX + dir.getFrontOffsetX() * 16, - rend.posY + dir.getFrontOffsetY() * 16, - rend.posZ + dir.getFrontOffsetZ() * 16 - ); - ci.setNeighbor(dir, neighbor == null ? null : ((IWorldRenderer)neighbor).arch$getCullInfo()); - } - } - } - - public void pushWorkerRenderer(WorldRenderer wr) { - if(!(mc.theWorld.getChunkFromBlockCoords(wr.posX, wr.posZ) instanceof EmptyChunk)) - addRendererToUpdateQueue(wr); - } - - public void markRendererInvisible(WorldRenderer instance) { - instance.isVisible = false; - instance.isInFrustum = false; - instance.markDirty(); - } - - public void setPositionAndMarkInvisible(WorldRenderer wr, int x, int y, int z) { - wr.setPosition(x, y, z); - if(((IWorldRenderer)wr).arch$isInUpdateList()) - resortUpdateList = true; - if(!wr.isInitialized) { - wr.isWaitingOnOcclusionQuery = false; - wr.isVisible = false; - } - } - - public void runWorker(int x, int y, int z) { - updateRendererNeighbors(); - OcclusionHelpers.worker.run(true); - } - - public int sortAndRender(EntityLivingBase view, int pass, double tick) { - CameraInfo cam = CameraInfo.getInstance(); - cam.update(view, tick); - - rg.theWorld.theProfiler.startSection("sortchunks"); - - if (this.mc.gameSettings.renderDistanceChunks != rg.renderDistanceChunks && !(this.mc.currentScreen instanceof GuiVideoSettings)) { - rg.loadRenderers(); - } - - WorldRenderer[] sortedWorldRenderers = rg.sortedWorldRenderers; - if (rg.renderersLoaded > 0) { - int e = rg.renderersLoaded - 10; - e &= e >> 31; - e += 10; - for (int j = 0; j < e; ++j) { - rg.worldRenderersCheckIndex = (rg.worldRenderersCheckIndex + 1) % rg.renderersLoaded; - WorldRenderer rend = sortedWorldRenderers[rg.worldRenderersCheckIndex]; - - if ((rend.isInFrustum && rend.isVisible) && (rend.needsUpdate || !rend.isInitialized) && !(this.mc.theWorld.getChunkFromBlockCoords(rend.posX, rend.posZ) instanceof EmptyChunk)) { - addRendererToUpdateQueue(rend); - } - } - } - - rg.theWorld.theProfiler.startSection("reposition_chunks"); - if (rg.prevChunkSortX != cam.getChunkCoordX() || rg.prevChunkSortY != cam.getChunkCoordY() || rg.prevChunkSortZ != cam.getChunkCoordZ()) { - rg.prevChunkSortX = cam.getChunkCoordX(); - rg.prevChunkSortY = cam.getChunkCoordY(); - rg.prevChunkSortZ = cam.getChunkCoordZ(); - rg.markRenderersForNewPosition(MathHelper.floor_double(cam.getX()), MathHelper.floor_double(cam.getY()), MathHelper.floor_double(cam.getZ())); - resortUpdateList = true; - } - rg.theWorld.theProfiler.endSection(); - - if(pass == 1){ - rg.theWorld.theProfiler.startSection("alpha_sort"); - if(distanceSquared(cam.getX(), cam.getY(), cam.getZ(), rg.prevRenderSortX, rg.prevRenderSortY, rg.prevRenderSortZ) > 1) { - rg.prevRenderSortX = cam.getX(); - rg.prevRenderSortY = cam.getY(); - rg.prevRenderSortZ = cam.getZ(); - - alphaSortProgress = 0; - } - - int amt = rg.renderersLoaded < 27 ? rg.renderersLoaded : Math.max(rg.renderersLoaded >> 1, 27); - if (alphaSortProgress < amt) { - int amountPerFrame = 1; - for (int i = 0; i < amountPerFrame && alphaSortProgress < amt; ++i) { - WorldRenderer r = sortedWorldRenderers[alphaSortProgress++]; - r.updateRendererSort(view); - } - } - rg.theWorld.theProfiler.endSection(); - } - - rg.theWorld.theProfiler.endStartSection("render"); - RenderHelper.disableStandardItemLighting(); - int k = rg.renderSortedRenderers(0, rg.renderersLoaded, pass, tick); - - rg.theWorld.theProfiler.endSection(); - return k; - } - - public int sortAndRender(int start, int end, int pass, double tick) { - CameraInfo cam = CameraInfo.getInstance(); - - RenderList[] allRenderLists = rg.allRenderLists; - for (RenderList allRenderList : allRenderLists) { - allRenderList.resetList(); - } - - int loopStart = start; - int loopEnd = end; - byte dir = 1; - - if (pass == 1) { - loopStart = end - 1; - loopEnd = start - 1; - dir = -1; - } - - if (pass == 0 && mc.gameSettings.showDebugInfo) { - - mc.theWorld.theProfiler.startSection("debug_info"); - int renderersNotInitialized = 0, renderersBeingClipped = 0, renderersBeingOccluded = 0; - int renderersBeingRendered = 0, renderersSkippingRenderPass = 0, renderersNeedUpdate = 0; - WorldRenderer[] worldRenderers = rg.worldRenderers; - for (WorldRenderer rend : worldRenderers) { - if (!rend.isInitialized) { - ++renderersNotInitialized; - } else if (!rend.isInFrustum) { - ++renderersBeingClipped; - } else if (!rend.isVisible) { - ++renderersBeingOccluded; - } else if (rend.isWaitingOnOcclusionQuery) { - ++renderersSkippingRenderPass; - } else { - ++renderersBeingRendered; - } - if (rend.needsUpdate) { - ++renderersNeedUpdate; - } - } - - rg.dummyRenderInt = renderersNotInitialized; - rg.renderersBeingClipped = renderersBeingClipped; - rg.renderersBeingOccluded = renderersBeingOccluded; - rg.renderersBeingRendered = renderersBeingRendered; - rg.renderersSkippingRenderPass = renderersSkippingRenderPass; - this.renderersNeedUpdate = renderersNeedUpdate; - mc.theWorld.theProfiler.endSection(); - } - - mc.theWorld.theProfiler.startSection("setup_lists"); - int glListsRendered = 0, allRenderListsLength = 0; - WorldRenderer[] sortedWorldRenderers = rg.sortedWorldRenderers; - - for (int i = loopStart; i != loopEnd; i += dir) { - WorldRenderer rend = sortedWorldRenderers[i]; - - if (rend.isVisible && rend.isInFrustum & !rend.skipRenderPass[pass]) { - - int renderListIndex; - - l: { - for (int j = 0; j < allRenderListsLength; ++j) { - if (allRenderLists[j].rendersChunk(rend.posXMinus, rend.posYMinus, rend.posZMinus)) { - renderListIndex = j; - break l; - } - } - renderListIndex = allRenderListsLength++; - allRenderLists[renderListIndex].setupRenderList(rend.posXMinus, rend.posYMinus, rend.posZMinus, cam.getEyeX(), cam.getEyeY(), cam.getEyeZ()); - } - - allRenderLists[renderListIndex].addGLRenderList(rend.getGLCallListForPass(pass)); - ++glListsRendered; - } - } - - mc.theWorld.theProfiler.endStartSection("call_lists"); - - { - int xSort = MathHelper.floor_double(cam.getX()); - int zSort = MathHelper.floor_double(cam.getZ()); - xSort -= xSort & 1023; - zSort -= zSort & 1023; - Arrays.sort(allRenderLists, new RenderDistanceSorter(xSort, zSort)); - rg.renderAllRenderLists(pass, tick); - } - mc.theWorld.theProfiler.endSection(); - - return glListsRendered; - } - - public void clipRenderersByFrustum(ICamera cam, float p_72729_2_) { - for (int i = 0; i < rg.worldRenderers.length; ++i) { - if((i + rg.frustumCheckOffset & 15) == 0) { - WorldRenderer wr = rg.worldRenderers[i]; - IWorldRenderer iwr = (IWorldRenderer) wr; - if (wr.isInFrustum && iwr.arch$getCullInfo().isFrustumCheckPending) { - wr.updateInFrustum(cam); - iwr.arch$getCullInfo().isFrustumCheckPending = false; - if (!wr.isInFrustum) { - OcclusionHelpers.worker.dirtyFrustumRenderers++; - } - } - } - } - - ++rg.frustumCheckOffset; - - if(rg.frustumCheckOffset % 15 == 0 && OcclusionHelpers.worker.dirtyFrustumRenderers > 0) { - OcclusionHelpers.worker.dirty = true; - OcclusionHelpers.worker.dirtyFrustumRenderers = 0; - } - } - - public void arch$setRendererUpdateOrderProvider(IRendererUpdateOrderProvider orderProvider) { - this.rendererUpdateOrderProvider = orderProvider; - } - - public void arch$addRenderGlobalListener(IRenderGlobalListener listener) { - this.eventListeners.add(listener); - } - - private static double distanceSquared(double x1, double y1, double z1, double x2, double y2, double z2) { - return Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2); - } - - private static boolean isChunkEmpty(Chunk chunk) { - return chunk == null || chunk.isEmpty(); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java b/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java deleted file mode 100644 index f8c397ae8..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/OcclusionWorker.java +++ /dev/null @@ -1,419 +0,0 @@ -package org.embeddedt.archaicfix.occlusion; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.WorldClient; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.renderer.culling.Frustrum; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.MathHelper; -import org.embeddedt.archaicfix.occlusion.interfaces.IWorldRenderer; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.stream.Stream; - -import static org.embeddedt.archaicfix.occlusion.OcclusionHelpers.DEBUG_PRINT_QUEUE_ITERATIONS; - -public class OcclusionWorker { - - public OcclusionWorker() { - } - - public void setWorld(RenderGlobal rg, WorldClient world) { - theWorld = world; - } - - public static final VisGraph DUMMY = new VisGraph(); - - static { - DUMMY.computeVisibility(); - } - - public volatile boolean dirty = false; - public int dirtyFrustumRenderers; - private int frame = 0; - private final List queue = new ArrayList<>(); - @SuppressWarnings("unused") - private Frustrum fStack = new Frustrum(); - private WorldClient theWorld; - - /** - * We cache the values of WorldRenderer#isInFrustum here to avoid the overhead of accessing the field. - */ - private boolean[] isWRInFrustum; - - private final Minecraft mc = Minecraft.getMinecraft(); - - private RenderGlobal getRender() { - return getExtendedRender().getRenderGlobal(); - } - - private OcclusionRenderer getExtendedRender() { - return OcclusionHelpers.renderer; - } - - public void run(boolean immediate) { - frame++; - queue.clear(); - int queueIterations = 0; - - if (getRender() == null) { - return; - } - EntityLivingBase view = mc.renderViewEntity; - if (theWorld == null || view == null) { - return; - } - long t0 = DEBUG_PRINT_QUEUE_ITERATIONS ? System.nanoTime() : 0; - - Frustrum frustum = getFrustum(); - - theWorld.theProfiler.startSection("prep"); - - prepareRenderers(); - - seedQueue(frustum); - - long t1 = DEBUG_PRINT_QUEUE_ITERATIONS ? System.nanoTime() : 0; - - theWorld.theProfiler.endStartSection("process_queue"); - for (int i = 0; i < queue.size(); i++) { - queueIterations++; - CullInfo ci = queue.get(i); - - for (StepDirection stepPos : CullInfo.ALLOWED_STEPS[ci.facings & 0b111111]) { - if (canStep(ci, stepPos)) { - maybeEnqueueNeighbor(ci, stepPos, queue, frustum); - } - } - } - theWorld.theProfiler.endStartSection("cleanup"); - - long t2 = DEBUG_PRINT_QUEUE_ITERATIONS ? System.nanoTime() : 0; - - for (CullInfo ci : queue) { - markRenderer(ci, view); - } - - if (DEBUG_PRINT_QUEUE_ITERATIONS) { - if (queueIterations != 0) { - System.out.println("queue iterations: " + queueIterations); - } - long t3 = System.nanoTime(); - System.out.println(((t1 - t0) / 1000000.0) + " ms prepare + " + (t2 - t1) / 1000000.0 + " ms queue + " + (t3 - t2) / 1000000.0 + " ms mark"); - } - - dirty = false; - queue.clear(); - theWorld.theProfiler.endSection(); - } - - private void prepareRenderers() { - RenderGlobal render = getRender(); - if (isWRInFrustum == null || isWRInFrustum.length != render.worldRenderers.length) { - isWRInFrustum = new boolean[render.worldRenderers.length]; - } - - for (int i = 0; i < render.worldRenderers.length; ++i) { - WorldRenderer wr = render.worldRenderers[i]; - wr.isVisible = false; - isWRInFrustum[i] = wr.isInFrustum; - } - render.renderersLoaded = 0; - } - - private Frustrum getFrustum() { - EntityLivingBase view = mc.renderViewEntity; - - Frustrum frustum = new Frustrum(); - // TODO: interpolate using partial tick time - frustum.setPosition(view.posX, view.posY, view.posZ); - return frustum; - } - - private void seedQueue(Frustrum frustum) { - CameraInfo cam = CameraInfo.getInstance(); - - int viewX = MathHelper.floor_double(cam.getX()); - int viewY = MathHelper.floor_double(cam.getY()); - int viewZ = MathHelper.floor_double(cam.getZ()); - - theWorld.theProfiler.endStartSection("gather_chunks"); - - OcclusionRenderer extendedRender = getExtendedRender(); - - theWorld.theProfiler.endStartSection("seed_queue"); - - WorldRenderer center = extendedRender.getRenderer(viewX, viewY, viewZ); - if (center != null) { - CullInfo ci = ((IWorldRenderer) center).arch$getCullInfo(); - isInFrustum(ci, frustum); // make sure frustum status gets updated for the starting renderer - ci.init(StepDirection.NONE, (byte) 0); - queue.add(ci); - } else { - int level = viewY > 5 ? 250 : 5; - center = extendedRender.getRenderer(viewX, level, viewZ); - if (center != null) { - { - CullInfo ci = ((IWorldRenderer) center).arch$getCullInfo(); - ci.init(StepDirection.NONE, (byte) 0); - queue.add(ci); - } - - boolean allNull = false; - theWorld.theProfiler.startSection("gather_world"); - for (int size = 1; !allNull; ++size) { - allNull = true; - for (int i = 0, j = size; i < size; ) { - for (int k = 0; k < 4; ++k) { - int xm = (k & 1) == 0 ? -1 : 1; - int zm = (k & 2) == 0 ? -1 : 1; - center = extendedRender.getRenderer(viewX + i * 16 * xm, level, viewZ + j * 16 * zm); - if (center != null) { - CullInfo ci = ((IWorldRenderer) center).arch$getCullInfo(); - if (isInFrustum(ci, frustum)) { - allNull = false; - ci.init(StepDirection.NONE, (byte) 0); - queue.add(ci); - } - } - } - ++i; - --j; - } - } - theWorld.theProfiler.endSection(); - } - } - } - - private boolean canStep(CullInfo info, StepDirection stepPos) { - boolean allVis = mc.playerController.currentGameType.getID() == 3; - - if (!allVis && !SetVisibility.isVisible(info.vis[0], info.dir.getOpposite().facing, stepPos.facing)) { - return false; - } - - return true; - } - - private void maybeEnqueueNeighbor(CullInfo info, StepDirection stepPos, Collection queue, Frustrum frustum) { - CullInfo neighbor = info.getNeighbor(stepPos.facing); - - if (neighbor == null || !neighbor.setLastCullUpdateFrame(frame) || !isInFrustum(neighbor, frustum)) - return; - - neighbor.init(stepPos, info.facings); - - queue.add(neighbor); - } - - private void markRenderer(CullInfo info, EntityLivingBase view) { - RenderGlobal render = getRender(); - WorldRenderer rend = render.worldRenderers[info.wrIdx]; - if (!rend.isVisible) { - rend.isVisible = true; - if (!rend.isWaitingOnOcclusionQuery) { - // only add it to the list of sorted renderers if it's not skipping all passes (re-used field) - render.sortedWorldRenderers[render.renderersLoaded++] = rend; - } - } - if (rend.needsUpdate || !rend.isInitialized || info.visGraph.isRenderDirty()) { - rend.needsUpdate = true; - if (!rend.isInitialized || (rend.needsUpdate && rend.distanceToEntitySquared(view) <= 1128.0F)) { - getExtendedRender().pushWorkerRenderer(rend); - } - } - } - - private boolean isInFrustum(CullInfo ci, Frustrum frustum) { - if (isWRInFrustum[ci.wrIdx]) { - ci.isFrustumCheckPending = true; - } else { - WorldRenderer wr = Minecraft.getMinecraft().renderGlobal.worldRenderers[ci.wrIdx]; - wr.updateInFrustum(frustum); - isWRInFrustum[ci.wrIdx] = wr.isInFrustum; - } - return isWRInFrustum[ci.wrIdx]; - } - - public enum StepDirection { - // EnumFacing.EAST and EnumFacing.WEST is flipped in MCP - DOWN(EnumFacing.DOWN, 0, -1, 0), - UP(EnumFacing.UP, 0, 16, 0), - WEST(EnumFacing.EAST /* WEST */, -1, 0, 0), - EAST(EnumFacing.WEST /* EAST */, 16, 0, 0), - NORTH(EnumFacing.NORTH, 0, 0, -1), - SOUTH(EnumFacing.SOUTH, 0, 0, 16), - NONE(null, 0, 0, 0), - NONE_opp(null, 0, 0, 0); - - public static final StepDirection[] DIRECTIONS = values(); - public static final StepDirection[][] DIRECTIONS_BIAS = new StepDirection[6][6]; - public static final StepDirection[] FROM_FACING = new StepDirection[6]; - public static final List SIDES = Arrays.asList(DIRECTIONS).subList(1, 6); - static { - for (int i = 0; i < 6; ++i) { - StepDirection pos = DIRECTIONS[i]; - FROM_FACING[pos.facing.ordinal()] = pos; - StepDirection[] bias = DIRECTIONS_BIAS[i]; - int j = 0, xor = pos.ordinal() & 1; - switch (pos) { - case DOWN, UP: - bias[j++] = pos; - bias[j++] = DIRECTIONS[NORTH.ordinal() ^ xor]; - bias[j++] = DIRECTIONS[SOUTH.ordinal() ^ xor]; - bias[j++] = DIRECTIONS[EAST.ordinal() ^ xor]; - bias[j++] = DIRECTIONS[WEST.ordinal() ^ xor]; - bias[j++] = pos.getOpposite(); - break; - case WEST, EAST: - bias[j++] = pos; - bias[j++] = DIRECTIONS[NORTH.ordinal() ^ xor]; - bias[j++] = DIRECTIONS[SOUTH.ordinal() ^ xor]; - bias[j++] = DIRECTIONS[UP.ordinal() ^ xor]; - bias[j++] = DIRECTIONS[DOWN.ordinal() ^ xor]; - bias[j++] = pos.getOpposite(); - break; - case NORTH, SOUTH: - bias[j++] = pos; - bias[j++] = DIRECTIONS[EAST.ordinal() ^ xor]; - bias[j++] = DIRECTIONS[WEST.ordinal() ^ xor]; - bias[j++] = DIRECTIONS[UP.ordinal() ^ xor]; - bias[j++] = DIRECTIONS[DOWN.ordinal() ^ xor]; - bias[j++] = pos.getOpposite(); - break; - case NONE, NONE_opp: - break; - } - } - } - - public final int x, y, z; - public final EnumFacing facing; - - StepDirection(EnumFacing face, int x, int y, int z) { - - this.facing = face; - this.x = x; - this.y = y; - this.z = z; - _x = x > 0 ? 1 : x; - _y = y > 0 ? 1 : y; - _z = z > 0 ? 1 : z; - } - - public StepDirection getOpposite() { - - return DIRECTIONS[ordinal() ^ 1]; - } - - private final int _x, _y, _z; - } - - public static class CullInfo { - - public static final StepDirection[][] ALLOWED_STEPS; - - static { - ALLOWED_STEPS = generateAllowedSteps(); - } - - private static StepDirection[][] generateAllowedSteps() { - StepDirection[][] allowedSteps = new StepDirection[(int) Math.pow(2, 6) + 1][]; - - for (int xStep = -1; xStep <= 1; xStep++) { - for (int yStep = -1; yStep <= 1; yStep++) { - for (int zStep = -1; zStep <= 1; zStep++) { - byte mask = 0; - - // SNEWUD - mask |= new byte[]{0b000100, - 0b000000, - 0b001000 - }[xStep + 1]; - - // SNEWUD - mask |= new byte[]{0b000001, - 0b000000, - 0b000010 - }[yStep + 1]; - - // SNEWUD - mask |= new byte[]{0b010000, - 0b000000, - 0b100000 - }[zStep + 1]; - - byte finalMask = mask; - allowedSteps[mask] = - Stream.of(StepDirection.DOWN, StepDirection.UP, StepDirection.NORTH, StepDirection.SOUTH, StepDirection.WEST, StepDirection.EAST) - .filter(p -> (1 << (p.getOpposite().ordinal()) & finalMask) == 0) - .toArray(StepDirection[]::new); - } - } - } - return allowedSteps; - } - - /** - * The index of the world renderer in RenderGlobal#worldRenderers. Not stored as a reference because I - * found that having it slows things down significantly. - */ - public int wrIdx; - public CullInfo[] neighbors; - /** - * A direct reference to the visibility graph's visibility mask, used to avoid the significant overhead of - * accessing VisGraph's fields. - */ - public long[] vis; - public VisGraph visGraph; - /** - * The direction we stepped in to reach this subchunk. - */ - public StepDirection dir; - /** - * All the directions we have stepped in to reach this subchunk. - */ - public byte facings; - public int lastCullUpdateFrame; - public boolean isFrustumCheckPending; - - public CullInfo() { - this.neighbors = new CullInfo[EnumFacing.values().length]; - this.visGraph = DUMMY; - this.vis = visGraph.getVisibilityArray(); - } - - public CullInfo init(StepDirection dir, byte facings) { - this.dir = dir; - - this.facings = facings; - this.facings |= (1 << dir.ordinal()); - - return this; - } - - public CullInfo getNeighbor(EnumFacing dir) { - return neighbors[dir.ordinal()]; - } - - public void setNeighbor(EnumFacing dir, CullInfo neighbor) { - neighbors[dir.ordinal()] = neighbor; - } - - /** - * Sets the number of the last frame when this renderer was visited by the occlusion culling algorithm. - * Returns true if the value was changed as a result. - */ - public boolean setLastCullUpdateFrame(int lastCullUpdateFrame) { - if (this.lastCullUpdateFrame == lastCullUpdateFrame) return false; - this.lastCullUpdateFrame = lastCullUpdateFrame; - return true; - } - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/PreviousActiveRenderInfo.java b/src/main/java/org/embeddedt/archaicfix/occlusion/PreviousActiveRenderInfo.java deleted file mode 100644 index ac28d2b39..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/PreviousActiveRenderInfo.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.embeddedt.archaicfix.occlusion; - -import net.minecraft.client.renderer.ActiveRenderInfo; - -public class PreviousActiveRenderInfo { - public static float objectX = Float.NaN, objectY, objectZ; - public static float rotationX, rotationZ, rotationYZ; - - public static boolean changed() { - return PreviousActiveRenderInfo.objectX != ActiveRenderInfo.objectX || - PreviousActiveRenderInfo.objectY != ActiveRenderInfo.objectY || - PreviousActiveRenderInfo.objectZ != ActiveRenderInfo.objectZ || - PreviousActiveRenderInfo.rotationX != ActiveRenderInfo.rotationX || - PreviousActiveRenderInfo.rotationYZ != ActiveRenderInfo.rotationYZ || - PreviousActiveRenderInfo.rotationZ != ActiveRenderInfo.rotationZ; - } - - public static void update() { - PreviousActiveRenderInfo.objectX = ActiveRenderInfo.objectX; - PreviousActiveRenderInfo.objectY = ActiveRenderInfo.objectY; - PreviousActiveRenderInfo.objectZ = ActiveRenderInfo.objectZ; - PreviousActiveRenderInfo.rotationX = ActiveRenderInfo.rotationX; - PreviousActiveRenderInfo.rotationYZ = ActiveRenderInfo.rotationYZ; - PreviousActiveRenderInfo.rotationZ = ActiveRenderInfo.rotationZ; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java b/src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java deleted file mode 100644 index 3ce9d917e..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/SetVisibility.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.embeddedt.archaicfix.occlusion; - -import net.minecraft.util.EnumFacing; - -import java.util.Set; - -public class SetVisibility { - - private static final int COUNT_FACES = EnumFacing.values().length; - - public static long setManyVisible(long bitSet, Set faces) { - - for (EnumFacing enumfacing : faces) { - - for (EnumFacing enumfacing1 : faces) { - bitSet = setVisible(bitSet, enumfacing, enumfacing1, true); - } - } - return bitSet; - } - - public static long setVisible(long bitSet, EnumFacing from, EnumFacing to, boolean visible) { - bitSet = setBit(bitSet, from.ordinal() + to.ordinal() * COUNT_FACES, visible); - bitSet = setBit(bitSet, to.ordinal() + from.ordinal() * COUNT_FACES, visible); - - return bitSet; - } - - private static long setBit(long bitSet, int index, boolean value) { - if(value) { - bitSet |= (1L << index); - } else { - bitSet &= ~(1L << index); - } - return bitSet; - } - - public static boolean isVisible(long bitSet, EnumFacing from, EnumFacing to) { - return from == null || to == null || (bitSet & (1L << (from.ordinal() + to.ordinal() * COUNT_FACES))) != 0; - } - - public static String toString(long bitSet) { - - StringBuilder stringbuilder = new StringBuilder(); - stringbuilder.append(' '); - EnumFacing[] aenumfacing = EnumFacing.values(); - int i = aenumfacing.length; - int j; - EnumFacing enumfacing; - - for (j = 0; j < i; ++j) { - enumfacing = aenumfacing[j]; - stringbuilder.append(' ').append(enumFacingToStringFixed(enumfacing).toUpperCase().charAt(0)); - } - - stringbuilder.append('\n'); - aenumfacing = EnumFacing.values(); - i = aenumfacing.length; - - for (j = 0; j < i; ++j) { - enumfacing = aenumfacing[j]; - stringbuilder.append(enumFacingToStringFixed(enumfacing).toUpperCase().charAt(0)); - EnumFacing[] aenumfacing1 = EnumFacing.values(); - int k = aenumfacing1.length; - - for (EnumFacing enumfacing1 : aenumfacing1) { - if (enumfacing == enumfacing1) { - stringbuilder.append(" "); - } else { - boolean flag = isVisible(bitSet, enumfacing, enumfacing1); - stringbuilder.append(' ').append(flag ? 'Y' : 'n'); - } - } - - stringbuilder.append('\n'); - } - - return stringbuilder.toString(); - } - - // Do not trust MCP. - private static String enumFacingToStringFixed(EnumFacing f) { - return new String[]{"DOWN", "UP", "NORTH", "SOUTH", "WEST", "EAST"}[f.ordinal()]; - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java b/src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java deleted file mode 100644 index 560e404fc..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/VisGraph.java +++ /dev/null @@ -1,215 +0,0 @@ -package org.embeddedt.archaicfix.occlusion; - -import lombok.Getter; -import net.minecraft.util.EnumFacing; -import org.embeddedt.archaicfix.occlusion.util.IntStack; - -import java.util.BitSet; -import java.util.EnumSet; -import java.util.Set; - -public class VisGraph { - - private static final int X_OFFSET = (int) Math.pow(16.0D, 0.0D); - private static final int Z_OFFSET = (int) Math.pow(16.0D, 1.0D); - private static final int Y_OFFSET = (int) Math.pow(16.0D, 2.0D); - private static final int[] EDGES = new int[1352]; - public static final long ALL_VIS = 0xFFFFFFFFFFFFFFFFL; - - static { - int i = 0; - - for (int x = 0; x < 16; ++x) { - for (int y = 0; y < 16; ++y) { - for (int z = 0; z < 16; ++z) { - if (x == 0 || x == 15 || y == 0 || y == 15 || z == 0 || z == 15) { - EDGES[i++] = getIndex(x, y, z); - } - } - } - } - } - - /* - * This is a pretty hefty structure: 1340 bytes per 16^3 (40+bytes per object, and the array of long[] in BitSet) - * weighing in around 190 bytes for BitSets, 40 bytes for SetVisibility, and 50 bytes for this. - * ~4,824,000 bytes at view distance 7; This could be halved if it were not reusable, but reusability is part - * of what makes it speedy when recalculating the viewable area. - */ - private final BitSet opaqueBlocks = new BitSet(4096); - private final BitSet visibleBlocks = new BitSet(4096); - private short transparentBlocks = 4096; - @Getter - private boolean dirty = true, computedVis = true; - - /** Accessing this class's fields is slow, so we let the visibility value be referenced directly. */ - private final long[] visibility = new long[]{ALL_VIS}; - - private static int getIndex(int x, int y, int z) { - - return x << 0 | y << 8 | z << 4; - } - - public boolean isRenderDirty() { - - if (isDirty()) { - return true; - } - boolean r = computedVis; - computedVis = false; - return r; - } - - public void setOpaque(int x, int y, int z, boolean opaque) { - - boolean prev = opaqueBlocks.get(getIndex(x, y, z)); - if (prev != opaque) { - opaqueBlocks.set(getIndex(x, y, z), opaque); - transparentBlocks += opaque ? -1 : 1; - dirty = true; - } - } - - public long getVisibility() { - return visibility[0]; - } - - public long[] getVisibilityArray() { - return visibility; - } - - @SuppressWarnings("unchecked") - public void computeVisibility() { - - dirty = false; - long setvisibility = 0; - - if (4096 - transparentBlocks < 256) { - setvisibility = ALL_VIS; - } else if (transparentBlocks == 0) { - setvisibility = 0; - } else { - int[] edges = EDGES; - int i = edges.length; - - visibleBlocks.andNot(visibleBlocks); - visibleBlocks.or(opaqueBlocks); - IntStack linkedlist = new IntStack(1024, 512); - for (int k : edges) { - if (!opaqueBlocks.get(k)) { - setvisibility = SetVisibility.setManyVisible(setvisibility, computeVisibleFacingsFrom(k, linkedlist)); - } - linkedlist.setSize(0); - } - } - - visibility[0] = setvisibility; - computedVis = true; - } - - @SuppressWarnings("unchecked") - public Set getVisibleFacingsFrom(int x, int y, int z) { - - visibleBlocks.andNot(visibleBlocks); - visibleBlocks.or(opaqueBlocks); - return computeVisibleFacingsFrom(getIndex(x & 15, y & 15, z & 15), new IntStack(256, 512)); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private EnumSet computeVisibleFacingsFrom(int index, IntStack linkedlist) { - - EnumSet enumset = EnumSet.noneOf((Class)EnumFacing.class); - linkedlist.add(index); - BitSet blocks = this.visibleBlocks; - blocks.set(index, true); - - EnumFacing[] facings = EnumFacing.values(); - final int k = facings.length; - while (!linkedlist.isEmpty()) { - int j = linkedlist.poll(); - addSides(j, enumset); - - for (EnumFacing face : facings) { - int i1 = stepTo(j, face); - - if (i1 >= 0 && !blocks.get(i1)) { - blocks.set(i1, true); - linkedlist.add(i1); - } - } - } - - return enumset; - } - - private void addSides(int index, Set set) { - - int j = index >> 0 & 15; - - if (j == 0) { - set.add(EnumFacing.EAST /* WEST */); - } else if (j == 15) { - set.add(EnumFacing.WEST /* EAST */); - } - - int k = index >> 8 & 15; - - if (k == 0) { - set.add(EnumFacing.DOWN); - } else if (k == 15) { - set.add(EnumFacing.UP); - } - - int l = index >> 4 & 15; - - if (l == 0) { - set.add(EnumFacing.NORTH); - } else if (l == 15) { - set.add(EnumFacing.SOUTH); - } - } - - private int stepTo(int index, EnumFacing side) { - - return switch (side) { - case DOWN -> { - if ((index >> 8 & 15) == 0) { - yield -1; - } - yield index - Y_OFFSET; - } - case UP -> { - if ((index >> 8 & 15) == 15) { - yield -1; - } - yield index + Y_OFFSET; - } - case NORTH -> { - if ((index >> 4 & 15) == 0) { - yield -1; - } - yield index - Z_OFFSET; - } - case SOUTH -> { - if ((index >> 4 & 15) == 15) { - yield -1; - } - yield index + Z_OFFSET; - } - case EAST -> { - if ((index >> 0 & 15) == 0) { - yield -1; - } - yield index - X_OFFSET; - } - case WEST -> { - if ((index >> 0 & 15) == 15) { - yield -1; - } - yield index + X_OFFSET; - } - default -> -1; - }; - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/ICulledChunk.java b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/ICulledChunk.java deleted file mode 100644 index df2033a91..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/ICulledChunk.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.embeddedt.archaicfix.occlusion.interfaces; - -import net.minecraft.world.chunk.Chunk; -import org.embeddedt.archaicfix.occlusion.VisGraph; - -public interface ICulledChunk { - VisGraph[] getVisibility(); - Chunk buildCulledSides(); -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRenderGlobalListener.java b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRenderGlobalListener.java deleted file mode 100644 index ecc4bb185..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRenderGlobalListener.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.embeddedt.archaicfix.occlusion.interfaces; - -import net.minecraft.client.renderer.WorldRenderer; - -public interface IRenderGlobalListener { - - /** Called when a world renderer changes while it's already dirty. */ - void onDirtyRendererChanged(WorldRenderer wr); - -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRendererUpdateOrderProvider.java b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRendererUpdateOrderProvider.java deleted file mode 100644 index 4ab0894d5..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IRendererUpdateOrderProvider.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.embeddedt.archaicfix.occlusion.interfaces; - -import net.minecraft.client.renderer.WorldRenderer; - -import java.util.List; - -/** Provides a traversal order of the elements of RenderGlobal#worldRenderersToUpdate. Ideally, the order should be from - * the closest renderer to the farthest. */ -public interface IRendererUpdateOrderProvider { - - /** Prepare providing a batch of renderers. */ - void prepare(List worldRenderersToUpdateList); - - boolean hasNext(List worldRenderersToUpdateList); - - WorldRenderer next(List worldRenderersToUpdateList); - - /** End the batch. Remove the renderers that were provided during the batch from worldRenderersToUpdate */ - void cleanup(List worldRenderersToUpdateList); - -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IWorldRenderer.java b/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IWorldRenderer.java deleted file mode 100644 index fac2dd407..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/interfaces/IWorldRenderer.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.embeddedt.archaicfix.occlusion.interfaces; - -import org.embeddedt.archaicfix.occlusion.OcclusionWorker; - -public interface IWorldRenderer { - - boolean arch$isInUpdateList(); - void arch$setInUpdateList(boolean b); - - OcclusionWorker.CullInfo arch$getCullInfo(); - -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/ArrayHashList.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/ArrayHashList.java deleted file mode 100644 index 30efcfcec..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/util/ArrayHashList.java +++ /dev/null @@ -1,626 +0,0 @@ -package org.embeddedt.archaicfix.occlusion.util; - -import com.google.common.base.Objects; -import com.google.common.primitives.Ints; - -import java.util.AbstractCollection; -import java.util.Arrays; -import java.util.Collection; -import java.util.ConcurrentModificationException; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.NoSuchElementException; - -@SuppressWarnings("unchecked") -public class ArrayHashList extends AbstractCollection implements List, Cloneable, java.io.Serializable { - - private static final long serialVersionUID = 3230581060536180693L; - - protected static final class Entry { - - public final Object key; - public final int hash; - public Entry nextInBucket; - - protected Entry(Object key, int keyHash) { - - this.key = key; - this.hash = keyHash; - } - } - - protected static int hash(Object n) { - - int h = n == null ? 0 : n.hashCode(); - h ^= (h >>> 20) ^ (h >>> 12); - return h ^ (h >>> 7) ^ (h >>> 4); - } - - private static int roundUpToPowerOf2(int number) { - - return number >= Ints.MAX_POWER_OF_TWO ? Ints.MAX_POWER_OF_TWO : (number > 2) ? Integer.highestOneBit((number - 1) << 1) : 2; - } - - private transient Object[] elementData; - protected transient int size; - protected transient int mask; - protected transient Entry[] hashTable; - protected transient int modCount; - - public ArrayHashList() { - - elementData = new Object[10]; - hashTable = new Entry[8]; - mask = 7; - } - - public ArrayHashList(int size) { - - elementData = new Object[size]; - size = roundUpToPowerOf2(size) >> 1; - hashTable = new Entry[size]; - mask = size - 1; - } - - public ArrayHashList(Collection col) { - - int size = col.size(); - elementData = new Object[size]; - size = roundUpToPowerOf2(size) >> 1; - hashTable = new Entry[size]; - mask = size - 1; - addAll(col); - } - - @Override - public int size() { - - return size; - } - - protected void add(E obj, int hash) { - - ensureCapacityInternal(size + 1); - elementData[size++] = obj; - insert(new Entry(obj, hash)); - rehashIfNecessary(); - } - - @Override - public boolean add(E obj) { - - int hash = hash(obj); - if (seek(obj, hash) != null) { - return false; - } - - add(obj, hash); - - return true; - } - - @Override - public E set(int index, E obj) { - - checkElementIndex(index); - - int hash = hash(obj); - if (seek(obj, hash) != null) { - // return null; - throw new IllegalArgumentException("Duplicate entries not allowed"); - } - - ++modCount; - Entry e = seek(elementData[index], hash(elementData[index])); - delete(e); - elementData[index] = obj; - insert(new Entry(obj, hash)); - - return (E) e.key; - } - - @Override - public void add(int index, E obj) { - - checkPositionIndex(index); - - int hash = hash(obj); - if (seek(obj, hash) != null) { - throw new IllegalArgumentException("Duplicate entries not allowed"); - } - - if (index == size) { - add(obj, hash); - return; - } - - ensureCapacityInternal(++size); - System.arraycopy(elementData, index, elementData, index + 1, size - index - 1); - elementData[index] = obj; - insert(new Entry(obj, hash)); - rehashIfNecessary(); - } - - @Override - public boolean addAll(int index, Collection c) { - - if (c.size() == 0) { - return false; - } - - for (E e : c) { - add(index++, e); - } - - return true; - } - - @Override - public E get(int index) { - - checkElementIndex(index); - return index(index); - } - - @Override - public int indexOf(Object obj) { - - Entry e = seek(obj, hash(obj)); - if (e == null) { - return -1; - } - - Object o = e.key; - Object[] data = elementData; - int i = size; - while (i-- > 0) { - if (data[i] == o) { - break; - } - } - return i; - } - - @Override - public int lastIndexOf(Object o) { - - return indexOf(o); - } - - @Override - public boolean contains(Object obj) { - - return seek(obj, hash(obj)) != null; - } - - @Override - public E remove(int index) { - - checkElementIndex(index); - - E oldValue = index(index); - delete(seek(oldValue, hash(oldValue))); - fastRemove(index); - - return oldValue; - } - - @Override - public boolean remove(Object obj) { - - Entry e = seek(obj, hash(obj)); - if (e == null) { - return false; - } - - Object o = e.key; - Object[] data = elementData; - for (int i = size; i-- > 0;) { - if (data[i] == o) { - fastRemove(i); - break; - } - } - delete(e); - return true; - } - - private void fastRemove(int index) { - - modCount++; - int numMoved = size - index - 1; - if (numMoved > 0) { - System.arraycopy(elementData, index + 1, elementData, index, numMoved); - } - elementData[--size] = null; // clear to let GC do its work - } - - // { following methods (until the next }) copied mostly verbatim from ArrayList - @Override - public void clear() { - - modCount++; - - // clear to let GC do its work - for (int i = 0; i < size; i++) { - elementData[i] = null; - } - - for (int i = hashTable.length; i-- > 0;) { - hashTable[i] = null; - } - - size = 0; - } - - /** - * Trims the capacity of this ArrayHashList instance to be the list's current size. An application can use this operation to minimize the storage - * of an ArrayHashList instance. - */ - public void trimToSize() { - - ++modCount; - if (size < elementData.length) { - elementData = Arrays.copyOf(elementData, size); - } - } - - /** - * Increases the capacity of this ArrayHashList instance, if necessary, to ensure that it can hold at least the number of elements specified by the - * minimum capacity argument. - * - * @param minCapacity - * the desired minimum capacity - */ - public void ensureCapacity(int minCapacity) { - - if (minCapacity > 0) { - ensureCapacityInternal(minCapacity); - } - } - - private void ensureCapacityInternal(int minCapacity) { - - ++modCount; - // overflow-conscious code - if (minCapacity - elementData.length > 0) { - grow(minCapacity); - } - } - - /** - * The maximum size of array to allocate. Some VMs reserve some header words in an array. Attempts to allocate larger arrays may result in OutOfMemoryError: - * Requested array size exceeds VM limit - */ - private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; - - /** - * Increases the capacity to ensure that it can hold at least the number of elements specified by the minimum capacity argument. - * - * @param minCapacity - * the desired minimum capacity - */ - private void grow(int minCapacity) { - - // overflow-conscious code - int oldCapacity = elementData.length; - int newCapacity = oldCapacity + (oldCapacity >> 1); - if (newCapacity - minCapacity < 0) { - newCapacity = minCapacity; - } - if (newCapacity - MAX_ARRAY_SIZE > 0) { - newCapacity = hugeCapacity(minCapacity); - } - // minCapacity is usually close to size, so this is a win: - elementData = Arrays.copyOf(elementData, newCapacity); - } - - private static int hugeCapacity(int minCapacity) { - - if (minCapacity < 0) { - throw new OutOfMemoryError(); - } - return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; - } - - private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { - - // Write out element count, and any hidden stuff - int expectedModCount = modCount; - s.defaultWriteObject(); - - // Write out size as capacity for behavioural compatibility with clone() - s.writeInt(size); - - // Write out all elements in the proper order. - for (int i = 0; i < size; i++) { - s.writeObject(elementData[i]); - } - - if (modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } - } - - private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - - elementData = new Object[10]; - hashTable = new Entry[8]; - mask = 7; - - // Read in size, and any hidden stuff - s.defaultReadObject(); - - // Read in capacity - int size = s.readInt(); - - if (size > 0) { - // be like clone(), allocate array based upon size not capacity - ensureCapacityInternal(size); - - // Read in all elements in the proper order. - for (int i = 0; i < size; i++) { - add((E) s.readObject()); - } - } - } - - // } - - E index(int index) { - - return (E) elementData[index]; - } - - protected Entry seek(Object obj, int hash) { - - for (Entry entry = hashTable[hash & mask]; entry != null; entry = entry.nextInBucket) { - if (hash == entry.hash && Objects.equal(obj, entry.key)) { - return entry; - } - } - - return null; - } - - protected void insert(Entry entry) { - - int bucket = entry.hash & mask; - entry.nextInBucket = hashTable[bucket]; - hashTable[bucket] = entry; - } - - protected void delete(Entry entry) { - - l: synchronized (hashTable) { - int bucket = entry.hash & mask; - Entry prev = null, cur = hashTable[bucket]; - if (cur == entry) { - hashTable[bucket] = cur.nextInBucket; - break l; - } - for (; true; cur = cur.nextInBucket) { - if (cur == entry) { - prev.nextInBucket = entry.nextInBucket; - break l; - } - prev = cur; - } - } - } - - protected void rehashIfNecessary() { - - Entry[] old = hashTable, newTable; - if (size > old.length * 2 && old.length < Ints.MAX_POWER_OF_TWO) { - synchronized (hashTable) { - int newTableSize = old.length * 2, newMask = newTableSize - 1; - newTable = new Entry[newTableSize]; - - for (int bucket = old.length; bucket-- > 0;) { - Entry entry = old[bucket]; - while (entry != null) { - Entry nextEntry = entry.nextInBucket; - int keyBucket = entry.hash & newMask; - entry.nextInBucket = newTable[keyBucket]; - newTable[keyBucket] = entry; - entry = nextEntry; - } - } - hashTable = newTable; - mask = newMask; - } - } - } - - @Override - public ArrayHashList clone() { - - return new ArrayHashList(this); - } - - @Override - public List subList(int fromIndex, int toIndex) { - - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public Iterator iterator() { - - return new Itr(); - } - - @Override - public ListIterator listIterator() { - - return listIterator(0); - } - - @Override - public ListIterator listIterator(int index) { - - return new ListItr(index); - } - - protected boolean isElementIndex(int index) { - - return index >= 0 && index < size; - } - - protected boolean isPositionIndex(int index) { - - return index >= 0 && index <= size; - } - - protected String outOfBoundsMsg(int index) { - - return "Index: " + index + ", Size: " + size; - } - - protected void checkElementIndex(int index) { - - if (!isElementIndex(index)) { - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } - } - - protected void checkPositionIndex(int index) { - - if (!isPositionIndex(index)) { - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } - } - - private class Itr implements Iterator { - - int cursor; // index of next element to return - int lastRet = -1; // index of last element returned; -1 if no such - int expectedModCount = modCount; - - @Override - public boolean hasNext() { - - return cursor != size; - } - - @Override - public E next() { - - checkForComodification(); - int i = cursor; - if (i >= size) { - throw new NoSuchElementException(); - } - Object[] elementData = ArrayHashList.this.elementData; - if (i >= elementData.length) { - throw new ConcurrentModificationException(); - } - cursor = i + 1; - return (E) elementData[lastRet = i]; - } - - @Override - public void remove() { - - if (lastRet < 0) { - throw new IllegalStateException(); - } - checkForComodification(); - - try { - ArrayHashList.this.remove(lastRet); - cursor = lastRet; - lastRet = -1; - expectedModCount = modCount; - } catch (IndexOutOfBoundsException ex) { - throw new ConcurrentModificationException(); - } - } - - final void checkForComodification() { - - if (modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } - } - } - - private class ListItr extends Itr implements ListIterator { - - ListItr(int index) { - - super(); - cursor = index; - } - - @Override - public boolean hasPrevious() { - - return cursor != 0; - } - - @Override - public int nextIndex() { - - return cursor; - } - - @Override - public int previousIndex() { - - return cursor - 1; - } - - @Override - @SuppressWarnings("unchecked") - public E previous() { - - checkForComodification(); - int i = cursor - 1; - if (i < 0) { - throw new NoSuchElementException(); - } - Object[] elementData = ArrayHashList.this.elementData; - if (i >= elementData.length) { - throw new ConcurrentModificationException(); - } - cursor = i; - return (E) elementData[lastRet = i]; - } - - @Override - public void set(E e) { - - if (lastRet < 0) { - throw new IllegalStateException(); - } - checkForComodification(); - - try { - ArrayHashList.this.set(lastRet, e); - } catch (IndexOutOfBoundsException ex) { - throw new ConcurrentModificationException(); - } - } - - @Override - public void add(E e) { - - checkForComodification(); - - try { - int i = cursor; - ArrayHashList.this.add(i, e); - cursor = i + 1; - lastRet = -1; - expectedModCount = modCount; - } catch (IndexOutOfBoundsException ex) { - throw new ConcurrentModificationException(); - } - } - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/IdentityLinkedHashList.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/IdentityLinkedHashList.java deleted file mode 100644 index f37bd7995..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/util/IdentityLinkedHashList.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.embeddedt.archaicfix.occlusion.util; - -import java.util.Collection; - -@SuppressWarnings("unchecked") -public class IdentityLinkedHashList extends LinkedHashList { - - private static final long serialVersionUID = 4893829808146776641L; - - public IdentityLinkedHashList() { - - super(); - } - - public IdentityLinkedHashList(int size) { - - super(size); - } - - public IdentityLinkedHashList(Collection col) { - - super(col); - } - - @Override - protected int hash(Object o) { - - return System.identityHashCode(o); - } - - @Override - protected Entry seek(Object obj, int hash) { - - for (Entry entry = hashTable[hash & mask]; entry != null; entry = entry.nextInBucket) { - if (obj == entry.key) { - return entry; - } - } - - return null; - } - - @Override - public IdentityLinkedHashList clone() { - - return new IdentityLinkedHashList(this); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntStack.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntStack.java deleted file mode 100644 index f1da2f639..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntStack.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - */ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * $Id: IntStack.java,v 1.2.4.1 2005/09/15 08:15:45 suresh_emailid Exp $ - */ -package org.embeddedt.archaicfix.occlusion.util; - -import java.util.EmptyStackException; - -/** - * Implement a stack of simple integers. - * - * %OPT% - * This is currently based on IntVector, which permits fast acess but pays a - * heavy recopying penalty if/when its size is increased. If we expect deep - * stacks, we should consider a version based on ChunkedIntVector. - * - * @xsl.usage internal - */ -public class IntStack extends IntVector { - - /** - * Default constructor. Note that the default - * block size is very small, for small lists. - */ - public IntStack() { - - super(); - } - - /** - * Construct a IntVector, using the given block size. - * - * @param blocksize - * Size of block to allocate - */ - public IntStack(int blocksize) { - - super(blocksize); - } - - /** - * Construct a IntVector, using the given block size. - * - * @param blocksize - * Size of block to allocate - */ - public IntStack(int blocksize, int increaseSize) { - - super(blocksize, increaseSize); - } - - /** - * Copy constructor for IntStack - * - * @param v - * IntStack to copy - */ - public IntStack(IntStack v) { - - super(v); - } - - /** - * Pushes an item onto the top of this stack. - * - * @param i - * the int to be pushed onto this stack. - * @return the item argument. - */ - public int push(int i) { - - if ((m_firstFree + 1) >= m_mapSize) { - m_mapSize += m_blocksize; - - int newMap[] = new int[m_mapSize]; - - System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1); - - m_map = newMap; - } - - m_map[m_firstFree] = i; - - m_firstFree++; - - return i; - } - - /** - * Removes the object at the top of this stack and returns that - * object as the value of this function. - * - * @return The object at the top of this stack. - */ - public final int pop() { - - return m_map[--m_firstFree]; - } - - /** - * Quickly pops a number of items from the stack. - */ - - public final void quickPop(int n) { - - m_firstFree -= n; - } - - /** - * Looks at the object at the top of this stack without removing it - * from the stack. - * - * @return the object at the top of this stack. - * @throws EmptyStackException - * if this stack is empty. - */ - public final int peek() { - - try { - return m_map[m_firstFree - 1]; - } catch (ArrayIndexOutOfBoundsException e) { - throw new EmptyStackException(); - } - } - - /** - * Looks at the object at the position the stack counting down n items. - * - * @param n - * The number of items down, indexed from zero. - * @return the object at n items down. - * @throws EmptyStackException - * if this stack is empty. - */ - public int peek(int n) { - - try { - return m_map[m_firstFree - (1 + n)]; - } catch (ArrayIndexOutOfBoundsException e) { - throw new EmptyStackException(); - } - } - - /** - * Sets an object at a the top of the statck - * - * - * @param val - * object to set at the top - * @throws EmptyStackException - * if this stack is empty. - */ - public void setTop(int val) { - - try { - m_map[m_firstFree - 1] = val; - } catch (ArrayIndexOutOfBoundsException e) { - throw new EmptyStackException(); - } - } - - /** - * Tests if this stack is empty. - * - * @return true if this stack is empty; false - * otherwise. - * @since JDK1.0 - */ - public boolean empty() { - - return m_firstFree == 0; - } - - /** - * Returns where an object is on this stack. - * - * @param o - * the desired object. - * @return the distance from the top of the stack where the object is] - * located; the return value -1 indicates that the - * object is not on the stack. - * @since JDK1.0 - */ - public int search(int o) { - - int i = lastIndexOf(o); - - if (i >= 0) { - return size() - i; - } - - return -1; - } - - /** - * Returns clone of current IntStack - * - * @return clone of current IntStack - */ - @Override - public Object clone() { - - return new IntStack(this); - } - - public boolean isEmpty() { - - return size() == 0; - } - - /* - @Override - public boolean contains(Object o) { - - return false; - } - - @Override - public Iterator iterator() { - - return null; - } - - @Override - public Object[] toArray() { - - return null; - } - - @Override - public Object[] toArray(Object[] a) { - - return null; - }//*/ - - public void clear() { - - setSize(0); - } - - public boolean add(int e) { - - push(e); - return true; - } - - public boolean offer(int e) { - - push(e); - return true; - } - - public int remove() { - - return pop(); - } - - public int poll() { - - return pop(); - } - - public int element() { - - return peek(0); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntVector.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntVector.java deleted file mode 100644 index 9ff505e3d..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/util/IntVector.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * $Id: IntVector.java,v 1.2.4.1 2005/09/15 08:15:45 suresh_emailid Exp $ - */ -package org.embeddedt.archaicfix.occlusion.util; - -/** - * A very simple table that stores a list of int. - * - * This version is based on a "realloc" strategy -- a simle array is - * used, and when more storage is needed, a larger array is obtained - * and all existing data is recopied into it. As a result, read/write - * access to existing nodes is O(1) fast but appending may be O(N**2) - * slow. See also SuballocatedIntVector. - * - * @xsl.usage internal - */ -public class IntVector implements Cloneable { - - /** Size of blocks to allocate */ - protected int m_blocksize; - - /** Array of ints */ - protected int m_map[]; // IntStack is trying to see this directly - - /** Number of ints in array */ - protected int m_firstFree = 0; - - /** Size of array */ - protected int m_mapSize; - - /** - * Default constructor. Note that the default - * block size is very small, for small lists. - */ - public IntVector() { - - m_blocksize = 32; - m_mapSize = m_blocksize; - m_map = new int[m_blocksize]; - } - - /** - * Construct a IntVector, using the given block size. - * - * @param blocksize - * Size of block to allocate - */ - public IntVector(int blocksize) { - - m_blocksize = blocksize; - m_mapSize = blocksize; - m_map = new int[blocksize]; - } - - /** - * Construct a IntVector, using the given block size. - * - * @param blocksize - * Size of block to allocate - */ - public IntVector(int blocksize, int increaseSize) { - - m_blocksize = increaseSize; - m_mapSize = blocksize; - m_map = new int[blocksize]; - } - - /** - * Copy constructor for IntVector - * - * @param v - * Existing IntVector to copy - */ - public IntVector(IntVector v) { - - m_map = new int[v.m_mapSize]; - m_mapSize = v.m_mapSize; - m_firstFree = v.m_firstFree; - m_blocksize = v.m_blocksize; - System.arraycopy(v.m_map, 0, m_map, 0, m_firstFree); - } - - /** - * Get the length of the list. - * - * @return length of the list - */ - public final int size() { - - return m_firstFree; - } - - /** - * Get the length of the list. - * - * @return length of the list - */ - public final void setSize(int sz) { - - m_firstFree = sz; - } - - /** - * Append a int onto the vector. - * - * @param value - * Int to add to the list - */ - public final void addElement(int value) { - - if ((m_firstFree + 1) >= m_mapSize) { - m_mapSize += m_blocksize; - - int newMap[] = new int[m_mapSize]; - - System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1); - - m_map = newMap; - } - - m_map[m_firstFree] = value; - - m_firstFree++; - } - - /** - * Append several int values onto the vector. - * - * @param value - * Int to add to the list - */ - public final void addElements(int value, int numberOfElements) { - - if ((m_firstFree + numberOfElements) >= m_mapSize) { - m_mapSize += (m_blocksize + numberOfElements); - - int newMap[] = new int[m_mapSize]; - - System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1); - - m_map = newMap; - } - - for (int i = 0; i < numberOfElements; i++) { - m_map[m_firstFree] = value; - m_firstFree++; - } - } - - /** - * Append several slots onto the vector, but do not set the values. - * - * @param numberOfElements - * Int to add to the list - */ - public final void addElements(int numberOfElements) { - - if ((m_firstFree + numberOfElements) >= m_mapSize) { - m_mapSize += (m_blocksize + numberOfElements); - - int newMap[] = new int[m_mapSize]; - - System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1); - - m_map = newMap; - } - - m_firstFree += numberOfElements; - } - - /** - * Inserts the specified node in this vector at the specified index. - * Each component in this vector with an index greater or equal to - * the specified index is shifted upward to have an index one greater - * than the value it had previously. - * - * @param value - * Int to insert - * @param at - * Index of where to insert - */ - public final void insertElementAt(int value, int at) { - - if ((m_firstFree + 1) >= m_mapSize) { - m_mapSize += m_blocksize; - - int newMap[] = new int[m_mapSize]; - - System.arraycopy(m_map, 0, newMap, 0, m_firstFree + 1); - - m_map = newMap; - } - - if (at <= (m_firstFree - 1)) { - System.arraycopy(m_map, at, m_map, at + 1, m_firstFree - at); - } - - m_map[at] = value; - - m_firstFree++; - } - - /** - * Inserts the specified node in this vector at the specified index. - * Each component in this vector with an index greater or equal to - * the specified index is shifted upward to have an index one greater - * than the value it had previously. - */ - public final void removeAllElements() { - - for (int i = 0; i < m_firstFree; i++) { - m_map[i] = Integer.MIN_VALUE; - } - - m_firstFree = 0; - } - - /** - * Removes the first occurrence of the argument from this vector. - * If the object is found in this vector, each component in the vector - * with an index greater or equal to the object's index is shifted - * downward to have an index one smaller than the value it had - * previously. - * - * @param s - * Int to remove from array - * - * @return True if the int was removed, false if it was not found - */ - public final boolean removeElement(int s) { - - for (int i = 0; i < m_firstFree; i++) { - if (m_map[i] == s) { - if ((i + 1) < m_firstFree) - System.arraycopy(m_map, i + 1, m_map, i - 1, m_firstFree - i); - else - m_map[i] = Integer.MIN_VALUE; - - m_firstFree--; - - return true; - } - } - - return false; - } - - /** - * Deletes the component at the specified index. Each component in - * this vector with an index greater or equal to the specified - * index is shifted downward to have an index one smaller than - * the value it had previously. - * - * @param i - * index of where to remove and int - */ - public final void removeElementAt(int i) { - - if (i > m_firstFree) - System.arraycopy(m_map, i + 1, m_map, i, m_firstFree); - else - m_map[i] = Integer.MIN_VALUE; - - m_firstFree--; - } - - /** - * Sets the component at the specified index of this vector to be the - * specified object. The previous component at that position is discarded. - * - * The index must be a value greater than or equal to 0 and less - * than the current size of the vector. - * - * @param value - * object to set - * @param index - * Index of where to set the object - */ - public final void setElementAt(int value, int index) { - - m_map[index] = value; - } - - /** - * Get the nth element. - * - * @param i - * index of object to get - * - * @return object at given index - */ - public final int elementAt(int i) { - - return m_map[i]; - } - - /** - * Tell if the table contains the given node. - * - * @param s - * object to look for - * - * @return true if the object is in the list - */ - public final boolean contains(int s) { - - for (int i = 0; i < m_firstFree; i++) { - if (m_map[i] == s) - return true; - } - - return false; - } - - /** - * Searches for the first occurence of the given argument, - * beginning the search at index, and testing for equality - * using the equals method. - * - * @param elem - * object to look for - * @param index - * Index of where to begin search - * @return the index of the first occurrence of the object - * argument in this vector at position index or later in the - * vector; returns -1 if the object is not found. - */ - public final int indexOf(int elem, int index) { - - for (int i = index; i < m_firstFree; i++) { - if (m_map[i] == elem) - return i; - } - - return Integer.MIN_VALUE; - } - - /** - * Searches for the first occurence of the given argument, - * beginning the search at index, and testing for equality - * using the equals method. - * - * @param elem - * object to look for - * @return the index of the first occurrence of the object - * argument in this vector at position index or later in the - * vector; returns -1 if the object is not found. - */ - public final int indexOf(int elem) { - - for (int i = 0; i < m_firstFree; i++) { - if (m_map[i] == elem) - return i; - } - - return Integer.MIN_VALUE; - } - - /** - * Searches for the first occurence of the given argument, - * beginning the search at index, and testing for equality - * using the equals method. - * - * @param elem - * Object to look for - * @return the index of the first occurrence of the object - * argument in this vector at position index or later in the - * vector; returns -1 if the object is not found. - */ - public final int lastIndexOf(int elem) { - - for (int i = (m_firstFree - 1); i >= 0; i--) { - if (m_map[i] == elem) - return i; - } - - return Integer.MIN_VALUE; - } - - /** - * Returns clone of current IntVector - * - * @return clone of current IntVector - */ - @Override - public Object clone() { - - return new IntVector(this); - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java deleted file mode 100644 index 582bd1334..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/util/LinkedHashList.java +++ /dev/null @@ -1,675 +0,0 @@ -package org.embeddedt.archaicfix.occlusion.util; - -import com.google.common.base.Objects; -import com.google.common.primitives.Ints; - -import java.util.AbstractCollection; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.ConcurrentModificationException; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.NoSuchElementException; - -@SuppressWarnings("unchecked") -public class LinkedHashList extends AbstractCollection implements List, Cloneable, java.io.Serializable { - - private static final long serialVersionUID = -642033533165934945L; - - protected static final class Entry { - - protected Entry next; - protected Entry prev; - protected final Object key; - protected final int hash; - protected Entry nextInBucket; - - protected Entry(Object key, int keyHash) { - - this.key = key; - this.hash = keyHash; - } - } - - protected static int roundUpToPowerOf2(int number) { - - return number >= Ints.MAX_POWER_OF_TWO ? Ints.MAX_POWER_OF_TWO : (number > 2) ? Integer.highestOneBit((number - 1) << 1) : 2; - } - - protected transient Entry head; - protected transient Entry tail; - protected transient int size; - protected transient int mask; - protected transient Entry[] hashTable; - protected transient int modCount; - - public LinkedHashList() { - - hashTable = new Entry[8]; - mask = 7; - } - - public LinkedHashList(int size) { - - size = roundUpToPowerOf2(size); - hashTable = new Entry[size]; - mask = size - 1; - } - - public LinkedHashList(Collection col) { - - int size = roundUpToPowerOf2(col.size()); - hashTable = new Entry[size]; - mask = size - 1; - addAll(col); - } - - protected int hash(Object n) { - - int h = n == null ? 0 : n.hashCode(); - h ^= (h >>> 20) ^ (h >>> 12); - return h ^ (h >>> 7) ^ (h >>> 4); - } - - @Override - public int size() { - - return size; - } - - protected boolean add(E obj, int hash) { - - if (seek(obj, hash) != null) { - return false; - } - - Entry e; - ++modCount; - insert(e = new Entry(obj, hash)); - rehashIfNecessary(); - e.prev = tail; - e.next = null; - if (tail != null) { - tail.next = e; - } else { - head = e; - } - tail = e; - return true; - } - - @Override - public boolean add(E obj) { - - int hash = hash(obj); - return add(obj, hash); - } - - @Override - public E set(int index, E obj) { - - checkElementIndex(index); - - int hash = hash(obj); - if (seek(obj, hash) != null) { - // return null; - throw new IllegalArgumentException("Duplicate entries not allowed"); - } - - ++modCount; - Entry e = index(index); - delete(e); - insert(new Entry(obj, hash)); - - return (E) e.key; - } - - @Override - public void add(int index, E obj) { - - checkPositionIndex(index); - - int hash = hash(obj); - if (seek(obj, hash) != null) { - throw new IllegalArgumentException("Duplicate entries not allowed"); - } - - if (index == size) { - add(obj, hash); - return; - } - - ++modCount; - Entry e = index(index); - Entry n = new Entry(obj, hash); - n.next = e.next; - n.prev = e; - e.next = n; - if (n.next != null) { - n.next.prev = n; - } - insert(n); - rehashIfNecessary(); - } - - @Override - public boolean addAll(int index, Collection c) { - - if (c.size() == 0) { - return false; - } - - for (E e : c) { - add(index++, e); - } - - return true; - } - - @Override - public E get(int index) { - - checkElementIndex(index); - return (E) index(index).key; - } - - @Override - public int indexOf(Object o) { - - Entry v = seek(o, hash(o)); - if (v == null) { - return -1; - } - Entry n = head; - for (int i = 0; n != tail; ++i) { - if (v == n) { - return i; - } - n = n.next; - } - return size; - } - - @Override - public int lastIndexOf(Object o) { - - return indexOf(o); - } - - public boolean push(E obj) { - - int hash = hash(obj); - return add(obj, hash); - } - - public E pop() { - - Entry e = tail; - if (e != null) { - unlink(e); - return (E) e.key; - } - return null; - } - - public E peek() { - - return tail != null ? (E) tail.key : null; - } - - public E poke() { - - return head != null ? (E) head.key : null; - } - - public boolean unshift(E obj) { - - int hash = hash(obj); - if (seek(obj, hash) != null) { - return false; - } - - Entry e; - ++modCount; - insert(e = new Entry(obj, hash)); - rehashIfNecessary(); - e.next = head; - e.prev = null; - if (head != null) { - head.prev = e; - } else { - tail = e; - } - head = e; - return true; - } - - public E shift() { - - Entry e = head; - if (e != null) { - unlink(e); - return (E) e.key; - } - return null; - } - - @Override - public boolean contains(Object obj) { - - return seek(obj, hash(obj)) != null; - } - - @Override - public boolean remove(Object obj) { - - Entry e = seek(obj, hash(obj)); - if (e == null) { - return false; - } - - unlink(e); - return true; - } - - @Override - public E remove(int index) { - - checkElementIndex(index); - - Entry oldValue = index(index); - unlink(oldValue); - - return (E) oldValue.key; - } - - protected Entry index(int index) { - - Entry x; - if (index < (size >> 1)) { - x = head; - for (int i = index; i-- > 0;) { - x = x.next; - } - } else { - x = tail; - for (int i = size - 1; i-- > index;) { - x = x.prev; - } - } - return x; - } - - protected Entry seek(Object obj, int hash) { - - for (Entry entry = hashTable[hash & mask]; entry != null; entry = entry.nextInBucket) { - if (hash == entry.hash && Objects.equal(obj, entry.key)) { - return entry; - } - } - - return null; - } - - protected void insert(Entry entry) { - - int bucket = entry.hash & mask; - entry.nextInBucket = hashTable[bucket]; - hashTable[bucket] = entry; - ++size; - } - - protected boolean linkBefore(E obj, Entry succ) { - - int hash = hash(obj); - if (seek(obj, hash) != null) { - return false; - } - - final Entry pred = succ.prev; - final Entry newNode = new Entry(obj, hash); - modCount++; - insert(newNode); - rehashIfNecessary(); - newNode.next = succ; - newNode.prev = pred; - succ.prev = newNode; - if (pred == null) { - head = newNode; - } else { - pred.next = newNode; - } - return true; - } - - protected void delete(Entry entry) { - - l: { - int bucket = entry.hash & mask; - Entry prev = null, cur = hashTable[bucket]; - if (cur == entry) { - hashTable[bucket] = cur.nextInBucket; - break l; - } - for (; true; cur = cur.nextInBucket) { - if (cur == entry) { - prev.nextInBucket = entry.nextInBucket; - break l; - } - prev = cur; - } - } - --size; - } - - protected E unlink(Entry x) { - - final E element = (E) x.key; - final Entry next = x.next; - final Entry prev = x.prev; - - if (prev == null) { - head = next; - } else { - prev.next = next; - x.prev = null; - } - - if (next == null) { - tail = prev; - } else { - next.prev = prev; - x.next = null; - } - - delete(x); - modCount++; - return element; - } - - protected void rehashIfNecessary() { - - Entry[] old = hashTable, newTable; - if (size > old.length * 2 && old.length < Ints.MAX_POWER_OF_TWO) { - int newTableSize = old.length * 2, newMask = newTableSize - 1; - newTable = new Entry[newTableSize]; - - for (int bucket = old.length; bucket-- > 0;) { - Entry entry = old[bucket]; - while (entry != null) { - Entry nextEntry = entry.nextInBucket; - int keyBucket = entry.hash & newMask; - entry.nextInBucket = newTable[keyBucket]; - newTable[keyBucket] = entry; - entry = nextEntry; - } - } - hashTable = newTable; - mask = newMask; - } - } - - private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { - - // Write out element count, and any hidden stuff - int expectedModCount = modCount; - s.defaultWriteObject(); - - // Write out size as capacity for behavioural compatibility with clone() - s.writeInt(size); - - // Write out all elements in the proper order. - Entry n = head; - for (int i = 0; i < size; i++) { - s.writeObject(n.key); - n = n.next; - } - - if (modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } - } - - private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - - head = tail = null; - hashTable = new Entry[8]; - mask = 7; - size = 0; - - // Read in size, and any hidden stuff - s.defaultReadObject(); - - // Read in capacity - int size = s.readInt(); - - if (size > 0) { - - // Read in all elements in the proper order. - for (int i = 0; i < size; i++) { - add((E) s.readObject()); - } - } - } - - @Override - public LinkedHashList clone() { - - return new LinkedHashList(this); - } - - @Override - public List subList(int fromIndex, int toIndex) { - - // TODO Auto-generated method stub - throw new UnsupportedOperationException(); - } - - @Override - public Iterator iterator() { - - return listIterator(); - } - - @Override - public ListIterator listIterator() { - - return listIterator(0); - } - - @Override - public ListIterator listIterator(int index) { - - checkPositionIndex(index); - return new ListItr(index); - } - - public Iterator descendingIterator() { - - return new DescendingIterator(); - } - - protected boolean isElementIndex(int index) { - - return index >= 0 && index < size; - } - - protected boolean isPositionIndex(int index) { - - return index >= 0 && index <= size; - } - - protected String outOfBoundsMsg(int index) { - - return "Index: " + index + ", Size: " + size; - } - - protected void checkElementIndex(int index) { - - if (!isElementIndex(index)) { - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } - } - - protected void checkPositionIndex(int index) { - - if (!isPositionIndex(index)) { - throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); - } - } - - @Override - public void sort(Comparator comparator) { - ArrayList sorter = new ArrayList<>(this); - sorter.sort(comparator); - this.clear(); - this.addAll(sorter); - } - - protected class ListItr implements ListIterator { - - protected Entry lastReturned = null; - protected Entry next; - protected int nextIndex; - protected int expectedModCount = modCount; - - protected ListItr(int index) { - - next = (index == size) ? null : index(index); - nextIndex = index; - } - - @Override - public boolean hasNext() { - - return nextIndex < size; - } - - @Override - public E next() { - - checkForComodification(); - if (!hasNext()) { - throw new NoSuchElementException(); - } - - lastReturned = next; - next = next.next; - nextIndex++; - return (E) lastReturned.key; - } - - @Override - public boolean hasPrevious() { - - return nextIndex > 0; - } - - @Override - public E previous() { - - checkForComodification(); - if (!hasPrevious()) { - throw new NoSuchElementException(); - } - - lastReturned = next = (next == null) ? tail : next.prev; - nextIndex--; - return (E) lastReturned.key; - } - - @Override - public int nextIndex() { - - return nextIndex; - } - - @Override - public int previousIndex() { - - return nextIndex - 1; - } - - @Override - public void remove() { - - checkForComodification(); - if (lastReturned == null) { - throw new IllegalStateException(); - } - - Entry lastNext = lastReturned.next; - unlink(lastReturned); - if (next == lastReturned) { - next = lastNext; - } else { - nextIndex--; - } - lastReturned = null; - expectedModCount++; - } - - @Override - public void set(E e) { - - checkForComodification(); - if (lastReturned == null) { - throw new IllegalStateException(); - } - - linkBefore(e, lastReturned); - unlink(lastReturned); - lastReturned = (next == null) ? tail : next.prev; - expectedModCount += 2; - } - - @Override - public void add(E e) { - - checkForComodification(); - lastReturned = null; - if (next == null) { - push(e); - } else { - linkBefore(e, next); - } - nextIndex++; - expectedModCount++; - } - - protected final void checkForComodification() { - - if (modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } - } - - } - - protected class DescendingIterator implements Iterator { - - protected final ListItr itr = new ListItr(size()); - - @Override - public boolean hasNext() { - - return itr.hasPrevious(); - } - - @Override - public E next() { - - return itr.previous(); - } - - @Override - public void remove() { - - itr.remove(); - } - - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/occlusion/util/SynchronizedIdentityLinkedHashList.java b/src/main/java/org/embeddedt/archaicfix/occlusion/util/SynchronizedIdentityLinkedHashList.java deleted file mode 100644 index 3a125b0db..000000000 --- a/src/main/java/org/embeddedt/archaicfix/occlusion/util/SynchronizedIdentityLinkedHashList.java +++ /dev/null @@ -1,137 +0,0 @@ -package org.embeddedt.archaicfix.occlusion.util; - -public class SynchronizedIdentityLinkedHashList extends IdentityLinkedHashList { - - private static final long serialVersionUID = -4821513020637725603L; - - public SynchronizedIdentityLinkedHashList() { - - } - - @Override - protected synchronized boolean add(E obj, int hash) { - - return super.add(obj, hash); - } - - @Override - public synchronized E set(int index, E obj) { - - return super.set(index, obj); - } - - @Override - public synchronized void add(int index, E obj) { - - super.add(index, obj); - } - - @Override - public synchronized E get(int index) { - - return super.get(index); - } - - @Override - public synchronized int indexOf(Object o) { - - return super.indexOf(o); - } - - @Override - public synchronized boolean push(E obj) { - - return super.add(obj); - } - - @Override - public synchronized E pop() { - - return super.pop(); - } - - @Override - public synchronized E peek() { - - return super.peek(); - } - - @Override - public synchronized E poke() { - - return super.poke(); - } - - @Override - public synchronized boolean unshift(E obj) { - - return super.unshift(obj); - } - - @Override - public synchronized E shift() { - - return super.shift(); - } - - @Override - public synchronized boolean contains(Object obj) { - - return super.contains(obj); - } - - @Override - public synchronized boolean remove(Object obj) { - - return super.remove(obj); - } - - @Override - public synchronized E remove(int index) { - - return super.remove(index); - } - - @Override - protected synchronized Entry index(int index) { - - return super.index(index); - } - - @Override - protected synchronized Entry seek(Object obj, int hash) { - - return super.seek(obj, hash); - } - - @Override - protected synchronized void insert(Entry entry) { - - super.insert(entry); - } - - @Override - protected synchronized boolean linkBefore(E obj, Entry succ) { - - return super.linkBefore(obj, succ); - } - - @Override - protected synchronized void delete(Entry entry) { - - super.delete(entry); - } - - @Override - protected synchronized E unlink(Entry x) { - - return super.unlink(x); - } - - @Override - protected synchronized void rehashIfNecessary() { - - super.rehashIfNecessary(); - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java b/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java index f4c00d48a..1ab1e3e82 100644 --- a/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java +++ b/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java @@ -25,7 +25,6 @@ import org.embeddedt.archaicfix.config.ArchaicConfig; import org.embeddedt.archaicfix.helpers.BuiltInResourcePack; import org.embeddedt.archaicfix.helpers.SoundDeviceThread; -import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; import zone.rong.rongasm.api.StringPool; import java.lang.management.ManagementFactory; @@ -38,8 +37,6 @@ public class ClientProxy extends CommonProxy { public void preinit() { super.preinit(); Minecraft.memoryReserve = new byte[0]; - if(ArchaicConfig.enableOcclusionTweaks) - OcclusionHelpers.init(); MinecraftForge.EVENT_BUS.register(new StringPool.EventHandler()); MinecraftForge.EVENT_BUS.register(this); FMLCommonHandler.instance().bus().register(this); diff --git a/src/main/java/org/embeddedt/archaicfix/threadedupdates/ICapturableTessellator.java b/src/main/java/org/embeddedt/archaicfix/threadedupdates/ICapturableTessellator.java deleted file mode 100644 index e0c71f153..000000000 --- a/src/main/java/org/embeddedt/archaicfix/threadedupdates/ICapturableTessellator.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.embeddedt.archaicfix.threadedupdates; - -import net.minecraft.client.shader.TesselatorVertexState; - -public interface ICapturableTessellator { - - /** Like getVertexState, but doesn't sort the quads. */ - TesselatorVertexState arch$getUnsortedVertexState(); - - /** Adds the quads inside a TessellatorVertexState to this tessellator. */ - void arch$addTessellatorVertexState(TesselatorVertexState state); - - /** Flushes the tessellator's state similarly to draw(), but without drawing anything. */ - void discard(); - -} diff --git a/src/main/java/org/embeddedt/archaicfix/threadedupdates/IRendererUpdateResultHolder.java b/src/main/java/org/embeddedt/archaicfix/threadedupdates/IRendererUpdateResultHolder.java deleted file mode 100644 index ffd10a80c..000000000 --- a/src/main/java/org/embeddedt/archaicfix/threadedupdates/IRendererUpdateResultHolder.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.embeddedt.archaicfix.threadedupdates; - -public interface IRendererUpdateResultHolder { - - ThreadedChunkUpdateHelper.UpdateTask arch$getRendererUpdateTask(); - -} diff --git a/src/main/java/org/embeddedt/archaicfix/threadedupdates/RenderBlocksStack.java b/src/main/java/org/embeddedt/archaicfix/threadedupdates/RenderBlocksStack.java deleted file mode 100644 index 1a277d51a..000000000 --- a/src/main/java/org/embeddedt/archaicfix/threadedupdates/RenderBlocksStack.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.embeddedt.archaicfix.threadedupdates; - -/** A helper class to detect re-entrance of renderBlockByRenderType. */ -public class RenderBlocksStack { - - private int level; - - /** Re-entrance should be impossible on the render threads, since only vanilla blocks are rendered there. So let's - * just assume this is the case. - */ - private boolean isMainThread() { - return Thread.currentThread() == ThreadedChunkUpdateHelper.MAIN_THREAD; - } - - public void push() { - if(!isMainThread()) return; - level++; - } - - public void pop() { - if(!isMainThread()) return; - level--; - } - - public void reset() { - if(!isMainThread()) return; - level = 0; - } - - public int getLevel() { - if(!isMainThread()) return 0; - return level; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java b/src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java deleted file mode 100644 index fe4a0930a..000000000 --- a/src/main/java/org/embeddedt/archaicfix/threadedupdates/ThreadedChunkUpdateHelper.java +++ /dev/null @@ -1,329 +0,0 @@ -package org.embeddedt.archaicfix.threadedupdates; - -import com.google.common.base.Preconditions; -import lombok.SneakyThrows; -import net.minecraft.block.Block; -import net.minecraft.block.material.Material; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.RenderBlocks; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.shader.TesselatorVertexState; -import net.minecraft.world.ChunkCache; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.occlusion.interfaces.IRenderGlobalListener; -import org.embeddedt.archaicfix.occlusion.interfaces.IRendererUpdateOrderProvider; -import org.embeddedt.archaicfix.occlusion.OcclusionHelpers; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.BlockingDeque; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingDeque; - -import static org.embeddedt.archaicfix.ArchaicLogger.LOGGER; - -public class ThreadedChunkUpdateHelper implements IRenderGlobalListener { - - public static ThreadedChunkUpdateHelper instance; - - public static Thread MAIN_THREAD; - - private static final boolean DEBUG_THREADED_UPDATE_FINE_LOG = Boolean.parseBoolean(System.getProperty("archaicfix.debug.enableThreadedUpdateFineLog")); - - /** Used within the scope of WorldRenderer#updateRenderer (on the main thread). */ - public static WorldRenderer lastWorldRenderer; - - public static final RenderBlocksStack renderBlocksStack = new RenderBlocksStack(); - - /** Tasks not yet started */ - public BlockingQueue taskQueue = new LinkedBlockingDeque<>(); - /** Finished tasks ready for consumption */ - public BlockingDeque finishedTasks = new LinkedBlockingDeque<>(); - - /** Tasks that should be completed immediately on the main thread */ - public Queue urgentTaskQueue = new ArrayDeque<>(); - - public ThreadLocal threadTessellator = ThreadLocal.withInitial(Tessellator::new); - - IRendererUpdateOrderProvider rendererUpdateOrderProvider = new IRendererUpdateOrderProvider() { - /** The renderers updated during the batch */ - private List updatedRenderers = new ArrayList<>(); - - private WorldRenderer nextRenderer; - - @Override - public void prepare(List worldRenderersToUpdateList) { - preRendererUpdates(worldRenderersToUpdateList); - } - - @Override - public boolean hasNext(List worldRenderersToUpdateList) { - WorldRenderer wr; - - if(!urgentTaskQueue.isEmpty()) { - nextRenderer = urgentTaskQueue.poll(); - UpdateTask task = ((IRendererUpdateResultHolder)nextRenderer).arch$getRendererUpdateTask(); - task.cancelled = true; - return true; - } - - while((wr = finishedTasks.poll()) != null) { - UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); - if(task.cancelled || !wr.needsUpdate) { - task.clear(); - } else { - nextRenderer = wr; - return true; - } - } - return false; - } - - @Override - public WorldRenderer next(List worldRenderersToUpdateList) { - Preconditions.checkNotNull(nextRenderer); - WorldRenderer wr = nextRenderer; - nextRenderer = null; - updatedRenderers.add(wr); - - debugLog("Consuming renderer " + worldRendererToString(wr) + " " + worldRendererUpdateTaskToString(wr)); - - return wr; - } - - @Override - public void cleanup(List worldRenderersToUpdateList) { - for(WorldRenderer wr : updatedRenderers) { - worldRenderersToUpdateList.remove(wr); - ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask().clear(); - } - updatedRenderers.clear(); - urgentTaskQueue.clear(); - nextRenderer = null; - } - }; - - public void init() { - OcclusionHelpers.renderer.arch$setRendererUpdateOrderProvider(rendererUpdateOrderProvider); - OcclusionHelpers.renderer.arch$addRenderGlobalListener(this); - MAIN_THREAD = Thread.currentThread(); - - LOGGER.info("Creating " + ArchaicConfig.numChunkUpdateThreads + " chunk builder" + (ArchaicConfig.numChunkUpdateThreads > 1 ? "s" : "")); - for(int i = 0; i < ArchaicConfig.numChunkUpdateThreads; i++) { - new Thread(this::runThread, "Chunk Update Worker Thread #" + i).start(); - } - } - - private void preRendererUpdates(List toUpdateList) { - updateWorkQueue(toUpdateList); - removeCancelledResults(); - } - - private void updateWorkQueue(List toUpdateList) { - final int updateQueueSize = 64; // TODO decide this dynamically - taskQueue.clear(); - for(int i = 0; i < updateQueueSize && i < toUpdateList.size(); i++) { - WorldRenderer wr = toUpdateList.get(i); - UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); - - if(wr.distanceToEntitySquared(Minecraft.getMinecraft().renderViewEntity) < 16 * 16) { - if(!ArchaicConfig.disableBlockingChunkUpdates){ - urgentTaskQueue.add(wr); - } else { - task.important = true; - } - } - - if(task.isEmpty()) { - // No update in progress; add to task queue - debugLog("Adding " + worldRendererToString(wr) + " to task queue"); - task.chunkCache = getChunkCacheSnapshot(wr); - taskQueue.add(wr); - } - } - } - - private void removeCancelledResults() { - for(Iterator it = finishedTasks.iterator(); it.hasNext(); ) { - WorldRenderer wr = it.next(); - UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); - if(task.cancelled) { - // Discard results and allow re-schedule on worker thread. - task.clear(); - it.remove(); - } - } - } - - @Override - public void onDirtyRendererChanged(WorldRenderer wr) { - onWorldRendererDirty(wr); - } - - public void onWorldRendererDirty(WorldRenderer wr) { - UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); - if(!task.isEmpty()) { - debugLog("Renderer " + worldRendererToString(wr) + " is dirty, cancelling task"); - task.cancelled = true; - } - } - - @SneakyThrows - private void runThread() { - while(true) { - WorldRenderer wr = taskQueue.take(); - UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); - task.started = true; - try { - doChunkUpdate(wr); - } catch(Exception e) { - LOGGER.error("Failed to update chunk " + worldRendererToString(wr)); - e.printStackTrace(); - for(UpdateTask.Result r : task.result) { - r.clear(); - } - ((ICapturableTessellator)threadTessellator.get()).discard(); - } - if(!task.important) { - finishedTasks.add(wr); - } else { - finishedTasks.addFirst(wr); - } - - } - } - - /** Renders certain blocks (as defined in canBlockBeRenderedOffThread) on the worker thread, and saves the - * tessellation result. WorldRenderer#updateRenderer will skip over these blocks, and use the result that was - * produced by the worker thread to fill them in. - */ - public void doChunkUpdate(WorldRenderer wr) { - debugLog("Starting update of renderer " + worldRendererToString(wr)); - - UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); - - ChunkCache chunkcache = task.chunkCache; - - Tessellator tess = threadTessellator.get(); - - if(chunkcache != null && !chunkcache.extendedLevelsInChunkCache()) { - RenderBlocks renderblocks = new RenderBlocks(chunkcache); - - for(int pass = 0; pass < 2; pass++) { - boolean renderedSomething = false; - boolean startedTessellator = false; - - BlockLoop: - for (int y = wr.posY; y < wr.posY + 16; ++y) { - for (int z = wr.posZ; z < wr.posZ + 16; ++z) { - for (int x = wr.posX; x < wr.posX + 16; ++x) { - if(task.cancelled) { - debugLog("Realized renderer " + worldRendererToString(wr) + " is dirty, aborting update"); - break BlockLoop; - } - - Block block = chunkcache.getBlock(x, y, z); - - if (block.getMaterial() != Material.air) { - if (!startedTessellator) { - startedTessellator = true; - tess.startDrawingQuads(); - tess.setTranslation(-wr.posX, -wr.posY, -wr.posZ); - } - - int k3 = block.getRenderBlockPass(); - - if (!block.canRenderInPass(pass)) continue; - - renderedSomething |= renderblocks.renderBlockByRenderType(block, x, y, z); - } - } - } - } - - if (startedTessellator) { - task.result[pass].renderedQuads = ((ICapturableTessellator) tess).arch$getUnsortedVertexState(); - ((ICapturableTessellator) tess).discard(); - } - task.result[pass].renderedSomething = renderedSomething; - } - } - debugLog("Result of updating " + worldRendererToString(wr) + ": " + worldRendererUpdateTaskToString(wr)); - } - - public static boolean canBlockBeRenderedOffThread(Block block, int pass, int renderType) { - return renderType < 42 && renderType != 22; // vanilla block - } - - private ChunkCache getChunkCacheSnapshot(WorldRenderer wr) { - // TODO This is not thread-safe! Actually make a snapshot here. - byte pad = 1; - ChunkCache chunkcache = new ChunkCache(wr.worldObj, wr.posX - pad, wr.posY - pad, wr.posZ - pad, - wr.posX + 16 + pad, wr.posY + 16 + pad, wr.posZ + 16 + pad, pad); - return chunkcache; - } - - public void clear() { - // TODO: destroy state when chunks are reloaded or server is stopped - } - - public Tessellator getThreadTessellator() { - if(Thread.currentThread() == MAIN_THREAD) { - return Tessellator.instance; - } else { - return threadTessellator.get(); - } - } - - private static String worldRendererToString(WorldRenderer wr) { - return wr + "(" + wr.posX + ", " + wr.posY + ", " + wr.posZ + ")"; - } - - private static String worldRendererUpdateTaskToString(WorldRenderer wr) { - UpdateTask task = ((IRendererUpdateResultHolder)wr).arch$getRendererUpdateTask(); - return task.result[0].renderedSomething + " (" + (task.result[0].renderedQuads == null ? "null" : task.result[0].renderedQuads.getVertexCount()) + ")/" + task.result[1].renderedSomething + " (" + (task.result[1].renderedQuads == null ? "null" : task.result[1].renderedQuads.getVertexCount()) + ")"; - } - - private static void debugLog(String msg) { - if(DEBUG_THREADED_UPDATE_FINE_LOG) { - LOGGER.trace(msg); - } - } - - public static class UpdateTask { - public boolean started; - public boolean cancelled; - public boolean important; - public Result[] result = new Result[]{new Result(), new Result()}; - - public ChunkCache chunkCache; - - public boolean isEmpty() { - return !started; - } - - public void clear() { - started = false; - chunkCache = null; - for(Result r : result) { - r.clear(); - } - cancelled = false; - important = false; - } - - public static class Result { - public boolean renderedSomething; - public TesselatorVertexState renderedQuads; - - public void clear() { - renderedSomething = false; - renderedQuads = null; - } - } - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/threadedupdates/api/ThreadedChunkUpdates.java b/src/main/java/org/embeddedt/archaicfix/threadedupdates/api/ThreadedChunkUpdates.java deleted file mode 100644 index e0ee7379e..000000000 --- a/src/main/java/org/embeddedt/archaicfix/threadedupdates/api/ThreadedChunkUpdates.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.embeddedt.archaicfix.threadedupdates.api; - -import net.minecraft.client.renderer.Tessellator; -import org.embeddedt.archaicfix.threadedupdates.ThreadedChunkUpdateHelper; - -public class ThreadedChunkUpdates { - - public static boolean isEnabled() { - return ThreadedChunkUpdateHelper.instance != null; - } - - /** Returns the thread-local tessellator instance. Can only be called after init phase. */ - public static Tessellator getThreadTessellator() { - return ThreadedChunkUpdateHelper.instance.getThreadTessellator(); - } - -} From d7c7f3125888fae4b48702eaecfebe3eee569cf2 Mon Sep 17 00:00:00 2001 From: Bogdan <64613894+Asek3@users.noreply.github.com> Date: Sat, 25 Nov 2023 02:11:35 +0200 Subject: [PATCH 118/301] Implemented Sodium's GUI and a couple of setting fixes (#20) * Ported Sodium's GUI * Correct AO * Fixed Vignette --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../early/sodium/MixinGuiIngameForge.java | 23 ++ .../early/sodium/MixinRenderManager.java | 5 +- .../jss/notfine/core/LoadMenuButtons.java | 2 +- .../mods/sodium/client/SodiumClientMod.java | 16 + .../client/gui/SodiumGameOptionPages.java | 350 ++++++++++++++++++ .../sodium/client/gui/SodiumGameOptions.java | 60 ++- .../sodium/client/gui/SodiumOptionsGUI.java | 335 +++++++++++++++++ .../sodium/client/gui/options/Option.java | 32 ++ .../sodium/client/gui/options/OptionFlag.java | 7 + .../client/gui/options/OptionGroup.java | 39 ++ .../client/gui/options/OptionImpact.java | 24 ++ .../sodium/client/gui/options/OptionImpl.java | 202 ++++++++++ .../sodium/client/gui/options/OptionPage.java | 35 ++ .../gui/options/binding/GenericBinding.java | 24 ++ .../gui/options/binding/OptionBinding.java | 7 + .../client/gui/options/control/Control.java | 12 + .../gui/options/control/ControlElement.java | 57 +++ .../control/ControlValueFormatter.java | 47 +++ .../gui/options/control/CyclingControl.java | 104 ++++++ .../gui/options/control/SliderControl.java | 163 ++++++++ .../gui/options/control/TickBoxControl.java | 93 +++++ .../storage/MinecraftOptionsStorage.java | 25 ++ .../gui/options/storage/OptionStorage.java | 7 + .../options/storage/SodiumOptionsStorage.java | 30 ++ .../sodium/client/gui/utils/Drawable.java | 5 + .../mods/sodium/client/gui/utils/Element.java | 11 + .../mods/sodium/client/gui/utils/Rect2i.java | 35 ++ .../client/gui/widgets/AbstractWidget.java | 64 ++++ .../client/gui/widgets/FlatButtonWidget.java | 69 ++++ src/main/resources/META-INF/angelica_at.cfg | 2 + .../resources/assets/angelica/lang/en_US.lang | 82 ++++ .../resources/assets/sodium/lang/en_us.json | 82 ---- 33 files changed, 1957 insertions(+), 93 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGuiIngameForge.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Drawable.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Element.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Rect2i.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java delete mode 100644 src/main/resources/assets/sodium/lang/en_us.json diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 267bb3060..5802962fb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -49,6 +49,7 @@ public enum Mixins { ,"sodium.MixinTessellator" ,"sodium.MixinWorldClient" ,"sodium.MixinWorldRenderer" + ,"sodium.MixinGuiIngameForge" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGuiIngameForge.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGuiIngameForge.java new file mode 100644 index 000000000..1c244adb7 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGuiIngameForge.java @@ -0,0 +1,23 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraftforge.client.GuiIngameForge; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(GuiIngameForge.class) +public class MixinGuiIngameForge { + + @Redirect( + method = "renderGameOverlay(FZII)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/Minecraft;isFancyGraphicsEnabled()Z" + ) + ) + private boolean checkVignette(float whyAndHowIsThisAFloat) { + return SodiumClientMod.options().quality.enableVignette; + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java index 4268b7cf7..b7a1ffa47 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java @@ -3,6 +3,7 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; import me.jellysquid.mods.sodium.client.model.light.EntityLighter; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; @@ -17,9 +18,7 @@ public class MixinRenderManager { */ @Redirect(method = "renderEntityStatic", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getBrightnessForRender(F)I")) private int sodium$getBrightnessForRender(Entity self, float partialTicks) { - - if (SodiumClientMod.options().quality.smoothLighting == SodiumGameOptions.LightingQuality.HIGH) { - + if (Minecraft.getMinecraft().gameSettings.ambientOcclusion == SodiumGameOptions.LightingQuality.HIGH.getVanilla()) { return EntityLighter.getBlendedLight(self, partialTicks); } diff --git a/src/main/java/jss/notfine/core/LoadMenuButtons.java b/src/main/java/jss/notfine/core/LoadMenuButtons.java index bac86ee3a..5e9ef395e 100644 --- a/src/main/java/jss/notfine/core/LoadMenuButtons.java +++ b/src/main/java/jss/notfine/core/LoadMenuButtons.java @@ -14,7 +14,7 @@ public class LoadMenuButtons { public static final LoadMenuButtons INSTANCE = new LoadMenuButtons(); - @SubscribeEvent(priority = EventPriority.LOWEST) + //@SubscribeEvent(priority = EventPriority.LOWEST) public void onGui(InitGuiEvent.Post event) { if(event.gui instanceof GuiOptions) { // Hide the vanilla video settings button diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index 1dd6665fe..f2b7f1a5d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -2,9 +2,15 @@ import com.gtnewhorizons.angelica.Tags; import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import lombok.Getter; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiOptions; +import net.minecraft.client.gui.GuiVideoSettings; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.common.MinecraftForge; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -27,11 +33,21 @@ public class SodiumClientMod { public SodiumClientMod() { MainThread = Thread.currentThread(); + + MinecraftForge.EVENT_BUS.register(this); // FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onInitializeClient); // // ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); } + @SubscribeEvent + public void onGui(GuiScreenEvent.InitGuiEvent.Pre event) { + if(event.gui instanceof GuiVideoSettings) { + event.setCanceled(true); + Minecraft.getMinecraft().displayGuiScreen(new SodiumOptionsGUI(((GuiVideoSettings) event.gui).parentGuiScreen)); + } + } + public static SodiumGameOptions options() { if (CONFIG == null) { CONFIG = loadConfig(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java new file mode 100644 index 000000000..a3d618bfd --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -0,0 +1,350 @@ +package me.jellysquid.mods.sodium.client.gui; + +import com.google.common.collect.ImmutableList; +import me.jellysquid.mods.sodium.client.gui.options.*; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; +import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl; +import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl; +import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl; +import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; +import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage; +import me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw.MultidrawChunkRenderBackend; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.settings.GameSettings; +import org.lwjgl.opengl.Display; + +import java.util.ArrayList; +import java.util.List; + +public class SodiumGameOptionPages { + private static final SodiumOptionsStorage sodiumOpts = new SodiumOptionsStorage(); + private static final MinecraftOptionsStorage vanillaOpts = new MinecraftOptionsStorage(); + + public static OptionPage general() { + List groups = new ArrayList<>(); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.renderDistance")) + .setTooltip(I18n.format("sodium.options.view_distance.tooltip")) + .setControl(option -> new SliderControl(option, 2, (int) GameSettings.Options.RENDER_DISTANCE.getValueMax(), 1, ControlValueFormatter.quantity("options.chunks"))) + .setBinding((options, value) -> options.renderDistanceChunks = value, options -> options.renderDistanceChunks) + .setImpact(OptionImpact.HIGH) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.gamma")) + .setTooltip(I18n.format("sodium.options.brightness.tooltip")) + .setControl(opt -> new SliderControl(opt, 0, 100, 1, ControlValueFormatter.brightness())) + .setBinding((opts, value) -> opts.gammaSetting = value * 0.01F, (opts) -> (int) (opts.gammaSetting / 0.01F)) + .build()) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("sodium.options.clouds.name")) + .setTooltip(I18n.format("sodium.options.clouds.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.clouds = value, (opts) -> opts.clouds) + .setImpact(OptionImpact.LOW) + .build()) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.guiScale")) + .setTooltip(I18n.format("sodium.options.gui_scale.tooltip")) + .setControl(option -> new SliderControl(option, 0, 3, 1, ControlValueFormatter.guiScale())) + .setBinding((opts, value) -> { + opts.guiScale = value; + // Resizing our window + if(Minecraft.getMinecraft().currentScreen instanceof SodiumOptionsGUI oldGui) { + Minecraft.getMinecraft().displayGuiScreen(new SodiumOptionsGUI(oldGui.prevScreen)); + } + }, opts -> opts.guiScale) + .build()) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("options.fullscreen")) + .setTooltip(I18n.format("sodium.options.fullscreen.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> { + opts.fullScreen = value; + + Minecraft client = Minecraft.getMinecraft(); + + if (client.isFullScreen() != opts.fullScreen) { + client.toggleFullscreen(); + + // The client might not be able to enter full-screen mode + opts.fullScreen = client.isFullScreen(); + } + }, (opts) -> opts.fullScreen) + .build()) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("options.vsync")) + .setTooltip(I18n.format("sodium.options.v_sync.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> { + opts.enableVsync = value; + Display.setVSyncEnabled(opts.enableVsync); + }, opts -> opts.enableVsync) + .setImpact(OptionImpact.VARIES) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.framerateLimit")) + .setTooltip(I18n.format("sodium.options.fps_limit.tooltip")) + .setControl(option -> new SliderControl(option, 5, 260, 5, ControlValueFormatter.fpsLimit())) + .setBinding((opts, value) -> opts.limitFramerate = value, opts -> opts.limitFramerate) + .build()) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("options.viewBobbing")) + .setTooltip(I18n.format("sodium.options.view_bobbing.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.viewBobbing = value, opts -> opts.viewBobbing) + .build()) + .build()); + + return new OptionPage(I18n.format("stat.generalButton"), ImmutableList.copyOf(groups)); + } + + public static OptionPage quality() { + List groups = new ArrayList<>(); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsMode.class, vanillaOpts) + .setName(I18n.format("options.graphics")) + .setTooltip(I18n.format("sodium.options.graphics_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsMode.class)) + .setBinding( + (opts, value) -> opts.fancyGraphics = value.isFancy(), + opts -> SodiumGameOptions.GraphicsMode.fromBoolean(opts.fancyGraphics)) + .setImpact(OptionImpact.HIGH) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .setName(I18n.format("options.renderClouds")) + .setTooltip(I18n.format("sodium.options.clouds_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setBinding((opts, value) -> opts.quality.cloudQuality = value, opts -> opts.quality.cloudQuality) + .setImpact(OptionImpact.LOW) + .build()) + .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .setName(I18n.format("soundCategory.weather")) + .setTooltip(I18n.format("sodium.options.weather_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setBinding((opts, value) -> opts.quality.weatherQuality = value, opts -> opts.quality.weatherQuality) + .setImpact(OptionImpact.MEDIUM) + .build()) + .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .setName(I18n.format("sodium.options.leaves_quality.name")) + .setTooltip(I18n.format("sodium.options.leaves_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setBinding((opts, value) -> opts.quality.leavesQuality = value, opts -> opts.quality.leavesQuality) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .add(OptionImpl.createBuilder(SodiumGameOptions.ParticleMode.class, vanillaOpts) + .setName(I18n.format("options.particles")) + .setTooltip(I18n.format("sodium.options.particle_quality.tooltip")) + .setControl(opt -> new CyclingControl<>(opt, SodiumGameOptions.ParticleMode.class)) + .setBinding((opts, value) -> opts.particleSetting = value.ordinal(), (opts) -> SodiumGameOptions.ParticleMode.fromOrdinal(opts.particleSetting)) + .setImpact(OptionImpact.MEDIUM) + .build()) + .add(OptionImpl.createBuilder(SodiumGameOptions.LightingQuality.class, vanillaOpts) + .setName(I18n.format("options.ao")) + .setTooltip(I18n.format("sodium.options.smooth_lighting.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.LightingQuality.class)) + .setBinding((opts, value) -> opts.ambientOcclusion = value.getVanilla(), opts -> SodiumGameOptions.LightingQuality.fromOrdinal(opts.ambientOcclusion)) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + // TODO + /*.add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(new TranslatableText("options.biomeBlendRadius")) + .setTooltip(new TranslatableText("sodium.options.biome_blend.tooltip")) + .setControl(option -> new SliderControl(option, 0, 7, 1, ControlValueFormatter.quantityOrDisabled("sodium.options.biome_blend.value", "gui.none"))) + .setBinding((opts, value) -> opts.biomeBlendRadius = value, opts -> opts.biomeBlendRadius) + .setImpact(OptionImpact.LOW) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(new TranslatableText("options.entityDistanceScaling")) + .setTooltip(new TranslatableText("sodium.options.entity_distance.tooltip")) + .setControl(option -> new SliderControl(option, 50, 500, 25, ControlValueFormatter.percentage())) + .setBinding((opts, value) -> opts.entityDistanceScaling = value / 100.0F, opts -> Math.round(opts.entityDistanceScaling * 100.0F)) + .setImpact(OptionImpact.MEDIUM) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(new TranslatableText("options.entityShadows")) + .setTooltip(new TranslatableText("sodium.options.entity_shadows.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.entityShadows = value, opts -> opts.entityShadows) + .setImpact(OptionImpact.LOW) + .build())*/ + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.vignette.name")) + .setTooltip(I18n.format("sodium.options.vignette.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.quality.enableVignette = value, opts -> opts.quality.enableVignette) + .setImpact(OptionImpact.LOW) + .build()) + .build()); + + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.mipmapLevels")) + .setTooltip(I18n.format("sodium.options.mipmap_levels.tooltip")) + .setControl(option -> new SliderControl(option, 0, 4, 1, ControlValueFormatter.multiplier())) + .setBinding((opts, value) -> opts.mipmapLevels = value, opts -> opts.mipmapLevels) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_ASSET_RELOAD) + .build()) + .build()); + + + return new OptionPage(I18n.format("sodium.options.pages.quality"), ImmutableList.copyOf(groups)); + } + + public static OptionPage advanced() { + List groups = new ArrayList<>(); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.use_chunk_multidraw.name")) + .setTooltip(I18n.format("sodium.options.use_chunk_multidraw.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.advanced.useChunkMultidraw = value, opts -> opts.advanced.useChunkMultidraw) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .setImpact(OptionImpact.EXTREME) + .setEnabled(MultidrawChunkRenderBackend.isSupported(sodiumOpts.getData().advanced.ignoreDriverBlacklist)) + .build()) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.use_vertex_objects.name")) + .setTooltip(I18n.format("sodium.options.use_vertex_objects.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.advanced.useVertexArrayObjects = value, opts -> opts.advanced.useVertexArrayObjects) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .setImpact(OptionImpact.LOW) + .build()) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.use_block_face_culling.name")) + .setTooltip(I18n.format("sodium.options.use_block_face_culling.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.MEDIUM) + .setBinding((opts, value) -> opts.advanced.useBlockFaceCulling = value, opts -> opts.advanced.useBlockFaceCulling) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.use_compact_vertex_format.name")) + .setTooltip(I18n.format("sodium.options.use_compact_vertex_format.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.MEDIUM) + .setBinding((opts, value) -> opts.advanced.useCompactVertexFormat = value, opts -> opts.advanced.useCompactVertexFormat) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.use_fog_occlusion.name")) + .setTooltip(I18n.format("sodium.options.use_fog_occlusion.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.advanced.useFogOcclusion = value, opts -> opts.advanced.useFogOcclusion) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.use_entity_culling.name")) + .setTooltip(I18n.format("sodium.options.use_entity_culling.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.MEDIUM) + .setBinding((opts, value) -> opts.advanced.useEntityCulling = value, opts -> opts.advanced.useEntityCulling) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.use_particle_culling.name")) + .setTooltip(I18n.format("sodium.options.use_particle_culling.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.MEDIUM) + .setBinding((opts, value) -> opts.advanced.useParticleCulling = value, opts -> opts.advanced.useParticleCulling) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.animate_only_visible_textures.name")) + .setTooltip(I18n.format("sodium.options.animate_only_visible_textures.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.HIGH) + .setBinding((opts, value) -> opts.advanced.animateOnlyVisibleTextures = value, opts -> opts.advanced.animateOnlyVisibleTextures) + .build() + ) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.allow_direct_memory_access.name")) + .setTooltip(I18n.format("sodium.options.allow_direct_memory_access.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.HIGH) + .setBinding((opts, value) -> opts.advanced.allowDirectMemoryAccess = value, opts -> opts.advanced.allowDirectMemoryAccess) + .build() + ) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.ignore_driver_blacklist.name")) + .setTooltip(I18n.format("sodium.options.ignore_driver_blacklist.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.advanced.ignoreDriverBlacklist = value, opts -> opts.advanced.ignoreDriverBlacklist) + .build() + ) + .build()); + + return new OptionPage(I18n.format("sodium.options.pages.advanced"), ImmutableList.copyOf(groups)); + } + + public static OptionPage performance() { + List groups = new ArrayList<>(); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(int.class, sodiumOpts) + .setName(I18n.format("sodium.options.chunk_update_threads.name")) + .setTooltip(I18n.format("sodium.options.chunk_update_threads.tooltip")) + .setControl(o -> new SliderControl(o, 0, Runtime.getRuntime().availableProcessors(), 1, ControlValueFormatter.quantityOrDisabled("sodium.options.threads.value", "sodium.options.default"))) + .setImpact(OptionImpact.HIGH) + .setBinding((opts, value) -> opts.performance.chunkBuilderThreads = value, opts -> opts.performance.chunkBuilderThreads) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build() + ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.always_defer_chunk_updates.name")) + .setTooltip(I18n.format("sodium.options.always_defer_chunk_updates.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.HIGH) + .setBinding((opts, value) -> opts.performance.alwaysDeferChunkUpdates = value, opts -> opts.performance.alwaysDeferChunkUpdates) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + // TODO Instead of value in Angelica config + /*.add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(new TranslatableText("sodium.options.use_no_error_context.name")) + .setTooltip(new TranslatableText("sodium.options.use_no_error_context.tooltip")) + .setControl(TickBoxControl::new) + .setImpact(OptionImpact.LOW) + .setBinding((opts, value) -> opts.performance.useNoErrorGLContext = value, opts -> opts.performance.useNoErrorGLContext) + .setEnabled(supportsNoErrorContext()) + .setFlags(OptionFlag.REQUIRES_GAME_RESTART) + .build())*/ + .build()); + + return new OptionPage(I18n.format("sodium.options.pages.performance"), ImmutableList.copyOf(groups)); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 0989e8707..986900d85 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -58,16 +58,50 @@ public static class QualitySettings { public GraphicsQuality leavesQuality = GraphicsQuality.DEFAULT; public boolean enableVignette = true; - public boolean enableClouds = true; - - public LightingQuality smoothLighting = LightingQuality.HIGH; } public static class NotificationSettings { public boolean hideDonationButton = false; } - public enum GraphicsQuality { + public enum ParticleMode { + ALL("options.graphics.fancy"), + DECREASED("options.graphics.fast"), + MINIMAL("options.particles.minimal"); + + private static final ParticleMode[] VALUES = values(); + + private final String name; + + ParticleMode(String name) { + this.name = name; + } + + public static ParticleMode fromOrdinal(int ordinal) { + return VALUES[ordinal]; + } + } + + public enum GraphicsMode { + FANCY("options.graphics.fancy"), + FAST("options.graphics.fast"); + + private final String name; + + GraphicsMode(String name) { + this.name = name; + } + + public boolean isFancy() { + return this == FANCY; + } + + public static GraphicsMode fromBoolean(boolean isFancy) { + return isFancy ? FANCY : FAST; + } + } + + public enum GraphicsQuality { DEFAULT("generator.default"), FANCY("options.clouds.fancy"), FAST("options.clouds.fast"); @@ -77,23 +111,35 @@ public enum GraphicsQuality { GraphicsQuality(String name) { this.name = name; } - } public enum LightingQuality { - HIGH("options.ao.max"), + OFF("options.ao.off"), LOW("options.ao.min"), - OFF("options.ao.off"); + HIGH("options.ao.max"); + + private static final LightingQuality[] VALUES = values(); private final String name; + private final int vanilla; + LightingQuality(String name) { this.name = name; + this.vanilla = ordinal(); } public String getLocalizedName() { return this.name; } + + public int getVanilla() { + return vanilla; + } + + public static LightingQuality fromOrdinal(int ordinal) { + return VALUES[ordinal]; + } } private static final Gson GSON = new GsonBuilder() diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java new file mode 100644 index 000000000..9ccb30d4e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java @@ -0,0 +1,335 @@ +package me.jellysquid.mods.sodium.client.gui; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.options.*; +import me.jellysquid.mods.sodium.client.gui.options.control.Control; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; +import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; +import me.jellysquid.mods.sodium.client.gui.utils.Drawable; +import me.jellysquid.mods.sodium.client.gui.utils.Element; +import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiVideoSettings; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.EnumChatFormatting; +import org.lwjgl.input.Keyboard; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Stream; + +public class SodiumOptionsGUI extends GuiScreen { + + private final List children = new CopyOnWriteArrayList<>(); + + private final List pages = new ArrayList<>(); + + private final List> controls = new ArrayList<>(); + private final List drawable = new ArrayList<>(); + + public final GuiScreen prevScreen; + + private OptionPage currentPage; + + private FlatButtonWidget applyButton, closeButton, undoButton; + private FlatButtonWidget donateButton, hideDonateButton; + + private boolean hasPendingChanges; + private ControlElement hoveredElement; + + public SodiumOptionsGUI(GuiScreen prevScreen) { + this.prevScreen = prevScreen; + + this.pages.add(SodiumGameOptionPages.general()); + this.pages.add(SodiumGameOptionPages.quality()); + this.pages.add(SodiumGameOptionPages.advanced()); + this.pages.add(SodiumGameOptionPages.performance()); + } + + public void setPage(OptionPage page) { + this.currentPage = page; + + this.rebuildGUI(); + } + + @Override + public void initGui() { + this.rebuildGUI(); + } + + private void rebuildGUI() { + this.controls.clear(); + this.children.clear(); + this.drawable.clear(); + + if (this.currentPage == null) { + if (this.pages.isEmpty()) { + throw new IllegalStateException("No pages are available?!"); + } + + // Just use the first page for now + this.currentPage = this.pages.get(0); + } + + this.rebuildGUIPages(); + this.rebuildGUIOptions(); + + this.undoButton = new FlatButtonWidget(new Dim2i(this.width - 211, this.height - 26, 65, 20), I18n.format("sodium.options.buttons.undo"), this::undoChanges); + this.applyButton = new FlatButtonWidget(new Dim2i(this.width - 142, this.height - 26, 65, 20), I18n.format("sodium.options.buttons.apply"), this::applyChanges); + this.closeButton = new FlatButtonWidget(new Dim2i(this.width - 73, this.height - 26, 65, 20), I18n.format("gui.done"), this::onClose); + String donateToJelly = I18n.format("sodium.options.buttons.donate"); + int width = 12 + this.fontRendererObj.getStringWidth(donateToJelly); + this.donateButton = new FlatButtonWidget(new Dim2i(this.width - width - 32, 6, width, 20), donateToJelly, this::openDonationPage); + this.hideDonateButton = new FlatButtonWidget(new Dim2i(this.width - 26, 6, 20, 20), "x", this::hideDonationButton); + + if (SodiumClientMod.options().notifications.hideDonationButton) { + this.setDonationButtonVisibility(false); + } + + this.children.add(this.undoButton); + this.children.add(this.applyButton); + this.children.add(this.closeButton); + this.children.add(this.donateButton); + this.children.add(this.hideDonateButton); + + for (Element element : this.children) { + if (element instanceof Drawable) { + this.drawable.add((Drawable) element); + } + } + } + + private void setDonationButtonVisibility(boolean value) { + this.donateButton.setVisible(value); + this.hideDonateButton.setVisible(value); + } + + private void hideDonationButton() { + SodiumGameOptions options = SodiumClientMod.options(); + options.notifications.hideDonationButton = true; + + try { + options.writeChanges(); + } catch (IOException e) { + throw new RuntimeException("Failed to save configuration", e); + } + + this.setDonationButtonVisibility(false); + } + + private void rebuildGUIPages() { + int x = 6; + int y = 6; + + for (OptionPage page : this.pages) { + int width = 12 + this.fontRendererObj.getStringWidth(page.getName()); + + FlatButtonWidget button = new FlatButtonWidget(new Dim2i(x, y, width, 18), page.getName(), () -> this.setPage(page)); + button.setSelected(this.currentPage == page); + + x += width + 6; + + this.children.add(button); + } + } + + private void rebuildGUIOptions() { + int x = 6; + int y = 28; + + for (OptionGroup group : this.currentPage.getGroups()) { + // Add each option's control element + for (Option option : group.getOptions()) { + Control control = option.getControl(); + ControlElement element = control.createElement(new Dim2i(x, y, 200, 18)); + + this.controls.add(element); + this.children.add(element); + + // Move down to the next option + y += 18; + } + + // Add padding beneath each option group + y += 4; + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float delta) { + super.drawDefaultBackground(); + + this.updateControls(); + + for (Drawable drawable : this.drawable) { + drawable.render(mouseX, mouseY, delta); + } + + if (this.hoveredElement != null) { + this.renderOptionTooltip(this.hoveredElement); + } + } + + private void updateControls() { + ControlElement hovered = this.getActiveControls() + .filter(ControlElement::isHovered) + .findFirst() + .orElse(null); + + boolean hasChanges = this.getAllOptions() + .anyMatch(Option::hasChanged); + + for (OptionPage page : this.pages) { + for (Option option : page.getOptions()) { + if (option.hasChanged()) { + hasChanges = true; + } + } + } + + this.applyButton.setEnabled(hasChanges); + this.undoButton.setVisible(hasChanges); + this.closeButton.setEnabled(!hasChanges); + + this.hasPendingChanges = hasChanges; + this.hoveredElement = hovered; + } + + private Stream> getAllOptions() { + return this.pages.stream() + .flatMap(s -> s.getOptions().stream()); + } + + private Stream> getActiveControls() { + return this.controls.stream(); + } + + private void renderOptionTooltip(ControlElement element) { + Dim2i dim = element.getDimensions(); + + int textPadding = 3; + int boxPadding = 3; + + int boxWidth = 200; + + int boxY = dim.getOriginY(); + int boxX = dim.getLimitX() + boxPadding; + + Option option = element.getOption(); + List tooltip = new ArrayList<>(this.fontRendererObj.listFormattedStringToWidth(option.getTooltip(), boxWidth - (textPadding * 2))); + + OptionImpact impact = option.getImpact(); + + if (impact != null) { + tooltip.add(EnumChatFormatting.GRAY + I18n.format("sodium.options.performance_impact_string", impact.toDisplayString())); + } + + int boxHeight = (tooltip.size() * 12) + boxPadding; + int boxYLimit = boxY + boxHeight; + int boxYCutoff = this.height - 40; + + // If the box is going to be cutoff on the Y-axis, move it back up the difference + if (boxYLimit > boxYCutoff) { + boxY -= boxYLimit - boxYCutoff; + } + + this.drawGradientRect(boxX, boxY, boxX + boxWidth, boxY + boxHeight, 0xE0000000, 0xE0000000); + + for (int i = 0; i < tooltip.size(); i++) { + this.fontRendererObj.drawString(tooltip.get(i), boxX + textPadding, boxY + textPadding + (i * 12), 0xFFFFFFFF); + } + } + + private void applyChanges() { + final HashSet> dirtyStorages = new HashSet<>(); + final EnumSet flags = EnumSet.noneOf(OptionFlag.class); + + this.getAllOptions().forEach((option -> { + if (!option.hasChanged()) { + return; + } + + option.applyChanges(); + + flags.addAll(option.getFlags()); + dirtyStorages.add(option.getStorage()); + })); + + if (flags.contains(OptionFlag.REQUIRES_RENDERER_RELOAD)) { + this.mc.renderGlobal.loadRenderers(); + } + + if (flags.contains(OptionFlag.REQUIRES_ASSET_RELOAD)) { + this.mc.getTextureMapBlocks().setMipmapLevels(this.mc.gameSettings.mipmapLevels); + this.mc.refreshResources(); + } + + for (OptionStorage storage : dirtyStorages) { + storage.save(); + } + } + + private void undoChanges() { + this.getAllOptions() + .forEach(Option::reset); + } + + // TODO Was taken from GuiChat, however i am pretty sure this code is very broken on other OS'es rather Windows + private void openDonationPage() { + try { + Class oclass = Class.forName("java.awt.Desktop"); + Object object = oclass.getMethod("getDesktop").invoke(null); + oclass.getMethod("browse", URI.class).invoke(object, "https://caffeinemc.net/donate"); + } catch (Throwable throwable) { + SodiumClientMod.logger().error("Couldn't open link", throwable); + } + } + + @Override + public void keyTyped(char typedChar, int keyCode) { + if(keyCode == Keyboard.KEY_ESCAPE && !shouldCloseOnEsc()) { + return; + } else if (keyCode == Keyboard.KEY_ESCAPE) { + onClose(); + return; + } + + if (keyCode == Keyboard.KEY_P && isShiftKeyDown()) { + this.mc.displayGuiScreen(new GuiVideoSettings(this.prevScreen, this.mc.gameSettings)); + + return; + } + + super.keyTyped(typedChar, keyCode); + } + + public boolean shouldCloseOnEsc() { + return !this.hasPendingChanges; + } + + // We can't override onGuiClosed due to StackOverflow + public void onClose() { + this.mc.displayGuiScreen(this.prevScreen); + super.onGuiClosed(); + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) { + super.mouseClicked(mouseX, mouseY, mouseButton); + + this.children.forEach(element -> element.mouseClicked(mouseX, mouseY, mouseButton)); + } + + @Override + protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { + super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick); + + this.children.forEach(element -> element.mouseDragged(mouseX, mouseY)); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java new file mode 100644 index 000000000..8169fff1f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java @@ -0,0 +1,32 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +import me.jellysquid.mods.sodium.client.gui.options.control.Control; +import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; + +import java.util.Collection; + +public interface Option { + String getName(); + + String getTooltip(); + + OptionImpact getImpact(); + + Control getControl(); + + T getValue(); + + void setValue(T value); + + void reset(); + + OptionStorage getStorage(); + + boolean isAvailable(); + + boolean hasChanged(); + + void applyChanges(); + + Collection getFlags(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java new file mode 100644 index 000000000..d7ac00621 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java @@ -0,0 +1,7 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +public enum OptionFlag { + REQUIRES_RENDERER_RELOAD, + REQUIRES_ASSET_RELOAD, + REQUIRES_GAME_RESTART +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java new file mode 100644 index 000000000..97426724a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java @@ -0,0 +1,39 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +import com.google.common.collect.ImmutableList; +import org.apache.commons.lang3.Validate; + +import java.util.ArrayList; +import java.util.List; + +public class OptionGroup { + private final ImmutableList> options; + + private OptionGroup(ImmutableList> options) { + this.options = options; + } + + public static Builder createBuilder() { + return new Builder(); + } + + public ImmutableList> getOptions() { + return this.options; + } + + public static class Builder { + private final List> options = new ArrayList<>(); + + public Builder add(Option option) { + this.options.add(option); + + return this; + } + + public OptionGroup build() { + Validate.notEmpty(this.options, "At least one option must be specified"); + + return new OptionGroup(ImmutableList.copyOf(this.options)); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java new file mode 100644 index 000000000..0f6aff1ad --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java @@ -0,0 +1,24 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +import net.minecraft.client.resources.I18n; +import net.minecraft.util.EnumChatFormatting; + +public enum OptionImpact { + LOW(EnumChatFormatting.GREEN, I18n.format("sodium.option_impact.low")), + MEDIUM(EnumChatFormatting.YELLOW, I18n.format("sodium.option_impact.medium")), + HIGH(EnumChatFormatting.GOLD, I18n.format("sodium.option_impact.high")), + EXTREME(EnumChatFormatting.RED, I18n.format("sodium.option_impact.extreme")), + VARIES(EnumChatFormatting.WHITE, I18n.format("sodium.option_impact.varies")); + + private final EnumChatFormatting color; + private final String text; + + OptionImpact(EnumChatFormatting color, String text) { + this.color = color; + this.text = text; + } + + public String toDisplayString() { + return this.color + this.text; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java new file mode 100644 index 000000000..7b65ea293 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java @@ -0,0 +1,202 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +import me.jellysquid.mods.sodium.client.gui.options.binding.GenericBinding; +import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding; +import me.jellysquid.mods.sodium.client.gui.options.control.Control; +import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; +import org.apache.commons.lang3.Validate; + +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class OptionImpl implements Option { + private final OptionStorage storage; + + private final OptionBinding binding; + private final Control control; + + private final EnumSet flags; + + private final String name; + private final String tooltip; + + private final OptionImpact impact; + + private T value; + private T modifiedValue; + + private final boolean enabled; + + private OptionImpl(OptionStorage storage, + String name, + String tooltip, + OptionBinding binding, + Function, Control> control, + EnumSet flags, + OptionImpact impact, + boolean enabled) { + this.storage = storage; + this.name = name; + this.tooltip = tooltip; + this.binding = binding; + this.impact = impact; + this.flags = flags; + this.control = control.apply(this); + this.enabled = enabled; + + this.reset(); + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getTooltip() { + return this.tooltip; + } + + @Override + public OptionImpact getImpact() { + return this.impact; + } + + @Override + public Control getControl() { + return this.control; + } + + @Override + public T getValue() { + return this.modifiedValue; + } + + @Override + public void setValue(T value) { + this.modifiedValue = value; + } + + @Override + public void reset() { + this.value = this.binding.getValue(this.storage.getData()); + this.modifiedValue = this.value; + } + + @Override + public OptionStorage getStorage() { + return this.storage; + } + + @Override + public boolean isAvailable() { + return this.enabled; + } + + @Override + public boolean hasChanged() { + return !this.value.equals(this.modifiedValue); + } + + @Override + public void applyChanges() { + this.binding.setValue(this.storage.getData(), this.modifiedValue); + this.value = this.modifiedValue; + } + + @Override + public Collection getFlags() { + return this.flags; + } + + public static OptionImpl.Builder createBuilder(Class type, OptionStorage storage) { + return new Builder<>(storage); + } + + public static class Builder { + private final OptionStorage storage; + private String name; + private String tooltip; + private OptionBinding binding; + private Function, Control> control; + private OptionImpact impact; + private final EnumSet flags = EnumSet.noneOf(OptionFlag.class); + private boolean enabled = true; + + private Builder(OptionStorage storage) { + this.storage = storage; + } + + public Builder setName(String name) { + Validate.notNull(name, "Argument must not be null"); + + this.name = name; + + return this; + } + + public Builder setTooltip(String tooltip) { + Validate.notNull(tooltip, "Argument must not be null"); + + this.tooltip = tooltip; + + return this; + } + + public Builder setBinding(BiConsumer setter, Function getter) { + Validate.notNull(setter, "Setter must not be null"); + Validate.notNull(getter, "Getter must not be null"); + + this.binding = new GenericBinding<>(setter, getter); + + return this; + } + + + public Builder setBinding(OptionBinding binding) { + Validate.notNull(binding, "Argument must not be null"); + + this.binding = binding; + + return this; + } + + public Builder setControl(Function, Control> control) { + Validate.notNull(control, "Argument must not be null"); + + this.control = control; + + return this; + } + + public Builder setImpact(OptionImpact impact) { + this.impact = impact; + + return this; + } + + public Builder setEnabled(boolean value) { + this.enabled = value; + + return this; + } + + public Builder setFlags(OptionFlag... flags) { + Collections.addAll(this.flags, flags); + + return this; + } + + public OptionImpl build() { + Validate.notNull(this.name, "Name must be specified"); + Validate.notNull(this.tooltip, "Tooltip must be specified"); + Validate.notNull(this.binding, "Option binding must be specified"); + Validate.notNull(this.control, "Control must be specified"); + + return new OptionImpl<>(this.storage, this.name, this.tooltip, this.binding, this.control, this.flags, this.impact, this.enabled); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java new file mode 100644 index 000000000..a02254c90 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java @@ -0,0 +1,35 @@ +package me.jellysquid.mods.sodium.client.gui.options; + +import com.google.common.collect.ImmutableList; + +public class OptionPage { + private final String name; + private final ImmutableList groups; + private final ImmutableList> options; + + public OptionPage(String name, ImmutableList groups) { + this.name = name; + this.groups = groups; + + ImmutableList.Builder> builder = ImmutableList.builder(); + + for (OptionGroup group : groups) { + builder.addAll(group.getOptions()); + } + + this.options = builder.build(); + } + + public ImmutableList getGroups() { + return this.groups; + } + + public ImmutableList> getOptions() { + return this.options; + } + + public String getName() { + return this.name; + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java new file mode 100644 index 000000000..9e166c93e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java @@ -0,0 +1,24 @@ +package me.jellysquid.mods.sodium.client.gui.options.binding; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class GenericBinding implements OptionBinding { + private final BiConsumer setter; + private final Function getter; + + public GenericBinding(BiConsumer setter, Function getter) { + this.setter = setter; + this.getter = getter; + } + + @Override + public void setValue(S storage, T value) { + this.setter.accept(storage, value); + } + + @Override + public T getValue(S storage) { + return this.getter.apply(storage); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java new file mode 100644 index 000000000..5e597a679 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java @@ -0,0 +1,7 @@ +package me.jellysquid.mods.sodium.client.gui.options.binding; + +public interface OptionBinding { + void setValue(S storage, T value); + + T getValue(S storage); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java new file mode 100644 index 000000000..28931db82 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java @@ -0,0 +1,12 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.util.Dim2i; + +public interface Control { + Option getOption(); + + ControlElement createElement(Dim2i dim); + + int getMaxWidth(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java new file mode 100644 index 000000000..0b3cadfeb --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java @@ -0,0 +1,57 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.widgets.AbstractWidget; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.util.EnumChatFormatting; + +public class ControlElement extends AbstractWidget { + protected final Option option; + + protected final Dim2i dim; + + protected boolean hovered; + + public ControlElement(Option option, Dim2i dim) { + this.option = option; + this.dim = dim; + } + + public boolean isHovered() { + return this.hovered; + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + String name = this.option.getName(); + String label; + + if (this.hovered && this.font.getStringWidth(name) > (this.dim.getWidth() - this.option.getControl().getMaxWidth())) { + name = name.substring(0, Math.min(name.length(), 10)) + "..."; + } + + if (this.option.isAvailable()) { + if (this.option.hasChanged()) { + label = EnumChatFormatting.ITALIC + name + " *"; + } else { + label = EnumChatFormatting.WHITE + name; + } + } else { + label = String.valueOf(EnumChatFormatting.GRAY) + EnumChatFormatting.STRIKETHROUGH + name; + } + + this.hovered = this.dim.containsCursor(mouseX, mouseY); + + + this.drawRect(this.dim.getOriginX(), this.dim.getOriginY(), this.dim.getLimitX(), this.dim.getLimitY(), this.hovered ? 0xE0000000 : 0x90000000); + this.drawString(label, this.dim.getOriginX() + 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); + } + + public Option getOption() { + return this.option; + } + + public Dim2i getDimensions() { + return this.dim; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java new file mode 100644 index 000000000..69c454848 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java @@ -0,0 +1,47 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import net.minecraft.client.resources.I18n; + +public interface ControlValueFormatter { + static ControlValueFormatter guiScale() { + return (v) -> (v == 0) ? I18n.format("options.guiScale.auto") : I18n.format(v + "x"); + } + + static ControlValueFormatter fpsLimit() { + return (v) -> (v == 260) ? I18n.format("options.framerateLimit.max") : I18n.format("options.framerate", v); + } + + static ControlValueFormatter brightness() { + return (v) -> { + if (v == 0) { + return I18n.format("options.gamma.min"); + } else if (v == 100) { + return I18n.format("options.gamma.max"); + } else { + return v + "%"; + } + }; + } + + String format(int value); + + static ControlValueFormatter percentage() { + return (v) -> v + "%"; + } + + static ControlValueFormatter multiplier() { + return (v) -> v + "x"; + } + + static ControlValueFormatter quantity(String name) { + return (v) -> I18n.format(name, v); + } + + static ControlValueFormatter quantityOrDisabled(String name, String disableText) { + return (v) -> I18n.format(v == 0 ? disableText : name, v); + } + + static ControlValueFormatter number() { + return String::valueOf; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java new file mode 100644 index 000000000..e31ab5e18 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java @@ -0,0 +1,104 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.resources.I18n; +import org.apache.commons.lang3.Validate; + +public class CyclingControl> implements Control { + private final Option option; + private final T[] allowedValues; + private final String[] names; + + public CyclingControl(Option option, Class enumType) { + this(option, enumType, enumType.getEnumConstants()); + } + + public CyclingControl(Option option, Class enumType, String[] names) { + T[] universe = enumType.getEnumConstants(); + + Validate.isTrue(universe.length == names.length, "Mismatch between universe length and names array length"); + Validate.notEmpty(universe, "The enum universe must contain at least one item"); + + this.option = option; + this.allowedValues = universe; + this.names = names; + } + + public CyclingControl(Option option, Class enumType, T[] allowedValues) { + T[] universe = enumType.getEnumConstants(); + + this.option = option; + this.allowedValues = allowedValues; + this.names = new String[universe.length]; + + for (int i = 0; i < this.names.length; i++) { + String name; + T value = universe[i]; + + name = I18n.format(value.name()); + + this.names[i] = name; + } + } + + @Override + public Option getOption() { + return this.option; + } + + @Override + public ControlElement createElement(Dim2i dim) { + return new CyclingControlElement<>(this.option, dim, this.allowedValues, this.names); + } + + @Override + public int getMaxWidth() { + return 70; + } + + private static class CyclingControlElement> extends ControlElement { + private final T[] allowedValues; + private final String[] names; + private int currentIndex; + + public CyclingControlElement(Option option, Dim2i dim, T[] allowedValues, String[] names) { + super(option, dim); + + this.allowedValues = allowedValues; + this.names = names; + this.currentIndex = 0; + + for (int i = 0; i < allowedValues.length; i++) { + if (allowedValues[i] == option.getValue()) { + this.currentIndex = i; + break; + } + } + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + super.render(mouseX, mouseY, delta); + + Enum value = this.option.getValue(); + String name = this.names[value.ordinal()]; + + int strWidth = this.getTextWidth(name); + this.drawString(name, this.dim.getLimitX() - strWidth - 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { + this.currentIndex = (this.option.getValue().ordinal() + 1) % this.allowedValues.length; + this.option.setValue(this.allowedValues[this.currentIndex]); + this.playClickSound(); + + return true; + } + + return false; + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java new file mode 100644 index 000000000..e95ae893f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java @@ -0,0 +1,163 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.utils.Rect2i; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.util.MathHelper; +import org.apache.commons.lang3.Validate; + +public class SliderControl implements Control { + private final Option option; + + private final int min, max, interval; + + private final ControlValueFormatter mode; + + public SliderControl(Option option, int min, int max, int interval, ControlValueFormatter mode) { + Validate.isTrue(max > min, "The maximum value must be greater than the minimum value"); + Validate.isTrue(interval > 0, "The slider interval must be greater than zero"); + Validate.isTrue(((max - min) % interval) == 0, "The maximum value must be divisable by the interval"); + Validate.notNull(mode, "The slider mode must not be null"); + + this.option = option; + this.min = min; + this.max = max; + this.interval = interval; + this.mode = mode; + } + + @Override + public ControlElement createElement(Dim2i dim) { + return new Button(this.option, dim, this.min, this.max, this.interval, this.mode); + } + + @Override + public Option getOption() { + return this.option; + } + + @Override + public int getMaxWidth() { + return 130; + } + + private static class Button extends ControlElement { + private static final int THUMB_WIDTH = 2, TRACK_HEIGHT = 1; + + private final Rect2i sliderBounds; + private final ControlValueFormatter formatter; + + private final int min; + private final int range; + private final int interval; + + private double thumbPosition; + + public Button(Option option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter) { + super(option, dim); + + this.min = min; + this.range = max - min; + this.interval = interval; + this.thumbPosition = this.getThumbPositionForValue(option.getValue()); + this.formatter = formatter; + + this.sliderBounds = new Rect2i(dim.getLimitX() - 96, dim.getCenterY() - 5, 90, 10); + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + super.render(mouseX, mouseY, delta); + + if (this.option.isAvailable() && this.hovered) { + this.renderSlider(); + } else { + this.renderStandaloneValue(); + } + } + + private void renderStandaloneValue() { + int sliderX = this.sliderBounds.getX(); + int sliderY = this.sliderBounds.getY(); + int sliderWidth = this.sliderBounds.getWidth(); + int sliderHeight = this.sliderBounds.getHeight(); + + String label = this.formatter.format(this.option.getValue()); + int labelWidth = this.font.getStringWidth(label); + + this.drawString(label, sliderX + sliderWidth - labelWidth, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); + } + + private void renderSlider() { + int sliderX = this.sliderBounds.getX(); + int sliderY = this.sliderBounds.getY(); + int sliderWidth = this.sliderBounds.getWidth(); + int sliderHeight = this.sliderBounds.getHeight(); + + this.thumbPosition = this.getThumbPositionForValue(option.getValue()); + + double thumbOffset = MathHelper.clamp_double((double) (this.getIntValue() - this.min) / this.range * sliderWidth, 0, sliderWidth); + + double thumbX = sliderX + thumbOffset - THUMB_WIDTH; + double trackY = sliderY + (sliderHeight / 2) - ((double) TRACK_HEIGHT / 2); + + this.drawRect(thumbX, sliderY, thumbX + (THUMB_WIDTH * 2), sliderY + sliderHeight, 0xFFFFFFFF); + this.drawRect(sliderX, trackY, sliderX + sliderWidth, trackY + TRACK_HEIGHT, 0xFFFFFFFF); + + String label = String.valueOf(this.getIntValue()); + + int labelWidth = this.font.getStringWidth(label); + + this.drawString(label, sliderX - labelWidth - 6, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); + } + + public int getIntValue() { + return this.min + (this.interval * (int) Math.round(this.getSnappedThumbPosition() / this.interval)); + } + + public double getSnappedThumbPosition() { + return this.thumbPosition / (1.0D / this.range); + } + + public double getThumbPositionForValue(int value) { + return (value - this.min) * (1.0D / this.range); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (this.option.isAvailable() && button == 0 && this.sliderBounds.contains((int) mouseX, (int) mouseY)) { + this.setValueFromMouse(mouseX); + + return true; + } + + return false; + } + + private void setValueFromMouse(double d) { + this.setValue((d - (double) this.sliderBounds.getX()) / (double) this.sliderBounds.getWidth()); + } + + private void setValue(double d) { + this.thumbPosition = MathHelper.clamp_double(d, 0.0D, 1.0D); + + int value = this.getIntValue(); + + if (this.option.getValue() != value) { + this.option.setValue(value); + } + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY) { + if (this.option.isAvailable() && this.sliderBounds.contains((int) mouseX, (int) mouseY)) { + this.setValueFromMouse(mouseX); + + return true; + } + + return false; + } + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java new file mode 100644 index 000000000..8b5cd3cab --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java @@ -0,0 +1,93 @@ +package me.jellysquid.mods.sodium.client.gui.options.control; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.utils.Rect2i; +import me.jellysquid.mods.sodium.client.util.Dim2i; + +public class TickBoxControl implements Control { + private final Option option; + + public TickBoxControl(Option option) { + this.option = option; + } + + @Override + public ControlElement createElement(Dim2i dim) { + return new TickBoxControlElement(this.option, dim); + } + + @Override + public int getMaxWidth() { + return 30; + } + + @Override + public Option getOption() { + return this.option; + } + + private static class TickBoxControlElement extends ControlElement { + private final Rect2i button; + + public TickBoxControlElement(Option option, Dim2i dim) { + super(option, dim); + + this.button = new Rect2i(dim.getLimitX() - 16, dim.getCenterY() - 5, 10, 10); + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + super.render(mouseX, mouseY, delta); + + final int x = this.button.getX(); + final int y = this.button.getY(); + final int w = x + this.button.getWidth(); + final int h = y + this.button.getHeight(); + + final boolean enabled = this.option.isAvailable(); + final boolean ticked = enabled && this.option.getValue(); + + final int color; + + if (enabled) { + color = ticked ? 0xFF94E4D3 : 0xFFFFFFFF; + } else { + color = 0xFFAAAAAA; + } + + if (ticked) { + this.drawRect(x + 2, y + 2, w - 2, h - 2, color); + } + + this.drawRectOutline(x, y, w, h, color); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { + this.option.setValue(!this.option.getValue()); + this.playClickSound(); + + return true; + } + + return false; + } + + protected void drawRectOutline(int x, int y, int w, int h, int color) { + final float a = (float) (color >> 24 & 255) / 255.0F; + final float r = (float) (color >> 16 & 255) / 255.0F; + final float g = (float) (color >> 8 & 255) / 255.0F; + final float b = (float) (color & 255) / 255.0F; + + this.drawQuads(vertices -> { + addQuad(vertices, x, y, w, y + 1, a, r, g, b); + addQuad(vertices, x, h - 1, w, h, a, r, g, b); + addQuad(vertices, x, y, x + 1, h, a, r, g, b); + addQuad(vertices, w - 1, y, w, h, a, r, g, b); + }); + } + } + + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java new file mode 100644 index 000000000..1630c57ef --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.sodium.client.gui.options.storage; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.client.Minecraft; +import net.minecraft.client.settings.GameSettings; + +public class MinecraftOptionsStorage implements OptionStorage { + private final Minecraft client; + + public MinecraftOptionsStorage() { + this.client = Minecraft.getMinecraft(); + } + + @Override + public GameSettings getData() { + return this.client.gameSettings; + } + + @Override + public void save() { + this.getData().saveOptions(); + + SodiumClientMod.logger().info("Flushed changes to Minecraft configuration"); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java new file mode 100644 index 000000000..a2e4966da --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java @@ -0,0 +1,7 @@ +package me.jellysquid.mods.sodium.client.gui.options.storage; + +public interface OptionStorage { + T getData(); + + void save(); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java new file mode 100644 index 000000000..c8b3372b5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java @@ -0,0 +1,30 @@ +package me.jellysquid.mods.sodium.client.gui.options.storage; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; + +import java.io.IOException; + +public class SodiumOptionsStorage implements OptionStorage { + private final SodiumGameOptions options; + + public SodiumOptionsStorage() { + this.options = SodiumClientMod.options(); + } + + @Override + public SodiumGameOptions getData() { + return this.options; + } + + @Override + public void save() { + try { + this.options.writeChanges(); + } catch (IOException e) { + throw new RuntimeException("Couldn't save configuration changes", e); + } + + SodiumClientMod.logger().info("Flushed changes to Rubidium configuration"); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Drawable.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Drawable.java new file mode 100644 index 000000000..19cb8a161 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Drawable.java @@ -0,0 +1,5 @@ +package me.jellysquid.mods.sodium.client.gui.utils; + +public interface Drawable { + void render(int mouseX, int mouseY, float delta); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Element.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Element.java new file mode 100644 index 000000000..feec11bb5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Element.java @@ -0,0 +1,11 @@ +package me.jellysquid.mods.sodium.client.gui.utils; + +public interface Element { + default boolean mouseClicked(double mouseX, double mouseY, int button) { + return false; + } + + default boolean mouseDragged(double mouseX, double mouseY) { + return false; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Rect2i.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Rect2i.java new file mode 100644 index 000000000..54491198e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/Rect2i.java @@ -0,0 +1,35 @@ +package me.jellysquid.mods.sodium.client.gui.utils; + +public class Rect2i { + private final int x; + private final int y; + private final int width; + private final int height; + + public Rect2i(int i, int j, int k, int l) { + this.x = i; + this.y = j; + this.width = k; + this.height = l; + } + + public int getX() { + return this.x; + } + + public int getY() { + return this.y; + } + + public int getWidth() { + return this.width; + } + + public int getHeight() { + return this.height; + } + + public boolean contains(int x, int y) { + return x >= this.x && x <= this.x + this.width && y >= this.y && y <= this.y + this.height; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java new file mode 100644 index 000000000..97f9feec4 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java @@ -0,0 +1,64 @@ +package me.jellysquid.mods.sodium.client.gui.widgets; + +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import me.jellysquid.mods.sodium.client.gui.utils.Drawable; +import me.jellysquid.mods.sodium.client.gui.utils.Element; +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +import java.util.function.Consumer; + +public abstract class AbstractWidget implements Drawable, Element { + protected final FontRenderer font; + + protected AbstractWidget() { + this.font = Minecraft.getMinecraft().fontRenderer; + } + + protected void drawString(String str, int x, int y, int color) { + this.font.drawString(str, x, y, color); + } + + protected void drawRect(double x1, double y1, double x2, double y2, int color) { + float a = (float) (color >> 24 & 255) / 255.0F; + float r = (float) (color >> 16 & 255) / 255.0F; + float g = (float) (color >> 8 & 255) / 255.0F; + float b = (float) (color & 255) / 255.0F; + + this.drawQuads(vertices -> addQuad(vertices, x1, y1, x2, y2, a, r, g, b)); + } + + protected void drawQuads(Consumer consumer) { + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GLStateManager.defaultBlendFunc(); + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + consumer.accept(tessellator); + tessellator.draw(); + + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + protected static void addQuad(Tessellator consumer, double x1, double y1, double x2, double y2, float a, float r, float g, float b) { + consumer.setColorRGBA_F(r, g, b, a); + consumer.addVertex(x2, y1, 0.0D); + consumer.addVertex(x1, y1, 0.0D); + consumer.addVertex(x1, y2, 0.0D); + consumer.addVertex(x2, y2, 0.0D); + } + + protected void playClickSound() { + Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F)); + } + + protected int getTextWidth(String text) { + return this.font.getStringWidth(text); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java new file mode 100644 index 000000000..956cb6426 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java @@ -0,0 +1,69 @@ +package me.jellysquid.mods.sodium.client.gui.widgets; + +import me.jellysquid.mods.sodium.client.gui.utils.Drawable; +import me.jellysquid.mods.sodium.client.util.Dim2i; + +public class FlatButtonWidget extends AbstractWidget implements Drawable { + private final Dim2i dim; + private final String label; + private final Runnable action; + + private boolean selected; + private boolean enabled = true; + private boolean visible = true; + + public FlatButtonWidget(Dim2i dim, String label, Runnable action) { + this.dim = dim; + this.label = label; + this.action = action; + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + if (!this.visible) { + return; + } + + boolean hovered = this.dim.containsCursor(mouseX, mouseY); + + int backgroundColor = this.enabled ? (hovered ? 0xE0000000 : 0x90000000) : 0x60000000; + int textColor = this.enabled ? 0xFFFFFFFF : 0x90FFFFFF; + + int strWidth = this.font.getStringWidth(this.label); + + this.drawRect(this.dim.getOriginX(), this.dim.getOriginY(), this.dim.getLimitX(), this.dim.getLimitY(), backgroundColor); + this.drawString(this.label, this.dim.getCenterX() - (strWidth / 2), this.dim.getCenterY() - 4, textColor); + + if (this.enabled && this.selected) { + this.drawRect(this.dim.getOriginX(), this.dim.getLimitY() - 1, this.dim.getLimitX(), this.dim.getLimitY(), 0xFF94E4D3); + } + } + + public void setSelected(boolean selected) { + this.selected = selected; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (!this.enabled || !this.visible) { + return false; + } + + if (button == 0 && this.dim.containsCursor(mouseX, mouseY)) { + this.action.run(); + this.playClickSound(); + + return true; + } + + return false; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public void setVisible(boolean visible) { + this.visible = visible; + } +} diff --git a/src/main/resources/META-INF/angelica_at.cfg b/src/main/resources/META-INF/angelica_at.cfg index 8932017b0..b3a70addc 100644 --- a/src/main/resources/META-INF/angelica_at.cfg +++ b/src/main/resources/META-INF/angelica_at.cfg @@ -33,3 +33,5 @@ public net.minecraft.client.renderer.texture.AbstractTexture field_110553_a # gl public net.minecraft.client.renderer.texture.TextureAtlasSprite field_147966_k # useAnisotropicFiltering public net.minecraft.client.renderer.texture.TextureMap func_147634_a(Lnet/minecraft/util/ResourceLocation;I)Lnet/minecraft/util/ResourceLocation; # ResourceLocation completeResourceLocation(ResourceLocation, int) + +public net.minecraft.client.gui.GuiVideoSettings field_146498_f # parentGuiScreen diff --git a/src/main/resources/assets/angelica/lang/en_US.lang b/src/main/resources/assets/angelica/lang/en_US.lang index 14627599b..1f296995e 100644 --- a/src/main/resources/assets/angelica/lang/en_US.lang +++ b/src/main/resources/assets/angelica/lang/en_US.lang @@ -1 +1,83 @@ options.button.shader=Shaders... + +options.chunks=%s chunks +sodium.option_impact.low=Low +sodium.option_impact.medium=Medium +sodium.option_impact.high=High +sodium.option_impact.extreme=Extreme +sodium.option_impact.varies=Varies +sodium.options.pages.quality=Quality +sodium.options.pages.performance=Performance +sodium.options.pages.advanced=Advanced +sodium.options.view_distance.tooltip=The render distance controls how far away terrain will be rendered. Shorter distances mean that less terrain will be rendered, improving frame rates. +sodium.options.simulation_distance.tooltip=The simulation distance controls how far away terrain and entities will be loaded and ticked. Shorter distances can reduce the internal server's load and may improve frame rates. +sodium.options.brightness.tooltip=Controls the brightness (gamma) of the game. +sodium.options.clouds.name=Clouds +sodium.options.clouds.tooltip=Controls whether or not clouds will be visible. +sodium.options.gui_scale.tooltip=Sets the maximum scale factor to be used for the user interface. If 'auto' is used, then the largest scale factor will always be used. +sodium.options.fullscreen.tooltip=If enabled, the game will display in full-screen (if supported). +sodium.options.v_sync.tooltip=If enabled, the game's frame rate will be synchronized to the monitor's refresh rate, making for a generally smoother experience at the expense of overall input latency. This setting might reduce performance if your system is too slow. +sodium.options.fps_limit.tooltip=Limits the maximum number of frames per second. This can help reduce battery usage and general system load when multi-tasking. If V-Sync is enabled, this option will be ignored unless it is lower than your display's refresh rate. +sodium.options.view_bobbing.tooltip=If enabled, the player's view will sway and bob when moving around. Players who experience motion sickness while playing can benefit from disabling this. +sodium.options.attack_indicator.tooltip=Controls where the Attack Indicator is displayed on screen. +sodium.options.autosave_indicator.tooltip=If enabled, an indicator will be shown when the game is saving the world to disk. +sodium.options.graphics_quality.tooltip=The default graphics quality controls some legacy options and is necessary for mod compatibility. If the options below are left to \"Default\ they will use this setting. +sodium.options.clouds_quality.tooltip=Controls the quality of rendered clouds in the sky. +sodium.options.weather_quality.tooltip=Controls the quality of rain and snow effects. +sodium.options.leaves_quality.name=Leaves Quality +sodium.options.leaves_quality.tooltip=Controls the quality of leaves. +sodium.options.particle_quality.name=Particle Quality +sodium.options.particle_quality.tooltip=Controls the maximum number of particles which can be present on screen at any one time. +sodium.options.smooth_lighting.tooltip=Controls whether blocks will be smoothly lit and shaded. This slightly increases the amount of time needed to re-build a chunk, but doesn't affect frame rates. +sodium.options.biome_blend.value=%s block(s) +sodium.options.biome_blend.tooltip=Controls the range which biomes will be sampled for block colorization. Higher values greatly increase the amount of time it takes to build chunks for diminishing improvements in quality. +sodium.options.entity_distance.tooltip=Controls how far away entities can render from the player. Higher values increase the render distance at the expense of frame rates. +sodium.options.entity_shadows.tooltip=If enabled, basic shadows will be rendered beneath mobs and other entities. +sodium.options.vignette.name=Vignette +sodium.options.vignette.tooltip=If enabled, a vignette effect will be rendered on the player's view. This is very unlikely to make a difference to frame rates unless you are fill-rate limited. +sodium.options.mipmap_levels.tooltip=Controls the number of mipmaps which will be used for block model textures. Higher values provide better rendering of blocks in the distance, but may adversely affect performance with many animated textures. +sodium.options.use_chunk_multidraw.name=Use Chunk Multi-Draw +sodium.options.use_chunk_multidraw.tooltip=Multi-draw allows multiple chunks to be rendered with fewer draw calls, greatly reducing CPU overhead when rendering the world while also potentially allowing for more efficient GPU utilization. This optimization may cause issues with some graphics drivers, so you should try disabling it if you are experiencing glitches. +sodium.options.use_vertex_objects.name=Use Vertex Array Objects +sodium.options.use_vertex_objects.tooltip=Helps to improve performance by moving information about how vertex data should be rendered into the driver, allowing it to better optimize for repeated rendering of the same objects. There is generally no reason to disable this unless you're using incompatible mods. +sodium.options.use_block_face_culling.name=Use Block Face Culling +sodium.options.use_block_face_culling.tooltip=If enabled, only the sides of blocks which are facing the camera will be submitted for rendering. This can eliminate a large number of block faces very early in the rendering process, saving memory bandwidth and time on the GPU. Some resource packs may have issues with this option, so try disabling it if you're seeing holes in blocks. +sodium.options.use_compact_vertex_format.name=Use Compact Vertex Format +sodium.options.use_compact_vertex_format.tooltip=If enabled, a more compact vertex format will be used for rendering chunks. This can reduce graphics memory usage and bandwidth requirements significantly, especially for integrated graphics cards, but can cause z-fighting with some resource packs due to how it reduces the precision of position and texture coordinate attributes. +sodium.options.use_fog_occlusion.name=Use Fog Occlusion +sodium.options.use_fog_occlusion.tooltip=If enabled, chunks which are determined to be fully hidden by fog effects will not be rendered, helping to improve performance. The improvement can be more dramatic when fog effects are heavier (such as while underwater), but it may cause undesirable visual artifacts between the sky and fog in some scenarios. +sodium.options.use_entity_culling.name=Use Entity Culling +sodium.options.use_entity_culling.tooltip=If enabled, entities determined not to be in any visible chunks will be skipped during rendering. This can help improve performance by avoiding the rendering of entities located underground or behind walls. +sodium.options.use_particle_culling.name=Use Particle Culling +sodium.options.use_particle_culling.tooltip=If enabled, only particles which are determined to be visible will be rendered. This can provide a significant improvement to frame rates when many particles are nearby. +sodium.options.animate_only_visible_textures.name=Animate Only Visible Textures +sodium.options.animate_only_visible_textures.tooltip=If enabled, only animated textures determined to be visible will be updated. This can provide a significant boost to frame rates on some hardware, especially with heavier resource packs. If you experience issues with some textures not being animated, try disabling this option. +sodium.options.translucency_sorting.name=Translucency Sorting +sodium.options.translucency_sorting.tooltip=If enabled, translucent blocks will be sorted correctly from back to front to provide better rendering, especially when multiple translucent blocks are in view and layered. This is a bit of an expensive operation. +sodium.options.cpu_render_ahead_limit.name=CPU Render-Ahead Limit +sodium.options.cpu_render_ahead_limit.tooltip=Specifies the maximum number of frames the CPU can be waiting on the GPU to finish rendering. Very low or high values may create frame rate instability. +sodium.options.cpu_render_ahead_limit.value=%s frame(s) +sodium.options.allow_direct_memory_access.name=Allow Direct Memory Access +sodium.options.allow_direct_memory_access.tooltip=If enabled, some critical code paths will be allowed to use direct memory access for performance. This often greatly reduces CPU overhead for chunk and entity rendering, but can make it harder to diagnose some bugs and crashes. You should only disable this if you've been asked to or otherwise know what you're doing. +sodium.options.ignore_driver_blacklist.name=Ignore Driver Blacklist +sodium.options.ignore_driver_blacklist.tooltip=If enabled, known incompatibilities with your hardware/driver configuration will be ignored, allowing you to enable options that may cause issues with your game. You should generally not touch this option unless you know exactly what you are doing. After changing this option, you must save, close, and then re-open the settings screen. +sodium.options.enable_memory_tracing.name=Enable Memory Tracing +sodium.options.enable_memory_tracing.tooltip=Debugging feature. If enabled, stack traces will be collected alongside memory allocations to help improve diagnostic information when memory leaks are detected. +sodium.options.performance_impact_string=Performance Impact: %s +sodium.options.use_persistent_mapping.name=Use Persistent Mapping +sodium.options.use_persistent_mapping.tooltip=If enabled, a small amount of memory will be persistently mapped for speeding up chunk updates and entity rendering.\n\nRequires OpenGL 4.4 or ARB_buffer_storage. +sodium.options.chunk_memory_allocator.name=Chunk Memory Allocator +sodium.options.chunk_memory_allocator.tooltip=Selects the memory allocator that will be used for chunk rendering.\n- ASYNC: Fastest option, works well with most modern graphics drivers.\n- SWAP: Fallback option for older graphics drivers. May increase memory usage significantly. +sodium.options.chunk_memory_allocator.async=Async +sodium.options.chunk_memory_allocator.swap=Swap +sodium.options.chunk_update_threads.name=Chunk Update Threads +sodium.options.chunk_update_threads.tooltip=Specifies the number of threads to use for chunk building. Using more threads can speed up chunk loading and update speed, but may negatively impact frame times. +sodium.options.always_defer_chunk_updates.name=Always Defer Chunk Updates +sodium.options.always_defer_chunk_updates.tooltip=If enabled, rendering will never wait for chunk updates to finish, even if they are important. This can greatly improve frame rates in some scenarios, but it may create significant visual lag in the world. +sodium.options.use_no_error_context.name=Use No Error Context +sodium.options.use_no_error_context.tooltip=If enabled, the OpenGL context will be created with error checking disabled. This may slightly improve performance, but it also increases the risk that the game will crash instead of gracefully handling OpenGL errors. You should disable this option if you are experiencing sudden unexplained crashes. +sodium.options.threads.value=%s thread(s) +sodium.options.default=Default +sodium.options.buttons.undo=Undo +sodium.options.buttons.apply=Apply +sodium.options.buttons.donate=Buy coffee for JellySquid! diff --git a/src/main/resources/assets/sodium/lang/en_us.json b/src/main/resources/assets/sodium/lang/en_us.json deleted file mode 100644 index 7b89303f8..000000000 --- a/src/main/resources/assets/sodium/lang/en_us.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "sodium.option_impact.low": "Low", - "sodium.option_impact.medium": "Medium", - "sodium.option_impact.high": "High", - "sodium.option_impact.extreme": "Extreme", - "sodium.option_impact.varies": "Varies", - "sodium.options.pages.quality": "Quality", - "sodium.options.pages.performance": "Performance", - "sodium.options.pages.advanced": "Advanced", - "sodium.options.view_distance.tooltip": "The render distance controls how far away terrain will be rendered. Shorter distances mean that less terrain will be rendered, improving frame rates.", - "sodium.options.simulation_distance.tooltip": "The simulation distance controls how far away terrain and entities will be loaded and ticked. Shorter distances can reduce the internal server's load and may improve frame rates.", - "sodium.options.brightness.tooltip": "Controls the brightness (gamma) of the game.", - "sodium.options.clouds.name": "Clouds", - "sodium.options.clouds.tooltip": "Controls whether or not clouds will be visible.", - "sodium.options.gui_scale.tooltip": "Sets the maximum scale factor to be used for the user interface. If 'auto' is used, then the largest scale factor will always be used.", - "sodium.options.fullscreen.tooltip": "If enabled, the game will display in full-screen (if supported).", - "sodium.options.v_sync.tooltip": "If enabled, the game's frame rate will be synchronized to the monitor's refresh rate, making for a generally smoother experience at the expense of overall input latency. This setting might reduce performance if your system is too slow.", - "sodium.options.fps_limit.tooltip": "Limits the maximum number of frames per second. This can help reduce battery usage and general system load when multi-tasking. If V-Sync is enabled, this option will be ignored unless it is lower than your display's refresh rate.", - "sodium.options.view_bobbing.tooltip": "If enabled, the player's view will sway and bob when moving around. Players who experience motion sickness while playing can benefit from disabling this.", - "sodium.options.attack_indicator.tooltip": "Controls where the Attack Indicator is displayed on screen.", - "sodium.options.autosave_indicator.tooltip": "If enabled, an indicator will be shown when the game is saving the world to disk.", - "sodium.options.graphics_quality.tooltip": "The default graphics quality controls some legacy options and is necessary for mod compatibility. If the options below are left to \"Default\", they will use this setting.", - "sodium.options.clouds_quality.tooltip": "Controls the quality of rendered clouds in the sky.", - "sodium.options.weather_quality.tooltip": "Controls the quality of rain and snow effects.", - "sodium.options.leaves_quality.name": "Leaves Quality", - "sodium.options.leaves_quality.tooltip": "Controls the quality of leaves.", - "sodium.options.particle_quality.name": "Particle Quality", - "sodium.options.particle_quality.tooltip": "Controls the maximum number of particles which can be present on screen at any one time.", - "sodium.options.smooth_lighting.tooltip": "Controls whether blocks will be smoothly lit and shaded. This slightly increases the amount of time needed to re-build a chunk, but doesn't affect frame rates.", - "sodium.options.biome_blend.value": "%s block(s)", - "sodium.options.biome_blend.tooltip": "Controls the range which biomes will be sampled for block colorization. Higher values greatly increase the amount of time it takes to build chunks for diminishing improvements in quality.", - "sodium.options.entity_distance.tooltip": "Controls how far away entities can render from the player. Higher values increase the render distance at the expense of frame rates.", - "sodium.options.entity_shadows.tooltip": "If enabled, basic shadows will be rendered beneath mobs and other entities.", - "sodium.options.vignette.name": "Vignette", - "sodium.options.vignette.tooltip": "If enabled, a vignette effect will be rendered on the player's view. This is very unlikely to make a difference to frame rates unless you are fill-rate limited.", - "sodium.options.mipmap_levels.tooltip": "Controls the number of mipmaps which will be used for block model textures. Higher values provide better rendering of blocks in the distance, but may adversely affect performance with many animated textures.", - "sodium.options.use_chunk_multidraw.name": "Use Chunk Multi-Draw", - "sodium.options.use_chunk_multidraw.tooltip": "Multi-draw allows multiple chunks to be rendered with fewer draw calls, greatly reducing CPU overhead when rendering the world while also potentially allowing for more efficient GPU utilization. This optimization may cause issues with some graphics drivers, so you should try disabling it if you are experiencing glitches.", - "sodium.options.use_vertex_objects.name": "Use Vertex Array Objects", - "sodium.options.use_vertex_objects.tooltip": "Helps to improve performance by moving information about how vertex data should be rendered into the driver, allowing it to better optimize for repeated rendering of the same objects. There is generally no reason to disable this unless you're using incompatible mods.", - "sodium.options.use_block_face_culling.name": "Use Block Face Culling", - "sodium.options.use_block_face_culling.tooltip": "If enabled, only the sides of blocks which are facing the camera will be submitted for rendering. This can eliminate a large number of block faces very early in the rendering process, saving memory bandwidth and time on the GPU. Some resource packs may have issues with this option, so try disabling it if you're seeing holes in blocks.", - "sodium.options.use_compact_vertex_format.name": "Use Compact Vertex Format", - "sodium.options.use_compact_vertex_format.tooltip": "If enabled, a more compact vertex format will be used for rendering chunks. This can reduce graphics memory usage and bandwidth requirements significantly, especially for integrated graphics cards, but can cause z-fighting with some resource packs due to how it reduces the precision of position and texture coordinate attributes.", - "sodium.options.use_fog_occlusion.name": "Use Fog Occlusion", - "sodium.options.use_fog_occlusion.tooltip": "If enabled, chunks which are determined to be fully hidden by fog effects will not be rendered, helping to improve performance. The improvement can be more dramatic when fog effects are heavier (such as while underwater), but it may cause undesirable visual artifacts between the sky and fog in some scenarios.", - "sodium.options.use_entity_culling.name": "Use Entity Culling", - "sodium.options.use_entity_culling.tooltip": "If enabled, entities determined not to be in any visible chunks will be skipped during rendering. This can help improve performance by avoiding the rendering of entities located underground or behind walls.", - "sodium.options.use_particle_culling.name": "Use Particle Culling", - "sodium.options.use_particle_culling.tooltip": "If enabled, only particles which are determined to be visible will be rendered. This can provide a significant improvement to frame rates when many particles are nearby.", - "sodium.options.animate_only_visible_textures.name": "Animate Only Visible Textures", - "sodium.options.animate_only_visible_textures.tooltip": "If enabled, only animated textures determined to be visible will be updated. This can provide a significant boost to frame rates on some hardware, especially with heavier resource packs. If you experience issues with some textures not being animated, try disabling this option.", - "sodium.options.translucency_sorting.name": "Translucency Sorting", - "sodium.options.translucency_sorting.tooltip": "If enabled, translucent blocks will be sorted correctly from back to front to provide better rendering, especially when multiple translucent blocks are in view and layered. This is a bit of an expensive operation.", - "sodium.options.cpu_render_ahead_limit.name": "CPU Render-Ahead Limit", - "sodium.options.cpu_render_ahead_limit.tooltip": "Specifies the maximum number of frames the CPU can be waiting on the GPU to finish rendering. Very low or high values may create frame rate instability.", - "sodium.options.cpu_render_ahead_limit.value": "%s frame(s)", - "sodium.options.allow_direct_memory_access.name": "Allow Direct Memory Access", - "sodium.options.allow_direct_memory_access.tooltip": "If enabled, some critical code paths will be allowed to use direct memory access for performance. This often greatly reduces CPU overhead for chunk and entity rendering, but can make it harder to diagnose some bugs and crashes. You should only disable this if you've been asked to or otherwise know what you're doing.", - "sodium.options.ignore_driver_blacklist.name": "Ignore Driver Blacklist", - "sodium.options.ignore_driver_blacklist.tooltip": "If enabled, known incompatibilities with your hardware/driver configuration will be ignored, allowing you to enable options that may cause issues with your game. You should generally not touch this option unless you know exactly what you are doing. After changing this option, you must save, close, and then re-open the settings screen.", - "sodium.options.enable_memory_tracing.name": "Enable Memory Tracing", - "sodium.options.enable_memory_tracing.tooltip": "Debugging feature. If enabled, stack traces will be collected alongside memory allocations to help improve diagnostic information when memory leaks are detected.", - "sodium.options.performance_impact_string": "Performance Impact: %s", - "sodium.options.use_persistent_mapping.name": "Use Persistent Mapping", - "sodium.options.use_persistent_mapping.tooltip": "If enabled, a small amount of memory will be persistently mapped for speeding up chunk updates and entity rendering.\n\nRequires OpenGL 4.4 or ARB_buffer_storage.", - "sodium.options.chunk_memory_allocator.name": "Chunk Memory Allocator", - "sodium.options.chunk_memory_allocator.tooltip": "Selects the memory allocator that will be used for chunk rendering.\n- ASYNC: Fastest option, works well with most modern graphics drivers.\n- SWAP: Fallback option for older graphics drivers. May increase memory usage significantly.", - "sodium.options.chunk_memory_allocator.async": "Async", - "sodium.options.chunk_memory_allocator.swap": "Swap", - "sodium.options.chunk_update_threads.name": "Chunk Update Threads", - "sodium.options.chunk_update_threads.tooltip": "Specifies the number of threads to use for chunk building. Using more threads can speed up chunk loading and update speed, but may negatively impact frame times.", - "sodium.options.always_defer_chunk_updates.name": "Always Defer Chunk Updates", - "sodium.options.always_defer_chunk_updates.tooltip": "If enabled, rendering will never wait for chunk updates to finish, even if they are important. This can greatly improve frame rates in some scenarios, but it may create significant visual lag in the world.", - "sodium.options.use_no_error_context.name": "Use No Error Context", - "sodium.options.use_no_error_context.tooltip": "If enabled, the OpenGL context will be created with error checking disabled. This may slightly improve performance, but it also increases the risk that the game will crash instead of gracefully handling OpenGL errors. You should disable this option if you are experiencing sudden unexplained crashes.", - "sodium.options.threads.value": "%s thread(s)", - "sodium.options.default": "Default", - "sodium.options.buttons.undo": "Undo", - "sodium.options.buttons.apply": "Apply", - "sodium.options.buttons.donate": "Buy coffee for JellySquid!" -} \ No newline at end of file From c3ead30acd9b270d34f80be3701e2f7dee8bff06 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 24 Nov 2023 17:04:32 -0800 Subject: [PATCH 119/301] Re-enable DirectMemoryAccess * Adds some code from lwjgl3 in CompatMemoryUtil.java * Re-add *Unsafe classes --- .../compat/lwjgl/CompatMemoryUtil.java | 58 +++++++++++++++++++ .../sodium/client/gui/SodiumGameOptions.java | 2 +- .../buffer/VertexBufferWriterUnsafe.java | 34 +++++++++++ .../vertex/formats/glyph/GlyphVertexType.java | 3 +- .../writer/GlyphVertexBufferWriterUnsafe.java | 29 ++++++++++ .../vertex/formats/line/LineVertexType.java | 3 +- .../writer/LineVertexBufferWriterUnsafe.java | 25 ++++++++ .../formats/particle/ParticleVertexType.java | 3 +- .../ParticleVertexBufferWriterUnsafe.java | 28 +++++++++ .../vertex/formats/quad/QuadVertexType.java | 3 +- .../writer/QuadVertexBufferWriterUnsafe.java | 30 ++++++++++ .../BasicScreenQuadVertexType.java | 3 +- ...sicScreenQuadVertexBufferWriterUnsafe.java | 25 ++++++++ .../multidraw/ChunkDrawCallBatcher.java | 39 ++++++++++++- .../multidraw/ChunkDrawParamsVector.java | 46 ++++++++++++++- .../hfp/HFPModelVertexBufferWriterUnsafe.java | 42 ++++++++++++++ .../chunk/format/hfp/HFPModelVertexType.java | 2 +- .../sfp/SFPModelVertexBufferWriterUnsafe.java | 50 ++++++++++++++++ .../chunk/format/sfp/SFPModelVertexType.java | 2 +- .../resources/assets/angelica/lang/en_US.lang | 2 +- 20 files changed, 417 insertions(+), 12 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java index e4b93a441..fc50b9bcc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java @@ -13,4 +13,62 @@ public static ByteBuffer memReallocDirect(ByteBuffer old, int capacity) { newBuf.position(Math.min(capacity, oldPos)); return newBuf; } + + /** + * Backported from LWJGL3 under the BSD 3-Clause "New" or "Revised" License license + * + *

This class provides functionality for managing native memory. + * + *

All methods in this class will make use of {@link sun.misc.Unsafe} if it's available, for performance. If Unsafe is not available, the fallback + * implementations make use of reflection and, in the worst-case, JNI.

+ * + *

Method names in this class are prefixed with {@code mem} to avoid ambiguities when used with static imports.

+ */ + + static final sun.misc.Unsafe UNSAFE; + + static { + UNSAFE = getUnsafeInstance(); + } + + private static sun.misc.Unsafe getUnsafeInstance() { + java.lang.reflect.Field[] fields = sun.misc.Unsafe.class.getDeclaredFields(); + + /* + Different runtimes use different names for the Unsafe singleton, + so we cannot use .getDeclaredField and we scan instead. For example: + + Oracle: theUnsafe + PERC : m_unsafe_instance + Android: THE_ONE + */ + for (java.lang.reflect.Field field : fields) { + if (!field.getType().equals(sun.misc.Unsafe.class)) { + continue; + } + + int modifiers = field.getModifiers(); + if (!(java.lang.reflect.Modifier.isStatic(modifiers) && java.lang.reflect.Modifier.isFinal(modifiers))) { + continue; + } + + try { + field.setAccessible(true); + return (sun.misc.Unsafe)field.get(null); + } catch (Exception ignored) { + } + break; + } + + throw new UnsupportedOperationException("LWJGL requires sun.misc.Unsafe to be available."); + } + + + public static void memPutByte(long ptr, byte value) { UNSAFE.putByte(null, ptr, value); } + public static void memPutShort(long ptr, short value) { UNSAFE.putShort(null, ptr, value); } + public static void memPutInt(long ptr, int value) { UNSAFE.putInt(null, ptr, value); } + public static void memPutLong(long ptr, long value) { UNSAFE.putLong(null, ptr, value); } + public static void memPutFloat(long ptr, float value) { UNSAFE.putFloat(null, ptr, value); } + public static void memPutDouble(long ptr, double value) { UNSAFE.putDouble(null, ptr, value); } + } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 986900d85..35667ad1d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -32,7 +32,7 @@ public static class AdvancedSettings { public boolean useFogOcclusion = true; public boolean useCompactVertexFormat = true; public boolean useBlockFaceCulling = true; - public boolean allowDirectMemoryAccess = false; + public boolean allowDirectMemoryAccess = true; public boolean ignoreDriverBlacklist = false; public boolean translucencySorting = false; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java new file mode 100644 index 000000000..90994d7b2 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/buffer/VertexBufferWriterUnsafe.java @@ -0,0 +1,34 @@ +package me.jellysquid.mods.sodium.client.model.vertex.buffer; + +import me.jellysquid.mods.sodium.client.model.vertex.type.BufferVertexType; +import org.lwjgl.MemoryUtil; + +/** + * An unsafe {@link VertexBufferWriter} implementation which uses direct memory operations to enable fast blitting of + * data into memory buffers. Only available on JVMs which support {@link sun.misc.Unsafe}, but generally produces much + * better optimized code than other implementations. The implementation does not check for invalid memory accesses, + * meaning that errors can corrupt process memory. + */ +public abstract class VertexBufferWriterUnsafe extends VertexBufferWriter { + /** + * The write pointer into the buffer storage. This is advanced by the vertex stride every time + * {@link VertexBufferWriterUnsafe#advance()} is called. + */ + protected long writePointer; + + protected VertexBufferWriterUnsafe(VertexBufferView backingBuffer, BufferVertexType vertexType) { + super(backingBuffer, vertexType); + } + + @Override + protected void onBufferStorageChanged() { + this.writePointer = MemoryUtil.getAddress(this.backingBuffer.getDirectBuffer(), this.backingBuffer.getWriterPosition()); + } + + @Override + protected void advance() { + this.writePointer += this.vertexStride; + + super.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java index b7291da9d..2be896c8a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer.GlyphVertexBufferWriterNio; +import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer.GlyphVertexBufferWriterUnsafe; 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; @@ -12,7 +13,7 @@ public class GlyphVertexType implements VanillaVertexType, BlittableVertexType { @Override public GlyphVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return new GlyphVertexBufferWriterNio(buffer); + return direct ? new GlyphVertexBufferWriterUnsafe(buffer) : new GlyphVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..697a6a95e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexBufferWriterUnsafe.java @@ -0,0 +1,29 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer; + +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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; + +public class GlyphVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements GlyphVertexSink { + public GlyphVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.GLYPHS); + } + + @Override + public void writeGlyph(float x, float y, float z, int color, float u, float v, int light) { + long i = this.writePointer; + + CompatMemoryUtil.memPutFloat(i, x); + CompatMemoryUtil.memPutFloat(i + 4, y); + CompatMemoryUtil.memPutFloat(i + 8, z); + CompatMemoryUtil.memPutInt(i + 12, color); + CompatMemoryUtil.memPutFloat(i + 16, u); + CompatMemoryUtil.memPutFloat(i + 20, v); + CompatMemoryUtil.memPutInt(i + 24, light); + + this.advance(); + + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java index 6170f686c..5e2ca5f05 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexBufferWriterNio; +import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; @@ -12,7 +13,7 @@ public class LineVertexType implements VanillaVertexType, BlittableVertexType { @Override public LineVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return new LineVertexBufferWriterNio(buffer); + return direct ? new LineVertexBufferWriterUnsafe(buffer) : new LineVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..2744be84a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexBufferWriterUnsafe.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer; + +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.line.LineVertexSink; + +public class LineVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements LineVertexSink { + public LineVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.LINES); + } + + @Override + public void vertexLine(float x, float y, float z, int color) { + long i = this.writePointer; + + CompatMemoryUtil.memPutFloat(i, x); + CompatMemoryUtil.memPutFloat(i + 4, y); + CompatMemoryUtil.memPutFloat(i + 8, z); + CompatMemoryUtil.memPutInt(i + 12, color); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java index c0a7ec15c..cdaff0e62 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexBufferWriterNio; +import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; @@ -11,7 +12,7 @@ public class ParticleVertexType implements VanillaVertexType, BlittableVertexType { @Override public ParticleVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return new ParticleVertexBufferWriterNio(buffer); + return direct ? new ParticleVertexBufferWriterUnsafe(buffer) : new ParticleVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..564f18bc2 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexBufferWriterUnsafe.java @@ -0,0 +1,28 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer; + +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.particle.ParticleVertexSink; + +public class ParticleVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ParticleVertexSink { + public ParticleVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.PARTICLES); + } + + @Override + public void writeParticle(float x, float y, float z, float u, float v, int color, int light) { + long i = this.writePointer; + + CompatMemoryUtil.memPutFloat(i, x); + CompatMemoryUtil.memPutFloat(i + 4, y); + CompatMemoryUtil.memPutFloat(i + 8, z); + CompatMemoryUtil.memPutFloat(i + 12, u); + CompatMemoryUtil.memPutFloat(i + 16, v); + CompatMemoryUtil.memPutInt(i + 20, color); + CompatMemoryUtil.memPutInt(i + 24, light); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java index 9e16c989a..094c9e9fe 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer.QuadVertexBufferWriterNio; +import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer.QuadVertexBufferWriterUnsafe; 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; @@ -17,7 +18,7 @@ public QuadVertexSink createFallbackWriter(VertexConsumer consumer) { @Override public QuadVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return new QuadVertexBufferWriterNio(buffer); + return direct ? new QuadVertexBufferWriterUnsafe(buffer) : new QuadVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..641b9bb71 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexBufferWriterUnsafe.java @@ -0,0 +1,30 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer; + +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.quad.QuadVertexSink; + +public class QuadVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements QuadVertexSink { + public QuadVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.QUADS); + } + + @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; + + CompatMemoryUtil.memPutFloat(i, x); + CompatMemoryUtil.memPutFloat(i + 4, y); + CompatMemoryUtil.memPutFloat(i + 8, z); + CompatMemoryUtil.memPutInt(i + 12, color); + CompatMemoryUtil.memPutFloat(i + 16, u); + CompatMemoryUtil.memPutFloat(i + 20, v); + CompatMemoryUtil.memPutInt(i + 24, overlay); + CompatMemoryUtil.memPutInt(i + 28, light); + CompatMemoryUtil.memPutInt(i + 32, normal); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java index 0d0070506..796dd3e70 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexBufferWriterNio; +import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexBufferWriterUnsafe; import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; import me.jellysquid.mods.sodium.client.model.vertex.type.VanillaVertexType; @@ -17,7 +18,7 @@ public BasicScreenQuadVertexSink createFallbackWriter(VertexConsumer consumer) { @Override public BasicScreenQuadVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return new BasicScreenQuadVertexBufferWriterNio(buffer); + return direct ? new BasicScreenQuadVertexBufferWriterUnsafe(buffer) : new BasicScreenQuadVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..502dbb226 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexBufferWriterUnsafe.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer; + +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; +import me.jellysquid.mods.sodium.client.model.vertex.VanillaVertexTypes; +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.screen_quad.BasicScreenQuadVertexSink; + +public class BasicScreenQuadVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements BasicScreenQuadVertexSink { + public BasicScreenQuadVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, VanillaVertexTypes.BASIC_SCREEN_QUADS); + } + + @Override + public void writeQuad(float x, float y, float z, int color) { + long i = this.writePointer; + + CompatMemoryUtil.memPutFloat(i, x); + CompatMemoryUtil.memPutFloat(i + 4, y); + CompatMemoryUtil.memPutFloat(i + 8, z); + CompatMemoryUtil.memPutInt(i + 12, color); + + this.advance(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java index a4e2351d7..aeb88fbcf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java @@ -1,7 +1,11 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; import com.gtnewhorizons.angelica.compat.mojang.CompatMathHelper; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import org.lwjgl.MemoryUtil; +import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; /** @@ -22,7 +26,7 @@ protected ChunkDrawCallBatcher(int capacity) { } public static ChunkDrawCallBatcher create(int capacity) { - return new NioChunkDrawCallBatcher(capacity); + return SodiumClientMod.isDirectMemoryAccessEnabled() ? new UnsafeChunkDrawCallBatcher(capacity) : new NioChunkDrawCallBatcher(capacity); } public void begin() { @@ -55,6 +59,39 @@ public boolean isEmpty() { return this.count <= 0; } + public static class UnsafeChunkDrawCallBatcher extends ChunkDrawCallBatcher { + + private final long basePointer; + private long writePointer; + + public UnsafeChunkDrawCallBatcher(int capacity) { + super(capacity); + + this.basePointer = MemoryUtil.getAddress(this.buffer); + } + + @Override + public void begin() { + super.begin(); + + this.writePointer = this.basePointer; + } + + @Override + public void addIndirectDrawCall(int first, int count, int baseInstance, int instanceCount) { + if (this.count++ >= this.capacity) { + throw new BufferUnderflowException(); + } + + CompatMemoryUtil.memPutInt(this.writePointer , count); // Vertex Count + CompatMemoryUtil.memPutInt(this.writePointer + 4, instanceCount); // Instance Count + CompatMemoryUtil.memPutInt(this.writePointer + 8, first); // Vertex Start + CompatMemoryUtil.memPutInt(this.writePointer + 12, baseInstance); // Base Instance + + this.writePointer += this.stride; + } + } + public static class NioChunkDrawCallBatcher extends ChunkDrawCallBatcher { private int writeOffset; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java index f6bc96e36..05b71837e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawParamsVector.java @@ -1,7 +1,8 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; -import org.lwjgl.BufferUtils; +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import org.lwjgl.MemoryUtil; import java.nio.ByteBuffer; @@ -20,7 +21,7 @@ protected ChunkDrawParamsVector(int capacity) { } public static ChunkDrawParamsVector create(int capacity) { - return new NioChunkDrawCallVector(capacity); + return SodiumClientMod.isDirectMemoryAccessEnabled() ? new UnsafeChunkDrawCallVector(capacity) : new NioChunkDrawCallVector(capacity); } public abstract void pushChunkDrawParams(float x, float y, float z); @@ -34,6 +35,47 @@ protected void growBuffer() { this.buffer = CompatMemoryUtil.memReallocDirect(this.buffer, this.capacity * this.stride); } + public static class UnsafeChunkDrawCallVector extends ChunkDrawParamsVector { + private long basePointer; + private long writePointer; + + public UnsafeChunkDrawCallVector(int capacity) { + super(capacity); + + this.basePointer = MemoryUtil.getAddress(this.buffer); + } + + @Override + public void pushChunkDrawParams(float x, float y, float z) { + if (this.count++ >= this.capacity) { + this.growBuffer(); + } + + CompatMemoryUtil.memPutFloat(this.writePointer , x); + CompatMemoryUtil.memPutFloat(this.writePointer + 4, y); + CompatMemoryUtil.memPutFloat(this.writePointer + 8, z); + + this.writePointer += this.stride; + } + + @Override + protected void growBuffer() { + super.growBuffer(); + + long offset = this.writePointer - this.basePointer; + + this.basePointer = MemoryUtil.getAddress(this.buffer); + this.writePointer = this.basePointer + offset; + } + + @Override + public void reset() { + super.reset(); + + this.writePointer = this.basePointer; + } + } + public static class NioChunkDrawCallVector extends ChunkDrawParamsVector { private int writeOffset; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..e53fbbe2c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexBufferWriterUnsafe.java @@ -0,0 +1,42 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format.hfp; + +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; +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.render.chunk.format.DefaultModelVertexFormats; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexUtil; + +public class HFPModelVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ModelVertexSink { + public HFPModelVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, DefaultModelVertexFormats.MODEL_VERTEX_HFP); + } + + @Override + public void writeQuad(float x, float y, float z, int color, float u, float v, int light) { + this.writeQuadInternal( + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(x), + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(y), + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(z), + color, + ModelVertexUtil.denormalizeVertexTextureFloatAsShort(u), + ModelVertexUtil.denormalizeVertexTextureFloatAsShort(v), + ModelVertexUtil.encodeLightMapTexCoord(light) + ); + } + + private void writeQuadInternal(short x, short y, short z, int color, short u, short v, int light) { + long i = this.writePointer; + + CompatMemoryUtil.memPutShort(i, x); + CompatMemoryUtil.memPutShort(i + 2, y); + CompatMemoryUtil.memPutShort(i + 4, z); + CompatMemoryUtil.memPutInt(i + 8, color); + CompatMemoryUtil.memPutShort(i + 12, u); + CompatMemoryUtil.memPutShort(i + 14, v); + CompatMemoryUtil.memPutInt(i + 16, light); + + this.advance(); + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java index fbf5c01b9..22355e26f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java @@ -35,7 +35,7 @@ public ModelVertexSink createFallbackWriter(VertexConsumer consumer) { @Override public ModelVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return new HFPModelVertexBufferWriterNio(buffer); + return direct ? new HFPModelVertexBufferWriterUnsafe(buffer) : new HFPModelVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..d4ca903cb --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexBufferWriterUnsafe.java @@ -0,0 +1,50 @@ +package me.jellysquid.mods.sodium.client.render.chunk.format.sfp; + +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; +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.render.chunk.format.DefaultModelVertexFormats; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; + +public class SFPModelVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ModelVertexSink { + public SFPModelVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, DefaultModelVertexFormats.MODEL_VERTEX_SFP); + } + + @Override + public void writeQuad(float x, float y, float z, int color, float u, float v, int light) { + long i = this.writePointer; + + CompatMemoryUtil.memPutFloat(i, x); + CompatMemoryUtil.memPutFloat(i + 4, y); + CompatMemoryUtil.memPutFloat(i + 8, z); + CompatMemoryUtil.memPutInt(i + 12, color); + CompatMemoryUtil.memPutFloat(i + 16, u); + CompatMemoryUtil.memPutFloat(i + 20, v); + CompatMemoryUtil.memPutInt(i + 24, encodeLightMapTexCoord(light)); + + this.advance(); + } + + /** + * This moves some work out the shader code and simplifies things a bit. In vanilla, the game encodes light map + * texture coordinates as two un-normalized unsigned shorts in the range 0..255. Using the fixed-function pipeline, + * it then applies a matrix transformation which normalizes these coordinates and applies a centering offset. This + * operation has non-zero overhead and complicates shader code a bit. + * + * To work around the problem, this function instead normalizes these light map texture coordinates and applies the + * centering offset, allowing it to be baked into the vertex data itself. + * + * @param light The light map value + * @return The light map texture coordinates as two unsigned shorts with a center offset applied + */ + private static int encodeLightMapTexCoord(int light) { + int sl = (light >> 16) & 255; + sl = (sl << 8) + 2048; + + int bl = light & 255; + bl = (bl << 8) + 2048; + + return (sl << 16) | bl; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java index 3692e9e72..984f1640d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java @@ -33,7 +33,7 @@ public ModelVertexSink createFallbackWriter(VertexConsumer consumer) { @Override public ModelVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { - return new SFPModelVertexBufferWriterNio(buffer); + return direct ? new SFPModelVertexBufferWriterUnsafe(buffer) : new SFPModelVertexBufferWriterNio(buffer); } @Override diff --git a/src/main/resources/assets/angelica/lang/en_US.lang b/src/main/resources/assets/angelica/lang/en_US.lang index 1f296995e..920182f18 100644 --- a/src/main/resources/assets/angelica/lang/en_US.lang +++ b/src/main/resources/assets/angelica/lang/en_US.lang @@ -21,7 +21,7 @@ sodium.options.fps_limit.tooltip=Limits the maximum number of frames per second. sodium.options.view_bobbing.tooltip=If enabled, the player's view will sway and bob when moving around. Players who experience motion sickness while playing can benefit from disabling this. sodium.options.attack_indicator.tooltip=Controls where the Attack Indicator is displayed on screen. sodium.options.autosave_indicator.tooltip=If enabled, an indicator will be shown when the game is saving the world to disk. -sodium.options.graphics_quality.tooltip=The default graphics quality controls some legacy options and is necessary for mod compatibility. If the options below are left to \"Default\ they will use this setting. +sodium.options.graphics_quality.tooltip=The default graphics quality controls some legacy options and is necessary for mod compatibility. If the options below are left to "Default they will use this setting. sodium.options.clouds_quality.tooltip=Controls the quality of rendered clouds in the sky. sodium.options.weather_quality.tooltip=Controls the quality of rain and snow effects. sodium.options.leaves_quality.name=Leaves Quality From 836337f5a8f17466cfaa72d38e0df31b6a1e726f Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 24 Nov 2023 20:25:54 -0500 Subject: [PATCH 120/301] Remove MixinWorldRenderer --- src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 5802962fb..710782bd5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -48,7 +48,6 @@ public enum Mixins { ,"sodium.MixinRenderGlobal" ,"sodium.MixinTessellator" ,"sodium.MixinWorldClient" - ,"sodium.MixinWorldRenderer" ,"sodium.MixinGuiIngameForge" ) ), From dee54975c9110d1a512da7f003d8a4e4b9bdc5ee Mon Sep 17 00:00:00 2001 From: Caedis Date: Fri, 24 Nov 2023 22:40:05 -0600 Subject: [PATCH 121/301] Add NEID (mixin pr) support --- dependencies.gradle | 1 + .../gtnewhorizons/angelica/AngelicaMod.java | 4 ++- .../compat/ExtendedBlockStorageExt.java | 30 ++++++++++++++----- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index ef026e051..4ddf56072 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -74,6 +74,7 @@ dependencies { compileOnly(rfg.deobf("curse.maven:extrautils-225561:2264383")) compileOnly(rfg.deobf("curse.maven:dynamiclights-227874:2337326")) + compileOnly("com.github.GTNewHorizons:NotEnoughIds:1.5-pre:dev") // based off https://github.com/GTNewHorizons/NotEnoughIds/pull/2 // HMMMMM compileOnly(rfg.deobf("curse.maven:journeymap-32274:2367915")) diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index 7bfdaa969..d1fe162b0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica; import com.gtnewhorizons.angelica.proxy.CommonProxy; +import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.SidedProxy; import cpw.mods.fml.common.event.FMLInitializationEvent; @@ -15,10 +16,11 @@ public class AngelicaMod { @SidedProxy(clientSide = "com.gtnewhorizons.angelica.proxy.ClientProxy", serverSide = "com.gtnewhorizons.angelica.proxy.CommonProxy") public static CommonProxy proxy; - + public static boolean isNEIDLoaded; @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { + isNEIDLoaded = Loader.isModLoaded("neid"); proxy.preInit(event); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java index 99129cf2d..b631b93d0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java @@ -1,7 +1,10 @@ package com.gtnewhorizons.angelica.compat; +import com.gtnewhorizons.angelica.AngelicaMod; import com.gtnewhorizons.angelica.mixins.early.sodium.MixinExtendedBlockStorage; import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedNibbleArray; +import com.gtnewhorizons.neid.mixins.interfaces.IExtendedBlockStorageMixin; +import cpw.mods.fml.common.Optional; import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; @@ -16,19 +19,32 @@ public ExtendedBlockStorageExt(int yBase, boolean hasSky) { public ExtendedBlockStorageExt(ExtendedBlockStorage storage) { super(((MixinExtendedBlockStorage) storage).getYBase(), storage.getSkylightArray() != null); - final byte[] blockLSBArray = this.getBlockLSBArray(); - - System.arraycopy(storage.getBlockLSBArray(), 0, blockLSBArray, 0, blockLSBArray.length); - if(storage.getBlockMSBArray() != null) { - this.setBlockMSBArray(new NibbleArray(blockLSBArray.length, 4)); - copyNibbleArray((ExtendedNibbleArray) storage.getBlockMSBArray(), (ExtendedNibbleArray) this.getBlockMSBArray()); + int arrayLen; + if (AngelicaMod.isNEIDLoaded){ + final short[] block16BArray = ((IExtendedBlockStorageMixin)(Object)this).getBlock16BArray(); + System.arraycopy(((IExtendedBlockStorageMixin)(Object)storage).getBlock16BArray(), 0, block16BArray, 0, block16BArray.length); + if(storage.getBlockMSBArray() != null) { + this.setBlockMSBArray(new NibbleArray(block16BArray.length, 4)); + copyNibbleArray((ExtendedNibbleArray) storage.getBlockMSBArray(), (ExtendedNibbleArray) this.getBlockMSBArray()); + } + arrayLen = block16BArray.length; + }else { + final byte[] blockLSBArray = this.getBlockLSBArray(); + System.arraycopy(storage.getBlockLSBArray(), 0, blockLSBArray, 0, blockLSBArray.length); + if(storage.getBlockMSBArray() != null) { + this.setBlockMSBArray(new NibbleArray(blockLSBArray.length, 4)); + copyNibbleArray((ExtendedNibbleArray) storage.getBlockMSBArray(), (ExtendedNibbleArray) this.getBlockMSBArray()); + } + arrayLen = blockLSBArray.length; } + + copyNibbleArray((ExtendedNibbleArray) storage.getMetadataArray(), (ExtendedNibbleArray)this.getMetadataArray()); copyNibbleArray((ExtendedNibbleArray) storage.getBlocklightArray(), (ExtendedNibbleArray)this.getBlocklightArray()); if(storage.getSkylightArray() != null) { hasSky = true; if(this.getSkylightArray() == null) { - this.setSkylightArray(new NibbleArray(blockLSBArray.length, 4)); + this.setSkylightArray(new NibbleArray(arrayLen, 4)); } copyNibbleArray((ExtendedNibbleArray) storage.getSkylightArray(), (ExtendedNibbleArray) this.getSkylightArray()); } From 3099931d9a81c5a6fbddc38d697ba25f0cb53d13 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 24 Nov 2023 20:44:45 -0800 Subject: [PATCH 122/301] Fix wildcard imports --- .../mods/sodium/client/gui/SodiumGameOptionPages.java | 6 +++++- .../jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index a3d618bfd..7d659bcb8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -1,7 +1,11 @@ package me.jellysquid.mods.sodium.client.gui; import com.google.common.collect.ImmutableList; -import me.jellysquid.mods.sodium.client.gui.options.*; +import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; +import me.jellysquid.mods.sodium.client.gui.options.OptionGroup; +import me.jellysquid.mods.sodium.client.gui.options.OptionImpact; +import me.jellysquid.mods.sodium.client.gui.options.OptionImpl; +import me.jellysquid.mods.sodium.client.gui.options.OptionPage; import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl; import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java index 9ccb30d4e..043f5f5aa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java @@ -1,7 +1,11 @@ package me.jellysquid.mods.sodium.client.gui; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.options.*; +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; +import me.jellysquid.mods.sodium.client.gui.options.OptionGroup; +import me.jellysquid.mods.sodium.client.gui.options.OptionImpact; +import me.jellysquid.mods.sodium.client.gui.options.OptionPage; import me.jellysquid.mods.sodium.client.gui.options.control.Control; import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; From a29a91c2450e332869384bc8a1ff2d10e7c8c567 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 24 Nov 2023 20:45:02 -0800 Subject: [PATCH 123/301] Iris.MODNAME --- src/main/java/net/coderbot/iris/Iris.java | 2 +- .../net/coderbot/iris/client/IrisDebugScreenHandler.java | 8 +++++--- .../iris/pipeline/DeferredWorldRenderingPipeline.java | 2 +- .../java/net/coderbot/iris/pipeline/ShadowRenderer.java | 8 +++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index b92fc908a..53204511f 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -55,7 +55,7 @@ public class Iris { * The user-facing name of the mod. Moved into a constant to facilitate easy branding changes (for forks). You'll still need to change this separately in * mixin plugin classes & the language files. */ - public static final String MODNAME = "Angelica"; + public static final String MODNAME = "AngelicaShaders"; public static final IrisLogging logger = new IrisLogging(MODNAME + "Shaders"); diff --git a/src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java b/src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java index e430bed01..ea7535f52 100644 --- a/src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java +++ b/src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java @@ -41,12 +41,14 @@ public void onRenderGameOverlayTextEvent(RenderGameOverlayEvent.Text event) { event.right.add(""); if (Iris.getIrisConfig().areShadersEnabled()) { - event.right.add("[Iris] Shaderpack: " + Iris.getCurrentPackName() + (Iris.isFallback() ? " (fallback)" : "")); - Iris.getCurrentPack().ifPresent(pack -> event.right.add("[Iris] " + pack.getProfileInfo())); + event.right.add("[" + Iris.MODNAME + "] Shaderpack: " + Iris.getCurrentPackName() + (Iris.isFallback() ? " (fallback)" : "")); + Iris.getCurrentPack().ifPresent(pack -> event.right.add("[" + Iris.MODNAME + "] " + pack.getProfileInfo())); } else { - event.right.add("[Iris] Shaders are disabled"); + event.right.add("[" + Iris.MODNAME + "] Shaders are disabled"); } + Iris.getPipelineManager().getPipeline().ifPresent(pipeline -> pipeline.addDebugText(event.left)); + } } diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 63b5e9d69..c8494f096 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -1054,7 +1054,7 @@ public void addDebugText(List messages) { if (shadowRenderer != null) { shadowRenderer.addDebugText(messages); } else { - messages.add("[Iris] Shadow Maps: not used by shader pack"); + messages.add("[" + Iris.MODNAME + "] Shadow Maps: not used by shader pack"); } } diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index d9d918e69..65c05eea7 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -642,14 +642,12 @@ public void addDebugText(List messages) { messages.add("[" + Iris.MODNAME + "] Shadow Maps: " + debugStringOverall); messages.add("[" + Iris.MODNAME + "] Shadow Distance Terrain: " + terrainFrustumHolder.getDistanceInfo() + " Entity: " + entityFrustumHolder.getDistanceInfo()); messages.add("[" + Iris.MODNAME + "] Shadow Culling Terrain: " + terrainFrustumHolder.getCullingInfo() + " Entity: " + entityFrustumHolder.getCullingInfo()); - messages.add("[" + Iris.MODNAME + "] Shadow Terrain: " + debugStringTerrain - + (shouldRenderTerrain ? "" : " (no terrain) ") + (shouldRenderTranslucent ? "" : "(no translucent)")); + messages.add("[" + Iris.MODNAME + "] Shadow Terrain: " + debugStringTerrain + (shouldRenderTerrain ? "" : " (no terrain) ") + (shouldRenderTranslucent ? "" : "(no translucent)")); messages.add("[" + Iris.MODNAME + "] Shadow Entities: " + getEntitiesDebugString()); messages.add("[" + Iris.MODNAME + "] Shadow Block Entities: " + getTileEntitiesDebugString()); - if (buffers instanceof DrawCallTrackingRenderBuffers && (shouldRenderEntities || shouldRenderPlayer)) { - DrawCallTrackingRenderBuffers drawCallTracker = (DrawCallTrackingRenderBuffers) buffers; - messages.add("[" + Iris.MODNAME + "] Shadow Entity Batching: " + BatchingDebugMessageHelper.getDebugMessage(drawCallTracker)); + if (buffers instanceof DrawCallTrackingRenderBuffers drawCallTracker && (shouldRenderEntities || shouldRenderPlayer)) { + messages.add("[" + Iris.MODNAME + "] Shadow Entity Batching: " + BatchingDebugMessageHelper.getDebugMessage(drawCallTracker)); } } From ca29fd414a147459495bf291cb1bc001ef5d5f95 Mon Sep 17 00:00:00 2001 From: makamys Date: Sat, 25 Nov 2023 05:46:06 +0100 Subject: [PATCH 124/301] Only shadow runtime module of antlr4 Reduces jar size by 11 mb --- dependencies.gradle | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 4ddf56072..0d60f6512 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -45,7 +45,10 @@ dependencies { shadowImplementation("it.unimi.dsi:fastutil:8.2.1") // Apache 2.0 shadowImplementation("org.joml:joml:1.10.5") // MIT shadowImplementation("org.anarres:jcpp:1.4.14") // Apache 2.0 - shadowImplementation("io.github.douira:glsl-transformer:1.0.0") // glsl-transformer Noncommercial License 1.0.0 + implementation("io.github.douira:glsl-transformer:1.0.0") + shadowImplementation("io.github.douira:glsl-transformer:1.0.0") { // glsl-transformer Noncommercial License 1.0.0 + exclude module: "antlr4" // we only want to shadow the runtime module + } compileOnly "org.apache.ant:ant:1.8.2" From 98e8d13113d8da0763588762ca45360848f77ae1 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Sat, 25 Nov 2023 01:01:56 -0500 Subject: [PATCH 125/301] More blockstate removal + basic Sodium FluidRenderer (#21) If you actually want to work on it, pass -Dsodium.enableFluidRenderer=true --- .../angelica/compat/mojang/FluidState.java | 7 +- .../angelica/compat/mojang/VoxelShape.java | 13 +- .../angelica/compat/mojang/VoxelShapes.java | 6 +- .../compat/mojang/WorldRendererExt.java | 16 ++- .../gtnewhorizons/angelica/mixins/Mixins.java | 6 + .../mixins/early/sodium/MixinBlockLiquid.java | 28 ++++ .../light/cache/ArrayLightDataCache.java | 4 +- .../model/light/cache/HashLightDataCache.java | 3 +- .../model/light/data/LightDataAccess.java | 28 ++-- .../chunk/tasks/ChunkRenderRebuildTask.java | 18 ++- .../client/render/pipeline/FluidRenderer.java | 128 ++++++++---------- .../context/ChunkRenderCacheLocal.java | 4 +- .../context/ChunkRenderCacheShared.java | 8 +- .../mods/sodium/client/util/WorldUtil.java | 84 ++++++++++++ .../mods/sodium/client/world/WorldSlice.java | 15 ++ .../sodium/common/config/SodiumConfig.java | 2 + 16 files changed, 266 insertions(+), 104 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinBlockLiquid.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/WorldUtil.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java index 5d7d81960..2de6149ab 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java @@ -1,6 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; -import net.minecraft.block.Block; +import net.minecraft.block.BlockLiquid; import net.minecraftforge.fluids.Fluid; import org.joml.Vector3d; @@ -30,7 +30,10 @@ public boolean method_15756(BlockRenderView world, BlockPos set) { return true; } + /** + * Returns how much of the block is fluid, from 0 to 1. + */ public float getHeight(BlockRenderView world, BlockPos pos) { - return 0.0f; + return fluid == null ? 0 : 1 - BlockLiquid.getLiquidHeightPercent(meta); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java index 7da3c011b..13fbb5c1a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java @@ -1,8 +1,17 @@ package com.gtnewhorizons.angelica.compat.mojang; -public class VoxelShape { +public enum VoxelShape { + + FULL_CUBE(false), + EMPTY(true); + + private final boolean empty; + + VoxelShape(boolean empty) { + this.empty = empty; + } public boolean isEmpty() { - return false; + return empty; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java index 6b91a9437..4bcb26479 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java @@ -5,7 +5,11 @@ public final class VoxelShapes { public static VoxelShape fullCube() { - return null; + return VoxelShape.FULL_CUBE; + } + + public static VoxelShape empty() { + return VoxelShape.EMPTY; } public static boolean matchesAnywhere(VoxelShape shape1, VoxelShape shape2, Object predicate) { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java index 76e2da087..ac4ff987c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java @@ -1,8 +1,20 @@ package com.gtnewhorizons.angelica.compat.mojang; +import me.jellysquid.mods.sodium.client.world.WorldSlice; +import net.minecraft.block.Block; +import net.minecraft.world.EnumSkyBlock; + public interface WorldRendererExt { - static int getLightmapCoordinates(BlockRenderView world, BlockState state, BlockPos pos) { - return 15; + static int getLightmapCoordinates(WorldSlice world, Block block, BlockPos pos) { + + if (block.getLightValue() > 0) { + return 0xF000F0; + } + + int sl = world.getLightLevel(EnumSkyBlock.Sky, pos.x, pos.y, pos.z); + int bl = world.getLightLevel(EnumSkyBlock.Block, pos.x, pos.y, pos.z); + bl += sl; + return sl << 20 | bl << 4; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 710782bd5..7ab1b02c4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -2,6 +2,7 @@ import com.gtnewhorizons.angelica.config.AngelicaConfig; import cpw.mods.fml.relauncher.FMLLaunchHandler; +import me.jellysquid.mods.sodium.common.config.SodiumConfig; import java.util.ArrayList; import java.util.Arrays; @@ -52,6 +53,11 @@ public enum Mixins { ) ), + // Required for Sodium's FluidRenderer, so it treats vanilla liquids as IFluidBlocks + SODIUM_WISHLIST(new Builder("Sodiumer").addTargetedMod(TargetedMod.VANILLA).setSide(Side.BOTH) + .setPhase(Phase.EARLY).setApplyIf(() -> SodiumConfig.ENABLE_FLUID_RENDERER).addMixinClasses( + "sodium.MixinBlockLiquid")), + IRIS_RENDERING(new Builder("Iris Shaders").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses( "shaders.MixinEntityRenderer" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinBlockLiquid.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinBlockLiquid.java new file mode 100644 index 000000000..c7baa4eac --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinBlockLiquid.java @@ -0,0 +1,28 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockLiquid; +import net.minecraft.block.material.Material; +import net.minecraft.world.World; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.IFluidBlock; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(BlockLiquid.class) +public abstract class MixinBlockLiquid implements IFluidBlock { + + @Shadow + public abstract int getBlockColor(); + + @Override + public Fluid getFluid() { + return ((Block) (Object) this).getMaterial() == Material.water ? FluidRegistry.WATER : FluidRegistry.LAVA; + } + + @Override + public float getFilledPercentage(World world, int x, int y, int z) { + return getFluid() == null ? 0 : 1 - BlockLiquid.getLiquidHeightPercent(world.getBlockMetadata(x, y, z)); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java index 429986e21..c7a445128 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java @@ -1,10 +1,8 @@ package me.jellysquid.mods.sodium.client.model.light.cache; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; import me.jellysquid.mods.sodium.client.world.WorldSlice; -import net.minecraft.world.IBlockAccess; import java.util.Arrays; @@ -21,7 +19,7 @@ public class ArrayLightDataCache extends LightDataAccess { private int xOffset, yOffset, zOffset; - public ArrayLightDataCache(BlockRenderView world) { + public ArrayLightDataCache(WorldSlice world) { this.world = world; this.light = new long[BLOCK_LENGTH * BLOCK_LENGTH * BLOCK_LENGTH]; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java index 93cad2763..89b59f3e7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import it.unimi.dsi.fastutil.longs.Long2LongLinkedOpenHashMap; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; +import me.jellysquid.mods.sodium.client.world.WorldSlice; /** @@ -12,7 +13,7 @@ public class HashLightDataCache extends LightDataAccess { private final Long2LongLinkedOpenHashMap map = new Long2LongLinkedOpenHashMap(1024, 0.50f); - public HashLightDataCache(BlockRenderView world) { + public HashLightDataCache(WorldSlice world) { this.world = world; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java index 38aff7de4..fd6ba4854 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.client.model.light.data; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.compat.mojang.WorldRendererExt; +import me.jellysquid.mods.sodium.client.world.WorldSlice; +import net.minecraft.block.Block; import net.minecraftforge.common.util.ForgeDirection; /** @@ -23,7 +23,7 @@ */ public abstract class LightDataAccess { private final BlockPos.Mutable pos = new BlockPos.Mutable(); - protected BlockRenderView world; + protected WorldSlice world; public long get(int x, int y, int z, ForgeDirection d1, ForgeDirection d2) { return this.get(x + d1.offsetX + d2.offsetX, y + d1.offsetY + d2.offsetY, z + d1.offsetZ + d2.offsetZ); @@ -49,28 +49,30 @@ public long get(BlockPos pos) { protected long compute(int x, int y, int z) { BlockPos pos = this.pos.set(x, y, z); - BlockRenderView world = this.world; + WorldSlice world = this.world; - BlockState state = world.getBlockState(pos); + Block block = world.getBlock(x, y, z); float ao; boolean em; - if (state.getLightValue(world, pos) == 0) { - ao = state.getAmbientOcclusionLightLevel(world, pos); - em = state.hasEmissiveLighting(world, pos); + if (block.getLightValue() == 0) { + ao = block.getAmbientOcclusionLightValue(); + em = false; //state.hasEmissiveLighting(world, pos); } else { ao = 1.0f; em = true; } - boolean op = !state.shouldBlockVision(world, pos) || state.getOpacity(world, pos) == 0; - boolean fo = state.isOpaqueFullCube(world, pos); - boolean fc = state.isFullCube(world, pos); + // First is shouldBlockVision, but I can't find if any transparent objects set it + boolean op = /*state.shouldBlockVision(world, pos) ||*/ block.getLightOpacity() == 0; + boolean fo = block.isOpaqueCube(); + // Should be isFullCube, but this is probably close enough + boolean fc = block.renderAsNormalBlock(); // OPTIMIZE: Do not calculate lightmap data if the block is full and opaque. // FIX: Calculate lightmap data for light-emitting or emissive blocks, even though they are full and opaque. - int lm = (fo && !em) ? 0 : WorldRendererExt.getLightmapCoordinates(world, state, pos); + int lm = (fo && !em) ? 0 : WorldRendererExt.getLightmapCoordinates(world, block, pos); return packAO(ao) | packLM(lm) | packOP(op) | packFO(fo) | packFC(fc) | (1L << 60); } @@ -117,7 +119,7 @@ public static float unpackAO(long word) { return aoi * (1.0f / 4096.0f); } - public BlockRenderView getWorld() { + public WorldSlice getWorld() { return this.world; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index a5abf5b78..388b4df78 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -17,6 +17,7 @@ import me.jellysquid.mods.sodium.client.util.task.CancellationSource; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; +import me.jellysquid.mods.sodium.common.config.SodiumConfig; import net.minecraft.block.Block; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.Tessellator; @@ -24,6 +25,7 @@ import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; +import net.minecraftforge.fluids.IFluidBlock; import org.joml.Vector3d; /** @@ -113,8 +115,8 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB buffers.setRenderOffset(pos.x - renderOffset.getX(), pos.y - renderOffset.getY(), pos.z - renderOffset.getZ()); // Do regular block rendering - for(BlockRenderPass pass : BlockRenderPass.VALUES) { - if(block.canRenderInPass(pass.ordinal())) { + for (BlockRenderPass pass : BlockRenderPass.VALUES) { + if (block.canRenderInPass(pass.ordinal()) && (!SodiumConfig.ENABLE_FLUID_RENDERER || !(block instanceof IFluidBlock))) { long seed = MathUtil.hashPos(pos.x, pos.y, pos.z); if (cache.getBlockRenderer().renderModel(cache.getWorldSlice(), tessellator, renderBlocks, block, meta, pos, buffers.get(pass), true, seed)) { @@ -123,6 +125,18 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB } } + // Do fluid rendering without RenderBlocks + if (SodiumConfig.ENABLE_FLUID_RENDERER && block instanceof IFluidBlock) { + for (BlockRenderPass pass : BlockRenderPass.VALUES) { + if (block.canRenderInPass(pass.ordinal())) { + + if (cache.getFluidRenderer().render(slice, cache.getWorldSlice(), (IFluidBlock) block, pos, buffers.get(pass))) { + bounds.addBlock(relX, relY, relZ); + } + } + } + } + if (block.hasTileEntity(meta)) { TileEntity entity = slice.getTileEntity(pos.x, pos.y, pos.z); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java index 332004846..71661a784 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java @@ -1,78 +1,72 @@ package me.jellysquid.mods.sodium.client.render.pipeline; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import com.gtnewhorizons.angelica.compat.mojang.FluidState; -import com.gtnewhorizons.angelica.compat.mojang.SideShapeType; import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; import com.gtnewhorizons.angelica.compat.mojang.VoxelShapes; -import me.jellysquid.mods.sodium.client.model.light.LightMode; -import me.jellysquid.mods.sodium.client.model.light.LightPipeline; -import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.ModelQuad; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadViewMutable; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadOrientation; import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; import me.jellysquid.mods.sodium.client.util.Norm3b; +import me.jellysquid.mods.sodium.client.util.WorldUtil; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; +import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.util.MathHelper; +import net.minecraft.world.IBlockAccess; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.IFluidBlock; import org.joml.Vector3d; import static org.joml.Math.lerp; public class FluidRenderer { - private static final float EPSILON = 0.001f; private final BlockPos.Mutable scratchPos = new BlockPos.Mutable(); private final ModelQuadViewMutable quad = new ModelQuad(); - private final LightPipelineProvider lighters; - private final QuadLightData quadLightData = new QuadLightData(); private final int[] quadColors = new int[4]; - public FluidRenderer(Minecraft client, LightPipelineProvider lighters) { + public FluidRenderer(Minecraft client) { int normal = Norm3b.pack(0.0f, 1.0f, 0.0f); for (int i = 0; i < 4; i++) { this.quad.setNormal(i, normal); } - - this.lighters = lighters; } - private boolean isFluidOccluded(BlockRenderView world, int x, int y, int z, ForgeDirection dir, Fluid fluid) { - BlockPos pos = this.scratchPos.set(x, y, z); - BlockState blockState = world.getBlockState(pos); - BlockPos adjPos = this.scratchPos.set(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); + private boolean isFluidOccluded(IBlockAccess world, int x, int y, int z, ForgeDirection d, Fluid fluid) { + Block block = world.getBlock(x, y, z); + boolean tmp = FluidRegistry.lookupFluidForBlock(world.getBlock(x + d.offsetX, y + d.offsetY, z + d.offsetZ)) == fluid; - if (blockState.isOpaque()) { - return world.getFluidState(adjPos).getFluid() == fluid || blockState.isSideSolid(world, pos, dir, SideShapeType.FULL); + if (block.getMaterial().isOpaque()) { + return tmp || block.isSideSolid(world, x, y, z, d); // fluidlogged or next to water, occlude sides that are solid or the same liquid // For a liquid block that's always - } - return world.getFluidState(adjPos).getFluid() == fluid; + } + return tmp; } - private boolean isSideExposed(BlockRenderView world, int x, int y, int z, ForgeDirection dir, float height) { + private boolean isSideExposed(IBlockAccess world, int x, int y, int z, ForgeDirection dir, float height) { BlockPos pos = this.scratchPos.set(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); - BlockState blockState = world.getBlockState(pos); + Block block = world.getBlock(pos.x, pos.y, pos.z); - if (blockState.isOpaque()) { - VoxelShape shape = blockState.getCullingShape(world, pos); + if (block.getMaterial().isOpaque()) { + VoxelShape shape = WorldUtil.getCullingShape(block); // Hoist these checks to avoid allocating the shape below if (shape == VoxelShapes.fullCube()) { @@ -90,13 +84,13 @@ private boolean isSideExposed(BlockRenderView world, int x, int y, int z, ForgeD return true; } - public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos, ChunkModelBuffers buffers) { + public boolean render(IBlockAccess world, WorldSlice slice, IFluidBlock block, BlockPos pos, ChunkModelBuffers buffers) { int posX = pos.x; int posY = pos.y; int posZ = pos.z; - Fluid fluid = fluidState.getFluid(); + Fluid fluid = block.getFluid(); // Check for occluded sides; if everything is occluded, don't render boolean sfUp = this.isFluidOccluded(world, posX, posY, posZ, ForgeDirection.UP, fluid); @@ -118,22 +112,19 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos (TextureAtlasSprite) RenderBlocks.getInstance().getBlockIconFromSide(fluid.getBlock(), 2), null };//ForgeHooksClientExt.getFluidSprites(world, pos, fluidState); - boolean hc = fluidState.getFluid().getColor() != 0xffffffff; //fluidState.getFluid().getAttributes().getColor() != 0xffffffff; + boolean hc = fluid.getColor() != 0xffffffff; //fluidState.getFluid().getAttributes().getColor() != 0xffffffff; boolean rendered = false; - float h1 = this.getCornerHeight(world, posX, posY, posZ, fluidState.getFluid()); - float h2 = this.getCornerHeight(world, posX, posY, posZ + 1, fluidState.getFluid()); - float h3 = this.getCornerHeight(world, posX + 1, posY, posZ + 1, fluidState.getFluid()); - float h4 = this.getCornerHeight(world, posX + 1, posY, posZ, fluidState.getFluid()); + float h1 = this.getCornerHeight(world, posX, posY, posZ, fluid); + float h2 = this.getCornerHeight(world, posX, posY, posZ + 1, fluid); + float h3 = this.getCornerHeight(world, posX + 1, posY, posZ + 1, fluid); + float h4 = this.getCornerHeight(world, posX + 1, posY, posZ, fluid); float yOffset = sfDown ? 0.0F : EPSILON; final ModelQuadViewMutable quad = this.quad; - LightMode lightMode = hc && Minecraft.isAmbientOcclusionEnabled() ? LightMode.SMOOTH : LightMode.FLAT; - LightPipeline lighter = this.lighters.getLighter(lightMode); - quad.setFlags(0); if (!sfUp && this.isSideExposed(world, posX, posY, posZ, ForgeDirection.UP, Math.min(Math.min(h1, h2), Math.min(h3, h4)))) { @@ -142,7 +133,7 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos h3 -= 0.001F; h4 -= 0.001F; - Vector3d velocity = fluidState.getVelocity(world, pos); + Vector3d velocity = WorldUtil.getVelocity(world, pos); TextureAtlasSprite sprite; ModelQuadFacing facing; @@ -198,10 +189,10 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos this.setVertex(quad, 2, 1.0F, h3, 1.0F, u3, v3); this.setVertex(quad, 3, 1.0F, h4, 0.0f, u4, v4); - this.calculateQuadColors(quad, world, pos, lighter, ForgeDirection.UP, 1.0F, hc); + this.calculateQuadColors(quad, pos, ForgeDirection.UP, 1.0F, hc); this.flushQuad(buffers, quad, facing, false); - if (fluidState.method_15756(world, this.scratchPos.set(posX, posY + 1, posZ))) { + if (WorldUtil.method_15756(slice, this.scratchPos.set(posX, posY + 1, posZ), fluid)) { this.setVertex(quad, 3, 0.0f, h1, 0.0f, u1, v1); this.setVertex(quad, 2, 0.0f, h2, 1.0F, u2, v2); this.setVertex(quad, 1, 1.0F, h3, 1.0F, u3, v3); @@ -227,7 +218,7 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos this.setVertex(quad, 2, 1.0F, yOffset, 0.0f, maxU, minV); this.setVertex(quad, 3, 1.0F, yOffset, 1.0F, maxU, maxV); - this.calculateQuadColors(quad, world, pos, lighter, ForgeDirection.DOWN, 1.0F, hc); + this.calculateQuadColors(quad, pos, ForgeDirection.DOWN, 1.0F, hc); this.flushQuad(buffers, quad, ModelQuadFacing.DOWN, false); rendered = true; @@ -305,10 +296,9 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos TextureAtlasSprite oSprite = sprites[2]; if (oSprite != null) { - BlockPos adjPos = this.scratchPos.set(adjX, adjY, adjZ); - BlockState adjBlock = world.getBlockState(adjPos); + Block adjBlock = world.getBlock(adjX, adjY, adjZ); - if (adjBlock.shouldDisplayFluidOverlay(world, adjPos, fluidState)) { + if (WorldUtil.shouldDisplayFluidOverlay(adjBlock)) { // should ignore invisible blocks, barriers, light blocks // use static water when adjacent block is ice, glass, stained glass, tinted glass sprite = oSprite; @@ -332,7 +322,7 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos ModelQuadFacing facing = ModelQuadFacing.fromDirection(dir); - this.calculateQuadColors(quad, world, pos, lighter, dir, br, hc); + this.calculateQuadColors(quad, pos, dir, br, hc); this.flushQuad(buffers, quad, facing, false); if (sprite != oSprite) { @@ -351,9 +341,8 @@ public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos return rendered; } - private void calculateQuadColors(ModelQuadView quad, BlockRenderView world, BlockPos pos, LightPipeline lighter, ForgeDirection dir, float brightness, boolean colorized) { + private void calculateQuadColors(ModelQuadView quad, BlockPos pos, ForgeDirection dir, float brightness, boolean colorized) { QuadLightData light = this.quadLightData; - lighter.calculate(quad, pos, light, null, dir, false); int[] biomeColors = null; @@ -367,34 +356,29 @@ private void calculateQuadColors(ModelQuadView quad, BlockRenderView world, Blo } private void flushQuad(ChunkModelBuffers buffers, ModelQuadView quad, ModelQuadFacing facing, boolean flip) { - int vertexIdx, lightOrder; - - if (flip) { - vertexIdx = 3; - lightOrder = -1; - } else { - vertexIdx = 0; - lightOrder = 1; - } ModelVertexSink sink = buffers.getSink(facing); sink.ensureCapacity(4); - for (int i = 0; i < 4; i++) { - float x = quad.getX(i); - float y = quad.getY(i); - float z = quad.getZ(i); + //ChunkRenderData.Builder renderData = buffers.getRenderData(); + + ModelQuadOrientation order = flip ? ModelQuadOrientation.NORMAL : ModelQuadOrientation.FLIP; + + for (int dstIndex = 0; dstIndex < 4; dstIndex++) { + int srcIndex = order.getVertexIndex(dstIndex); - int color = this.quadColors[vertexIdx]; + float x = quad.getX(srcIndex); + float y = quad.getY(srcIndex); + float z = quad.getZ(srcIndex); - float u = quad.getTexU(i); - float v = quad.getTexV(i); + int color = this.quadColors[srcIndex]; - int light = this.quadLightData.lm[vertexIdx]; + float u = quad.getTexU(srcIndex); + float v = quad.getTexV(srcIndex); - sink.writeQuad(x, y, z, color, u, v, light); + int lm = quad.getLight(srcIndex); - vertexIdx += lightOrder; + sink.writeQuad(x, y, z, color, u, v, lm); } TextureAtlasSprite sprite = quad.rubidium$getSprite(); @@ -414,7 +398,7 @@ private void setVertex(ModelQuadViewMutable quad, int i, float x, float y, float quad.setTexV(i, v); } - private float getCornerHeight(BlockRenderView world, int x, int y, int z, Fluid fluid) { + private float getCornerHeight(IBlockAccess world, int x, int y, int z, Fluid fluid) { int samples = 0; float totalHeight = 0.0F; @@ -422,18 +406,20 @@ private float getCornerHeight(BlockRenderView world, int x, int y, int z, Fluid int x2 = x - (i & 1); int z2 = z - (i >> 1 & 1); + Block block = world.getBlock(x2, y + 1, z2); - if (world.getFluidState(this.scratchPos.set(x2, y + 1, z2)).getFluid() == fluid) { + if (block instanceof IFluidBlock && ((IFluidBlock) block).getFluid() == fluid) { return 1.0F; } BlockPos pos = this.scratchPos.set(x2, y, z2); - BlockState blockState = world.getBlockState(pos); - FluidState fluidState = blockState.getFluidState(); + block = world.getBlock(pos.x, pos.y, pos.z); + int meta = world.getBlockMetadata(pos.x, pos.y, pos.z); + Fluid fluid2 = block instanceof IFluidBlock ? ((IFluidBlock) world.getBlock(pos.x, pos.y, pos.z)).getFluid() : null; - if (fluidState.getFluid() == fluid) { - float height = fluidState.getHeight(world, pos); + if (fluid2 == fluid) { + float height = WorldUtil.getFluidHeight(fluid2, meta); if (height >= 0.8F) { totalHeight += height * 10.0F; @@ -442,7 +428,7 @@ private float getCornerHeight(BlockRenderView world, int x, int y, int z, Fluid totalHeight += height; ++samples; } - } else if (!blockState.getMaterial().isSolid()) { + } else if (!block.getMaterial().isSolid()) { ++samples; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java index b5246a2b8..c0ebef104 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java @@ -1,8 +1,6 @@ package me.jellysquid.mods.sodium.client.render.pipeline.context; import com.gtnewhorizons.angelica.compat.mojang.BlockModels; -import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; -import me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache; import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; import me.jellysquid.mods.sodium.client.render.pipeline.FluidRenderer; @@ -22,7 +20,7 @@ public ChunkRenderCacheLocal(Minecraft client, WorldClient world) { this.worldSlice = new WorldSlice(world); this.blockRenderer = new BlockRenderer(client); - this.fluidRenderer = new FluidRenderer(client, null); + this.fluidRenderer = new FluidRenderer(client); // TODO: Sodium this.blockModels = null; // client.getBakedModelManager().getBlockModels(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java index ed6447236..8274f6ece 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java @@ -2,10 +2,10 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; -import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.cache.HashLightDataCache; import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; +import me.jellysquid.mods.sodium.client.world.WorldSlice; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.world.World; @@ -18,10 +18,10 @@ public class ChunkRenderCacheShared extends ChunkRenderCache { private final BlockRenderer blockRenderer; private final HashLightDataCache lightCache; - private ChunkRenderCacheShared(WorldClient world) { + private ChunkRenderCacheShared(WorldSlice world) { Minecraft client = Minecraft.getMinecraft(); - this.lightCache = new HashLightDataCache((BlockRenderView)world); + this.lightCache = new HashLightDataCache(world); this.blockRenderer = new BlockRenderer(client); } @@ -55,7 +55,7 @@ public static void createRenderContext(WorldClient world) { throw new IllegalStateException("Render context already exists for world: " + world); } - INSTANCES.put(world, new ChunkRenderCacheShared(world)); + INSTANCES.put(world, new ChunkRenderCacheShared(new WorldSlice(world))); } public static void resetCaches() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/WorldUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/WorldUtil.java new file mode 100644 index 000000000..b56e9a21e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/WorldUtil.java @@ -0,0 +1,84 @@ +package me.jellysquid.mods.sodium.client.util; + +import com.gtnewhorizons.angelica.compat.mojang.*; +import net.minecraft.block.Block; +import net.minecraft.block.BlockLiquid; +import net.minecraft.block.material.Material; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import org.joml.Vector3d; + +/** + * Contains methods stripped from BlockState or FluidState that didn't actually need to be there. Technically these + * could be a mixin to Block or Fluid, but that's annoying while not actually providing any benefit. + */ +public class WorldUtil { + + public static Vector3d getVelocity(IBlockAccess world, BlockPos pos) { + + Vector3d velocity = new Vector3d(); + ForgeDirection[] news = new ForgeDirection[]{ ForgeDirection.NORTH, ForgeDirection.EAST, ForgeDirection.WEST, ForgeDirection.SOUTH }; + BlockPos target = new BlockPos.Mutable(); + target.set(pos); + Fluid thisFluid = FluidRegistry.lookupFluidForBlock(world.getBlock(pos.x, pos.y, pos.z)); + int meta = world.getBlockMetadata(pos.x, pos.y, pos.z); + + // for each orthogonally adjacent fluid, add the height delta + for (ForgeDirection d : news) { + + target.add(d.offsetX, 0, d.offsetZ); + Fluid orthoFluid = FluidRegistry.lookupFluidForBlock(world.getBlock(pos.x, pos.y, pos.z)); + int orthoMeta = world.getBlockMetadata(pos.x, pos.y, pos.z); + double mult; + + // blocks always add 0.9, for some reason + if (orthoFluid == null) { + mult = 0.9; + } else { + + mult = WorldUtil.getFluidHeight(thisFluid, meta) - WorldUtil.getFluidHeight(orthoFluid, orthoMeta); + } + + velocity.add(d.offsetX * mult, 0, d.offsetZ * mult); + target.add(-d.offsetX, 0, -d.offsetZ); + } + + return velocity.normalize(); + } + + /** + * Returns true if any block in a 3x3x3 cube is not the same fluid and not an opaque full cube. + * Equivalent to FluidState::method_15756 in modern. + */ + public static boolean method_15756(IBlockAccess world, BlockPos pos, Fluid fluid) { + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) { + Block block = world.getBlock(pos.x, pos.y, pos.z); + if (!block.isOpaqueCube() && FluidRegistry.lookupFluidForBlock(block) != fluid) { + return true; + } + } + } + + return false; + } + + public static VoxelShape getCullingShape(Block block) { + return block.renderAsNormalBlock() ? VoxelShapes.fullCube() : VoxelShapes.empty(); + } + + /** + * Returns fluid height as a percentage of the block; 0 is none and 1 is full. + */ + public static float getFluidHeight(Fluid fluid, int meta) { + return fluid == null ? 0 : 1 - BlockLiquid.getLiquidHeightPercent(meta); + } + + // I believe forge mappings in modern say BreakableBlock, while yarn says TransparentBlock. + // I have a sneaking suspicion isOpaque is neither, but it works for now + public static boolean shouldDisplayFluidOverlay(Block block) { + return !block.getMaterial().isOpaque() || block.getMaterial() == Material.leaves; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 4ce4f920c..b13d0f74b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -344,4 +344,19 @@ public static int getLocalSectionIndex(int x, int y, int z) { public static int getLocalChunkIndex(int x, int z) { return z << TABLE_BITS | x; } + + // Modern checks if the sky is darkened, which only happens in the nether. However, I think 1.7.10's hasNoSky is + // close enough and possibly a behavior change between versions. I also don't know why it's rotationally asymmetric + public float getBrightness(ForgeDirection direction, boolean shaded) { + if (world.provider.hasNoSky) { + return shaded ? 0.9f : 1.0f; + } + return switch (direction) { + case DOWN -> shaded ? 0.9f : 0.5f; + case UP -> shaded ? 0.9f : 1.0f; + case NORTH, SOUTH -> 0.8f; + case WEST, EAST -> 0.6f; + case UNKNOWN -> 1.0f; + }; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java b/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java index 552bc68ab..1a2731ed8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java @@ -29,6 +29,8 @@ public class SodiumConfig { ).map(SodiumConfig::getMixinRuleName).collect(Collectors.toSet()); private final Map options = new HashMap<>(); + // Enable Sodium's fluid renderer. Part of RenderBlocks removal, postponed for now + public static final boolean ENABLE_FLUID_RENDERER = Boolean.parseBoolean(System.getProperty("sodium.enableFluidRenderer", "false")); private SodiumConfig() { // Defines the default rules which can be configured by the user or other mods. From b26db41daff1c4fa1d1436ac130c44bad6cf1308 Mon Sep 17 00:00:00 2001 From: jss2a98aj Date: Sat, 25 Nov 2023 03:39:01 -0500 Subject: [PATCH 126/301] Update NotFine --- .../angelica/loading/AngelicaTweaker.java | 5 + .../notfine/clouds/MixinRenderGlobal.java | 7 +- .../early/notfine/faceculling/MixinBlock.java | 75 +++++++++ .../notfine/faceculling/MixinBlockSlab.java | 67 ++++++++ .../notfine/faceculling/MixinBlockSnow.java | 60 +++++++ .../notfine/faceculling/MixinBlockStairs.java | 30 ++++ .../early/notfine/glint/MixinRenderItem.java | 7 +- .../notfine/leaves/MixinBlockLeaves.java | 28 ++-- .../notfine/leaves/MixinBlockLeavesBase.java | 2 +- .../particles/MixinEffectRenderer.java | 91 ++--------- .../notfine/renderer/MixinRenderGlobal.java | 4 +- .../notfine/settings/MixinGameSettings.java | 81 ++++------ .../notfine/toggle/MixinEntityRenderer.java | 23 +++ .../early/notfine/toggle/MixinRender.java | 6 +- .../early/notfine/toggle/MixinRenderItem.java | 8 +- .../thaumcraft/MixinBlockMagicalLeaves.java | 26 ++- .../twilightforest/MixinBlockTFLeaves.java | 9 +- .../twilightforest/MixinBlockTFLeaves3.java | 9 +- .../MixinBlockTFMagicLeaves.java | 11 +- .../witchery/MixinBlockWitchLeaves.java | 9 +- .../jss/notfine/core/LoadMenuButtons.java | 5 +- src/main/java/jss/notfine/core/Settings.java | 25 +-- .../jss/notfine/core/SettingsManager.java | 22 +++ .../jss/notfine/gui/GuiCustomMenuButton.java | 1 - .../java/jss/notfine/gui/MenuButtonLists.java | 9 +- .../util/IFaceObstructionCheckHelper.java | 9 ++ .../java/jss/notfine/util/ILeafBlock.java | 41 ++++- .../java/jss/notfine/util/LeafRenderUtil.java | 150 ++++++++++-------- src/main/java/jss/util/DirectionHelper.java | 41 ----- 29 files changed, 543 insertions(+), 318 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlock.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockSlab.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockSnow.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockStairs.java create mode 100644 src/main/java/jss/notfine/util/IFaceObstructionCheckHelper.java delete mode 100644 src/main/java/jss/util/DirectionHelper.java diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index 03b01d5c8..79656f0ff 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -117,6 +117,11 @@ private List getNotFineMixins(Set loadedCoreMods) { mixins.add("notfine.clouds.MixinGameSettings"); mixins.add("notfine.clouds.MixinRenderGlobal"); mixins.add("notfine.clouds.MixinWorldType"); + + mixins.add("notfine.faceculling.MixinBlock"); + mixins.add("notfine.faceculling.MixinBlockSlab"); + mixins.add("notfine.faceculling.MixinBlockSnow"); + mixins.add("notfine.faceculling.MixinBlockStairs"); mixins.add("notfine.glint.MixinItemRenderer"); mixins.add("notfine.glint.MixinRenderBiped"); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java index f7dc0dc9b..133137afc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java @@ -18,7 +18,7 @@ import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; -@Mixin(RenderGlobal.class) +@Mixin(value = RenderGlobal.class, priority = 990) public abstract class MixinRenderGlobal { /** @@ -199,7 +199,7 @@ public void renderCloudsFast(float partialTicks) { float red = (float)color.xCoord; float green = (float)color.yCoord; float blue = (float)color.zCoord; - if (mc.gameSettings.anaglyph) { + if(mc.gameSettings.anaglyph) { float altRed = (red * 30.0F + green * 59.0F + blue * 11.0F) / 100.0F; float altGreen = (red * 30.0F + green * 70.0F) / 100.0F; float altBlue = (red * 30.0F + blue * 70.0F) / 100.0F; @@ -208,9 +208,8 @@ public void renderCloudsFast(float partialTicks) { blue = altBlue; } double cloudTick = ((float)cloudTickCounter + partialTicks); - float cameraOffsetY = (float)(mc.renderViewEntity.lastTickPosY + (mc.renderViewEntity.posY - mc.renderViewEntity.lastTickPosY) * (double)partialTicks); - double cameraOffsetX = mc.renderViewEntity.prevPosX + (mc.renderViewEntity.posX - mc.renderViewEntity.prevPosX) * (double)partialTicks + cloudTick * 0.029999999329447746D; + double cameraOffsetX = mc.renderViewEntity.prevPosX + (mc.renderViewEntity.posX - mc.renderViewEntity.prevPosX) * (double)partialTicks + cloudTick * 0.03D; double cameraOffsetZ = mc.renderViewEntity.prevPosZ + (mc.renderViewEntity.posZ - mc.renderViewEntity.prevPosZ) * (double)partialTicks; cameraOffsetX -= MathHelper.floor_double(cameraOffsetX / 2048.0D) * 2048; cameraOffsetZ -= MathHelper.floor_double(cameraOffsetZ / 2048.0D) * 2048; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlock.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlock.java new file mode 100644 index 000000000..4402922e3 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlock.java @@ -0,0 +1,75 @@ +package com.gtnewhorizons.angelica.mixins.early.notfine.faceculling; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import jss.notfine.util.IFaceObstructionCheckHelper; +import net.minecraft.block.Block; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(value = Block.class) +public abstract class MixinBlock { + + /** + * @author jss2a98aj + * @reason More accurate face culling. + */ + @Overwrite() + @SideOnly(Side.CLIENT) + public boolean shouldSideBeRendered(IBlockAccess worldIn, int x, int y, int z, int side) { + //Check if side is touching another block + switch(side) { + case 0 -> { + if (minY > 0.0D) { + return true; + } + } + case 1 -> { + if (maxY < 1.0D) { + return true; + } + } + case 2 -> { + if (minZ > 0.0D) { + return true; + } + } + case 3 -> { + if (maxZ < 1.0D) { + return true; + } + } + case 4 -> { + if (minX > 0.0D) { + return true; + } + } + case 5 -> { + if (maxX < 1.0D) { + return true; + } + } + } + //Check if other block is solid + Block otherBlock = worldIn.getBlock(x, y, z); + if(otherBlock.isOpaqueCube()) { + return false; + } + //Check for IFaceObstructionCheckHelper + if(otherBlock instanceof IFaceObstructionCheckHelper target) { + return target.isFaceNonObstructing(worldIn, x, y, z, side, minX, minY, minZ, maxX, maxY, maxZ); + } + //Default + return true; + } + + @Shadow protected double minX; + @Shadow protected double minY; + @Shadow protected double minZ; + @Shadow protected double maxX; + @Shadow protected double maxY; + @Shadow protected double maxZ; + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockSlab.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockSlab.java new file mode 100644 index 000000000..42e43e9e0 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockSlab.java @@ -0,0 +1,67 @@ +package com.gtnewhorizons.angelica.mixins.early.notfine.faceculling; + +import jss.notfine.util.IFaceObstructionCheckHelper; +import net.minecraft.block.Block; +import net.minecraft.block.BlockSlab; +import net.minecraft.block.material.Material; +import net.minecraft.util.Facing; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(value = BlockSlab.class) +public abstract class MixinBlockSlab extends Block implements IFaceObstructionCheckHelper { + + public boolean shouldSideBeRendered(IBlockAccess worldIn, int x, int y, int z, int side) { + //If the slab is not a full cube and this is up or down + if(!field_150004_a && side <= 1) { + int thisX = x + Facing.offsetsXForSide[Facing.oppositeSide[side]]; + int thisY = y + Facing.offsetsYForSide[Facing.oppositeSide[side]]; + int thisZ = z + Facing.offsetsZForSide[Facing.oppositeSide[side]]; + if((worldIn.getBlockMetadata(thisX, thisY, thisZ) & 8) != side) { + return true; + } + } + //Check if other block is solid + Block otherBlock = worldIn.getBlock(x, y, z); + if(otherBlock.isOpaqueCube()) { + return false; + } + //Check for IFaceObstructionCheckHelper + if(otherBlock instanceof IFaceObstructionCheckHelper target) { + return target.isFaceNonObstructing(worldIn, x, y, z, side, minX, minY, minZ, maxX, maxY, maxZ); + } + //Default + return true; + } + + /** + * @author jss2a98aj + * @reason Improved accuracy in the case a mod ever uses this. + */ + @Overwrite() + private static boolean func_150003_a(Block block) { + return block.getRenderBlockPass() == 0 && block instanceof BlockSlab; + } + + @Override() + public boolean isFaceNonObstructing(IBlockAccess worldIn, int x, int y, int z, int side, double otherMinX, double otherMinY, double otherMinZ, double otherMaxX, double otherMaxY, double otherMaxZ) { + if(getRenderBlockPass() == 1) { + return true; + } + boolean isTop = (worldIn.getBlockMetadata(x, y, z) & 8) != 0; + return switch (side) { + // -y bottom + case 0 -> !isTop; + // +y top + case 1 -> isTop; + default -> isTop ? otherMinY < 0.5D : otherMaxY > 0.5D; + }; + } + + MixinBlockSlab(Material material) { super(material); } + + @Shadow @Final protected boolean field_150004_a; +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockSnow.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockSnow.java new file mode 100644 index 000000000..97c7b0d24 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockSnow.java @@ -0,0 +1,60 @@ +package com.gtnewhorizons.angelica.mixins.early.notfine.faceculling; + +import jss.notfine.util.IFaceObstructionCheckHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.block.Block; +import net.minecraft.block.BlockSnow; +import net.minecraft.block.material.Material; +import net.minecraft.world.IBlockAccess; + +@Mixin(value = BlockSnow.class) +public abstract class MixinBlockSnow extends Block implements IFaceObstructionCheckHelper { + + MixinBlockSnow(Material material) { + super(material); + } + + /** + * @author jss2a98aj + * @reason More accurate face culling. + */ + @Overwrite() + @SideOnly(Side.CLIENT) + public boolean shouldSideBeRendered(IBlockAccess worldIn, int x, int y, int z, int side) { + //If this is the top and this is not full height + if(side == 1 && maxY < 1.0D) { + return true; + } + //Check if other block is solid + Block otherBlock = worldIn.getBlock(x, y, z); + if(otherBlock.isOpaqueCube()) { + return false; + } + //Check for IFaceObstructionCheckHelper + if(otherBlock instanceof IFaceObstructionCheckHelper target) { + return target.isFaceNonObstructing(worldIn, x, y, z, side, minX, minY, minZ, maxX, maxY, maxZ); + } + //Default + return true; + } + + @Override() + public boolean isFaceNonObstructing(IBlockAccess worldIn, int x, int y, int z, int side, double otherMinX, double otherMinY, double otherMinZ, double otherMaxX, double otherMaxY, double otherMaxZ) { + if(getRenderBlockPass() == 1) { + return true; + } + int meta = worldIn.getBlockMetadata(x, y, z) & 7; + return switch (side) { + // +y top + case 0 -> meta != 7; + // -y bottom + case 1 -> false; + default -> otherMaxY > (float) (2 * (1 + meta)) * 0.0625f; + }; + } +} + diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockStairs.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockStairs.java new file mode 100644 index 000000000..7f81d2ad8 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockStairs.java @@ -0,0 +1,30 @@ +package com.gtnewhorizons.angelica.mixins.early.notfine.faceculling; + +import jss.notfine.util.IFaceObstructionCheckHelper; +import net.minecraft.block.Block; +import net.minecraft.block.BlockStairs; +import net.minecraft.block.material.Material; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(value = BlockStairs.class) +public abstract class MixinBlockStairs extends Block implements IFaceObstructionCheckHelper { + + @Override() + public boolean isFaceNonObstructing(IBlockAccess worldIn, int x, int y, int z, int side, double otherMinX, double otherMinY, double otherMinZ, double otherMaxX, double otherMaxY, double otherMaxZ) { + if(getRenderBlockPass() == 1) { + return true; + } + boolean isTop = (worldIn.getBlockMetadata(x, y, z) & 7) > 3; + return switch (side) { + // -y bottom + case 0 -> !isTop; + // +y top + case 1 -> isTop; + default -> isTop ? otherMinY < 0.5D : otherMaxY > 0.5D; + }; + } + + protected MixinBlockStairs(Material materialIn) { super(materialIn); } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java index b6b58e4fb..59b6feb63 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java @@ -64,7 +64,12 @@ private void renderGlint(int unused, int posX, int posY, int width, int height) @Redirect( method = "renderDroppedItem(Lnet/minecraft/entity/item/EntityItem;Lnet/minecraft/util/IIcon;IFFFFI)V", - at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;hasEffect(I)Z"), remap = false) + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/item/ItemStack;hasEffect(I)Z" + ), + remap = false + ) private boolean notFine$toggleGlint(ItemStack stack, int pass) { return Settings.MODE_GLINT_WORLD.isValueBase() && stack.hasEffect(pass); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java index b21fdaa47..2b06318ba 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java @@ -3,10 +3,10 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; import jss.notfine.util.ILeafBlock; -import jss.util.DirectionHelper; import net.minecraft.block.BlockLeaves; import net.minecraft.block.BlockLeavesBase; import net.minecraft.block.material.Material; +import net.minecraft.util.Facing; import net.minecraft.util.IIcon; import net.minecraft.world.IBlockAccess; import org.spongepowered.asm.mixin.Mixin; @@ -32,28 +32,22 @@ public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { } int renderMode = (int)Settings.MODE_LEAVES.getValue(); int maskedMeta = world.getBlockMetadata(x, y, z) & 3; - switch(renderMode) { - case -1: - renderMode = SettingsManager.leavesOpaque ? 1 : 0; - break; - case 4: - renderMode = world.getBlock( - x + DirectionHelper.xDirectionalIncrease[side], - y + DirectionHelper.yDirectionalIncrease[side], - z + DirectionHelper.zDirectionalIncrease[side] - ) instanceof ILeafBlock ? 1 : 0; - break; - default: - renderMode = renderMode > 1 ? 0 : renderMode; - break; - } + renderMode = switch (renderMode) { + case -1 -> SettingsManager.leavesOpaque ? 1 : 0; + case 4 -> world.getBlock( + x + Facing.offsetsXForSide[side], + y + Facing.offsetsYForSide[side], + z + Facing.offsetsZForSide[side] + ) instanceof ILeafBlock ? 1 : 0; + default -> renderMode > 1 ? 0 : renderMode; + }; maskedMeta = maskedMeta >= field_150129_M[renderMode].length ? 0 : maskedMeta; return field_150129_M[renderMode][maskedMeta]; } @Shadow protected IIcon[][] field_150129_M; - private MixinBlockLeaves(Material material, boolean overridden) { + protected MixinBlockLeaves(Material material, boolean overridden) { super(material, overridden); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java index 8583e3c4f..555c0591b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java @@ -16,7 +16,7 @@ public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int return LeafRenderUtil.shouldSideBeRendered(world, x, y, z, side); } - private MixinBlockLeavesBase(Material material) { + protected MixinBlockLeavesBase(Material material) { super(material); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java index acea5f6e9..0ab4c61b2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java @@ -1,23 +1,9 @@ package com.gtnewhorizons.angelica.mixins.early.notfine.particles; import net.minecraft.client.particle.EffectRenderer; -import net.minecraft.client.particle.EntityFX; -import net.minecraft.client.renderer.ActiveRenderInfo; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.client.renderer.texture.TextureMap; -import net.minecraft.crash.CrashReport; -import net.minecraft.crash.CrashReportCategory; -import net.minecraft.entity.Entity; -import net.minecraft.util.ReportedException; -import net.minecraft.util.ResourceLocation; -import org.lwjgl.opengl.GL11; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.List; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(value = EffectRenderer.class) public abstract class MixinEffectRenderer { @@ -26,69 +12,16 @@ public abstract class MixinEffectRenderer { * @author jss2a98aj * @reason Makes most particles render with the expected depth. */ - @Overwrite - public void renderParticles(Entity entity, float p_78874_2_) { - float f1 = ActiveRenderInfo.rotationX; - float f2 = ActiveRenderInfo.rotationZ; - float f3 = ActiveRenderInfo.rotationYZ; - float f4 = ActiveRenderInfo.rotationXY; - float f5 = ActiveRenderInfo.rotationXZ; - EntityFX.interpPosX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * (double)p_78874_2_; - EntityFX.interpPosY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * (double)p_78874_2_; - EntityFX.interpPosZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * (double)p_78874_2_; - - GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - GL11.glEnable(GL11.GL_BLEND); - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - GL11.glAlphaFunc(GL11.GL_GREATER, 0.003921569F); - Tessellator tessellator = Tessellator.instance; - - for (int k = 0; k < 3; ++k) { - final int i = k; - - if (!fxLayers[i].isEmpty()) { - switch(i) { - case 0: - default: - renderer.bindTexture(particleTextures); - break; - case 1: - renderer.bindTexture(TextureMap.locationBlocksTexture); - break; - case 2: - renderer.bindTexture(TextureMap.locationItemsTexture); - } - - tessellator.startDrawingQuads(); - - for (int j = 0; j < fxLayers[i].size(); ++j) { - final EntityFX entityfx = (EntityFX)fxLayers[i].get(j); - if (entityfx == null) continue; - tessellator.setBrightness(entityfx.getBrightnessForRender(p_78874_2_)); - - try { - entityfx.renderParticle(tessellator, p_78874_2_, f1, f5, f2, f3, f4); - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Rendering Particle"); - CrashReportCategory crashreportcategory = crashreport.makeCategory("Particle being rendered"); - crashreportcategory.addCrashSectionCallable("Particle", entityfx::toString); - crashreportcategory.addCrashSectionCallable( - "Particle Type", - () -> i == 0 ? "MISC_TEXTURE" : (i == 1 ? "TERRAIN_TEXTURE" : (i == 2 ? "ITEM_TEXTURE" : (i == 3 ? "ENTITY_PARTICLE_TEXTURE" : "Unknown - " + i))) - ); - throw new ReportedException(crashreport); - } - } - tessellator.draw(); - } - } - GL11.glDisable(GL11.GL_BLEND); - GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F); + @Redirect( + method = "renderParticles", + at = @At( + value = "INVOKE", + target = "Lorg/lwjgl/opengl/GL11;glDepthMask(Z)V", + ordinal = 0, + remap = false + ) + ) + private void skipGlDepthMask(boolean flag) { } - @Shadow @Final - private static ResourceLocation particleTextures; - @Shadow private List[] fxLayers; - @Shadow private TextureManager renderer; - } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/renderer/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/renderer/MixinRenderGlobal.java index 4f8a186a7..21e69564f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/renderer/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/renderer/MixinRenderGlobal.java @@ -9,8 +9,8 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(RenderGlobal.class) -public class MixinRenderGlobal { +@Mixin(value = RenderGlobal.class) +public abstract class MixinRenderGlobal { @Inject(method = "renderSky", at = @At("HEAD"), cancellable = true) void notFine$toggleSky(CallbackInfo ci) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java index 39e89d25b..f1e31ff71 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/settings/MixinGameSettings.java @@ -29,75 +29,57 @@ public abstract class MixinGameSettings { */ @Overwrite public void setOptionFloatValue(GameSettings.Options option, float value) { - switch(option) { - case SENSITIVITY: - mouseSensitivity = value; - break; - case FOV: - fovSetting = value; - break; - case GAMMA: - gammaSetting = value; - break; - case FRAMERATE_LIMIT: - limitFramerate = (int) value; - break; - case CHAT_OPACITY: + switch (option) { + case SENSITIVITY -> mouseSensitivity = value; + case FOV -> fovSetting = value; + case GAMMA -> gammaSetting = value; + case FRAMERATE_LIMIT -> limitFramerate = (int) value; + case CHAT_OPACITY -> { chatOpacity = value; mc.ingameGUI.getChatGUI().refreshChat(); - break; - case CHAT_HEIGHT_FOCUSED: + } + case CHAT_HEIGHT_FOCUSED -> { chatHeightFocused = value; mc.ingameGUI.getChatGUI().refreshChat(); - break; - case CHAT_HEIGHT_UNFOCUSED: + } + case CHAT_HEIGHT_UNFOCUSED -> { chatHeightUnfocused = value; mc.ingameGUI.getChatGUI().refreshChat(); - break; - case CHAT_WIDTH: + } + case CHAT_WIDTH -> { chatWidth = value; mc.ingameGUI.getChatGUI().refreshChat(); - break; - case CHAT_SCALE: + } + case CHAT_SCALE -> { chatScale = value; mc.ingameGUI.getChatGUI().refreshChat(); - break; - case ANISOTROPIC_FILTERING: - if(anisotropicFiltering != (int) value) { + } + case ANISOTROPIC_FILTERING -> { + if (anisotropicFiltering != (int) value) { anisotropicFiltering = (int) value; mc.getTextureMapBlocks().setAnisotropicFiltering(this.anisotropicFiltering); mc.scheduleResourcesRefresh(); } - break; - case MIPMAP_LEVELS: - if(mipmapLevels != (int) value) { + } + case MIPMAP_LEVELS -> { + if (mipmapLevels != (int) value) { mipmapLevels = (int) value; mc.getTextureMapBlocks().setMipmapLevels(this.mipmapLevels); mc.scheduleResourcesRefresh(); } - break; - case RENDER_DISTANCE: - renderDistanceChunks = (int) value; - break; - case STREAM_BYTES_PER_PIXEL: - field_152400_J = value; - break; - case STREAM_VOLUME_MIC: + } + case RENDER_DISTANCE -> renderDistanceChunks = (int) value; + case STREAM_BYTES_PER_PIXEL -> field_152400_J = value; + case STREAM_VOLUME_MIC -> { field_152401_K = value; mc.func_152346_Z().func_152915_s(); - break; - case STREAM_VOLUME_SYSTEM: + } + case STREAM_VOLUME_SYSTEM -> { field_152402_L = value; mc.func_152346_Z().func_152915_s(); - break; - case STREAM_KBPS: - field_152403_M = value; - break; - case STREAM_FPS: - field_152404_N = value; - break; - default: - break; + } + case STREAM_KBPS -> field_152403_M = value; + case STREAM_FPS -> field_152404_N = value; } } @@ -196,14 +178,13 @@ public void setOptionValue(GameSettings.Options option, int value) { enableVsync = !enableVsync; Display.setVSyncEnabled(enableVsync); break; - default: - break; } saveOptions(); } @Shadow - public void saveOptions() {} + public void saveOptions() { + } @Shadow protected Minecraft mc; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinEntityRenderer.java index acfeeee91..6ec1b85ba 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinEntityRenderer.java @@ -1,11 +1,13 @@ package com.gtnewhorizons.angelica.mixins.early.notfine.toggle; import jss.notfine.core.SettingsManager; + import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.settings.GameSettings; import org.spongepowered.asm.lib.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(EntityRenderer.class) @@ -24,4 +26,25 @@ abstract public class MixinEntityRenderer { return SettingsManager.waterDetail; } + @Redirect( + method = "renderRainSnow(F)V", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", + opcode = Opcodes.GETFIELD + ) + ) + private boolean notFine$bypassWeatherMode(GameSettings settings) { + return false; + } + + @ModifyVariable( + method = "renderRainSnow(F)V", + at = @At("STORE"), + ordinal = 0 + ) + private byte notFine$weatherDistance(byte distance) { + return SettingsManager.downfallDistance; + } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRender.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRender.java index 7ac1a7e0d..de551a3a1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRender.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRender.java @@ -16,9 +16,9 @@ public abstract class MixinRender { at = @At( value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", - opcode = Opcodes.GETFIELD - ), - allow = 1 + opcode = Opcodes.GETFIELD, + ordinal = 0 + ) ) private boolean notFine$toggleEntityShadows(GameSettings settings) { return SettingsManager.shadows; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRenderItem.java index 67311d331..7927253e0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/toggle/MixinRenderItem.java @@ -13,8 +13,12 @@ abstract public class MixinRenderItem { @Redirect( method = "renderDroppedItem(Lnet/minecraft/entity/item/EntityItem;Lnet/minecraft/util/IIcon;IFFFFI)V", - at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", opcode = Opcodes.GETFIELD), - allow = 1, expect = 0 + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", + opcode = Opcodes.GETFIELD + ), + allow = 1 ) private boolean notFine$toggleDroppedItemDetail(GameSettings settings) { return SettingsManager.droppedItemDetail; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java index 6a7427e2d..8cf7ad6f4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java @@ -4,9 +4,9 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; import jss.notfine.util.LeafRenderUtil; -import jss.util.DirectionHelper; import net.minecraft.block.Block; import net.minecraft.block.material.Material; +import net.minecraft.util.Facing; import net.minecraft.util.IIcon; import net.minecraft.world.IBlockAccess; import org.spongepowered.asm.mixin.Mixin; @@ -21,21 +21,15 @@ public abstract class MixinBlockMagicalLeaves extends Block implements ILeafBloc public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { int renderMode = (int) Settings.MODE_LEAVES.getValue(); int maskedMeta = world.getBlockMetadata(x, y, z) & 3; - switch(renderMode) { - case -1: - renderMode = SettingsManager.leavesOpaque ? 1 : 0; - break; - case 4: - renderMode = world.getBlock( - x + DirectionHelper.xDirectionalIncrease[side], - y + DirectionHelper.yDirectionalIncrease[side], - z + DirectionHelper.zDirectionalIncrease[side] - ) instanceof ILeafBlock ? 1 : 0; - break; - default: - renderMode = renderMode > 1 ? 0 : renderMode; - break; - } + renderMode = switch (renderMode) { + case -1 -> SettingsManager.leavesOpaque ? 1 : 0; + case 4 -> world.getBlock( + x + Facing.offsetsXForSide[side], + y + Facing.offsetsYForSide[side], + z + Facing.offsetsZForSide[side] + ) instanceof ILeafBlock ? 1 : 0; + default -> renderMode > 1 ? 0 : renderMode; + }; maskedMeta = maskedMeta > 1 ? 0 : maskedMeta; return icon[renderMode + maskedMeta * 2]; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves.java index 23ea06ae5..29673e275 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves.java @@ -3,9 +3,9 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; import jss.notfine.util.ILeafBlock; -import jss.util.DirectionHelper; import net.minecraft.block.BlockLeaves; import net.minecraft.init.Blocks; +import net.minecraft.util.Facing; import net.minecraft.util.IIcon; import net.minecraft.world.IBlockAccess; import org.spongepowered.asm.mixin.Mixin; @@ -21,9 +21,10 @@ public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { renderMode = switch (renderMode) { case -1 -> SettingsManager.leavesOpaque ? 1 : 0; case 4 -> world.getBlock( - x + DirectionHelper.xDirectionalIncrease[side], - y + DirectionHelper.yDirectionalIncrease[side], - z + DirectionHelper.zDirectionalIncrease[side]) instanceof ILeafBlock ? 1 : 0; + x + Facing.offsetsXForSide[side], + y + Facing.offsetsYForSide[side], + z + Facing.offsetsZForSide[side] + ) instanceof ILeafBlock ? 1 : 0; default -> renderMode > 1 ? 0 : renderMode; }; maskedMeta = maskedMeta > 1 ? 0 : maskedMeta; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves3.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves3.java index b96587565..42a2b7610 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves3.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves3.java @@ -3,9 +3,9 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; import jss.notfine.util.ILeafBlock; -import jss.util.DirectionHelper; import net.minecraft.block.BlockLeaves; import net.minecraft.init.Blocks; +import net.minecraft.util.Facing; import net.minecraft.util.IIcon; import net.minecraft.world.IBlockAccess; import org.spongepowered.asm.mixin.Mixin; @@ -20,9 +20,10 @@ public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { renderMode = switch (renderMode) { case -1 -> SettingsManager.leavesOpaque ? 1 : 0; case 4 -> world.getBlock( - x + DirectionHelper.xDirectionalIncrease[side], - y + DirectionHelper.yDirectionalIncrease[side], - z + DirectionHelper.zDirectionalIncrease[side]) instanceof ILeafBlock ? 1 : 0; + x + Facing.offsetsXForSide[side], + y + Facing.offsetsYForSide[side], + z + Facing.offsetsZForSide[side] + ) instanceof ILeafBlock ? 1 : 0; default -> renderMode > 1 ? 0 : renderMode; }; return Blocks.leaves.field_150129_M[renderMode][0]; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFMagicLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFMagicLeaves.java index 7e41b8f27..fe50c78d0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFMagicLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFMagicLeaves.java @@ -3,8 +3,8 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; import jss.notfine.util.ILeafBlock; -import jss.util.DirectionHelper; import net.minecraft.block.BlockLeaves; +import net.minecraft.util.Facing; import net.minecraft.util.IIcon; import net.minecraft.world.IBlockAccess; import org.spongepowered.asm.mixin.Mixin; @@ -20,16 +20,17 @@ public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { renderMode = switch (renderMode) { case -1 -> SettingsManager.leavesOpaque ? 1 : 0; case 4 -> world.getBlock( - x + DirectionHelper.xDirectionalIncrease[side], - y + DirectionHelper.yDirectionalIncrease[side], - z + DirectionHelper.zDirectionalIncrease[side]) instanceof ILeafBlock ? 1 : 0; + x + Facing.offsetsXForSide[side], + y + Facing.offsetsYForSide[side], + z + Facing.offsetsZForSide[side] + ) instanceof ILeafBlock ? 1 : 0; default -> renderMode > 1 ? 0 : renderMode; }; maskedMeta = maskedMeta > 1 ? 0 : maskedMeta; return switch (maskedMeta) { - default -> renderMode == 1 ? SPR_TIMELEAVES_OPAQUE : SPR_TIMELEAVES; case 1 -> renderMode == 1 ? SPR_TRANSLEAVES_OPAQUE : SPR_TRANSLEAVES; case 3 -> renderMode == 1 ? SPR_SORTLEAVES_OPAQUE : SPR_SORTLEAVES; + default -> renderMode == 1 ? SPR_TIMELEAVES_OPAQUE : SPR_TIMELEAVES; }; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java index 213ab7509..a491ac783 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java @@ -4,9 +4,9 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; import jss.notfine.util.ILeafBlock; -import jss.util.DirectionHelper; import net.minecraft.block.BlockLeavesBase; import net.minecraft.block.material.Material; +import net.minecraft.util.Facing; import net.minecraft.util.IIcon; import net.minecraft.world.IBlockAccess; import org.spongepowered.asm.mixin.Mixin; @@ -32,9 +32,10 @@ public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { renderMode = switch (renderMode) { case -1 -> SettingsManager.leavesOpaque ? 1 : 0; case 4 -> world.getBlock( - x + DirectionHelper.xDirectionalIncrease[side], - y + DirectionHelper.yDirectionalIncrease[side], - z + DirectionHelper.zDirectionalIncrease[side]) instanceof ILeafBlock ? 1 : 0; + x + Facing.offsetsXForSide[side], + y + Facing.offsetsYForSide[side], + z + Facing.offsetsZForSide[side] + ) instanceof ILeafBlock ? 1 : 0; default -> renderMode > 1 ? 0 : renderMode; }; maskedMeta = maskedMeta > 1 ? 0 : maskedMeta; diff --git a/src/main/java/jss/notfine/core/LoadMenuButtons.java b/src/main/java/jss/notfine/core/LoadMenuButtons.java index 5e9ef395e..032c713d8 100644 --- a/src/main/java/jss/notfine/core/LoadMenuButtons.java +++ b/src/main/java/jss/notfine/core/LoadMenuButtons.java @@ -17,11 +17,10 @@ public class LoadMenuButtons { //@SubscribeEvent(priority = EventPriority.LOWEST) public void onGui(InitGuiEvent.Post event) { if(event.gui instanceof GuiOptions) { - // Hide the vanilla video settings button GuiButton videoSettings = ((List)event.buttonList).stream().filter(button -> button.id == 101).findFirst().get(); + //Hide vanilla video settings button videoSettings.visible = false; - - // and add the custom one + //Add new video settings button event.buttonList.add( new GuiCustomMenuButton( videoSettings.xPosition, videoSettings.yPosition, diff --git a/src/main/java/jss/notfine/core/Settings.java b/src/main/java/jss/notfine/core/Settings.java index 36106a7e9..1e93c9a20 100644 --- a/src/main/java/jss/notfine/core/Settings.java +++ b/src/main/java/jss/notfine/core/Settings.java @@ -13,6 +13,12 @@ public void updateSetting() { } }, CLOUD_SCALE(true, 1f, 0.5f, 5f, 0.25f), + DOWNFALL_DISTANCE(false, -1f, -1f, 3f, 1f, "-1:Default, 0:Fancy, 1:Fast, 2:Ultra, 2:Off") { + @Override + public void updateSetting() { + SettingsManager.downfallDistanceUpdated(); + } + }, FOG_DEPTH(false,0f, 0f, 1f, 1f, "0:On, 1:Off"), GUI_BACKGROUND(false, -1f, -1f, 5f, 1f, "-1:Default, 0:Sand, 1:Mycelium, 2:Stonebrick, 3:Mossy Stonebrick, 4:Oak Planks, 5: Birch Planks") { @Override @@ -26,7 +32,7 @@ public void updateSetting() { SettingsManager.cloudsUpdated(); } }, - MODE_CLOUDS(false,-1f, -1f, 2f, 1f, "-1:Default, 0:Fancy, 1:Fast, 2:Off") { + MODE_CLOUDS(false, -1f, -1f, 2f, 1f, "-1:Default, 0:Fancy, 1:Fast, 2:Off") { @Override public void updateSetting() { SettingsManager.cloudsUpdated(); @@ -38,10 +44,10 @@ public void updateSetting() { SettingsManager.droppedItemDetailUpdated(); } }, - MODE_GLINT_INV(false,0f, 0f, 1f, 1f, "0:On, 1:Off"), - MODE_GLINT_WORLD(false,0f, 0f, 1f, 1f, "0:On, 1:Off"), + MODE_GLINT_INV(false, 0f, 0f, 1f, 1f, "0:On, 1:Off"), + MODE_GLINT_WORLD(false, 0f, 0f, 1f, 1f, "0:On, 1:Off"), MODE_GUI_BACKGROUND(false, 0f, 0f, 1f, 1f, "0:On, 1:Off"), - MODE_LEAVES(false,-1f, -1f, 4f,1f,"-1:Default, 0:Fancy, 1:Fast, 2: Smart, 3:Hybrid Fancy, 3:Hybrid Fast") { + MODE_LEAVES(false,-1f, -1f, 4f,1f,"-1:Default, 0:Fancy, 1:Fast, 2:Smart, 3:Hybrid Fancy, 4:Hybrid Fast") { @Override public void updateSetting() { SettingsManager.leavesUpdated(); @@ -66,8 +72,8 @@ public void updateSetting() { SettingsManager.vignetteUpdated(); } }, - PARTICLES_ENC_TABLE(true,1f, 0f, 16f, 1f), - PARTICLES_VOID(false,0f, 0f, 1f, 1f, "0:On, 1:Off"), + PARTICLES_ENC_TABLE(true, 1f, 0f, 16f, 1f), + PARTICLES_VOID(false, 0f, 0f, 1f, 1f, "0:On, 1:Off"), RENDER_DISTANCE_CLOUDS(true, 4f, 4f, 64f, 2f) { @Override public void updateSetting() { @@ -86,6 +92,7 @@ public void updateSetting() { SettingsManager.entityRenderDistanceUpdated(); } }; + public final boolean slider; public final float base; public final float minimum; @@ -113,10 +120,8 @@ public void setValue(float value) { if(step > 0f) { value = step * (float)Math.round(value / step); } - if(this.value != value) { - this.value = value; - updateSetting(); - } + this.value = value; + updateSetting(); } public void setValueNormalized(float value) { diff --git a/src/main/java/jss/notfine/core/SettingsManager.java b/src/main/java/jss/notfine/core/SettingsManager.java index b85419e60..86cd0b276 100644 --- a/src/main/java/jss/notfine/core/SettingsManager.java +++ b/src/main/java/jss/notfine/core/SettingsManager.java @@ -24,6 +24,7 @@ public class SettingsManager { public static boolean leavesOpaque; public static boolean waterDetail; public static boolean vignette; + public static byte downfallDistance; public static double entityRenderScaleFactor; public static ResourceLocation defaultBackground = Gui.optionsBackground; @@ -67,6 +68,26 @@ public static void cloudsUpdated() { } } + public static void downfallDistanceUpdated() { + switch((int)Settings.DOWNFALL_DISTANCE.getValue()) { + case -1: + downfallDistance = (byte)(mc.gameSettings.fancyGraphics ? 10 : 5); + break; + case 0: + downfallDistance = (byte)5; + break; + case 1: + downfallDistance = (byte)10; + break; + case 2: + downfallDistance = (byte)15; + break; + case 3: + downfallDistance = (byte)0; + break; + } + } + public static void leavesUpdated() { mc.renderGlobal.loadRenderers(); leavesOpaque = Settings.MODE_LEAVES.getValue() == 1 || (Settings.MODE_LEAVES.getValue() == -1 && !mc.gameSettings.fancyGraphics); @@ -135,6 +156,7 @@ public static void entityRenderDistanceUpdated() { } public static void graphicsUpdated() { + downfallDistanceUpdated(); leavesUpdated(); shadowsUpdated(); droppedItemDetailUpdated(); diff --git a/src/main/java/jss/notfine/gui/GuiCustomMenuButton.java b/src/main/java/jss/notfine/gui/GuiCustomMenuButton.java index 72eba0319..71d59a52d 100644 --- a/src/main/java/jss/notfine/gui/GuiCustomMenuButton.java +++ b/src/main/java/jss/notfine/gui/GuiCustomMenuButton.java @@ -2,7 +2,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.resources.I18n; public class GuiCustomMenuButton extends GuiButton { diff --git a/src/main/java/jss/notfine/gui/MenuButtonLists.java b/src/main/java/jss/notfine/gui/MenuButtonLists.java index b1003b880..6a47f33e0 100644 --- a/src/main/java/jss/notfine/gui/MenuButtonLists.java +++ b/src/main/java/jss/notfine/gui/MenuButtonLists.java @@ -1,6 +1,5 @@ package jss.notfine.gui; -import cpw.mods.fml.common.Loader; import jss.notfine.config.NotFineConfig; import jss.notfine.core.Settings; import net.minecraft.client.renderer.OpenGlHelper; @@ -11,8 +10,6 @@ import java.util.HashMap; import java.util.List; -import static com.gtnewhorizons.angelica.client.gui.AngelicaVideoSettings.SHADERS; - public enum MenuButtonLists implements ISettingsEnum { VIDEO("options.video") { @Override @@ -38,9 +35,9 @@ public List> entries() { ArrayList> list = new ArrayList<>(); list.add(Settings.MODE_LEAVES); list.add(Settings.MODE_WATER); - list.add(Settings.MODE_SHADOWS); list.add(Settings.MODE_VIGNETTE); - list.add(Settings.MODE_DROPPED_ITEMS); list.add(Settings.MODE_GLINT_WORLD); - list.add(Settings.MODE_GLINT_INV); + list.add(Settings.DOWNFALL_DISTANCE); list.add(Settings.MODE_VIGNETTE); + list.add(Settings.MODE_SHADOWS); list.add(Settings.MODE_DROPPED_ITEMS); + list.add(Settings.MODE_GLINT_WORLD); list.add(Settings.MODE_GLINT_INV); return list; } diff --git a/src/main/java/jss/notfine/util/IFaceObstructionCheckHelper.java b/src/main/java/jss/notfine/util/IFaceObstructionCheckHelper.java new file mode 100644 index 000000000..78b488385 --- /dev/null +++ b/src/main/java/jss/notfine/util/IFaceObstructionCheckHelper.java @@ -0,0 +1,9 @@ +package jss.notfine.util; + +import net.minecraft.world.IBlockAccess; + +public interface IFaceObstructionCheckHelper { + + boolean isFaceNonObstructing(IBlockAccess worldIn, int x, int y, int z, int side, double otherMinX, double otherMinY, double otherMinZ, double otherMaxX, double otherMaxY, double otherMaxZ); + +} diff --git a/src/main/java/jss/notfine/util/ILeafBlock.java b/src/main/java/jss/notfine/util/ILeafBlock.java index d946f84e9..ad8561fc9 100644 --- a/src/main/java/jss/notfine/util/ILeafBlock.java +++ b/src/main/java/jss/notfine/util/ILeafBlock.java @@ -1,5 +1,44 @@ package jss.notfine.util; -public interface ILeafBlock { +import jss.notfine.core.Settings; +import jss.notfine.core.SettingsManager; +import net.minecraft.block.Block; +import net.minecraft.world.IBlockAccess; + +public interface ILeafBlock extends IFaceObstructionCheckHelper { + + @Override() + default boolean isFaceNonObstructing(IBlockAccess worldIn, int x, int y, int z, int side, double otherMinX, double otherMinY, double otherMinZ, double otherMaxX, double otherMaxY, double otherMaxZ) { + if((int) Settings.MODE_LEAVES.getValue() == 4) { + Block otherBlock; + otherBlock = worldIn.getBlock(x + 1, y, z); + if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { + return true; + } + otherBlock = worldIn.getBlock(x - 1, y, z); + if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { + return true; + } + otherBlock = worldIn.getBlock(x, y + 1, z); + if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { + return true; + } + otherBlock = worldIn.getBlock(x, y - 1, z); + if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { + return true; + } + otherBlock = worldIn.getBlock(x, y, z + 1); + if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { + return true; + } + otherBlock = worldIn.getBlock(x, y, z - 1); + if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { + return true; + } + return false; + } else { + return !SettingsManager.leavesOpaque; + } + } } diff --git a/src/main/java/jss/notfine/util/LeafRenderUtil.java b/src/main/java/jss/notfine/util/LeafRenderUtil.java index 82ebb00ab..20d560c4b 100644 --- a/src/main/java/jss/notfine/util/LeafRenderUtil.java +++ b/src/main/java/jss/notfine/util/LeafRenderUtil.java @@ -2,106 +2,128 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; -import jss.util.DirectionHelper; import net.minecraft.block.Block; +import net.minecraft.util.Facing; import net.minecraft.world.IBlockAccess; public class LeafRenderUtil { - public static boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int side) { - Block otherBlock = world.getBlock(x, y, z); + public static final int[] relativeADirections = { + 2, 3, 4, 5, 0, 1 + }; + + public static final int[] relativeBDirections = { + 3, 2, 5, 4, 1, 0 + }; + + public static final int[] relativeCDirections = { + 4, 5, 0, 1, 2, 3 + }; + + public static final int[] relativeDDirections = { + 5, 4, 1, 0, 3, 2 + }; + + public static boolean shouldSideBeRendered(IBlockAccess worldIn, int x, int y, int z, int side) { + Block otherBlock = worldIn.getBlock(x, y, z); if(otherBlock.isOpaqueCube()) { return false; } - switch((int)Settings.MODE_LEAVES.getValue()) { - case 1: - case 2: - return !(otherBlock instanceof ILeafBlock); - case 3: - case 4: - if(otherBlock instanceof ILeafBlock) { - x -= DirectionHelper.xDirectionalIncrease[side]; - y -= DirectionHelper.yDirectionalIncrease[side]; - z -= DirectionHelper.zDirectionalIncrease[side]; + if(otherBlock instanceof ILeafBlock) { + switch ((int) Settings.MODE_LEAVES.getValue()) { + case 1, 2 -> { + return false; + } + case 3, 4 -> { + x -= Facing.offsetsXForSide[side]; + y -= Facing.offsetsYForSide[side]; + z -= Facing.offsetsZForSide[side]; int renderCheck = 0; - otherBlock = world.getBlock(x + 1, y, z); - if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + otherBlock = worldIn.getBlock(x + 1, y, z); + if(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube()) { renderCheck++; } - otherBlock = world.getBlock(x - 1, y, z); - if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + otherBlock = worldIn.getBlock(x - 1, y, z); + if(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube()) { renderCheck++; } - otherBlock = world.getBlock(x, y + 1, z); - if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + otherBlock = worldIn.getBlock(x, y + 1, z); + if(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube()) { renderCheck++; } - otherBlock = world.getBlock(x, y - 1, z); - if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + otherBlock = worldIn.getBlock(x, y - 1, z); + if(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube()) { renderCheck++; } - otherBlock = world.getBlock(x, y, z + 1); - if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + otherBlock = worldIn.getBlock(x, y, z + 1); + if(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube()) { renderCheck++; } - otherBlock = world.getBlock(x, y, z - 1); - if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + otherBlock = worldIn.getBlock(x, y, z - 1); + if(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube()) { renderCheck++; } boolean renderSide = renderCheck == 6; - if(renderSide) { - x += 2 * DirectionHelper.xDirectionalIncrease[side]; - y += 2 * DirectionHelper.yDirectionalIncrease[side]; - z += 2 * DirectionHelper.zDirectionalIncrease[side]; - otherBlock = world.getBlock(x, y, z); - if(((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { + if (renderSide) { + x += 2 * Facing.offsetsXForSide[side]; + y += 2 * Facing.offsetsYForSide[side]; + z += 2 * Facing.offsetsZForSide[side]; + otherBlock = worldIn.getBlock(x, y, z); + if(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube()) { renderSide = false; } - x -= DirectionHelper.xDirectionalIncrease[side]; - y -= DirectionHelper.yDirectionalIncrease[side]; - z -= DirectionHelper.zDirectionalIncrease[side]; - int nextSide = DirectionHelper.relativeADirections[side]; - otherBlock = world.getBlock( - x + DirectionHelper.xDirectionalIncrease[nextSide], - y + DirectionHelper.yDirectionalIncrease[nextSide], - z + DirectionHelper.zDirectionalIncrease[nextSide] + x -= Facing.offsetsXForSide[side]; + y -= Facing.offsetsYForSide[side]; + z -= Facing.offsetsZForSide[side]; + int nextSide = relativeADirections[side]; + otherBlock = worldIn.getBlock( + x + Facing.offsetsXForSide[nextSide], + y + Facing.offsetsYForSide[nextSide], + z + Facing.offsetsZForSide[nextSide] ); - if(!((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { - renderSide = true; + if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { + return true; } - nextSide = DirectionHelper.relativeBDirections[side]; - otherBlock = world.getBlock( - x + DirectionHelper.xDirectionalIncrease[nextSide], - y + DirectionHelper.yDirectionalIncrease[nextSide], - z + DirectionHelper.zDirectionalIncrease[nextSide] + nextSide = relativeBDirections[side]; + otherBlock = worldIn.getBlock( + x + Facing.offsetsXForSide[nextSide], + y + Facing.offsetsYForSide[nextSide], + z + Facing.offsetsZForSide[nextSide] ); - if(!((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { - renderSide = true; + if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { + return true; } - nextSide = DirectionHelper.relativeCDirections[side]; - otherBlock = world.getBlock( - x + DirectionHelper.xDirectionalIncrease[nextSide], - y + DirectionHelper.yDirectionalIncrease[nextSide], - z + DirectionHelper.zDirectionalIncrease[nextSide] + nextSide = relativeCDirections[side]; + otherBlock = worldIn.getBlock( + x + Facing.offsetsXForSide[nextSide], + y + Facing.offsetsYForSide[nextSide], + z + Facing.offsetsZForSide[nextSide] ); - if(!((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { - renderSide = true; + if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { + return true; } - nextSide = DirectionHelper.relativeDDirections[side]; - otherBlock = world.getBlock( - x + DirectionHelper.xDirectionalIncrease[nextSide], - y + DirectionHelper.yDirectionalIncrease[nextSide], - z + DirectionHelper.zDirectionalIncrease[nextSide] + nextSide = relativeDDirections[side]; + otherBlock = worldIn.getBlock( + x + Facing.offsetsXForSide[nextSide], + y + Facing.offsetsYForSide[nextSide], + z + Facing.offsetsZForSide[nextSide] ); - if(!((otherBlock instanceof ILeafBlock) || otherBlock.isOpaqueCube())) { - renderSide = true; + if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { + return true; } } return renderSide; } - default: - return !SettingsManager.leavesOpaque || !(otherBlock instanceof ILeafBlock); + default -> { + return !SettingsManager.leavesOpaque; + } + } + } + //Check for IFaceObstructionCheckHelper + if(otherBlock instanceof IFaceObstructionCheckHelper target) { + return target.isFaceNonObstructing(worldIn, x, y, z, side, 0D, 0D, 0D, 1D, 1D, 1D); } + return true; } } diff --git a/src/main/java/jss/util/DirectionHelper.java b/src/main/java/jss/util/DirectionHelper.java deleted file mode 100644 index c051e931a..000000000 --- a/src/main/java/jss/util/DirectionHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -package jss.util; - -public class DirectionHelper { - - public static final int[] orderedDirections = { - 0, 1, 2, 3, 4, 5 - }; - - public static final int[] oppositeDirections = { - 1, 0, 3, 2, 5, 4 - }; - - public static final int[] yDirectionalIncrease = { - -1, 1, -0, 0, -0, 0 - }; - - public static final int[] zDirectionalIncrease = { - -0, 0, -1, 1, -0, 0 - }; - - public static final int[] xDirectionalIncrease = { - -0, 0, -0, 0, -1, 1 - }; - - public static final int[] relativeADirections = { - 2, 3, 4, 5, 0, 1 - }; - - public static final int[] relativeBDirections = { - 3, 2, 5, 4, 1, 0 - }; - - public static final int[] relativeCDirections = { - 4, 5, 0, 1, 2, 3 - }; - - public static final int[] relativeDDirections = { - 5, 4, 1, 0, 3, 2 - }; - -} From 395afdee60fed790bac9a850038b44bd069d273e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 25 Nov 2023 10:52:36 -0500 Subject: [PATCH 127/301] Make LongHashMap actually perform like a hash map --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../mixins/early/sodium/MixinLongHashMap.java | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinLongHashMap.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 7ab1b02c4..0339e393a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -50,6 +50,7 @@ public enum Mixins { ,"sodium.MixinTessellator" ,"sodium.MixinWorldClient" ,"sodium.MixinGuiIngameForge" + ,"sodium.MixinLongHashMap" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinLongHashMap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinLongHashMap.java new file mode 100644 index 000000000..136bd27ff --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinLongHashMap.java @@ -0,0 +1,17 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import net.minecraft.util.LongHashMap; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(LongHashMap.class) +public class MixinLongHashMap { + /** + * @author TheMasterCaver, embeddedt (mixin version) + * @reason Use a better hash (from TMCW) that avoids collisions. + */ + @Overwrite + private static int getHashedKey(long par0) { + return (int)par0 + (int)(par0 >>> 32) * 92821; + } +} From ef7839ed84877ef1bb5a28c6db1301d5ed905409 Mon Sep 17 00:00:00 2001 From: Bogdan <64613894+Asek3@users.noreply.github.com> Date: Sat, 25 Nov 2023 19:13:56 +0200 Subject: [PATCH 128/301] Options GUI Fixes and some option implementations (#22) * Correct useNoErrorGLContext option * Added translucency sorting option * Implemented Particle Culling gives real fps boost, however, it's not as big as i thought * Begin implementing animateOnlyVisibleTextures * Correct Donation page opening * Fixed Shift + P Now it uses NotFine's GUI, but it think that NotFine's GUI should be rewrited for using other config options * Added Shaders button * Correct URL's for Linux * second code cleanup in particle culling --- .../angelica/config/AngelicaConfig.java | 3 - .../gtnewhorizons/angelica/mixins/Mixins.java | 6 +- .../mixins/early/angelica/MixinMinecraft.java | 17 ---- .../early/sodium/MixinEffectRenderer.java | 59 ++++++++++++++ .../mixins/early/sodium/MixinEntityFX.java | 35 ++++++++ .../mixins/early/sodium/MixinMinecraft.java | 8 ++ .../early/sodium/MixinTextureAtlasSprite.java | 79 +++++++++++++++++++ .../mixins/early/sodium/MixinTextureMap.java | 24 ++++++ .../client/gui/SodiumGameOptionPages.java | 23 ++++-- .../sodium/client/gui/SodiumGameOptions.java | 1 + .../sodium/client/gui/SodiumOptionsGUI.java | 35 ++++---- .../sodium/client/gui/utils/URLUtils.java | 27 +++++++ 12 files changed, 273 insertions(+), 44 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinMinecraft.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEffectRenderer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityFX.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTextureAtlasSprite.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTextureMap.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/utils/URLUtils.java diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index e64da07ba..6899eab5d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -4,9 +4,6 @@ @Config(modid = "angelica") public class AngelicaConfig { - @Config.Comment("Disable Minecraft's check for OpenGL errors. Minor speedup.") - @Config.DefaultBoolean(true) - public static boolean disableMinecraftCheckGLErrors; @Config.Comment("Enable Sodium rendering") @Config.DefaultBoolean(true) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 0339e393a..1e77d976f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -14,7 +14,6 @@ public enum Mixins { ANGELICA(new Builder("Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( "angelica.MixinEntityRenderer" - ,"angelica.MixinMinecraft" ) ), IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) @@ -50,6 +49,11 @@ public enum Mixins { ,"sodium.MixinTessellator" ,"sodium.MixinWorldClient" ,"sodium.MixinGuiIngameForge" + ,"sodium.MixinEffectRenderer" + // TODO Doesn't work correctly + //,"sodium.MixinTextureAtlasSprite" + //,"sodium.MixinTextureMap" + //,"sodium.MixinEntityFX" ,"sodium.MixinLongHashMap" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinMinecraft.java deleted file mode 100644 index 068d75be1..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinMinecraft.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.angelica; - -import com.gtnewhorizons.angelica.config.AngelicaConfig; -import net.minecraft.client.Minecraft; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(Minecraft.class) -public class MixinMinecraft { - @Inject(method = "checkGLError", at = @At(value = "HEAD"), cancellable = true) - private void angelica$checkGLError(CallbackInfo ci) { - if(AngelicaConfig.disableMinecraftCheckGLErrors) - ci.cancel(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEffectRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEffectRenderer.java new file mode 100644 index 000000000..78859e1ef --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEffectRenderer.java @@ -0,0 +1,59 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; +import net.minecraft.client.particle.EffectRenderer; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.culling.Frustrum; +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EffectRenderer.class) +public class MixinEffectRenderer { + + @Unique + private Frustrum cullingFrustum; + + @Unique + private void setupCullingFrustum() { + Frustrum frustum = SodiumWorldRenderer.getInstance().getFrustum(); + boolean useCulling = SodiumClientMod.options().advanced.useParticleCulling; + // Setup the frustum state before rendering particles + if (useCulling && frustum != null) { + this.cullingFrustum = frustum; + } else { + this.cullingFrustum = null; + } + } + + @Inject(method = "renderParticles", at = @At("HEAD")) + private void setupFrustum$standart(Entity player, float partialTickTime, CallbackInfo ci) { + setupCullingFrustum(); + } + + @Redirect(method = "renderParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/Tessellator;FFFFFF)V")) + private void renderParticles(EntityFX particle, Tessellator tessellator, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + if(cullingFrustum == null || cullingFrustum.isBoundingBoxInFrustum(particle.boundingBox)) { + particle.renderParticle(tessellator, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); + } + } + + @Inject(method = "renderLitParticles", at = @At("HEAD")) + private void setupFrustum$lit(Entity player, float partialTickTime, CallbackInfo ci) { + setupCullingFrustum(); + } + + @Redirect(method = "renderLitParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/Tessellator;FFFFFF)V")) + private void renderLitParticles(EntityFX particle, Tessellator tessellator, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + if(cullingFrustum == null || cullingFrustum.isBoundingBoxInFrustum(particle.boundingBox)) { + particle.renderParticle(tessellator, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); + } + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityFX.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityFX.java new file mode 100644 index 000000000..6926b8273 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityFX.java @@ -0,0 +1,35 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.client.textures.ISpriteExt; +import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.IIcon; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityFX.class) +public class MixinEntityFX { + + @Shadow + protected IIcon particleIcon; + + private boolean shouldTickSprite; + + @Inject(method = "setParticleIcon", at = @At("RETURN")) + public void afterSetSprite(IIcon icon, CallbackInfo ci) { + this.shouldTickSprite = icon instanceof ISpriteExt atlasSprite && atlasSprite.isAnimation(); + } + + @Inject(method = "renderParticle", at = @At("HEAD")) + public void renderParticle(Tessellator tessellator, float offset, float x, float y, float z, float u, float v, CallbackInfo ci) { + if (this.shouldTickSprite && this.particleIcon instanceof TextureAtlasSprite atlasSprite) { + SpriteUtil.markSpriteActive(atlasSprite); + } + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java index b4087f17a..a1cfbc827 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java @@ -1,6 +1,8 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; +import me.jellysquid.mods.sodium.client.SodiumClientMod; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderGlobal; import org.spongepowered.asm.mixin.Mixin; @@ -26,4 +28,10 @@ public class MixinMinecraft { private int sodium$chunksUpdated() { return ((IRenderGlobalExt)this.renderGlobal).getChunksSubmitted(); } + + @Inject(method = "checkGLError", at = @At(value = "HEAD"), cancellable = true) + private void sodium$checkGLError(CallbackInfo ci) { + if(SodiumClientMod.options().performance.useNoErrorGLContext) + ci.cancel(); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTextureAtlasSprite.java new file mode 100644 index 000000000..a6e6550ec --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTextureAtlasSprite.java @@ -0,0 +1,79 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.render.texture.SpriteExtended; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureUtil; +import net.minecraft.client.resources.data.AnimationMetadataSection; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.List; + +@Mixin(TextureAtlasSprite.class) +public class MixinTextureAtlasSprite implements SpriteExtended { + private boolean forceNextUpdate; + + @Shadow + protected List framesTextureData; + + @Shadow + private AnimationMetadataSection animationMetadata; + + @Shadow + protected int originX; + + @Shadow + protected int originY; + + @Shadow + protected int width; + + @Shadow + protected int height; + + @Shadow + protected int frameCounter; + + @Shadow + protected int tickCounter; + + /** + * @author JellySquid & Asek3 + * @reason To optimal solution it's better to overwrite + */ + @Overwrite + public void updateAnimation() { + ++this.tickCounter; + + boolean onDemand = SodiumClientMod.options().advanced.animateOnlyVisibleTextures; + + if (!onDemand || this.forceNextUpdate) { + this.uploadTexture(); + } + } + + private void uploadTexture() { + if (this.tickCounter >= this.animationMetadata.getFrameTimeSingle(this.frameCounter)) { + int prevFrameIndex = this.animationMetadata.getFrameIndex(this.frameCounter); + int frameCount = this.animationMetadata.getFrameCount() == 0 ? this.framesTextureData.size() : this.animationMetadata.getFrameCount(); + + this.frameCounter = (this.frameCounter + 1) % frameCount; + this.tickCounter = 0; + + int frameIndex = this.animationMetadata.getFrameIndex(this.frameCounter); + + if (prevFrameIndex != frameIndex && frameIndex >= 0 && frameIndex < this.framesTextureData.size()) { + TextureUtil.uploadTextureMipmap(this.framesTextureData.get(frameIndex), this.width, this.height, this.originX, this.originY, false, false); + } + } + + this.forceNextUpdate = false; + } + + @Override + public void markActive() { + this.forceNextUpdate = true; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTextureMap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTextureMap.java new file mode 100644 index 000000000..f23aa5606 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTextureMap.java @@ -0,0 +1,24 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(TextureMap.class) +public class MixinTextureMap { + + @Inject(method = "getAtlasSprite", at = @At("RETURN")) + private void preReturnSprite(CallbackInfoReturnable cir) { + TextureAtlasSprite sprite = cir.getReturnValue(); + + if (sprite != null) { + SpriteUtil.markSpriteActive(sprite); + } + } + + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index 7d659bcb8..be1223f3e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -156,7 +156,7 @@ public static OptionPage quality() { .setTooltip(I18n.format("sodium.options.particle_quality.tooltip")) .setControl(opt -> new CyclingControl<>(opt, SodiumGameOptions.ParticleMode.class)) .setBinding((opts, value) -> opts.particleSetting = value.ordinal(), (opts) -> SodiumGameOptions.ParticleMode.fromOrdinal(opts.particleSetting)) - .setImpact(OptionImpact.MEDIUM) + .setImpact(OptionImpact.LOW) .build()) .add(OptionImpl.createBuilder(SodiumGameOptions.LightingQuality.class, vanillaOpts) .setName(I18n.format("options.ao")) @@ -266,6 +266,15 @@ public static OptionPage advanced() { .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build() ) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.translucency_sorting.name")) + .setTooltip(I18n.format("sodium.options.translucency_sorting.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.advanced.translucencySorting = value, opts -> opts.advanced.translucencySorting) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build() + ) .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) .setName(I18n.format("sodium.options.use_entity_culling.name")) .setTooltip(I18n.format("sodium.options.use_entity_culling.tooltip")) @@ -286,7 +295,7 @@ public static OptionPage advanced() { .setName(I18n.format("sodium.options.animate_only_visible_textures.name")) .setTooltip(I18n.format("sodium.options.animate_only_visible_textures.tooltip")) .setControl(TickBoxControl::new) - .setImpact(OptionImpact.HIGH) + .setImpact(OptionImpact.MEDIUM) .setBinding((opts, value) -> opts.advanced.animateOnlyVisibleTextures = value, opts -> opts.advanced.animateOnlyVisibleTextures) .build() ) @@ -337,16 +346,14 @@ public static OptionPage performance() { .setBinding((opts, value) -> opts.performance.alwaysDeferChunkUpdates = value, opts -> opts.performance.alwaysDeferChunkUpdates) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build()) - // TODO Instead of value in Angelica config - /*.add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName(new TranslatableText("sodium.options.use_no_error_context.name")) - .setTooltip(new TranslatableText("sodium.options.use_no_error_context.tooltip")) + .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .setName(I18n.format("sodium.options.use_no_error_context.name")) + .setTooltip(I18n.format("sodium.options.use_no_error_context.tooltip")) .setControl(TickBoxControl::new) .setImpact(OptionImpact.LOW) .setBinding((opts, value) -> opts.performance.useNoErrorGLContext = value, opts -> opts.performance.useNoErrorGLContext) - .setEnabled(supportsNoErrorContext()) .setFlags(OptionFlag.REQUIRES_GAME_RESTART) - .build())*/ + .build()) .build()); return new OptionPage(I18n.format("sodium.options.pages.performance"), ImmutableList.copyOf(groups)); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 35667ad1d..cd6d800dd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -40,6 +40,7 @@ public static class AdvancedSettings { public static class PerformanceSettings { public int chunkBuilderThreads = 0; public boolean alwaysDeferChunkUpdates = false; + public boolean useNoErrorGLContext = true; } public static class EntityRenderDistance { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java index 043f5f5aa..c56af7603 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java @@ -1,5 +1,10 @@ package me.jellysquid.mods.sodium.client.gui; +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.angelica.client.gui.GuiShaders; +import com.gtnewhorizons.angelica.config.AngelicaConfig; +import jss.notfine.gui.GuiCustomMenu; +import jss.notfine.gui.MenuButtonLists; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gui.options.Option; import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; @@ -11,6 +16,7 @@ import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; import me.jellysquid.mods.sodium.client.gui.utils.Drawable; import me.jellysquid.mods.sodium.client.gui.utils.Element; +import me.jellysquid.mods.sodium.client.gui.utils.URLUtils; import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget; import me.jellysquid.mods.sodium.client.util.Dim2i; import net.minecraft.client.gui.GuiScreen; @@ -47,6 +53,8 @@ public class SodiumOptionsGUI extends GuiScreen { private boolean hasPendingChanges; private ControlElement hoveredElement; + private OptionPage shaderPacks; + public SodiumOptionsGUI(GuiScreen prevScreen) { this.prevScreen = prevScreen; @@ -54,9 +62,17 @@ public SodiumOptionsGUI(GuiScreen prevScreen) { this.pages.add(SodiumGameOptionPages.quality()); this.pages.add(SodiumGameOptionPages.advanced()); this.pages.add(SodiumGameOptionPages.performance()); + + if(AngelicaConfig.enableIris) + this.pages.add(shaderPacks = new OptionPage(I18n.format("options.iris.shaderPackSelection"), ImmutableList.of())); } public void setPage(OptionPage page) { + if (AngelicaConfig.enableIris && page == shaderPacks) { + mc.displayGuiScreen(new GuiShaders(prevScreen, mc.gameSettings)); + return; + } + this.currentPage = page; this.rebuildGUI(); @@ -89,7 +105,7 @@ private void rebuildGUI() { this.closeButton = new FlatButtonWidget(new Dim2i(this.width - 73, this.height - 26, 65, 20), I18n.format("gui.done"), this::onClose); String donateToJelly = I18n.format("sodium.options.buttons.donate"); int width = 12 + this.fontRendererObj.getStringWidth(donateToJelly); - this.donateButton = new FlatButtonWidget(new Dim2i(this.width - width - 32, 6, width, 20), donateToJelly, this::openDonationPage); + this.donateButton = new FlatButtonWidget(new Dim2i(this.width - width - 32, 6, width, 20), donateToJelly, () -> openDonationPage("https://caffeinemc.net/donate")); this.hideDonateButton = new FlatButtonWidget(new Dim2i(this.width - 26, 6, 20, 20), "x", this::hideDonationButton); if (SodiumClientMod.options().notifications.hideDonationButton) { @@ -284,15 +300,8 @@ private void undoChanges() { .forEach(Option::reset); } - // TODO Was taken from GuiChat, however i am pretty sure this code is very broken on other OS'es rather Windows - private void openDonationPage() { - try { - Class oclass = Class.forName("java.awt.Desktop"); - Object object = oclass.getMethod("getDesktop").invoke(null); - oclass.getMethod("browse", URI.class).invoke(object, "https://caffeinemc.net/donate"); - } catch (Throwable throwable) { - SodiumClientMod.logger().error("Couldn't open link", throwable); - } + private void openDonationPage(String url) { + URLUtils.open(url); } @Override @@ -305,12 +314,8 @@ public void keyTyped(char typedChar, int keyCode) { } if (keyCode == Keyboard.KEY_P && isShiftKeyDown()) { - this.mc.displayGuiScreen(new GuiVideoSettings(this.prevScreen, this.mc.gameSettings)); - - return; + this.mc.displayGuiScreen(new GuiCustomMenu(this.prevScreen, MenuButtonLists.VIDEO)); } - - super.keyTyped(typedChar, keyCode); } public boolean shouldCloseOnEsc() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/URLUtils.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/URLUtils.java new file mode 100644 index 000000000..9fb35cfda --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/utils/URLUtils.java @@ -0,0 +1,27 @@ +package me.jellysquid.mods.sodium.client.gui.utils; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.util.Util; + +import java.io.IOException; + +public class URLUtils { + + private static String[] getURLOpenCommand(String url) { + return switch (Util.getOSType()) { + case WINDOWS -> new String[]{"rundll32", "url.dll,FileProtocolHandler", url}; + case OSX -> new String[]{"open", url}; + case UNKNOWN, LINUX, SOLARIS -> new String[]{"xdg-open", url}; + }; + } + + public static void open(String url) { + try { + Runtime.getRuntime().exec(getURLOpenCommand(url)); + } catch (IOException exception) { + SodiumClientMod.logger().error("Couldn't open url '{}'", url, exception); + } + + } + +} From a172471167859b769cc0b1cbbec1aae92adfddc3 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 25 Nov 2023 12:46:58 -0500 Subject: [PATCH 129/301] Fix incorrect TE map population --- .../mods/sodium/client/world/cloned/ClonedChunkSection.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 98b4dafba..5819e3af5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -78,9 +78,9 @@ public void init(ChunkSectionPos pos) { if(block.hasTileEntity(data.getExtBlockMetadata(lX, lY, lZ))) { TileEntity tileentity = chunk.func_150806_e(x & 15, y, z & 15); - if (TileEntityRendererDispatcher.instance.hasSpecialRenderer(tileentity)) + if (tileentity != null) { - this.tileEntities.put(ChunkSectionPos.packLocal(new BlockPos(tileentity.xCoord, tileentity.yCoord, tileentity.zCoord)), tileentity); + this.tileEntities.put(ChunkSectionPos.packLocal(new BlockPos(tileentity.xCoord & 15, tileentity.yCoord & 15, tileentity.zCoord & 15)), tileentity); } } } From a3b628bd82824456cbbaa82b9ee2674683fd87d5 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 25 Nov 2023 11:06:36 -0800 Subject: [PATCH 130/301] Add optional assertMainThread behind `-Dangelica.assertMainThread=true` --- .../angelica/config/AngelicaConfig.java | 1 - .../gtnewhorizons/angelica/glsm/GLStateManager.java | 10 ++++++++++ .../transform/GLStateManagerTransformer.java | 12 ++++++++++-- .../mods/sodium/client/SodiumClientMod.java | 1 - 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index 6899eab5d..3b4eec7a7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -4,7 +4,6 @@ @Config(modid = "angelica") public class AngelicaConfig { - @Config.Comment("Enable Sodium rendering") @Config.DefaultBoolean(true) @Config.RequiresMcRestart diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index f31543bd0..46d4d1a61 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -70,6 +70,9 @@ public class GLStateManager { private static Runnable fogEndListener = null; private static Runnable fogDensityListener = null; + // Thread Checking + private static Thread MainThread; + static { if(AngelicaConfig.enableIris) { StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener; @@ -80,6 +83,13 @@ public class GLStateManager { StateUpdateNotifiers.fogDensityNotifier = listener -> fogDensityListener = listener; } Textures = (TextureState[]) IntStream.range(0, SamplerLimits.get().getMaxTextureUnits()).mapToObj(i -> new TextureState()).toArray(TextureState[]::new); + MainThread = Thread.currentThread(); + } + + public static void assertMainThread() { + if (Thread.currentThread() != MainThread) { + throw new IllegalStateException("Not on the main thread!"); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index cfbd40382..f4b40c8b2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -24,6 +24,7 @@ public class GLStateManagerTransformer implements IClassTransformer { * Redirects a subset of GL11 calls to GLStateManager * NOTE: Still need to verify compatibility with Mixins and Lwjgl3ify */ + public static final boolean ASSERT_MAIN_THREAD = Boolean.parseBoolean(System.getProperty("angelica.assertMainThread", "false")); public static final String GLStateTracker = "com/gtnewhorizons/angelica/glsm/GLStateManager"; private static final String GL11 = "org/lwjgl/opengl/GL11"; private static final String GL13 = "org/lwjgl/opengl/GL13"; @@ -45,6 +46,7 @@ public class GLStateManagerTransformer implements IClassTransformer { "org.lwjgl", "com.gtnewhorizons.angelica.glsm.", "com.gtnewhorizons.angelica.transform", "me.eigenraven.lwjgl3ify", "cpw.mods.fml.client.SplashProgress") ); public static int remaps = 0, calls = 0; + public static Method lastMethod = null; @Override public byte[] transform(final String className, String transformedName, byte[] basicClass) { @@ -70,9 +72,11 @@ public byte[] transform(final String className, String transformedName, byte[] b @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); - if (!eligibleMethods.contains(new Method(name, desc))) { + final Method method = new Method(name, desc); + if (!eligibleMethods.contains(method)) { return mv; } + return new MethodVisitor(Opcodes.ASM9, mv) { @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { @@ -82,10 +86,14 @@ public void visitMethodInsn(int opcode, String owner, String name, String desc, final String shortOwner = owner.substring(owner.lastIndexOf("/") + 1); AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", className, shortOwner, name, desc, name, desc); } + + if(ASSERT_MAIN_THREAD && !method.equals(lastMethod)) { + super.visitMethodInsn(Opcodes.INVOKESTATIC, GLStateTracker, "assertMainThread", "()V", false); + } owner = GLStateTracker; + lastMethod = method; remaps++; } - // TODO: Add an optional (if DEBUG) inject to assert we're on the main thread. super.visitMethodInsn(opcode, owner, name, desc, itf); } }; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index f2b7f1a5d..a141fc1c6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -7,7 +7,6 @@ import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiOptions; import net.minecraft.client.gui.GuiVideoSettings; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.MinecraftForge; From 7ee195a9313b6c41e544cbdb506ffaf1745a2e2e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 25 Nov 2023 16:07:45 -0500 Subject: [PATCH 131/301] Add back air optimization, but only apply to vanilla air --- .../client/render/chunk/tasks/ChunkRenderRebuildTask.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 388b4df78..76ca394a7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -23,6 +23,7 @@ import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraftforge.fluids.IFluidBlock; @@ -109,6 +110,13 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB for (int relZ = 0; relZ < 16; relZ++) { for (int relX = 0; relX < 16; relX++) { Block block = slice.getBlockRelative(relX + 16, relY + 16, relZ + 16); + + // If the block is vanilla air, assume it renders nothing. Don't use isAir because mods + // can abuse it for all sorts of things + if (block == Blocks.air) { + continue; + } + int meta = slice.getBlockMetadataRelative(relX + 16, relY + 16, relZ + 16); pos.set(baseX + relX, baseY + relY, baseZ + relZ); From 931dd8a8346ab9091e454224403dc5d1982fa931 Mon Sep 17 00:00:00 2001 From: Bogdan <64613894+Asek3@users.noreply.github.com> Date: Sun, 26 Nov 2023 01:15:01 +0200 Subject: [PATCH 132/301] Implement more options (#23) --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../early/sodium/MixinEntityRenderer.java | 9 ++++ .../early/sodium/MixinGuiIngameForge.java | 12 ++--- .../mixins/early/sodium/MixinRender.java | 19 ++++++++ .../early/sodium/MixinRenderGlobal.java | 7 +++ .../client/gui/SodiumGameOptionPages.java | 18 +++---- .../sodium/client/gui/SodiumGameOptions.java | 47 ++++++++++++++----- .../gui/options/control/CyclingControl.java | 3 +- .../resources/assets/angelica/lang/en_US.lang | 1 + 9 files changed, 87 insertions(+), 30 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRender.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 1e77d976f..7e7b9c0ee 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -55,6 +55,7 @@ public enum Mixins { //,"sodium.MixinTextureMap" //,"sodium.MixinEntityFX" ,"sodium.MixinLongHashMap" + ,"sodium.MixinRender" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityRenderer.java index 5245d6673..a3e72c685 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityRenderer.java @@ -1,11 +1,15 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; +import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.compat.FogHelper; import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.settings.GameSettings; +import org.spongepowered.asm.lib.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(EntityRenderer.class) @@ -18,4 +22,9 @@ private void storeFog(CallbackInfo ci) { FogHelper.green = fogColorGreen; FogHelper.blue = fogColorBlue; } + + @Redirect(method = "renderRainSnow(F)V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", opcode = Opcodes.GETFIELD)) + protected boolean redirectGetFancyWeather(GameSettings settings) { + return SodiumClientMod.options().quality.weatherQuality.isFancy(); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGuiIngameForge.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGuiIngameForge.java index 1c244adb7..7715670f2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGuiIngameForge.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinGuiIngameForge.java @@ -9,15 +9,9 @@ @Mixin(GuiIngameForge.class) public class MixinGuiIngameForge { - @Redirect( - method = "renderGameOverlay(FZII)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/Minecraft;isFancyGraphicsEnabled()Z" - ) - ) - private boolean checkVignette(float whyAndHowIsThisAFloat) { - return SodiumClientMod.options().quality.enableVignette; + @Redirect(method = "renderGameOverlay(FZII)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;isFancyGraphicsEnabled()Z")) + private boolean checkVignette(float idk) { + return SodiumClientMod.options().quality.enableVignette.isFancy(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRender.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRender.java new file mode 100644 index 000000000..80be62237 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRender.java @@ -0,0 +1,19 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.settings.GameSettings; +import org.spongepowered.asm.lib.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(Render.class) +public class MixinRender { + + @Redirect(method = "doRenderShadowAndFire", at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", opcode = Opcodes.GETFIELD, ordinal = 0)) + private boolean redirectGetFancyShadows(GameSettings settings) { + return SodiumClientMod.options().quality.entityShadows.isFancy(); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 74f12785b..5393a69e7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -5,6 +5,7 @@ import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; +import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; @@ -16,10 +17,12 @@ import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.client.renderer.culling.ICamera; +import net.minecraft.client.settings.GameSettings; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.Blocks; import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.lib.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; @@ -270,5 +273,9 @@ private boolean isInRange(Entity e, double x, double y, double z) { return e.isInRangeToRender3d(x, y, z) && SodiumWorldRenderer.getInstance().isEntityVisible(e); } + @Redirect(method = "renderClouds", at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z", opcode = Opcodes.GETFIELD, ordinal = 0)) + private boolean redirectGetFancyClouds(GameSettings settings) { + return SodiumClientMod.options().quality.cloudQuality.isFancy(); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index be1223f3e..cde4225f1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -182,18 +182,18 @@ public static OptionPage quality() { .setBinding((opts, value) -> opts.entityDistanceScaling = value / 100.0F, opts -> Math.round(opts.entityDistanceScaling * 100.0F)) .setImpact(OptionImpact.MEDIUM) .build() - ) - .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(new TranslatableText("options.entityShadows")) - .setTooltip(new TranslatableText("sodium.options.entity_shadows.tooltip")) - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.entityShadows = value, opts -> opts.entityShadows) + )*/ + .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .setName(I18n.format("options.entityShadows")) + .setTooltip(I18n.format("sodium.options.entity_shadows.tooltip")) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setBinding((opts, value) -> opts.quality.entityShadows = value, opts -> opts.quality.entityShadows) .setImpact(OptionImpact.LOW) - .build())*/ - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) + .build()) + .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) .setName(I18n.format("sodium.options.vignette.name")) .setTooltip(I18n.format("sodium.options.vignette.tooltip")) - .setControl(TickBoxControl::new) + .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) .setBinding((opts, value) -> opts.quality.enableVignette = value, opts -> opts.quality.enableVignette) .setImpact(OptionImpact.LOW) .build()) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index cd6d800dd..1078122d9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; import me.jellysquid.mods.sodium.client.SodiumClientMod; +import net.minecraft.client.Minecraft; import java.io.FileReader; @@ -57,17 +58,21 @@ public static class QualitySettings { public GraphicsQuality cloudQuality = GraphicsQuality.DEFAULT; public GraphicsQuality weatherQuality = GraphicsQuality.DEFAULT; public GraphicsQuality leavesQuality = GraphicsQuality.DEFAULT; - - public boolean enableVignette = true; + public GraphicsQuality entityShadows = GraphicsQuality.DEFAULT; + public GraphicsQuality enableVignette = GraphicsQuality.DEFAULT; } public static class NotificationSettings { public boolean hideDonationButton = false; } - public enum ParticleMode { - ALL("options.graphics.fancy"), - DECREASED("options.graphics.fast"), + public interface NamedState { + String getKey(); + } + + public enum ParticleMode implements NamedState { + ALL("options.particles.all"), + DECREASED("options.particles.decreased"), MINIMAL("options.particles.minimal"); private static final ParticleMode[] VALUES = values(); @@ -78,12 +83,17 @@ public enum ParticleMode { this.name = name; } + @Override + public String getKey() { + return this.name; + } + public static ParticleMode fromOrdinal(int ordinal) { return VALUES[ordinal]; } } - public enum GraphicsMode { + public enum GraphicsMode implements NamedState { FANCY("options.graphics.fancy"), FAST("options.graphics.fast"); @@ -93,6 +103,11 @@ public enum GraphicsMode { this.name = name; } + @Override + public String getKey() { + return this.name; + } + public boolean isFancy() { return this == FANCY; } @@ -102,19 +117,28 @@ public static GraphicsMode fromBoolean(boolean isFancy) { } } - public enum GraphicsQuality { + public enum GraphicsQuality implements NamedState { DEFAULT("generator.default"), - FANCY("options.clouds.fancy"), - FAST("options.clouds.fast"); + FANCY("options.graphics.fancy"), + FAST("options.graphics.fast"); private final String name; GraphicsQuality(String name) { this.name = name; } + + @Override + public String getKey() { + return this.name; + } + + public boolean isFancy() { + return this == FANCY || (this == DEFAULT && Minecraft.getMinecraft().gameSettings.fancyGraphics); + } } - public enum LightingQuality { + public enum LightingQuality implements NamedState { OFF("options.ao.off"), LOW("options.ao.min"), HIGH("options.ao.max"); @@ -130,7 +154,8 @@ public enum LightingQuality { this.vanilla = ordinal(); } - public String getLocalizedName() { + @Override + public String getKey() { return this.name; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java index e31ab5e18..981f980bd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.gui.options.control; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; import me.jellysquid.mods.sodium.client.gui.options.Option; import me.jellysquid.mods.sodium.client.util.Dim2i; import net.minecraft.client.resources.I18n; @@ -36,7 +37,7 @@ public CyclingControl(Option option, Class enumType, T[] allowedValues) { String name; T value = universe[i]; - name = I18n.format(value.name()); + name = I18n.format(value instanceof SodiumGameOptions.NamedState namedState ? namedState.getKey() : value.name()); this.names[i] = name; } diff --git a/src/main/resources/assets/angelica/lang/en_US.lang b/src/main/resources/assets/angelica/lang/en_US.lang index 920182f18..ff4d50724 100644 --- a/src/main/resources/assets/angelica/lang/en_US.lang +++ b/src/main/resources/assets/angelica/lang/en_US.lang @@ -1,6 +1,7 @@ options.button.shader=Shaders... options.chunks=%s chunks +options.entityShadows=Entity Shadows sodium.option_impact.low=Low sodium.option_impact.medium=Medium sodium.option_impact.high=High From 005757ad2135c5ac17eb31806f6486fade38bf3c Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 6 Nov 2023 08:59:55 -0500 Subject: [PATCH 133/301] Combine free regions in GlBufferArena Fixes https://github.com/CaffeineMC/sodium-fabric/issues/740 --- .../sodium/client/gl/arena/GlBufferArena.java | 37 ++++++++++++++++++- .../client/gl/arena/GlBufferSegment.java | 4 ++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferArena.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferArena.java index 3b4a7b707..8d727b614 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferArena.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferArena.java @@ -69,10 +69,45 @@ private int getNextSize(int len) { } public void free(GlBufferSegment segment) { - if (!this.freeRegions.add(segment)) { + if (this.freeRegions.contains(segment)) { throw new IllegalArgumentException("Segment already freed"); } + // Attempt merging + GlBufferSegment prev = null, next = null; + int selfEnd = segment.getEnd(); + for (GlBufferSegment freeSeg : this.freeRegions) { + if (prev != null && next != null) + break; + if (freeSeg.getStart() == selfEnd) { + next = freeSeg; + } else if (freeSeg.getEnd() == segment.getStart()) { + prev = freeSeg; + } + } + + if(prev != null || next != null) { + int start, end; + + if(prev != null) { + this.freeRegions.remove(prev); + start = prev.getStart(); + } else { + start = segment.getStart(); + } + + if(next != null) { + this.freeRegions.remove(next); + end = next.getEnd(); + } else { + end = segment.getEnd(); + } + + segment = new GlBufferSegment(this, start, end - start); + } + + this.freeRegions.add(segment); + this.allocCount--; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferSegment.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferSegment.java index 295d5bff2..c9f4d3432 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferSegment.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/arena/GlBufferSegment.java @@ -19,6 +19,10 @@ public int getLength() { return this.len; } + public int getEnd() { + return this.start + this.len; + } + public void delete() { this.arena.free(this); } From 768cac071e151eecdb0706cc1996ab280a8424b2 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:26:41 -0500 Subject: [PATCH 134/301] Clear global block entity list when initializing renderer --- .../mods/sodium/client/render/SodiumWorldRenderer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 2568a6caa..b4b5f8a77 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -268,6 +268,8 @@ private void initRenderer() { this.chunkRenderBackend = null; } + this.globalBlockEntities.clear(); + RenderDevice device = RenderDevice.INSTANCE; SodiumGameOptions opts = SodiumClientMod.options(); From 3aed1a0eaf00c0631eb0a1362702b6f4dda8fa2b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:18:33 -0500 Subject: [PATCH 135/301] Use Set for globalBlockEntities --- .../mods/sodium/client/render/chunk/data/ChunkRenderData.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java index e23695f15..a7944914d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java @@ -29,7 +29,7 @@ public class ChunkRenderData { .build(); public static final ChunkRenderData EMPTY = createEmptyData(); - private List globalTileEntities; + private Set globalTileEntities; private List tileEntities; private EnumMap meshes; @@ -163,7 +163,7 @@ public void addTileEntity(TileEntity entity, boolean cull) { public ChunkRenderData build() { ChunkRenderData data = new ChunkRenderData(); - data.globalTileEntities = this.globalTileEntities; + data.globalTileEntities = new ObjectOpenHashSet<>(this.globalTileEntities); data.tileEntities = this.tileEntities; data.occlusionData = this.occlusionData; data.meshes = this.meshes; From 13ff905cd2b3645c00a5dee578cb94ede0af175f Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 25 Nov 2023 19:42:52 -0500 Subject: [PATCH 136/301] Render invalid TEs but suppress errors --- .../client/render/SodiumWorldRenderer.java | 60 ++++++------------- 1 file changed, 17 insertions(+), 43 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index b4b5f8a77..38bae5426 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -303,55 +303,29 @@ private boolean checkBEVisibility(TileEntity entity) { return frustum.isBoundingBoxInFrustum(entity.getRenderBoundingBox()); } + private void renderTE(TileEntity tileEntity, int pass, float partialTicks) { + if(!tileEntity.shouldRenderInPass(pass) || !checkBEVisibility(tileEntity)) + return; + + try { + TileEntityRendererDispatcher.instance.renderTileEntity(tileEntity, partialTicks); + } catch(RuntimeException e) { + if(tileEntity.isInvalid()) { + SodiumClientMod.logger().error("Suppressing crash from invalid tile entity", e); + } else { + throw e; + } + } + } + public void renderTileEntities(EntityLivingBase entity, ICamera camera, float partialTicks) { -// VertexConsumerProvider.Immediate immediate = bufferBuilders.getEntityVertexConsumers(); -// -// Vector3d cameraPos = camera.getPos(); -// double x = cameraPos.x; -// double y = cameraPos.y; -// double z = cameraPos.z; -// int pass = MinecraftForgeClient.getRenderPass(); for (TileEntity tileEntity : this.chunkRenderManager.getVisibleBlockEntities()) { - if(tileEntity.isInvalid() || !tileEntity.shouldRenderInPass(pass) || !checkBEVisibility(tileEntity)) - continue; -// BlockPos pos = new BlockPos(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); -// -// matrices.push(); -// matrices.translate((double) pos.x - x, (double) pos.y - y, (double) pos.z - z); -// -// VertexConsumerProvider consumer = immediate; -// SortedSet breakingInfos = blockBreakingProgressions.get(pos.asLong()); -// -// if (breakingInfos != null && !breakingInfos.isEmpty()) { -// int stage = breakingInfos.last().getStage(); -// -// if (stage >= 0) { -// MatrixStack.Entry entry = matrices.peek(); -// VertexConsumer transformer = new OverlayVertexConsumer(bufferBuilders.getEffectVertexConsumers().getBuffer(ModelLoader.BLOCK_DESTRUCTION_RENDER_LAYERS.get(stage)), entry.getModel(), entry.getNormal()); -// consumer = (layer) -> layer.hasCrumbling() ? VertexConsumers.union(transformer, immediate.getBuffer(layer)) : immediate.getBuffer(layer); -// } -// } - // TODO: Sodium TileEntity Rendering Dispatcher - TileEntityRendererDispatcher.instance.renderTileEntity(tileEntity, partialTicks); -// BlockEntityRenderDispatcher.INSTANCE.render(tileEntity, tickDelta, matrices, consumer); - -// matrices.pop(); + renderTE(tileEntity, pass, partialTicks); } for (TileEntity tileEntity : this.globalTileEntities) { - if(!tileEntity.shouldRenderInPass(pass) || !checkBEVisibility(tileEntity)) - continue; -// BlockPos pos = new BlockPos(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord); -// -// matrices.push(); -// matrices.translate((double) pos.x - x, (double) pos.y - y, (double) pos.z - z); - - // TODO: Sodium TileEntity Rendering Dispatcher - TileEntityRendererDispatcher.instance.renderTileEntity(tileEntity, partialTicks); -// BlockEntityRenderDispatcher.INSTANCE.render(tileEntity, tickDelta, matrices, immediate); - -// matrices.pop(); + renderTE(tileEntity, pass, partialTicks); } } From 15f7666181baf754533e89ffe749bdb679394ad1 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 25 Nov 2023 20:08:16 -0500 Subject: [PATCH 137/301] Fix defaultBlendFunc calling uncached method --- .../java/com/gtnewhorizons/angelica/glsm/GLStateManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 46d4d1a61..660ff046a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -395,7 +395,7 @@ public static void glDrawArrays(int mode, int first, int count) { public static void defaultBlendFunc() { - GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); } public static void enableCull() { From 92b56413fe34eded549c6e1554ea9e7431828b02 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 25 Nov 2023 20:22:25 -0500 Subject: [PATCH 138/301] Fix incorrect variable name --- .../mods/sodium/client/render/SodiumWorldRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 38bae5426..3363c727e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -268,7 +268,7 @@ private void initRenderer() { this.chunkRenderBackend = null; } - this.globalBlockEntities.clear(); + this.globalTileEntities.clear(); RenderDevice device = RenderDevice.INSTANCE; From 458e6fccef15cde5d33743b329c901cf94f24cfd Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 25 Nov 2023 20:22:35 -0500 Subject: [PATCH 139/301] Redirect glColor3f --- .../java/com/gtnewhorizons/angelica/glsm/GLStateManager.java | 4 ++++ .../angelica/transform/GLStateManagerTransformer.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 660ff046a..2dc008866 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -203,6 +203,10 @@ public static void glColor4f(float red, float green, float blue, float alpha) { } } + public static void glColor3f(float red, float green, float blue) { + glColor4f(red, green, blue, 1.0f); + } + public static void clearCurrentColor() { Color.red = -1.0F; Color.green = -1.0F; diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index f4b40c8b2..a23b11ae8 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -34,7 +34,7 @@ public class GLStateManagerTransformer implements IClassTransformer { public static final Map> EnabledRedirects = ImmutableMap.of( GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", - "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor4f", "glShadeModel", "glFog", "glFogi", "glFogf", "glClearColor") + "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor3f", "glColor4f", "glShadeModel", "glFog", "glFogi", "glFogf", "glClearColor") ,GL13, Sets.newHashSet("glActiveTexture") ,GL14, Sets.newHashSet("glBlendFuncSeparate") ,EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") From deecb0ab8e118b1319b8b6a3081b173e0aeb9218 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 25 Nov 2023 18:13:55 -0800 Subject: [PATCH 140/301] AF, CompileStubs, and SplashProgress Remove most of ArchaicFix * Move a few mixins over to angelica * Keep AF's Config classes for now Remove CompileStubs * Comment out anything using them (shadersmod) SplashProgress - Stop errors * Disable if org.lwjgl.util.Debug is set * Only enable Iris/lwjgl debug callbacks if org.lwjgl.util.Debug is set --- .../renderer/texture/AbstractTexture.java | 19 - .../renderer/texture/ITextureObject.java | 10 - .../client/renderer/texture/TextureMap.java | 31 - .../ca/fxco/memoryleakfix/MemoryLeakFix.java | 51 -- .../angelica/client/DefaultTexture.java | 2 +- .../angelica/client/Shaders.java | 6 +- .../angelica/client/ShadersTex.java | 329 +++++----- .../angelica/compat/mojang/TextureAtlas.java | 2 +- .../angelica/config/AngelicaConfig.java | 17 +- .../angelica/config/AngelicaGuiConfig.java | 9 + .../config/AngelicaGuiConfigFactory.java | 10 + .../angelica}/config/Config.java | 4 +- .../angelica}/config/ConfigException.java | 2 +- .../config/ConfigurationManager.java | 2 +- .../angelica}/config/IConfigElementProxy.java | 2 +- .../angelica}/config/SimpleGuiConfig.java | 3 +- .../angelica}/config/SimpleGuiFactory.java | 2 +- .../angelica/glsm/GLStateManager.java | 1 + .../helpers/LoadControllerHelper.java | 2 +- .../angelica/loading/AngelicaLateMixins.java | 5 - .../angelica/loading/AngelicaTweaker.java | 24 +- .../angelica/mixins/ArchaicMixins.java | 163 ----- .../gtnewhorizons/angelica/mixins/Mixins.java | 24 +- .../archaic}/AccessorSplashProgress.java | 4 +- .../archaic}/MixinBlockFence.java | 2 +- .../archaic}/MixinFMLClientHandler.java | 2 +- .../archaic}/MixinGuiIngameForge.java | 4 +- .../archaic}/MixinNetHandlerPlayClient.java | 10 +- .../archaic}/MixinSplashProgress.java | 13 +- .../MixinThreadDownloadImageData.java | 2 +- .../angelica/debug/MixinSplashProgress.java | 20 + .../client/core/MixinChunkProviderClient.java | 18 - .../client/core/MixinEntityRenderer.java | 19 - .../client/core/MixinGuiBeaconButton.java | 21 - .../archaic/client/core/MixinGuiButton.java | 23 - .../client/core/MixinGuiCreateWorld.java | 22 - .../client/core/MixinIntegratedServer.java | 23 - .../archaic/client/core/MixinMinecraft.java | 62 -- .../core/MixinNetHandlerLoginClient.java | 22 - .../archaic/client/core/MixinRenderItem.java | 16 - .../archaic/client/core/MixinSkinManager.java | 21 - .../client/core/MixinWorldRenderer.java | 59 -- .../client/lighting/MixinChunkCache.java | 19 - .../client/lighting/MixinMinecraft.java | 33 - .../archaic/client/lighting/MixinWorld.java | 33 - .../renderdistance/MixinGameSettings.java | 15 - .../renderdistance/MixinRenderGlobal.java | 46 -- .../MixinPlayerChunkViewerManager.java | 33 - .../common/core/AccessorEntityLiving.java | 13 - .../archaic/common/core/MixinASMData.java | 25 - .../common/core/MixinAxisAlignedBB.java | 31 - .../early/archaic/common/core/MixinBlock.java | 19 - .../early/archaic/common/core/MixinChunk.java | 93 --- .../common/core/MixinChunkProviderHell.java | 20 - .../common/core/MixinChunkProviderServer.java | 31 - .../common/core/MixinEmbeddedChannel.java | 118 ---- .../common/core/MixinEnchantmentHelper.java | 40 -- .../common/core/MixinEntityLiving.java | 28 - .../common/core/MixinEntityPlayerMP.java | 33 - .../common/core/MixinEntityTrackerEntry.java | 84 --- .../common/core/MixinEntityVillager.java | 40 -- .../archaic/common/core/MixinEntityXPOrb.java | 14 - .../common/core/MixinForgeChunkManager.java | 26 - .../archaic/common/core/MixinLongHashMap.java | 18 - .../common/core/MixinMapGenStructure.java | 21 - .../common/core/MixinMaterialLiquid.java | 18 - .../common/core/MixinMerchantRecipe.java | 24 - .../common/core/MixinModCandidate.java | 56 -- .../core/MixinNetHandlerPlayServer.java | 18 - .../common/core/MixinNetworkDispatcher.java | 37 -- .../common/core/MixinNetworkManager.java | 26 - .../common/core/MixinNextTickListEntry.java | 39 -- .../core/MixinObjectIntIdentityMap.java | 34 - .../common/core/MixinSpawnerAnimals.java | 33 - .../common/core/MixinStructureStart.java | 17 - .../early/archaic/common/core/MixinWorld.java | 103 --- .../common/core/MixinWorldChunkManager.java | 48 -- .../archaic/common/core/MixinWorldServer.java | 38 -- .../extrautils/MixinEventHandlerServer.java | 22 - .../extrautils/MixinEventHandlerSiege.java | 14 - .../extrautils/MixinItemDivisionSigil.java | 25 - .../extrautils/MixinTileEntityTrashCan.java | 19 - .../lighting/MixinAnvilChunkLoader.java | 53 -- .../archaic/common/lighting/MixinChunk.java | 392 ----------- .../lighting/MixinChunkProviderServer.java | 45 -- .../common/lighting/MixinChunkVanilla.java | 81 --- .../lighting/MixinExtendedBlockStorage.java | 97 --- .../lighting/MixinSPacketChunkData.java | 23 - .../common/lighting/MixinWorld_Lighting.java | 54 -- .../renderdistance/MixinPlayerManager.java | 15 - .../shaders/startup/MixinInitRenderer.java | 7 + .../early/sodium/startup/MixinInitDebug.java | 6 + .../angelica/proxy/ClientProxy.java | 108 +++ .../transform/GLStateManagerTransformer.java | 3 +- .../mods/sodium/client/SodiumClientMod.java | 1 + src/main/java/net/coderbot/iris/Iris.java | 2 + .../java/net/coderbot/iris/gl/GLDebug.java | 10 + .../iris/texture/pbr/PBRAtlasTexture.java | 8 +- .../org/embeddedt/archaicfix/ArchaicFix.java | 63 -- .../embeddedt/archaicfix/ArchaicLogger.java | 8 - .../archaicfix/CommandDebugUpdateQueue.java | 39 -- .../org/embeddedt/archaicfix/FixHelper.java | 36 - .../archaicfix/block/ThreadedBlockData.java | 32 - .../archaicfix/config/ArchaicConfig.java | 121 ---- .../archaicfix/config/ArchaicGuiConfig.java | 9 - .../config/ArchaicGuiConfigFactory.java | 10 - .../helpers/BuiltInResourcePack.java | 184 ------ .../helpers/ChickenChunkHelper.java | 10 - .../archaicfix/helpers/ChunkQueueSorter.java | 31 - .../archaicfix/helpers/DragonAPIHelper.java | 28 - .../archaicfix/helpers/NEISearchHelper.java | 13 - .../archaicfix/helpers/OreDictIterator.java | 111 ---- .../archaicfix/helpers/SoundDeviceThread.java | 64 -- .../helpers/UnexpectionalObjectArrayList.java | 15 - .../helpers/WorldRendererDistanceHelper.java | 17 - .../interfaces/IAcceleratedRecipe.java | 11 - .../interfaces/IArchaicNetworkManager.java | 7 - .../interfaces/ILazyChunkProviderServer.java | 5 - .../archaicfix/interfaces/IPendingChunk.java | 9 - .../archaicfix/interfaces/IWorldRenderer.java | 5 - .../lighting/api/IChunkLighting.java | 7 - .../lighting/api/IChunkLightingData.java | 13 - .../lighting/api/ILightingEngine.java | 11 - .../lighting/api/ILightingEngineProvider.java | 5 - .../lighting/collections/PooledLongQueue.java | 164 ----- .../lighting/world/WorldChunkSlice.java | 58 -- .../world/lighting/AxisDirection.java | 16 - .../lighting/world/lighting/BlockPos.java | 41 -- .../world/lighting/LightingEngine.java | 613 ------------------ .../world/lighting/LightingEngineHelpers.java | 44 -- .../world/lighting/LightingHooks.java | 431 ------------ .../archaicfix/proxy/ClientProxy.java | 177 ----- .../archaicfix/proxy/CommonProxy.java | 18 - .../archaicfix/recipe/LastMatchedInfo.java | 70 -- .../archaicfix/recipe/RecipeCacheLoader.java | 41 -- .../archaicfix/recipe/RecipeWeigher.java | 14 - .../zone/rong/rongasm/api/CaptureSet.java | 34 - .../java/zone/rong/rongasm/api/DummyMap.java | 50 -- .../zone/rong/rongasm/api/ResourceCache.java | 15 - .../zone/rong/rongasm/api/RongHelpers.java | 40 -- .../zone/rong/rongasm/api/RongReflector.java | 226 ------- .../zone/rong/rongasm/api/StringPool.java | 142 ---- 142 files changed, 418 insertions(+), 6032 deletions(-) delete mode 100644 src/compileStubs/java/net/minecraft/client/renderer/texture/AbstractTexture.java delete mode 100644 src/compileStubs/java/net/minecraft/client/renderer/texture/ITextureObject.java delete mode 100644 src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java delete mode 100644 src/main/java/ca/fxco/memoryleakfix/MemoryLeakFix.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/config/AngelicaGuiConfig.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/config/AngelicaGuiConfigFactory.java rename src/main/java/{org/embeddedt/archaicfix => com/gtnewhorizons/angelica}/config/Config.java (98%) rename src/main/java/{org/embeddedt/archaicfix => com/gtnewhorizons/angelica}/config/ConfigException.java (87%) rename src/main/java/{org/embeddedt/archaicfix => com/gtnewhorizons/angelica}/config/ConfigurationManager.java (99%) rename src/main/java/{org/embeddedt/archaicfix => com/gtnewhorizons/angelica}/config/IConfigElementProxy.java (98%) rename src/main/java/{org/embeddedt/archaicfix => com/gtnewhorizons/angelica}/config/SimpleGuiConfig.java (85%) rename src/main/java/{org/embeddedt/archaicfix => com/gtnewhorizons/angelica}/config/SimpleGuiFactory.java (93%) rename src/main/java/{org/embeddedt/archaicfix => com/gtnewhorizons/angelica}/helpers/LoadControllerHelper.java (99%) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{archaic/client/core => angelica/archaic}/AccessorSplashProgress.java (88%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{archaic/client/core => angelica/archaic}/MixinBlockFence.java (91%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{archaic/client/core => angelica/archaic}/MixinFMLClientHandler.java (92%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{archaic/client/core => angelica/archaic}/MixinGuiIngameForge.java (85%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{archaic/client/core => angelica/archaic}/MixinNetHandlerPlayClient.java (79%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{archaic/client/core => angelica/archaic}/MixinSplashProgress.java (91%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/{archaic/client/core => angelica/archaic}/MixinThreadDownloadImageData.java (93%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/debug/MixinSplashProgress.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinChunkProviderClient.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinEntityRenderer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiBeaconButton.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiButton.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiCreateWorld.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinIntegratedServer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinMinecraft.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerLoginClient.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinRenderItem.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSkinManager.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinWorldRenderer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinChunkCache.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinMinecraft.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinGameSettings.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinRenderGlobal.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/chickenchunks/MixinPlayerChunkViewerManager.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/AccessorEntityLiving.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinASMData.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinAxisAlignedBB.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinBlock.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderHell.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderServer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEmbeddedChannel.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEnchantmentHelper.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityPlayerMP.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityTrackerEntry.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityVillager.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityXPOrb.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinForgeChunkManager.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinLongHashMap.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMapGenStructure.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMaterialLiquid.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMerchantRecipe.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinModCandidate.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetHandlerPlayServer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkDispatcher.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkManager.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNextTickListEntry.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinObjectIntIdentityMap.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinSpawnerAnimals.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinStructureStart.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorld.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldChunkManager.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldServer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerServer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerSiege.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinItemDivisionSigil.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinTileEntityTrashCan.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinAnvilChunkLoader.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunk.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkProviderServer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkVanilla.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinExtendedBlockStorage.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinSPacketChunkData.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinWorld_Lighting.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/renderdistance/MixinPlayerManager.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/ArchaicFix.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/ArchaicLogger.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/CommandDebugUpdateQueue.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/FixHelper.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfig.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfigFactory.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/ChickenChunkHelper.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/ChunkQueueSorter.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/NEISearchHelper.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/SoundDeviceThread.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/UnexpectionalObjectArrayList.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/interfaces/IAcceleratedRecipe.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/interfaces/IArchaicNetworkManager.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/interfaces/ILazyChunkProviderServer.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/interfaces/IPendingChunk.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/interfaces/IWorldRenderer.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLighting.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLightingData.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngine.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngineProvider.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/collections/PooledLongQueue.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/WorldChunkSlice.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/AxisDirection.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/BlockPos.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngine.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngineHelpers.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/recipe/LastMatchedInfo.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java delete mode 100644 src/main/java/org/embeddedt/archaicfix/recipe/RecipeWeigher.java delete mode 100644 src/main/java/zone/rong/rongasm/api/CaptureSet.java delete mode 100644 src/main/java/zone/rong/rongasm/api/DummyMap.java delete mode 100644 src/main/java/zone/rong/rongasm/api/ResourceCache.java delete mode 100644 src/main/java/zone/rong/rongasm/api/RongHelpers.java delete mode 100644 src/main/java/zone/rong/rongasm/api/RongReflector.java delete mode 100644 src/main/java/zone/rong/rongasm/api/StringPool.java diff --git a/src/compileStubs/java/net/minecraft/client/renderer/texture/AbstractTexture.java b/src/compileStubs/java/net/minecraft/client/renderer/texture/AbstractTexture.java deleted file mode 100644 index afd7ea1d3..000000000 --- a/src/compileStubs/java/net/minecraft/client/renderer/texture/AbstractTexture.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.minecraft.client.renderer.texture; - -import com.gtnewhorizons.angelica.client.MultiTexID; - -public abstract class AbstractTexture implements ITextureObject { - - public int glTextureId = -1; - public MultiTexID angelica$multiTex; - - public int getGlTextureId() { - return 0; - } - - public void deleteGlTexture() {} - - public MultiTexID angelica$getMultiTexID() { - return null; - } -} diff --git a/src/compileStubs/java/net/minecraft/client/renderer/texture/ITextureObject.java b/src/compileStubs/java/net/minecraft/client/renderer/texture/ITextureObject.java deleted file mode 100644 index 3749903ec..000000000 --- a/src/compileStubs/java/net/minecraft/client/renderer/texture/ITextureObject.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.minecraft.client.renderer.texture; - -import com.gtnewhorizons.angelica.client.MultiTexID; - -public interface ITextureObject { - - MultiTexID angelica$getMultiTexID(); - - int getGlTextureId(); -} diff --git a/src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java b/src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java deleted file mode 100644 index c9b2c03df..000000000 --- a/src/compileStubs/java/net/minecraft/client/renderer/texture/TextureMap.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.minecraft.client.renderer.texture; - -import net.minecraft.client.resources.IResourceManager; -import net.minecraft.util.ResourceLocation; - -import java.util.Map; - -public class TextureMap extends AbstractTexture { - - public static ResourceLocation locationBlocksTexture; - public static ResourceLocation locationItemsTexture; - - public int angelica$atlasWidth; - public int angelica$atlasHeight; - - public void loadTextureAtlas(IResourceManager p_110571_1_) {} - - public ResourceLocation completeResourceLocation(ResourceLocation p_147634_1_, int p_147634_2_) { - return null; - } - - public void updateAnimations() {} - public void setAnisotropicFiltering(int p_147632_1_) {} - public void setMipmapLevels(int p_147633_1_) {} - - public int getTextureType() { - return 0; - } - - public Object getTextureEntry(String iconName) { return null; } -} diff --git a/src/main/java/ca/fxco/memoryleakfix/MemoryLeakFix.java b/src/main/java/ca/fxco/memoryleakfix/MemoryLeakFix.java deleted file mode 100644 index 92c3225e8..000000000 --- a/src/main/java/ca/fxco/memoryleakfix/MemoryLeakFix.java +++ /dev/null @@ -1,51 +0,0 @@ -package ca.fxco.memoryleakfix; - -import org.embeddedt.archaicfix.ArchaicLogger; -import org.spongepowered.asm.mixin.MixinEnvironment; -import org.spongepowered.asm.mixin.injection.struct.InjectorGroupInfo; -import org.spongepowered.asm.mixin.transformer.ClassInfo; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.List; -import java.util.Map; - -public class MemoryLeakFix { - public static void forceLoadAllMixinsAndClearSpongePoweredCache() { - ArchaicLogger.LOGGER.info("Forceloading mixins and clearing mixin cache"); - try { - Field noGroupField; - try { - noGroupField = InjectorGroupInfo.Map.class.getDeclaredField("NO_GROUP"); - } catch(NoSuchFieldException e) { - noGroupField = null; - } - if(noGroupField == null || !Modifier.isStatic(noGroupField.getModifiers())) { - ArchaicLogger.LOGGER.info("No need to forceload, this mixin version doesn't have the memory leak"); - return; - } - MixinEnvironment.getCurrentEnvironment().audit(); - noGroupField.setAccessible(true); - Object noGroup = noGroupField.get(null); - Field membersField = noGroup.getClass().getDeclaredField("members"); - membersField.setAccessible(true); - ((List) membersField.get(noGroup)).clear(); // Clear spongePoweredCache - emptyClassInfo(); - } catch (NoSuchFieldException | IllegalAccessException e) { - e.printStackTrace(); - } - ArchaicLogger.LOGGER.info("Finished clearing mixin cache"); - } - - private static final String OBJECT = "java/lang/Object"; - - private static void emptyClassInfo() throws NoSuchFieldException, IllegalAccessException { - Field cacheField = ClassInfo.class.getDeclaredField("cache"); - cacheField.setAccessible(true); - @SuppressWarnings("unchecked") - Map cache = ((Map)cacheField.get(null)); - ClassInfo jlo = cache.get(OBJECT); - cache.clear(); - cache.put(OBJECT, jlo); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/DefaultTexture.java b/src/main/java/com/gtnewhorizons/angelica/client/DefaultTexture.java index 3dc99cdfc..ef44df10d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/DefaultTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/DefaultTexture.java @@ -11,6 +11,6 @@ public DefaultTexture() { public void loadTexture(IResourceManager resourcemanager) { int[] aint = ShadersTex.createAIntImage(1, 0xFFFFFFFF); - ShadersTex.setupTexture(this.angelica$getMultiTexID(), aint, 1, 1, false, false); +// ShadersTex.setupTexture(this.angelica$getMultiTexID(), aint, 1, 1, false, false); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index 9ee5355c9..14bb1166d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -2117,7 +2117,7 @@ public static void beginRender(Minecraft minecraft, float f, long l) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dfb); GL11.glViewport(0, 0, Shaders.renderWidth, Shaders.renderHeight); activeDrawBuffers = null; - ShadersTex.bindNSTextures(defaultTexture.angelica$getMultiTexID()); +// ShadersTex.bindNSTextures(defaultTexture.angelica$getMultiTexID()); useProgram(ProgramTextured); checkGLError("end beginRender"); @@ -2783,7 +2783,7 @@ public static void endBlockEntities() { if (isRenderingWorld) { checkGLError("endBlockEntities"); useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); - ShadersTex.bindNSTextures(defaultTexture.angelica$getMultiTexID()); +// ShadersTex.bindNSTextures(defaultTexture.angelica$getMultiTexID()); } } @@ -2921,7 +2921,7 @@ public static void preWater() { checkGLError("copy depth"); GL13.glActiveTexture(GL13.GL_TEXTURE0); } - ShadersTex.bindNSTextures(defaultTexture.angelica$getMultiTexID()); // flat +// ShadersTex.bindNSTextures(defaultTexture.angelica$getMultiTexID()); // flat } } diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java index 34040e0f6..4cceb7a43 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java @@ -1,14 +1,11 @@ package com.gtnewhorizons.angelica.client; -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.DynamicTexture; import net.minecraft.client.renderer.texture.ITextureObject; import net.minecraft.client.renderer.texture.LayeredTexture; import net.minecraft.client.renderer.texture.Stitcher; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.texture.TextureUtil; import net.minecraft.client.resources.IResource; @@ -27,7 +24,6 @@ import java.nio.IntBuffer; import java.util.Arrays; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -100,36 +96,37 @@ public static int[] createAIntImage(int size, int color) { } public static MultiTexID getMultiTexID(AbstractTexture tex) { - MultiTexID multiTex = tex.angelica$multiTex; - if (multiTex == null) { - int baseTex = tex.getGlTextureId(); - multiTex = multiTexMap.get(Integer.valueOf(baseTex)); - if (multiTex == null) { - multiTex = new MultiTexID(baseTex, GL11.glGenTextures(), GL11.glGenTextures()); - multiTexMap.put(baseTex, multiTex); - } - tex.angelica$multiTex = multiTex; - } - return multiTex; + return null; +// MultiTexID multiTex = tex.angelica$multiTex; +// if (multiTex == null) { +// int baseTex = tex.getGlTextureId(); +// multiTex = multiTexMap.get(Integer.valueOf(baseTex)); +// if (multiTex == null) { +// multiTex = new MultiTexID(baseTex, GL11.glGenTextures(), GL11.glGenTextures()); +// multiTexMap.put(baseTex, multiTex); +// } +// tex.angelica$multiTex = multiTex; +// } +// return multiTex; } public static void deleteTextures(AbstractTexture atex) { - int texid = atex.glTextureId; - if (texid != -1) { - GL11.glDeleteTextures(texid); - atex.glTextureId = -1; - } - MultiTexID multiTex = atex.angelica$multiTex; - if (multiTex != null) { - atex.angelica$multiTex = null; - multiTexMap.remove(Integer.valueOf(multiTex.base)); - GL11.glDeleteTextures(multiTex.norm); - GL11.glDeleteTextures(multiTex.spec); - if (multiTex.base != texid) { - AngelicaTweaker.LOGGER.warn("Error : MultiTexID.base mismatch."); - GL11.glDeleteTextures(multiTex.base); - } - } +// int texid = atex.glTextureId; +// if (texid != -1) { +// GL11.glDeleteTextures(texid); +// atex.glTextureId = -1; +// } +// MultiTexID multiTex = atex.angelica$multiTex; +// if (multiTex != null) { +// atex.angelica$multiTex = null; +// multiTexMap.remove(Integer.valueOf(multiTex.base)); +// GL11.glDeleteTextures(multiTex.norm); +// GL11.glDeleteTextures(multiTex.spec); +// if (multiTex.base != texid) { +// AngelicaTweaker.LOGGER.warn("Error : MultiTexID.base mismatch."); +// GL11.glDeleteTextures(multiTex.base); +// } +// } } /** Remove MultiTexID object reference and delete textures */ @@ -188,14 +185,14 @@ public static void bindTextures(MultiTexID multiTex) { } public static void bindTexture(ITextureObject tex) { - if (tex instanceof TextureMap) { - Shaders.atlasSizeX = ((TextureMap) tex).angelica$atlasWidth; - Shaders.atlasSizeY = ((TextureMap) tex).angelica$atlasHeight; - } else { - Shaders.atlasSizeX = 0; - Shaders.atlasSizeY = 0; - } - bindTextures(tex.angelica$getMultiTexID()); +// if (tex instanceof TextureMap) { +// Shaders.atlasSizeX = ((TextureMap) tex).angelica$atlasWidth; +// Shaders.atlasSizeY = ((TextureMap) tex).angelica$atlasHeight; +// } else { +// Shaders.atlasSizeX = 0; +// Shaders.atlasSizeY = 0; +// } +// bindTextures(tex.angelica$getMultiTexID()); } /** not used */ @@ -224,41 +221,41 @@ public static void allocTexStorage(int width, int height, int maxLevel) { // for Dynamic Texture public static void initDynamicTexture(int texID, int width, int height, DynamicTexture tex) { // TODO: PBR - MultiTexID multiTex = tex.angelica$getMultiTexID(); - int[] aint = tex.getTextureData(); - int size = width * height; - Arrays.fill(aint, size, size * 2, defNormTexColor); - Arrays.fill(aint, size * 2, size * 3, defSpecTexColor); - // base texture - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); - allocTexStorage(width, height, 0); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0); - - // This seems PBR related... - // norm texture - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - allocTexStorage(width, height, 0); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0); - - // spec texture - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); - allocTexStorage(width, height, 0); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0); - - // base texture - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); +// MultiTexID multiTex = tex.angelica$getMultiTexID(); +// int[] aint = tex.getTextureData(); +// int size = width * height; +// Arrays.fill(aint, size, size * 2, defNormTexColor); +// Arrays.fill(aint, size * 2, size * 3, defSpecTexColor); +// // base texture +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); +// allocTexStorage(width, height, 0); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0); +// +// // This seems PBR related... +// // norm texture +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); +// allocTexStorage(width, height, 0); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0); +// +// // spec texture +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); +// allocTexStorage(width, height, 0); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0); +// +// // base texture +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); } public static ITextureObject createDefaultTexture() { @@ -271,18 +268,18 @@ public static ITextureObject createDefaultTexture() { // for TextureMap public static void allocateTextureMap(int texID, int mipmapLevels, int width, int height, float anisotropy, Stitcher stitcher, TextureMap tex) { - AngelicaTweaker.LOGGER.trace("allocateTextureMap {} {} {} {} {}", tex.getTextureType(), mipmapLevels, width, height, anisotropy); - updatingTextureMap = tex; - tex.angelica$atlasWidth = width; - tex.angelica$atlasHeight = height; - MultiTexID multiTex = getMultiTexID(tex); - updatingTex = multiTex; - TextureUtil.allocateTextureImpl(multiTex.base, mipmapLevels, width, height, anisotropy); - if (Shaders.configNormalMap) - TextureUtil.allocateTextureImpl(multiTex.norm, mipmapLevels, width, height, anisotropy); - if (Shaders.configSpecularMap) - TextureUtil.allocateTextureImpl(multiTex.spec, mipmapLevels, width, height, anisotropy); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID); +// AngelicaTweaker.LOGGER.trace("allocateTextureMap {} {} {} {} {}", tex.getTextureType(), mipmapLevels, width, height, anisotropy); +// updatingTextureMap = tex; +// tex.angelica$atlasWidth = width; +// tex.angelica$atlasHeight = height; +// MultiTexID multiTex = getMultiTexID(tex); +// updatingTex = multiTex; +// TextureUtil.allocateTextureImpl(multiTex.base, mipmapLevels, width, height, anisotropy); +// if (Shaders.configNormalMap) +// TextureUtil.allocateTextureImpl(multiTex.norm, mipmapLevels, width, height, anisotropy); +// if (Shaders.configSpecularMap) +// TextureUtil.allocateTextureImpl(multiTex.spec, mipmapLevels, width, height, anisotropy); +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID); } public static TextureAtlasSprite setSprite(TextureAtlasSprite tas) { @@ -609,13 +606,13 @@ public static void setupTextureMipmap(TextureMap tex) { public static void updateDynamicTexture(int texID, int[] src, int width, int height, DynamicTexture tex) { // TODO: PBR - MultiTexID multiTex = tex.angelica$getMultiTexID(); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - updateSubImage1(src, width, height, 0, 0, 1, defNormTexColor); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); - updateSubImage1(src, width, height, 0, 0, 2, defSpecTexColor); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); - updateSubImage1(src, width, height, 0, 0, 0, defBaseTexColor); +// MultiTexID multiTex = tex.angelica$getMultiTexID(); +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); +// updateSubImage1(src, width, height, 0, 0, 1, defNormTexColor); +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); +// updateSubImage1(src, width, height, 0, 0, 2, defSpecTexColor); +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); +// updateSubImage1(src, width, height, 0, 0, 0, defBaseTexColor); } public static void updateSubImage(int[] src, int width, int height, int posX, int posY, boolean linear, @@ -632,23 +629,23 @@ public static void updateSubImage(int[] src, int width, int height, int posX, in // not used public static void updateAnimationTextureMap(TextureMap tex, List tasList) { - Iterator iterator; - MultiTexID multiTex = tex.angelica$getMultiTexID(); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - for (iterator = tasList.iterator(); iterator.hasNext();) { - TextureAtlasSprite tas = iterator.next(); - tas.updateAnimation(); - } - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - for (iterator = tasList.iterator(); iterator.hasNext();) { - TextureAtlasSprite tas = iterator.next(); - tas.updateAnimation(); - } - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - for (iterator = tasList.iterator(); iterator.hasNext();) { - TextureAtlasSprite tas = iterator.next(); - tas.updateAnimation(); - } +// Iterator iterator; +// MultiTexID multiTex = tex.angelica$getMultiTexID(); +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); +// for (iterator = tasList.iterator(); iterator.hasNext();) { +// TextureAtlasSprite tas = iterator.next(); +// tas.updateAnimation(); +// } +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); +// for (iterator = tasList.iterator(); iterator.hasNext();) { +// TextureAtlasSprite tas = iterator.next(); +// tas.updateAnimation(); +// } +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); +// for (iterator = tasList.iterator(); iterator.hasNext();) { +// TextureAtlasSprite tas = iterator.next(); +// tas.updateAnimation(); +// } } public static void setupTexture(MultiTexID multiTex, int[] src, int width, int height, boolean linear, @@ -785,66 +782,66 @@ public static int blendColor(int color1, int color2, int factor1) { } public static void loadLayeredTexture(LayeredTexture tex, IResourceManager manager, List list) { - int width = 0; - int height = 0; - int size = 0; - int[] image = null; - Iterator iterator; - for (iterator = list.iterator(); iterator.hasNext();) { - String s = iterator.next(); - if (s != null) { - try { - ResourceLocation location = new ResourceLocation(s); - InputStream inputstream = manager.getResource(location).getInputStream(); - BufferedImage bufimg = ImageIO.read(inputstream); - - if (size == 0) { - width = bufimg.getWidth(); - height = bufimg.getHeight(); - size = width * height; - image = createAIntImage(size, 0x00000000); - } - int[] aint = getIntArray(size * 3); - bufimg.getRGB(0, 0, width, height, aint, 0, width); - loadNSMap(manager, location, width, height, aint); - // merge - for (int i = 0; i < size; ++i) { - int alpha = (aint[i] >>> 24) & 255; - image[size * 0 + i] = blendColor(aint[size * 0 + i], image[size * 0 + i], alpha); - image[size * 1 + i] = blendColor(aint[size * 1 + i], image[size * 1 + i], alpha); - image[size * 2 + i] = blendColor(aint[size * 2 + i], image[size * 2 + i], alpha); - } - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - // init and upload - setupTexture(tex.angelica$getMultiTexID(), image, width, height, false, false); +// int width = 0; +// int height = 0; +// int size = 0; +// int[] image = null; +// Iterator iterator; +// for (iterator = list.iterator(); iterator.hasNext();) { +// String s = iterator.next(); +// if (s != null) { +// try { +// ResourceLocation location = new ResourceLocation(s); +// InputStream inputstream = manager.getResource(location).getInputStream(); +// BufferedImage bufimg = ImageIO.read(inputstream); +// +// if (size == 0) { +// width = bufimg.getWidth(); +// height = bufimg.getHeight(); +// size = width * height; +// image = createAIntImage(size, 0x00000000); +// } +// int[] aint = getIntArray(size * 3); +// bufimg.getRGB(0, 0, width, height, aint, 0, width); +// loadNSMap(manager, location, width, height, aint); +// // merge +// for (int i = 0; i < size; ++i) { +// int alpha = (aint[i] >>> 24) & 255; +// image[size * 0 + i] = blendColor(aint[size * 0 + i], image[size * 0 + i], alpha); +// image[size * 1 + i] = blendColor(aint[size * 1 + i], image[size * 1 + i], alpha); +// image[size * 2 + i] = blendColor(aint[size * 2 + i], image[size * 2 + i], alpha); +// } +// } catch (IOException ex) { +// ex.printStackTrace(); +// } +// } +// } +// // init and upload +// setupTexture(tex.angelica$getMultiTexID(), image, width, height, false, false); } /* update block texture filter +/- items texture */ public static void updateTextureMinMagFilter() { - TextureManager texman = Minecraft.getMinecraft().getTextureManager(); - ITextureObject texObj = texman.getTexture(TextureMap.locationBlocksTexture); - if (texObj != null) { - MultiTexID multiTex = texObj.angelica$getMultiTexID(); - // base texture - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilB]); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilB]); - // norm texture - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilN]); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilN]); - - // spec texture - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilS]); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilS]); - - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); - } +// TextureManager texman = Minecraft.getMinecraft().getTextureManager(); +// ITextureObject texObj = texman.getTexture(TextureMap.locationBlocksTexture); +// if (texObj != null) { +// MultiTexID multiTex = texObj.angelica$getMultiTexID(); +// // base texture +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilB]); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilB]); +// // norm texture +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilN]); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilN]); +// +// // spec texture +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilS]); +// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilS]); +// +// GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); +// } } static IResourceManager resManager = null; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java index 1c7ecacd6..4615a3140 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java @@ -5,7 +5,7 @@ import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourceManagerReloadListener; -public class TextureAtlas extends AbstractTexture implements ITickable, IResourceManagerReloadListener { +public abstract class TextureAtlas extends AbstractTexture implements ITickable, IResourceManagerReloadListener { @Override public void tick() { diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index 3b4eec7a7..265d799f5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -1,7 +1,5 @@ package com.gtnewhorizons.angelica.config; -import org.embeddedt.archaicfix.config.Config; - @Config(modid = "angelica") public class AngelicaConfig { @Config.Comment("Enable Sodium rendering") @@ -9,10 +7,23 @@ public class AngelicaConfig { @Config.RequiresMcRestart public static boolean enableSodium; - @Config.Comment("Enable Iris Shaders") + @Config.Comment("Enable Iris Shaders [Requires Sodium]") @Config.DefaultBoolean(false) @Config.RequiresMcRestart public static boolean enableIris; + @Config.Comment("Tweak F3 screen to be closer to modern versions. [From ArchaicFix]") + @Config.DefaultBoolean(true) + public static boolean modernizeF3Screen; + + @Config.Comment("Show block registry name and meta value in F3, similar to 1.8+. [From ArchaicFix]") + @Config.DefaultBoolean(true) + public static boolean showBlockDebugInfo; + @Config.DefaultBoolean(true) + public static boolean hideDownloadingTerrainScreen; + + @Config.Comment("Show memory usage during game load. [From ArchaicFix]") + @Config.DefaultBoolean(true) + public static boolean showSplashMemoryBar; } diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaGuiConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaGuiConfig.java new file mode 100644 index 000000000..09377919c --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaGuiConfig.java @@ -0,0 +1,9 @@ +package com.gtnewhorizons.angelica.config; + +import net.minecraft.client.gui.GuiScreen; + +public class AngelicaGuiConfig extends SimpleGuiConfig { + public AngelicaGuiConfig(GuiScreen parent) throws ConfigException { + super(parent, AngelicaConfig.class, "archaicfix", "ArchaicFix"); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaGuiConfigFactory.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaGuiConfigFactory.java new file mode 100644 index 000000000..73080f10c --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaGuiConfigFactory.java @@ -0,0 +1,10 @@ +package com.gtnewhorizons.angelica.config; + +import net.minecraft.client.gui.GuiScreen; + +public class AngelicaGuiConfigFactory implements SimpleGuiFactory { + @Override + public Class mainConfigGuiClass() { + return AngelicaGuiConfig.class; + } +} diff --git a/src/main/java/org/embeddedt/archaicfix/config/Config.java b/src/main/java/com/gtnewhorizons/angelica/config/Config.java similarity index 98% rename from src/main/java/org/embeddedt/archaicfix/config/Config.java rename to src/main/java/com/gtnewhorizons/angelica/config/Config.java index 320bca568..647d2e9c7 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/Config.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/Config.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.config; +package com.gtnewhorizons.angelica.config; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -110,4 +110,4 @@ @Target({ElementType.FIELD, ElementType.TYPE}) @interface RequiresWorldRestart { } -} \ No newline at end of file +} diff --git a/src/main/java/org/embeddedt/archaicfix/config/ConfigException.java b/src/main/java/com/gtnewhorizons/angelica/config/ConfigException.java similarity index 87% rename from src/main/java/org/embeddedt/archaicfix/config/ConfigException.java rename to src/main/java/com/gtnewhorizons/angelica/config/ConfigException.java index 64b221797..2be81c802 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/ConfigException.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/ConfigException.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.config; +package com.gtnewhorizons.angelica.config; /** * A really basic wrapper for config to simplify handling them in external code. diff --git a/src/main/java/org/embeddedt/archaicfix/config/ConfigurationManager.java b/src/main/java/com/gtnewhorizons/angelica/config/ConfigurationManager.java similarity index 99% rename from src/main/java/org/embeddedt/archaicfix/config/ConfigurationManager.java rename to src/main/java/com/gtnewhorizons/angelica/config/ConfigurationManager.java index 3a7873d29..7681bb418 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/ConfigurationManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/ConfigurationManager.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.config; +package com.gtnewhorizons.angelica.config; import cpw.mods.fml.client.config.IConfigElement; import cpw.mods.fml.client.event.ConfigChangedEvent; diff --git a/src/main/java/org/embeddedt/archaicfix/config/IConfigElementProxy.java b/src/main/java/com/gtnewhorizons/angelica/config/IConfigElementProxy.java similarity index 98% rename from src/main/java/org/embeddedt/archaicfix/config/IConfigElementProxy.java rename to src/main/java/com/gtnewhorizons/angelica/config/IConfigElementProxy.java index e272681cd..1c4e9638d 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/IConfigElementProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/IConfigElementProxy.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.config; +package com.gtnewhorizons.angelica.config; import cpw.mods.fml.client.config.ConfigGuiType; import cpw.mods.fml.client.config.GuiConfigEntries; diff --git a/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/SimpleGuiConfig.java similarity index 85% rename from src/main/java/org/embeddedt/archaicfix/config/SimpleGuiConfig.java rename to src/main/java/com/gtnewhorizons/angelica/config/SimpleGuiConfig.java index 7e19e2094..8365be361 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/SimpleGuiConfig.java @@ -1,10 +1,9 @@ -package org.embeddedt.archaicfix.config; +package com.gtnewhorizons.angelica.config; import cpw.mods.fml.client.config.GuiConfig; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.resources.I18n; @SideOnly(Side.CLIENT) public class SimpleGuiConfig extends GuiConfig { diff --git a/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiFactory.java b/src/main/java/com/gtnewhorizons/angelica/config/SimpleGuiFactory.java similarity index 93% rename from src/main/java/org/embeddedt/archaicfix/config/SimpleGuiFactory.java rename to src/main/java/com/gtnewhorizons/angelica/config/SimpleGuiFactory.java index ee9b9cac3..9d8560715 100644 --- a/src/main/java/org/embeddedt/archaicfix/config/SimpleGuiFactory.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/SimpleGuiFactory.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.config; +package com.gtnewhorizons.angelica.config; import cpw.mods.fml.client.IModGuiFactory; import cpw.mods.fml.relauncher.Side; diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 2dc008866..0caa85805 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -71,6 +71,7 @@ public class GLStateManager { private static Runnable fogDensityListener = null; // Thread Checking + @Getter private static Thread MainThread; static { diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/LoadControllerHelper.java b/src/main/java/com/gtnewhorizons/angelica/helpers/LoadControllerHelper.java similarity index 99% rename from src/main/java/org/embeddedt/archaicfix/helpers/LoadControllerHelper.java rename to src/main/java/com/gtnewhorizons/angelica/helpers/LoadControllerHelper.java index 880942f7c..92a906696 100644 --- a/src/main/java/org/embeddedt/archaicfix/helpers/LoadControllerHelper.java +++ b/src/main/java/com/gtnewhorizons/angelica/helpers/LoadControllerHelper.java @@ -1,4 +1,4 @@ -package org.embeddedt.archaicfix.helpers; +package com.gtnewhorizons.angelica.helpers; import com.google.common.collect.ListMultimap; import com.google.common.eventbus.EventBus; diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java index 65a6b86de..bb83cdf6c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java @@ -2,7 +2,6 @@ import com.gtnewhorizon.gtnhmixins.ILateMixinLoader; import com.gtnewhorizon.gtnhmixins.LateMixin; -import com.gtnewhorizons.angelica.mixins.ArchaicMixins; import com.gtnewhorizons.angelica.mixins.Mixins; import com.gtnewhorizons.angelica.mixins.TargetedMod; import cpw.mods.fml.common.Loader; @@ -98,10 +97,6 @@ public List getArchaicMixins(Set loadedMods) { TargetedMod t = modById.get(modId); if(t != null) validMods.add(t); } - for(ArchaicMixins mixin : ArchaicMixins.values()) { - if(mixin.getPhase() == ArchaicMixins.Phase.LATE && mixin.shouldLoadSide() && mixin.getFilter().test(validMods)) - mixins.addAll(mixin.getMixins()); - } return mixins; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index 79656f0ff..77920cf20 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -3,7 +3,8 @@ import com.google.common.collect.ImmutableMap; import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader; import com.gtnewhorizons.angelica.config.AngelicaConfig; -import com.gtnewhorizons.angelica.mixins.ArchaicMixins; +import com.gtnewhorizons.angelica.config.ConfigException; +import com.gtnewhorizons.angelica.config.ConfigurationManager; import com.gtnewhorizons.angelica.mixins.Mixins; import com.gtnewhorizons.angelica.mixins.TargetedMod; import cpw.mods.fml.relauncher.FMLLaunchHandler; @@ -14,9 +15,6 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.LoggerConfig; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.config.ConfigException; -import org.embeddedt.archaicfix.config.ConfigurationManager; import org.spongepowered.asm.launch.GlobalProperties; import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper; @@ -26,7 +24,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; @IFMLLoadingPlugin.MCVersion("1.7.10") @IFMLLoadingPlugin.TransformerExclusions("com.gtnewhorizons.angelica.transform.GLStateManagerTransformer") @@ -39,8 +36,6 @@ public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader { try { // Angelica Config ConfigurationManager.registerConfig(AngelicaConfig.class); - // ArchaicFix Config - ConfigurationManager.registerConfig(ArchaicConfig.class); LoggerContext ctx = (LoggerContext) LogManager.getContext(false); Configuration config = ctx.getConfiguration(); LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME); @@ -117,7 +112,7 @@ private List getNotFineMixins(Set loadedCoreMods) { mixins.add("notfine.clouds.MixinGameSettings"); mixins.add("notfine.clouds.MixinRenderGlobal"); mixins.add("notfine.clouds.MixinWorldType"); - + mixins.add("notfine.faceculling.MixinBlock"); mixins.add("notfine.faceculling.MixinBlockSlab"); mixins.add("notfine.faceculling.MixinBlockSnow"); @@ -162,17 +157,4 @@ private static void detectCoreMods(Set loadedCoreMods) { }); } - public List getArchaicMixins(Set loadedCoreMods) { - List mixins = new ArrayList<>(); - detectCoreMods(loadedCoreMods); - LOGGER.info("Detected coremods: [" + coreMods.stream().map(TargetedMod::name).collect(Collectors.joining(", ")) + "]"); - for(ArchaicMixins mixin : ArchaicMixins.values()) { - if(mixin.getPhase() == ArchaicMixins.Phase.EARLY && mixin.shouldLoadSide() && mixin.getFilter().test(coreMods)) { - mixins.addAll(mixin.getMixins()); - } - } - return mixins; - } - - } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java deleted file mode 100644 index f5670d1fa..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/ArchaicMixins.java +++ /dev/null @@ -1,163 +0,0 @@ -package com.gtnewhorizons.angelica.mixins; - -import cpw.mods.fml.relauncher.FMLLaunchHandler; -import lombok.Getter; -import org.embeddedt.archaicfix.config.ArchaicConfig; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Locale; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -public enum ArchaicMixins { - // COMMON MIXINS - common_chickenchunks_MixinPlayerChunkViewerManager(Side.COMMON, Phase.EARLY, require(TargetedMod.CHICKENCHUNKS), "chickenchunks.MixinPlayerChunkViewerManager"), - common_core(Side.COMMON, Phase.EARLY, always(), - "core.AccessorEntityLiving", - "core.MixinASMData", - "core.MixinAxisAlignedBB", - "core.MixinBlock", - "core.MixinChunk", - "core.MixinChunkProviderHell", - "core.MixinChunkProviderServer", - "core.MixinEnchantmentHelper", - "core.MixinEntityLiving", - "core.MixinEntityPlayerMP", - "core.MixinEntityTrackerEntry", - "core.MixinEntityVillager", - "core.MixinEntityXPOrb", - "core.MixinForgeChunkManager", - "core.MixinLongHashMap", - "core.MixinMapGenStructure", - "core.MixinMaterialLiquid", - "core.MixinMerchantRecipe", - "core.MixinSpawnerAnimals", - "core.MixinStructureStart", - "core.MixinWorld", - "core.MixinWorldChunkManager", - "core.MixinWorldServer" - ), - common_core_client(Side.CLIENT, Phase.EARLY, always(), - "core.AccessorSplashProgress", - "core.MixinBlockFence", - "core.MixinChunkProviderClient", - "core.MixinEntityRenderer", - "core.MixinFMLClientHandler", - "core.MixinGuiBeaconButton", - "core.MixinGuiButton", - "core.MixinGuiCreateWorld", - "core.MixinGuiIngameForge", - "core.MixinIntegratedServer", - "core.MixinMinecraft", - "core.MixinNetHandlerPlayClient", - "core.MixinSplashProgress", - "core.MixinThreadDownloadImageData", - "core.MixinRenderItem" - ), - - common_core_MixinModCandidate(Side.COMMON, Phase.EARLY, avoid(TargetedMod.COFHCORE), "core.MixinModCandidate"), - common_core_MixinNetworkDispatcher(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetworkDispatcher"), - common_core_MixinNetworkManager(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetworkManager"), - common_core_MixinEmbeddedChannel(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinEmbeddedChannel"), - common_core_MixinNetHandlerPlayServer(Side.COMMON, Phase.EARLY, always(), "core.MixinNetHandlerPlayServer"), - common_core_MixinObjectIntIdentityMap(Side.COMMON, Phase.EARLY, m -> ArchaicConfig.optimizeObjectIntIdentityMap, "core.MixinObjectIntIdentityMap"), - - common_mrtjp_MixinBlockUpdateHandler(Side.COMMON, Phase.LATE, require(TargetedMod.MRTJPCORE), "mrtjp.MixinBlockUpdateHandler"), - - // CLIENT MIXINS - - - - client_core_MixinSkinManager(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.fixSkinMemoryLeak, "core.MixinSkinManager"), - client_core_MixinWorldRenderer(Side.CLIENT, Phase.EARLY, m -> !Boolean.parseBoolean(System.getProperty("archaicFix.disableMC129", "false")), "core.MixinWorldRenderer"), - - client_core_MixinNetHandlerLoginClient(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.fixLoginRaceCondition, "core.MixinNetHandlerLoginClient"), - - client_lighting_client(Side.CLIENT, Phase.EARLY, phosphor(), - "lighting.MixinMinecraft", - "lighting.MixinWorld", - "lighting.MixinChunkCache"), - - client_lighting_common(Side.COMMON, Phase.EARLY, phosphor(), - "lighting.MixinAnvilChunkLoader", - "lighting.MixinChunk", - "lighting.MixinChunkProviderServer", - "lighting.MixinChunkVanilla", - "lighting.MixinExtendedBlockStorage", - "lighting.MixinSPacketChunkData", - "lighting.MixinWorld_Lighting"), - - client_renderdistance(Side.CLIENT, Phase.EARLY, m -> ArchaicConfig.raiseMaxRenderDistance, - "renderdistance.MixinGameSettings", - "renderdistance.MixinRenderGlobal", - "renderdistance.MixinPlayerManager"), - - common_botania_MixinBlockSpecialFlower(Side.COMMON, Phase.LATE, require(TargetedMod.BOTANIA), "botania.MixinBlockSpecialFlower"), - - common_extrautils(Side.COMMON, Phase.LATE, require(TargetedMod.EXTRAUTILS), - "extrautils.MixinEventHandlerSiege", - "extrautils.MixinEventHandlerServer", - "extrautils.MixinItemDivisionSigil", - "extrautils.MixinTileEntityTrashCan"), - - client_journeymap_MixinTileDrawStep(Side.CLIENT, Phase.LATE, require(TargetedMod.JOURNEYMAP).and(m -> ArchaicConfig.removeJourneymapDebug), "journeymap.MixinTileDrawStep"), - - - // The modFilter argument is a predicate, so you can also use the .and(), .or(), and .negate() methods to mix and match multiple predicates. - ; - - @Getter - public final Side side; - @Getter - public final Phase phase; - - @Getter - public final Predicate> filter; - private final List mixinClasses = new ArrayList<>(); - - ArchaicMixins(Side side, Phase phase, Predicate> filter, String... mixinClasses) { - this.side = side; - this.phase = phase; - this.filter = filter; - this.mixinClasses.addAll(Arrays.asList(mixinClasses)); - } - - static Predicate> phosphor() { - return m -> ArchaicConfig.enablePhosphor; - } - - static Predicate> require(TargetedMod in) { - return modList -> modList.contains(in); - } - - static Predicate> avoid(TargetedMod in) { - return modList -> !modList.contains(in); - } - - static Predicate> always() { - return m -> true; - } - - enum Side { - COMMON, - CLIENT - } - - public enum Phase { - EARLY, - LATE - } - - public boolean shouldLoadSide() { - return (side == Side.COMMON - || (side == Side.CLIENT && FMLLaunchHandler.side().isClient())); - } - - public List getMixins() { - return this.mixinClasses.stream().map((m) -> "archaic." + side.name().toLowerCase(Locale.ROOT) + "." + m).collect(Collectors.toList()); - - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 7e7b9c0ee..632f07592 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -16,6 +16,24 @@ public enum Mixins { "angelica.MixinEntityRenderer" ) ), +// +// ARCHAIC_SPLASH(new Builder("ArchaicFix Splash").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) +// .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.showSplashMemoryBar && false).addMixinClasses( +// "angelica.archaic.MixinSplashProgress" +// ,"angelica.archaic.AccessorSplashProgress" +// ) +// ), +// +// ARCHAIC_CORE(new Builder("Archaic Core").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) +// .setPhase(Phase.EARLY).addMixinClasses( +// "angelica.archaic.MixinBlockFence" +// ,"angelica.archaic.MixinFMLClientHandler" +// ,"angelica.archaic.MixinGuiIngameForge" +// ,"angelica.archaic.MixinNetHandlerPlayClient" +// ,"angelica.archaic.MixinThreadDownloadImageData" +// ) +// ), + IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses( "shaders.startup.MixinGameSettings" @@ -23,7 +41,11 @@ public enum Mixins { ,"shaders.startup.MixinInitRenderer" ) ), - + ANGELICA_ENABLE_DEBUG(new Builder("Angelica Debug").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).setApplyIf(() -> Boolean.parseBoolean(System.getProperty("org.lwjgl.util.Debug", "false"))).addMixinClasses( + "angelica.debug.MixinSplashProgress" + ) + ), SODIUM_STARTUP(new Builder("Start Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodium && !AngelicaConfig.enableIris).addMixinClasses( "sodium.startup.MixinInitDebug" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/AccessorSplashProgress.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/AccessorSplashProgress.java similarity index 88% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/AccessorSplashProgress.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/AccessorSplashProgress.java index efb45d0ca..0d7459ea7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/AccessorSplashProgress.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/AccessorSplashProgress.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; +package com.gtnewhorizons.angelica.mixins.early.angelica.archaic; import cpw.mods.fml.client.SplashProgress; import org.spongepowered.asm.mixin.Mixin; @@ -7,7 +7,7 @@ @SuppressWarnings("deprecation") @Mixin(SplashProgress.class) public interface AccessorSplashProgress { - + @Accessor(remap = false) static int getBarBorderColor() { throw new AssertionError(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinBlockFence.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinBlockFence.java similarity index 91% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinBlockFence.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinBlockFence.java index 7d0fde598..c4e04b06d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinBlockFence.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinBlockFence.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; +package com.gtnewhorizons.angelica.mixins.early.angelica.archaic; import net.minecraft.block.Block; import net.minecraft.block.BlockFence; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinFMLClientHandler.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinFMLClientHandler.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinFMLClientHandler.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinFMLClientHandler.java index 5893d3ece..4d410af81 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinFMLClientHandler.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinFMLClientHandler.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; +package com.gtnewhorizons.angelica.mixins.early.angelica.archaic; import cpw.mods.fml.client.FMLClientHandler; import cpw.mods.fml.client.GuiModList; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiIngameForge.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinGuiIngameForge.java similarity index 85% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiIngameForge.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinGuiIngameForge.java index 1ce5841f3..e9fe26039 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiIngameForge.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinGuiIngameForge.java @@ -1,9 +1,9 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; +package com.gtnewhorizons.angelica.mixins.early.angelica.archaic; import cpw.mods.fml.common.ModContainer; import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.client.GuiIngameForge; -import org.embeddedt.archaicfix.helpers.LoadControllerHelper; +import com.gtnewhorizons.angelica.helpers.LoadControllerHelper; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerPlayClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinNetHandlerPlayClient.java similarity index 79% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerPlayClient.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinNetHandlerPlayClient.java index 6ec605280..e3c3f0301 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerPlayClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinNetHandlerPlayClient.java @@ -1,10 +1,10 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; +package com.gtnewhorizons.angelica.mixins.early.angelica.archaic; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.network.play.INetHandlerPlayClient; -import org.embeddedt.archaicfix.config.ArchaicConfig; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -14,18 +14,18 @@ * teleportation by removing the "Downloading terrain..." screen. This will cause * the player to see partially loaded terrain rather than waiting for the whole * render distance to load, but that's also the vanilla behaviour for same-dimension - * teleportation. + * teleportation. [From ArchaicFix] */ @Mixin(value = NetHandlerPlayClient.class, priority = 500) public abstract class MixinNetHandlerPlayClient implements INetHandlerPlayClient { @Redirect(method = "handleJoinGame", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;displayGuiScreen(Lnet/minecraft/client/gui/GuiScreen;)V")) private void onGuiDisplayJoin(Minecraft mc, GuiScreen guiScreenIn) { - mc.displayGuiScreen(ArchaicConfig.hideDownloadingTerrainScreen ? null : guiScreenIn); + mc.displayGuiScreen(AngelicaConfig.hideDownloadingTerrainScreen ? null : guiScreenIn); } @Redirect(method = "handleRespawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;displayGuiScreen(Lnet/minecraft/client/gui/GuiScreen;)V")) private void onGuiDisplayRespawn(Minecraft mc, GuiScreen guiScreenIn) { - mc.displayGuiScreen(ArchaicConfig.hideDownloadingTerrainScreen ? null : guiScreenIn); + mc.displayGuiScreen(AngelicaConfig.hideDownloadingTerrainScreen ? null : guiScreenIn); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSplashProgress.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinSplashProgress.java similarity index 91% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSplashProgress.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinSplashProgress.java index bff59c450..7b2e2a74a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSplashProgress.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinSplashProgress.java @@ -1,14 +1,14 @@ /* * Based off SplashProgress from Forge 14.23.5.2860. */ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; +package com.gtnewhorizons.angelica.mixins.early.angelica.archaic; import com.gtnewhorizons.angelica.Tags; +import com.gtnewhorizons.angelica.config.AngelicaConfig; +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import cpw.mods.fml.client.SplashProgress; import net.minecraft.client.gui.FontRenderer; import org.apache.commons.lang3.StringUtils; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.embeddedt.archaicfix.config.ArchaicConfig; import org.lwjgl.opengl.Display; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -38,13 +38,14 @@ public class MixinSplashProgress { private static FontRenderer fontRenderer = null; @Inject(method = "run", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", ordinal = 1, remap = false, shift = At.Shift.AFTER), remap = false, require = 0) private void injectDrawMemoryBar(CallbackInfo ci) { + // NOTE: Disable this if you're checking for off thread GL calls via `-Dangelica.assertMainThread=true` if(fontRenderer == null) { try { Field f = SplashProgress.class.getDeclaredField("fontRenderer"); f.setAccessible(true); fontRenderer = (FontRenderer)f.get(null); } catch(ReflectiveOperationException e) { - ArchaicLogger.LOGGER.error(e); + AngelicaTweaker.LOGGER.error(e); return; } } @@ -52,10 +53,10 @@ private void injectDrawMemoryBar(CallbackInfo ci) { glTranslatef(320 - Display.getWidth() / 2 + 4, 240 + Display.getHeight() / 2 - textHeight2, 0); glScalef(2, 2, 1); glEnable(GL_TEXTURE_2D); - fontRenderer.drawString("ArchaicFix " + Tags.VERSION, 0, 0, 0x000000); + fontRenderer.drawString("Angelica " + Tags.VERSION, 0, 0, 0x000000); glDisable(GL_TEXTURE_2D); glPopMatrix(); - if(ArchaicConfig.showSplashMemoryBar) { + if(AngelicaConfig.showSplashMemoryBar) { glPushMatrix(); glTranslatef(320 - (float) barWidth / 2, 20, 0); drawMemoryBar(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinThreadDownloadImageData.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinThreadDownloadImageData.java similarity index 93% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinThreadDownloadImageData.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinThreadDownloadImageData.java index b962c8daf..737052f62 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinThreadDownloadImageData.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinThreadDownloadImageData.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; +package com.gtnewhorizons.angelica.mixins.early.angelica.archaic; import com.google.common.util.concurrent.ThreadFactoryBuilder; import net.minecraft.client.renderer.ThreadDownloadImageData; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/debug/MixinSplashProgress.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/debug/MixinSplashProgress.java new file mode 100644 index 000000000..482e71efa --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/debug/MixinSplashProgress.java @@ -0,0 +1,20 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.debug; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import cpw.mods.fml.client.SplashProgress; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(value = SplashProgress.class, remap = false) +public class MixinSplashProgress { + @WrapOperation(method="Lcpw/mods/fml/client/SplashProgress;start()V", at=@At(value="INVOKE", target="Lcpw/mods/fml/client/SplashProgress;getBool(Ljava/lang/String;Z)Z")) + private static boolean angelica$disableSplashProgress(String name, boolean def, Operation original) { + // Forcibly disable splash progress until we can figure out why it's not working with our debug callback + if(name.equals("enabled")) + return false; + else + return original.call(name, def); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinChunkProviderClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinChunkProviderClient.java deleted file mode 100644 index fc3aff13e..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinChunkProviderClient.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ChunkProviderClient; -import net.minecraft.world.chunk.Chunk; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(ChunkProviderClient.class) -public class MixinChunkProviderClient { - @Inject(method = "loadChunk", at = @At("HEAD")) - private void onChunkLoad(int x, int z, CallbackInfoReturnable cir) { - if(!Minecraft.getMinecraft().func_152345_ab/*isCallingFromMinecraftThread*/()) - throw new IllegalStateException("Attempted to load a chunk off-thread!"); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinEntityRenderer.java deleted file mode 100644 index ca3af32bc..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinEntityRenderer.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; - -import net.minecraft.client.multiplayer.WorldClient; -import net.minecraft.client.renderer.EntityRenderer; -import net.minecraft.util.MovingObjectPosition; -import net.minecraft.util.Vec3; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(value = EntityRenderer.class, priority = 1500) -public abstract class MixinEntityRenderer { - /** @reason Makes the third-person view camera pass through non-solid blocks (fixes https://bugs.mojang.com/browse/MC-30845) */ - // Note: Overlaps with https://github.com/GTNewHorizons/Hodgepodge/blob/master/src/main/java/com/mitchej123/hodgepodge/mixins/early/minecraft/MixinEntityRenderer.java - @Redirect(method = "orientCamera", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;rayTraceBlocks(Lnet/minecraft/util/Vec3;Lnet/minecraft/util/Vec3;)Lnet/minecraft/util/MovingObjectPosition;")) - private MovingObjectPosition rayTraceBlocks(WorldClient world, Vec3 from, Vec3 to) { - return world.func_147447_a(from, to, false, true, true); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiBeaconButton.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiBeaconButton.java deleted file mode 100644 index 5d010882f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiBeaconButton.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.OpenGlHelper; -import org.lwjgl.opengl.GL11; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(targets = { "net/minecraft/client/gui/inventory/GuiBeacon$Button" }) -public class MixinGuiBeaconButton { - /** - * Make transparent beacon buttons look right (e.g. with Modernity). - */ - @Inject(method = "drawButton", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/inventory/GuiBeacon$Button;drawTexturedModalRect(IIIIII)V", ordinal = 1), require = 0) - private void enableTransparency(Minecraft minecraft, int x, int y, CallbackInfo ci) { - GL11.glEnable(GL11.GL_BLEND); - OpenGlHelper.glBlendFunc(770, 771, 1, 0); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiButton.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiButton.java deleted file mode 100644 index 0b08439ef..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiButton.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; - -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiOptionSlider; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(GuiButton.class) -public class MixinGuiButton { - /** - * Make buttons render without yellow text (like in 1.14). - */ - @Redirect(method = "drawButton", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/gui/GuiButton;field_146123_n:Z", ordinal = 1)) - private boolean isHovered(GuiButton button) { - if(!ArchaicConfig.enableNewButtonAppearance || button instanceof GuiOptionSlider) - return button.field_146123_n; - else - return false; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiCreateWorld.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiCreateWorld.java deleted file mode 100644 index 147b81c4f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinGuiCreateWorld.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; - -import net.minecraft.client.gui.GuiCreateWorld; -import net.minecraft.world.storage.ISaveFormat; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(GuiCreateWorld.class) -public class MixinGuiCreateWorld { - @Inject(method = "func_146317_a", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/storage/ISaveFormat;getWorldInfo(Ljava/lang/String;)Lnet/minecraft/world/storage/WorldInfo;"), cancellable = true) - private static void useNumberForCopies(ISaveFormat format, String worldName, CallbackInfoReturnable cir) { - int index = 1; - String finalWorldName = worldName; - while (format.getWorldInfo(finalWorldName) != null) { - finalWorldName = worldName + " (" + index + ")"; - index++; - } - cir.setReturnValue(finalWorldName); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinIntegratedServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinIntegratedServer.java deleted file mode 100644 index e13628f32..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinIntegratedServer.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; - -import net.minecraft.client.settings.GameSettings; -import net.minecraft.server.integrated.IntegratedServer; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(IntegratedServer.class) -public class MixinIntegratedServer { - /** - * Force the integrated server to have a minimum view distance of 8, so mob spawning works correctly. - */ - @Redirect(method = "tick", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/settings/GameSettings;renderDistanceChunks:I")) - private int getRealRenderDistance(GameSettings settings) { - if(ArchaicConfig.fixMobSpawnsAtLowRenderDist) - return Math.max(settings.renderDistanceChunks, 8); - else - return settings.renderDistanceChunks; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinMinecraft.java deleted file mode 100644 index 476bb1e3b..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinMinecraft.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.gui.GuiScreenWorking; -import net.minecraft.client.multiplayer.WorldClient; -import net.minecraft.client.settings.GameSettings; -import net.minecraft.server.integrated.IntegratedServer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(Minecraft.class) -public abstract class MixinMinecraft { - @Shadow private IntegratedServer theIntegratedServer; - - @Shadow public abstract void loadWorld(WorldClient p_71403_1_); - - @Shadow public abstract void displayGuiScreen(GuiScreen p_147108_1_); - - @Shadow public GuiScreen currentScreen; - - /** @reason Makes grass display as fancy regardless of the graphics setting. Matches the appearance of 1.8+ */ - @Redirect(method = "runGameLoop", at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z")) - private boolean getFancyGrass(GameSettings gameSettings) { - return true; - } - - /** @reason Removes a call to {@link System#gc()} to make world loading as fast as possible */ - @Inject(method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V", at = @At(value = "INVOKE", target = "Ljava/lang/System;gc()V"), cancellable = true) - private void onSystemGC(WorldClient worldClient, String reason, CallbackInfo ci) { - ci.cancel(); - } - - @Inject(method = "checkGLError", at = @At("HEAD"), cancellable = true) - private void skipErrorCheck(String msg, CallbackInfo ci) { - ci.cancel(); - } - - @Redirect(method = "launchIntegratedServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;displayGuiScreen(Lnet/minecraft/client/gui/GuiScreen;)V", ordinal = 1)) - private void displayWorkingScreen(Minecraft mc, GuiScreen in) { - mc.displayGuiScreen(new GuiScreenWorking()); - } - - @Inject(method = "launchIntegratedServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/integrated/IntegratedServer;func_147137_ag()Lnet/minecraft/network/NetworkSystem;", ordinal = 0), cancellable = true) - private void checkServerStopped(CallbackInfo ci) { - try { - Thread.sleep(200L); - } - catch (InterruptedException ignored) {} - - if(this.theIntegratedServer.isServerStopped()) { - loadWorld(null); - displayGuiScreen(null); - ci.cancel(); - } - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerLoginClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerLoginClient.java deleted file mode 100644 index 5e5179dbe..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinNetHandlerLoginClient.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; - -import net.minecraft.client.network.NetHandlerLoginClient; -import net.minecraft.network.NetworkManager; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(NetHandlerLoginClient.class) -public class MixinNetHandlerLoginClient { - @Shadow @Final private NetworkManager field_147393_d; - - @Inject(method = "handleLoginSuccess", at=@At("RETURN")) - public void archaic_raceConditionWorkAround(CallbackInfo cb) { - if(ArchaicConfig.fixLoginRaceCondition) - field_147393_d.channel().config().setAutoRead(true); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinRenderItem.java deleted file mode 100644 index a53d65137..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinRenderItem.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; - -import net.minecraft.client.renderer.entity.RenderItem; -import net.minecraft.client.settings.GameSettings; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(value = RenderItem.class, priority = 1001) -public class MixinRenderItem { - @Redirect(method = "renderDroppedItem(Lnet/minecraft/entity/item/EntityItem;Lnet/minecraft/util/IIcon;IFFFFI)V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z")) - private boolean forceFancyGraphics(GameSettings settings) { - return ArchaicConfig.forceFancyItems || settings.fancyGraphics; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSkinManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSkinManager.java deleted file mode 100644 index 9ba6ab4e2..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinSkinManager.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; - -import net.minecraft.client.resources.SkinManager; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(targets = { "net/minecraft/client/resources/SkinManager$2" }) -public class MixinSkinManager { - @Shadow private SkinManager.SkinAvailableCallback field_152636_b; - - /** - * Avoid leaking an EntityClientPlayerMP instance. - */ - @Inject(method = "func_152634_a", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/SkinManager$SkinAvailableCallback;func_152121_a(Lcom/mojang/authlib/minecraft/MinecraftProfileTexture$Type;Lnet/minecraft/util/ResourceLocation;)V", shift = At.Shift.AFTER)) - private void onMakeCallback(CallbackInfo ci) { - field_152636_b = null; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinWorldRenderer.java deleted file mode 100644 index 7fcb205c6..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/core/MixinWorldRenderer.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.core; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.entity.Entity; -import org.embeddedt.archaicfix.interfaces.IWorldRenderer; -import org.lwjgl.opengl.GL11; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.Arrays; - -/* MC-129 */ -@Mixin(WorldRenderer.class) -public abstract class MixinWorldRenderer implements IWorldRenderer { - @Shadow private boolean isInitialized; - @Shadow public boolean needsUpdate; - - @Shadow public abstract float distanceToEntitySquared(Entity p_78912_1_); - - @Shadow public boolean[] skipRenderPass; - - @Shadow private int glRenderList; - - @Shadow private int bytesDrawn; - - public boolean arch$isInView() { - if(Minecraft.getMinecraft().renderViewEntity == null) - return true; - float distance = this.distanceToEntitySquared(Minecraft.getMinecraft().renderViewEntity); - int renderDistanceBlocks = (Minecraft.getMinecraft().gameSettings.renderDistanceChunks) * 16; - return distance <= (renderDistanceBlocks * renderDistanceBlocks); - } - - /** - * Make sure chunks re-render immediately (MC-129). - */ - @Inject(method = "markDirty", at = @At("TAIL")) - private void forceRender(CallbackInfo ci) { - Arrays.fill(this.skipRenderPass, false); - } - - /** - * When switching worlds/dimensions, clear out the old render lists for old chunks. This prevents old dimension - * content from being visible in the new world. - */ - @Inject(method = "setDontDraw", at = @At("TAIL")) - private void clearOldRenderList(CallbackInfo ci) { - if(this.glRenderList == -1 || this.bytesDrawn <= 0) - return; - for(int pass = 0; pass < 2; pass++) { - GL11.glNewList(this.glRenderList + pass, GL11.GL_COMPILE); - GL11.glEndList(); - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinChunkCache.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinChunkCache.java deleted file mode 100644 index 14227f6ce..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinChunkCache.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.lighting; - -import net.minecraft.world.ChunkCache; -import net.minecraft.world.EnumSkyBlock; -import net.minecraft.world.chunk.Chunk; -import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(ChunkCache.class) -public class MixinChunkCache { - @Redirect(method = "getSpecialBlockBrightness", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;getSavedLightValue(Lnet/minecraft/world/EnumSkyBlock;III)I")) - private int getIntrinsicValue(Chunk instance, EnumSkyBlock p_76614_1_, int p_76614_2_, int p_76614_3_, int p_76614_4_) { - return p_76614_1_ == EnumSkyBlock.Sky ? - instance.getSavedLightValue(p_76614_1_, p_76614_2_, p_76614_3_, p_76614_4_) : - LightingHooks.getIntrinsicOrSavedBlockLightValue(instance, p_76614_2_, p_76614_3_, p_76614_4_); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinMinecraft.java deleted file mode 100644 index 9e0110f17..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinMinecraft.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.lighting; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.WorldClient; -import net.minecraft.profiler.Profiler; -import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(Minecraft.class) -public abstract class MixinMinecraft { - - @Shadow @Final public Profiler mcProfiler; - - @Shadow public WorldClient theWorld; - - /** - * @author Angeline - * Forces the client to process light updates before rendering the world. We inject before the call to the profiler - * which designates the start of world rendering. This is a rather injection site. - */ - @Inject(method = "runTick", at = @At(value = "CONSTANT", args = "stringValue=levelRenderer", shift = At.Shift.BY, by = -3)) - private void onRunTick(CallbackInfo ci) { - this.mcProfiler.endStartSection("lighting"); - - ((ILightingEngineProvider) this.theWorld).getLightingEngine().processLightUpdates(); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java deleted file mode 100644 index 85ffad2c5..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/lighting/MixinWorld.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.lighting; - -import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngine; -import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.minecraft.world.EnumSkyBlock; -import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; - -@Mixin(World.class) -public abstract class MixinWorld { - - @SuppressWarnings("unused") - private LightingEngine lightingEngine; - - @Inject(method = "finishSetup", at = @At("RETURN"), remap = false) - private void onConstructed(CallbackInfo ci) { - this.lightingEngine = new LightingEngine((World) (Object) this); - } - - @Redirect(method = { "getSkyBlockTypeBrightness", "getSavedLightValue" }, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;getSavedLightValue(Lnet/minecraft/world/EnumSkyBlock;III)I")) - private int useBlockIntrinsicBrightness(Chunk instance, EnumSkyBlock type, int x, int y, int z) { - if(type == EnumSkyBlock.Block) - return LightingHooks.getIntrinsicOrSavedBlockLightValue(instance, x, y, z); - else - return instance.getSavedLightValue(type, x, y, z); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinGameSettings.java deleted file mode 100644 index 69966ccc3..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinGameSettings.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.renderdistance; - -import net.minecraft.client.settings.GameSettings; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; - -@Mixin(GameSettings.class) -public class MixinGameSettings { - @ModifyConstant(method = "(Lnet/minecraft/client/Minecraft;Ljava/io/File;)V", constant = @Constant(floatValue = 16.0f)) - private float increaseMaxDistance(float old) { - return ArchaicConfig.newMaxRenderDistance; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinRenderGlobal.java deleted file mode 100644 index 343b0851f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/client/renderdistance/MixinRenderGlobal.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.client.renderdistance; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.RenderList; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(value = RenderGlobal.class, priority = -10) -public class MixinRenderGlobal { - @Shadow private RenderList[] allRenderLists; - - @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GLAllocation;generateDisplayLists(I)I"), index = 0) - private int generateDisplayLists(int original) { - int chunkNum = (ArchaicConfig.newMaxRenderDistance * 2) + 2; - return chunkNum * chunkNum * 16 * 3; - } - - @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GLAllocation;createDirectIntBuffer(I)Ljava/nio/IntBuffer;"), index = 0) - private int createOcclusionBuffer(int original) { - int chunkNum = (ArchaicConfig.newMaxRenderDistance * 2) + 2; - return chunkNum * chunkNum * 16; - } - - @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Ljava/nio/IntBuffer;limit(I)Ljava/nio/Buffer;"), index = 0) - private int limitOcclusionBuffer(int i) { - int chunkNum = (ArchaicConfig.newMaxRenderDistance * 2) + 2; - return chunkNum * chunkNum * 16; - } - - @Inject(method = "", at = @At("RETURN")) - private void resizeAllRenderLists(Minecraft p_i1249_1_, CallbackInfo ci) { - int sideLength = Math.max(2, ArchaicConfig.newMaxRenderDistance / 16); - if(allRenderLists.length >= (sideLength * sideLength)) - return; - allRenderLists = new RenderList[sideLength*sideLength]; - for(int i = 0; i < allRenderLists.length; i++) { - allRenderLists[i] = new RenderList(); - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/chickenchunks/MixinPlayerChunkViewerManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/chickenchunks/MixinPlayerChunkViewerManager.java deleted file mode 100644 index 9ea474e34..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/chickenchunks/MixinPlayerChunkViewerManager.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.chickenchunks; - -import codechicken.chunkloader.PlayerChunkViewerManager; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import com.llamalad7.mixinextras.sugar.Share; -import com.llamalad7.mixinextras.sugar.ref.LocalRef; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -@Mixin(PlayerChunkViewerManager.class) -public class MixinPlayerChunkViewerManager { - @Shadow(remap = false) public LinkedList ticketChanges; - - @Redirect(method = "update", at = @At(ordinal = 7, value = "INVOKE", target = "Ljava/util/LinkedList;iterator()Ljava/util/Iterator;"), remap = false) - private Iterator getSafeIterator(LinkedList list, @Share("oldTicketChanges") LocalRef> oldTicketChanges) { - oldTicketChanges.set(new ArrayList<>(list)); - return oldTicketChanges.get().iterator(); - } - - @Redirect(method = "update", at = @At(ordinal = 4, value = "INVOKE", target = "Ljava/util/LinkedList;clear()V"), remap = false) - private void clearListSafely(LinkedList list, @Share("oldTicketChanges") LocalRef> oldTicketChanges) { - this.ticketChanges.removeAll(oldTicketChanges.get()); - oldTicketChanges.set(null); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/AccessorEntityLiving.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/AccessorEntityLiving.java deleted file mode 100644 index 59215a3a63..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/AccessorEntityLiving.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.entity.EntityLiving; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(EntityLiving.class) -public interface AccessorEntityLiving { - @Invoker - public boolean invokeCanDespawn(); - @Invoker - public void invokeDespawnEntity(); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinASMData.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinASMData.java deleted file mode 100644 index 47393852a..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinASMData.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import cpw.mods.fml.common.discovery.ASMDataTable; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; -import zone.rong.rongasm.api.StringPool; - -@Mixin(value = ASMDataTable.ASMData.class, remap = false) -public class MixinASMData { - @Shadow private String annotationName; - - @Shadow private String className; - - @Redirect(method = "", at = @At(value = "FIELD", target = "Lcpw/mods/fml/common/discovery/ASMDataTable$ASMData;annotationName:Ljava/lang/String;")) - private void canonicalizeAnnotation(ASMDataTable.ASMData instance, String value) { - this.annotationName = value == null ? null : StringPool.canonicalize(value); - } - - @Redirect(method = "", at = @At(value = "FIELD", target = "Lcpw/mods/fml/common/discovery/ASMDataTable$ASMData;className:Ljava/lang/String;")) - private void canonicalizeClassName(ASMDataTable.ASMData instance, String value) { - this.className = value == null ? null : StringPool.canonicalize(value); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinAxisAlignedBB.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinAxisAlignedBB.java deleted file mode 100644 index f2f1c31f2..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinAxisAlignedBB.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.util.AxisAlignedBB; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; - -@Mixin(AxisAlignedBB.class) -public class MixinAxisAlignedBB { - private final double XZ_MARGIN = 1E-6; - - @ModifyVariable(method = "calculateXOffset", at = @At(value = "STORE", ordinal = 0), index = 2, argsOnly = true) - private double subXMargin(double old) { - return old - XZ_MARGIN; - } - - @ModifyVariable(method = "calculateXOffset", at = @At(value = "STORE", ordinal = 1), index = 2, argsOnly = true) - private double addXMargin(double old) { - return old + XZ_MARGIN; - } - - @ModifyVariable(method = "calculateZOffset", at = @At(value = "STORE", ordinal = 0), index = 2, argsOnly = true) - private double subZMargin(double old) { - return old - XZ_MARGIN; - } - - @ModifyVariable(method = "calculateZOffset", at = @At(value = "STORE", ordinal = 1), index = 2, argsOnly = true) - private double addZMargin(double old) { - return old + XZ_MARGIN; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinBlock.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinBlock.java deleted file mode 100644 index 96ccbb95d..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinBlock.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.block.Block; -import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(Block.class) -public class MixinBlock { - - @Shadow public Block.SoundType stepSound; - - @Redirect(method = "", at = @At(opcode = Opcodes.PUTFIELD, value = "FIELD", target = "Lnet/minecraft/block/Block;stepSound:Lnet/minecraft/block/Block$SoundType;", ordinal = 0)) - private void onConstruct(Block block, Block.SoundType sound) { - stepSound = sound; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java deleted file mode 100644 index 327e602e6..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunk.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import cpw.mods.fml.common.Loader; -import cpw.mods.fml.common.ModContainer; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.world.ChunkCoordIntPair; -import net.minecraft.world.World; -import net.minecraft.world.biome.BiomeGenBase; -import net.minecraft.world.biome.WorldChunkManager; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.IChunkProvider; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -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.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import com.llamalad7.mixinextras.sugar.Share; -import com.llamalad7.mixinextras.sugar.ref.LocalRef; - -import java.util.ArrayList; -import java.util.Deque; -import java.util.LinkedList; -import java.util.List; - -@Mixin(value = Chunk.class, priority = 1100) -public class MixinChunk { - - @Shadow @Final private List[] entityLists; - @Shadow @Final private World worldObj; - - @Shadow @Final public int xPosition; - - @Shadow @Final public int zPosition; - - @Inject(method = "onChunkUnload", at = @At("HEAD")) - public void handlePlayerChunkUnload(CallbackInfo ci) { - final List players = new ArrayList<>(); - for (final List list : entityLists) { - for (final Entity entity : list) { - if (entity instanceof EntityPlayer) players.add((EntityPlayer) entity); - } - } - for (final EntityPlayer player : players) { - worldObj.updateEntityWithOptionalForce(player, false); - } - } - - @Inject(method = "getBiomeGenForWorldCoords", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/biome/WorldChunkManager;getBiomeGenAt(II)Lnet/minecraft/world/biome/BiomeGenBase;"), cancellable = true) - private void avoidBiomeGenOnClient(int p_76591_1_, int p_76591_2_, WorldChunkManager p_76591_3_, CallbackInfoReturnable cir) { - if (this.worldObj.isRemote) { - cir.setReturnValue(BiomeGenBase.ocean); - } - } - - @Unique - private void logCascadingWorldGeneration(Deque populatingChunk) { - ModContainer activeModContainer = Loader.instance().activeModContainer(); - String format = "{} loaded a new chunk {} in dimension {} ({}) while populating chunk {}, causing cascading worldgen lag."; - - ChunkCoordIntPair pos = new ChunkCoordIntPair(this.xPosition, this.zPosition); - - if (activeModContainer == null) { - ArchaicLogger.LOGGER.warn(format, "Minecraft", pos, this.worldObj.provider.dimensionId, this.worldObj.provider.getDimensionName(), populatingChunk.peek()); - } else { - ArchaicLogger.LOGGER.warn(format, activeModContainer.getName(), pos, this.worldObj.provider.dimensionId, this.worldObj.provider.getDimensionName(), populatingChunk.peek()); - ArchaicLogger.LOGGER.warn("Please report this to the mod's issue tracker. This log can be disabled in the ArchaicFix config."); - } - - if (ArchaicConfig.logCascadingWorldgenStacktrace) { - ArchaicLogger.LOGGER.warn("Stacktrace", new Exception("Cascading world generation")); - } - } - - @Inject(method = "populateChunk", at = @At("HEAD")) - private void savePopulatingChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int x, int z, CallbackInfo ci, @Share("populatingChunk") LocalRef> populatingChunk) { - if(populatingChunk.get() == null) populatingChunk.set(new LinkedList<>()); - if (populatingChunk.get().size() > 0 && ArchaicConfig.logCascadingWorldgen) logCascadingWorldGeneration(populatingChunk.get()); - populatingChunk.get().push(new ChunkCoordIntPair(x, z)); - } - - @Inject(method = "populateChunk", at = @At("TAIL")) - private void restorePopulatingChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int p_76624_3_, int p_76624_4_, CallbackInfo ci, @Share("populatingChunk") LocalRef> populatingChunk) { - populatingChunk.get().pop(); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderHell.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderHell.java deleted file mode 100644 index e73e1a1d0..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderHell.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.world.World; -import net.minecraft.world.gen.ChunkProviderHell; -import net.minecraft.world.gen.feature.WorldGenHellLava; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.Random; - -@Mixin(ChunkProviderHell.class) -public class MixinChunkProviderHell { - @Redirect(method = "populate", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/gen/feature/WorldGenHellLava;generate(Lnet/minecraft/world/World;Ljava/util/Random;III)Z", ordinal = 1)) - private boolean applyOffsetIfConfigured(WorldGenHellLava gen, World world, Random random, int x, int y, int z) { - int offset = ArchaicConfig.fixVanillaCascadingWorldgen ? 8 : 0; - return gen.generate(world, random, x + offset, y, z + offset); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderServer.java deleted file mode 100644 index 3b2cc0f90..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinChunkProviderServer.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.world.WorldServer; -import net.minecraft.world.biome.WorldChunkManager; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.IChunkProvider; -import net.minecraft.world.gen.ChunkProviderServer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(ChunkProviderServer.class) -public abstract class MixinChunkProviderServer { - - @Shadow public WorldServer worldObj; - - @Redirect(method = "originalLoadChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/IChunkProvider;provideChunk(II)Lnet/minecraft/world/chunk/Chunk;", remap = true), remap = false) - private Chunk populateChunkWithBiomes(IChunkProvider instance, int chunkX, int chunkZ) { - final Chunk chunk = instance.provideChunk(chunkX, chunkZ); - if(chunk != null) { - final WorldChunkManager manager = chunk.worldObj.getWorldChunkManager(); - for(int z = 0; z < 16; z++) { - for(int x = 0; x < 16; x++) { - chunk.getBiomeGenForWorldCoords(x, z, manager); - } - } - } - return chunk; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEmbeddedChannel.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEmbeddedChannel.java deleted file mode 100644 index 94ff96b6a..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEmbeddedChannel.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import io.netty.channel.AbstractChannel; -import io.netty.channel.Channel; -import io.netty.channel.ChannelConfig; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelPromise; -import io.netty.channel.embedded.EmbeddedChannel; -import io.netty.util.ReferenceCountUtil; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.nio.channels.ClosedChannelException; -import java.util.AbstractMap; -import java.util.ArrayDeque; -import java.util.Queue; - -@Mixin(EmbeddedChannel.class) -public abstract class MixinEmbeddedChannel extends AbstractChannel { - private MixinEmbeddedChannel(Channel parent) { - super(parent); - } - - @Shadow(remap = false) public abstract ChannelConfig config(); - - @Shadow(remap = false) private Throwable lastException; - /** - * Used to simulate socket buffers. When autoRead is false, all inbound information will be temporarily stored here. - */ - private Queue> tempInboundMessages; - - private Queue> tempInboundMessages() { - if (tempInboundMessages == null) { - tempInboundMessages = new ArrayDeque<>(); - } - return tempInboundMessages; - } - - @Inject(method = "writeInbound", at = @At(value = "INVOKE", target = "Lio/netty/channel/embedded/EmbeddedChannel;pipeline()Lio/netty/channel/ChannelPipeline;"), cancellable = true, remap = false) - private void storeMsgs(Object[] msgs, CallbackInfoReturnable cir) { - if (!config().isAutoRead()) { - Queue> tempInboundMessages = tempInboundMessages(); - for (Object msg : msgs) { - tempInboundMessages.add(new AbstractMap.SimpleEntry<>(msg, null)); - } - cir.setReturnValue(false); - } - } - - private static boolean isNotEmpty(Queue queue) { - return queue != null && !queue.isEmpty(); - } - - @Inject(method = "doClose", at = @At("RETURN"), remap = false) - private void handleInboundClosing(CallbackInfo ci) { - if (isNotEmpty(tempInboundMessages)) { - ClosedChannelException exception = null; - for (;;) { - AbstractMap.SimpleEntry entry = tempInboundMessages.poll(); - if (entry == null) { - break; - } - Object value = entry.getKey(); - if (value != null) { - ReferenceCountUtil.release(value); - } - ChannelPromise promise = entry.getValue(); - if (promise != null) { - if (exception == null) { - exception = new ClosedChannelException(); - } - promise.tryFailure(exception); - } - } - } - } - - private ChannelFuture checkException(ChannelPromise promise) { - Throwable t = lastException; - if (t != null) { - lastException = null; - - return promise.setFailure(t); - } - - return promise.setSuccess(); - } - - @Inject(method = "doBeginRead", at = @At("HEAD"), remap = false) - private void readTmpInbounds(CallbackInfo ci) { - // read from tempInboundMessages and fire channelRead. - if (isNotEmpty(tempInboundMessages)) { - for (;;) { - AbstractMap.SimpleEntry pair = tempInboundMessages.poll(); - if (pair == null) { - break; - } - - Object msg = pair.getKey(); - if (msg != null) { - pipeline().fireChannelRead(msg); - } - - ChannelPromise promise = pair.getValue(); - if (promise != null) { - checkException(promise); - } - } - - // fire channelReadComplete. - flush(); - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEnchantmentHelper.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEnchantmentHelper.java deleted file mode 100644 index 5a1cc35b6..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEnchantmentHelper.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.enchantment.EnchantmentHelper; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.item.ItemStack; -import net.minecraft.util.DamageSource; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(EnchantmentHelper.class) -public class MixinEnchantmentHelper { - @Shadow @Final private static EnchantmentHelper.ModifierDamage enchantmentModifierDamage; - - @Shadow @Final private static EnchantmentHelper.HurtIterator field_151388_d; - - @Shadow @Final private static EnchantmentHelper.DamageIterator field_151389_e; - - @Inject(method = "getEnchantmentModifierDamage", at = @At("RETURN")) - private static void clearWorldReference1(ItemStack[] p_77508_0_, DamageSource p_77508_1_, CallbackInfoReturnable cir) { - enchantmentModifierDamage.source = null; - } - - @Inject(method = "func_151384_a", at = @At("RETURN")) - private static void clearWorldReference2(EntityLivingBase p_151384_0_, Entity p_151384_1_, CallbackInfo ci) { - field_151388_d.field_151363_b = null; - field_151388_d.field_151364_a = null; - } - - @Inject(method = "func_151385_b", at = @At("RETURN")) - private static void clearWorldReference3(EntityLivingBase p_151385_0_, Entity p_151385_1_, CallbackInfo ci) { - field_151389_e.field_151366_a = null; - field_151389_e.field_151365_b = null; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java deleted file mode 100644 index 5a2d6b075..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityLiving.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.world.World; -import net.minecraft.world.WorldServer; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; - -@Mixin(EntityLiving.class) -public abstract class MixinEntityLiving extends EntityLivingBase { - private MixinEntityLiving(World p_i1594_1_) { - super(p_i1594_1_); - } - - @ModifyConstant(method = "despawnEntity", constant = @Constant(doubleValue = 16384.0D)) - private double lowerHardRange(double old) { - if(!ArchaicConfig.fixMobSpawnsAtLowRenderDist) - return old; - if(worldObj.isRemote) - return old; - if(((WorldServer)worldObj).func_73046_m().getConfigurationManager().getViewDistance() < 10) - return 96 * 96; - return old; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityPlayerMP.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityPlayerMP.java deleted file mode 100644 index 0ba6051ee..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityPlayerMP.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import com.mojang.authlib.GameProfile; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.management.ItemInWorldManager; -import net.minecraft.world.World; -import net.minecraft.world.WorldServer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(EntityPlayerMP.class) -public abstract class MixinEntityPlayerMP extends EntityPlayer { - - private MixinEntityPlayerMP(World worldIn, GameProfile gameProfileIn) {super(worldIn, gameProfileIn);} - - /** - * @reason This is incorrectly set to 1, but not noticable in vanilla since the move logic - * trusts the client about its y position after a move due to a bug: (y > -0.5 || y - * < 0.5) rather than &&. If this is fixed, a player standing in moving water at the - * edge of a block is considered to have "moved wrongly" and teleported onto the block. - *

- * Leaving this to 1 would also allow hacked clients to step up blocks without having - * to jump (not increasing hunger). - */ - @Inject(method = "", at = @At("RETURN")) - private void afterInit(MinecraftServer server, WorldServer worldIn, GameProfile profile, ItemInWorldManager interactionManagerIn, CallbackInfo ci) { - stepHeight = 0.7F; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityTrackerEntry.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityTrackerEntry.java deleted file mode 100644 index 84a3b329b..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityTrackerEntry.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLeashKnot; -import net.minecraft.entity.EntityTrackerEntry; -import net.minecraft.entity.item.EntityItemFrame; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.projectile.EntityArrow; -import net.minecraft.network.Packet; -import net.minecraft.network.play.server.S0CPacketSpawnPlayer; -import net.minecraft.network.play.server.S0EPacketSpawnObject; -import net.minecraft.network.play.server.S11PacketSpawnExperienceOrb; -import net.minecraft.network.play.server.S18PacketEntityTeleport; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyVariable; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import java.util.List; - -@Mixin(EntityTrackerEntry.class) -public class MixinEntityTrackerEntry { - @Shadow public int lastScaledXPosition, lastScaledYPosition, lastScaledZPosition; - - @Shadow public int lastYaw; - - @Shadow public int lastPitch; - - @Shadow public Entity myEntity; - - @Shadow public int ticks; - - @Inject(method = "sendLocationToAllClients", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/EntityTrackerEntry;sendMetadataToAllAssociatedPlayers()V", ordinal = 1, shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD) - private void saveIfTeleported(List clientList, CallbackInfo ci, int i, int j, int k, int l, int i1, int j1, int k1, int l1, Object object) { - if(object instanceof S18PacketEntityTeleport) { - this.lastScaledXPosition = i; - this.lastScaledYPosition = j; - this.lastScaledZPosition = k; - this.lastYaw = l; - this.lastPitch = i1; - } - } - - @Inject(method = "func_151260_c", at = @At("RETURN"), cancellable = true) - private void useCorrectSpawnPosition(CallbackInfoReturnable cir) { - if (!(this.myEntity instanceof EntityItemFrame) && !(this.myEntity instanceof EntityLeashKnot)) { - Packet packet = cir.getReturnValue(); - if(packet instanceof S0EPacketSpawnObject) { - S0EPacketSpawnObject spawnObject = (S0EPacketSpawnObject)packet; - spawnObject.func_148996_a(this.lastScaledXPosition); - spawnObject.func_148995_b(this.lastScaledYPosition); - spawnObject.func_149005_c(this.lastScaledZPosition); - } else if(packet instanceof S0CPacketSpawnPlayer) { - S0CPacketSpawnPlayer spawnPlayer = (S0CPacketSpawnPlayer)packet; - spawnPlayer.field_148956_c = this.lastScaledXPosition; - spawnPlayer.field_148953_d = this.lastScaledYPosition; - spawnPlayer.field_148954_e = this.lastScaledZPosition; - } else if(packet instanceof S11PacketSpawnExperienceOrb) { - S11PacketSpawnExperienceOrb spawnXpOrb = (S11PacketSpawnExperienceOrb)packet; - spawnXpOrb.field_148990_b = this.lastScaledXPosition; - spawnXpOrb.field_148991_c = this.lastScaledYPosition; - spawnXpOrb.field_148988_d = this.lastScaledZPosition; - } - } - } - - private boolean arch$wouldSendPacket() { - return (this.ticks > 0 || this.myEntity instanceof EntityArrow); - } - - @ModifyVariable(method = "sendLocationToAllClients", at = @At("STORE"), index = 11, name = "flag") - private boolean avoidSavingIfPacketNotSent1(boolean incoming) { - return incoming && arch$wouldSendPacket(); - } - - @ModifyVariable(method = "sendLocationToAllClients", at = @At("STORE"), index = 12, name = "flag1") - private boolean avoidSavingIfPacketNotSent2(boolean incoming) { - return incoming && arch$wouldSendPacket(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityVillager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityVillager.java deleted file mode 100644 index b8b30e925..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityVillager.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - - -import net.minecraft.entity.passive.EntityVillager; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.village.MerchantRecipe; -import net.minecraft.village.MerchantRecipeList; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(EntityVillager.class) -public class MixinEntityVillager { - @Shadow private MerchantRecipeList buyingList; - - @Shadow private int timeUntilReset; - - @Shadow private boolean needsInitilization; - - @Inject(method = "readEntityFromNBT", at = @At("TAIL")) - private void handleLockedVillager(NBTTagCompound compound, CallbackInfo ci) { - if(compound.hasKey("archTimeToReset")) { - this.timeUntilReset = compound.getInteger("archTimeToReset"); - this.needsInitilization = this.timeUntilReset > 0; - } else if(this.buyingList != null) { - // FIX: Robustness, and fixes accumulated bugged merchants: - if (((MerchantRecipe) this.buyingList.get(this.buyingList.size() - 1)).isRecipeDisabled()) { - this.timeUntilReset = 40; - this.needsInitilization = true; - } - } - } - - @Inject(method = "writeEntityToNBT", at = @At("TAIL")) - private void persistResetTime(NBTTagCompound compound, CallbackInfo ci) { - compound.setInteger("archTimeToReset", this.timeUntilReset); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityXPOrb.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityXPOrb.java deleted file mode 100644 index b5268bb42..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinEntityXPOrb.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.entity.item.EntityXPOrb; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; - -@Mixin(EntityXPOrb.class) -public class MixinEntityXPOrb { - @ModifyConstant(method = "(Lnet/minecraft/world/World;DDDI)V", constant = @Constant(floatValue = 0.5f)) - private float useSmallerSizeAlways(float old) { - return 0.25f; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinForgeChunkManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinForgeChunkManager.java deleted file mode 100644 index d58e49e5f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinForgeChunkManager.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import cpw.mods.fml.common.Loader; -import net.minecraft.world.World; -import net.minecraft.world.WorldServer; -import net.minecraftforge.common.ForgeChunkManager; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.embeddedt.archaicfix.helpers.ChickenChunkHelper; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(ForgeChunkManager.class) -public class MixinForgeChunkManager { - @Inject(method = "loadWorld", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ArrayListMultimap;keySet()Ljava/util/Set;", ordinal = 0), cancellable = true, remap = false) - private static void callCCLoadHandler(World world, CallbackInfo ci) { - if(!world.isRemote && Loader.isModLoaded("ChickenChunks")) { - try { - ChickenChunkHelper.load((WorldServer)world); - } catch (Exception e) { - ArchaicLogger.LOGGER.error("An exception occured while loading CC data", e); - } - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinLongHashMap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinLongHashMap.java deleted file mode 100644 index 28bb99fb0..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinLongHashMap.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.util.LongHashMap; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -@Mixin(LongHashMap.class) -public abstract class MixinLongHashMap { - /** - * @author embeddedt - * @reason Use a better hash (from TMCW) that avoids collisions. - */ - @Overwrite - private static int getHashedKey(long par0) - { - return (int)par0 + (int)(par0 >>> 32) * 92821; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMapGenStructure.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMapGenStructure.java deleted file mode 100644 index 316ed69be..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMapGenStructure.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import com.google.common.collect.ImmutableList; -import net.minecraft.world.gen.structure.MapGenStructure; -import net.minecraft.world.gen.structure.StructureStart; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.Collection; -import java.util.Map; - -@Mixin(MapGenStructure.class) -public abstract class MixinMapGenStructure { - - @Redirect(method = { "func_143028_c", "func_142038_b", "func_151545_a", "generateStructuresInChunk" }, at = @At(value = "INVOKE", target = "Ljava/util/Map;values()Ljava/util/Collection;")) - private Collection getStructureMapValues(Map structureMap) { - return ImmutableList.copyOf(structureMap.values()); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMaterialLiquid.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMaterialLiquid.java deleted file mode 100644 index 1ca4eaef1..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMaterialLiquid.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.block.material.MapColor; -import net.minecraft.block.material.Material; -import net.minecraft.block.material.MaterialLiquid; -import org.spongepowered.asm.mixin.Mixin; - -@Mixin(MaterialLiquid.class) -public abstract class MixinMaterialLiquid extends Material { - private MixinMaterialLiquid(MapColor p_i2116_1_) { - super(p_i2116_1_); - } - - @Override - public boolean getCanBlockGrass() { - return false; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMerchantRecipe.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMerchantRecipe.java deleted file mode 100644 index a336af4fa..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinMerchantRecipe.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.item.ItemStack; -import net.minecraft.village.MerchantRecipe; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(MerchantRecipe.class) -public class MixinMerchantRecipe { - @Shadow private ItemStack itemToBuy; - - @Shadow private ItemStack secondItemToBuy; - - @Inject(method = "(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;)V", at = @At("RETURN")) - private void capItemAmounts(ItemStack p_i1941_1_, ItemStack p_i1941_2_, ItemStack p_i1941_3_, CallbackInfo ci) { - if(this.itemToBuy != null) - this.itemToBuy.stackSize = Math.min(this.itemToBuy.stackSize, this.itemToBuy.getMaxStackSize()); - if(this.secondItemToBuy != null) - this.secondItemToBuy.stackSize = Math.min(this.secondItemToBuy.stackSize, this.secondItemToBuy.getMaxStackSize()); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinModCandidate.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinModCandidate.java deleted file mode 100644 index 48339583a..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinModCandidate.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import cpw.mods.fml.common.discovery.ASMDataTable; -import cpw.mods.fml.common.discovery.ModCandidate; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; -import speiger.src.collections.objects.sets.ObjectOpenHashSet; -import zone.rong.rongasm.api.StringPool; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/* based on LoliASM */ -@Mixin(ModCandidate.class) -public class MixinModCandidate { - @Shadow(remap = false) private List packages; - @Shadow(remap = false) private Set foundClasses; - @Shadow(remap = false) private ASMDataTable table; - private Set packageSet; - - @Redirect(method = "(Ljava/io/File;Ljava/io/File;Lcpw/mods/fml/common/discovery/ContainerType;ZZ)V", at = @At(value = "FIELD", target = "Lcpw/mods/fml/common/discovery/ModCandidate;packages:Ljava/util/List;", remap = false), remap = false) - private void avoidPackageList(ModCandidate instance, List value) { - this.packages = null; - packageSet = new ObjectOpenHashSet<>(); - } - - /** - * @author embeddedt - * @reason more efficient storage - */ - @Overwrite(remap = false) - public void addClassEntry(String name) { - String className = name.substring(0, name.lastIndexOf('.')); - this.foundClasses.add(className); - className = className.replace('/','.'); - int pkgIdx = className.lastIndexOf('.'); - if (pkgIdx > -1) { - String pkg = StringPool.canonicalize(className.substring(0, pkgIdx)); - packageSet.add(pkg); - table.registerPackage((ModCandidate)(Object)this, pkg); - } - } - - /** - * @author embeddedt - * @reason avoid storing packages as a list - */ - @Overwrite(remap = false) - public List getContainedPackages() { - return new ArrayList<>(packageSet); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetHandlerPlayServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetHandlerPlayServer.java deleted file mode 100644 index c7481e813..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetHandlerPlayServer.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.network.NetHandlerPlayServer; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyArg; - -@Mixin(NetHandlerPlayServer.class) -public class MixinNetHandlerPlayServer { - @ModifyArg(method = "processPlayerBlockPlacement", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/EntityPlayerMP;getDistanceSq(DDD)D", ordinal = 0), index = 1) - private double adjustForEyeHeight(double y) { - if(ArchaicConfig.fixPlacementFlicker) - return y - 1.5; - else - return y; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkDispatcher.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkDispatcher.java deleted file mode 100644 index 02e824999..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkDispatcher.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import cpw.mods.fml.common.network.handshake.NetworkDispatcher; -import cpw.mods.fml.relauncher.Side; -import io.netty.channel.ChannelConfig; -import net.minecraft.network.EnumConnectionState; -import net.minecraft.network.NetworkManager; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.interfaces.IArchaicNetworkManager; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(NetworkDispatcher.class) -public class MixinNetworkDispatcher { - @Shadow(remap = false) @Final private Side side; - - @Redirect(method = "clientListenForServerHandshake", at = @At(value = "INVOKE", remap = true, target = - "Lnet/minecraft/network/NetworkManager;setConnectionState(Lnet/minecraft/network/EnumConnectionState;)V")) - public void archaic_raceConditionWorkAround1(NetworkManager self, EnumConnectionState state) { - if(ArchaicConfig.fixLoginRaceCondition) - ((IArchaicNetworkManager)self).setConnectionStateWithoutAutoRead(state); - else - self.setConnectionState(state); - } - - @Redirect(method = "handlerAdded", at = @At(value = "INVOKE", target = - "Lio/netty/channel/ChannelConfig;setAutoRead(Z)Lio/netty/channel/ChannelConfig;"), remap = false) - public ChannelConfig archaic_raceConditionWorkAround2(ChannelConfig self, boolean autoRead) { - if (ArchaicConfig.fixLoginRaceCondition && side == Side.CLIENT) { - autoRead = false; - } - return self.setAutoRead(autoRead); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkManager.java deleted file mode 100644 index 560d04e55..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNetworkManager.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import io.netty.channel.Channel; -import net.minecraft.network.EnumConnectionState; -import net.minecraft.network.NetworkManager; -import org.embeddedt.archaicfix.interfaces.IArchaicNetworkManager; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(NetworkManager.class) -public class MixinNetworkManager implements IArchaicNetworkManager { - - @Shadow private EnumConnectionState connectionState; - - @Shadow private Channel channel; - - @Shadow @Final private boolean isClientSide; - - @Override - public void setConnectionStateWithoutAutoRead(EnumConnectionState state) { - this.connectionState = (EnumConnectionState)this.channel.attr(NetworkManager.attrKeyConnectionState).getAndSet(state); - this.channel.attr(NetworkManager.attrKeyReceivable).set(state.func_150757_a(this.isClientSide)); - this.channel.attr(NetworkManager.attrKeySendable).set(state.func_150754_b(this.isClientSide)); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNextTickListEntry.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNextTickListEntry.java deleted file mode 100644 index 081fbb361..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinNextTickListEntry.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.block.Block; -import net.minecraft.world.NextTickListEntry; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(NextTickListEntry.class) -public class MixinNextTickListEntry { - @Shadow public int xCoord; - - @Shadow public int yCoord; - - @Shadow public int zCoord; - - @Shadow @Final private Block field_151352_g; - - @Inject(method = "compareTo(Lnet/minecraft/world/NextTickListEntry;)I", at = @At("RETURN")) - private void considerCoordinatesForEquality(NextTickListEntry other, CallbackInfoReturnable cir) { - if(ArchaicConfig.fixTickListSynchronization && cir.getReturnValue() == 0) { - int myCoords = this.xCoord + this.yCoord + this.zCoord; - int theirCoords = other.xCoord + other.yCoord + other.zCoord; - int diff = theirCoords - myCoords; - if(diff != 0) - cir.setReturnValue(diff); - else { - Block b1 = other.func_151351_a(); - Block b2 = this.field_151352_g; - if(b1 != b2) - cir.setReturnValue(Block.getIdFromBlock(b1) - Block.getIdFromBlock(b2)); - } - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinObjectIntIdentityMap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinObjectIntIdentityMap.java deleted file mode 100644 index 72c1faca0..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinObjectIntIdentityMap.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.util.ObjectIntIdentityMap; -import org.embeddedt.archaicfix.helpers.UnexpectionalObjectArrayList; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.List; - -@Mixin(ObjectIntIdentityMap.class) -public class MixinObjectIntIdentityMap { - - @Shadow protected List field_148748_b; - - @Inject(method = "", at = @At("RETURN")) - private void initIdArray(CallbackInfo ci) { - this.field_148748_b = new UnexpectionalObjectArrayList<>(); - } - - /** - * @author embeddedt - * @reason Avoid unnecessary range checks - * @param id ID - * @return object if ID is valid, else null - */ - @Overwrite - public Object func_148745_a(int id) { - return ((UnexpectionalObjectArrayList)field_148748_b).getOrNull(id); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinSpawnerAnimals.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinSpawnerAnimals.java deleted file mode 100644 index ebd7dc67c..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinSpawnerAnimals.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.entity.Entity; -import net.minecraft.world.ChunkCoordIntPair; -import net.minecraft.world.SpawnerAnimals; -import net.minecraft.world.World; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.HashMap; - -@Mixin(SpawnerAnimals.class) -public class MixinSpawnerAnimals { - @Shadow private HashMap eligibleChunksForSpawning; - - @ModifyConstant(method = "findChunksForSpawning", constant = @Constant(doubleValue = 24.0D)) - private double lowerSpawnRange(double old) { - return ArchaicConfig.fixMobSpawnsAtLowRenderDist ? 16 : old; - } - - @Redirect(method = "performWorldGenSpawning", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;spawnEntityInWorld(Lnet/minecraft/entity/Entity;)Z")) - private static boolean checkForCollision(World world, Entity instance) { - if(!ArchaicConfig.preventEntitySuffocationWorldgen || world.getCollidingBoundingBoxes(instance, instance.boundingBox).isEmpty()) { - return world.spawnEntityInWorld(instance); - } - return false; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinStructureStart.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinStructureStart.java deleted file mode 100644 index 8ad5c5517..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinStructureStart.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.world.gen.structure.StructureComponent; -import net.minecraft.world.gen.structure.StructureStart; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.LinkedList; - -@Mixin(StructureStart.class) -public class MixinStructureStart { - @Redirect(method = "generateStructure", at = @At(value = "FIELD", target = "Lnet/minecraft/world/gen/structure/StructureStart;components:Ljava/util/LinkedList;", ordinal = 0)) - private LinkedList debugStructureCME(StructureStart instance) { - return new LinkedList<>((LinkedList)instance.getComponents()); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorld.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorld.java deleted file mode 100644 index 20c45572b..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorld.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import com.google.common.collect.ImmutableSet; -import cpw.mods.fml.common.FMLCommonHandler; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityList; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.MathHelper; -import net.minecraft.world.World; -import net.minecraft.world.biome.BiomeGenBase; -import net.minecraft.world.biome.WorldChunkManager; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.IChunkProvider; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngineHelpers; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import java.util.List; -import java.util.Set; - -@Mixin(World.class) -public abstract class MixinWorld { - @Shadow public boolean isRemote; - - @Shadow public List playerEntities; - - @Shadow protected IChunkProvider chunkProvider; - - @Redirect(method = "getBiomeGenForCoordsBody", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/biome/WorldChunkManager;getBiomeGenAt(II)Lnet/minecraft/world/biome/BiomeGenBase;")) - private BiomeGenBase skipBiomeGenOnClient(WorldChunkManager manager, int x, int z) { - if(this.isRemote) - return BiomeGenBase.ocean; - else - return manager.getBiomeGenAt(x, z); - } - - private Set entityOptimizationIgnoreSet = null; - - @Inject(method = "updateEntityWithOptionalForce", at = @At(value = "FIELD", target = "Lnet/minecraft/entity/Entity;lastTickPosX:D", ordinal = 0), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) - private void skipUpdateIfOptimizing(Entity entity, boolean force, CallbackInfo ci, int chunkX, int chunkZ, boolean isInForcedChunk) { - if(!ArchaicConfig.optimizeEntityTicking) - return; - if (isRemote || isInForcedChunk || !(entity instanceof EntityLivingBase) || entity instanceof EntityPlayer || !entity.addedToChunk) { - return; - } - if(entityOptimizationIgnoreSet == null) - entityOptimizationIgnoreSet = ImmutableSet.copyOf(ArchaicConfig.optimizeEntityTickingIgnoreList); - if(entityOptimizationIgnoreSet.contains(EntityList.getEntityString(entity))) - return; - double finalDist = Double.MAX_VALUE; - for(EntityPlayer player : (List)entity.worldObj.playerEntities) { - finalDist = Math.min(finalDist, player.getDistanceSq(entity.posX, entity.posY, entity.posZ)); - if(finalDist <= ArchaicConfig.optimizeEntityTickingDistance) - break; - } - if(((EntityLivingBase)entity).deathTime <= 0 && finalDist > ArchaicConfig.optimizeEntityTickingDistance) { - if(entity instanceof EntityLiving && ((AccessorEntityLiving)entity).invokeCanDespawn()) { - /* Despawn even if outside the ticking range */ - ((AccessorEntityLiving)entity).invokeDespawnEntity(); - } - ci.cancel(); - } - } - - @Inject(method = "setActivePlayerChunksAndCheckLight", at = @At("TAIL")) - private void saveInactiveChunks(CallbackInfo ci) { - if(this.isRemote || ArchaicConfig.optimizeBlockTickingDistance <= 0) - return; - int renderDistance = FMLCommonHandler.instance().getMinecraftServerInstance().getConfigurationManager().getViewDistance(); - if(renderDistance <= ArchaicConfig.optimizeBlockTickingDistance) - return; - EntityPlayer entityplayer; - int j; - int k; - - int activeDistance = ArchaicConfig.optimizeBlockTickingDistance; - - for (Object playerEntity : this.playerEntities) { - entityplayer = (EntityPlayer) playerEntity; - j = MathHelper.floor_double(entityplayer.posX / 16.0D); - k = MathHelper.floor_double(entityplayer.posZ / 16.0D); - - for (int offX = -renderDistance; offX <= renderDistance; ++offX) { - for (int offZ = -renderDistance; offZ <= renderDistance; ++offZ) { - if (Math.abs(offX) <= activeDistance && Math.abs(offZ) <= activeDistance) continue; - Chunk chunk = LightingEngineHelpers.getLoadedChunk(this.chunkProvider, offX + j, offZ + k); - if (chunk != null && !chunk.func_150802_k()) { - chunk.func_150804_b(false); - } - } - } - } - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldChunkManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldChunkManager.java deleted file mode 100644 index 6f6a9e928..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldChunkManager.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.world.World; -import net.minecraft.world.biome.BiomeCache; -import net.minecraft.world.biome.BiomeGenBase; -import net.minecraft.world.biome.WorldChunkManager; -import net.minecraft.world.gen.layer.GenLayer; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(WorldChunkManager.class) -public class MixinWorldChunkManager { - @Shadow private BiomeCache biomeCache; - - @Shadow private GenLayer genBiomes; - - @Shadow private GenLayer biomeIndexLayer; - - private World clientWorld = null; - - @Inject(method = "(Lnet/minecraft/world/World;)V", at = @At("RETURN")) - private void noCacheOnClient(World world, CallbackInfo ci) { - if(world.isRemote) { - /* Make sure the client NEVER uses these */ - this.biomeCache = null; - this.genBiomes = null; - this.biomeIndexLayer = null; - clientWorld = world; - } - } - - @Inject(method = "getBiomeGenAt(II)Lnet/minecraft/world/biome/BiomeGenBase;", at = @At("HEAD"), cancellable = true) - private void safelyGetClientBiome(int x, int z, CallbackInfoReturnable cir) { - if(this.biomeCache == null) { - if(clientWorld != null) - cir.setReturnValue(clientWorld.getBiomeGenForCoords(x, z)); - else { - ArchaicLogger.LOGGER.warn("A mod attempted to retrieve a biome client-side via a WorldChunkManager without a client world reference. This is not safe. ArchaicFix has prevented a crash but some things may not work properly."); - cir.setReturnValue(BiomeGenBase.ocean); - } - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldServer.java deleted file mode 100644 index af0e9a274..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/core/MixinWorldServer.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.core; - -import net.minecraft.profiler.Profiler; -import net.minecraft.world.World; -import net.minecraft.world.WorldProvider; -import net.minecraft.world.WorldServer; -import net.minecraft.world.WorldSettings; -import net.minecraft.world.gen.ChunkProviderServer; -import net.minecraft.world.storage.ISaveHandler; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -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; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(WorldServer.class) -public abstract class MixinWorldServer extends World { - @Shadow public ChunkProviderServer theChunkProviderServer; - - private MixinWorldServer(ISaveHandler p_i45368_1_, String p_i45368_2_, WorldProvider p_i45368_3_, WorldSettings p_i45368_4_, Profiler p_i45368_5_) { - super(p_i45368_1_, p_i45368_2_, p_i45368_3_, p_i45368_4_, p_i45368_5_); - } - - @ModifyConstant(method = "tickUpdates", constant = @Constant(intValue = 1000), expect = 2, require = 0) - private int increaseUpdateLimit(int old) { - return ArchaicConfig.increaseBlockUpdateLimit ? 65000 : old; - } - - @Inject(method = "func_152379_p", at = @At("RETURN"), cancellable = true) - private void shortenBlockUpdateDistance(CallbackInfoReturnable cir) { - if(ArchaicConfig.optimizeBlockTickingDistance > 0) { - cir.setReturnValue(Math.min(cir.getReturnValue(), ArchaicConfig.optimizeBlockTickingDistance)); - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerServer.java deleted file mode 100644 index aa0e9f4e1..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerServer.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.extrautils; - -import com.rwtema.extrautils.EventHandlerServer; -import net.minecraft.block.Block; -import net.minecraft.block.BlockEnchantmentTable; -import net.minecraft.init.Blocks; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(EventHandlerServer.class) -public class MixinEventHandlerServer { - @Redirect(method = "ActivationRitual", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getBlock(III)Lnet/minecraft/block/Block;", remap = true), remap = false) - private Block getSpecialBlock(World world, int x, int y, int z) { - Block block = world.getBlock(x, y, z); - if(block instanceof BlockEnchantmentTable) - return Blocks.enchanting_table; - else - return block; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerSiege.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerSiege.java deleted file mode 100644 index 8780a9966..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinEventHandlerSiege.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.extrautils; - -import com.rwtema.extrautils.EventHandlerSiege; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(value = EventHandlerSiege.class, remap = false) -public class MixinEventHandlerSiege { - @Redirect(method = "golemDeath", at = @At(value = "INVOKE", target = "Ljava/lang/Object;equals(Ljava/lang/Object;)Z")) - private boolean checkSubclassofBeacon(Object subject, Object teBeaconClass) { - return ((Class)teBeaconClass).isAssignableFrom((Class)subject); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinItemDivisionSigil.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinItemDivisionSigil.java deleted file mode 100644 index 9efc873ab..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinItemDivisionSigil.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.extrautils; - -import com.rwtema.extrautils.item.ItemDivisionSigil; -import net.minecraft.block.Block; -import net.minecraft.block.BlockBeacon; -import net.minecraft.block.BlockEnchantmentTable; -import net.minecraft.init.Blocks; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(ItemDivisionSigil.class) -public class MixinItemDivisionSigil { - @Redirect(method = "onItemUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getBlock(III)Lnet/minecraft/block/Block;")) - private Block checkIsSpecialBlock(World world, int x, int y, int z) { - Block block = world.getBlock(x, y, z); - if(block instanceof BlockEnchantmentTable) - return Blocks.enchanting_table; - else if(block instanceof BlockBeacon) - return Blocks.beacon; - else - return block; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinTileEntityTrashCan.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinTileEntityTrashCan.java deleted file mode 100644 index 01e26fab5..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/extrautils/MixinTileEntityTrashCan.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.extrautils; - -import com.rwtema.extrautils.tileentity.TileEntityTrashCan; -import net.minecraft.nbt.NBTTagCompound; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(TileEntityTrashCan.class) -public class MixinTileEntityTrashCan { - @Shadow(remap = false) private boolean added; - - @Inject(method = "readFromNBT", at = @At("TAIL"), remap = false) - private void forceRescan(NBTTagCompound par1NBTTagCompound, CallbackInfo ci) { - this.added = true; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinAnvilChunkLoader.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinAnvilChunkLoader.java deleted file mode 100644 index ddaa240ce..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinAnvilChunkLoader.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; - -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.storage.AnvilChunkLoader; -import org.embeddedt.archaicfix.lighting.api.IChunkLightingData; -import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; -import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(AnvilChunkLoader.class) -public abstract class MixinAnvilChunkLoader { - /** - * Injects into the head of saveChunk() to forcefully process all pending light updates. Fail-safe. - * - * @author Angeline - */ - @Inject(method = "saveChunk", at = @At("HEAD")) - private void onConstructed(World world, Chunk chunkIn, CallbackInfo callbackInfo) { - ((ILightingEngineProvider) world).getLightingEngine().processLightUpdates(); - } - - /** - * Injects the deserialization logic for chunk data on load so we can extract whether or not we've populated light yet. - * - * @author Angeline - */ - @Inject(method = "readChunkFromNBT", at = @At("RETURN")) - private void onReadChunkFromNBT(World world, NBTTagCompound compound, CallbackInfoReturnable cir) { - Chunk chunk = cir.getReturnValue(); - - LightingHooks.readNeighborLightChecksFromNBT(chunk, compound); - - ((IChunkLightingData) chunk).setLightInitialized(compound.getBoolean("LightPopulated")); - - } - - /** - * Injects the serialization logic for chunk data on save so we can store whether or not we've populated light yet. - * @author Angeline - */ - @Inject(method = "writeChunkToNBT", at = @At("RETURN")) - private void onWriteChunkToNBT(Chunk chunk, World world, NBTTagCompound compound, CallbackInfo ci) { - LightingHooks.writeNeighborLightChecksToNBT(chunk, compound); - - compound.setBoolean("LightPopulated", ((IChunkLightingData) chunk).isLightInitialized()); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunk.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunk.java deleted file mode 100644 index 7546c85dc..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunk.java +++ /dev/null @@ -1,392 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; - -import net.minecraft.block.Block; -import net.minecraft.util.EnumFacing; -import net.minecraft.world.ChunkCoordIntPair; -import net.minecraft.world.EnumSkyBlock; -import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; -import org.embeddedt.archaicfix.lighting.api.IChunkLighting; -import org.embeddedt.archaicfix.lighting.api.IChunkLightingData; -import org.embeddedt.archaicfix.lighting.api.ILightingEngine; -import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; -import org.embeddedt.archaicfix.lighting.world.WorldChunkSlice; -import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(value = Chunk.class) -public abstract class MixinChunk implements IChunkLighting, IChunkLightingData, ILightingEngineProvider { - - /** - * Callback injected to the head of getLightSubtracted(BlockPos, int) to force deferred light updates to be processed. - * - * @author Angeline - */ - @Inject(method = "getBlockLightValue", at = @At("HEAD")) - private void onGetLightSubtracted(int x, int y, int z, int amount, CallbackInfoReturnable cir) { - this.getLightingEngine().processLightUpdates(); - } - - /** - * Callback injected at the end of onLoad() to have previously scheduled light updates scheduled again. - * - * @author Angeline - */ - @Inject(method = "onChunkLoad", at = @At("RETURN")) - private void onLoad(CallbackInfo ci) { - LightingHooks.scheduleRelightChecksForChunkBoundaries(this.worldObj, (Chunk) (Object) this); - } - - // === REPLACEMENTS === - - /** - * Replaces the call in setLightFor(Chunk, EnumSkyBlock, BlockPos) with our hook. - * - * @author Angeline - */ - @Redirect( - method = "setLightValue", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/chunk/Chunk;generateSkylightMap()V" - ), - expect = 0 - ) - private void setLightForRedirectGenerateSkylightMap(Chunk chunk, EnumSkyBlock type, int x, int y, int z, int value) { - LightingHooks.initSkylightForSection(this.worldObj, (Chunk) (Object) this, this.storageArrays[y >> 4]); - } - - private int getBlockLightOpacity(int x, int y, int z) { - return this.getBlock(x, y, z).getLightOpacity(this.worldObj, x, y, z); - } - - /** - * @reason Overwrites relightBlock with a more efficient implementation. - * @author Angeline - */ - @Overwrite - private void relightBlock(int x, int y, int z) { - int i = this.heightMap[z << 4 | x] & 255; - - int j = Math.max(y, i); - - while (j > 0 && this.getBlockLightOpacity(x, j - 1, z) == 0) { - --j; - } - - if (j != i) { - this.heightMap[z << 4 | x] = j; - - if (!this.worldObj.provider.hasNoSky) { - LightingHooks.relightSkylightColumn(this.worldObj, (Chunk) (Object) this, x, z, i, j); - } - - int l1 = this.heightMap[z << 4 | x]; - - if (l1 < this.heightMapMinimum) { - this.heightMapMinimum = l1; - } - } - } - - /** - * @reason Hook for calculating light updates only as needed. {@link MixinChunk#getCachedLightFor(EnumSkyBlock, int, int, int)} does not - * call this hook. - * - * @author Angeline - */ - @Overwrite - public int getSavedLightValue(EnumSkyBlock type, int x, int y, int z) { - getLightingEngine().processLightUpdatesForType(type); - - return this.getCachedLightFor(type, x, y, z); - } - - /** - * @reason Hooks into checkLight() to check chunk lighting and returns immediately after, voiding the rest of the function. - * - * @author Angeline - */ - @Overwrite - public void func_150809_p() { - this.isTerrainPopulated = true; - - LightingHooks.checkChunkLighting((Chunk) (Object) this, this.worldObj); - } - - /** - * @reason Optimized version of recheckGaps. Avoids chunk fetches as much as possible. - * - * @author Angeline - */ - @Overwrite - private void recheckGaps(boolean onlyOne) { - this.worldObj.theProfiler.startSection("recheckGaps"); - - WorldChunkSlice slice = new WorldChunkSlice(this.worldObj, this.xPosition, this.zPosition); - - if (this.worldObj.doChunksNearChunkExist(this.xPosition * 16 + 8, 0, this.zPosition * 16 + 8, 16)) { - for (int x = 0; x < 16; ++x) { - for (int z = 0; z < 16; ++z) { - if (this.recheckGapsForColumn(slice, x, z)) { - if (onlyOne) { - this.worldObj.theProfiler.endSection(); - - return; - } - } - } - } - - this.isGapLightingUpdated = false; - } - - this.worldObj.theProfiler.endSection(); - } - - private boolean recheckGapsForColumn(WorldChunkSlice slice, int x, int z) { - int i = x + z * 16; - - if (this.updateSkylightColumns[i]) { - this.updateSkylightColumns[i] = false; - - int height = this.getHeightValue(x, z); - - int x1 = this.xPosition * 16 + x; - int z1 = this.zPosition * 16 + z; - - int max = this.recheckGapsGetLowestHeight(slice, x1, z1); - - this.recheckGapsSkylightNeighborHeight(slice, x1, z1, height, max); - - return true; - } - - return false; - } - - private int recheckGapsGetLowestHeight(WorldChunkSlice slice, int x, int z) { - int max = Integer.MAX_VALUE; - - for (EnumFacing facing : LightingHooks.HORIZONTAL_FACINGS) { - int j = x + facing.getFrontOffsetX(); - int k = z + facing.getFrontOffsetZ(); - - max = Math.min(max, slice.getChunkFromWorldCoords(j, k).heightMapMinimum); - } - - return max; - } - - private void recheckGapsSkylightNeighborHeight(WorldChunkSlice slice, int x, int z, int height, int max) { - this.checkSkylightNeighborHeight(slice, x, z, max); - - for (EnumFacing facing : LightingHooks.HORIZONTAL_FACINGS) { - int j = x + facing.getFrontOffsetX(); - int k = z + facing.getFrontOffsetZ(); - - this.checkSkylightNeighborHeight(slice, j, k, height); - } - } - - private void checkSkylightNeighborHeight(WorldChunkSlice slice, int x, int z, int maxValue) { - int i = slice.getChunkFromWorldCoords(x, z).getHeightValue(x & 15, z & 15); - - if (i > maxValue) { - this.updateSkylightNeighborHeight(slice, x, z, maxValue, i + 1); - } else if (i < maxValue) { - this.updateSkylightNeighborHeight(slice, x, z, i, maxValue + 1); - } - } - - private void updateSkylightNeighborHeight(WorldChunkSlice slice, int x, int z, int startY, int endY) { - if (endY > startY) { - if (!slice.isLoaded(x, z, 16)) { - return; - } - - for (int i = startY; i < endY; ++i) { - this.worldObj.updateLightByType(EnumSkyBlock.Sky, x, i, z); - } - - this.isModified = true; - } - } - - /** - * @author embeddedt - * @reason optimize random light checks so they complete faster - */ - @Overwrite - public void enqueueRelightChecks() - { - /* Skip object allocation if we weren't going to run checks anyway */ - if (this.queuedLightChecks >= 4096) - return; - boolean isActiveChunk = worldObj.activeChunkSet.contains(new ChunkCoordIntPair(this.xPosition, this.zPosition)); - int lightRecheckSpeed; - if(worldObj.isRemote && isActiveChunk) { - lightRecheckSpeed = 256; - } else if(worldObj.isRemote) - lightRecheckSpeed = 64; - else - lightRecheckSpeed = 32; - for (int i = 0; i < lightRecheckSpeed; ++i) - { - if (this.queuedLightChecks >= 4096) - { - return; - } - - int section = this.queuedLightChecks % 16; - int x = this.queuedLightChecks / 16 % 16; - int z = this.queuedLightChecks / 256; - ++this.queuedLightChecks; - int bx = (this.xPosition << 4) + x; - int bz = (this.zPosition << 4) + z; - - for (int y = 0; y < 16; ++y) - { - int by = (section << 4) + y; - ExtendedBlockStorage storage = this.storageArrays[section]; - - boolean performFullLightUpdate = false; - if (storage == null && (y == 0 || y == 15 || x == 0 || x == 15 || z == 0 || z == 15)) - performFullLightUpdate = true; - else if(storage != null) { - Block block = storage.getBlockByExtId(x, y, z); - if(block.getLightOpacity(this.worldObj, bx, by, bz) >= 255 && block.getLightValue(this.worldObj, bx, by, bz) <= 0) { - int prevLight = storage.getExtBlocklightValue(x, y, z); - if(prevLight != 0) { - storage.setExtBlocklightValue(x, y, z, 0); - this.worldObj.markBlockRangeForRenderUpdate(bx, by, bz, bx, by, bz); - } - } else - performFullLightUpdate = true; - } - if (performFullLightUpdate) - { - this.worldObj.func_147451_t(bx, by, bz); - } - } - } - } - - @Shadow - public abstract int getHeightValue(int i, int j); - - // === INTERFACE IMPL === - - private short[] neighborLightChecks; - - private boolean isLightInitialized; - - private ILightingEngine lightingEngine; - - @Override - public short[] getNeighborLightChecks() { - return this.neighborLightChecks; - } - - @Override - public void setNeighborLightChecks(short[] data) { - this.neighborLightChecks = data; - } - - @Override - public ILightingEngine getLightingEngine() { - if(this.lightingEngine == null) { - this.lightingEngine = ((ILightingEngineProvider) this.worldObj).getLightingEngine(); - if(this.lightingEngine == null) - throw new IllegalStateException(); - } - return this.lightingEngine; - } - - @Override - public boolean isLightInitialized() { - return this.isLightInitialized; - } - - @Override - public void setLightInitialized(boolean lightInitialized) { - this.isLightInitialized = lightInitialized; - } - - @Shadow public World worldObj; - - @Shadow private ExtendedBlockStorage[] storageArrays; - - @Shadow public abstract boolean canBlockSeeTheSky(int p_76619_1_, int p_76619_2_, int p_76619_3_); - - @Shadow public int[] heightMap; - - @Shadow public abstract Block getBlock(int p_150810_1_, int p_150810_2_, int p_150810_3_); - - @Shadow public int heightMapMinimum; - - @Shadow public boolean isTerrainPopulated; - - @Shadow @Final public int xPosition; - - @Shadow @Final public int zPosition; - - @Shadow private boolean isGapLightingUpdated; - - @Shadow public boolean[] updateSkylightColumns; - - @Shadow public boolean isModified; - - @Shadow private int queuedLightChecks; - - @Override - public void setSkylightUpdatedPublic() { - for (int i = 0; i < this.updateSkylightColumns.length; ++i) - { - this.updateSkylightColumns[i] = true; - } - - this.recheckGaps(false); - } - - @Override - public int getCachedLightFor(EnumSkyBlock type, int xIn, int yIn, int zIn) { - int i = xIn & 15; - int j = yIn; - int k = zIn & 15; - - ExtendedBlockStorage extendedblockstorage = this.storageArrays[j >> 4]; - - if (extendedblockstorage == null) { - if (this.canBlockSeeTheSky(i, j, k)) { - return type.defaultLightValue; - } else { - return 0; - } - } else if (type == EnumSkyBlock.Sky) { - if (this.worldObj.provider.hasNoSky) { - return 0; - } else { - return extendedblockstorage.getExtSkylightValue(i, j & 15, k); - } - } else { - if (type == EnumSkyBlock.Block) { - return extendedblockstorage.getExtBlocklightValue(i, j & 15, k); - } else { - return type.defaultLightValue; - } - } - } - - - // === END OF INTERFACE IMPL === -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkProviderServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkProviderServer.java deleted file mode 100644 index f88d58fa1..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkProviderServer.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; - -import net.minecraft.util.IProgressUpdate; -import net.minecraft.world.WorldServer; -import net.minecraft.world.gen.ChunkProviderServer; -import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.Set; - -@Mixin(ChunkProviderServer.class) -public abstract class MixinChunkProviderServer { - @Shadow private Set chunksToUnload; - - @Shadow public WorldServer worldObj; - - /** - * Injects a callback into the start of saveChunks(boolean) to force all light updates to be processed before saving. - * - * @author Angeline - */ - @Inject(method = "saveChunks", at = @At("HEAD")) - private void onSaveChunks(boolean all, IProgressUpdate update, CallbackInfoReturnable cir) { - ((ILightingEngineProvider) this.worldObj).getLightingEngine().processLightUpdates(); - } - - /** - * Injects a callback into the start of the onTick() method to process all pending light updates. This is not necessarily - * required, but we don't want our work queues getting too large. - * - * @author Angeline - */ - @Inject(method = "unloadQueuedChunks", at = @At("HEAD")) - private void onTick(CallbackInfoReturnable cir) { - if (!this.worldObj.levelSaving) { - if (!this.chunksToUnload.isEmpty()) { - ((ILightingEngineProvider) this.worldObj).getLightingEngine().processLightUpdates(); - } - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkVanilla.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkVanilla.java deleted file mode 100644 index 1516c8c22..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinChunkVanilla.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; - -import net.minecraft.world.EnumSkyBlock; -import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; -import org.embeddedt.archaicfix.lighting.world.lighting.LightingHooks; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(value = Chunk.class) -public abstract class MixinChunkVanilla { - @Shadow public World worldObj; - private static final String SET_BLOCK_STATE_VANILLA = "func_150807_a(IIILnet/minecraft/block/Block;I)Z"; - - /** - * Redirects the construction of the ExtendedBlockStorage in setBlockState(BlockPos, IBlockState). We need to initialize - * the skylight data for the constructed section as soon as possible. - * - * @author Angeline - */ - @Redirect( - method = SET_BLOCK_STATE_VANILLA, - at = @At( - value = "NEW", - args = "class=net/minecraft/world/chunk/storage/ExtendedBlockStorage" - ), - expect = 0 - ) - private ExtendedBlockStorage setBlockStateCreateSectionVanilla(int y, boolean storeSkylight) { - return this.initSection(y, storeSkylight); - } - - private ExtendedBlockStorage initSection(int y, boolean storeSkylight) { - ExtendedBlockStorage storage = new ExtendedBlockStorage(y, storeSkylight); - - LightingHooks.initSkylightForSection(this.worldObj, (Chunk) (Object) this, storage); - - return storage; - } - - /** - * Modifies the flag variable of setBlockState(BlockPos, IBlockState) to always be false after it is set. - * - * @author Angeline - */ - @ModifyVariable( - method = SET_BLOCK_STATE_VANILLA, - at = @At( - value = "STORE", - ordinal = 1 - ), - name = "flag", - index = 11, - allow = 1 - ) - private boolean setBlockStateInjectGenerateSkylightMapVanilla(boolean generateSkylight) { - return false; - } - - /** - * Prevent propagateSkylightOcclusion from being called. - * @author embeddedt - */ - @Redirect(method = SET_BLOCK_STATE_VANILLA, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;propagateSkylightOcclusion(II)V")) - private void doPropagateSkylight(Chunk chunk, int i1, int i2) { - /* No-op, we don't want skylight propagated */ - } - - /** - * Prevent getLightFor from being called. - * @author embeddedt - */ - @Redirect(method = SET_BLOCK_STATE_VANILLA, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/Chunk;getSavedLightValue(Lnet/minecraft/world/EnumSkyBlock;III)I")) - private int getFakeLightFor(Chunk chunk, EnumSkyBlock skyBlock, int x, int y, int z) { - return 0; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinExtendedBlockStorage.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinExtendedBlockStorage.java deleted file mode 100644 index 29bed6756..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinExtendedBlockStorage.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; - -import net.minecraft.world.chunk.NibbleArray; -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(ExtendedBlockStorage.class) -public class MixinExtendedBlockStorage { - @Shadow - private int blockRefCount; - - @Shadow private NibbleArray skylightArray; - @Shadow private NibbleArray blocklightArray; - private int lightRefCount = -1; - - /** - * @author Angeline - * @reason Reset lightRefCount on call - */ - @Overwrite - public void setExtSkylightValue(int x, int y, int z, int value) { - this.skylightArray.set(x, y, z, value); - this.lightRefCount = -1; - } - - /** - * @author Angeline - * @reason Reset lightRefCount on call - */ - @Overwrite - public void setExtBlocklightValue(int x, int y, int z, int value) { - this.blocklightArray.set(x, y, z, value); - this.lightRefCount = -1; - } - - /** - * @author Angeline - * @reason Reset lightRefCount on call - */ - @Overwrite - public void setBlocklightArray(NibbleArray array) { - this.blocklightArray = array; - this.lightRefCount = -1; - } - - /** - * @author Angeline - * @reason Reset lightRefCount on call - */ - @Overwrite - public void setSkylightArray(NibbleArray array) { - this.skylightArray = array; - this.lightRefCount = -1; - } - - - /** - * @author Angeline - * @reason Send light data to clients when lighting is non-trivial - */ - @Overwrite - public boolean isEmpty() { - if (this.blockRefCount != 0) { - return false; - } - - // -1 indicates the lightRefCount needs to be re-calculated - if (this.lightRefCount == -1) { - if (this.checkLightArrayEqual(this.skylightArray, (byte) 0xFF) - && this.checkLightArrayEqual(this.blocklightArray, (byte) 0x00)) { - this.lightRefCount = 0; // Lighting is trivial, don't send to clients - } else { - this.lightRefCount = 1; // Lighting is not trivial, send to clients - } - } - - return this.lightRefCount == 0; - } - - private boolean checkLightArrayEqual(NibbleArray storage, byte val) { - if (storage == null) { - return true; - } - - byte[] arr = storage.data; - - for (byte b : arr) { - if (b != val) { - return false; - } - } - - return true; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinSPacketChunkData.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinSPacketChunkData.java deleted file mode 100644 index 2e0fdff67..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinSPacketChunkData.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; - -import net.minecraft.network.play.server.S21PacketChunkData; -import net.minecraft.world.chunk.Chunk; -import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(S21PacketChunkData.class) -public abstract class MixinSPacketChunkData { - /** - * @author Angeline - * Injects a callback into SPacketChunkData#calculateChunkSize(Chunk, booolean, int) to force light updates to be - * processed before creating the client payload. We use this method rather than the constructor as it is not valid - * to inject elsewhere other than the RETURN of a ctor, which is too late for our needs. - */ - @Inject(method = "func_149269_a", at = @At("HEAD")) - private static void onCalculateChunkSize(Chunk chunkIn, boolean hasSkyLight, int changedSectionFilter, CallbackInfoReturnable cir) { - ((ILightingEngineProvider) chunkIn).getLightingEngine().processLightUpdates(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinWorld_Lighting.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinWorld_Lighting.java deleted file mode 100644 index 1a481ad2b..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/lighting/MixinWorld_Lighting.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.lighting; - -import net.minecraft.world.ChunkCoordIntPair; -import net.minecraft.world.EnumSkyBlock; -import net.minecraft.world.World; -import net.minecraft.world.chunk.IChunkProvider; -import net.minecraft.world.storage.ISaveHandler; -import net.minecraft.world.storage.WorldInfo; -import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; -import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngine; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.Set; - -@Mixin(value = World.class, priority = 999) -public abstract class MixinWorld_Lighting implements ILightingEngineProvider { - @Shadow protected Set activeChunkSet; - - @Shadow public abstract IChunkProvider getChunkProvider(); - - private LightingEngine lightingEngine; - - /** - * @author Angeline - * Initialize the lighting engine on world construction. - */ - @Redirect(method = "(Lnet/minecraft/world/storage/ISaveHandler;Ljava/lang/String;Lnet/minecraft/world/WorldSettings;Lnet/minecraft/world/WorldProvider;Lnet/minecraft/profiler/Profiler;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/storage/ISaveHandler;loadWorldInfo()Lnet/minecraft/world/storage/WorldInfo;")) - private WorldInfo onConstructed(ISaveHandler handler) { - this.lightingEngine = new LightingEngine((World) (Object) this); - return handler.loadWorldInfo(); - } - - - /** - * Directs the light update to the lighting engine and always returns a success value. - * @author Angeline - * @reason Phosphor replaces the lighting engine with a more efficient implementation. - */ - @Overwrite - public boolean updateLightByType(EnumSkyBlock type, int x, int y, int z) { - this.lightingEngine.scheduleLightUpdate(type, x, y, z); - - return true; - } - - @Override - public LightingEngine getLightingEngine() { - return this.lightingEngine; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/renderdistance/MixinPlayerManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/renderdistance/MixinPlayerManager.java deleted file mode 100644 index 03257c771..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/archaic/common/renderdistance/MixinPlayerManager.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.archaic.common.renderdistance; - -import net.minecraft.server.management.PlayerManager; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; - -@Mixin(PlayerManager.class) -public class MixinPlayerManager { - @ModifyConstant(method = "func_152622_a", constant = @Constant(intValue = 20)) - private int increaseSendDistance(int constant) { - return ArchaicConfig.newMaxRenderDistance; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinInitRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinInitRenderer.java index 629ce6931..8b5f2ef35 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinInitRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinInitRenderer.java @@ -1,5 +1,7 @@ package com.gtnewhorizons.angelica.mixins.early.shaders.startup; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.coderbot.iris.Iris; import net.coderbot.iris.gl.GLDebug; import net.coderbot.iris.gl.IrisRenderSystem; @@ -13,6 +15,11 @@ public class MixinInitRenderer { @Inject(method = "initializeTextures", at = @At("RETURN")) private static void angelica$initializeRenderer(CallbackInfo ci) { + if (Thread.currentThread() != GLStateManager.getMainThread()) { + AngelicaTweaker.LOGGER.warn("Renderer initialization called from non-main thread!"); + return; + } + Iris.identifyCapabilities(); GLDebug.initRenderer(); IrisRenderSystem.initRenderer(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/startup/MixinInitDebug.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/startup/MixinInitDebug.java index 28cf0c229..253c90b56 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/startup/MixinInitDebug.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/startup/MixinInitDebug.java @@ -1,5 +1,7 @@ package com.gtnewhorizons.angelica.mixins.early.sodium.startup; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.coderbot.iris.Iris; import net.minecraft.client.renderer.OpenGlHelper; import org.spongepowered.asm.mixin.Mixin; @@ -11,6 +13,10 @@ public class MixinInitDebug { @Inject(method = "initializeTextures", at = @At("RETURN")) private static void sodium$initIrisDebug(CallbackInfo ci) { + if (Thread.currentThread() != GLStateManager.getMainThread()) { + AngelicaTweaker.LOGGER.warn("Renderer initialization called from non-main thread!"); + return; + } // Temp -- move this into common debug code Iris.identifyCapabilities(); Iris.setDebug(true); diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index 3d50bb31c..2380311f1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -1,21 +1,44 @@ package com.gtnewhorizons.angelica.proxy; +import com.google.common.base.Objects; import com.gtnewhorizons.angelica.client.gui.AngelicaEntityRenderDistanceSetting; import com.gtnewhorizons.angelica.client.gui.AngelicaVideoSettings; import com.gtnewhorizons.angelica.config.AngelicaConfig; +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.eventhandler.EventPriority; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; import jss.notfine.gui.GuiCustomMenu; import jss.notfine.gui.ISettingsEnum; import jss.notfine.gui.MenuButtonLists; import me.jellysquid.mods.sodium.client.SodiumDebugScreenHandler; import net.coderbot.iris.client.IrisDebugScreenHandler; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiMainMenu; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.server.integrated.IntegratedServer; +import net.minecraft.util.Direction; +import net.minecraft.util.MathHelper; +import net.minecraft.util.MovingObjectPosition; +import net.minecraftforge.client.event.EntityViewRenderEvent; +import net.minecraftforge.client.event.GuiOpenEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.common.MinecraftForge; +import java.lang.management.ManagementFactory; +import java.util.Locale; + public class ClientProxy extends CommonProxy { @Override public void preInit(FMLPreInitializationEvent event) { + FMLCommonHandler.instance().bus().register(this); + MinecraftForge.EVENT_BUS.register(this); + MenuButtonLists.addAdditionalEntry(MenuButtonLists.VIDEO, AngelicaVideoSettings.SHADERS); GuiCustomMenu.addButtonHandler(AngelicaVideoSettings.class, (xPosition, yPosition, setting) -> { ISettingsEnum settingsEnum = (ISettingsEnum) setting; @@ -42,4 +65,89 @@ public void postInit(FMLInitializationEvent event) { MinecraftForge.EVENT_BUS.register(IrisDebugScreenHandler.INSTANCE); } } + float lastIntegratedTickTime; + @SubscribeEvent + public void onTick(TickEvent.ServerTickEvent event) { + if(FMLCommonHandler.instance().getSide().isClient() && event.phase == TickEvent.Phase.END) { + IntegratedServer srv = Minecraft.getMinecraft().getIntegratedServer(); + if(srv != null) { + long currentTickTime = srv.tickTimeArray[srv.getTickCounter() % 100]; + lastIntegratedTickTime = lastIntegratedTickTime * 0.8F + (float)currentTickTime / 1000000.0F * 0.2F; + } else + lastIntegratedTickTime = 0; + } + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onRenderOverlay(RenderGameOverlayEvent.Text event) { + Minecraft mc = Minecraft.getMinecraft(); + if(event.isCanceled() || !mc.gameSettings.showDebugInfo || event.left.size() < 1) + return; + NetHandlerPlayClient cl = mc.getNetHandler(); + if(cl != null) { + IntegratedServer srv = mc.getIntegratedServer(); + + if (srv != null) { + String s = String.format("Integrated server @ %.0f ms ticks", lastIntegratedTickTime); + event.left.add(1, s); + } + } + if(AngelicaConfig.showBlockDebugInfo && mc.objectMouseOver != null && mc.objectMouseOver.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) { + if(!event.right.isEmpty() && Objects.firstNonNull(event.right.get(event.right.size() - 1), "").length() > 0) + event.right.add(""); + Block block = mc.theWorld.getBlock(mc.objectMouseOver.blockX, mc.objectMouseOver.blockY, mc.objectMouseOver.blockZ); + int meta = mc.theWorld.getBlockMetadata(mc.objectMouseOver.blockX, mc.objectMouseOver.blockY, mc.objectMouseOver.blockZ); + event.right.add(Block.blockRegistry.getNameForObject(block)); + event.right.add("meta: " + meta); + } + if(AngelicaConfig.modernizeF3Screen) { + boolean hasReplacedXYZ = false; + for(int i = 0; i < event.left.size() - 3; i++) { + /* These checks should not be inefficient as most of the time the first one will already fail */ + if(!hasReplacedXYZ && Objects.firstNonNull(event.left.get(i), "").startsWith("x:") + && Objects.firstNonNull(event.left.get(i + 1), "").startsWith("y:") + && Objects.firstNonNull(event.left.get(i + 2), "").startsWith("z:") + && Objects.firstNonNull(event.left.get(i + 3), "").startsWith("f:")) { + hasReplacedXYZ = true; + int heading = MathHelper.floor_double((double)(mc.thePlayer.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3; + String heading_str = switch (heading) { + case 0 -> "Towards positive Z"; + case 1 -> "Towards negative X"; + case 2 -> "Towards negative Z"; + case 3 -> "Towards positive X"; + default -> throw new RuntimeException(); + }; + event.left.set(i, String.format("XYZ: %.3f / %.5f / %.3f", mc.thePlayer.posX, mc.thePlayer.boundingBox.minY, mc.thePlayer.posZ)); + int blockX = MathHelper.floor_double(mc.thePlayer.posX); + int blockY = MathHelper.floor_double(mc.thePlayer.boundingBox.minY); + int blockZ = MathHelper.floor_double(mc.thePlayer.posZ); + event.left.set(i + 1, String.format("Block: %d %d %d [%d %d %d]", blockX, blockY, blockZ, blockX & 15, blockY & 15, blockZ & 15)); + event.left.set(i + 2, String.format("Chunk: %d %d %d", blockX >> 4, blockY >> 4, blockZ >> 4)); + event.left.set(i + 3, String.format("Facing: %s (%s) (%.1f / %.1f)", Direction.directions[heading].toLowerCase(Locale.ROOT), heading_str, MathHelper.wrapAngleTo180_float(mc.thePlayer.rotationYaw), MathHelper.wrapAngleTo180_float(mc.thePlayer.rotationPitch))); + } + } + } + } + + private float gameStartTime = -1; + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onGuiOpen(GuiOpenEvent event) { + if(!event.isCanceled() && event.gui instanceof GuiMainMenu && gameStartTime == -1) { + gameStartTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f; + AngelicaTweaker.LOGGER.info("The game loaded in " + gameStartTime + " seconds."); + } + } + + /* coerce NaN fog values back to 0 (https://bugs.mojang.com/browse/MC-10480) - from ArchaicFix */ + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onFogColor(EntityViewRenderEvent.FogColors event) { + if(Float.isNaN(event.red)) + event.red = 0f; + if(Float.isNaN(event.green)) + event.green = 0f; + if(Float.isNaN(event.blue)) + event.blue = 0f; + } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index a23b11ae8..99dc96c7a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -43,7 +43,8 @@ public class GLStateManagerTransformer implements IClassTransformer { private static final List TransformerExclusions = new ArrayList<>(Arrays.asList( - "org.lwjgl", "com.gtnewhorizons.angelica.glsm.", "com.gtnewhorizons.angelica.transform", "me.eigenraven.lwjgl3ify", "cpw.mods.fml.client.SplashProgress") + "org.lwjgl", "com.gtnewhorizons.angelica.glsm.", "com.gtnewhorizons.angelica.transform", "me.eigenraven.lwjgl3ify", + "cpw.mods.fml.client.SplashProgress") ); public static int remaps = 0, calls = 0; public static Method lastMethod = null; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index a141fc1c6..9a9f32c6e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -39,6 +39,7 @@ public SodiumClientMod() { // ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); } + @SubscribeEvent public void onGui(GuiScreenEvent.InitGuiEvent.Pre event) { if(event.gui instanceof GuiVideoSettings) { diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 53204511f..c4022e5cb 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -1,5 +1,6 @@ package net.coderbot.iris; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.mojang.realmsclient.gui.ChatFormatting; import lombok.Getter; import net.coderbot.iris.config.IrisConfig; @@ -393,6 +394,7 @@ private static void setShadersDisabled() { // Temp escalation public static void setDebug(boolean enable) { + GLStateManager.assertMainThread(); int success; if (enable) { success = GLDebug.setupDebugMessageCallback(); diff --git a/src/main/java/net/coderbot/iris/gl/GLDebug.java b/src/main/java/net/coderbot/iris/gl/GLDebug.java index fbb51f9ee..b4770d473 100644 --- a/src/main/java/net/coderbot/iris/gl/GLDebug.java +++ b/src/main/java/net/coderbot/iris/gl/GLDebug.java @@ -5,6 +5,8 @@ package net.coderbot.iris.gl; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.coderbot.iris.Iris; import org.lwjgl.opengl.AMDDebugOutput; import org.lwjgl.opengl.AMDDebugOutputCallback; @@ -27,6 +29,10 @@ public final class GLDebug { * @return 0 for failure, 1 for success, 2 for restart required. */ public static int setupDebugMessageCallback() { + if (Thread.currentThread() != GLStateManager.getMainThread()) { + AngelicaTweaker.LOGGER.warn("setupDebugMessageCallback called from non-main thread!"); + return 0; + } return setupDebugMessageCallback(System.err); } @@ -311,6 +317,10 @@ public void popGroup() { } public static void initRenderer() { + // Only enable if debug is enabled, and also forcibly disable the splash screen + if(!Boolean.parseBoolean(System.getProperty("org.lwjgl.util.Debug", "false"))) + return; + if (Iris.capabilities.GL_KHR_debug || Iris.capabilities.OpenGL43) { debugState = new KHRDebugState(); } else { diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java index 8907a6466..3bc112afb 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java @@ -14,6 +14,7 @@ import net.minecraft.util.ResourceLocation; import org.jetbrains.annotations.Nullable; +import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -104,7 +105,12 @@ public boolean tryUpload(int atlasWidth, int atlasHeight, int mipLevel) { } } - protected void uploadSprite(TextureAtlasSprite sprite) { + @Override + public void loadTexture(IResourceManager p_110551_1_) throws IOException { + // todo + } + + protected void uploadSprite(TextureAtlasSprite sprite) { if (((MixinTextureAtlasSprite) (Object)sprite).isAnimation()) { MixinTextureAtlasSprite mixinSprite = ((MixinTextureAtlasSprite) (Object) sprite); AnimationMetadataSection metadata = mixinSprite.getMetadata(); diff --git a/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java b/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java deleted file mode 100644 index 4f4c1b323..000000000 --- a/src/main/java/org/embeddedt/archaicfix/ArchaicFix.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.embeddedt.archaicfix; - -import cpw.mods.fml.common.FMLCommonHandler; -import cpw.mods.fml.common.Mod; -import cpw.mods.fml.common.Mod.EventHandler; -import cpw.mods.fml.common.SidedProxy; -import cpw.mods.fml.common.event.FMLConstructionEvent; -import cpw.mods.fml.common.event.FMLInitializationEvent; -import cpw.mods.fml.common.event.FMLLoadCompleteEvent; -import cpw.mods.fml.common.event.FMLPreInitializationEvent; -import cpw.mods.fml.common.event.FMLServerStartingEvent; -import cpw.mods.fml.common.network.NetworkRegistry; -import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper; -import net.minecraftforge.common.MinecraftForge; -import org.embeddedt.archaicfix.proxy.CommonProxy; - -@Mod(modid = ArchaicFix.MODID, version = ArchaicFix.VERSION, dependencies = "required-after:gtnhmixins@[2.0.0,);", guiFactory = "org.embeddedt.archaicfix.config.ArchaicGuiConfigFactory") -public class ArchaicFix -{ - public static final String MODID = "archaicfix"; - public static final String VERSION = "ArchaicFix"; - - private FixHelper helper; - - public static final SimpleNetworkWrapper NETWORK = NetworkRegistry.INSTANCE.newSimpleChannel(MODID); - - @SidedProxy(clientSide = "org.embeddedt.archaicfix.proxy.ClientProxy", serverSide = "org.embeddedt.archaicfix.proxy.CommonProxy") - public static CommonProxy proxy; - - @EventHandler - public void onConstruct(FMLConstructionEvent event) { - try { - Class.forName("com.gildedgames.util.threadedlighting.asm.TLTransformer"); - ArchaicLogger.LOGGER.fatal("=================== WARNING ==================="); - ArchaicLogger.LOGGER.fatal("A version of GG Util that includes threaded lighting was detected. ArchaicFix has prevented launching to avoid issues. Please download a fixed version of GG Util: https://www.curseforge.com/minecraft/mc-mods/gilded-game-utils-fix."); - ArchaicLogger.LOGGER.fatal("==============================================="); - throw new UnsupportedOperationException("Please download a fixed version of GG Util: https://www.curseforge.com/minecraft/mc-mods/gilded-game-utils-fix"); - } catch(ClassNotFoundException ignored) {} - } - - @EventHandler - public void preinit(FMLPreInitializationEvent event) { - helper = new FixHelper(); - MinecraftForge.EVENT_BUS.register(helper); - FMLCommonHandler.instance().bus().register(helper); - proxy.preinit(); - } - - @EventHandler - public void init(FMLInitializationEvent event) { - } - - @EventHandler - public void serverStart(FMLServerStartingEvent event) { - event.registerServerCommand(new CommandDebugUpdateQueue()); - } - - @EventHandler - public void loadComplete(FMLLoadCompleteEvent event) { - proxy.loadcomplete(); - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/ArchaicLogger.java b/src/main/java/org/embeddedt/archaicfix/ArchaicLogger.java deleted file mode 100644 index a8e54dba6..000000000 --- a/src/main/java/org/embeddedt/archaicfix/ArchaicLogger.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.embeddedt.archaicfix; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -public class ArchaicLogger { - public static final Logger LOGGER = LogManager.getLogger("ArchaicFix"); -} diff --git a/src/main/java/org/embeddedt/archaicfix/CommandDebugUpdateQueue.java b/src/main/java/org/embeddedt/archaicfix/CommandDebugUpdateQueue.java deleted file mode 100644 index ce964bf84..000000000 --- a/src/main/java/org/embeddedt/archaicfix/CommandDebugUpdateQueue.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.embeddedt.archaicfix; - -import com.mojang.realmsclient.gui.ChatFormatting; -import cpw.mods.fml.relauncher.ReflectionHelper; -import net.minecraft.command.CommandBase; -import net.minecraft.command.ICommandSender; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.ChatComponentText; -import net.minecraft.world.NextTickListEntry; -import net.minecraft.world.WorldServer; - -import java.util.TreeSet; - -public class CommandDebugUpdateQueue extends CommandBase { - @Override - public String getCommandName() { - return "debugupdatequeue"; - } - - @Override - public String getCommandUsage(ICommandSender p_71518_1_) { - return "/debugupdatequeue"; - } - - @Override - public void processCommand(ICommandSender sender, String[] p_71515_2_) { - MinecraftServer server = MinecraftServer.getServer(); - if(server != null) { - sender.addChatMessage(new ChatComponentText("Update queue sizes:")); - for(WorldServer world : server.worldServers) { - TreeSet ticks = ReflectionHelper.getPrivateValue(WorldServer.class, world, "field_73065_O", "pendingTickListEntriesTreeSet"); - if(ticks.size() > 0) - sender.addChatMessage(new ChatComponentText("Dimension " + world.provider.dimensionId + ": " + ticks.size())); - } - } else { - sender.addChatMessage(new ChatComponentText(ChatFormatting.RED + "No server found.")); - } - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/FixHelper.java b/src/main/java/org/embeddedt/archaicfix/FixHelper.java deleted file mode 100644 index aadd7edc5..000000000 --- a/src/main/java/org/embeddedt/archaicfix/FixHelper.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.embeddedt.archaicfix; - -import cpw.mods.fml.common.eventhandler.SubscribeEvent; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.monster.EntitySlime; -import net.minecraftforge.event.entity.living.LivingEvent; -import net.minecraftforge.oredict.OreDictionary; -import org.embeddedt.archaicfix.interfaces.IAcceleratedRecipe; -import org.embeddedt.archaicfix.helpers.OreDictIterator; - -import java.util.ArrayList; - -public class FixHelper { - public static final ArrayList recipesHoldingPotentialItems = new ArrayList<>(); - - @SubscribeEvent - public void onSizeUpdate(LivingEvent.LivingUpdateEvent event) { - EntityLivingBase entity = event.entityLiving; - if(entity.worldObj.isRemote && entity instanceof EntitySlime slime && entity.getAge() <= 1) { - float newSize = 0.6F * (float)slime.getSlimeSize(); - slime.width = newSize; - slime.height = newSize; - slime.setPosition(slime.posX, slime.posY, slime.posZ); - } - } - - @SubscribeEvent - public void onOreRegister(OreDictionary.OreRegisterEvent event) { - for(IAcceleratedRecipe recipe : recipesHoldingPotentialItems) { - if(recipe != null) - recipe.invalidatePotentialItems(); - } - recipesHoldingPotentialItems.clear(); - OreDictIterator.clearCache(event.Name); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java b/src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java deleted file mode 100644 index 6041ebeac..000000000 --- a/src/main/java/org/embeddedt/archaicfix/block/ThreadedBlockData.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.embeddedt.archaicfix.block; - -public class ThreadedBlockData { - public double minX = 0; - public double minY = 0; - public double minZ = 0; - public double maxX = 0; - public double maxY = 0; - public double maxZ = 0; - - public ThreadedBlockData() { - - } - - public ThreadedBlockData(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { - this.minX = minX; - this.minY = minY; - this.minZ = minZ; - this.maxX = maxX; - this.maxY = maxY; - this.maxZ = maxZ; - } - - public ThreadedBlockData(ThreadedBlockData other) { - this.minX = other.minX; - this.minY = other.minY; - this.minZ = other.minZ; - this.maxX = other.maxX; - this.maxY = other.maxY; - this.maxZ = other.maxZ; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java b/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java deleted file mode 100644 index bf820bb46..000000000 --- a/src/main/java/org/embeddedt/archaicfix/config/ArchaicConfig.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.embeddedt.archaicfix.config; - -@Config(modid = "archaicfix") -public class ArchaicConfig { - @Config.DefaultBoolean(true) - public static boolean hideDownloadingTerrainScreen; - - @Config.Comment("Prevents buttons from showing a yellow text color when hovered, as was done in 1.14+.") - @Config.DefaultBoolean(false) - public static boolean enableNewButtonAppearance; - - @Config.Comment("Cap the integrated server render distance at a minimum of 8 chunks, and adjust despawn ranges so mobs will always despawn properly on low render distances.") - @Config.DefaultBoolean(true) - public static boolean fixMobSpawnsAtLowRenderDist; - - @Config.Comment("Allow 65000 block updates to be performed per tick, rather than 1000.") - @Config.DefaultBoolean(true) - public static boolean increaseBlockUpdateLimit; - - - @Config.Comment("Increase the maximum render distance.") - @Config.DefaultBoolean(false) - public static boolean raiseMaxRenderDistance; - - @Config.Comment("What the maximum render distance should be if raiseMaxRenderDistance is enabled.") - @Config.DefaultInt(32) - @Config.RangeInt(min = 16, max = 128) - public static int newMaxRenderDistance; - - @Config.Comment("Log when cascading worldgen occurs.") - @Config.DefaultBoolean(true) - public static boolean logCascadingWorldgen; - - @Config.Comment("Print a stacktrace when cascading worldgen occurs. Use only for development as this will add more lag in game.") - @Config.DefaultBoolean(false) - public static boolean logCascadingWorldgenStacktrace; - - @Config.Comment("Fix instances of cascading worldgen in vanilla Minecraft. Turn this option off if you require 100% seed parity.") - @Config.DefaultBoolean(true) - public static boolean fixVanillaCascadingWorldgen; - - @Config.Comment("Force all mixins to be loaded and the cache to be cleared. This saves RAM, but may reveal bugs in mods' mixin configs. Based on MemoryLeakFix.") - @Config.DefaultBoolean(false) - public static boolean clearMixinCache; - - @Config.Comment("Clean up LaunchClassLoader cache.") - @Config.DefaultBoolean(true) - public static boolean clearLaunchLoaderCache; - - @Config.Comment("Fix the 'TickNextTick list out of synch' error.") - @Config.DefaultBoolean(true) - public static boolean fixTickListSynchronization; - - @Config.Comment("Make sure entities don't spawn inside blocks that would make them suffocate. Off by default because it might reduce the number of passive entities that spawn during worldgen.") - @Config.DefaultBoolean(false) - public static boolean preventEntitySuffocationWorldgen; - - @Config.Comment("Show block registry name and meta value in F3, similar to 1.8+.") - @Config.DefaultBoolean(false) - public static boolean showBlockDebugInfo; - - @Config.Comment("Prevent entities outside a certain distance from being ticked. This does not affect tile entities, and is essentially another view distance slider.") - @Config.DefaultBoolean(false) - public static boolean optimizeEntityTicking; - - @Config.Comment("Squared distance outside which most entities aren't ticked, default is 64 blocks.") - @Config.DefaultInt(4096) - public static int optimizeEntityTickingDistance; - - @Config.Comment("Distance in chunks at which blocks are ticked, the default value of 0 means to use the render distance.") - @Config.DefaultInt(0) - public static int optimizeBlockTickingDistance; - - @Config.Comment("List of entities to ignore for entity ticking optimization.") - @Config.DefaultStringList({ "Wither", "EnderDragon" }) - public static String[] optimizeEntityTickingIgnoreList; - - @Config.Comment("Attempt to fix hanging in SP when logging in.") - @Config.DefaultBoolean(true) - public static boolean fixLoginRaceCondition; - - @Config.Comment("Fix MC-1406.") - @Config.DefaultBoolean(true) - public static boolean fixPlacementFlicker; - - @Config.Comment("Optimize vanilla's ID-to-object map.") - @Config.DefaultBoolean(true) - public static boolean optimizeObjectIntIdentityMap; - - @Config.Comment("Fix the client leaking memory by holding on to skins and player instances that aren't needed.") - @Config.DefaultBoolean(true) - public static boolean fixSkinMemoryLeak; - - @Config.Comment("Show memory usage during game load.") - @Config.DefaultBoolean(true) - public static boolean showSplashMemoryBar; - - @Config.Comment("Tweak F3 screen to be closer to modern versions.") - @Config.DefaultBoolean(true) - public static boolean modernizeF3Screen; - - @Config.Comment("Replace tall grass texture with modern version.") - @Config.DefaultBoolean(false) - public static boolean modernizeTextures; - - @Config.Comment("Remove JourneyMap debug feature.") - @Config.DefaultBoolean(false) - public static boolean removeJourneymapDebug; - - @Config.Comment("When true, the Phosphor backport is enabled. Disabling is not recommended as it will generally add lag.") - @Config.DefaultBoolean(true) - public static boolean enablePhosphor; - - @Config.Comment("When true, dropped items will always render as though fancy graphics are enabled.") - @Config.DefaultBoolean(false) - public static boolean forceFancyItems; - - @Config.Comment("Add the Let's Encrypt root certificates to the default trust store.") - @Config.DefaultBoolean(false) - public static boolean enableLetsEncryptRoot; -} diff --git a/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfig.java b/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfig.java deleted file mode 100644 index 576366f1f..000000000 --- a/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfig.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.embeddedt.archaicfix.config; - -import net.minecraft.client.gui.GuiScreen; - -public class ArchaicGuiConfig extends SimpleGuiConfig { - public ArchaicGuiConfig(GuiScreen parent) throws ConfigException { - super(parent, ArchaicConfig.class, "archaicfix", "ArchaicFix"); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfigFactory.java b/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfigFactory.java deleted file mode 100644 index 94b44c05d..000000000 --- a/src/main/java/org/embeddedt/archaicfix/config/ArchaicGuiConfigFactory.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.embeddedt.archaicfix.config; - -import net.minecraft.client.gui.GuiScreen; - -public class ArchaicGuiConfigFactory implements SimpleGuiFactory { - @Override - public Class mainConfigGuiClass() { - return ArchaicGuiConfig.class; - } -} \ No newline at end of file diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java b/src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java deleted file mode 100644 index be4e7e080..000000000 --- a/src/main/java/org/embeddedt/archaicfix/helpers/BuiltInResourcePack.java +++ /dev/null @@ -1,184 +0,0 @@ -package org.embeddedt.archaicfix.helpers; - -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; -import cpw.mods.fml.common.Loader; -import cpw.mods.fml.relauncher.ReflectionHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.AbstractResourcePack; -import net.minecraft.client.resources.IResourceManager; -import net.minecraft.client.resources.IResourcePack; -import net.minecraft.client.resources.SimpleReloadableResourceManager; -import net.minecraft.client.resources.data.IMetadataSection; -import net.minecraft.client.resources.data.IMetadataSerializer; -import org.apache.commons.io.filefilter.DirectoryFileFilter; - -import java.awt.image.BufferedImage; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -// Inspired by ResourceManagerHelper in fabric-resource-loader-v0 - -public abstract class BuiltInResourcePack extends AbstractResourcePack { - - private static final Splitter entryNameSplitter = Splitter.on('/').omitEmptyStrings().limit(5); - - private String modid; - private final String id; - protected boolean enabled = true; - - /** - *

Register a built-in resource pack. This is a resource pack located in the JAR at {@code "resourcepacks/"}. - * - *

The resource pack is "invisible", it will not show up in the resource pack GUI. - * - * @param id The name of the resource pack. - */ - public static BuiltInResourcePack register(String id) { - BuiltInResourcePack rp = BuiltInResourcePack.of(Loader.instance().activeModContainer().getSource(), Loader.instance().activeModContainer().getModId(), id); - inject(rp); - return rp; - } - - private static BuiltInResourcePack of(File file, String modid, String id) { - if(file.isDirectory()) { - return new BuiltInFolderResourcePack(file, modid, id); - } else { - return new BuiltInFileResourcePack(file, modid, id); - } - } - - public BuiltInResourcePack(File file, String modid, String id) { - super(file); - this.modid = modid; - this.id = id; - } - - @Override - public String getPackName() { - return modid + "/" + id; - } - - @Override - public IMetadataSection getPackMetadata(IMetadataSerializer p_135058_1_, String p_135058_2_) throws IOException { - return null; - } - - @Override - public BufferedImage getPackImage() throws IOException { - return null; - } - - protected String getRootPath() { - return "resourcepacks/" + id + "/"; - } - - protected void addNamespaceIfLowerCase(Set set, String ns) { - if (!ns.equals(ns.toLowerCase())) { - this.logNameNotLowercase(ns); - } else { - set.add(ns); - } - } - - public BuiltInResourcePack setEnabled(boolean enabled) { - this.enabled = enabled; - return this; - } - - @SuppressWarnings("unchecked") - private static void inject(IResourcePack resourcePack) { - List defaultResourcePacks = ReflectionHelper.getPrivateValue(Minecraft.class, Minecraft.getMinecraft(), "defaultResourcePacks", "field_110449_ao"); - defaultResourcePacks.add(resourcePack); - IResourceManager resMan = Minecraft.getMinecraft().getResourceManager(); - if(resMan instanceof SimpleReloadableResourceManager) { - ((SimpleReloadableResourceManager)resMan).reloadResourcePack(resourcePack); - } - } - - private static class BuiltInFileResourcePack extends BuiltInResourcePack { - - private final ZipFile zipFile; - - public BuiltInFileResourcePack(File file, String modid, String id) { - super(file, modid, id); - try { - this.zipFile = new ZipFile(file); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public Set getResourceDomains() { - Set domains = new HashSet<>(); - - Enumeration en = zipFile.entries(); - while(en.hasMoreElements()) { - ZipEntry entry = en.nextElement(); - if(entry.getName().startsWith(getRootPath() + "assets/")) { - List nameParts = Lists.newArrayList(entryNameSplitter.split(entry.getName())); - if(nameParts.size() > 3) { - addNamespaceIfLowerCase(domains, nameParts.get(3)); - } - } - } - return domains; - } - - @Override - protected InputStream getInputStreamByName(String name) throws IOException { - return zipFile.getInputStream(zipFile.getEntry(getRootPath() + name)); - } - - @Override - protected boolean hasResourceName(String name) { - return enabled && zipFile.getEntry(getRootPath() + name) != null; - } - - } - - private static class BuiltInFolderResourcePack extends BuiltInResourcePack { - - public BuiltInFolderResourcePack(File file, String modid, String id) { - super(file, modid, id); - } - - @Override - public Set getResourceDomains() { - Set domains = new HashSet<>(); - - File assetsDir = new File(this.resourcePackFile, getRootPath() + "assets/"); - if(assetsDir.isDirectory()) { - File[] files = assetsDir.listFiles((FileFilter)DirectoryFileFilter.DIRECTORY); - for(File file : files) { - addNamespaceIfLowerCase(domains, file.getName()); - } - } - - return domains; - } - - @Override - protected InputStream getInputStreamByName(String name) throws IOException { - return new BufferedInputStream(new FileInputStream(new File(this.resourcePackFile, getRootPath() + "/" + name))); - } - - @Override - protected boolean hasResourceName(String name) { - return enabled && new File(this.resourcePackFile, getRootPath() + "/" + name).isFile(); - } - - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/ChickenChunkHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/ChickenChunkHelper.java deleted file mode 100644 index 1beb125fd..000000000 --- a/src/main/java/org/embeddedt/archaicfix/helpers/ChickenChunkHelper.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.embeddedt.archaicfix.helpers; - -import codechicken.chunkloader.ChunkLoaderManager; -import net.minecraft.world.WorldServer; - -public class ChickenChunkHelper { - public static void load(WorldServer world) { - ChunkLoaderManager.load(world); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/ChunkQueueSorter.java b/src/main/java/org/embeddedt/archaicfix/helpers/ChunkQueueSorter.java deleted file mode 100644 index c2d55d291..000000000 --- a/src/main/java/org/embeddedt/archaicfix/helpers/ChunkQueueSorter.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.embeddedt.archaicfix.helpers; - -import net.minecraft.world.ChunkCoordIntPair; -import org.apache.commons.lang3.tuple.Pair; - -import java.util.Comparator; - -public class ChunkQueueSorter implements Comparator> { - private final ChunkCoordIntPair[] playerChunks; - - public ChunkQueueSorter(ChunkCoordIntPair[] playerChunks) { - this.playerChunks = playerChunks; - } - - private int averagePlayerDistance(ChunkCoordIntPair pair) { - int shortestDistance = Integer.MAX_VALUE; - for(ChunkCoordIntPair p : playerChunks) { - int xDist = p.chunkXPos - pair.chunkXPos; - int zDist = p.chunkZPos - pair.chunkZPos; - shortestDistance = Math.min(shortestDistance, (xDist * xDist) + (zDist * zDist)); - } - return shortestDistance; - } - - @Override - public int compare(Pair c1, Pair c2) { - int d1 = averagePlayerDistance(c1.getLeft()); - int d2 = averagePlayerDistance(c2.getLeft()); - return d1 - d2; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java deleted file mode 100644 index 57ed2f195..000000000 --- a/src/main/java/org/embeddedt/archaicfix/helpers/DragonAPIHelper.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.embeddedt.archaicfix.helpers; - -import org.apache.commons.lang3.tuple.Pair; - -import java.io.InputStream; -import java.util.Properties; - -public class DragonAPIHelper { - public static boolean isVersionInInclusiveRange(int minMajor, char minMinor, int maxMajor, char maxMinor) { - try(InputStream is = DragonAPIHelper.class.getResourceAsStream("/version_dragonapi.properties")) { - if (is != null) { - Properties props = new Properties(); - props.load(is); - int major = Integer.parseInt(props.getProperty("Major")); - char minor = props.getProperty("Minor").charAt(0); - - Pair min = Pair.of(minMajor, minMinor); - Pair max = Pair.of(maxMajor, maxMinor); - Pair ver = Pair.of(major, minor); - - return min.compareTo(ver) <= 0 && ver.compareTo(max) <= 0; - } - } catch(Exception e) { - e.printStackTrace(); - } - return false; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/NEISearchHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/NEISearchHelper.java deleted file mode 100644 index 2694b0753..000000000 --- a/src/main/java/org/embeddedt/archaicfix/helpers/NEISearchHelper.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.embeddedt.archaicfix.helpers; - -import codechicken.nei.api.ItemInfo; -import net.minecraft.item.ItemStack; - -import java.util.function.Function; - -public class NEISearchHelper implements Function { - @Override - public String apply(ItemStack itemStack) { - return ItemInfo.getSearchName(itemStack); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java b/src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java deleted file mode 100644 index a8503f8ab..000000000 --- a/src/main/java/org/embeddedt/archaicfix/helpers/OreDictIterator.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.embeddedt.archaicfix.helpers; - -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraftforge.oredict.OreDictionary; -import org.apache.commons.lang3.tuple.Pair; - -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; - -/** - * Provides a facility to iterate over a subset of the accelerated ore dictionary. - */ -public class OreDictIterator { - private static final IdentityHashMap, IdentityHashMap>> ITERATOR_CACHE = new IdentityHashMap<>(); - - private static int findStartingIndex(List oreList, Item target) { - int low = 0; - int high = oreList.size() - 1; - int targetId = Item.getIdFromItem(target); - while(low <= high) { - int mid = (low + high) / 2; - ItemStack option = oreList.get(mid); - int comparisonResult; - if(option.getItem() == target) { - ItemStack previous = mid > 0 ? oreList.get(mid-1) : null; - if(previous != null && previous.getItem() == target) { - comparisonResult = 1; - } else { - return mid; - } - } else { - int optionId = Item.getIdFromItem(option.getItem()); - if(optionId < targetId) - comparisonResult = -1; - else if(optionId > targetId) - comparisonResult = 1; - else - throw new IllegalStateException(); - } - if (comparisonResult < 0) - low = mid + 1; - else - high = mid - 1; - } - return low; - } - public static Item getItemFromStack(ItemStack stack) { - if(stack == null) - return null; - else - return stack.getItem(); - } - public static Iterator get(String oreName, Item target) { - if(target == null) - return Collections.emptyIterator(); - List oreList = OreDictionary.getOres(oreName, false); - if (oreList == null) - return Collections.emptyIterator(); - if(oreList.size() < 10) - return oreList.iterator(); - return get(oreList, target); - } - public static Iterator get(List oreList, Item target) { - if(target == null) - return Collections.emptyIterator(); - var targetMap = ITERATOR_CACHE.get(oreList); - if(targetMap == null) { - targetMap = new IdentityHashMap<>(); - ITERATOR_CACHE.put(oreList, targetMap); - } - int startIndex, endIndex; - Pair indices = targetMap.get(target); - if(indices != null) { - startIndex = indices.getLeft(); - endIndex = indices.getRight(); - } else { - int potentialStartIndex = findStartingIndex(oreList, target); - if(potentialStartIndex < 0 || potentialStartIndex >= oreList.size() || oreList.get(potentialStartIndex).getItem() != target) { - startIndex = -1; - endIndex = -1; - } else { - startIndex = potentialStartIndex; - int end = -1; - for(int i = startIndex; i < oreList.size(); i++) { - if(oreList.get(i).getItem() != target) { - end = i; - break; - } - } - if(end == -1) - end = oreList.size(); - endIndex = end; - } - targetMap.put(target, Pair.of(startIndex, endIndex)); - } - if(startIndex == -1 || endIndex == -1) - return Collections.emptyIterator(); - else { - return oreList.subList(startIndex, endIndex).iterator(); - } - } - - public static void clearCache(String oreName) { - List theList = OreDictionary.getOres(oreName, false); - if(theList != null) - ITERATOR_CACHE.remove(theList); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/SoundDeviceThread.java b/src/main/java/org/embeddedt/archaicfix/helpers/SoundDeviceThread.java deleted file mode 100644 index c1a573716..000000000 --- a/src/main/java/org/embeddedt/archaicfix/helpers/SoundDeviceThread.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.embeddedt.archaicfix.helpers; - -import cpw.mods.fml.relauncher.ReflectionHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.client.audio.SoundHandler; -import net.minecraft.client.audio.SoundManager; -import net.minecraft.client.renderer.GLAllocation; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.embeddedt.archaicfix.proxy.ClientProxy; -import org.lwjgl.openal.AL; -import org.lwjgl.openal.ALC10; -import org.lwjgl.openal.ALCdevice; - -import java.nio.IntBuffer; - -public class SoundDeviceThread extends Thread { - private static final int ALC_CONNECTED = 0x313; - public SoundDeviceThread() { - setName("Default Sound Device Checker"); - setDaemon(true); - } - private String getDefault() { - return ALC10.alcGetString(null, ALC10.ALC_DEFAULT_DEVICE_SPECIFIER); - } - - private IntBuffer connectionBuffer = GLAllocation.createDirectIntBuffer(1); - - private boolean isDisconnected(ALCdevice device) { - if(!ALC10.alcIsExtensionPresent(device, "ALC_EXT_disconnect")) - return false; - ALC10.alcGetInteger(device, ALC_CONNECTED, connectionBuffer); - return connectionBuffer.get(0) == ALC10.ALC_FALSE; - } - - public void run() { - try { - String previousDefault = null; - SoundManager manager = ReflectionHelper.getPrivateValue(SoundHandler.class, Minecraft.getMinecraft().getSoundHandler(), "sndManager", "field_147694_f"); - while(!Thread.interrupted()) { - boolean managerLoaded = ReflectionHelper.getPrivateValue(SoundManager.class, manager, "loaded", "field_148617_f"); - if(managerLoaded && !ClientProxy.soundSystemReloadLock) { - if(previousDefault == null) { - previousDefault = getDefault(); - continue; - } - ALCdevice device = AL.getDevice(); - if((device != null && !device.isValid()) || isDisconnected(device) || !previousDefault.equals(getDefault())) { - ArchaicLogger.LOGGER.info("Sound device is not valid anymore, reloading sound system"); - previousDefault = getDefault(); - ClientProxy.soundSystemReloadLock = true; - Minecraft.getMinecraft().func_152344_a(manager::reloadSoundSystem); - } - } - try { - Thread.sleep(1000); - } catch(InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } catch(Throwable e) { - ArchaicLogger.LOGGER.error("An exception occured while checking sound device status", e); - } - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/UnexpectionalObjectArrayList.java b/src/main/java/org/embeddedt/archaicfix/helpers/UnexpectionalObjectArrayList.java deleted file mode 100644 index 20da59516..000000000 --- a/src/main/java/org/embeddedt/archaicfix/helpers/UnexpectionalObjectArrayList.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.embeddedt.archaicfix.helpers; - -import speiger.src.collections.objects.lists.ObjectArrayList; - -/** An ObjectArrayList that has a getter that returns null instead of throwing an exception when the index is out of - * bounds. */ -public class UnexpectionalObjectArrayList extends ObjectArrayList { - public T getOrNull(int index) { - if(index >= 0 && index < size()) { - return data[index]; - } else { - return null; - } - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java b/src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java deleted file mode 100644 index 86f96c516..000000000 --- a/src/main/java/org/embeddedt/archaicfix/helpers/WorldRendererDistanceHelper.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.embeddedt.archaicfix.helpers; - -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.entity.Entity; - -public class WorldRendererDistanceHelper { - /** - * Get the squared distance of this world renderer, adjusted to favor the XZ axes over the Y one. - * @author embeddedt, makamys - * @param e render view entity - * @param instance world renderer - * @return an adjusted squared distance of this renderer from the entity - */ - public static double betterDistanceSquared(Entity e, WorldRenderer instance) { - return instance.distanceToEntitySquared(e); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/interfaces/IAcceleratedRecipe.java b/src/main/java/org/embeddedt/archaicfix/interfaces/IAcceleratedRecipe.java deleted file mode 100644 index 533ae66fd..000000000 --- a/src/main/java/org/embeddedt/archaicfix/interfaces/IAcceleratedRecipe.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.embeddedt.archaicfix.interfaces; - -import net.minecraft.item.Item; - -import java.util.Set; - -public interface IAcceleratedRecipe { - Set getPotentialItems(); - - void invalidatePotentialItems(); -} diff --git a/src/main/java/org/embeddedt/archaicfix/interfaces/IArchaicNetworkManager.java b/src/main/java/org/embeddedt/archaicfix/interfaces/IArchaicNetworkManager.java deleted file mode 100644 index 785e14683..000000000 --- a/src/main/java/org/embeddedt/archaicfix/interfaces/IArchaicNetworkManager.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.embeddedt.archaicfix.interfaces; - -import net.minecraft.network.EnumConnectionState; - -public interface IArchaicNetworkManager { - void setConnectionStateWithoutAutoRead(EnumConnectionState state); -} diff --git a/src/main/java/org/embeddedt/archaicfix/interfaces/ILazyChunkProviderServer.java b/src/main/java/org/embeddedt/archaicfix/interfaces/ILazyChunkProviderServer.java deleted file mode 100644 index e496af8e6..000000000 --- a/src/main/java/org/embeddedt/archaicfix/interfaces/ILazyChunkProviderServer.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.embeddedt.archaicfix.interfaces; - -public interface ILazyChunkProviderServer { - boolean dropLazyChunk(int x, int z, Runnable runnable); -} diff --git a/src/main/java/org/embeddedt/archaicfix/interfaces/IPendingChunk.java b/src/main/java/org/embeddedt/archaicfix/interfaces/IPendingChunk.java deleted file mode 100644 index 5e7722709..000000000 --- a/src/main/java/org/embeddedt/archaicfix/interfaces/IPendingChunk.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.embeddedt.archaicfix.interfaces; - -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.world.ChunkCoordIntPair; - -public interface IPendingChunk { - NBTTagCompound arch$getNbt(); - ChunkCoordIntPair arch$getPos(); -} diff --git a/src/main/java/org/embeddedt/archaicfix/interfaces/IWorldRenderer.java b/src/main/java/org/embeddedt/archaicfix/interfaces/IWorldRenderer.java deleted file mode 100644 index da6a7b519..000000000 --- a/src/main/java/org/embeddedt/archaicfix/interfaces/IWorldRenderer.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.embeddedt.archaicfix.interfaces; - -public interface IWorldRenderer { - boolean arch$isInView(); -} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLighting.java b/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLighting.java deleted file mode 100644 index 8d93d38fb..000000000 --- a/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLighting.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.embeddedt.archaicfix.lighting.api; - -import net.minecraft.world.EnumSkyBlock; - -public interface IChunkLighting { - int getCachedLightFor(EnumSkyBlock enumSkyBlock, int xIn, int yIn, int zIn); -} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLightingData.java b/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLightingData.java deleted file mode 100644 index c8397decb..000000000 --- a/src/main/java/org/embeddedt/archaicfix/lighting/api/IChunkLightingData.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.embeddedt.archaicfix.lighting.api; - -public interface IChunkLightingData { - short[] getNeighborLightChecks(); - - void setNeighborLightChecks(short[] data); - - boolean isLightInitialized(); - - void setLightInitialized(boolean val); - - void setSkylightUpdatedPublic(); -} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngine.java b/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngine.java deleted file mode 100644 index 7510d9ca5..000000000 --- a/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngine.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.embeddedt.archaicfix.lighting.api; - -import net.minecraft.world.EnumSkyBlock; - -public interface ILightingEngine { - void scheduleLightUpdate(EnumSkyBlock lightType, int xIn, int yIn, int zIn); - - void processLightUpdates(); - - void processLightUpdatesForType(EnumSkyBlock lightType); -} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngineProvider.java b/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngineProvider.java deleted file mode 100644 index 7ceeec091..000000000 --- a/src/main/java/org/embeddedt/archaicfix/lighting/api/ILightingEngineProvider.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.embeddedt.archaicfix.lighting.api; - -public interface ILightingEngineProvider { - ILightingEngine getLightingEngine(); -} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/collections/PooledLongQueue.java b/src/main/java/org/embeddedt/archaicfix/lighting/collections/PooledLongQueue.java deleted file mode 100644 index 1fc389877..000000000 --- a/src/main/java/org/embeddedt/archaicfix/lighting/collections/PooledLongQueue.java +++ /dev/null @@ -1,164 +0,0 @@ -package org.embeddedt.archaicfix.lighting.collections; - -import java.util.ArrayDeque; -import java.util.Deque; - -//Implement own queue with pooled segments to reduce allocation costs and reduce idle memory footprint -public class PooledLongQueue { - private static final int CACHED_QUEUE_SEGMENTS_COUNT = 1 << 12; // 4096 - private static final int QUEUE_SEGMENT_SIZE = 1 << 10; // 1024 - - private final Pool pool; - - private Segment cur, last; - - private int size = 0; - - // Stores whether or not the queue is empty. Updates to this field will be seen by all threads immediately. Writes - // to volatile fields are generally quite a bit more expensive, so we avoid repeatedly setting this flag to true. - private volatile boolean empty; - - public PooledLongQueue(Pool pool) { - this.pool = pool; - } - - /** - * Not thread-safe! If you must know whether or not the queue is empty, please use {@link PooledLongQueue#isEmpty()}. - * - * @return The number of encoded values present in this queue - */ - public int size() { - return this.size; - } - - /** - * Thread-safe method to check whether or not this queue has work to do. Significantly cheaper than acquiring a lock. - * @return True if the queue is empty, otherwise false - */ - public boolean isEmpty() { - return this.empty; - } - - /** - * Not thread-safe! Adds an encoded long value into this queue. - * @param val The encoded value to add - */ - public void add(final long val) { - if (this.cur == null) { - this.empty = false; - this.cur = this.last = this.pool.acquire(); - } - - if (this.last.index == QUEUE_SEGMENT_SIZE) { - Segment ret = this.last.next = this.last.pool.acquire(); - ret.longArray[ret.index++] = val; - - this.last = ret; - } else { - this.last.longArray[this.last.index++] = val; - } - - ++this.size; - } - - /** - * Not thread safe! Creates an iterator over the values in this queue. Values will be returned in a FIFO fashion. - * @return The iterator - */ - public LongQueueIterator iterator() { - return new LongQueueIterator(this.cur); - } - - private void clear() { - Segment segment = this.cur; - - while (segment != null) { - Segment next = segment.next; - segment.release(); - segment = next; - } - - this.size = 0; - this.cur = null; - this.last = null; - this.empty = true; - } - - public class LongQueueIterator { - private Segment cur; - private long[] curArray; - - private int index, capacity; - - private LongQueueIterator(Segment cur) { - this.cur = cur; - - if (this.cur != null) { - this.curArray = cur.longArray; - this.capacity = cur.index; - } - } - - public boolean hasNext() { - return this.cur != null; - } - - public long next() { - final long ret = this.curArray[this.index++]; - - if (this.index == this.capacity) { - this.index = 0; - - this.cur = this.cur.next; - - if (this.cur != null) { - this.curArray = this.cur.longArray; - this.capacity = this.cur.index; - } - } - - return ret; - } - - public void finish() { - PooledLongQueue.this.clear(); - } - } - - public static class Pool { - private final Deque segmentPool = new ArrayDeque<>(); - - private Segment acquire() { - if (this.segmentPool.isEmpty()) { - return new Segment(this); - } - - return this.segmentPool.pop(); - } - - private void release(Segment segment) { - if (this.segmentPool.size() < CACHED_QUEUE_SEGMENTS_COUNT) { - this.segmentPool.push(segment); - } - } - } - - private static class Segment { - private final long[] longArray = new long[QUEUE_SEGMENT_SIZE]; - private int index = 0; - private Segment next; - private final Pool pool; - - private Segment(Pool pool) { - this.pool = pool; - } - - private void release() { - this.index = 0; - this.next = null; - - this.pool.release(this); - } - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/WorldChunkSlice.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/WorldChunkSlice.java deleted file mode 100644 index 899a3c268..000000000 --- a/src/main/java/org/embeddedt/archaicfix/lighting/world/WorldChunkSlice.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.embeddedt.archaicfix.lighting.world; - -import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; -import org.embeddedt.archaicfix.lighting.world.lighting.LightingEngineHelpers; - -public class WorldChunkSlice { - private static final int DIAMETER = 5; - - private final Chunk[] chunks; - - private final int x, z; - - public WorldChunkSlice(World world, int x, int z) { - this.chunks = new Chunk[DIAMETER * DIAMETER]; - - int radius = DIAMETER / 2; - - for (int xDiff = -radius; xDiff <= radius; xDiff++) { - for (int zDiff = -radius; zDiff <= radius; zDiff++) { - Chunk chunk = LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(), x + xDiff, z + zDiff); - this.chunks[((xDiff + radius) * DIAMETER) + (zDiff + radius)] = chunk; - } - } - - this.x = x - radius; - this.z = z - radius; - } - - public Chunk getChunk(int x, int z) { - return this.chunks[(x * DIAMETER) + z]; - } - - public Chunk getChunkFromWorldCoords(int x, int z) { - return this.getChunk((x >> 4) - this.x, (z >> 4) - this.z); - } - - public boolean isLoaded(int x, int z, int radius) { - return this.isLoaded(x - radius, z - radius, x + radius, z + radius); - } - - public boolean isLoaded(int xStart, int zStart, int xEnd, int zEnd) { - xStart = (xStart >> 4) - this.x; - zStart = (zStart >> 4) - this.z; - xEnd = (xEnd >> 4) - this.x; - zEnd = (zEnd >> 4) - this.z; - - for (int i = xStart; i <= xEnd; ++i) { - for (int j = zStart; j <= zEnd; ++j) { - if (this.getChunk(i, j) == null) { - return false; - } - } - } - - return true; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/AxisDirection.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/AxisDirection.java deleted file mode 100644 index c39c71e42..000000000 --- a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/AxisDirection.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.embeddedt.archaicfix.lighting.world.lighting; - -public enum AxisDirection { - POSITIVE(1), - NEGATIVE(-1); - - private final int off; - AxisDirection(int off) { - this.off = off; - } - - public int getOffset() { - return off; - } - -} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/BlockPos.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/BlockPos.java deleted file mode 100644 index d1779aa4e..000000000 --- a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/BlockPos.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.embeddedt.archaicfix.lighting.world.lighting; - -/** - * Stub for aiding in porting Phosphor. DO NOT USE in other code. - */ -public class BlockPos { - protected int x, y, z; - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public int getZ() { - return z; - } - - BlockPos() { - - } - - public static class MutableBlockPos extends BlockPos { - public MutableBlockPos() { - this(0, 0, 0); - } - - public MutableBlockPos(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; - } - public MutableBlockPos setPos(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; - return this; - } - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngine.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngine.java deleted file mode 100644 index 1a3d2f40a..000000000 --- a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngine.java +++ /dev/null @@ -1,613 +0,0 @@ -package org.embeddedt.archaicfix.lighting.world.lighting; - -import cpw.mods.fml.common.Loader; -import cpw.mods.fml.relauncher.Side; -import cpw.mods.fml.relauncher.SideOnly; -import net.minecraft.block.Block; -import net.minecraft.client.Minecraft; -import net.minecraft.profiler.Profiler; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.MathHelper; -import net.minecraft.world.EnumSkyBlock; -import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.IChunkProvider; -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.embeddedt.archaicfix.lighting.api.IChunkLighting; -import org.embeddedt.archaicfix.lighting.api.ILightingEngine; -import org.embeddedt.archaicfix.lighting.collections.PooledLongQueue; - -import java.util.concurrent.locks.ReentrantLock; - -public class LightingEngine implements ILightingEngine { - private static final boolean ENABLE_ILLEGAL_THREAD_ACCESS_WARNINGS = true; - private static final int MAX_SCHEDULED_COUNT = 1 << 22; - - private static final int MAX_LIGHT = 15; - - private final Thread ownedThread = Thread.currentThread(); - - private final World world; - - private final Profiler profiler; - - //Layout of longs: [padding(4)] [y(8)] [x(26)] [z(26)] - private final PooledLongQueue[] queuedLightUpdates = new PooledLongQueue[EnumSkyBlock.values().length]; - - //Layout of longs: see above - private final PooledLongQueue[] queuedDarkenings = new PooledLongQueue[MAX_LIGHT + 1]; - private final PooledLongQueue[] queuedBrightenings = new PooledLongQueue[MAX_LIGHT + 1]; - - //Layout of longs: [newLight(4)] [pos(60)] - private final PooledLongQueue initialBrightenings; - //Layout of longs: [padding(4)] [pos(60)] - private final PooledLongQueue initialDarkenings; - - private boolean updating = false; - - //Layout parameters - //Length of bit segments - private static final int - lX = 26, - lY = 8, - lZ = 26, - lL = 4; - - //Bit segment shifts/positions - private static final int - sZ = 0, - sX = sZ + lZ, - sY = sX + lX, - sL = sY + lY; - - //Bit segment masks - private static final long - mX = (1L << lX) - 1, - mY = (1L << lY) - 1, - mZ = (1L << lZ) - 1, - mL = (1L << lL) - 1, - mPos = (mY << sY) | (mX << sX) | (mZ << sZ); - - //Bit to check whether y had overflow - private static final long yCheck = 1L << (sY + lY); - - private static final long[] neighborShifts = new long[6]; - - static { - EnumFacing[] values = new EnumFacing[] { EnumFacing.DOWN, EnumFacing.UP, EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.WEST, EnumFacing.EAST }; - for (int i = 0; i < 6; ++i) { - neighborShifts[i] = ((long) values[i].getFrontOffsetY() << sY) | ((long) values[i].getFrontOffsetX() << sX) | ((long) values[i].getFrontOffsetZ() << sZ); - } - } - - //Mask to extract chunk identifier - private static final long mChunk = ((mX >> 4) << (4 + sX)) | ((mZ >> 4) << (4 + sZ)); - - //Iteration state data - //Cache position to avoid allocation of new object each time - private final BlockPos.MutableBlockPos curPos = new BlockPos.MutableBlockPos(); - private Chunk curChunk; - private long curChunkIdentifier; - private long curData; - static boolean isDynamicLightsLoaded; - - //Cached data about neighboring blocks (of tempPos) - private boolean isNeighborDataValid = false; - - private final NeighborInfo[] neighborInfos = new NeighborInfo[6]; - private PooledLongQueue.LongQueueIterator queueIt; - - private final ReentrantLock lock = new ReentrantLock(); - - public LightingEngine(final World world) { - this.world = world; - this.profiler = world.theProfiler; - isDynamicLightsLoaded = Loader.isModLoaded("DynamicLights"); - - PooledLongQueue.Pool pool = new PooledLongQueue.Pool(); - - this.initialBrightenings = new PooledLongQueue(pool); - this.initialDarkenings = new PooledLongQueue(pool); - - for (int i = 0; i < EnumSkyBlock.values().length; ++i) { - this.queuedLightUpdates[i] = new PooledLongQueue(pool); - } - - for (int i = 0; i < this.queuedDarkenings.length; ++i) { - this.queuedDarkenings[i] = new PooledLongQueue(pool); - } - - for (int i = 0; i < this.queuedBrightenings.length; ++i) { - this.queuedBrightenings[i] = new PooledLongQueue(pool); - } - - for (int i = 0; i < this.neighborInfos.length; ++i) { - this.neighborInfos[i] = new NeighborInfo(); - } - } - - /** - * Schedules a light update for the specified light type and position to be processed later by {@link ILightingEngine#processLightUpdatesForType(EnumSkyBlock)} - */ - @Override - public void scheduleLightUpdate(final EnumSkyBlock lightType, final int xIn, final int yIn, final int zIn) { - this.acquireLock(); - - try { - this.scheduleLightUpdate(lightType, encodeWorldCoord(xIn, yIn, zIn)); - } finally { - this.releaseLock(); - } - } - - /** - * Schedules a light update for the specified light type and position to be processed later by {@link ILightingEngine#processLightUpdates()} - */ - private void scheduleLightUpdate(final EnumSkyBlock lightType, final long pos) { - final PooledLongQueue queue = this.queuedLightUpdates[lightType.ordinal()]; - - queue.add(pos); - - //make sure there are not too many queued light updates - if (queue.size() >= MAX_SCHEDULED_COUNT) { - this.processLightUpdatesForType(lightType); - } - } - - /** - * Calls {@link ILightingEngine#processLightUpdatesForType(EnumSkyBlock)} for both light types - * - */ - @Override - public void processLightUpdates() { - this.processLightUpdatesForType(EnumSkyBlock.Sky); - this.processLightUpdatesForType(EnumSkyBlock.Block); - } - - /** - * Processes light updates of the given light type - */ - @Override - public void processLightUpdatesForType(final EnumSkyBlock lightType) { - // We only want to perform updates if we're being called from a tick event on the client - // There are many locations in the client code which will end up making calls to this method, usually from - // other threads. - if (this.world.isRemote && !this.isCallingFromMainThread()) { - return; - } - - final PooledLongQueue queue = this.queuedLightUpdates[lightType.ordinal()]; - - // Quickly check if the queue is empty before we acquire a more expensive lock. - if (queue.isEmpty()) { - return; - } - - this.acquireLock(); - - try { - this.processLightUpdatesForTypeInner(lightType, queue); - } finally { - this.releaseLock(); - } - } - - @SideOnly(Side.CLIENT) - private boolean isCallingFromMainThread() { - return Minecraft.getMinecraft().func_152345_ab(); - } - - private void acquireLock() { - if (!this.lock.tryLock()) { - // If we cannot lock, something has gone wrong... Only one thread should ever acquire the lock. - // Validate that we're on the right thread immediately so we can gather information. - // It is NEVER valid to call World methods from a thread other than the owning thread of the world instance. - // Users can safely disable this warning, however it will not resolve the issue. - if (ENABLE_ILLEGAL_THREAD_ACCESS_WARNINGS) { - Thread current = Thread.currentThread(); - - if (current != this.ownedThread) { - IllegalAccessException e = new IllegalAccessException(String.format("World is owned by '%s' (ID: %s)," + - " but was accessed from thread '%s' (ID: %s)", - this.ownedThread.getName(), this.ownedThread.getId(), current.getName(), current.getId())); - - ArchaicLogger.LOGGER.warn( - "Something (likely another mod) has attempted to modify the world's state from the wrong thread!\n" + - "This is *bad practice* and can cause severe issues in your game. Phosphor has done as best as it can to mitigate this violation," + - " but it may negatively impact performance or introduce stalls.\nIn a future release, this violation may result in a hard crash instead" + - " of the current soft warning. You should report this issue to our issue tracker with the following stacktrace information.\n(If you are" + - " aware you have misbehaving mods and cannot resolve this issue, you can safely disable this warning by setting" + - " `enable_illegal_thread_access_warnings` to `false` in Phosphor's configuration file for the time being.)", e); - - } - - } - - // Wait for the lock to be released. This will likely introduce unwanted stalls, but will mitigate the issue. - this.lock.lock(); - } - } - - private void releaseLock() { - this.lock.unlock(); - } - - private void processLightUpdatesForTypeInner(final EnumSkyBlock lightType, final PooledLongQueue queue) { - //avoid nested calls - if (this.updating) { - throw new IllegalStateException("Already processing updates!"); - } - - this.updating = true; - - this.curChunkIdentifier = -1; //reset chunk cache - - this.profiler.startSection("lighting"); - - this.profiler.startSection("checking"); - - this.queueIt = queue.iterator(); - - //process the queued updates and enqueue them for further processing - while (this.nextItem()) { - if (this.curChunk == null) { - continue; - } - - final int oldLight = this.getCursorCachedLight(lightType); - final int newLight = this.calculateNewLightFromCursor(lightType); - - if (oldLight < newLight) { - //don't enqueue directly for brightening in order to avoid duplicate scheduling - this.initialBrightenings.add(((long) newLight << sL) | this.curData); - } else if (oldLight > newLight) { - //don't enqueue directly for darkening in order to avoid duplicate scheduling - this.initialDarkenings.add(this.curData); - } - } - - this.queueIt = this.initialBrightenings.iterator(); - - while (this.nextItem()) { - final int newLight = (int) (this.curData >> sL & mL); - - if (newLight > this.getCursorCachedLight(lightType)) { - //Sets the light to newLight to only schedule once. Clear leading bits of curData for later - this.enqueueBrightening(this.curPos, this.curData & mPos, newLight, this.curChunk, lightType); - } - } - - this.queueIt = this.initialDarkenings.iterator(); - - while (this.nextItem()) { - final int oldLight = this.getCursorCachedLight(lightType); - - if (oldLight != 0) { - //Sets the light to 0 to only schedule once - this.enqueueDarkening(this.curPos, this.curData, oldLight, this.curChunk, lightType); - } - } - - this.profiler.endSection(); - - //Iterate through enqueued updates (brightening and darkening in parallel) from brightest to darkest so that we only need to iterate once - for (int curLight = MAX_LIGHT; curLight >= 0; --curLight) { - this.profiler.startSection("darkening"); - - this.queueIt = this.queuedDarkenings[curLight].iterator(); - - while (this.nextItem()) { - if (this.getCursorCachedLight(lightType) >= curLight) //don't darken if we got brighter due to some other change - { - continue; - } - - final Block state = LightingEngineHelpers.posToState(this.curPos, this.curChunk); - final int luminosity = this.getCursorLuminosity(state, lightType); - final int opacity; //if luminosity is high enough, opacity is irrelevant - - if (luminosity >= MAX_LIGHT - 1) { - opacity = 1; - } else { - opacity = this.getPosOpacity(this.curPos, state); - } - - //only darken neighbors if we indeed became darker - if (this.calculateNewLightFromCursor(luminosity, opacity, lightType) < curLight) { - //need to calculate new light value from neighbors IGNORING neighbors which are scheduled for darkening - int newLight = luminosity; - - this.fetchNeighborDataFromCursor(lightType); - - for (NeighborInfo info : this.neighborInfos) { - final Chunk nChunk = info.chunk; - - if (nChunk == null) { - continue; - } - - final int nLight = info.light; - - if (nLight == 0) { - continue; - } - - final BlockPos.MutableBlockPos nPos = info.pos; - - if (curLight - this.getPosOpacity(nPos, LightingEngineHelpers.posToState(nPos, info.section)) >= nLight) //schedule neighbor for darkening if we possibly light it - { - this.enqueueDarkening(nPos, info.key, nLight, nChunk, lightType); - } else //only use for new light calculation if not - { - //if we can't darken the neighbor, no one else can (because of processing order) -> safe to let us be illuminated by it - newLight = Math.max(newLight, nLight - opacity); - } - } - - //schedule brightening since light level was set to 0 - this.enqueueBrighteningFromCursor(newLight, lightType); - } else //we didn't become darker, so we need to re-set our initial light value (was set to 0) and notify neighbors - { - this.enqueueBrighteningFromCursor(curLight, lightType); //do not spread to neighbors immediately to avoid scheduling multiple times - } - } - - this.profiler.endStartSection("brightening"); - - this.queueIt = this.queuedBrightenings[curLight].iterator(); - - while (this.nextItem()) { - final int oldLight = this.getCursorCachedLight(lightType); - - if (oldLight == curLight) //only process this if nothing else has happened at this position since scheduling - { - this.world.func_147479_m(this.curPos.getX(), this.curPos.getY(), this.curPos.getZ()); - - if (curLight > 1) { - this.spreadLightFromCursor(curLight, lightType); - } - } - } - - this.profiler.endSection(); - } - - this.profiler.endSection(); - - this.updating = false; - } - - /** - * Gets data for neighbors of curPos and saves the results into neighbor state data members. If a neighbor can't be accessed/doesn't exist, the corresponding entry in neighborChunks is null - others are not reset - */ - private void fetchNeighborDataFromCursor(final EnumSkyBlock lightType) { - //only update if curPos was changed - if (this.isNeighborDataValid) { - return; - } - - this.isNeighborDataValid = true; - - for (int i = 0; i < this.neighborInfos.length; ++i) { - NeighborInfo info = this.neighborInfos[i]; - - final long nLongPos = info.key = this.curData + neighborShifts[i]; - - if ((nLongPos & yCheck) != 0) { - info.chunk = null; - info.section = null; - continue; - } - - final BlockPos.MutableBlockPos nPos = decodeWorldCoord(info.pos, nLongPos); - - final Chunk nChunk; - - if ((nLongPos & mChunk) == this.curChunkIdentifier) { - nChunk = info.chunk = this.curChunk; - } else { - nChunk = info.chunk = this.getChunk(nPos); - } - - if (nChunk != null) { - ExtendedBlockStorage nSection = nChunk.getBlockStorageArray()[nPos.getY() >> 4]; - - info.light = getCachedLightFor(nChunk, nSection, nPos, lightType); - info.section = nSection; - } - } - } - - - private static int getCachedLightFor(Chunk chunk, ExtendedBlockStorage storage, BlockPos pos, EnumSkyBlock type) { - int i = pos.getX() & 15; - int j = pos.getY(); - int k = pos.getZ() & 15; - - if (storage == null) { - if (type == EnumSkyBlock.Sky && chunk.canBlockSeeTheSky(i, j, k)) { - return type.defaultLightValue; - } else { - return 0; - } - } else if (type == EnumSkyBlock.Sky) { - if (chunk.worldObj.provider.hasNoSky) { - return 0; - } else { - return storage.getExtSkylightValue(i, j & 15, k); - } - } else { - if (type == EnumSkyBlock.Block) { - return storage.getExtBlocklightValue(i, j & 15, k); - } else { - return type.defaultLightValue; - } - } - } - - - private int calculateNewLightFromCursor(final EnumSkyBlock lightType) { - final Block state = LightingEngineHelpers.posToState(this.curPos, this.curChunk); - - final int luminosity = this.getCursorLuminosity(state, lightType); - final int opacity; - - if (luminosity >= MAX_LIGHT - 1) { - opacity = 1; - } else { - opacity = this.getPosOpacity(this.curPos, state); - } - - return this.calculateNewLightFromCursor(luminosity, opacity, lightType); - } - - private int calculateNewLightFromCursor(final int luminosity, final int opacity, final EnumSkyBlock lightType) { - if (luminosity >= MAX_LIGHT - opacity) { - return luminosity; - } - - int newLight = luminosity; - - this.fetchNeighborDataFromCursor(lightType); - - for (NeighborInfo info : this.neighborInfos) { - if (info.chunk == null) { - continue; - } - - final int nLight = info.light; - - newLight = Math.max(nLight - opacity, newLight); - } - - return newLight; - } - - private void spreadLightFromCursor(final int curLight, final EnumSkyBlock lightType) { - this.fetchNeighborDataFromCursor(lightType); - - for (NeighborInfo info : this.neighborInfos) { - final Chunk nChunk = info.chunk; - - if (nChunk == null) { - continue; - } - - final int newLight = curLight - this.getPosOpacity(info.pos, LightingEngineHelpers.posToState(info.pos, info.section)); - - if (newLight > info.light) { - this.enqueueBrightening(info.pos, info.key, newLight, nChunk, lightType); - } - } - } - - private void enqueueBrighteningFromCursor(final int newLight, final EnumSkyBlock lightType) { - this.enqueueBrightening(this.curPos, this.curData, newLight, this.curChunk, lightType); - } - - /** - * Enqueues the pos for brightening and sets its light value to newLight - */ - private void enqueueBrightening(final BlockPos pos, final long longPos, final int newLight, final Chunk chunk, final EnumSkyBlock lightType) { - this.queuedBrightenings[newLight].add(longPos); - - chunk.setLightValue(lightType, pos.getX() & 15, pos.getY(), pos.getZ() & 15, newLight); - } - - /** - * Enqueues the pos for darkening and sets its light value to 0 - */ - private void enqueueDarkening(final BlockPos pos, final long longPos, final int oldLight, final Chunk chunk, final EnumSkyBlock lightType) { - this.queuedDarkenings[oldLight].add(longPos); - - chunk.setLightValue(lightType, pos.getX() & 15, pos.getY(), pos.getZ() & 15, 0); - } - - private static BlockPos.MutableBlockPos decodeWorldCoord(final BlockPos.MutableBlockPos pos, final long longPos) { - final int posX = (int) (longPos >> sX & mX) - (1 << lX - 1); - final int posY = (int) (longPos >> sY & mY); - final int posZ = (int) (longPos >> sZ & mZ) - (1 << lZ - 1); - - return pos.setPos(posX, posY, posZ); - } - - private static long encodeWorldCoord(final long x, final long y, final long z) { - return (y << sY) | (x + (1 << lX - 1) << sX) | (z + (1 << lZ - 1) << sZ); - } - - private static int ITEMS_PROCESSED = 0, CHUNKS_FETCHED = 0; - - /** - * Polls a new item from curQueue and fills in state data members - * - * @return If there was an item to poll - */ - private boolean nextItem() { - if (!this.queueIt.hasNext()) { - this.queueIt.finish(); - this.queueIt = null; - - return false; - } - - this.curData = this.queueIt.next(); - this.isNeighborDataValid = false; - - decodeWorldCoord(this.curPos, this.curData); - - final long chunkIdentifier = this.curData & mChunk; - - if (this.curChunkIdentifier != chunkIdentifier) { - this.curChunk = this.getChunk(this.curPos); - this.curChunkIdentifier = chunkIdentifier; - CHUNKS_FETCHED++; - } - - ITEMS_PROCESSED++; - - return true; - } - - private int getCursorCachedLight(final EnumSkyBlock lightType) { - return ((IChunkLighting) this.curChunk).getCachedLightFor(lightType, this.curPos.getX(), this.curPos.getY(), this.curPos.getZ()); - } - - /** - * Calculates the luminosity for curPos, taking into account lightType - */ - private int getCursorLuminosity(final Block state, final EnumSkyBlock lightType) { - if (lightType == EnumSkyBlock.Sky) { - if (this.curChunk.canBlockSeeTheSky(this.curPos.getX() & 15, this.curPos.getY(), this.curPos.getZ() & 15)) { - return EnumSkyBlock.Sky.defaultLightValue; - } else { - return 0; - } - } - - return MathHelper.clamp_int(LightingEngineHelpers.getLightValueForState(state, this.world, this.curPos.getX(), this.curPos.getY(), this.curPos.getZ()), 0, MAX_LIGHT); - } - - private int getPosOpacity(final BlockPos pos, final Block state) { - return MathHelper.clamp_int(state.getLightOpacity(world, pos.getX(), pos.getY(), pos.getZ()), 1, MAX_LIGHT); - } - - private Chunk getChunk(final BlockPos pos) { - IChunkProvider prov = this.world.getChunkProvider(); - int chunkX = pos.getX() >> 4; - int chunkZ = pos.getZ() >> 4; - return LightingEngineHelpers.getLoadedChunk(prov, chunkX, chunkZ); - } - - private static class NeighborInfo { - Chunk chunk; - ExtendedBlockStorage section; - - int light; - - long key; - - final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); - } -} - diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngineHelpers.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngineHelpers.java deleted file mode 100644 index b758467ee..000000000 --- a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingEngineHelpers.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.embeddedt.archaicfix.lighting.world.lighting; - -import atomicstryker.dynamiclights.client.DynamicLights; -import net.minecraft.block.Block; -import net.minecraft.init.Blocks; -import net.minecraft.world.IBlockAccess; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.IChunkProvider; -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; - -public class LightingEngineHelpers { - private static final Block DEFAULT_BLOCK_STATE = Blocks.air; - - // Avoids some additional logic in Chunk#getBlockState... 0 is always air - static Block posToState(final BlockPos pos, final Chunk chunk) { - return posToState(pos, chunk.getBlockStorageArray()[pos.getY() >> 4]); - } - - static Block posToState(final BlockPos pos, final ExtendedBlockStorage section) { - final int x = pos.getX(); - final int y = pos.getY(); - final int z = pos.getZ(); - - if (section != null) - { - return section.getBlockByExtId(x & 15, y & 15, z & 15); - } - - return DEFAULT_BLOCK_STATE; - } - - static int getLightValueForState(final Block state, final IBlockAccess world, final int x, final int y, final int z) { - if(LightingEngine.isDynamicLightsLoaded) { - return DynamicLights.getLightValue(world, state, x, y, z); - } else - return state.getLightValue(world, x, y, z); - } - - public static Chunk getLoadedChunk(final IChunkProvider provider, int chunkX, int chunkZ) { - if(!provider.chunkExists(chunkX, chunkZ)) - return null; - return provider.provideChunk(chunkX, chunkZ); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java b/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java deleted file mode 100644 index e56bfa424..000000000 --- a/src/main/java/org/embeddedt/archaicfix/lighting/world/lighting/LightingHooks.java +++ /dev/null @@ -1,431 +0,0 @@ -package org.embeddedt.archaicfix.lighting.world.lighting; - -import net.minecraft.block.Block; -import net.minecraft.init.Blocks; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.nbt.NBTTagShort; -import net.minecraft.util.EnumFacing; -import net.minecraft.world.EnumSkyBlock; -import net.minecraft.world.World; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.embeddedt.archaicfix.lighting.api.IChunkLighting; -import org.embeddedt.archaicfix.lighting.api.IChunkLightingData; -import org.embeddedt.archaicfix.lighting.api.ILightingEngine; -import org.embeddedt.archaicfix.lighting.api.ILightingEngineProvider; - -@SuppressWarnings("unused") -public class LightingHooks { - private static final EnumSkyBlock[] ENUM_SKY_BLOCK_VALUES = EnumSkyBlock.values(); - - private static final AxisDirection[] ENUM_AXIS_DIRECTION_VALUES = AxisDirection.values(); - - public static final EnumFacing[] HORIZONTAL_FACINGS = new EnumFacing[] { EnumFacing.SOUTH, EnumFacing.WEST, EnumFacing.NORTH, EnumFacing.EAST }; - - private static final int FLAG_COUNT = 32; //2 light types * 4 directions * 2 halves * (inwards + outwards) - - public static void relightSkylightColumn(final World world, final Chunk chunk, final int x, final int z, final int height1, final int height2) { - final int yMin = Math.min(height1, height2); - final int yMax = Math.max(height1, height2) - 1; - - final ExtendedBlockStorage[] sections = chunk.getBlockStorageArray(); - - final int xBase = (chunk.xPosition << 4) + x; - final int zBase = (chunk.zPosition << 4) + z; - - scheduleRelightChecksForColumn(world, EnumSkyBlock.Sky, xBase, zBase, yMin, yMax); - - if (sections[yMin >> 4] == null && yMin > 0) { - world.updateLightByType(EnumSkyBlock.Sky, xBase, yMin - 1, zBase); - } - - short emptySections = 0; - - for (int sec = yMax >> 4; sec >= yMin >> 4; --sec) { - if (sections[sec] == null) { - emptySections |= 1 << sec; - } - } - - if (emptySections != 0) { - for (final EnumFacing dir : HORIZONTAL_FACINGS) { - final int xOffset = dir.getFrontOffsetX(); - final int zOffset = dir.getFrontOffsetZ(); - - final boolean neighborColumnExists = - (((x + xOffset) | (z + zOffset)) & 16) == 0 - //Checks whether the position is at the specified border (the 16 bit is set for both 15+1 and 0-1) - || LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(), chunk.xPosition + xOffset, chunk.zPosition + zOffset) != null; - - if (neighborColumnExists) { - for (int sec = yMax >> 4; sec >= yMin >> 4; --sec) { - if ((emptySections & (1 << sec)) != 0) { - scheduleRelightChecksForColumn(world, EnumSkyBlock.Sky, xBase + xOffset, zBase + zOffset, sec << 4, (sec << 4) + 15); - } - } - } else { - flagChunkBoundaryForUpdate(chunk, emptySections, EnumSkyBlock.Sky, dir, getAxisDirection(dir, x, z), EnumBoundaryFacing.OUT); - } - } - } - } - - public static void scheduleRelightChecksForArea(final World world, final EnumSkyBlock lightType, final int xMin, final int yMin, final int zMin, - final int xMax, final int yMax, final int zMax) { - for (int x = xMin; x <= xMax; ++x) { - for (int z = zMin; z <= zMax; ++z) { - scheduleRelightChecksForColumn(world, lightType, x, z, yMin, yMax); - } - } - } - - private static void scheduleRelightChecksForColumn(final World world, final EnumSkyBlock lightType, final int x, final int z, final int yMin, final int yMax) { - for (int y = yMin; y <= yMax; ++y) { - world.updateLightByType(lightType, x, y, z); - } - } - - public enum EnumBoundaryFacing { - IN, OUT; - - public EnumBoundaryFacing getOpposite() { - return this == IN ? OUT : IN; - } - } - - public static void flagSecBoundaryForUpdate(final Chunk chunk, final BlockPos pos, final EnumSkyBlock lightType, final EnumFacing dir, - final EnumBoundaryFacing boundaryFacing) { - flagChunkBoundaryForUpdate(chunk, (short) (1 << (pos.getY() >> 4)), lightType, dir, getAxisDirection(dir, pos.getX(), pos.getZ()), boundaryFacing); - } - - public static void flagChunkBoundaryForUpdate(final Chunk chunk, final short sectionMask, final EnumSkyBlock lightType, final EnumFacing dir, - final AxisDirection axisDirection, final EnumBoundaryFacing boundaryFacing) { - initNeighborLightChecks(chunk); - ((IChunkLightingData) chunk).getNeighborLightChecks()[getFlagIndex(lightType, dir, axisDirection, boundaryFacing)] |= sectionMask; - chunk.setChunkModified(); - } - - public static int getFlagIndex(final EnumSkyBlock lightType, final int xOffset, final int zOffset, final AxisDirection axisDirection, - final EnumBoundaryFacing boundaryFacing) { - return (lightType == EnumSkyBlock.Block ? 0 : 16) | ((xOffset + 1) << 2) | ((zOffset + 1) << 1) | (axisDirection.getOffset() + 1) | boundaryFacing - .ordinal(); - } - - public static int getFlagIndex(final EnumSkyBlock lightType, final EnumFacing dir, final AxisDirection axisDirection, - final EnumBoundaryFacing boundaryFacing) { - return getFlagIndex(lightType, dir.getFrontOffsetX(), dir.getFrontOffsetZ(), axisDirection, boundaryFacing); - } - - private static AxisDirection getAxisDirection(final EnumFacing dir, final int x, final int z) { - return (((dir == EnumFacing.EAST || dir == EnumFacing.WEST) ? z : x) & 15) < 8 ? AxisDirection.NEGATIVE : AxisDirection.POSITIVE; - } - - private static EnumFacing getOpposite(EnumFacing in) { - return switch (in) { - case NORTH -> EnumFacing.SOUTH; - case SOUTH -> EnumFacing.NORTH; - case EAST -> EnumFacing.WEST; - case WEST -> EnumFacing.EAST; - case DOWN -> EnumFacing.UP; - case UP -> EnumFacing.DOWN; - default -> throw new IllegalArgumentException(); - }; - } - - private static AxisDirection getAxisDirection(EnumFacing in) { - switch (in) { - case DOWN: - case NORTH: - case WEST: - return AxisDirection.NEGATIVE; - default: - return AxisDirection.POSITIVE; - } - } - - public static void scheduleRelightChecksForChunkBoundaries(final World world, final Chunk chunk) { - for (final EnumFacing dir : HORIZONTAL_FACINGS) { - final int xOffset = dir.getFrontOffsetX(); - final int zOffset = dir.getFrontOffsetZ(); - - final Chunk nChunk = LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(), chunk.xPosition + xOffset, chunk.zPosition + zOffset); - - if(nChunk == null) - continue; - - for (final EnumSkyBlock lightType : ENUM_SKY_BLOCK_VALUES) { - for (final AxisDirection axisDir : ENUM_AXIS_DIRECTION_VALUES) { - //Merge flags upon loading of a chunk. This ensures that all flags are always already on the IN boundary below - mergeFlags(lightType, chunk, nChunk, dir, axisDir); - mergeFlags(lightType, nChunk, chunk, getOpposite(dir), axisDir); - - //Check everything that might have been canceled due to this chunk not being loaded. - //Also, pass in chunks if already known - //The boundary to the neighbor chunk (both ways) - scheduleRelightChecksForBoundary(world, chunk, nChunk, null, lightType, xOffset, zOffset, axisDir); - scheduleRelightChecksForBoundary(world, nChunk, chunk, null, lightType, -xOffset, -zOffset, axisDir); - //The boundary to the diagonal neighbor (since the checks in that chunk were aborted if this chunk wasn't loaded, see scheduleRelightChecksForBoundary) - scheduleRelightChecksForBoundary(world, nChunk, null, chunk, lightType, (zOffset != 0 ? axisDir.getOffset() : 0), - (xOffset != 0 ? axisDir.getOffset() : 0), getAxisDirection(dir) == AxisDirection.POSITIVE ? - AxisDirection.NEGATIVE : - AxisDirection.POSITIVE); - } - } - } - } - - private static void mergeFlags(final EnumSkyBlock lightType, final Chunk inChunk, final Chunk outChunk, final EnumFacing dir, - final AxisDirection axisDir) { - IChunkLightingData outChunkLightingData = (IChunkLightingData) outChunk; - - if (outChunkLightingData.getNeighborLightChecks() == null) { - return; - } - - IChunkLightingData inChunkLightingData = (IChunkLightingData) inChunk; - - initNeighborLightChecks(inChunk); - - final int inIndex = getFlagIndex(lightType, dir, axisDir, EnumBoundaryFacing.IN); - final int outIndex = getFlagIndex(lightType, getOpposite(dir), axisDir, EnumBoundaryFacing.OUT); - - inChunkLightingData.getNeighborLightChecks()[inIndex] |= outChunkLightingData.getNeighborLightChecks()[outIndex]; - //no need to call Chunk.setModified() since checks are not deleted from outChunk - } - - private static void scheduleRelightChecksForBoundary(final World world, final Chunk chunk, Chunk nChunk, Chunk sChunk, final EnumSkyBlock lightType, - final int xOffset, final int zOffset, final AxisDirection axisDir) { - IChunkLightingData chunkLightingData = (IChunkLightingData) chunk; - - if (chunkLightingData.getNeighborLightChecks() == null) { - return; - } - - final int flagIndex = getFlagIndex(lightType, xOffset, zOffset, axisDir, EnumBoundaryFacing.IN); //OUT checks from neighbor are already merged - - final int flags = chunkLightingData.getNeighborLightChecks()[flagIndex]; - - if (flags == 0) { - return; - } - - if (nChunk == null) { - nChunk = LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(),chunk.xPosition + xOffset, chunk.zPosition + zOffset); - if(nChunk == null) - return; - } - - if (sChunk == null) { - int theX = chunk.xPosition + (zOffset != 0 ? axisDir.getOffset() : 0); - int theZ = chunk.zPosition + (xOffset != 0 ? axisDir.getOffset() : 0); - - sChunk = LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(), theX, theZ); - if(sChunk == null) - return; - } - - final int reverseIndex = getFlagIndex(lightType, -xOffset, -zOffset, axisDir, EnumBoundaryFacing.OUT); - - chunkLightingData.getNeighborLightChecks()[flagIndex] = 0; - - IChunkLightingData nChunkLightingData = (IChunkLightingData) nChunk; - - if (nChunkLightingData.getNeighborLightChecks() != null) { - nChunkLightingData.getNeighborLightChecks()[reverseIndex] = 0; //Clear only now that it's clear that the checks are processed - } - - chunk.setChunkModified(); - nChunk.setChunkModified(); - - //Get the area to check - //Start in the corner... - int xMin = chunk.xPosition << 4; - int zMin = chunk.zPosition << 4; - - //move to other side of chunk if the direction is positive - if ((xOffset | zOffset) > 0) { - xMin += 15 * xOffset; - zMin += 15 * zOffset; - } - - //shift to other half if necessary (shift perpendicular to dir) - if (axisDir == AxisDirection.POSITIVE) { - xMin += 8 * (zOffset & 1); //x & 1 is same as abs(x) for x=-1,0,1 - zMin += 8 * (xOffset & 1); - } - - //get maximal values (shift perpendicular to dir) - final int xMax = xMin + 7 * (zOffset & 1); - final int zMax = zMin + 7 * (xOffset & 1); - - for (int y = 0; y < 16; ++y) { - if ((flags & (1 << y)) != 0) { - scheduleRelightChecksForArea(world, lightType, xMin, y << 4, zMin, xMax, (y << 4) + 15, zMax); - } - } - } - - public static void initNeighborLightChecks(final Chunk chunk) { - IChunkLightingData lightingData = (IChunkLightingData) chunk; - - if (lightingData.getNeighborLightChecks() == null) { - lightingData.setNeighborLightChecks(new short[FLAG_COUNT]); - } - } - - public static final String neighborLightChecksKey = "NeighborLightChecks"; - - public static void writeNeighborLightChecksToNBT(final Chunk chunk, final NBTTagCompound nbt) { - short[] neighborLightChecks = ((IChunkLightingData) chunk).getNeighborLightChecks(); - - if (neighborLightChecks == null) { - return; - } - - boolean empty = true; - - final NBTTagList list = new NBTTagList(); - - for (final short flags : neighborLightChecks) { - list.appendTag(new NBTTagShort(flags)); - - if (flags != 0) { - empty = false; - } - } - - if (!empty) { - nbt.setTag(neighborLightChecksKey, list); - } - } - - public static void readNeighborLightChecksFromNBT(final Chunk chunk, final NBTTagCompound nbt) { - if (nbt.hasKey(neighborLightChecksKey, 9)) { - final NBTTagList list = nbt.getTagList(neighborLightChecksKey, 2); - - if (list.tagCount() == FLAG_COUNT) { - initNeighborLightChecks(chunk); - - short[] neighborLightChecks = ((IChunkLightingData) chunk).getNeighborLightChecks(); - - for (int i = 0; i < FLAG_COUNT; ++i) { - neighborLightChecks[i] = ((NBTTagShort) list.tagList.get(i)).func_150289_e(); - } - } else { - ArchaicLogger.LOGGER.warn("Chunk field {} had invalid length, ignoring it (chunk coordinates: {} {})", neighborLightChecksKey, chunk.xPosition, chunk.zPosition); - } - } - } - - public static void initChunkLighting(final Chunk chunk, final World world) { - final int xBase = chunk.xPosition << 4; - final int zBase = chunk.zPosition << 4; - - final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(xBase, 0, zBase); - - if (world.checkChunksExist(xBase - 16, 0, zBase - 16, xBase + 31, 255, zBase + 31)) { - final ExtendedBlockStorage[] extendedBlockStorage = chunk.getBlockStorageArray(); - - for (int j = 0; j < extendedBlockStorage.length; ++j) { - final ExtendedBlockStorage storage = extendedBlockStorage[j]; - - if (storage == null) { - continue; - } - - int yBase = j * 16; - - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++) { - Block block = storage.getBlockByExtId(x, y, z); - if(block != Blocks.air) { - pos.setPos(xBase + x, yBase + y, zBase + z); - int light = LightingEngineHelpers.getLightValueForState(block, world, pos.getX(), pos.getY(), pos.getZ()); - - if (light > 0) { - world.updateLightByType(EnumSkyBlock.Block, pos.getX(), pos.getY(), pos.getZ()); - } - } - } - } - } - } - - if (!world.provider.hasNoSky) { - ((IChunkLightingData) chunk).setSkylightUpdatedPublic(); - } - - ((IChunkLightingData) chunk).setLightInitialized(true); - } - } - - public static void checkChunkLighting(final Chunk chunk, final World world) { - if (!((IChunkLightingData) chunk).isLightInitialized()) { - initChunkLighting(chunk, world); - } - - for (int x = -1; x <= 1; ++x) { - for (int z = -1; z <= 1; ++z) { - if (x != 0 || z != 0) { - Chunk nChunk = LightingEngineHelpers.getLoadedChunk(world.getChunkProvider(), chunk.xPosition + x, chunk.zPosition + z); - - if (nChunk == null || !((IChunkLightingData) nChunk).isLightInitialized()) { - return; - } - } - } - } - - chunk.isLightPopulated = true; - } - - public static void initSkylightForSection(final World world, final Chunk chunk, final ExtendedBlockStorage section) { - if (!world.provider.hasNoSky) { - for (int x = 0; x < 16; ++x) { - for (int z = 0; z < 16; ++z) { - if (chunk.getHeightValue(x, z) <= section.getYLocation()) { - for (int y = 0; y < 16; ++y) { - section.setExtSkylightValue(x, y, z, EnumSkyBlock.Sky.defaultLightValue); - } - } - } - } - } - } - - private static short[] getNeighborLightChecks(Chunk chunk) { - return ((IChunkLightingData) chunk).getNeighborLightChecks(); - } - - private static void setNeighborLightChecks(Chunk chunk, short[] table) { - ((IChunkLightingData) chunk).setNeighborLightChecks(table); - } - - public static int getCachedLightFor(Chunk chunk, EnumSkyBlock type, int x, int y, int z) { - return ((IChunkLighting) chunk).getCachedLightFor(type, x, y, z); - } - - public static ILightingEngine getLightingEngine(World world) { - return ((ILightingEngineProvider) world).getLightingEngine(); - } - - /** - * Get the intrinsic or saved block light value in a chunk. - * @param chunk the chunk - * @param x X coordinate (0-15) - * @param y Y coordinate (0-255) - * @param z Z coordinate (0-15) - * @return light level - */ - public static int getIntrinsicOrSavedBlockLightValue(Chunk chunk, int x, int y, int z) { - int savedLightValue = chunk.getSavedLightValue(EnumSkyBlock.Block, x, y, z); - int bx = x + (chunk.xPosition * 16); - int bz = z + (chunk.zPosition * 16); - Block block = chunk.getBlock(x, y, z); - int lightValue = LightingEngineHelpers.getLightValueForState(block, chunk.worldObj, bx, y, bz); - return Math.max(savedLightValue, lightValue); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java b/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java deleted file mode 100644 index 1ab1e3e82..000000000 --- a/src/main/java/org/embeddedt/archaicfix/proxy/ClientProxy.java +++ /dev/null @@ -1,177 +0,0 @@ -package org.embeddedt.archaicfix.proxy; - -import com.google.common.base.Objects; -import cpw.mods.fml.common.FMLCommonHandler; -import cpw.mods.fml.common.eventhandler.EventPriority; -import cpw.mods.fml.common.eventhandler.SubscribeEvent; -import cpw.mods.fml.common.gameevent.TickEvent; -import net.minecraft.block.Block; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.gui.Gui; -import net.minecraft.client.gui.GuiMainMenu; -import net.minecraft.client.gui.ScaledResolution; -import net.minecraft.client.network.NetHandlerPlayClient; -import net.minecraft.server.integrated.IntegratedServer; -import net.minecraft.util.Direction; -import net.minecraft.util.MathHelper; -import net.minecraft.util.MovingObjectPosition; -import net.minecraftforge.client.event.EntityViewRenderEvent; -import net.minecraftforge.client.event.GuiOpenEvent; -import net.minecraftforge.client.event.RenderGameOverlayEvent; -import net.minecraftforge.client.event.sound.SoundLoadEvent; -import net.minecraftforge.common.MinecraftForge; -import org.embeddedt.archaicfix.ArchaicLogger; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import org.embeddedt.archaicfix.helpers.BuiltInResourcePack; -import org.embeddedt.archaicfix.helpers.SoundDeviceThread; -import zone.rong.rongasm.api.StringPool; - -import java.lang.management.ManagementFactory; -import java.util.Locale; - -public class ClientProxy extends CommonProxy { - SoundDeviceThread soundThread = null; - public static volatile boolean soundSystemReloadLock = false; - @Override - public void preinit() { - super.preinit(); - Minecraft.memoryReserve = new byte[0]; - MinecraftForge.EVENT_BUS.register(new StringPool.EventHandler()); - MinecraftForge.EVENT_BUS.register(this); - FMLCommonHandler.instance().bus().register(this); - if(ArchaicConfig.modernizeTextures) { - BuiltInResourcePack.register("vanilla_overrides"); - } - } - - float lastIntegratedTickTime; - @SubscribeEvent - public void onTick(TickEvent.ServerTickEvent event) { - if(FMLCommonHandler.instance().getSide().isClient() && event.phase == TickEvent.Phase.END) { - IntegratedServer srv = Minecraft.getMinecraft().getIntegratedServer(); - if(srv != null) { - long currentTickTime = srv.tickTimeArray[srv.getTickCounter() % 100]; - lastIntegratedTickTime = lastIntegratedTickTime * 0.8F + (float)currentTickTime / 1000000.0F * 0.2F; - } else - lastIntegratedTickTime = 0; - } - } - - private float gameStartTime = -1; - - @SubscribeEvent(priority = EventPriority.LOWEST) - public void onGuiOpen(GuiOpenEvent event) { - if(!event.isCanceled() && event.gui instanceof GuiMainMenu && gameStartTime == -1) { - gameStartTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f; - ArchaicLogger.LOGGER.info("The game loaded in " + gameStartTime + " seconds."); - } - } - - @SubscribeEvent(priority = EventPriority.LOWEST) - public void onRenderOverlay(RenderGameOverlayEvent.Text event) { - Minecraft mc = Minecraft.getMinecraft(); - if(event.isCanceled() || !mc.gameSettings.showDebugInfo || event.left.size() < 1) - return; - NetHandlerPlayClient cl = mc.getNetHandler(); - if(cl != null) { - IntegratedServer srv = mc.getIntegratedServer(); - - if (srv != null) { - String s = String.format("Integrated server @ %.0f ms ticks", lastIntegratedTickTime); - event.left.add(1, s); - } - } - if(ArchaicConfig.showBlockDebugInfo && mc.objectMouseOver != null && mc.objectMouseOver.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) { - if(!event.right.isEmpty() && Objects.firstNonNull(event.right.get(event.right.size() - 1), "").length() > 0) - event.right.add(""); - Block block = mc.theWorld.getBlock(mc.objectMouseOver.blockX, mc.objectMouseOver.blockY, mc.objectMouseOver.blockZ); - int meta = mc.theWorld.getBlockMetadata(mc.objectMouseOver.blockX, mc.objectMouseOver.blockY, mc.objectMouseOver.blockZ); - event.right.add(Block.blockRegistry.getNameForObject(block)); - event.right.add("meta: " + meta); - } - if(ArchaicConfig.modernizeF3Screen) { - boolean hasReplacedXYZ = false; - for(int i = 0; i < event.left.size() - 3; i++) { - /* These checks should not be inefficient as most of the time the first one will already fail */ - if(!hasReplacedXYZ && Objects.firstNonNull(event.left.get(i), "").startsWith("x:") - && Objects.firstNonNull(event.left.get(i + 1), "").startsWith("y:") - && Objects.firstNonNull(event.left.get(i + 2), "").startsWith("z:") - && Objects.firstNonNull(event.left.get(i + 3), "").startsWith("f:")) { - hasReplacedXYZ = true; - int heading = MathHelper.floor_double((double)(mc.thePlayer.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3; - String heading_str; - switch(heading) { - case 0: - heading_str = "Towards positive Z"; - break; - case 1: - heading_str = "Towards negative X"; - break; - case 2: - heading_str = "Towards negative Z"; - break; - case 3: - heading_str = "Towards positive X"; - break; - default: - throw new RuntimeException(); - } - event.left.set(i, String.format("XYZ: %.3f / %.5f / %.3f", mc.thePlayer.posX, mc.thePlayer.boundingBox.minY, mc.thePlayer.posZ)); - int blockX = MathHelper.floor_double(mc.thePlayer.posX); - int blockY = MathHelper.floor_double(mc.thePlayer.boundingBox.minY); - int blockZ = MathHelper.floor_double(mc.thePlayer.posZ); - event.left.set(i + 1, String.format("Block: %d %d %d [%d %d %d]", blockX, blockY, blockZ, blockX & 15, blockY & 15, blockZ & 15)); - event.left.set(i + 2, String.format("Chunk: %d %d %d", blockX >> 4, blockY >> 4, blockZ >> 4)); - event.left.set(i + 3, String.format("Facing: %s (%s) (%.1f / %.1f)", Direction.directions[heading].toLowerCase(Locale.ROOT), heading_str, MathHelper.wrapAngleTo180_float(mc.thePlayer.rotationYaw), MathHelper.wrapAngleTo180_float(mc.thePlayer.rotationPitch))); - } - } - event.setCanceled(true); - /* render ourselves */ - FontRenderer fontrenderer = mc.fontRenderer; - int fontColor = 0xe0e0e0; - int rectColor = 0x90505050; - for (int x = 0; x < event.left.size(); x++) - { - String msg = event.left.get(x); - if (msg == null) continue; - int strX = 2; - int strY = 2 + x * fontrenderer.FONT_HEIGHT; - Gui.drawRect(1, strY - 1, strX + fontrenderer.getStringWidth(msg) + 1, strY + fontrenderer.FONT_HEIGHT - 1, rectColor); - fontrenderer.drawString(msg, strX, strY, fontColor); - } - int width = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight).getScaledWidth(); - for (int x = 0; x < event.right.size(); x++) - { - String msg = event.right.get(x); - if (msg == null) continue; - int w = fontrenderer.getStringWidth(msg); - int strX = width - w - 2; - int strY = 2 + x * fontrenderer.FONT_HEIGHT; - Gui.drawRect(strX - 1, strY - 1, strX + w + 1, strY + fontrenderer.FONT_HEIGHT - 1, rectColor); - fontrenderer.drawString(msg, strX, strY, fontColor); - } - } - } - - @SubscribeEvent - public void onSoundSetup(SoundLoadEvent event) { - soundSystemReloadLock = false; - if(soundThread == null) { - ArchaicLogger.LOGGER.info("Starting sound device thread"); - soundThread = new SoundDeviceThread(); - soundThread.start(); - } - } - - /* coerce NaN fog values back to 0 (https://bugs.mojang.com/browse/MC-10480) */ - @SubscribeEvent(priority = EventPriority.LOWEST) - public void onFogColor(EntityViewRenderEvent.FogColors event) { - if(Float.isNaN(event.red)) - event.red = 0f; - if(Float.isNaN(event.green)) - event.green = 0f; - if(Float.isNaN(event.blue)) - event.blue = 0f; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java b/src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java deleted file mode 100644 index 00dd86310..000000000 --- a/src/main/java/org/embeddedt/archaicfix/proxy/CommonProxy.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.embeddedt.archaicfix.proxy; - -import ca.fxco.memoryleakfix.MemoryLeakFix; -import org.embeddedt.archaicfix.config.ArchaicConfig; -import zone.rong.rongasm.api.RongHelpers; - -public class CommonProxy { - public void preinit() { - - } - - public void loadcomplete() { - if(ArchaicConfig.clearMixinCache) - MemoryLeakFix.forceLoadAllMixinsAndClearSpongePoweredCache(); - if(ArchaicConfig.clearLaunchLoaderCache) - RongHelpers.cleanupLaunchClassLoader(); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/recipe/LastMatchedInfo.java b/src/main/java/org/embeddedt/archaicfix/recipe/LastMatchedInfo.java deleted file mode 100644 index d52295747..000000000 --- a/src/main/java/org/embeddedt/archaicfix/recipe/LastMatchedInfo.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.embeddedt.archaicfix.recipe; - -import net.minecraft.inventory.InventoryCrafting; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; - -public class LastMatchedInfo { - public final IRecipe recipe; - int hash; - ItemStack[] invItems; - - public LastMatchedInfo(IRecipe recipe, InventoryCrafting inventory) { - invItems = new ItemStack[inventory.getSizeInventory()]; - for(int i = 0; i < invItems.length; i++) { - ItemStack stack = inventory.getStackInSlot(i); - invItems[i] = stack != null ? stack.copy() : null; - } - this.recipe = recipe; - hash = getHash(inventory); - } - - private boolean matchesSavedInventory(InventoryCrafting inventory) { - if(invItems == null) - return false; - if(invItems.length != inventory.getSizeInventory()) - return false; - for(int i = 0; i < invItems.length; i++) { - ItemStack newStack = inventory.getStackInSlot(i); - /* they definitely match */ - if(invItems[i] == null && newStack == null) - continue; - /* they don't match */ - if(invItems[i] == null || newStack == null) - return false; - /* now we know they are both non-null */ - if(!invItems[i].isItemEqual(newStack) || !ItemStack.areItemStackTagsEqual(invItems[i], newStack)) - return false; - } - return true; - } - - public boolean matches(InventoryCrafting crafting) { - if(getHash(crafting) != hash) - return false; - return matchesSavedInventory(crafting); - } - - public ItemStack getCraftingResult(InventoryCrafting inventory) { - if(recipe != null) - return recipe.getCraftingResult(inventory); - return null; - } - - private int getHash(InventoryCrafting inventory) { - int result = 1; - for(int i = 0; i < inventory.getSizeInventory(); i++) { - ItemStack stack = inventory.getStackInSlot(i); - int hashCode = 1; - if(stack != null) { - //hashCode = 31 * hashCode + stack.stackSize; - hashCode = 31 * hashCode + Item.getIdFromItem(stack.getItem()); - hashCode = 31 * hashCode + stack.getItemDamage(); - hashCode = 31 * hashCode + (!stack.hasTagCompound() ? 0 : stack.getTagCompound().hashCode()); - } - result = 17 * result + hashCode; - } - return result; - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java b/src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java deleted file mode 100644 index 41496df0a..000000000 --- a/src/main/java/org/embeddedt/archaicfix/recipe/RecipeCacheLoader.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.embeddedt.archaicfix.recipe; - -import com.google.common.cache.CacheLoader; -import net.minecraft.item.Item; -import net.minecraft.item.crafting.CraftingManager; -import net.minecraft.item.crafting.IRecipe; -import org.embeddedt.archaicfix.interfaces.IAcceleratedRecipe; - -import java.util.List; -import java.util.Set; - -/** - * Helper class that determines the set of all crafting recipes that utilize a given set of items. - */ -public class RecipeCacheLoader extends CacheLoader, IRecipe[]> { - private static final IRecipe[] NO_RECIPES = new IRecipe[0]; - @Override - public IRecipe[] load(Set key) throws Exception { - List recipes = CraftingManager.getInstance().getRecipeList(); - if (key.size() == 0) { - return NO_RECIPES; /* no recipes that utilize no items */ - } - return recipes.parallelStream() - .filter(recipe -> { - if (!(recipe instanceof IAcceleratedRecipe)) - return true; - Set potentialItems = ((IAcceleratedRecipe) recipe).getPotentialItems(); - if (potentialItems == null) { - /* The recipe can accept an unbounded set of items */ - return true; - } - for (Item item : key) { - /* If the recipe would never make use of an item we have, don't include it in the final list */ - if (!potentialItems.contains(item)) - return false; - } - return true; - }) - .toArray(IRecipe[]::new); - } -} diff --git a/src/main/java/org/embeddedt/archaicfix/recipe/RecipeWeigher.java b/src/main/java/org/embeddedt/archaicfix/recipe/RecipeWeigher.java deleted file mode 100644 index a57304f1a..000000000 --- a/src/main/java/org/embeddedt/archaicfix/recipe/RecipeWeigher.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.embeddedt.archaicfix.recipe; - -import com.google.common.cache.Weigher; -import net.minecraft.item.Item; -import net.minecraft.item.crafting.IRecipe; - -import java.util.Set; - -public class RecipeWeigher implements Weigher, IRecipe[]> { - @Override - public int weigh(Set key, IRecipe[] value) { - return value.length; - } -} diff --git a/src/main/java/zone/rong/rongasm/api/CaptureSet.java b/src/main/java/zone/rong/rongasm/api/CaptureSet.java deleted file mode 100644 index 429600892..000000000 --- a/src/main/java/zone/rong/rongasm/api/CaptureSet.java +++ /dev/null @@ -1,34 +0,0 @@ -package zone.rong.rongasm.api; - -import speiger.src.collections.objects.sets.ObjectOpenHashSet; - -import java.util.HashSet; -import java.util.Set; - -public class CaptureSet extends HashSet { - - private final Set backingCaptures; - - public CaptureSet() { - super(); - this.backingCaptures = new ObjectOpenHashSet<>(); - } - - public CaptureSet(Set populate) { - this(); - addAll(populate); - } - - public void addCapture(K capture) { - this.backingCaptures.add(capture); - } - - public boolean put(K k) { - return super.add(k); - } - - @Override - public boolean add(K k) { - return this.backingCaptures.contains(k) || super.add(k); - } -} diff --git a/src/main/java/zone/rong/rongasm/api/DummyMap.java b/src/main/java/zone/rong/rongasm/api/DummyMap.java deleted file mode 100644 index c7e9f35ac..000000000 --- a/src/main/java/zone/rong/rongasm/api/DummyMap.java +++ /dev/null @@ -1,50 +0,0 @@ -package zone.rong.rongasm.api; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Set; - -/** - * Used as a ImmutableMap-like structure, but with the methods not throwing UnsupportedOperationException - */ -public class DummyMap implements Map { - - private static final DummyMap INSTANCE = new DummyMap<>(); - private static final Set SET_INSTANCE = Collections.newSetFromMap(INSTANCE); - - @SuppressWarnings("unchecked") - public static Map of() { - return (DummyMap) INSTANCE; - } - - @SuppressWarnings("unchecked") - public static Set asSet() { - return (Set) SET_INSTANCE; - } - - public int size() { return 0; } - - public boolean isEmpty() { return true; } - - public boolean containsKey(Object key) { return false; } - - public boolean containsValue(Object value) { return false; } - - public V get(Object key) { return null; } - - public V put(K key, V value) { return value; } - - public V remove(Object key) { return null; } - - public void putAll(Map m) { } - - public void clear() { } - - public Set keySet() { return Collections.emptySet(); } - - public Collection values() { return Collections.emptySet(); } - - public Set entrySet() { return Collections.emptySet(); } - -} diff --git a/src/main/java/zone/rong/rongasm/api/ResourceCache.java b/src/main/java/zone/rong/rongasm/api/ResourceCache.java deleted file mode 100644 index f1907e33c..000000000 --- a/src/main/java/zone/rong/rongasm/api/ResourceCache.java +++ /dev/null @@ -1,15 +0,0 @@ -package zone.rong.rongasm.api; - -import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap; - -public class ResourceCache extends Object2ObjectOpenHashMap { - - public byte[] add(String s, byte[] bytes) { - return super.put(s, bytes); - } - - @Override - public byte[] put(String s, byte[] bytes) { - return bytes; - } -} diff --git a/src/main/java/zone/rong/rongasm/api/RongHelpers.java b/src/main/java/zone/rong/rongasm/api/RongHelpers.java deleted file mode 100644 index be7255863..000000000 --- a/src/main/java/zone/rong/rongasm/api/RongHelpers.java +++ /dev/null @@ -1,40 +0,0 @@ -package zone.rong.rongasm.api; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import net.minecraft.launchwrapper.Launch; -import net.minecraft.launchwrapper.LaunchClassLoader; -import org.embeddedt.archaicfix.ArchaicLogger; - -import java.util.Map; - -public class RongHelpers { - private static final boolean noClassCache = false; - private static final boolean weakClassCache = true; - private static final boolean noResourceCache = false; - private static final boolean weakResourceCache = true; - public static void cleanupLaunchClassLoader() { - try { - ArchaicLogger.LOGGER.info("Cleaning up LaunchClassLoader"); - if (noClassCache) { - RongReflector.resolveFieldSetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader, DummyMap.of()); - } else if (weakClassCache) { - Map> oldClassCache = (Map>) RongReflector.resolveFieldGetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader); - Cache> newClassCache = CacheBuilder.newBuilder().concurrencyLevel(2).weakValues().build(); - newClassCache.putAll(oldClassCache); - RongReflector.resolveFieldSetter(LaunchClassLoader.class, "cachedClasses").invoke(Launch.classLoader, newClassCache.asMap()); - } - if (noResourceCache) { - RongReflector.resolveFieldSetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader, new ResourceCache()); - RongReflector.resolveFieldSetter(LaunchClassLoader.class, "negativeResourceCache").invokeExact(Launch.classLoader, DummyMap.asSet()); - } else if (weakResourceCache) { - Map oldResourceCache = (Map) RongReflector.resolveFieldGetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader); - Cache newResourceCache = CacheBuilder.newBuilder().concurrencyLevel(2).weakValues().build(); - newResourceCache.putAll(oldResourceCache); - RongReflector.resolveFieldSetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader, newResourceCache.asMap()); - } - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } -} diff --git a/src/main/java/zone/rong/rongasm/api/RongReflector.java b/src/main/java/zone/rong/rongasm/api/RongReflector.java deleted file mode 100644 index 8c9aa0bec..000000000 --- a/src/main/java/zone/rong/rongasm/api/RongReflector.java +++ /dev/null @@ -1,226 +0,0 @@ -package zone.rong.rongasm.api; - -import com.google.common.base.Preconditions; -import cpw.mods.fml.relauncher.ReflectionHelper; -import net.minecraft.launchwrapper.Launch; -import net.minecraft.launchwrapper.LaunchClassLoader; -import org.objectweb.asm.Type; - -import java.io.InputStream; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -/** - * Helper class for Reflection nonsense. - */ -public class RongReflector { - - public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); - - private static final MethodHandle classLoader$DefineClass = resolveMethod(ClassLoader.class, "defineClass", String.class, byte[].class, int.class, int.class); - private static final CaptureSet transformerExclusions; - - static { - CaptureSet captureSet = new CaptureSet<>(); - try { - captureSet = new CaptureSet<>(((Set) resolveFieldGetter(LaunchClassLoader.class, "transformerExceptions").invokeExact(Launch.classLoader))); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - transformerExclusions = captureSet; - try { - resolveFieldSetter(LaunchClassLoader.class, "transformerExceptions").invoke(Launch.classLoader, transformerExclusions); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - public static Class defineMixinClass(String className, byte[] classBytes) { - try { - // defineClass(Launch.classLoader, className, classBytes); - Map resourceCache = (Map) resolveFieldGetter(LaunchClassLoader.class, "resourceCache").invoke(Launch.classLoader); - if (resourceCache instanceof ResourceCache) { - ((ResourceCache) resourceCache).add(className, classBytes); - } else { - resourceCache.put(className, classBytes); - } - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - return null; - } - - public static Class defineClass(CL classLoader, Class clazz) { - String name = Type.getInternalName(clazz); - InputStream byteStream = clazz.getResourceAsStream('/' + name + ".class"); - try { - byte[] classBytes = new byte[byteStream.available()]; - final int bytesRead = byteStream.read(classBytes); - Preconditions.checkState(bytesRead == classBytes.length); - return (Class) classLoader$DefineClass.invokeExact(classLoader, name.replace('/', '.'), classBytes, 0, classBytes.length); - } catch (Throwable e) { - e.printStackTrace(); - } - return clazz; - } - - public static Class defineClass(CL classLoader, String name, byte[] classBytes) { - try { - return (Class) classLoader$DefineClass.invokeExact(classLoader, name, classBytes, 0, classBytes.length); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - return null; - } - - public static MethodHandle resolveCtor(Class clazz, Class... args) { - try { - Constructor ctor = clazz.getDeclaredConstructor(args); - ctor.setAccessible(true); - return LOOKUP.unreflectConstructor(ctor); - } catch (IllegalAccessException | NoSuchMethodException e) { - e.printStackTrace(); - return null; - } - } - - public static Constructor getCtor(Class clazz, Class... args) { - try { - Constructor ctor = clazz.getDeclaredConstructor(args); - ctor.setAccessible(true); - return ctor; - } catch (NoSuchMethodException e) { - e.printStackTrace(); - return null; - } - } - - public static MethodHandle resolveMethod(Class clazz, String methodName, Class... args) { - try { - Method method = clazz.getDeclaredMethod(methodName, args); - method.setAccessible(true); - return LOOKUP.unreflect(method); - } catch (IllegalAccessException | NoSuchMethodException e) { - e.printStackTrace(); - return null; - } - } - - public static Method getMethod(Class clazz, String methodName, Class... args) { - try { - Method method = clazz.getDeclaredMethod(methodName, args); - method.setAccessible(true); - return method; - } catch (NoSuchMethodException e) { - e.printStackTrace(); - return null; - } - } - - @SuppressWarnings("unchecked") - public static MethodHandle resolveMethod(Class clazz, String methodName, String obfMethodName, Class... args) { - try { - return LOOKUP.unreflect(ReflectionHelper.findMethod((Class)clazz, null, new String[] { methodName, obfMethodName }, args)); - } catch (IllegalAccessException e) { - e.printStackTrace(); - return null; - } - } - - @SuppressWarnings("unchecked") - public static Method getMethod(Class clazz, String methodName, String obfMethodName, Class... args) { - return ReflectionHelper.findMethod((Class)clazz, null, new String[] { methodName, obfMethodName }, args); - } - - public static MethodHandle resolveFieldGetter(Class clazz, String fieldName) { - try { - Field field = clazz.getDeclaredField(fieldName); - field.setAccessible(true); - return LOOKUP.unreflectGetter(field); - } catch (Throwable e) { - e.printStackTrace(); - return null; - } - } - - public static MethodHandle resolveFieldSetter(Class clazz, String fieldName) { - try { - Field field = clazz.getDeclaredField(fieldName); - field.setAccessible(true); - return LOOKUP.unreflectSetter(field); - } catch (Throwable e) { - e.printStackTrace(); - return null; - } - } - - public static MethodHandle resolveFieldGetter(Class clazz, String fieldName, String obfFieldName) { - try { - return LOOKUP.unreflectGetter(ReflectionHelper.findField(clazz, fieldName, obfFieldName)); - } catch (IllegalAccessException e) { - e.printStackTrace(); - return null; - } - } - - public static MethodHandle resolveFieldSetter(Class clazz, String fieldName, String obfFieldName) { - try { - return LOOKUP.unreflectSetter(ReflectionHelper.findField(clazz, fieldName, obfFieldName)); - } catch (IllegalAccessException e) { - e.printStackTrace(); - return null; - } - } - - public static Field getField(Class clazz, String fieldName) { - try { - Field field = clazz.getDeclaredField(fieldName); - field.setAccessible(true); - return field; - } catch (Throwable e) { - e.printStackTrace(); - return null; - } - } - - public static Field getField(Class clazz, String fieldName, String obfFieldName) { - return ReflectionHelper.findField(clazz, fieldName, obfFieldName); - } - - public static boolean doesClassExist(String className) { - try { - Class.forName(className); - return true; - } catch (ClassNotFoundException ignored) { } - return false; - } - - public static boolean doesTweakExist(String tweakName) { - return ((List) Launch.blackboard.get("TweakClasses")).contains(tweakName); - } - - public static Optional> getClass(String className) { - try { - return Optional.of(Class.forName(className)); - } catch (ClassNotFoundException ignored) { } - return Optional.empty(); - } - - public static void removeTransformerExclusion(String transformerExclusion) { - if (!transformerExclusions.remove(transformerExclusion)) { - transformerExclusions.addCapture(transformerExclusion); - } - } - - public static void addTransformerExclusion(String transformerExclusion) { - transformerExclusions.put(transformerExclusion); - } - -} diff --git a/src/main/java/zone/rong/rongasm/api/StringPool.java b/src/main/java/zone/rong/rongasm/api/StringPool.java deleted file mode 100644 index 6f827eca6..000000000 --- a/src/main/java/zone/rong/rongasm/api/StringPool.java +++ /dev/null @@ -1,142 +0,0 @@ -package zone.rong.rongasm.api; - -import org.embeddedt.archaicfix.ArchaicLogger; -import speiger.src.collections.ints.maps.impl.misc.Int2ObjectArrayMap; -import speiger.src.collections.objects.sets.ObjectOpenHashSet; - -import java.util.Locale; - -public class StringPool { - - public static final int FILE_PERMISSIONS_ID = 1; - - private static final Int2ObjectArrayMap POOLS = new Int2ObjectArrayMap<>(); - - static { - establishPool(-1, 12288, "", " "); - POOLS.setDefaultReturnValue(POOLS.get(-1)); - } - - public static void establishPool(int poolId, int expectedSize, String... startingValues) { - if (POOLS.containsKey(poolId)) { - return; - } - POOLS.put(poolId, new Internal(poolId, expectedSize, startingValues)); - } - - public static Internal purgePool(int poolId) { - return POOLS.remove(poolId); - } - - public static int getSize() { - return POOLS.getDefaultReturnValue().internalPool.size(); - } - - public static int getSize(int pool) { - return POOLS.get(pool).internalPool.size(); - } - - public static long getDeduplicatedCount() { - return POOLS.getDefaultReturnValue().deduplicatedCount; - } - - public static long getDeduplicatedCount(int pool) { - return POOLS.get(pool).deduplicatedCount; - } - - public static String canonicalize(String string) { - synchronized (POOLS) { - return POOLS.getDefaultReturnValue().addOrGet(string); - } - } - - public static String unsafe$Canonicalize(String string) { - return POOLS.getDefaultReturnValue().addOrGet(string); - } - - @SuppressWarnings("unused") - public static String lowerCaseAndCanonicalize(String string) { - synchronized (POOLS) { - return POOLS.getDefaultReturnValue().addOrGet(string.toLowerCase(Locale.ROOT)); - } - } - - @SuppressWarnings("unused") - public static String unsafe$LowerCaseAndCanonicalize(String string) { - return POOLS.getDefaultReturnValue().addOrGet(string.toLowerCase(Locale.ROOT)); - } - - public static String canonicalize(String string, int poolId, boolean checkMainPool) { - if (checkMainPool) { - synchronized (POOLS) { - ObjectOpenHashSet internalPool = POOLS.get(poolId).internalPool; - String canonicalized = internalPool.contains(string) ? internalPool.addOrGet(string) : null; - if (canonicalized != null) { - return canonicalized; - } - } - } - synchronized (POOLS) { - return POOLS.get(poolId).addOrGet(string); - } - } - - public static String unsafe$Canonicalize(String string, int poolId, boolean checkMainPool) { - if (checkMainPool) { - ObjectOpenHashSet internalPool = POOLS.get(poolId).internalPool; - String canonicalized = internalPool.contains(string) ? internalPool.addOrGet(string) : null; - if (canonicalized != null) { - return canonicalized; - } - } - return POOLS.get(poolId).addOrGet(string); - } - - public static class EventHandler { - /* - @SubscribeEvent - public void onDebugList(RenderGameOverlayEvent.Text event) { - Minecraft minecraft = Minecraft.getMinecraft(); - if (minecraft.gameSettings.showDebugInfo) { - ArrayList list = event.left; - if (!list.get(list.size() - 1).equals("")) { - list.add(""); - } - int size = getSize(); - long deduplicatedCount = getDeduplicatedCount(); - list.add(String.format("%s%s%s: %s strings processed. %s unique, %s deduplicated.", EnumChatFormatting.AQUA, "", EnumChatFormatting.RESET, deduplicatedCount, size, deduplicatedCount - size)); - } - } - */ - } - - - - static class Internal { - - final int id; - final ObjectOpenHashSet internalPool; - - long deduplicatedCount; - - @SuppressWarnings("all") - Internal(int id, int expectedSize, String... startingValues) { - this.id = id; - this.internalPool = new ObjectOpenHashSet<>(expectedSize); - for (String startingValue : startingValues) { - this.internalPool.add(startingValue); - } - } - - String addOrGet(String string) { - deduplicatedCount++; - return internalPool.addOrGet(string); - } - - @Override - protected void finalize() { - ArchaicLogger.LOGGER.warn("Clearing LoliStringPool {}", id); - } - } - -} From 146d80570ba1cbf869bd978f3536263b0f2d8ebc Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 25 Nov 2023 21:32:39 -0500 Subject: [PATCH 141/301] Rewrite Tessellator hacks - now using a ThreadLocal instead of only patching RenderBlocks --- .../angelica/glsm/TessellatorManager.java | 26 ++++++++++ .../loading/MixinCompatHackTweaker.java | 2 + .../gtnewhorizons/angelica/mixins/Mixins.java | 1 - .../early/sodium/MixinRenderBlocks.java | 35 -------------- .../mixins/early/sodium/MixinTessellator.java | 5 +- .../mixins/interfaces/IHasTessellator.java | 8 ---- .../transform/GLStateManagerTransformer.java | 2 +- .../transform/TessellatorTransformer.java | 47 +++++++++++++++++++ .../chunk/tasks/ChunkRenderRebuildTask.java | 4 +- 9 files changed, 81 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/TessellatorManager.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasTessellator.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/TessellatorManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/TessellatorManager.java new file mode 100644 index 000000000..e99513170 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/TessellatorManager.java @@ -0,0 +1,26 @@ +package com.gtnewhorizons.angelica.glsm; + +import net.minecraft.client.renderer.Tessellator; + +public class TessellatorManager { + private static final ThreadLocal theTessellator = ThreadLocal.withInitial(Tessellator::new); + private static final Thread mainThread = Thread.currentThread(); + + public static Tessellator get() { + if(isOnMainThread()) + return Tessellator.instance; + return theTessellator.get(); + } + + public static boolean isOnMainThread() { + return Thread.currentThread() == mainThread; + } + + public static boolean isMainInstance(Object instance) { + return instance == Tessellator.instance; + } + + static { + System.out.println("[TessellatorManager] Initialized on thread " + mainThread.getName()); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java index 387cb71ac..9d59aa1b4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java @@ -2,6 +2,7 @@ import com.gtnewhorizons.angelica.transform.AClassTransformer; import com.gtnewhorizons.angelica.transform.GLStateManagerTransformer; +import com.gtnewhorizons.angelica.transform.TessellatorTransformer; import cpw.mods.fml.common.asm.transformers.TerminalTransformer; import net.minecraft.launchwrapper.IClassTransformer; import net.minecraft.launchwrapper.ITweaker; @@ -61,6 +62,7 @@ public String getLaunchTarget() { public String[] getLaunchArguments() { // Run after Mixins, but hopefully before LWJGl3ify Launch.classLoader.registerTransformer(GLStateManagerTransformer.class.getName()); + Launch.classLoader.registerTransformer(TessellatorTransformer.class.getName()); return new String[0]; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 632f07592..c7a3f4fa3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -66,7 +66,6 @@ public enum Mixins { ,"sodium.MixinMinecraft" ,"sodium.MixinNetHandlerPlayClient" ,"sodium.MixinNibbleArray" - ,"sodium.MixinRenderBlocks" ,"sodium.MixinRenderGlobal" ,"sodium.MixinTessellator" ,"sodium.MixinWorldClient" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java deleted file mode 100644 index f0f48b452..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.sodium; - -import com.gtnewhorizons.angelica.mixins.interfaces.IHasTessellator; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.client.renderer.RenderBlocks; -import net.minecraft.client.renderer.Tessellator; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(RenderBlocks.class) -public class MixinRenderBlocks implements IHasTessellator { - // Sodium Tesselator will be non null if we are not on the main thread - private Tessellator sodium$tessellator = null; - - @Override - public Tessellator getTessellator() { - return sodium$tessellator; - } - - @Inject(method = {"()V","(Lnet/minecraft/world/IBlockAccess;)V"}, at = @At("TAIL")) - private void initTessellator(CallbackInfo ci) { - if(Thread.currentThread() != SodiumClientMod.getMainThread()) { - sodium$tessellator = new Tessellator(); - } - } - - @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;instance:Lnet/minecraft/client/renderer/Tessellator;")) - private Tessellator modifyTessellatorAccess() { - return sodium$tessellator != null ? sodium$tessellator : Tessellator.instance; - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java index a5cf6f58e..b4507c8d7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinTessellator.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; +import com.gtnewhorizons.angelica.glsm.TessellatorManager; import com.gtnewhorizons.angelica.mixins.interfaces.ITessellatorInstance; import net.minecraft.client.renderer.Tessellator; import org.spongepowered.asm.mixin.Mixin; @@ -30,7 +31,7 @@ public abstract class MixinTessellator implements ITessellatorInstance { **/ @Redirect(method = "reset", at = @At(value = "INVOKE", target = "Ljava/nio/ByteBuffer;clear()Ljava/nio/Buffer;")) private Buffer removeStaticBufferResetOutsideSingleton(ByteBuffer buffer) { - if(((Object)this) == Tessellator.instance) { + if(TessellatorManager.isMainInstance(this)) { return buffer.clear(); } return buffer; @@ -38,7 +39,7 @@ private Buffer removeStaticBufferResetOutsideSingleton(ByteBuffer buffer) { @Inject(method="draw", at=@At("HEAD")) private void preventOffMainThreadDrawing(CallbackInfoReturnable cir) { - if(((Object)this) != Tessellator.instance) { + if(!TessellatorManager.isMainInstance(this)) { throw new RuntimeException("Tried to draw on a tessellator that isn't on the main thread!"); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasTessellator.java deleted file mode 100644 index 03c764e40..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasTessellator.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.interfaces; - -import net.minecraft.client.renderer.Tessellator; - -public interface IHasTessellator { - Tessellator getTessellator(); - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index 99dc96c7a..66345c339 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -42,7 +42,7 @@ public class GLStateManagerTransformer implements IClassTransformer { ); - private static final List TransformerExclusions = new ArrayList<>(Arrays.asList( + public static final List TransformerExclusions = new ArrayList<>(Arrays.asList( "org.lwjgl", "com.gtnewhorizons.angelica.glsm.", "com.gtnewhorizons.angelica.transform", "me.eigenraven.lwjgl3ify", "cpw.mods.fml.client.SplashProgress") ); diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java new file mode 100644 index 000000000..2bb357d3f --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java @@ -0,0 +1,47 @@ +package com.gtnewhorizons.angelica.transform; + +import net.minecraft.launchwrapper.IClassTransformer; +import org.spongepowered.asm.lib.*; +import org.spongepowered.asm.lib.tree.*; + +/** + * Redirects all Tessellator.instance accesses to go through our TessellatorManager. + */ +public class TessellatorTransformer implements IClassTransformer { + @Override + public byte[] transform(final String className, String transformedName, byte[] basicClass) { + if (basicClass == null) return null; + + // Ignore classes that are excluded from transformation + for (String exclusion : GLStateManagerTransformer.TransformerExclusions) { + if (className.startsWith(exclusion)) { + return basicClass; + } + } + + final ClassReader reader = new ClassReader(basicClass); + ClassNode node = new ClassNode(); + reader.accept(node, Opcodes.ASM9); + boolean changed = false; + for(MethodNode m : node.methods) { + for(AbstractInsnNode insn : m.instructions) { + if(insn.getOpcode() == Opcodes.GETSTATIC) { + FieldInsnNode fNode = (FieldInsnNode)insn; + if(fNode.name.equals("instance") && fNode.owner.equals("net/minecraft/client/renderer/Tessellator")) { + MethodInsnNode getNode = new MethodInsnNode(Opcodes.INVOKESTATIC, "com/gtnewhorizons/angelica/glsm/TessellatorManager", "get", "()Lnet/minecraft/client/renderer/Tessellator;", false); + m.instructions.set(fNode, getNode); + changed = true; + break; + } + } + } + } + + if(!changed) + return basicClass; + + ClassWriter writer = new ClassWriter(reader, 0); + node.accept(writer); + return writer.toByteArray(); + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 76ca394a7..697e5be3f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -2,7 +2,7 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionDataBuilder; -import com.gtnewhorizons.angelica.mixins.interfaces.IHasTessellator; +import com.gtnewhorizons.angelica.glsm.TessellatorManager; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer; @@ -100,7 +100,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB BlockPos.Mutable pos = new BlockPos.Mutable(); BlockPos renderOffset = this.offset; - final Tessellator tessellator = ((IHasTessellator)renderBlocks).getTessellator(); + final Tessellator tessellator = TessellatorManager.get(); for (int relY = 0; relY < 16; relY++) { if (cancellationSource.isCancelled()) { From f4e4236a83cb44463e750d89a5733836c6c6282d Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 25 Nov 2023 19:01:52 -0800 Subject: [PATCH 142/301] Reenable AF mixins, switch to cached debug var, disable incompatible mixins --- .../gtnewhorizons/angelica/AngelicaMod.java | 1 + .../gtnewhorizons/angelica/mixins/Mixins.java | 38 ++++++++++--------- .../java/net/coderbot/iris/gl/GLDebug.java | 3 +- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index d1fe162b0..af0c26c71 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -17,6 +17,7 @@ public class AngelicaMod { @SidedProxy(clientSide = "com.gtnewhorizons.angelica.proxy.ClientProxy", serverSide = "com.gtnewhorizons.angelica.proxy.CommonProxy") public static CommonProxy proxy; public static boolean isNEIDLoaded; + public static final boolean lwjglDebug = Boolean.parseBoolean(System.getProperty("org.lwjgl.util.Debug", "false")); @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index c7a3f4fa3..dda61c677 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.mixins; +import com.gtnewhorizons.angelica.AngelicaMod; import com.gtnewhorizons.angelica.config.AngelicaConfig; import cpw.mods.fml.relauncher.FMLLaunchHandler; import me.jellysquid.mods.sodium.common.config.SodiumConfig; @@ -16,23 +17,24 @@ public enum Mixins { "angelica.MixinEntityRenderer" ) ), -// -// ARCHAIC_SPLASH(new Builder("ArchaicFix Splash").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) -// .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.showSplashMemoryBar && false).addMixinClasses( -// "angelica.archaic.MixinSplashProgress" -// ,"angelica.archaic.AccessorSplashProgress" -// ) -// ), -// -// ARCHAIC_CORE(new Builder("Archaic Core").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) -// .setPhase(Phase.EARLY).addMixinClasses( -// "angelica.archaic.MixinBlockFence" -// ,"angelica.archaic.MixinFMLClientHandler" -// ,"angelica.archaic.MixinGuiIngameForge" -// ,"angelica.archaic.MixinNetHandlerPlayClient" -// ,"angelica.archaic.MixinThreadDownloadImageData" -// ) -// ), + + // Not compatible with the lwjgl debug callbacks, so disable if that's enabled + ARCHAIC_SPLASH(new Builder("ArchaicFix Splash").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.showSplashMemoryBar && !AngelicaMod.lwjglDebug).addMixinClasses( + "angelica.archaic.MixinSplashProgress" + ,"angelica.archaic.AccessorSplashProgress" + ) + ), + + ARCHAIC_CORE(new Builder("Archaic Core").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).addMixinClasses( + "angelica.archaic.MixinBlockFence" + ,"angelica.archaic.MixinFMLClientHandler" + ,"angelica.archaic.MixinGuiIngameForge" + ,"angelica.archaic.MixinNetHandlerPlayClient" + ,"angelica.archaic.MixinThreadDownloadImageData" + ) + ), IRIS_STARTUP(new Builder("Start Iris").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris).addMixinClasses( @@ -42,7 +44,7 @@ public enum Mixins { ) ), ANGELICA_ENABLE_DEBUG(new Builder("Angelica Debug").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).setApplyIf(() -> Boolean.parseBoolean(System.getProperty("org.lwjgl.util.Debug", "false"))).addMixinClasses( + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaMod.lwjglDebug).addMixinClasses( "angelica.debug.MixinSplashProgress" ) ), diff --git a/src/main/java/net/coderbot/iris/gl/GLDebug.java b/src/main/java/net/coderbot/iris/gl/GLDebug.java index b4770d473..a1c869aaa 100644 --- a/src/main/java/net/coderbot/iris/gl/GLDebug.java +++ b/src/main/java/net/coderbot/iris/gl/GLDebug.java @@ -5,6 +5,7 @@ package net.coderbot.iris.gl; +import com.gtnewhorizons.angelica.AngelicaMod; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.coderbot.iris.Iris; @@ -318,7 +319,7 @@ public void popGroup() { public static void initRenderer() { // Only enable if debug is enabled, and also forcibly disable the splash screen - if(!Boolean.parseBoolean(System.getProperty("org.lwjgl.util.Debug", "false"))) + if(!AngelicaMod.lwjglDebug) return; if (Iris.capabilities.GL_KHR_debug || Iris.capabilities.OpenGL43) { From 213493ff3b8f9024375479b219dabf85572ebf3a Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 25 Nov 2023 19:07:05 -0800 Subject: [PATCH 143/301] Remove AF deps and a late mixin that was missed --- dependencies.gradle | 12 +++-------- .../botania/MixinBlockSpecialFlower.java | 18 ---------------- .../common/mrtjp/MixinBlockUpdateHandler.java | 21 ------------------- 3 files changed, 3 insertions(+), 48 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/botania/MixinBlockSpecialFlower.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/mrtjp/MixinBlockUpdateHandler.java diff --git a/dependencies.gradle b/dependencies.gradle index 0d60f6512..ca477da23 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -40,6 +40,9 @@ dependencies { api("com.github.GTNewHorizons:Hodgepodge:2.3.35") + compileOnly("org.projectlombok:lombok:1.18.22") {transitive = false } + annotationProcessor("org.projectlombok:lombok:1.18.22") + // Iris Shaders shadowImplementation('org.jetbrains:annotations:24.0.1') // Apache 2.0 shadowImplementation("it.unimi.dsi:fastutil:8.2.1") // Apache 2.0 @@ -65,15 +68,6 @@ dependencies { devOnlyNonPublishable(rfg.deobf('curse.maven:witchery-69673:2234410')) - // ArchaicFix Deps - shadowImplementation("com.github.Speiger:Primitive-Collections:0.9.0") // Apache 2.0 - compileOnly("codechicken:ChickenChunks:1.7.10-1.3.4.19:dev") - compileOnly "thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev" - compileOnly('curse.maven:cofh-core-69162:2388751') - compileOnly('com.github.GTNewHorizons:Botania:1.10.2-GTNH:dev') {transitive = false } - compileOnly("org.projectlombok:lombok:1.18.22") {transitive = false } - annotationProcessor("org.projectlombok:lombok:1.18.22") - compileOnly(rfg.deobf("curse.maven:extrautils-225561:2264383")) compileOnly(rfg.deobf("curse.maven:dynamiclights-227874:2337326")) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/botania/MixinBlockSpecialFlower.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/botania/MixinBlockSpecialFlower.java deleted file mode 100644 index 6348a54e5..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/botania/MixinBlockSpecialFlower.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.late.archaic.common.botania; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; -import vazkii.botania.common.block.BlockSpecialFlower; -import vazkii.botania.common.block.tile.TileSpecialFlower; - -@Mixin(BlockSpecialFlower.class) -public class MixinBlockSpecialFlower { - @Redirect(method = "getLightValue", at = @At(value = "INVOKE", target = "Lvazkii/botania/common/block/tile/TileSpecialFlower;getLightValue()I", remap = false), remap = false) - private int archaic$avoidNullCrash(TileSpecialFlower instance) { - if(instance == null) - return -1; - else - return instance.getLightValue(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/mrtjp/MixinBlockUpdateHandler.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/mrtjp/MixinBlockUpdateHandler.java deleted file mode 100644 index 9e66a5c19..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/archaic/common/mrtjp/MixinBlockUpdateHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.late.archaic.common.mrtjp; - -import mrtjp.core.world.BlockUpdateHandler$; -import net.minecraft.world.ChunkCoordIntPair; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.HashSet; - -@Mixin(BlockUpdateHandler$.class) -public class MixinBlockUpdateHandler { - @Redirect(method = "getActiveChunkSet", at = @At(value = "INVOKE", target = "Ljava/util/HashSet;add(Ljava/lang/Object;)Z"), remap = false) - private boolean addChunkIfLoaded(HashSet chunkSet, Object o, World world) { - ChunkCoordIntPair pair = (ChunkCoordIntPair)o; - if(world.getChunkProvider().chunkExists(pair.chunkXPos, pair.chunkZPos)) - return chunkSet.add(pair); - return false; - } -} From e6b00352513be68003137b92f88b5d377be97dbc Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 25 Nov 2023 22:16:48 -0800 Subject: [PATCH 144/301] Remove compile stubs and compat mixins (Can reintroduce them when Iris is wired up, if needed) --- addon.gradle | 12 -------- dependencies.gradle | 7 ----- src/compileStubsStubs/README.MD | 1 - .../angelica/client/MultiTexID.java | 4 --- .../client/resources/IResourceManager.java | 5 ---- .../net/minecraft/util/ResourceLocation.java | 5 ---- .../compat/MixinModelRotationRenderer.java | 20 ------------- .../mixins/late/compat/MixinRenderHalo.java | 28 ------------------- 8 files changed, 82 deletions(-) delete mode 100644 src/compileStubsStubs/README.MD delete mode 100644 src/compileStubsStubs/java/com/gtnewhorizons/angelica/client/MultiTexID.java delete mode 100644 src/compileStubsStubs/java/net/minecraft/client/resources/IResourceManager.java delete mode 100644 src/compileStubsStubs/java/net/minecraft/util/ResourceLocation.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinModelRotationRenderer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinRenderHalo.java diff --git a/addon.gradle b/addon.gradle index 39de83d6e..58cadb25b 100644 --- a/addon.gradle +++ b/addon.gradle @@ -1,15 +1,3 @@ - -configurations { - compileStubs -} - -sourceSets { - compileStubsStubs - compileStubs { - compileClasspath += configurations.compileStubs - } -} - allprojects { gradle.projectsEvaluated { tasks.withType(JavaCompile) { diff --git a/dependencies.gradle b/dependencies.gradle index ca477da23..8b58e3e4b 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -35,9 +35,6 @@ */ dependencies { - compileOnly(sourceSets.compileStubs.output) - compileStubs(sourceSets.compileStubsStubs.output) - api("com.github.GTNewHorizons:Hodgepodge:2.3.35") compileOnly("org.projectlombok:lombok:1.18.22") {transitive = false } @@ -54,10 +51,6 @@ dependencies { } compileOnly "org.apache.ant:ant:1.8.2" - - compileOnly("com.github.GTNewHorizons:ProjectRed:4.7.12-GTNH:dev") - compileOnly(files("dependencies/SmartRender-1.7.10-2.1-dev.jar")) - // Because who doesn't want NEI compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.4.9-GTNH:dev') diff --git a/src/compileStubsStubs/README.MD b/src/compileStubsStubs/README.MD deleted file mode 100644 index 41a7b63cf..000000000 --- a/src/compileStubsStubs/README.MD +++ /dev/null @@ -1 +0,0 @@ -Stubs for the compile stubs diff --git a/src/compileStubsStubs/java/com/gtnewhorizons/angelica/client/MultiTexID.java b/src/compileStubsStubs/java/com/gtnewhorizons/angelica/client/MultiTexID.java deleted file mode 100644 index c64dbcb5e..000000000 --- a/src/compileStubsStubs/java/com/gtnewhorizons/angelica/client/MultiTexID.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -public class MultiTexID { -} diff --git a/src/compileStubsStubs/java/net/minecraft/client/resources/IResourceManager.java b/src/compileStubsStubs/java/net/minecraft/client/resources/IResourceManager.java deleted file mode 100644 index 49577ca30..000000000 --- a/src/compileStubsStubs/java/net/minecraft/client/resources/IResourceManager.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.minecraft.client.resources; - -public interface IResourceManager { - -} diff --git a/src/compileStubsStubs/java/net/minecraft/util/ResourceLocation.java b/src/compileStubsStubs/java/net/minecraft/util/ResourceLocation.java deleted file mode 100644 index bb0f42125..000000000 --- a/src/compileStubsStubs/java/net/minecraft/util/ResourceLocation.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.minecraft.util; - -public class ResourceLocation { - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinModelRotationRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinModelRotationRenderer.java deleted file mode 100644 index ed2fe7aa0..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinModelRotationRenderer.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.late.compat; - -import net.minecraft.client.model.ModelRenderer; -import net.smart.render.ModelRotationRenderer; - -import org.spongepowered.asm.mixin.Mixin; - -import com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer.MixinModelRenderer; - -@Mixin(ModelRotationRenderer.class) -public class MixinModelRotationRenderer extends MixinModelRenderer { - - @Override - public void angelica$resetDisplayList() { - super.angelica$resetDisplayList(); - ((ModelRenderer) (Object) this).compiled = false; - ((ModelRenderer) (Object) this).displayList = 0; - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinRenderHalo.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinRenderHalo.java deleted file mode 100644 index 2836b6aa2..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinRenderHalo.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.late.compat; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.gtnewhorizons.angelica.client.Shaders; - -import mrtjp.projectred.core.RenderHalo; - -@Mixin(value = RenderHalo.class) -public class MixinRenderHalo { - - @Inject( - at = @At(remap = false, target = "Lcodechicken/lib/render/CCRenderState;reset()V", value = "INVOKE"), - method = "prepareRenderState()V", - remap = false) - private void angelica$beginProjectRedHalo(CallbackInfo ci) { - Shaders.beginProjectRedHalo(); - } - - @Inject(at = @At("TAIL"), method = "restoreRenderState()V", remap = false) - private void angelica$endProjectRedHalo(CallbackInfo ci) { - Shaders.endProjectRedHalo(); - } - -} From 9c64c9db6513828d3dd21b47ff56b6e8763201a2 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 25 Nov 2023 22:47:34 -0800 Subject: [PATCH 145/301] Add Iris Sodium Compat impl --- .../sodium/IrisChunkShaderBindingPoints.java | 16 ++ .../block_context/BlockContextHolder.java | 47 ++++ .../block_context/ChunkBuildBuffersExt.java | 11 + .../ContextAwareVertexWriter.java | 5 + .../sodium/options/IrisSodiumOptions.java | 79 +++++++ .../sodium/options/OptionImplExtended.java | 7 + .../sodium/options/SupportedGraphicsMode.java | 23 ++ .../ChunkRenderBackendExt.java | 8 + .../shader_overrides/IrisChunkProgram.java | 98 ++++++++ .../IrisChunkProgramOverrides.java | 219 ++++++++++++++++++ .../shader_overrides/IrisShaderTypes.java | 10 + .../shader_overrides/IrisTerrainPass.java | 17 ++ .../SwappableChunkRenderManager.java | 5 + .../IrisChunkMeshAttributes.java | 14 ++ .../IrisGlVertexAttributeFormat.java | 11 + .../vertex_format/IrisModelVertexFormats.java | 7 + .../EntityVertexBufferWriterNio.java | 96 ++++++++ .../EntityVertexBufferWriterUnsafe.java | 93 ++++++++ .../entity_xhfp/ExtendedGlyphVertexType.java | 33 +++ .../entity_xhfp/ExtendedQuadVertexType.java | 33 +++ .../GlyphVertexBufferWriterNio.java | 95 ++++++++ .../GlyphVertexBufferWriterUnsafe.java | 92 ++++++++ .../entity_xhfp/QuadViewEntity.java | 65 ++++++ .../terrain_xhfp/QuadViewTerrain.java | 73 ++++++ .../XHFPModelVertexBufferWriterNio.java | 149 ++++++++++++ .../XHFPModelVertexBufferWriterUnsafe.java | 147 ++++++++++++ .../terrain_xhfp/XHFPModelVertexType.java | 63 +++++ 27 files changed, 1516 insertions(+) create mode 100644 src/main/java/net/coderbot/iris/sodium/IrisChunkShaderBindingPoints.java create mode 100644 src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java create mode 100644 src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java create mode 100644 src/main/java/net/coderbot/iris/sodium/block_context/ContextAwareVertexWriter.java create mode 100644 src/main/java/net/coderbot/iris/sodium/options/IrisSodiumOptions.java create mode 100644 src/main/java/net/coderbot/iris/sodium/options/OptionImplExtended.java create mode 100644 src/main/java/net/coderbot/iris/sodium/options/SupportedGraphicsMode.java create mode 100644 src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java create mode 100644 src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java create mode 100644 src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgramOverrides.java create mode 100644 src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisShaderTypes.java create mode 100644 src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisTerrainPass.java create mode 100644 src/main/java/net/coderbot/iris/sodium/shadow_map/SwappableChunkRenderManager.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/IrisChunkMeshAttributes.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/IrisGlVertexAttributeFormat.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/IrisModelVertexFormats.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/QuadViewEntity.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/QuadViewTerrain.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterNio.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterUnsafe.java create mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java diff --git a/src/main/java/net/coderbot/iris/sodium/IrisChunkShaderBindingPoints.java b/src/main/java/net/coderbot/iris/sodium/IrisChunkShaderBindingPoints.java new file mode 100644 index 000000000..ad470fbfe --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/IrisChunkShaderBindingPoints.java @@ -0,0 +1,16 @@ +package net.coderbot.iris.sodium; + +import me.jellysquid.mods.sodium.client.gl.shader.ShaderBindingPoint; + +/** + * Defines Iris-specific chunk shader binding points. + * + * NB: Make sure this doesn't collide with anything in {@link me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints} + */ +public class IrisChunkShaderBindingPoints { + public static final ShaderBindingPoint NORMAL = new ShaderBindingPoint(5); + public static final ShaderBindingPoint TANGENT = new ShaderBindingPoint(6); + public static final ShaderBindingPoint MID_TEX_COORD = new ShaderBindingPoint(7); + public static final ShaderBindingPoint BLOCK_ID = new ShaderBindingPoint(8); + public static final ShaderBindingPoint MID_BLOCK = new ShaderBindingPoint(9); +} diff --git a/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java b/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java new file mode 100644 index 000000000..0342f1d13 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java @@ -0,0 +1,47 @@ +package net.coderbot.iris.sodium.block_context; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMaps; +import net.minecraft.world.level.block.state.BlockState; + +public class BlockContextHolder { + private final Object2IntMap blockStateIds; + + public int localPosX; + public int localPosY; + public int localPosZ; + + public short blockId; + public short renderType; + + public BlockContextHolder() { + this.blockStateIds = Object2IntMaps.emptyMap(); + this.blockId = -1; + this.renderType = -1; + } + + public BlockContextHolder(Object2IntMap idMap) { + this.blockStateIds = idMap; + this.blockId = -1; + this.renderType = -1; + } + + public void setLocalPos(int localPosX, int localPosY, int localPosZ) { + this.localPosX = localPosX; + this.localPosY = localPosY; + this.localPosZ = localPosZ; + } + + public void set(BlockState state, short renderType) { + this.blockId = (short) this.blockStateIds.getOrDefault(state, -1); + this.renderType = renderType; + } + + public void reset() { + this.blockId = -1; + this.renderType = -1; + this.localPosX = 0; + this.localPosY = 0; + this.localPosZ = 0; + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java b/src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java new file mode 100644 index 000000000..551a978f0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java @@ -0,0 +1,11 @@ +package net.coderbot.iris.sodium.block_context; + +import net.minecraft.world.level.block.state.BlockState; + +public interface ChunkBuildBuffersExt { + void iris$setLocalPos(int localPosX, int localPosY, int localPosZ); + + void iris$setMaterialId(BlockState state, short renderType); + + void iris$resetBlockContext(); +} diff --git a/src/main/java/net/coderbot/iris/sodium/block_context/ContextAwareVertexWriter.java b/src/main/java/net/coderbot/iris/sodium/block_context/ContextAwareVertexWriter.java new file mode 100644 index 000000000..b0ba32679 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/block_context/ContextAwareVertexWriter.java @@ -0,0 +1,5 @@ +package net.coderbot.iris.sodium.block_context; + +public interface ContextAwareVertexWriter { + void iris$setContextHolder(BlockContextHolder holder); +} diff --git a/src/main/java/net/coderbot/iris/sodium/options/IrisSodiumOptions.java b/src/main/java/net/coderbot/iris/sodium/options/IrisSodiumOptions.java new file mode 100644 index 000000000..518390101 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/options/IrisSodiumOptions.java @@ -0,0 +1,79 @@ +package net.coderbot.iris.sodium.options; + +import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; +import me.jellysquid.mods.sodium.client.gui.options.OptionImpact; +import me.jellysquid.mods.sodium.client.gui.options.OptionImpl; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; +import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl; +import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl; +import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; +import net.coderbot.iris.Iris; +import net.coderbot.iris.colorspace.ColorSpace; +import net.coderbot.iris.gui.option.IrisVideoSettings; +import net.minecraft.client.Options; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; + +import java.io.IOException; + +public class IrisSodiumOptions { + public static OptionImpl createMaxShadowDistanceSlider(MinecraftOptionsStorage vanillaOpts) { + OptionImpl maxShadowDistanceSlider = OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(new TranslatableComponent("options.iris.shadowDistance")) + .setTooltip(new TranslatableComponent("options.iris.shadowDistance.sodium_tooltip")) + .setControl(option -> new SliderControl(option, 0, 32, 1, ControlValueFormatter.quantity("options.chunks"))) + .setBinding((options, value) -> { + IrisVideoSettings.shadowDistance = value; + try { + Iris.getIrisConfig().save(); + } catch (IOException e) { + e.printStackTrace(); + } + }, + options -> IrisVideoSettings.getOverriddenShadowDistance(IrisVideoSettings.shadowDistance)) + .setImpact(OptionImpact.HIGH) + .setEnabled(true) + .build(); + + ((OptionImplExtended) maxShadowDistanceSlider).iris$dynamicallyEnable(IrisVideoSettings::isShadowDistanceSliderEnabled); + + return maxShadowDistanceSlider; + } + + public static OptionImpl createColorSpaceButton(MinecraftOptionsStorage vanillaOpts) { + OptionImpl colorSpace = OptionImpl.createBuilder(ColorSpace.class, vanillaOpts) + .setName(new TranslatableComponent("options.iris.colorSpace")) + .setTooltip(new TranslatableComponent("options.iris.colorSpace.sodium_tooltip")) + .setControl(option -> new CyclingControl<>(option, ColorSpace.class, + new Component[] { new TextComponent("SRGB"), new TextComponent("DCI_P3"), new TextComponent("Display P3"), new TextComponent("REC2020"), new TextComponent("Adobe RGB") })) + .setBinding((options, value) -> { + IrisVideoSettings.colorSpace = value; + try { + Iris.getIrisConfig().save(); + } catch (IOException e) { + e.printStackTrace(); + } + }, + options -> IrisVideoSettings.colorSpace) + .setImpact(OptionImpact.LOW) + .setEnabled(true) + .build(); + + + return colorSpace; + } + + public static OptionImpl createLimitedVideoSettingsButton(MinecraftOptionsStorage vanillaOpts) { + return OptionImpl.createBuilder(SupportedGraphicsMode.class, vanillaOpts) + .setName(new TranslatableComponent("options.graphics")) + .setTooltip(new TranslatableComponent("sodium.options.graphics_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, SupportedGraphicsMode.class, new Component[] { new TranslatableComponent("options.graphics.fast"), new TranslatableComponent("options.graphics.fancy") })) + .setBinding( + (opts, value) -> opts.graphicsMode = value.toVanilla(), + opts -> SupportedGraphicsMode.fromVanilla(opts.graphicsMode)) + .setImpact(OptionImpact.HIGH) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build(); + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/options/OptionImplExtended.java b/src/main/java/net/coderbot/iris/sodium/options/OptionImplExtended.java new file mode 100644 index 000000000..a9a1135fa --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/options/OptionImplExtended.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.sodium.options; + +import java.util.function.BooleanSupplier; + +public interface OptionImplExtended { + void iris$dynamicallyEnable(BooleanSupplier enabled); +} diff --git a/src/main/java/net/coderbot/iris/sodium/options/SupportedGraphicsMode.java b/src/main/java/net/coderbot/iris/sodium/options/SupportedGraphicsMode.java new file mode 100644 index 000000000..5e59e5274 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/options/SupportedGraphicsMode.java @@ -0,0 +1,23 @@ +package net.coderbot.iris.sodium.options; + +import net.minecraft.client.GraphicsStatus; + +public enum SupportedGraphicsMode { + FAST, FANCY; + + public static SupportedGraphicsMode fromVanilla(GraphicsStatus vanilla) { + if (vanilla == GraphicsStatus.FAST) { + return FAST; + } else { + return FANCY; + } + } + + public GraphicsStatus toVanilla() { + if (this == FAST) { + return GraphicsStatus.FAST; + } else { + return GraphicsStatus.FANCY; + } + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java b/src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java new file mode 100644 index 000000000..d5ef2a605 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java @@ -0,0 +1,8 @@ +package net.coderbot.iris.sodium.shader_overrides; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; + +public interface ChunkRenderBackendExt { + void iris$begin(PoseStack poseStack, BlockRenderPass pass); +} diff --git a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java new file mode 100644 index 000000000..45341fe2a --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java @@ -0,0 +1,98 @@ +package net.coderbot.iris.sodium.shader_overrides; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Matrix4f; +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkProgram; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderFogComponent; +import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.program.ProgramImages; +import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.program.ProgramUniforms; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.system.MemoryStack; + +import java.nio.FloatBuffer; + +public class IrisChunkProgram extends ChunkProgram { + // Uniform variable binding indexes + private final int uModelViewMatrix; + private final int uNormalMatrix; + + @Nullable + private final ProgramUniforms irisProgramUniforms; + + @Nullable + private final ProgramSamplers irisProgramSamplers; + + @Nullable + private final ProgramImages irisProgramImages; + + public IrisChunkProgram(RenderDevice owner, ResourceLocation name, int handle, + @Nullable ProgramUniforms irisProgramUniforms, @Nullable ProgramSamplers irisProgramSamplers, + @Nullable ProgramImages irisProgramImages) { + super(owner, name, handle, ChunkShaderFogComponent.None::new); + this.uModelViewMatrix = this.getUniformLocation("iris_ModelViewMatrix"); + this.uNormalMatrix = this.getUniformLocation("iris_NormalMatrix"); + this.irisProgramUniforms = irisProgramUniforms; + this.irisProgramSamplers = irisProgramSamplers; + this.irisProgramImages = irisProgramImages; + } + + public void setup(PoseStack poseStack, float modelScale, float textureScale) { + super.setup(poseStack, modelScale, textureScale); + + if (irisProgramUniforms != null) { + irisProgramUniforms.update(); + } + + if (irisProgramSamplers != null) { + irisProgramSamplers.update(); + } + + if (irisProgramImages != null) { + irisProgramImages.update(); + } + + Matrix4f modelViewMatrix = poseStack.last().pose(); + Matrix4f normalMatrix = poseStack.last().pose().copy(); + normalMatrix.invert(); + normalMatrix.transpose(); + + uniformMatrix(uModelViewMatrix, modelViewMatrix); + uniformMatrix(uNormalMatrix, normalMatrix); + } + + @Override + public int getUniformLocation(String name) { + // NB: We pass through calls involving u_ModelViewProjectionMatrix, u_ModelScale, and u_TextureScale, since + // currently patched Iris shader programs use those. + + if ("iris_BlockTex".equals(name) || "iris_LightTex".equals(name)) { + // Not relevant for Iris shader programs + return -1; + } + + try { + return super.getUniformLocation(name); + } catch (NullPointerException e) { + // Suppress getUniformLocation + return -1; + } + } + + private void uniformMatrix(int location, Matrix4f matrix) { + if (location == -1) { + return; + } + + try (MemoryStack memoryStack = MemoryStack.stackPush()) { + FloatBuffer buffer = memoryStack.mallocFloat(16); + + matrix.store(buffer); + + IrisRenderSystem.uniformMatrix4fv(location, false, buffer); + } + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgramOverrides.java b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgramOverrides.java new file mode 100644 index 000000000..e4862bc8f --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgramOverrides.java @@ -0,0 +1,219 @@ +package net.coderbot.iris.sodium.shader_overrides; + +import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; +import me.jellysquid.mods.sodium.client.gl.shader.GlShader; +import me.jellysquid.mods.sodium.client.gl.shader.ShaderConstants; +import me.jellysquid.mods.sodium.client.gl.shader.ShaderType; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkProgram; +import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; +import net.coderbot.iris.Iris; +import net.coderbot.iris.compat.sodium.impl.IrisChunkShaderBindingPoints; +import net.coderbot.iris.gl.program.ProgramImages; +import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.program.ProgramUniforms; +import net.coderbot.iris.pipeline.SodiumTerrainPipeline; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.coderbot.iris.shadows.ShadowRenderingState; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.EnumMap; +import java.util.Locale; +import java.util.Optional; + +public class IrisChunkProgramOverrides { + private static final ShaderConstants EMPTY_CONSTANTS = ShaderConstants.builder().build(); + + private final EnumMap programs = new EnumMap<>(IrisTerrainPass.class); + + private int versionCounterForSodiumShaderReload = -1; + + private GlShader createVertexShader(RenderDevice device, IrisTerrainPass pass, SodiumTerrainPipeline pipeline) { + Optional irisVertexShader; + + if (pass == IrisTerrainPass.SHADOW) { + irisVertexShader = pipeline.getShadowVertexShaderSource(); + } else if (pass == IrisTerrainPass.GBUFFER_SOLID) { + irisVertexShader = pipeline.getTerrainVertexShaderSource(); + } else if (pass == IrisTerrainPass.GBUFFER_TRANSLUCENT) { + irisVertexShader = pipeline.getTranslucentVertexShaderSource(); + } else { + throw new IllegalArgumentException("Unknown pass type " + pass); + } + + String source = irisVertexShader.orElse(null); + + if (source == null) { + return null; + } + + return new GlShader(device, ShaderType.VERTEX, new ResourceLocation("iris", + "sodium-terrain-" + pass.toString().toLowerCase(Locale.ROOT) + ".vsh"), source, EMPTY_CONSTANTS); + } + + private GlShader createGeometryShader(RenderDevice device, IrisTerrainPass pass, SodiumTerrainPipeline pipeline) { + Optional irisGeometryShader; + + if (pass == IrisTerrainPass.SHADOW) { + irisGeometryShader = pipeline.getShadowGeometryShaderSource(); + } else if (pass == IrisTerrainPass.GBUFFER_SOLID) { + irisGeometryShader = pipeline.getTerrainGeometryShaderSource(); + } else if (pass == IrisTerrainPass.GBUFFER_TRANSLUCENT) { + irisGeometryShader = pipeline.getTranslucentGeometryShaderSource(); + } else { + throw new IllegalArgumentException("Unknown pass type " + pass); + } + + String source = irisGeometryShader.orElse(null); + + if (source == null) { + return null; + } + + return new GlShader(device, IrisShaderTypes.GEOMETRY, new ResourceLocation("iris", + "sodium-terrain-" + pass.toString().toLowerCase(Locale.ROOT) + ".gsh"), source, EMPTY_CONSTANTS); + } + + private GlShader createFragmentShader(RenderDevice device, IrisTerrainPass pass, SodiumTerrainPipeline pipeline) { + Optional irisFragmentShader; + + if (pass == IrisTerrainPass.SHADOW) { + irisFragmentShader = pipeline.getShadowFragmentShaderSource(); + } else if (pass == IrisTerrainPass.GBUFFER_SOLID) { + irisFragmentShader = pipeline.getTerrainFragmentShaderSource(); + } else if (pass == IrisTerrainPass.GBUFFER_TRANSLUCENT) { + irisFragmentShader = pipeline.getTranslucentFragmentShaderSource(); + } else { + throw new IllegalArgumentException("Unknown pass type " + pass); + } + + String source = irisFragmentShader.orElse(null); + + if (source == null) { + return null; + } + + return new GlShader(device, ShaderType.FRAGMENT, new ResourceLocation("iris", + "sodium-terrain-" + pass.toString().toLowerCase(Locale.ROOT) + ".fsh"), source, EMPTY_CONSTANTS); + } + + @Nullable + private ChunkProgram createShader(RenderDevice device, IrisTerrainPass pass, SodiumTerrainPipeline pipeline) { + GlShader vertShader = createVertexShader(device, pass, pipeline); + GlShader geomShader = createGeometryShader(device, pass, pipeline); + GlShader fragShader = createFragmentShader(device, pass, pipeline); + + if (vertShader == null || fragShader == null) { + if (vertShader != null) { + vertShader.delete(); + } + + if (geomShader != null) { + geomShader.delete(); + } + + if (fragShader != null) { + fragShader.delete(); + } + + // TODO: Partial shader programs? + return null; + } + + try { + GlProgram.Builder builder = GlProgram.builder(new ResourceLocation("sodium", "chunk_shader_for_" + + pass.getName())); + + if (geomShader != null) { + builder.attachShader(geomShader); + } + + return builder.attachShader(vertShader) + .attachShader(fragShader) + .bindAttribute("iris_Pos", ChunkShaderBindingPoints.POSITION) + .bindAttribute("iris_Color", ChunkShaderBindingPoints.COLOR) + .bindAttribute("iris_TexCoord", ChunkShaderBindingPoints.TEX_COORD) + .bindAttribute("iris_LightCoord", ChunkShaderBindingPoints.LIGHT_COORD) + .bindAttribute("iris_Normal", IrisChunkShaderBindingPoints.NORMAL) + .bindAttribute("at_tangent", IrisChunkShaderBindingPoints.TANGENT) + .bindAttribute("mc_midTexCoord", IrisChunkShaderBindingPoints.MID_TEX_COORD) + .bindAttribute("mc_Entity", IrisChunkShaderBindingPoints.BLOCK_ID) + .bindAttribute("at_midBlock", IrisChunkShaderBindingPoints.MID_BLOCK) + .bindAttribute("iris_ModelOffset", ChunkShaderBindingPoints.MODEL_OFFSET) + .build((program, name) -> { + ProgramUniforms uniforms = pipeline.initUniforms(name); + ProgramSamplers samplers; + ProgramImages images; + + if (pass == IrisTerrainPass.SHADOW) { + samplers = pipeline.initShadowSamplers(name); + images = pipeline.initShadowImages(name); + } else { + samplers = pipeline.initTerrainSamplers(name); + images = pipeline.initTerrainImages(name); + } + + return new IrisChunkProgram(device, program, name, uniforms, samplers, images); + }); + } finally { + vertShader.delete(); + if (geomShader != null) { + geomShader.delete(); + } + fragShader.delete(); + } + } + + public void createShaders(SodiumTerrainPipeline sodiumTerrainPipeline, RenderDevice device) { + if (sodiumTerrainPipeline != null) { + for (IrisTerrainPass pass : IrisTerrainPass.values()) { + if (pass == IrisTerrainPass.SHADOW && !sodiumTerrainPipeline.hasShadowPass()) { + this.programs.put(pass, null); + continue; + } + + this.programs.put(pass, createShader(device, pass, sodiumTerrainPipeline)); + } + } else { + this.programs.clear(); + } + } + + @Nullable + public ChunkProgram getProgramOverride(RenderDevice device, BlockRenderPass pass) { + WorldRenderingPipeline worldRenderingPipeline = Iris.getPipelineManager().getPipelineNullable(); + SodiumTerrainPipeline sodiumTerrainPipeline = null; + + if (worldRenderingPipeline != null) { + sodiumTerrainPipeline = worldRenderingPipeline.getSodiumTerrainPipeline(); + } + + if (versionCounterForSodiumShaderReload != Iris.getPipelineManager().getVersionCounterForSodiumShaderReload()) { + versionCounterForSodiumShaderReload = Iris.getPipelineManager().getVersionCounterForSodiumShaderReload(); + deleteShaders(); + createShaders(sodiumTerrainPipeline, device); + } + + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + if (sodiumTerrainPipeline != null && !sodiumTerrainPipeline.hasShadowPass()) { + throw new IllegalStateException("Shadow program requested, but the pack does not have a shadow pass?"); + } + + return this.programs.get(IrisTerrainPass.SHADOW); + } else { + return this.programs.get(pass.isTranslucent() ? IrisTerrainPass.GBUFFER_TRANSLUCENT : IrisTerrainPass.GBUFFER_SOLID); + } + } + + public void deleteShaders() { + for (ChunkProgram program : this.programs.values()) { + if (program != null) { + program.delete(); + } + } + + this.programs.clear(); + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisShaderTypes.java b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisShaderTypes.java new file mode 100644 index 000000000..f1a7ba002 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisShaderTypes.java @@ -0,0 +1,10 @@ +package net.coderbot.iris.sodium.shader_overrides; + +import me.jellysquid.mods.sodium.client.gl.shader.ShaderType; + +/** + * Initialized by {@link net.coderbot.iris.compat.sodium.mixin.shader_overrides.MixinShaderType} + */ +public class IrisShaderTypes { + public static ShaderType GEOMETRY; +} diff --git a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisTerrainPass.java b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisTerrainPass.java new file mode 100644 index 000000000..1c0d6a2a8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisTerrainPass.java @@ -0,0 +1,17 @@ +package net.coderbot.iris.sodium.shader_overrides; + +public enum IrisTerrainPass { + SHADOW("shadow"), + GBUFFER_SOLID("gbuffers_terrain"), + GBUFFER_TRANSLUCENT("gbuffers_water"); + + private final String name; + + IrisTerrainPass(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/shadow_map/SwappableChunkRenderManager.java b/src/main/java/net/coderbot/iris/sodium/shadow_map/SwappableChunkRenderManager.java new file mode 100644 index 000000000..1692cf79c --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/shadow_map/SwappableChunkRenderManager.java @@ -0,0 +1,5 @@ +package net.coderbot.iris.sodium.shadow_map; + +public interface SwappableChunkRenderManager { + void iris$swapVisibilityState(); +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisChunkMeshAttributes.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisChunkMeshAttributes.java new file mode 100644 index 000000000..1b987124f --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisChunkMeshAttributes.java @@ -0,0 +1,14 @@ +package net.coderbot.iris.sodium.vertex_format; + +import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; + +/** + * Initialized by {@link net.coderbot.iris.compat.sodium.mixin.vertex_format.MixinChunkMeshAttribute} + */ +public class IrisChunkMeshAttributes { + public static ChunkMeshAttribute NORMAL; + public static ChunkMeshAttribute TANGENT; + public static ChunkMeshAttribute MID_TEX_COORD; + public static ChunkMeshAttribute BLOCK_ID; + public static ChunkMeshAttribute MID_BLOCK; +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisGlVertexAttributeFormat.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisGlVertexAttributeFormat.java new file mode 100644 index 000000000..b48031b54 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisGlVertexAttributeFormat.java @@ -0,0 +1,11 @@ +package net.coderbot.iris.sodium.vertex_format; + +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; +import net.coderbot.iris.compat.sodium.mixin.vertex_format.GlVertexAttributeFormatAccessor; +import org.lwjgl.opengl.GL20C; + +public class IrisGlVertexAttributeFormat { + public static final GlVertexAttributeFormat BYTE = + GlVertexAttributeFormatAccessor.createGlVertexAttributeFormat(GL20C.GL_BYTE, 1); + public static final GlVertexAttributeFormat SHORT = GlVertexAttributeFormatAccessor.createGlVertexAttributeFormat(GL20C.GL_SHORT, 2); +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisModelVertexFormats.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisModelVertexFormats.java new file mode 100644 index 000000000..953600930 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisModelVertexFormats.java @@ -0,0 +1,7 @@ +package net.coderbot.iris.sodium.vertex_format; + +import net.coderbot.iris.compat.sodium.impl.vertex_format.terrain_xhfp.XHFPModelVertexType; + +public class IrisModelVertexFormats { + public static final XHFPModelVertexType MODEL_VERTEX_XHFP = new XHFPModelVertexType(); +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java new file mode 100644 index 000000000..7bfdc7039 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java @@ -0,0 +1,96 @@ +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.vendored.joml.Vector3f; +import net.coderbot.iris.vertices.IrisVertexFormats; +import net.coderbot.iris.vertices.NormalHelper; +import net.minecraft.client.renderer.texture.OverlayTexture; + +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, OverlayTexture.NO_OVERLAY, 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; + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..c345d4397 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java @@ -0,0 +1,93 @@ +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.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.vendored.joml.Vector3f; +import net.coderbot.iris.vertices.IrisVertexFormats; +import net.coderbot.iris.vertices.NormalHelper; +import net.minecraft.client.renderer.texture.OverlayTexture; +import org.lwjgl.system.MemoryUtil; + +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; + + MemoryUtil.memPutFloat(i, x); + MemoryUtil.memPutFloat(i + 4, y); + MemoryUtil.memPutFloat(i + 8, z); + MemoryUtil.memPutInt(i + 12, color); + MemoryUtil.memPutFloat(i + 16, u); + MemoryUtil.memPutFloat(i + 20, v); + MemoryUtil.memPutInt(i + 24, overlay); + MemoryUtil.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, OverlayTexture.NO_OVERLAY, 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++) { + MemoryUtil.memPutFloat(i + 36 - STRIDE * vertex, uSum); + MemoryUtil.memPutFloat(i + 40 - STRIDE * vertex, vSum); + MemoryUtil.memPutInt(i + 32 - STRIDE * vertex, normal); + MemoryUtil.memPutInt(i + 44 - STRIDE * vertex, tangent); + } + + uSum = 0; + vSum = 0; + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java new file mode 100644 index 000000000..5a0530255 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java @@ -0,0 +1,33 @@ +package net.coderbot.iris.sodium.vertex_format.entity_xhfp; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.VertexFormat; +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, BlittableVertexType { + 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 asBlittable() { + return this; + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java new file mode 100644 index 000000000..e433d4f2b --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java @@ -0,0 +1,33 @@ +package net.coderbot.iris.sodium.vertex_format.entity_xhfp; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.VertexFormat; +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, BlittableVertexType { + 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 asBlittable() { + return this; + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java new file mode 100644 index 000000000..5ede018ce --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java @@ -0,0 +1,95 @@ +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.vendored.joml.Vector3f; +import net.coderbot.iris.vertices.IrisVertexFormats; +import net.coderbot.iris.vertices.NormalHelper; +import net.minecraft.client.renderer.texture.OverlayTexture; + +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, OverlayTexture.NO_OVERLAY, 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; + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..10eb28037 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java @@ -0,0 +1,92 @@ +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.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.vendored.joml.Vector3f; +import net.coderbot.iris.vertices.IrisVertexFormats; +import net.coderbot.iris.vertices.NormalHelper; +import net.minecraft.client.renderer.texture.OverlayTexture; +import org.lwjgl.system.MemoryUtil; + +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; + + MemoryUtil.memPutFloat(i, x); + MemoryUtil.memPutFloat(i + 4, y); + MemoryUtil.memPutFloat(i + 8, z); + MemoryUtil.memPutInt(i + 12, color); + MemoryUtil.memPutFloat(i + 16, u); + MemoryUtil.memPutFloat(i + 20, v); + MemoryUtil.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, OverlayTexture.NO_OVERLAY, 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++) { + MemoryUtil.memPutFloat(i + 36 - STRIDE * vertex, uSum); + MemoryUtil.memPutFloat(i + 40 - STRIDE * vertex, vSum); + MemoryUtil.memPutInt(i + 28 - STRIDE * vertex, normal); + MemoryUtil.memPutInt(i + 44 - STRIDE * vertex, tangent); + } + + uSum = 0; + vSum = 0; + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/QuadViewEntity.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/QuadViewEntity.java new file mode 100644 index 000000000..3bece5210 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/QuadViewEntity.java @@ -0,0 +1,65 @@ +package net.coderbot.iris.sodium.vertex_format.entity_xhfp; + +import net.coderbot.iris.vertices.QuadView; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; + +public abstract class QuadViewEntity implements QuadView { + long writePointer; + int stride; + + @Override + public float x(int index) { + return getFloat(writePointer - stride * (3L - index)); + } + + @Override + public float y(int index) { + return getFloat(writePointer + 4 - stride * (3L - index)); + } + + @Override + public float z(int index) { + return getFloat(writePointer + 8 - stride * (3L - index)); + } + + @Override + public float u(int index) { + return getFloat(writePointer + 16 - stride * (3L - index)); + } + + @Override + public float v(int index) { + return getFloat(writePointer + 20 - stride * (3L - index)); + } + + abstract float getFloat(long writePointer); + + public static class QuadViewEntityUnsafe extends QuadViewEntity { + public void setup(long writePointer, int stride) { + this.writePointer = writePointer; + this.stride = stride; + } + + @Override + float getFloat(long writePointer) { + return MemoryUtil.memGetFloat(writePointer); + } + } + + public static class QuadViewEntityNio extends QuadViewEntity { + private ByteBuffer buffer; + + public void setup(ByteBuffer buffer, int writePointer, int stride) { + this.buffer = buffer; + this.writePointer = writePointer; + this.stride = stride; + } + + @Override + float getFloat(long writePointer) { + return buffer.getFloat((int) writePointer); + } + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/QuadViewTerrain.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/QuadViewTerrain.java new file mode 100644 index 000000000..23040d713 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/QuadViewTerrain.java @@ -0,0 +1,73 @@ +package net.coderbot.iris.sodium.vertex_format.terrain_xhfp; + +import net.coderbot.iris.vertices.QuadView; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; + +public abstract class QuadViewTerrain implements QuadView { + long writePointer; + int stride; + + @Override + public float x(int index) { + return normalizeVertexPositionShortAsFloat(getShort(writePointer - stride * (3L - index))); + } + + @Override + public float y(int index) { + return normalizeVertexPositionShortAsFloat(getShort(writePointer + 2 - stride * (3L - index))); + } + + @Override + public float z(int index) { + return normalizeVertexPositionShortAsFloat(getShort(writePointer + 4 - stride * (3L - index))); + } + + @Override + public float u(int index) { + return normalizeVertexTextureShortAsFloat(getShort(writePointer + 12 - stride * (3L - index))); + } + + @Override + public float v(int index) { + return normalizeVertexTextureShortAsFloat(getShort(writePointer + 14 - stride * (3L - index))); + } + + private static float normalizeVertexTextureShortAsFloat(short value) { + return (value & 0xFFFF) * (1.0f / 32768.0f); + } + + private static float normalizeVertexPositionShortAsFloat(short value) { + return (value & 0xFFFF) * (1.0f / 65535.0f); + } + + abstract short getShort(long writePointer); + + public static class QuadViewTerrainUnsafe extends QuadViewTerrain { + public void setup(long writePointer, int stride) { + this.writePointer = writePointer; + this.stride = stride; + } + + @Override + short getShort(long writePointer) { + return MemoryUtil.memGetShort(writePointer); + } + } + + public static class QuadViewTerrainNio extends QuadViewTerrain { + private ByteBuffer buffer; + + public void setup(ByteBuffer buffer, int writePointer, int stride) { + this.buffer = buffer; + this.writePointer = writePointer; + this.stride = stride; + } + + @Override + short getShort(long writePointer) { + return buffer.getShort((int) writePointer); + } + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterNio.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterNio.java new file mode 100644 index 000000000..babae0e67 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterNio.java @@ -0,0 +1,149 @@ +package net.coderbot.iris.sodium.vertex_format.terrain_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.render.chunk.format.ModelVertexSink; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexUtil; +import net.coderbot.iris.compat.sodium.impl.block_context.BlockContextHolder; +import net.coderbot.iris.compat.sodium.impl.block_context.ContextAwareVertexWriter; +import net.coderbot.iris.compat.sodium.impl.vertex_format.IrisModelVertexFormats; +import net.coderbot.iris.vendored.joml.Vector3f; +import net.coderbot.iris.vertices.ExtendedDataHelper; +import net.coderbot.iris.vertices.NormalHelper; + +import java.nio.ByteBuffer; + +import static net.coderbot.iris.compat.sodium.impl.vertex_format.terrain_xhfp.XHFPModelVertexType.STRIDE; + +public class XHFPModelVertexBufferWriterNio extends VertexBufferWriterNio implements ModelVertexSink, ContextAwareVertexWriter { + private final QuadViewTerrain.QuadViewTerrainNio quad = new QuadViewTerrain.QuadViewTerrainNio(); + private final Vector3f normal = new Vector3f(); + + private BlockContextHolder contextHolder; + + private int vertexCount; + private float uSum; + private float vSum; + + public XHFPModelVertexBufferWriterNio(VertexBufferView backingBuffer) { + super(backingBuffer, IrisModelVertexFormats.MODEL_VERTEX_XHFP); + } + + @Override + public void writeQuad(float x, float y, float z, int color, float u, float v, int light) { + uSum += u; + vSum += v; + + this.writeQuadInternal( + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(x), + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(y), + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(z), + color, + ModelVertexUtil.denormalizeVertexTextureFloatAsShort(u), + ModelVertexUtil.denormalizeVertexTextureFloatAsShort(v), + light, + contextHolder.blockId, + contextHolder.renderType, + ExtendedDataHelper.computeMidBlock(x, y, z, contextHolder.localPosX, contextHolder.localPosY, contextHolder.localPosZ) + ); + } + + private void writeQuadInternal(short x, short y, short z, int color, short u, short v, int light, short materialId, + short renderType, int packedMidBlock) { + int i = this.writeOffset; + + vertexCount++; + // NB: uSum and vSum must already be incremented outside of this function. + + ByteBuffer buffer = this.byteBuffer; + buffer.putShort(i, x); + buffer.putShort(i + 2, y); + buffer.putShort(i + 4, z); + buffer.putInt(i + 8, color); + buffer.putShort(i + 12, u); + buffer.putShort(i + 14, v); + buffer.putShort(i + 16, (short) (light & 0xFFFF)); + buffer.putShort(i + 18, (short) (light >> 16 & 0xFFFF)); + // NB: We don't set midTexCoord, normal, and tangent here, they will be filled in later. + // block ID: We only set the first 2 values, any legacy shaders using z or w will get filled in based on the GLSL spec + // https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_format + // TODO: can we pack this into one short? + buffer.putShort(i + 36, materialId); + buffer.putShort(i + 38, renderType); + buffer.putInt(i + 40, packedMidBlock); + + if (vertexCount == 4) { + vertexCount = 0; + + // FIXME + // The following logic is incorrect because OpenGL denormalizes shorts by dividing by 65535. The atlas is + // based on power-of-two values and so a normalization factor that is not a power of two causes the values + // used in the shader to be off by enough to cause visual errors. These are most noticeable on 1.18 with POM + // on block edges. + // + // The only reliable way that this can be fixed is to apply the same shader transformations to midTexCoord + // as Sodium does to the regular texture coordinates - dividing them by the correct power-of-two value inside + // of the shader instead of letting OpenGL value normalization do the division. However, this requires + // fragile patching that is not yet possible. + // + // As a temporary solution, the normalized shorts have been replaced with regular floats, but this takes up + // an extra 4 bytes per vertex. + + // NB: Be careful with the math here! A previous bug was caused by midU going negative as a short, which + // was sign-extended into midTexCoord, causing midV to have garbage (likely NaN data). If you're touching + // this code, be aware of that, and don't introduce those kinds of bugs! + // + // Also note that OpenGL takes shorts in the range of [0, 65535] and transforms them linearly to [0.0, 1.0], + // so multiply by 65535, not 65536. + // + // TODO: Does this introduce precision issues? Do we need to fall back to floats here? This might break + // with high resolution texture packs. +// int midU = (int)(65535.0F * Math.min(uSum * 0.25f, 1.0f)) & 0xFFFF; +// int midV = (int)(65535.0F * Math.min(vSum * 0.25f, 1.0f)) & 0xFFFF; +// int midTexCoord = (midV << 16) | midU; + + uSum *= 0.25f; + vSum *= 0.25f; + + buffer.putFloat(i + 20, uSum); + buffer.putFloat(i + 20 - STRIDE, uSum); + buffer.putFloat(i + 20 - STRIDE * 2, uSum); + buffer.putFloat(i + 20 - STRIDE * 3, uSum); + + buffer.putFloat(i + 24, vSum); + buffer.putFloat(i + 24 - STRIDE, vSum); + buffer.putFloat(i + 24 - STRIDE * 2, vSum); + buffer.putFloat(i + 24 - STRIDE * 3, vSum); + + uSum = 0; + vSum = 0; + + // normal computation + // Implementation based on the algorithm found here: + // https://github.com/IrisShaders/ShaderDoc/blob/master/vertex-format-extensions.md#surface-normal-vector + + quad.setup(buffer, i, STRIDE); + NormalHelper.computeFaceNormal(normal, quad); + int packedNormal = NormalHelper.packNormal(normal, 0.0f); + + buffer.putInt(i + 32, packedNormal); + buffer.putInt(i + 32 - STRIDE, packedNormal); + buffer.putInt(i + 32 - STRIDE * 2, packedNormal); + buffer.putInt(i + 32 - STRIDE * 3, packedNormal); + + int tangent = NormalHelper.computeTangent(normal.x, normal.y, normal.z, quad); + + buffer.putInt(i + 28, tangent); + buffer.putInt(i + 28 - STRIDE, tangent); + buffer.putInt(i + 28 - STRIDE * 2, tangent); + buffer.putInt(i + 28 - STRIDE * 3, tangent); + } + + this.advance(); + } + + @Override + public void iris$setContextHolder(BlockContextHolder holder) { + this.contextHolder = holder; + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterUnsafe.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterUnsafe.java new file mode 100644 index 000000000..116807d4f --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterUnsafe.java @@ -0,0 +1,147 @@ +package net.coderbot.iris.sodium.vertex_format.terrain_xhfp; + +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.render.chunk.format.ModelVertexSink; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexUtil; +import net.coderbot.iris.compat.sodium.impl.block_context.BlockContextHolder; +import net.coderbot.iris.compat.sodium.impl.block_context.ContextAwareVertexWriter; +import net.coderbot.iris.compat.sodium.impl.vertex_format.IrisModelVertexFormats; +import net.coderbot.iris.vendored.joml.Vector3f; +import net.coderbot.iris.vertices.ExtendedDataHelper; +import net.coderbot.iris.vertices.NormalHelper; +import org.lwjgl.system.MemoryUtil; + +import static net.coderbot.iris.compat.sodium.impl.vertex_format.terrain_xhfp.XHFPModelVertexType.STRIDE; + +public class XHFPModelVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ModelVertexSink, ContextAwareVertexWriter { + private final QuadViewTerrain.QuadViewTerrainUnsafe quad = new QuadViewTerrain.QuadViewTerrainUnsafe(); + private final Vector3f normal = new Vector3f(); + + private BlockContextHolder contextHolder; + + private int vertexCount; + private float uSum; + private float vSum; + + public XHFPModelVertexBufferWriterUnsafe(VertexBufferView backingBuffer) { + super(backingBuffer, IrisModelVertexFormats.MODEL_VERTEX_XHFP); + } + + @Override + public void writeQuad(float x, float y, float z, int color, float u, float v, int light) { + uSum += u; + vSum += v; + + this.writeQuadInternal( + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(x), + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(y), + ModelVertexUtil.denormalizeVertexPositionFloatAsShort(z), + color, + ModelVertexUtil.denormalizeVertexTextureFloatAsShort(u), + ModelVertexUtil.denormalizeVertexTextureFloatAsShort(v), + light, + contextHolder.blockId, + contextHolder.renderType, + ExtendedDataHelper.computeMidBlock(x, y, z, contextHolder.localPosX, contextHolder.localPosY, contextHolder.localPosZ) + ); + } + + private void writeQuadInternal(short x, short y, short z, int color, short u, short v, int light, short materialId, + short renderType, int packedMidBlock) { + long i = this.writePointer; + + vertexCount++; + // NB: uSum and vSum must already be incremented outside of this function. + + MemoryUtil.memPutShort(i, x); + MemoryUtil.memPutShort(i + 2, y); + MemoryUtil.memPutShort(i + 4, z); + MemoryUtil.memPutInt(i + 8, color); + MemoryUtil.memPutShort(i + 12, u); + MemoryUtil.memPutShort(i + 14, v); + MemoryUtil.memPutShort(i + 16, (short) (light & 0xFFFF)); + MemoryUtil.memPutShort(i + 18, (short) (light >> 16 & 0xFFFF)); + // NB: We don't set midTexCoord, normal, and tangent here, they will be filled in later. + // block ID: We only set the first 2 values, any legacy shaders using z or w will get filled in based on the GLSL spec + // https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_format + // TODO: can we pack this into one short? + MemoryUtil.memPutShort(i + 36, materialId); + MemoryUtil.memPutShort(i + 38, renderType); + MemoryUtil.memPutInt(i + 40, packedMidBlock); + + if (vertexCount == 4) { + vertexCount = 0; + + // FIXME + // The following logic is incorrect because OpenGL denormalizes shorts by dividing by 65535. The atlas is + // based on power-of-two values and so a normalization factor that is not a power of two causes the values + // used in the shader to be off by enough to cause visual errors. These are most noticeable on 1.18 with POM + // on block edges. + // + // The only reliable way that this can be fixed is to apply the same shader transformations to midTexCoord + // as Sodium does to the regular texture coordinates - dividing them by the correct power-of-two value inside + // of the shader instead of letting OpenGL value normalization do the division. However, this requires + // fragile patching that is not yet possible. + // + // As a temporary solution, the normalized shorts have been replaced with regular floats, but this takes up + // an extra 4 bytes per vertex. + + // NB: Be careful with the math here! A previous bug was caused by midU going negative as a short, which + // was sign-extended into midTexCoord, causing midV to have garbage (likely NaN data). If you're touching + // this code, be aware of that, and don't introduce those kinds of bugs! + // + // Also note that OpenGL takes shorts in the range of [0, 65535] and transforms them linearly to [0.0, 1.0], + // so multiply by 65535, not 65536. + // + // TODO: Does this introduce precision issues? Do we need to fall back to floats here? This might break + // with high resolution texture packs. +// int midU = (int)(65535.0F * Math.min(uSum * 0.25f, 1.0f)) & 0xFFFF; +// int midV = (int)(65535.0F * Math.min(vSum * 0.25f, 1.0f)) & 0xFFFF; +// int midTexCoord = (midV << 16) | midU; + + uSum *= 0.25f; + vSum *= 0.25f; + + MemoryUtil.memPutFloat(i + 20, uSum); + MemoryUtil.memPutFloat(i + 20 - STRIDE, uSum); + MemoryUtil.memPutFloat(i + 20 - STRIDE * 2, uSum); + MemoryUtil.memPutFloat(i + 20 - STRIDE * 3, uSum); + + MemoryUtil.memPutFloat(i + 24, vSum); + MemoryUtil.memPutFloat(i + 24 - STRIDE, vSum); + MemoryUtil.memPutFloat(i + 24 - STRIDE * 2, vSum); + MemoryUtil.memPutFloat(i + 24 - STRIDE * 3, vSum); + + uSum = 0; + vSum = 0; + + // normal computation + // Implementation based on the algorithm found here: + // https://github.com/IrisShaders/ShaderDoc/blob/master/vertex-format-extensions.md#surface-normal-vector + + quad.setup(i, STRIDE); + NormalHelper.computeFaceNormal(normal, quad); + int packedNormal = NormalHelper.packNormal(normal, 0.0f); + + MemoryUtil.memPutInt(i + 32, packedNormal); + MemoryUtil.memPutInt(i + 32 - STRIDE, packedNormal); + MemoryUtil.memPutInt(i + 32 - STRIDE * 2, packedNormal); + MemoryUtil.memPutInt(i + 32 - STRIDE * 3, packedNormal); + + int tangent = NormalHelper.computeTangent(normal.x, normal.y, normal.z, quad); + + MemoryUtil.memPutInt(i + 28, tangent); + MemoryUtil.memPutInt(i + 28 - STRIDE, tangent); + MemoryUtil.memPutInt(i + 28 - STRIDE * 2, tangent); + MemoryUtil.memPutInt(i + 28 - STRIDE * 3, tangent); + } + + this.advance(); + } + + @Override + public void iris$setContextHolder(BlockContextHolder holder) { + this.contextHolder = holder; + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java new file mode 100644 index 000000000..afe9e4750 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java @@ -0,0 +1,63 @@ +package net.coderbot.iris.sodium.vertex_format.terrain_xhfp; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; +import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; +import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; +import me.jellysquid.mods.sodium.client.model.vertex.type.BlittableVertexType; +import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; +import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; +import net.coderbot.iris.compat.sodium.impl.vertex_format.IrisChunkMeshAttributes; +import net.coderbot.iris.compat.sodium.impl.vertex_format.IrisGlVertexAttributeFormat; + +/** + * Like HFPModelVertexType, but extended to support Iris. The extensions aren't particularly efficient right now. + */ +public class XHFPModelVertexType implements ChunkVertexType { + public static final int STRIDE = 44; + public static final GlVertexFormat VERTEX_FORMAT = GlVertexFormat.builder(ChunkMeshAttribute.class, STRIDE) + .addElement(ChunkMeshAttribute.POSITION, 0, GlVertexAttributeFormat.UNSIGNED_SHORT, 3, false) + .addElement(ChunkMeshAttribute.COLOR, 8, GlVertexAttributeFormat.UNSIGNED_BYTE, 4, true) + .addElement(ChunkMeshAttribute.TEXTURE, 12, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, false) + .addElement(ChunkMeshAttribute.LIGHT, 16, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, false) + .addElement(IrisChunkMeshAttributes.MID_TEX_COORD, 20, GlVertexAttributeFormat.FLOAT, 2, false) + .addElement(IrisChunkMeshAttributes.TANGENT, 28, IrisGlVertexAttributeFormat.BYTE, 4, true) + .addElement(IrisChunkMeshAttributes.NORMAL, 32, IrisGlVertexAttributeFormat.BYTE, 3, true) + .addElement(IrisChunkMeshAttributes.BLOCK_ID, 36, IrisGlVertexAttributeFormat.SHORT, 2, false) + .addElement(IrisChunkMeshAttributes.MID_BLOCK, 40, IrisGlVertexAttributeFormat.BYTE, 3, false) + .build(); + + public static final float MODEL_SCALE = (32.0f / 65536.0f); + public static final float TEXTURE_SCALE = (1.0f / 32768.0f); + + @Override + public ModelVertexSink createFallbackWriter(VertexConsumer consumer) { + throw new UnsupportedOperationException(); + } + + @Override + public ModelVertexSink createBufferWriter(VertexBufferView buffer, boolean direct) { + return direct ? new XHFPModelVertexBufferWriterUnsafe(buffer) : new XHFPModelVertexBufferWriterNio(buffer); + } + + @Override + public BlittableVertexType asBlittable() { + return this; + } + + @Override + public GlVertexFormat getCustomVertexFormat() { + return VERTEX_FORMAT; + } + + @Override + public float getModelScale() { + return MODEL_SCALE; + } + + @Override + public float getTextureScale() { + return TEXTURE_SCALE; + } +} From d49b31c1584b48575ede017fdcb10c13365d2c0c Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 25 Nov 2023 23:28:29 -0800 Subject: [PATCH 146/301] Iris work * More CompatMemoryUtil functions * Fix Sodium GLProgram to use ResourceLocation instead of Identifier * rm GUI options for now --- .../compat/lwjgl/CompatMemoryUtil.java | 8 ++ .../compat/mojang/OverlayTexture.java | 7 ++ .../gl/attribute/GlVertexAttributeFormat.java | 2 +- .../sodium/client/gl/shader/GlProgram.java | 16 ++-- .../render/chunk/shader/ChunkProgram.java | 5 +- .../shader/ChunkRenderShaderBackend.java | 3 +- .../iris/pipeline/PipelineManager.java | 2 + .../block_context/BlockContextHolder.java | 2 +- .../block_context/ChunkBuildBuffersExt.java | 2 +- .../sodium/options/IrisSodiumOptions.java | 79 ------------------- .../sodium/options/OptionImplExtended.java | 7 -- .../sodium/options/SupportedGraphicsMode.java | 23 ------ .../ChunkRenderBackendExt.java | 4 +- .../shader_overrides/IrisChunkProgram.java | 24 +++--- .../IrisChunkProgramOverrides.java | 4 +- .../IrisGlVertexAttributeFormat.java | 8 +- .../vertex_format/IrisModelVertexFormats.java | 2 +- .../EntityVertexBufferWriterNio.java | 4 +- .../EntityVertexBufferWriterUnsafe.java | 30 +++---- .../entity_xhfp/ExtendedGlyphVertexType.java | 4 +- .../entity_xhfp/ExtendedQuadVertexType.java | 4 +- .../GlyphVertexBufferWriterNio.java | 4 +- .../GlyphVertexBufferWriterUnsafe.java | 28 +++---- .../entity_xhfp/QuadViewEntity.java | 4 +- .../terrain_xhfp/QuadViewTerrain.java | 4 +- .../XHFPModelVertexBufferWriterNio.java | 10 +-- .../XHFPModelVertexBufferWriterUnsafe.java | 66 ++++++++-------- .../terrain_xhfp/XHFPModelVertexType.java | 6 +- 28 files changed, 132 insertions(+), 230 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java delete mode 100644 src/main/java/net/coderbot/iris/sodium/options/IrisSodiumOptions.java delete mode 100644 src/main/java/net/coderbot/iris/sodium/options/OptionImplExtended.java delete mode 100644 src/main/java/net/coderbot/iris/sodium/options/SupportedGraphicsMode.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java index fc50b9bcc..0cfc3c7c1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java @@ -71,4 +71,12 @@ private static sun.misc.Unsafe getUnsafeInstance() { public static void memPutFloat(long ptr, float value) { UNSAFE.putFloat(null, ptr, value); } public static void memPutDouble(long ptr, double value) { UNSAFE.putDouble(null, ptr, value); } + public static boolean memGetBoolean(long ptr) { return UNSAFE.getByte(null, ptr) != 0; } + public static byte memGetByte(long ptr) { return UNSAFE.getByte(null, ptr); } + public static short memGetShort(long ptr) { return UNSAFE.getShort(null, ptr); } + public static int memGetInt(long ptr) { return UNSAFE.getInt(null, ptr); } + public static long memGetLong(long ptr) { return UNSAFE.getLong(null, ptr); } + public static float memGetFloat(long ptr) { return UNSAFE.getFloat(null, ptr); } + public static double memGetDouble(long ptr) { return UNSAFE.getDouble(null, ptr); } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java new file mode 100644 index 000000000..fd219461f --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java @@ -0,0 +1,7 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class OverlayTexture { + + // This is definitely wrong + public static final int NO_OVERLAY = 0; +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java index 43324e3eb..11ba3aa27 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java @@ -13,7 +13,7 @@ public class GlVertexAttributeFormat { private final int glId; private final int size; - private GlVertexAttributeFormat(int glId, int size) { + public GlVertexAttributeFormat(int glId, int size) { this.glId = glId; this.size = size; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java index 722a15590..c7a8618fb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/GlProgram.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.gl.shader; -import io.github.douira.glsl_transformer.ast.node.Identifier; import me.jellysquid.mods.sodium.client.gl.GlObject; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import net.minecraft.util.ResourceLocation; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL11; @@ -15,16 +15,16 @@ public abstract class GlProgram extends GlObject { private static final Logger LOGGER = LogManager.getLogger(GlProgram.class); - private final Identifier name; + private final ResourceLocation name; - protected GlProgram(RenderDevice owner, Identifier name, int program) { + protected GlProgram(RenderDevice owner, ResourceLocation name, int program) { super(owner); this.name = name; this.setHandle(program); } - public static Builder builder(Identifier identifier) { + public static Builder builder(ResourceLocation identifier) { return new Builder(identifier); } @@ -36,7 +36,7 @@ public void unbind() { GL20.glUseProgram(0); } - public Identifier getName() { + public ResourceLocation getName() { return this.name; } @@ -63,10 +63,10 @@ public void delete() { } public static class Builder { - private final Identifier name; + private final ResourceLocation name; private final int program; - public Builder(Identifier name) { + public Builder(ResourceLocation name) { this.name = name; this.program = GL20.glCreateProgram(); } @@ -112,6 +112,6 @@ public Builder bindAttribute(String name, ShaderBindingPoint binding) { } public interface ProgramFactory

{ - P create(Identifier name, int handle); + P create(ResourceLocation name, int handle); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java index 99062857d..07d2ec44c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java @@ -1,12 +1,11 @@ package me.jellysquid.mods.sodium.client.render.chunk.shader; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; -import io.github.douira.glsl_transformer.ast.node.Identifier; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; import me.jellysquid.mods.sodium.client.render.GameRendererContext; import net.minecraft.client.renderer.OpenGlHelper; - +import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; @@ -26,7 +25,7 @@ public class ChunkProgram extends GlProgram { // The fog shader component used by this program in order to setup the appropriate GL state private final ChunkShaderFogComponent fogShader; - protected ChunkProgram(RenderDevice owner, Identifier name, int handle, Function fogShaderFunction) { + protected ChunkProgram(RenderDevice owner, ResourceLocation name, int handle, Function fogShaderFunction) { super(owner, name, handle); this.uModelViewProjectionMatrix = this.getUniformLocation("u_ModelViewProjectionMatrix"); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java index 4cabb257c..f88773b61 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java @@ -1,7 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.shader; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; -import io.github.douira.glsl_transformer.ast.node.Identifier; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; import me.jellysquid.mods.sodium.client.gl.compat.FogHelper; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; @@ -36,7 +35,7 @@ private ChunkProgram createShader(RenderDevice device, ChunkFogMode fogMode, GlV GlShader fragShader = ShaderLoader.loadShader(device, ShaderType.FRAGMENT, new ResourceLocation("sodium", "chunk_gl20"), fogMode.getDefines()); try { - return GlProgram.builder(new Identifier("chunk_shader")) + return GlProgram.builder(new ResourceLocation("sodium", "chunk_shader")) .attachShader(vertShader) .attachShader(fragShader) .bindAttribute("a_Pos", ChunkShaderBindingPoints.POSITION) diff --git a/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java b/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java index 86f37583b..987419f9b 100644 --- a/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java +++ b/src/main/java/net/coderbot/iris/pipeline/PipelineManager.java @@ -1,6 +1,7 @@ package net.coderbot.iris.pipeline; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import lombok.Getter; import net.coderbot.iris.Iris; import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.coderbot.iris.shaderpack.DimensionId; @@ -20,6 +21,7 @@ public class PipelineManager { private final Function pipelineFactory; private final Map pipelinesPerDimension = new HashMap<>(); private WorldRenderingPipeline pipeline = new FixedFunctionWorldRenderingPipeline(); + @Getter private int versionCounterForSodiumShaderReload = 0; public PipelineManager(Function pipelineFactory) { diff --git a/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java b/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java index 0342f1d13..87ce2e4fe 100644 --- a/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java +++ b/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java @@ -1,8 +1,8 @@ package net.coderbot.iris.sodium.block_context; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMaps; -import net.minecraft.world.level.block.state.BlockState; public class BlockContextHolder { private final Object2IntMap blockStateIds; diff --git a/src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java b/src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java index 551a978f0..8f4545c3b 100644 --- a/src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java +++ b/src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java @@ -1,6 +1,6 @@ package net.coderbot.iris.sodium.block_context; -import net.minecraft.world.level.block.state.BlockState; +import com.gtnewhorizons.angelica.compat.mojang.BlockState; public interface ChunkBuildBuffersExt { void iris$setLocalPos(int localPosX, int localPosY, int localPosZ); diff --git a/src/main/java/net/coderbot/iris/sodium/options/IrisSodiumOptions.java b/src/main/java/net/coderbot/iris/sodium/options/IrisSodiumOptions.java deleted file mode 100644 index 518390101..000000000 --- a/src/main/java/net/coderbot/iris/sodium/options/IrisSodiumOptions.java +++ /dev/null @@ -1,79 +0,0 @@ -package net.coderbot.iris.sodium.options; - -import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; -import me.jellysquid.mods.sodium.client.gui.options.OptionImpact; -import me.jellysquid.mods.sodium.client.gui.options.OptionImpl; -import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; -import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl; -import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl; -import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; -import net.coderbot.iris.Iris; -import net.coderbot.iris.colorspace.ColorSpace; -import net.coderbot.iris.gui.option.IrisVideoSettings; -import net.minecraft.client.Options; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.chat.TranslatableComponent; - -import java.io.IOException; - -public class IrisSodiumOptions { - public static OptionImpl createMaxShadowDistanceSlider(MinecraftOptionsStorage vanillaOpts) { - OptionImpl maxShadowDistanceSlider = OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(new TranslatableComponent("options.iris.shadowDistance")) - .setTooltip(new TranslatableComponent("options.iris.shadowDistance.sodium_tooltip")) - .setControl(option -> new SliderControl(option, 0, 32, 1, ControlValueFormatter.quantity("options.chunks"))) - .setBinding((options, value) -> { - IrisVideoSettings.shadowDistance = value; - try { - Iris.getIrisConfig().save(); - } catch (IOException e) { - e.printStackTrace(); - } - }, - options -> IrisVideoSettings.getOverriddenShadowDistance(IrisVideoSettings.shadowDistance)) - .setImpact(OptionImpact.HIGH) - .setEnabled(true) - .build(); - - ((OptionImplExtended) maxShadowDistanceSlider).iris$dynamicallyEnable(IrisVideoSettings::isShadowDistanceSliderEnabled); - - return maxShadowDistanceSlider; - } - - public static OptionImpl createColorSpaceButton(MinecraftOptionsStorage vanillaOpts) { - OptionImpl colorSpace = OptionImpl.createBuilder(ColorSpace.class, vanillaOpts) - .setName(new TranslatableComponent("options.iris.colorSpace")) - .setTooltip(new TranslatableComponent("options.iris.colorSpace.sodium_tooltip")) - .setControl(option -> new CyclingControl<>(option, ColorSpace.class, - new Component[] { new TextComponent("SRGB"), new TextComponent("DCI_P3"), new TextComponent("Display P3"), new TextComponent("REC2020"), new TextComponent("Adobe RGB") })) - .setBinding((options, value) -> { - IrisVideoSettings.colorSpace = value; - try { - Iris.getIrisConfig().save(); - } catch (IOException e) { - e.printStackTrace(); - } - }, - options -> IrisVideoSettings.colorSpace) - .setImpact(OptionImpact.LOW) - .setEnabled(true) - .build(); - - - return colorSpace; - } - - public static OptionImpl createLimitedVideoSettingsButton(MinecraftOptionsStorage vanillaOpts) { - return OptionImpl.createBuilder(SupportedGraphicsMode.class, vanillaOpts) - .setName(new TranslatableComponent("options.graphics")) - .setTooltip(new TranslatableComponent("sodium.options.graphics_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, SupportedGraphicsMode.class, new Component[] { new TranslatableComponent("options.graphics.fast"), new TranslatableComponent("options.graphics.fancy") })) - .setBinding( - (opts, value) -> opts.graphicsMode = value.toVanilla(), - opts -> SupportedGraphicsMode.fromVanilla(opts.graphicsMode)) - .setImpact(OptionImpact.HIGH) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build(); - } -} diff --git a/src/main/java/net/coderbot/iris/sodium/options/OptionImplExtended.java b/src/main/java/net/coderbot/iris/sodium/options/OptionImplExtended.java deleted file mode 100644 index a9a1135fa..000000000 --- a/src/main/java/net/coderbot/iris/sodium/options/OptionImplExtended.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.coderbot.iris.sodium.options; - -import java.util.function.BooleanSupplier; - -public interface OptionImplExtended { - void iris$dynamicallyEnable(BooleanSupplier enabled); -} diff --git a/src/main/java/net/coderbot/iris/sodium/options/SupportedGraphicsMode.java b/src/main/java/net/coderbot/iris/sodium/options/SupportedGraphicsMode.java deleted file mode 100644 index 5e59e5274..000000000 --- a/src/main/java/net/coderbot/iris/sodium/options/SupportedGraphicsMode.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.coderbot.iris.sodium.options; - -import net.minecraft.client.GraphicsStatus; - -public enum SupportedGraphicsMode { - FAST, FANCY; - - public static SupportedGraphicsMode fromVanilla(GraphicsStatus vanilla) { - if (vanilla == GraphicsStatus.FAST) { - return FAST; - } else { - return FANCY; - } - } - - public GraphicsStatus toVanilla() { - if (this == FAST) { - return GraphicsStatus.FAST; - } else { - return GraphicsStatus.FANCY; - } - } -} diff --git a/src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java b/src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java index d5ef2a605..9bf87b91b 100644 --- a/src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java +++ b/src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java @@ -1,8 +1,8 @@ package net.coderbot.iris.sodium.shader_overrides; -import com.mojang.blaze3d.vertex.PoseStack; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; public interface ChunkRenderBackendExt { - void iris$begin(PoseStack poseStack, BlockRenderPass pass); + void iris$begin(MatrixStack matrixStack, BlockRenderPass pass); } diff --git a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java index 45341fe2a..dc8c39c41 100644 --- a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java +++ b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java @@ -1,7 +1,6 @@ package net.coderbot.iris.sodium.shader_overrides; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Matrix4f; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkProgram; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderFogComponent; @@ -9,9 +8,10 @@ import net.coderbot.iris.gl.program.ProgramImages; import net.coderbot.iris.gl.program.ProgramSamplers; import net.coderbot.iris.gl.program.ProgramUniforms; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.ResourceLocation; import org.jetbrains.annotations.Nullable; -import org.lwjgl.system.MemoryStack; +import org.joml.Matrix4f; +import org.lwjgl.BufferUtils; import java.nio.FloatBuffer; @@ -40,8 +40,8 @@ public IrisChunkProgram(RenderDevice owner, ResourceLocation name, int handle, this.irisProgramImages = irisProgramImages; } - public void setup(PoseStack poseStack, float modelScale, float textureScale) { - super.setup(poseStack, modelScale, textureScale); + public void setup(MatrixStack matrixStack, float modelScale, float textureScale) { + super.setup(matrixStack, modelScale, textureScale); if (irisProgramUniforms != null) { irisProgramUniforms.update(); @@ -55,8 +55,8 @@ public void setup(PoseStack poseStack, float modelScale, float textureScale) { irisProgramImages.update(); } - Matrix4f modelViewMatrix = poseStack.last().pose(); - Matrix4f normalMatrix = poseStack.last().pose().copy(); + Matrix4f modelViewMatrix = matrixStack.peek().getModel(); + Matrix4f normalMatrix = new Matrix4f(matrixStack.peek().getModel()); normalMatrix.invert(); normalMatrix.transpose(); @@ -87,12 +87,10 @@ private void uniformMatrix(int location, Matrix4f matrix) { return; } - try (MemoryStack memoryStack = MemoryStack.stackPush()) { - FloatBuffer buffer = memoryStack.mallocFloat(16); + FloatBuffer buffer = BufferUtils.createFloatBuffer(16); - matrix.store(buffer); + matrix.get(buffer); - IrisRenderSystem.uniformMatrix4fv(location, false, buffer); - } + IrisRenderSystem.uniformMatrix4fv(location, false, buffer); } } diff --git a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgramOverrides.java b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgramOverrides.java index e4862bc8f..97b26ff4c 100644 --- a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgramOverrides.java +++ b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgramOverrides.java @@ -9,14 +9,14 @@ import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkProgram; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; import net.coderbot.iris.Iris; -import net.coderbot.iris.compat.sodium.impl.IrisChunkShaderBindingPoints; import net.coderbot.iris.gl.program.ProgramImages; import net.coderbot.iris.gl.program.ProgramSamplers; import net.coderbot.iris.gl.program.ProgramUniforms; import net.coderbot.iris.pipeline.SodiumTerrainPipeline; import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.coderbot.iris.shadows.ShadowRenderingState; -import net.minecraft.resources.ResourceLocation; +import net.coderbot.iris.sodium.IrisChunkShaderBindingPoints; +import net.minecraft.util.ResourceLocation; import org.jetbrains.annotations.Nullable; import java.util.EnumMap; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisGlVertexAttributeFormat.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisGlVertexAttributeFormat.java index b48031b54..b2736642c 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisGlVertexAttributeFormat.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisGlVertexAttributeFormat.java @@ -1,11 +1,9 @@ package net.coderbot.iris.sodium.vertex_format; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; -import net.coderbot.iris.compat.sodium.mixin.vertex_format.GlVertexAttributeFormatAccessor; -import org.lwjgl.opengl.GL20C; +import org.lwjgl.opengl.GL11; public class IrisGlVertexAttributeFormat { - public static final GlVertexAttributeFormat BYTE = - GlVertexAttributeFormatAccessor.createGlVertexAttributeFormat(GL20C.GL_BYTE, 1); - public static final GlVertexAttributeFormat SHORT = GlVertexAttributeFormatAccessor.createGlVertexAttributeFormat(GL20C.GL_SHORT, 2); + public static final GlVertexAttributeFormat BYTE = new GlVertexAttributeFormat(GL11.GL_BYTE, 1); + public static final GlVertexAttributeFormat SHORT = new GlVertexAttributeFormat(GL11.GL_SHORT, 2); } diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisModelVertexFormats.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisModelVertexFormats.java index 953600930..b8c963997 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisModelVertexFormats.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisModelVertexFormats.java @@ -1,6 +1,6 @@ package net.coderbot.iris.sodium.vertex_format; -import net.coderbot.iris.compat.sodium.impl.vertex_format.terrain_xhfp.XHFPModelVertexType; +import net.coderbot.iris.sodium.vertex_format.terrain_xhfp.XHFPModelVertexType; public class IrisModelVertexFormats { public static final XHFPModelVertexType MODEL_VERTEX_XHFP = new XHFPModelVertexType(); diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java index 7bfdc7039..47631e385 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java @@ -1,14 +1,14 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; +import com.gtnewhorizons.angelica.compat.mojang.OverlayTexture; 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.vendored.joml.Vector3f; import net.coderbot.iris.vertices.IrisVertexFormats; import net.coderbot.iris.vertices.NormalHelper; -import net.minecraft.client.renderer.texture.OverlayTexture; +import org.joml.Vector3f; import java.nio.ByteBuffer; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java index c345d4397..3f44e1045 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java @@ -1,15 +1,15 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; +import com.gtnewhorizons.angelica.compat.mojang.OverlayTexture; 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.vendored.joml.Vector3f; import net.coderbot.iris.vertices.IrisVertexFormats; import net.coderbot.iris.vertices.NormalHelper; -import net.minecraft.client.renderer.texture.OverlayTexture; -import org.lwjgl.system.MemoryUtil; +import org.joml.Vector3f; public class EntityVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements QuadVertexSink, GlyphVertexSink { private static final int STRIDE = IrisVertexFormats.ENTITY.getVertexSize(); @@ -33,14 +33,14 @@ public void writeQuad(float x, float y, float z, int color, float u, float v, in uSum += u; vSum += v; - MemoryUtil.memPutFloat(i, x); - MemoryUtil.memPutFloat(i + 4, y); - MemoryUtil.memPutFloat(i + 8, z); - MemoryUtil.memPutInt(i + 12, color); - MemoryUtil.memPutFloat(i + 16, u); - MemoryUtil.memPutFloat(i + 20, v); - MemoryUtil.memPutInt(i + 24, overlay); - MemoryUtil.memPutInt(i + 28, light); + CompatMemoryUtil.memPutFloat(i, x); + CompatMemoryUtil.memPutFloat(i + 4, y); + CompatMemoryUtil.memPutFloat(i + 8, z); + CompatMemoryUtil.memPutInt(i + 12, color); + CompatMemoryUtil.memPutFloat(i + 16, u); + CompatMemoryUtil.memPutFloat(i + 20, v); + CompatMemoryUtil.memPutInt(i + 24, overlay); + CompatMemoryUtil.memPutInt(i + 28, light); if (vertexCount == 4) { this.endQuad(normal); @@ -81,10 +81,10 @@ private void endQuad(int normal) { int tangent = NormalHelper.computeTangent(normalX, normalY, normalZ, quad); for (long vertex = 0; vertex < 4; vertex++) { - MemoryUtil.memPutFloat(i + 36 - STRIDE * vertex, uSum); - MemoryUtil.memPutFloat(i + 40 - STRIDE * vertex, vSum); - MemoryUtil.memPutInt(i + 32 - STRIDE * vertex, normal); - MemoryUtil.memPutInt(i + 44 - STRIDE * vertex, tangent); + CompatMemoryUtil.memPutFloat(i + 36 - STRIDE * vertex, uSum); + CompatMemoryUtil.memPutFloat(i + 40 - STRIDE * vertex, vSum); + CompatMemoryUtil.memPutInt(i + 32 - STRIDE * vertex, normal); + CompatMemoryUtil.memPutInt(i + 44 - STRIDE * vertex, tangent); } uSum = 0; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java index 5a0530255..24809d274 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java @@ -1,7 +1,7 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.blaze3d.vertex.VertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; 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; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java index e433d4f2b..df7ddbb28 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java @@ -1,7 +1,7 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.blaze3d.vertex.VertexFormat; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; 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; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java index 5ede018ce..0ca02f7ef 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java @@ -1,14 +1,14 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; +import com.gtnewhorizons.angelica.compat.mojang.OverlayTexture; 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.vendored.joml.Vector3f; import net.coderbot.iris.vertices.IrisVertexFormats; import net.coderbot.iris.vertices.NormalHelper; -import net.minecraft.client.renderer.texture.OverlayTexture; +import org.joml.Vector3f; import java.nio.ByteBuffer; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java index 10eb28037..f4a9222df 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java @@ -1,15 +1,15 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; +import com.gtnewhorizons.angelica.compat.mojang.OverlayTexture; 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.vendored.joml.Vector3f; import net.coderbot.iris.vertices.IrisVertexFormats; import net.coderbot.iris.vertices.NormalHelper; -import net.minecraft.client.renderer.texture.OverlayTexture; -import org.lwjgl.system.MemoryUtil; +import org.joml.Vector3f; public class GlyphVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements QuadVertexSink, GlyphVertexSink { private static final int STRIDE = IrisVertexFormats.TERRAIN.getVertexSize(); @@ -33,13 +33,13 @@ public void writeQuad(float x, float y, float z, int color, float u, float v, in uSum += u; vSum += v; - MemoryUtil.memPutFloat(i, x); - MemoryUtil.memPutFloat(i + 4, y); - MemoryUtil.memPutFloat(i + 8, z); - MemoryUtil.memPutInt(i + 12, color); - MemoryUtil.memPutFloat(i + 16, u); - MemoryUtil.memPutFloat(i + 20, v); - MemoryUtil.memPutInt(i + 24, light); + CompatMemoryUtil.memPutFloat(i, x); + CompatMemoryUtil.memPutFloat(i + 4, y); + CompatMemoryUtil.memPutFloat(i + 8, z); + CompatMemoryUtil.memPutInt(i + 12, color); + CompatMemoryUtil.memPutFloat(i + 16, u); + CompatMemoryUtil.memPutFloat(i + 20, v); + CompatMemoryUtil.memPutInt(i + 24, light); if (vertexCount == 4) { this.endQuad(normal); @@ -80,10 +80,10 @@ private void endQuad(int normal) { int tangent = NormalHelper.computeTangent(normalX, normalY, normalZ, quad); for (long vertex = 0; vertex < 4; vertex++) { - MemoryUtil.memPutFloat(i + 36 - STRIDE * vertex, uSum); - MemoryUtil.memPutFloat(i + 40 - STRIDE * vertex, vSum); - MemoryUtil.memPutInt(i + 28 - STRIDE * vertex, normal); - MemoryUtil.memPutInt(i + 44 - STRIDE * vertex, tangent); + CompatMemoryUtil.memPutFloat(i + 36 - STRIDE * vertex, uSum); + CompatMemoryUtil.memPutFloat(i + 40 - STRIDE * vertex, vSum); + CompatMemoryUtil.memPutInt(i + 28 - STRIDE * vertex, normal); + CompatMemoryUtil.memPutInt(i + 44 - STRIDE * vertex, tangent); } uSum = 0; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/QuadViewEntity.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/QuadViewEntity.java index 3bece5210..e8f59688f 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/QuadViewEntity.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/QuadViewEntity.java @@ -1,7 +1,7 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; import net.coderbot.iris.vertices.QuadView; -import org.lwjgl.system.MemoryUtil; import java.nio.ByteBuffer; @@ -44,7 +44,7 @@ public void setup(long writePointer, int stride) { @Override float getFloat(long writePointer) { - return MemoryUtil.memGetFloat(writePointer); + return CompatMemoryUtil.memGetFloat(writePointer); } } diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/QuadViewTerrain.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/QuadViewTerrain.java index 23040d713..b08298626 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/QuadViewTerrain.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/QuadViewTerrain.java @@ -1,7 +1,7 @@ package net.coderbot.iris.sodium.vertex_format.terrain_xhfp; +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; import net.coderbot.iris.vertices.QuadView; -import org.lwjgl.system.MemoryUtil; import java.nio.ByteBuffer; @@ -52,7 +52,7 @@ public void setup(long writePointer, int stride) { @Override short getShort(long writePointer) { - return MemoryUtil.memGetShort(writePointer); + return CompatMemoryUtil.memGetShort(writePointer); } } diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterNio.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterNio.java index babae0e67..0585aaab8 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterNio.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterNio.java @@ -4,16 +4,16 @@ import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferWriterNio; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexUtil; -import net.coderbot.iris.compat.sodium.impl.block_context.BlockContextHolder; -import net.coderbot.iris.compat.sodium.impl.block_context.ContextAwareVertexWriter; -import net.coderbot.iris.compat.sodium.impl.vertex_format.IrisModelVertexFormats; -import net.coderbot.iris.vendored.joml.Vector3f; +import net.coderbot.iris.sodium.block_context.BlockContextHolder; +import net.coderbot.iris.sodium.block_context.ContextAwareVertexWriter; +import net.coderbot.iris.sodium.vertex_format.IrisModelVertexFormats; import net.coderbot.iris.vertices.ExtendedDataHelper; import net.coderbot.iris.vertices.NormalHelper; +import org.joml.Vector3f; import java.nio.ByteBuffer; -import static net.coderbot.iris.compat.sodium.impl.vertex_format.terrain_xhfp.XHFPModelVertexType.STRIDE; +import static net.coderbot.iris.sodium.vertex_format.terrain_xhfp.XHFPModelVertexType.STRIDE; public class XHFPModelVertexBufferWriterNio extends VertexBufferWriterNio implements ModelVertexSink, ContextAwareVertexWriter { private final QuadViewTerrain.QuadViewTerrainNio quad = new QuadViewTerrain.QuadViewTerrainNio(); diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterUnsafe.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterUnsafe.java index 116807d4f..f9047c6a6 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterUnsafe.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexBufferWriterUnsafe.java @@ -1,18 +1,18 @@ package net.coderbot.iris.sodium.vertex_format.terrain_xhfp; +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; 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.render.chunk.format.ModelVertexSink; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexUtil; -import net.coderbot.iris.compat.sodium.impl.block_context.BlockContextHolder; -import net.coderbot.iris.compat.sodium.impl.block_context.ContextAwareVertexWriter; -import net.coderbot.iris.compat.sodium.impl.vertex_format.IrisModelVertexFormats; -import net.coderbot.iris.vendored.joml.Vector3f; +import net.coderbot.iris.sodium.block_context.BlockContextHolder; +import net.coderbot.iris.sodium.block_context.ContextAwareVertexWriter; +import net.coderbot.iris.sodium.vertex_format.IrisModelVertexFormats; import net.coderbot.iris.vertices.ExtendedDataHelper; import net.coderbot.iris.vertices.NormalHelper; -import org.lwjgl.system.MemoryUtil; +import org.joml.Vector3f; -import static net.coderbot.iris.compat.sodium.impl.vertex_format.terrain_xhfp.XHFPModelVertexType.STRIDE; +import static net.coderbot.iris.sodium.vertex_format.terrain_xhfp.XHFPModelVertexType.STRIDE; public class XHFPModelVertexBufferWriterUnsafe extends VertexBufferWriterUnsafe implements ModelVertexSink, ContextAwareVertexWriter { private final QuadViewTerrain.QuadViewTerrainUnsafe quad = new QuadViewTerrain.QuadViewTerrainUnsafe(); @@ -54,21 +54,21 @@ private void writeQuadInternal(short x, short y, short z, int color, short u, sh vertexCount++; // NB: uSum and vSum must already be incremented outside of this function. - MemoryUtil.memPutShort(i, x); - MemoryUtil.memPutShort(i + 2, y); - MemoryUtil.memPutShort(i + 4, z); - MemoryUtil.memPutInt(i + 8, color); - MemoryUtil.memPutShort(i + 12, u); - MemoryUtil.memPutShort(i + 14, v); - MemoryUtil.memPutShort(i + 16, (short) (light & 0xFFFF)); - MemoryUtil.memPutShort(i + 18, (short) (light >> 16 & 0xFFFF)); + CompatMemoryUtil.memPutShort(i, x); + CompatMemoryUtil.memPutShort(i + 2, y); + CompatMemoryUtil.memPutShort(i + 4, z); + CompatMemoryUtil.memPutInt(i + 8, color); + CompatMemoryUtil.memPutShort(i + 12, u); + CompatMemoryUtil.memPutShort(i + 14, v); + CompatMemoryUtil.memPutShort(i + 16, (short) (light & 0xFFFF)); + CompatMemoryUtil.memPutShort(i + 18, (short) (light >> 16 & 0xFFFF)); // NB: We don't set midTexCoord, normal, and tangent here, they will be filled in later. // block ID: We only set the first 2 values, any legacy shaders using z or w will get filled in based on the GLSL spec // https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_format // TODO: can we pack this into one short? - MemoryUtil.memPutShort(i + 36, materialId); - MemoryUtil.memPutShort(i + 38, renderType); - MemoryUtil.memPutInt(i + 40, packedMidBlock); + CompatMemoryUtil.memPutShort(i + 36, materialId); + CompatMemoryUtil.memPutShort(i + 38, renderType); + CompatMemoryUtil.memPutInt(i + 40, packedMidBlock); if (vertexCount == 4) { vertexCount = 0; @@ -103,15 +103,15 @@ private void writeQuadInternal(short x, short y, short z, int color, short u, sh uSum *= 0.25f; vSum *= 0.25f; - MemoryUtil.memPutFloat(i + 20, uSum); - MemoryUtil.memPutFloat(i + 20 - STRIDE, uSum); - MemoryUtil.memPutFloat(i + 20 - STRIDE * 2, uSum); - MemoryUtil.memPutFloat(i + 20 - STRIDE * 3, uSum); + CompatMemoryUtil.memPutFloat(i + 20, uSum); + CompatMemoryUtil.memPutFloat(i + 20 - STRIDE, uSum); + CompatMemoryUtil.memPutFloat(i + 20 - STRIDE * 2, uSum); + CompatMemoryUtil.memPutFloat(i + 20 - STRIDE * 3, uSum); - MemoryUtil.memPutFloat(i + 24, vSum); - MemoryUtil.memPutFloat(i + 24 - STRIDE, vSum); - MemoryUtil.memPutFloat(i + 24 - STRIDE * 2, vSum); - MemoryUtil.memPutFloat(i + 24 - STRIDE * 3, vSum); + CompatMemoryUtil.memPutFloat(i + 24, vSum); + CompatMemoryUtil.memPutFloat(i + 24 - STRIDE, vSum); + CompatMemoryUtil.memPutFloat(i + 24 - STRIDE * 2, vSum); + CompatMemoryUtil.memPutFloat(i + 24 - STRIDE * 3, vSum); uSum = 0; vSum = 0; @@ -124,17 +124,17 @@ private void writeQuadInternal(short x, short y, short z, int color, short u, sh NormalHelper.computeFaceNormal(normal, quad); int packedNormal = NormalHelper.packNormal(normal, 0.0f); - MemoryUtil.memPutInt(i + 32, packedNormal); - MemoryUtil.memPutInt(i + 32 - STRIDE, packedNormal); - MemoryUtil.memPutInt(i + 32 - STRIDE * 2, packedNormal); - MemoryUtil.memPutInt(i + 32 - STRIDE * 3, packedNormal); + CompatMemoryUtil.memPutInt(i + 32, packedNormal); + CompatMemoryUtil.memPutInt(i + 32 - STRIDE, packedNormal); + CompatMemoryUtil.memPutInt(i + 32 - STRIDE * 2, packedNormal); + CompatMemoryUtil.memPutInt(i + 32 - STRIDE * 3, packedNormal); int tangent = NormalHelper.computeTangent(normal.x, normal.y, normal.z, quad); - MemoryUtil.memPutInt(i + 28, tangent); - MemoryUtil.memPutInt(i + 28 - STRIDE, tangent); - MemoryUtil.memPutInt(i + 28 - STRIDE * 2, tangent); - MemoryUtil.memPutInt(i + 28 - STRIDE * 3, tangent); + CompatMemoryUtil.memPutInt(i + 28, tangent); + CompatMemoryUtil.memPutInt(i + 28 - STRIDE, tangent); + CompatMemoryUtil.memPutInt(i + 28 - STRIDE * 2, tangent); + CompatMemoryUtil.memPutInt(i + 28 - STRIDE * 3, tangent); } this.advance(); diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java index afe9e4750..6e1e83a15 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java @@ -1,6 +1,6 @@ package net.coderbot.iris.sodium.vertex_format.terrain_xhfp; -import com.mojang.blaze3d.vertex.VertexConsumer; +import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; @@ -8,8 +8,8 @@ import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; -import net.coderbot.iris.compat.sodium.impl.vertex_format.IrisChunkMeshAttributes; -import net.coderbot.iris.compat.sodium.impl.vertex_format.IrisGlVertexAttributeFormat; +import net.coderbot.iris.sodium.vertex_format.IrisChunkMeshAttributes; +import net.coderbot.iris.sodium.vertex_format.IrisGlVertexAttributeFormat; /** * Like HFPModelVertexType, but extended to support Iris. The extensions aren't particularly efficient right now. From 6a03b31b9ed7051b6b2a48725c18724e2593a7f3 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 25 Nov 2023 23:48:53 -0800 Subject: [PATCH 147/301] Start applying Iris -> Sodium Mixins --- .../model/light/flat/FlatLightPipeline.java | 7 +++- .../light/smooth/SmoothLightPipeline.java | 8 +++- .../java/net/coderbot/iris/sodium/Mixins.txt | 39 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/main/java/net/coderbot/iris/sodium/Mixins.txt diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java index 2a87fd05d..3f3a3119e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java @@ -3,11 +3,14 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; +import net.minecraft.client.renderer.WorldRenderer; import net.minecraftforge.common.util.ForgeDirection; import java.util.Arrays; @@ -45,7 +48,9 @@ public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Forge } Arrays.fill(out.lm, lightmap); - Arrays.fill(out.br, this.lightCache.getWorld().getBrightness(face, shade)); + final float brightness = (AngelicaConfig.enableIris && BlockRenderingSettings.INSTANCE.shouldDisableDirectionalShading()) + ? 1.0F : this.lightCache.getWorld().getBrightness(face, shade); + Arrays.fill(out.br, brightness); } /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java index 4bbac4afb..dbc6ef5c4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java @@ -1,12 +1,14 @@ package me.jellysquid.mods.sodium.client.model.light.smooth; import com.google.common.math.DoubleMath; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.minecraftforge.common.util.ForgeDirection; @@ -218,6 +220,10 @@ private void applyInsetPartialFaceVertex(BlockPos pos, ForgeDirection dir, float } private void applySidedBrightness(QuadLightData out, ForgeDirection face, boolean shade) { + if(AngelicaConfig.enableIris && BlockRenderingSettings.INSTANCE.shouldDisableDirectionalShading()) { + return; + } + float brightness = this.lightCache.getWorld().getBrightness(face, shade); float[] br = out.br; diff --git a/src/main/java/net/coderbot/iris/sodium/Mixins.txt b/src/main/java/net/coderbot/iris/sodium/Mixins.txt new file mode 100644 index 000000000..3a76d7698 --- /dev/null +++ b/src/main/java/net/coderbot/iris/sodium/Mixins.txt @@ -0,0 +1,39 @@ +Y directional_shading + Y MixinSmoothLightPipeline.java + Y MixinFlatLightPipeline.java +* shader_overrides + * ShaderTypeAccessor.java + * MixinChunkRenderShaderBackend.java + * MixinShaderType.java + * MixinChunkProgram.java + * MixinChunkRenderManager.java +* shadow_map + * MixinSodiumWorldRenderer.java + * MixinGameRendererContext.java + * MixinChunkRenderManager.java +* block_id + * MixinChunkRenderRebuildTask.java + * MixinChunkBuildBuffers.java +* pbr_animation + * MixinTextureAtlasSprite.java +* vertex_format + * entity + * MixinBufferBuilder_ExtendedVertexFormatCompat.java + * MixinSodiumWorldRenderer.java + * MixinChunkOneshotGraphicsState.java + * GlVertexAttributeFormatAccessor.java + * MixinMultidrawChunkRenderBackend.java + * MixinChunkMeshAttribute.java + * MixinGlVertexFormatBuilder.java + * ChunkMeshAttributeAccessor.java +* separate_ao + * MixinBlockRenderer.java + * MixinFluidRenderer.java + * MixinBufferBuilder_IntrinsicSeparateAo.java +* options + X MixinSodiumGameOptionPages.java + X MixinOptionImpl.java + X MixinSodiumGameOptions.java + X MixinSodiumOptionsGUI.java + X MixinChunkRenderManager.java +* IrisSodiumCompatMixinPlugin.java From 539dea52fbb7f63adc31ffdce4100c3a4a64d06d Mon Sep 17 00:00:00 2001 From: jss2a98aj Date: Sun, 26 Nov 2023 05:07:45 -0500 Subject: [PATCH 148/301] Make NotFine menu open if holding shift --- .../mods/sodium/client/SodiumClientMod.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index 9a9f32c6e..42b3b71e4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -3,10 +3,13 @@ import com.gtnewhorizons.angelica.Tags; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import jss.notfine.gui.GuiCustomMenu; +import jss.notfine.gui.MenuButtonLists; import lombok.Getter; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiVideoSettings; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.MinecraftForge; @@ -42,9 +45,13 @@ public SodiumClientMod() { @SubscribeEvent public void onGui(GuiScreenEvent.InitGuiEvent.Pre event) { - if(event.gui instanceof GuiVideoSettings) { + if(event.gui instanceof GuiVideoSettings eventGui) { event.setCanceled(true); - Minecraft.getMinecraft().displayGuiScreen(new SodiumOptionsGUI(((GuiVideoSettings) event.gui).parentGuiScreen)); + if(GuiScreen.isShiftKeyDown()) { + Minecraft.getMinecraft().displayGuiScreen(new GuiCustomMenu(eventGui.parentGuiScreen, MenuButtonLists.VIDEO)); + } else { + Minecraft.getMinecraft().displayGuiScreen(new SodiumOptionsGUI(eventGui.parentGuiScreen)); + } } } From 1fdd1b319cf94092e7c040ef8be1455b7c144c58 Mon Sep 17 00:00:00 2001 From: Asek3 <64613894+Asek3@users.noreply.github.com> Date: Sun, 26 Nov 2023 12:13:59 +0200 Subject: [PATCH 149/301] Fixed Tessellators in production env --- .../angelica/transform/TessellatorTransformer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java index 2bb357d3f..732e3076a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java @@ -27,7 +27,7 @@ public byte[] transform(final String className, String transformedName, byte[] b for(AbstractInsnNode insn : m.instructions) { if(insn.getOpcode() == Opcodes.GETSTATIC) { FieldInsnNode fNode = (FieldInsnNode)insn; - if(fNode.name.equals("instance") && fNode.owner.equals("net/minecraft/client/renderer/Tessellator")) { + if((fNode.name.equals("field_78398_a") || fNode.name.equals("instance")) && fNode.owner.equals("net/minecraft/client/renderer/Tessellator")) { MethodInsnNode getNode = new MethodInsnNode(Opcodes.INVOKESTATIC, "com/gtnewhorizons/angelica/glsm/TessellatorManager", "get", "()Lnet/minecraft/client/renderer/Tessellator;", false); m.instructions.set(fNode, getNode); changed = true; From 5e8c4a6968c9ff065c63c83f2e36e3d523b1e2af Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Sun, 26 Nov 2023 08:09:59 -0500 Subject: [PATCH 150/301] Finish Sodium Fluid Renderer (#24) * Get icon sanely * Update WorldSlice.java * Update SodiumConfig.java oops * Init and pass Sodium LightPipelines * Update FluidRenderer.java actually save the lpp * Remove registry lookup and refactor WorldUtil * Hook up lighting pipeline * Patch fluid velocity * Update WorldUtil.java oops * It's alive! Sodium Fluid Renderer is alive! --- .../angelica/compat/mojang/BlockPos.java | 22 +++ .../angelica/compat/mojang/BlockState.java | 3 +- .../compat/mojang/WorldRendererExt.java | 15 -- .../model/light/data/LightDataAccess.java | 3 +- .../chunk/tasks/ChunkRenderRebuildTask.java | 2 +- .../client/render/pipeline/FluidRenderer.java | 77 +++++---- .../context/ChunkRenderCacheLocal.java | 10 +- .../mods/sodium/client/util/WorldUtil.java | 84 ---------- .../mods/sodium/client/world/WorldSlice.java | 8 +- .../mods/sodium/common/util/WorldUtil.java | 146 ++++++++++++++++++ 10 files changed, 230 insertions(+), 140 deletions(-) delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/util/WorldUtil.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java index 4d9bd1feb..83586a52d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java @@ -2,6 +2,7 @@ import net.minecraft.util.MathHelper; import net.minecraft.world.ChunkPosition; +import net.minecraftforge.common.util.ForgeDirection; import org.joml.Vector3i; import java.math.RoundingMode; @@ -45,6 +46,27 @@ public BlockPos set(int x, int y, int z) { return this; } + /** + * This method does NOT mutate the BlockPos + */ + public BlockPos offset(ForgeDirection d) { + return new BlockPos(this.x + d.offsetX, this.y + d.offsetY, this.z + d.offsetZ); + } + + /** + * This method does NOT mutate the BlockPos + */ + public BlockPos down() { + return offset(ForgeDirection.DOWN); + } + + /** + * This method does NOT mutate the BlockPos + */ + public BlockPos up() { + return offset(ForgeDirection.UP); + } + public long asLong() { return asLong(this.x, this.y, this.z); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java index 0075dcf87..46238b871 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.compat.mojang; import com.gtnewhorizons.angelica.compat.forge.IForgeBlockState; +import me.jellysquid.mods.sodium.common.util.WorldUtil; import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; import net.minecraft.block.material.Material; @@ -79,7 +80,7 @@ public long getRenderingSeed(BlockPos.Mutable pos) { } public FluidState getFluidState() { - return new FluidState(FluidRegistry.lookupFluidForBlock(block), meta); + return new FluidState(WorldUtil.getFluid(block), meta); } public boolean shouldDisplayFluidOverlay(BlockRenderView world, BlockPos adjPos, FluidState fluidState) { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java index ac4ff987c..36e679bfb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java @@ -1,20 +1,5 @@ package com.gtnewhorizons.angelica.compat.mojang; -import me.jellysquid.mods.sodium.client.world.WorldSlice; -import net.minecraft.block.Block; -import net.minecraft.world.EnumSkyBlock; - public interface WorldRendererExt { - static int getLightmapCoordinates(WorldSlice world, Block block, BlockPos pos) { - - if (block.getLightValue() > 0) { - return 0xF000F0; - } - - int sl = world.getLightLevel(EnumSkyBlock.Sky, pos.x, pos.y, pos.z); - int bl = world.getLightLevel(EnumSkyBlock.Block, pos.x, pos.y, pos.z); - bl += sl; - return sl << 20 | bl << 4; - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java index fd6ba4854..4282fa7d8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java @@ -1,7 +1,6 @@ package me.jellysquid.mods.sodium.client.model.light.data; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.WorldRendererExt; import me.jellysquid.mods.sodium.client.world.WorldSlice; import net.minecraft.block.Block; import net.minecraftforge.common.util.ForgeDirection; @@ -72,7 +71,7 @@ protected long compute(int x, int y, int z) { // OPTIMIZE: Do not calculate lightmap data if the block is full and opaque. // FIX: Calculate lightmap data for light-emitting or emissive blocks, even though they are full and opaque. - int lm = (fo && !em) ? 0 : WorldRendererExt.getLightmapCoordinates(world, block, pos); + int lm = (fo && !em) ? 0 : block.getMixedBrightnessForBlock(world, x, y, z); return packAO(ao) | packLM(lm) | packOP(op) | packFO(fo) | packFC(fc) | (1L << 60); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 697e5be3f..2df5aff27 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -138,7 +138,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB for (BlockRenderPass pass : BlockRenderPass.VALUES) { if (block.canRenderInPass(pass.ordinal())) { - if (cache.getFluidRenderer().render(slice, cache.getWorldSlice(), (IFluidBlock) block, pos, buffers.get(pass))) { + if (cache.getFluidRenderer().render(slice, cache.getWorldSlice(), block, pos, buffers.get(pass))) { bounds.addBlock(relX, relY, relZ); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java index 71661a784..c1de8dc24 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java @@ -3,29 +3,29 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; import com.gtnewhorizons.angelica.compat.mojang.VoxelShapes; +import me.jellysquid.mods.sodium.client.model.light.LightMode; +import me.jellysquid.mods.sodium.client.model.light.LightPipeline; +import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.ModelQuad; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.ModelQuadViewMutable; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; -import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadOrientation; import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; import me.jellysquid.mods.sodium.client.util.Norm3b; -import me.jellysquid.mods.sodium.client.util.WorldUtil; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.common.util.DirectionUtil; +import me.jellysquid.mods.sodium.common.util.WorldUtil; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.util.MathHelper; import net.minecraft.world.IBlockAccess; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.IFluidBlock; import org.joml.Vector3d; @@ -33,6 +33,7 @@ public class FluidRenderer { private static final float EPSILON = 0.001f; + private final LightPipelineProvider lpp; private final BlockPos.Mutable scratchPos = new BlockPos.Mutable(); @@ -41,17 +42,19 @@ public class FluidRenderer { private final QuadLightData quadLightData = new QuadLightData(); private final int[] quadColors = new int[4]; - public FluidRenderer(Minecraft client) { + public FluidRenderer(LightPipelineProvider lpp) { int normal = Norm3b.pack(0.0f, 1.0f, 0.0f); for (int i = 0; i < 4; i++) { this.quad.setNormal(i, normal); } + + this.lpp = lpp; } private boolean isFluidOccluded(IBlockAccess world, int x, int y, int z, ForgeDirection d, Fluid fluid) { Block block = world.getBlock(x, y, z); - boolean tmp = FluidRegistry.lookupFluidForBlock(world.getBlock(x + d.offsetX, y + d.offsetY, z + d.offsetZ)) == fluid; + boolean tmp = WorldUtil.getFluid(world.getBlock(x + d.offsetX, y + d.offsetY, z + d.offsetZ)) == fluid; if (block.getMaterial().isOpaque()) { return tmp || block.isSideSolid(world, x, y, z, d); @@ -84,13 +87,13 @@ private boolean isSideExposed(IBlockAccess world, int x, int y, int z, ForgeDire return true; } - public boolean render(IBlockAccess world, WorldSlice slice, IFluidBlock block, BlockPos pos, ChunkModelBuffers buffers) { + public boolean render(IBlockAccess world, WorldSlice slice, Block block, BlockPos pos, ChunkModelBuffers buffers) { int posX = pos.x; int posY = pos.y; int posZ = pos.z; - Fluid fluid = block.getFluid(); + Fluid fluid = ((IFluidBlock) block).getFluid(); // Check for occluded sides; if everything is occluded, don't render boolean sfUp = this.isFluidOccluded(world, posX, posY, posZ, ForgeDirection.UP, fluid); @@ -106,13 +109,13 @@ public boolean render(IBlockAccess world, WorldSlice slice, IFluidBlock block, B } // sprites[0] should be the still frames, [1] the flowing, [2] the overlay - // Sides 0 and 1 (top and bottom) are still, 2+ flowing. Overlay is null because I can't find it used anywhere + // Sides 0 and 1 (top and bottom) are still, 2+ flowing. Overlay is null because 1.7.10 probably doesn't use it. TextureAtlasSprite[] sprites = new TextureAtlasSprite[]{ - (TextureAtlasSprite) RenderBlocks.getInstance().getBlockIconFromSide(fluid.getBlock(), 1), - (TextureAtlasSprite) RenderBlocks.getInstance().getBlockIconFromSide(fluid.getBlock(), 2), + (TextureAtlasSprite) fluid.getStillIcon(), + (TextureAtlasSprite) fluid.getFlowingIcon(), null - };//ForgeHooksClientExt.getFluidSprites(world, pos, fluidState); - boolean hc = fluid.getColor() != 0xffffffff; //fluidState.getFluid().getAttributes().getColor() != 0xffffffff; + }; + boolean hc = fluid.getColor() != 0xffffffff; boolean rendered = false; @@ -125,6 +128,9 @@ public boolean render(IBlockAccess world, WorldSlice slice, IFluidBlock block, B final ModelQuadViewMutable quad = this.quad; + LightMode mode = hc && Minecraft.isAmbientOcclusionEnabled() ? LightMode.SMOOTH : LightMode.FLAT; + LightPipeline lighter = this.lpp.getLighter(mode); + quad.setFlags(0); if (!sfUp && this.isSideExposed(world, posX, posY, posZ, ForgeDirection.UP, Math.min(Math.min(h1, h2), Math.min(h3, h4)))) { @@ -133,7 +139,7 @@ public boolean render(IBlockAccess world, WorldSlice slice, IFluidBlock block, B h3 -= 0.001F; h4 -= 0.001F; - Vector3d velocity = WorldUtil.getVelocity(world, pos); + Vector3d velocity = WorldUtil.getVelocity(world, pos.x, pos.y, pos.z, block); TextureAtlasSprite sprite; ModelQuadFacing facing; @@ -189,7 +195,7 @@ public boolean render(IBlockAccess world, WorldSlice slice, IFluidBlock block, B this.setVertex(quad, 2, 1.0F, h3, 1.0F, u3, v3); this.setVertex(quad, 3, 1.0F, h4, 0.0f, u4, v4); - this.calculateQuadColors(quad, pos, ForgeDirection.UP, 1.0F, hc); + this.calculateQuadColors(quad, pos, lighter, ForgeDirection.UP, 1.0F, hc); this.flushQuad(buffers, quad, facing, false); if (WorldUtil.method_15756(slice, this.scratchPos.set(posX, posY + 1, posZ), fluid)) { @@ -218,7 +224,7 @@ public boolean render(IBlockAccess world, WorldSlice slice, IFluidBlock block, B this.setVertex(quad, 2, 1.0F, yOffset, 0.0f, maxU, minV); this.setVertex(quad, 3, 1.0F, yOffset, 1.0F, maxU, maxV); - this.calculateQuadColors(quad, pos, ForgeDirection.DOWN, 1.0F, hc); + this.calculateQuadColors(quad, pos, lighter, ForgeDirection.DOWN, 1.0F, hc); this.flushQuad(buffers, quad, ModelQuadFacing.DOWN, false); rendered = true; @@ -322,7 +328,7 @@ public boolean render(IBlockAccess world, WorldSlice slice, IFluidBlock block, B ModelQuadFacing facing = ModelQuadFacing.fromDirection(dir); - this.calculateQuadColors(quad, pos, dir, br, hc); + this.calculateQuadColors(quad, pos, lighter, dir, br, hc); this.flushQuad(buffers, quad, facing, false); if (sprite != oSprite) { @@ -341,8 +347,9 @@ public boolean render(IBlockAccess world, WorldSlice slice, IFluidBlock block, B return rendered; } - private void calculateQuadColors(ModelQuadView quad, BlockPos pos, ForgeDirection dir, float brightness, boolean colorized) { + private void calculateQuadColors(ModelQuadView quad, BlockPos pos, LightPipeline lighter, ForgeDirection dir, float brightness, boolean colorized) { QuadLightData light = this.quadLightData; + lighter.calculate(quad, pos, light, null, dir, false); int[] biomeColors = null; @@ -357,28 +364,34 @@ private void calculateQuadColors(ModelQuadView quad, BlockPos pos, ForgeDirecti private void flushQuad(ChunkModelBuffers buffers, ModelQuadView quad, ModelQuadFacing facing, boolean flip) { - ModelVertexSink sink = buffers.getSink(facing); - sink.ensureCapacity(4); + int vertexIdx, lightOrder; - //ChunkRenderData.Builder renderData = buffers.getRenderData(); + if (flip) { + vertexIdx = 3; + lightOrder = -1; + } else { + vertexIdx = 0; + lightOrder = 1; + } - ModelQuadOrientation order = flip ? ModelQuadOrientation.NORMAL : ModelQuadOrientation.FLIP; + ModelVertexSink sink = buffers.getSink(facing); + sink.ensureCapacity(4); - for (int dstIndex = 0; dstIndex < 4; dstIndex++) { - int srcIndex = order.getVertexIndex(dstIndex); + for (int i = 0; i < 4; i++) { + float x = quad.getX(i); + float y = quad.getY(i); + float z = quad.getZ(i); - float x = quad.getX(srcIndex); - float y = quad.getY(srcIndex); - float z = quad.getZ(srcIndex); + int color = this.quadColors[vertexIdx]; - int color = this.quadColors[srcIndex]; + float u = quad.getTexU(i); + float v = quad.getTexV(i); - float u = quad.getTexU(srcIndex); - float v = quad.getTexV(srcIndex); + int light = this.quadLightData.lm[vertexIdx]; - int lm = quad.getLight(srcIndex); + sink.writeQuad(x, y, z, color, u, v, light); - sink.writeQuad(x, y, z, color, u, v, lm); + vertexIdx += lightOrder; } TextureAtlasSprite sprite = quad.rubidium$getSprite(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java index c0ebef104..76bbab8c8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java @@ -1,6 +1,8 @@ package me.jellysquid.mods.sodium.client.render.pipeline.context; import com.gtnewhorizons.angelica.compat.mojang.BlockModels; +import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; +import me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache; import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; import me.jellysquid.mods.sodium.client.render.pipeline.FluidRenderer; @@ -10,6 +12,8 @@ import net.minecraft.client.multiplayer.WorldClient; public class ChunkRenderCacheLocal extends ChunkRenderCache { + private final ArrayLightDataCache lightDataCache; + private final BlockRenderer blockRenderer; private final FluidRenderer fluidRenderer; @@ -18,9 +22,12 @@ public class ChunkRenderCacheLocal extends ChunkRenderCache { public ChunkRenderCacheLocal(Minecraft client, WorldClient world) { this.worldSlice = new WorldSlice(world); + this.lightDataCache = new ArrayLightDataCache(this.worldSlice); + + LightPipelineProvider lpp = new LightPipelineProvider(lightDataCache); this.blockRenderer = new BlockRenderer(client); - this.fluidRenderer = new FluidRenderer(client); + this.fluidRenderer = new FluidRenderer(lpp); // TODO: Sodium this.blockModels = null; // client.getBakedModelManager().getBlockModels(); @@ -39,6 +46,7 @@ public FluidRenderer getFluidRenderer() { } public void init(ChunkRenderContext context) { + this.lightDataCache.reset(context.getOrigin()); this.worldSlice.copyData(context); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/WorldUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/WorldUtil.java deleted file mode 100644 index b56e9a21e..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/WorldUtil.java +++ /dev/null @@ -1,84 +0,0 @@ -package me.jellysquid.mods.sodium.client.util; - -import com.gtnewhorizons.angelica.compat.mojang.*; -import net.minecraft.block.Block; -import net.minecraft.block.BlockLiquid; -import net.minecraft.block.material.Material; -import net.minecraft.world.IBlockAccess; -import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidRegistry; -import org.joml.Vector3d; - -/** - * Contains methods stripped from BlockState or FluidState that didn't actually need to be there. Technically these - * could be a mixin to Block or Fluid, but that's annoying while not actually providing any benefit. - */ -public class WorldUtil { - - public static Vector3d getVelocity(IBlockAccess world, BlockPos pos) { - - Vector3d velocity = new Vector3d(); - ForgeDirection[] news = new ForgeDirection[]{ ForgeDirection.NORTH, ForgeDirection.EAST, ForgeDirection.WEST, ForgeDirection.SOUTH }; - BlockPos target = new BlockPos.Mutable(); - target.set(pos); - Fluid thisFluid = FluidRegistry.lookupFluidForBlock(world.getBlock(pos.x, pos.y, pos.z)); - int meta = world.getBlockMetadata(pos.x, pos.y, pos.z); - - // for each orthogonally adjacent fluid, add the height delta - for (ForgeDirection d : news) { - - target.add(d.offsetX, 0, d.offsetZ); - Fluid orthoFluid = FluidRegistry.lookupFluidForBlock(world.getBlock(pos.x, pos.y, pos.z)); - int orthoMeta = world.getBlockMetadata(pos.x, pos.y, pos.z); - double mult; - - // blocks always add 0.9, for some reason - if (orthoFluid == null) { - mult = 0.9; - } else { - - mult = WorldUtil.getFluidHeight(thisFluid, meta) - WorldUtil.getFluidHeight(orthoFluid, orthoMeta); - } - - velocity.add(d.offsetX * mult, 0, d.offsetZ * mult); - target.add(-d.offsetX, 0, -d.offsetZ); - } - - return velocity.normalize(); - } - - /** - * Returns true if any block in a 3x3x3 cube is not the same fluid and not an opaque full cube. - * Equivalent to FluidState::method_15756 in modern. - */ - public static boolean method_15756(IBlockAccess world, BlockPos pos, Fluid fluid) { - for (int i = 0; i < 2; ++i) { - for (int j = 0; j < 2; ++j) { - Block block = world.getBlock(pos.x, pos.y, pos.z); - if (!block.isOpaqueCube() && FluidRegistry.lookupFluidForBlock(block) != fluid) { - return true; - } - } - } - - return false; - } - - public static VoxelShape getCullingShape(Block block) { - return block.renderAsNormalBlock() ? VoxelShapes.fullCube() : VoxelShapes.empty(); - } - - /** - * Returns fluid height as a percentage of the block; 0 is none and 1 is full. - */ - public static float getFluidHeight(Fluid fluid, int meta) { - return fluid == null ? 0 : 1 - BlockLiquid.getLiquidHeightPercent(meta); - } - - // I believe forge mappings in modern say BreakableBlock, while yarn says TransparentBlock. - // I have a sneaking suspicion isOpaque is neither, but it works for now - public static boolean shouldDisplayFluidOverlay(Block block) { - return !block.getMaterial().isOpaque() || block.getMaterial() == Material.leaves; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index b13d0f74b..4fb82730b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -348,12 +348,12 @@ public static int getLocalChunkIndex(int x, int z) { // Modern checks if the sky is darkened, which only happens in the nether. However, I think 1.7.10's hasNoSky is // close enough and possibly a behavior change between versions. I also don't know why it's rotationally asymmetric public float getBrightness(ForgeDirection direction, boolean shaded) { - if (world.provider.hasNoSky) { - return shaded ? 0.9f : 1.0f; + if (!shaded) { + return world.provider.hasNoSky ? 0.9f : 1.0f; } return switch (direction) { - case DOWN -> shaded ? 0.9f : 0.5f; - case UP -> shaded ? 0.9f : 1.0f; + case DOWN -> world.provider.hasNoSky ? 0.9f : 0.5f; + case UP -> world.provider.hasNoSky ? 0.9f : 1.0f; case NORTH, SOUTH -> 0.8f; case WEST, EAST -> 0.6f; case UNKNOWN -> 1.0f; diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java b/src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java new file mode 100644 index 000000000..e3f553ea4 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java @@ -0,0 +1,146 @@ +package me.jellysquid.mods.sodium.common.util; + +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; +import com.gtnewhorizons.angelica.compat.mojang.VoxelShapes; +import net.minecraft.block.Block; +import net.minecraft.block.BlockLiquid; +import net.minecraft.block.material.Material; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.IFluidBlock; +import org.joml.Vector3d; + +/** + * Contains methods stripped from BlockState or FluidState that didn't actually need to be there. Technically these + * could be a mixin to Block or Fluid, but that's annoying while not actually providing any benefit. + */ +public class WorldUtil { + + public static Vector3d getVelocity(IBlockAccess world, int x, int y, int z, Block thizz) { + + Vector3d velocity = new Vector3d(); + int decay = getEffectiveFlowDecay(world, x, y, z, thizz); + + for (ForgeDirection dire : DirectionUtil.HORIZONTAL_DIRECTIONS) { + + int adjX = x + dire.offsetX; + int adjZ = z + dire.offsetZ; + + int adjDecay = getEffectiveFlowDecay(world, adjX, y, adjZ, thizz); + + if (adjDecay < 0) { + + if (!world.getBlock(adjX, y, adjZ).getMaterial().blocksMovement()) { + + adjDecay = getEffectiveFlowDecay(world, adjX, y - 1, adjZ, thizz); + + if (adjDecay >= 0) { + + adjDecay -= (decay - 8); + velocity = velocity.add((adjX - x) * adjDecay, 0, (adjZ - z) * adjDecay); + } + } + } else { + + adjDecay -= decay; + velocity = velocity.add((adjX - x) * adjDecay, 0, (adjZ - z) * adjDecay); + } + } + + if (world.getBlockMetadata(x, y, z) >= 8) { + + if (thizz.isBlockSolid(world, x, y, z - 1, 2) + || thizz.isBlockSolid(world, x, y, z + 1, 3) + || thizz.isBlockSolid(world, x - 1, y, z, 4) + || thizz.isBlockSolid(world, x + 1, y, z, 5) + || thizz.isBlockSolid(world, x, y + 1, z - 1, 2) + || thizz.isBlockSolid(world, x, y + 1, z + 1, 3) + || thizz.isBlockSolid(world, x - 1, y + 1, z, 4) + || thizz.isBlockSolid(world, x + 1, y + 1, z, 5)) { + velocity = velocity.normalize().add(0.0D, -6.0D, 0.0D); + } + } + + if (velocity.x == 0 && velocity.y == 0 && velocity.z == 0) + return velocity.zero(); + return velocity.normalize(); + } + + /** + * Returns true if any block in a 3x3x3 cube is not the same fluid and not an opaque full cube. + * Equivalent to FluidState::method_15756 in modern. + */ + public static boolean method_15756(IBlockAccess world, BlockPos pos, Fluid fluid) { + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) { + Block block = world.getBlock(pos.x, pos.y, pos.z); + if (!block.isOpaqueCube() && getFluid(block) != fluid) { + return true; + } + } + } + + return false; + } + + public static VoxelShape getCullingShape(Block block) { + return block.renderAsNormalBlock() ? VoxelShapes.fullCube() : VoxelShapes.empty(); + } + + /** + * Returns fluid height as a percentage of the block; 0 is none and 1 is full. + */ + public static float getFluidHeight(Fluid fluid, int meta) { + return fluid == null ? 0 : 1 - BlockLiquid.getLiquidHeightPercent(meta); + } + + /** + * Returns the flow decay but converts values indicating falling liquid (values >=8) to their effective source block + * value of zero + */ + public static int getEffectiveFlowDecay(IBlockAccess world, int x, int y, int z, Block thiz) { + + if (world.getBlock(x, y, z).getMaterial() != thiz.getMaterial()) { + + return -1; + } else { + + int decay = world.getBlockMetadata(x, y, z); + return decay >= 8 ? 0 : decay; + } + } + + // I believe forge mappings in modern say BreakableBlock, while yarn says TransparentBlock. + // I have a sneaking suspicion isOpaque is neither, but it works for now + public static boolean shouldDisplayFluidOverlay(Block block) { + return !block.getMaterial().isOpaque() || block.getMaterial() == Material.leaves; + } + + public static Fluid getFluid(Block b) { + return b instanceof IFluidBlock ? ((IFluidBlock) b).getFluid() : null; + } + + /** + * Equivalent to method_15748 in 1.16.5 + */ + public static boolean isEmptyOrSame(Fluid fluid, Fluid otherFluid) { + return otherFluid == null || fluid == otherFluid; + } + + /** + * Equivalent to method_15749 in 1.16.5 + */ + public static boolean method_15749(IBlockAccess world, Fluid thiz, BlockPos pos, ForgeDirection dir) { + Block b = world.getBlock(pos.x, pos.y, pos.z); + Fluid f = getFluid(b); + if (f == thiz) { + return false; + } + if (dir == ForgeDirection.UP) { + return true; + } + return b.getMaterial() != Material.ice && b.isSideSolid(world, pos.x, pos.y, pos.z, dir); + } +} From 33052562463f351ee5a5d87bd2c0e872e4c16eff Mon Sep 17 00:00:00 2001 From: makamys Date: Sun, 26 Nov 2023 22:05:17 +0100 Subject: [PATCH 151/301] Fix face culling not taking third person camera offset into account --- .../angelica/compat/mojang/Camera.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java index 497168006..5287aaca7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java @@ -3,7 +3,12 @@ import lombok.Getter; import net.minecraft.client.Minecraft; import net.minecraft.entity.EntityLivingBase; + +import org.joml.Matrix4f; import org.joml.Vector3d; +import org.joml.Vector4f; + +import com.gtnewhorizons.angelica.rendering.RenderingState; @Getter public class Camera { @@ -15,10 +20,15 @@ public class Camera { boolean thirdPerson; public Camera(EntityLivingBase entity, float partialTicks) { - final double camX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks; - final double camY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks; - final double camZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks; + 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; + pos.set(camX, camY, camZ); blockPos.set((int)entity.posX, (int)entity.posY, (int)entity.posZ); pitch = entity.cameraPitch; From 46574edb67f504e6f006da5c19e092ebeaa22d70 Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Mon, 27 Nov 2023 00:56:55 +0100 Subject: [PATCH 152/301] rewrite ACTEntityRenderer to stop transforming ALL the classes --- .../angelica/transform/ACTEntityRenderer.java | 94 +++++++------------ 1 file changed, 33 insertions(+), 61 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java index 18f5509ab..678ae799c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java @@ -1,78 +1,50 @@ package com.gtnewhorizons.angelica.transform; +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.launchwrapper.IClassTransformer; - import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; - -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import org.objectweb.asm.tree.*; /** Transformer for {@link EntityRenderer} */ -public class ACTEntityRenderer implements IClassTransformer { +public class ACTEntityRenderer implements IClassTransformer, Opcodes { @Override public byte[] transform(String name, String transformedName, byte[] basicClass) { - AngelicaTweaker.LOGGER.debug("transforming {} {}", name, transformedName); - ClassReader cr = new ClassReader(basicClass); - ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); - CVTransform cv = new CVTransform(cw); - cr.accept(cv, 0); - return cw.toByteArray(); - } - - private static class CVTransform extends ClassVisitor { - - private String classname; - - public CVTransform(ClassVisitor cv) { - super(Opcodes.ASM4, cv); - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - classname = name; - cv.visit(version, access, name, signature, superName, interfaces); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - if (Names.entityRenderer_renderHand.equalsNameDesc(name, desc)) { - AngelicaTweaker.LOGGER.trace(" patching method {}.{}{}", classname, name, desc); - return new MVrenderHand(cv.visitMethod(access, name, desc, signature, exceptions)); + if ("net.minecraft.client.renderer.EntityRenderer".equals(transformedName)) { + AngelicaTweaker.LOGGER.debug("transforming {} {}", name, transformedName); + ClassReader cr = new ClassReader(basicClass); + ClassNode cn = new ClassNode(); + cr.accept(cn, 0); + for (MethodNode mn : cn.methods) { + if (Names.entityRenderer_renderHand.equalsNameDesc(mn.name, mn.desc)) { + // Wraps the code from GL11.glPushMatrix() to GL11.glPopMatrix() in an if(!Shaders.isHandRendered) check + AngelicaTweaker.LOGGER.trace(" patching method {}.{}{}", transformedName, mn.name, mn.desc); + LabelNode label = new LabelNode(); + for (AbstractInsnNode node : mn.instructions.toArray()) { + if (node instanceof MethodInsnNode mNode) { + if (Names.equals(mNode, "org/lwjgl/opengl/GL11", "glPushMatrix", "()V")) { + InsnList list = new InsnList(); + list.add(new FieldInsnNode(GETSTATIC, "com/gtnewhorizons/angelica/client/Shaders", "isHandRendered", "Z")); + list.add(new JumpInsnNode(IFNE, label)); + mn.instructions.insertBefore(node, list); + } else if (Names.equals(mNode, "org/lwjgl/opengl/GL11", "glPopMatrix", "()V")) { + InsnList list = new InsnList(); + list.add(label); + list.add(new FrameNode(F_SAME, 0, null, 0, null)); + mn.instructions.insert(node, list); + } + } + } + } } - return cv.visitMethod(access, name, desc, signature, exceptions); + ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); + cn.accept(cw); + return cw.toByteArray(); } + return basicClass; } - private static class MVrenderHand extends MethodVisitor { - - private Label label; - - public MVrenderHand(MethodVisitor mv) { - super(Opcodes.ASM4, mv); - label = new Label(); - } - - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { - // Wraps the code from GL11.glPushMatrix() to GL11.glPopMatrix() in an if(!Shaders.isHandRendered) check - if (Names.equals("org/lwjgl/opengl/GL11", "glPushMatrix", "()V", owner, name, desc)) { - mv.visitFieldInsn(Opcodes.GETSTATIC, "com/gtnewhorizons/angelica/client/Shaders", "isHandRendered", "Z"); - mv.visitJumpInsn(Opcodes.IFNE, label); - mv.visitMethodInsn(opcode, owner, name, desc); - return; - } else if (Names.equals("org/lwjgl/opengl/GL11", "glPopMatrix", "()V", owner, name, desc)) { - mv.visitMethodInsn(opcode, owner, name, desc); - mv.visitLabel(label); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - return; - } - mv.visitMethodInsn(opcode, owner, name, desc); - } - } } From 6400bf855cbb99b9dc600ec710a6d1c4c459d73f Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Mon, 27 Nov 2023 00:57:06 +0100 Subject: [PATCH 153/301] rewrite ACTEntityRenderer to stop transforming ALL the classes - forgot file --- .../java/com/gtnewhorizons/angelica/transform/Names.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/Names.java b/src/main/java/com/gtnewhorizons/angelica/transform/Names.java index 16e0cbda3..4ff1492f4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/Names.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/Names.java @@ -1,5 +1,7 @@ package com.gtnewhorizons.angelica.transform; +import org.objectweb.asm.tree.MethodInsnNode; + public class Names { public static class Name { @@ -81,4 +83,8 @@ public boolean equalsNameDesc(String name, String desc) { public static boolean equals(String clas1, String name1, String desc1, String clas2, String name2, String desc2) { return clas1.equals(clas2) && name1.equals(name2) && desc1.equals(desc2); } + + public static boolean equals(MethodInsnNode node, String owner, String name, String desc) { + return node.owner.equals(owner) && node.name.equals(name) && node.desc.equals(desc); + } } From 45e61357db7c3c616671233b829fb28bb0275942 Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Mon, 27 Nov 2023 01:28:20 +0100 Subject: [PATCH 154/301] use ClassConstantPoolParser in TessellatorTransformer to speed up search for Tessellator references --- .../transform/ClassConstantPoolParser.java | 123 ++++++++++++++++++ .../transform/TessellatorTransformer.java | 35 +++-- 2 files changed, 145 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/ClassConstantPoolParser.java diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/ClassConstantPoolParser.java b/src/main/java/com/gtnewhorizons/angelica/transform/ClassConstantPoolParser.java new file mode 100644 index 000000000..b74a90512 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/transform/ClassConstantPoolParser.java @@ -0,0 +1,123 @@ +/*** + * This Class is derived from the ASM ClassReader + *

+ * ASM: a very small and fast Java bytecode manipulation framework Copyright (c) 2000-2011 INRIA, France Telecom All + * rights reserved. + *

+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other materials provided with the + * distribution. 3. Neither the name of the copyright holders nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + *

+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.gtnewhorizons.angelica.transform; + +import org.objectweb.asm.Opcodes; + +import java.nio.charset.StandardCharsets; + +/** + * Using this class to search for a (single) String reference is > 40 times faster than parsing a class with a ClassReader + + * ClassNode while using way less RAM + */ +public class ClassConstantPoolParser { + + private static final int UTF8 = 1; + private static final int INT = 3; + private static final int FLOAT = 4; + private static final int LONG = 5; + private static final int DOUBLE = 6; + private static final int FIELD = 9; + private static final int METH = 10; + private static final int IMETH = 11; + private static final int NAME_TYPE = 12; + private static final int HANDLE = 15; + private static final int INDY = 18; + + private final byte[][] BYTES_TO_SEARCH; + + public ClassConstantPoolParser(String... strings) { + BYTES_TO_SEARCH = new byte[strings.length][]; + for (int i = 0; i < BYTES_TO_SEARCH.length; i++) { + BYTES_TO_SEARCH[i] = strings[i].getBytes(StandardCharsets.UTF_8); + } + } + + /** + * Returns true if the constant pool of the class represented by this byte array contains one of the Strings we are looking + * for + */ + public boolean find(byte[] basicClass) { + if (basicClass == null || basicClass.length == 0) { + return false; + } + // checks the class version + if (readShort(6, basicClass) > Opcodes.V1_8) { + return false; + } + // parses the constant pool + int n = readUnsignedShort(8, basicClass); + int index = 10; + for (int i = 1; i < n; ++i) { + int size; + switch (basicClass[index]) { + case FIELD: + case METH: + case IMETH: + case INT: + case FLOAT: + case NAME_TYPE: + case INDY: + size = 5; + break; + case LONG: + case DOUBLE: + size = 9; + ++i; + break; + case UTF8: + final int strLen = readUnsignedShort(index + 1, basicClass); + size = 3 + strLen; + label: + for (byte[] bytes : BYTES_TO_SEARCH) { + if (strLen == bytes.length) { + for (int j = index + 3; j < index + 3 + strLen; j++) { + if (basicClass[j] != bytes[j - (index + 3)]) { + break label; + } + } + return true; + } + } + break; + case HANDLE: + size = 4; + break; + default: + size = 3; + break; + } + index += size; + } + return false; + } + + private static short readShort(final int index, byte[] basicClass) { + return (short) (((basicClass[index] & 0xFF) << 8) | (basicClass[index + 1] & 0xFF)); + } + + private static int readUnsignedShort(final int index, byte[] basicClass) { + return ((basicClass[index] & 0xFF) << 8) | (basicClass[index + 1] & 0xFF); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java index 732e3076a..cbe2a8da7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java @@ -1,13 +1,18 @@ package com.gtnewhorizons.angelica.transform; import net.minecraft.launchwrapper.IClassTransformer; -import org.spongepowered.asm.lib.*; +import org.spongepowered.asm.lib.ClassReader; +import org.spongepowered.asm.lib.ClassWriter; +import org.spongepowered.asm.lib.Opcodes; import org.spongepowered.asm.lib.tree.*; /** - * Redirects all Tessellator.instance accesses to go through our TessellatorManager. + * Redirects all Tessellator.instance field accesses to go through our TessellatorManager. */ public class TessellatorTransformer implements IClassTransformer { + + private static final ClassConstantPoolParser parser = new ClassConstantPoolParser("net/minecraft/client/renderer/Tessellator"); + @Override public byte[] transform(final String className, String transformedName, byte[] basicClass) { if (basicClass == null) return null; @@ -19,29 +24,33 @@ public byte[] transform(final String className, String transformedName, byte[] b } } + if (!parser.find(basicClass)) { + return basicClass; + } + final ClassReader reader = new ClassReader(basicClass); ClassNode node = new ClassNode(); reader.accept(node, Opcodes.ASM9); boolean changed = false; - for(MethodNode m : node.methods) { - for(AbstractInsnNode insn : m.instructions) { - if(insn.getOpcode() == Opcodes.GETSTATIC) { - FieldInsnNode fNode = (FieldInsnNode)insn; - if((fNode.name.equals("field_78398_a") || fNode.name.equals("instance")) && fNode.owner.equals("net/minecraft/client/renderer/Tessellator")) { + for (MethodNode m : node.methods) { + for (AbstractInsnNode insn : m.instructions) { + if (insn.getOpcode() == Opcodes.GETSTATIC) { + FieldInsnNode fNode = (FieldInsnNode) insn; + if ((fNode.name.equals("field_78398_a") || fNode.name.equals("instance")) && fNode.owner.equals("net/minecraft/client/renderer/Tessellator")) { MethodInsnNode getNode = new MethodInsnNode(Opcodes.INVOKESTATIC, "com/gtnewhorizons/angelica/glsm/TessellatorManager", "get", "()Lnet/minecraft/client/renderer/Tessellator;", false); m.instructions.set(fNode, getNode); changed = true; - break; } } } } - if(!changed) - return basicClass; + if (changed) { + ClassWriter writer = new ClassWriter(reader, 0); + node.accept(writer); + return writer.toByteArray(); + } + return basicClass; - ClassWriter writer = new ClassWriter(reader, 0); - node.accept(writer); - return writer.toByteArray(); } } From a3b1661bbe00efd3b71566ac31a8ef4dfad24a9e Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Mon, 27 Nov 2023 01:29:09 +0100 Subject: [PATCH 155/301] use ClassConstantPoolParser in GLStateManagerTransformer to speed up search for class references --- .../transform/GLStateManagerTransformer.java | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index 66345c339..d73d536f5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -12,7 +12,6 @@ import org.spongepowered.asm.lib.Opcodes; import org.spongepowered.asm.lib.commons.Method; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -24,27 +23,31 @@ public class GLStateManagerTransformer implements IClassTransformer { * Redirects a subset of GL11 calls to GLStateManager * NOTE: Still need to verify compatibility with Mixins and Lwjgl3ify */ - public static final boolean ASSERT_MAIN_THREAD = Boolean.parseBoolean(System.getProperty("angelica.assertMainThread", "false")); - public static final String GLStateTracker = "com/gtnewhorizons/angelica/glsm/GLStateManager"; + private static final boolean ASSERT_MAIN_THREAD = Boolean.parseBoolean(System.getProperty("angelica.assertMainThread", "false")); + private static final String GLStateTracker = "com/gtnewhorizons/angelica/glsm/GLStateManager"; private static final String GL11 = "org/lwjgl/opengl/GL11"; private static final String GL13 = "org/lwjgl/opengl/GL13"; private static final String GL14 = "org/lwjgl/opengl/GL14"; private static final String EXTBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate"; private static final String ARBMultiTexture = "org/lwjgl/opengl/ARBMultitexture"; - public static final Map> EnabledRedirects = ImmutableMap.of( - GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", + private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, EXTBlendFunc, ARBMultiTexture); + + private static final Map> EnabledRedirects = ImmutableMap.of( + GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor3f", "glColor4f", "glShadeModel", "glFog", "glFogi", "glFogf", "glClearColor") - ,GL13, Sets.newHashSet("glActiveTexture") - ,GL14, Sets.newHashSet("glBlendFuncSeparate") - ,EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") - ,ARBMultiTexture, Sets.newHashSet("glActiveTextureARB") + , GL13, Sets.newHashSet("glActiveTexture") + , GL14, Sets.newHashSet("glBlendFuncSeparate") + , EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") + , ARBMultiTexture, Sets.newHashSet("glActiveTextureARB") ); - - public static final List TransformerExclusions = new ArrayList<>(Arrays.asList( - "org.lwjgl", "com.gtnewhorizons.angelica.glsm.", "com.gtnewhorizons.angelica.transform", "me.eigenraven.lwjgl3ify", - "cpw.mods.fml.client.SplashProgress") + public static final List TransformerExclusions = Arrays.asList( + "org.lwjgl", + "com.gtnewhorizons.angelica.glsm.", + "com.gtnewhorizons.angelica.transform", + "me.eigenraven.lwjgl3ify", + "cpw.mods.fml.client.SplashProgress" ); public static int remaps = 0, calls = 0; public static Method lastMethod = null; @@ -53,7 +56,6 @@ public class GLStateManagerTransformer implements IClassTransformer { public byte[] transform(final String className, String transformedName, byte[] basicClass) { if (basicClass == null) return null; - // Ignore classes that are excluded from transformation - Doesn't fully work without the // TransformerExclusions due to some nested classes for (String exclusion : TransformerExclusions) { @@ -62,6 +64,10 @@ public byte[] transform(final String className, String transformedName, byte[] b } } + if (!cstPoolParser.find(basicClass)) { + return basicClass; + } + final ClassReader reader = new ClassReader(basicClass); Set eligibleMethods = findEligibleMethods(reader); if (eligibleMethods.isEmpty()) { @@ -83,12 +89,12 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { final Set redirects = EnabledRedirects.get(owner); if (redirects != null && redirects.contains(name)) { - if(IrisLogging.ENABLE_SPAM) { + if (IrisLogging.ENABLE_SPAM) { final String shortOwner = owner.substring(owner.lastIndexOf("/") + 1); AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", className, shortOwner, name, desc, name, desc); } - if(ASSERT_MAIN_THREAD && !method.equals(lastMethod)) { + if (ASSERT_MAIN_THREAD && !method.equals(lastMethod)) { super.visitMethodInsn(Opcodes.INVOKESTATIC, GLStateTracker, "assertMainThread", "()V", false); } owner = GLStateTracker; @@ -103,7 +109,6 @@ public void visitMethodInsn(int opcode, String owner, String name, String desc, return writer.toByteArray(); } - private Set findEligibleMethods(ClassReader reader) { Set eligibleMethods = new HashSet<>(); reader.accept(new ClassVisitor(Opcodes.ASM9) { @@ -113,7 +118,7 @@ public MethodVisitor visitMethod(int access, String methodName, String methodDes @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { final Set redirects = EnabledRedirects.get(owner); - if(redirects != null && redirects.contains(name)) { + if (redirects != null && redirects.contains(name)) { eligibleMethods.add(new Method(methodName, methodDesc)); } } From 4ebc230af716d0c106eca58ed947c9e8b4e11736 Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Mon, 27 Nov 2023 02:28:32 +0100 Subject: [PATCH 156/301] rewrite GLStateManagerTransformer and TessellatorTransformer --- .../transform/GLStateManagerTransformer.java | 90 +++++++------------ .../transform/TessellatorTransformer.java | 22 ++--- 2 files changed, 43 insertions(+), 69 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java index d73d536f5..c21599e4c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java @@ -6,14 +6,14 @@ import net.coderbot.iris.IrisLogging; import net.minecraft.launchwrapper.IClassTransformer; import org.spongepowered.asm.lib.ClassReader; -import org.spongepowered.asm.lib.ClassVisitor; import org.spongepowered.asm.lib.ClassWriter; -import org.spongepowered.asm.lib.MethodVisitor; import org.spongepowered.asm.lib.Opcodes; -import org.spongepowered.asm.lib.commons.Method; +import org.spongepowered.asm.lib.tree.AbstractInsnNode; +import org.spongepowered.asm.lib.tree.ClassNode; +import org.spongepowered.asm.lib.tree.MethodInsnNode; +import org.spongepowered.asm.lib.tree.MethodNode; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -50,7 +50,6 @@ public class GLStateManagerTransformer implements IClassTransformer { "cpw.mods.fml.client.SplashProgress" ); public static int remaps = 0, calls = 0; - public static Method lastMethod = null; @Override public byte[] transform(final String className, String transformedName, byte[] basicClass) { @@ -68,64 +67,39 @@ public byte[] transform(final String className, String transformedName, byte[] b return basicClass; } - final ClassReader reader = new ClassReader(basicClass); - Set eligibleMethods = findEligibleMethods(reader); - if (eligibleMethods.isEmpty()) { - return basicClass; - } - - ClassWriter writer = new ClassWriter(reader, 0); - reader.accept(new ClassVisitor(Opcodes.ASM9, writer) { - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); - final Method method = new Method(name, desc); - if (!eligibleMethods.contains(method)) { - return mv; - } + final ClassReader cr = new ClassReader(basicClass); + final ClassNode cn = new ClassNode(); + cr.accept(cn, 0); - return new MethodVisitor(Opcodes.ASM9, mv) { - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { - final Set redirects = EnabledRedirects.get(owner); - if (redirects != null && redirects.contains(name)) { - if (IrisLogging.ENABLE_SPAM) { - final String shortOwner = owner.substring(owner.lastIndexOf("/") + 1); - AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", className, shortOwner, name, desc, name, desc); - } - - if (ASSERT_MAIN_THREAD && !method.equals(lastMethod)) { - super.visitMethodInsn(Opcodes.INVOKESTATIC, GLStateTracker, "assertMainThread", "()V", false); - } - owner = GLStateTracker; - lastMethod = method; - remaps++; + boolean changed = false; + for (MethodNode mn : cn.methods) { + boolean redirectInMethod = false; + for (AbstractInsnNode node : mn.instructions.toArray()) { + if (node instanceof MethodInsnNode mNode) { + final Set redirects = EnabledRedirects.get(mNode.owner); + if (redirects != null && redirects.contains(mNode.name)) { + if (IrisLogging.ENABLE_SPAM) { + final String shortOwner = mNode.owner.substring(mNode.owner.lastIndexOf("/") + 1); + AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", className, shortOwner, mNode.name, mNode.desc, mNode.name, mNode.desc); } - super.visitMethodInsn(opcode, owner, name, desc, itf); + ((MethodInsnNode) node).owner = GLStateTracker; + changed = true; + redirectInMethod = true; + remaps++; } - }; + } } - }, 0); - return writer.toByteArray(); - } - - private Set findEligibleMethods(ClassReader reader) { - Set eligibleMethods = new HashSet<>(); - reader.accept(new ClassVisitor(Opcodes.ASM9) { - @Override - public MethodVisitor visitMethod(int access, String methodName, String methodDesc, String signature, String[] exceptions) { - return new MethodVisitor(Opcodes.ASM9) { - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { - final Set redirects = EnabledRedirects.get(owner); - if (redirects != null && redirects.contains(name)) { - eligibleMethods.add(new Method(methodName, methodDesc)); - } - } - }; + if (ASSERT_MAIN_THREAD && redirectInMethod) { + mn.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, GLStateTracker, "assertMainThread", "()V", false)); } - }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - return eligibleMethods; + } + + if (changed) { + ClassWriter cw = new ClassWriter(0); + cn.accept(cw); + return cw.toByteArray(); + } + return basicClass; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java index cbe2a8da7..2ea268a91 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java @@ -28,17 +28,17 @@ public byte[] transform(final String className, String transformedName, byte[] b return basicClass; } - final ClassReader reader = new ClassReader(basicClass); - ClassNode node = new ClassNode(); - reader.accept(node, Opcodes.ASM9); + final ClassReader cr = new ClassReader(basicClass); + ClassNode cn = new ClassNode(); + cr.accept(cn, 0); boolean changed = false; - for (MethodNode m : node.methods) { - for (AbstractInsnNode insn : m.instructions) { - if (insn.getOpcode() == Opcodes.GETSTATIC) { - FieldInsnNode fNode = (FieldInsnNode) insn; + + for (MethodNode mn : cn.methods) { + for (AbstractInsnNode node : mn.instructions) { + if (node.getOpcode() == Opcodes.GETSTATIC && node instanceof FieldInsnNode fNode) { if ((fNode.name.equals("field_78398_a") || fNode.name.equals("instance")) && fNode.owner.equals("net/minecraft/client/renderer/Tessellator")) { MethodInsnNode getNode = new MethodInsnNode(Opcodes.INVOKESTATIC, "com/gtnewhorizons/angelica/glsm/TessellatorManager", "get", "()Lnet/minecraft/client/renderer/Tessellator;", false); - m.instructions.set(fNode, getNode); + mn.instructions.set(fNode, getNode); changed = true; } } @@ -46,9 +46,9 @@ public byte[] transform(final String className, String transformedName, byte[] b } if (changed) { - ClassWriter writer = new ClassWriter(reader, 0); - node.accept(writer); - return writer.toByteArray(); + ClassWriter cw = new ClassWriter(0); + cn.accept(cw); + return cw.toByteArray(); } return basicClass; From 34edbd26c6b20a4dbb37ab3438e999e16f1be1ad Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Mon, 27 Nov 2023 02:41:56 +0100 Subject: [PATCH 157/301] merge GLStateManagerTransfor and TessellatorTransformer into one Transformer --- .../angelica/loading/AngelicaTweaker.java | 2 +- .../loading/MixinCompatHackTweaker.java | 8 +-- ...former.java => RedirectorTransformer.java} | 34 ++++++----- .../transform/TessellatorTransformer.java | 56 ------------------- 4 files changed, 25 insertions(+), 75 deletions(-) rename src/main/java/com/gtnewhorizons/angelica/transform/{GLStateManagerTransformer.java => RedirectorTransformer.java} (73%) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index 77920cf20..b56356876 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -26,7 +26,7 @@ import java.util.Set; @IFMLLoadingPlugin.MCVersion("1.7.10") -@IFMLLoadingPlugin.TransformerExclusions("com.gtnewhorizons.angelica.transform.GLStateManagerTransformer") +@IFMLLoadingPlugin.TransformerExclusions("com.gtnewhorizons.angelica.transform.RedirectorTransformer") @IFMLLoadingPlugin.SortingIndex(Integer.MAX_VALUE - 5) public class AngelicaTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader { diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java index 9d59aa1b4..8c2d828e5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java @@ -1,8 +1,7 @@ package com.gtnewhorizons.angelica.loading; import com.gtnewhorizons.angelica.transform.AClassTransformer; -import com.gtnewhorizons.angelica.transform.GLStateManagerTransformer; -import com.gtnewhorizons.angelica.transform.TessellatorTransformer; +import com.gtnewhorizons.angelica.transform.RedirectorTransformer; import cpw.mods.fml.common.asm.transformers.TerminalTransformer; import net.minecraft.launchwrapper.IClassTransformer; import net.minecraft.launchwrapper.ITweaker; @@ -36,7 +35,7 @@ public void acceptOptions(List args, File gameDir, File assetsDir, Strin AngelicaTweaker.LOGGER.info("LwjglRedirectTransformer found, injecting before it"); terminalIndex -= 2; - } catch(Exception ignored) { + } catch (Exception ignored) { AngelicaTweaker.LOGGER.info("LwjglRedirectTransformer not found, injecting near the end"); terminalIndex -= 1; } @@ -61,8 +60,7 @@ public String getLaunchTarget() { @Override public String[] getLaunchArguments() { // Run after Mixins, but hopefully before LWJGl3ify - Launch.classLoader.registerTransformer(GLStateManagerTransformer.class.getName()); - Launch.classLoader.registerTransformer(TessellatorTransformer.class.getName()); + Launch.classLoader.registerTransformer(RedirectorTransformer.class.getName()); return new String[0]; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java similarity index 73% rename from src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java rename to src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index c21599e4c..59ca5ccd8 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/GLStateManagerTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -8,21 +8,20 @@ import org.spongepowered.asm.lib.ClassReader; import org.spongepowered.asm.lib.ClassWriter; import org.spongepowered.asm.lib.Opcodes; -import org.spongepowered.asm.lib.tree.AbstractInsnNode; -import org.spongepowered.asm.lib.tree.ClassNode; -import org.spongepowered.asm.lib.tree.MethodInsnNode; -import org.spongepowered.asm.lib.tree.MethodNode; +import org.spongepowered.asm.lib.tree.*; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; -public class GLStateManagerTransformer implements IClassTransformer { - /* - * Redirects a subset of GL11 calls to GLStateManager - * NOTE: Still need to verify compatibility with Mixins and Lwjgl3ify - */ +/** + * This transformer redirects all Tessellator.instance field accesses to go through our TessellatorManager. + * As well as redirect some GL calls to our custom GLStateManager + * NOTE: Still need to verify compatibility with Mixins and Lwjgl3ify + */ +public class RedirectorTransformer implements IClassTransformer { + private static final boolean ASSERT_MAIN_THREAD = Boolean.parseBoolean(System.getProperty("angelica.assertMainThread", "false")); private static final String GLStateTracker = "com/gtnewhorizons/angelica/glsm/GLStateManager"; private static final String GL11 = "org/lwjgl/opengl/GL11"; @@ -30,8 +29,9 @@ public class GLStateManagerTransformer implements IClassTransformer { private static final String GL14 = "org/lwjgl/opengl/GL14"; private static final String EXTBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate"; private static final String ARBMultiTexture = "org/lwjgl/opengl/ARBMultitexture"; + private static final String tessellatorClass = "net/minecraft/client/renderer/Tessellator"; - private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, EXTBlendFunc, ARBMultiTexture); + private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, EXTBlendFunc, ARBMultiTexture, tessellatorClass); private static final Map> EnabledRedirects = ImmutableMap.of( GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", @@ -42,14 +42,14 @@ public class GLStateManagerTransformer implements IClassTransformer { , ARBMultiTexture, Sets.newHashSet("glActiveTextureARB") ); - public static final List TransformerExclusions = Arrays.asList( + private static final List TransformerExclusions = Arrays.asList( "org.lwjgl", "com.gtnewhorizons.angelica.glsm.", "com.gtnewhorizons.angelica.transform", "me.eigenraven.lwjgl3ify", "cpw.mods.fml.client.SplashProgress" ); - public static int remaps = 0, calls = 0; + private static int remaps = 0; @Override public byte[] transform(final String className, String transformedName, byte[] basicClass) { @@ -80,13 +80,21 @@ public byte[] transform(final String className, String transformedName, byte[] b if (redirects != null && redirects.contains(mNode.name)) { if (IrisLogging.ENABLE_SPAM) { final String shortOwner = mNode.owner.substring(mNode.owner.lastIndexOf("/") + 1); - AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", className, shortOwner, mNode.name, mNode.desc, mNode.name, mNode.desc); + AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", transformedName, shortOwner, mNode.name, mNode.desc, mNode.name, mNode.desc); } ((MethodInsnNode) node).owner = GLStateTracker; changed = true; redirectInMethod = true; remaps++; } + } else if (node.getOpcode() == Opcodes.GETSTATIC && node instanceof FieldInsnNode fNode) { + if ((fNode.name.equals("field_78398_a") || fNode.name.equals("instance")) && fNode.owner.equals("net/minecraft/client/renderer/Tessellator")) { + if (IrisLogging.ENABLE_SPAM) { + AngelicaTweaker.LOGGER.info("Redirecting Tessellator.instance field in {} to TessellatorManager.get()", transformedName); + } + mn.instructions.set(node, new MethodInsnNode(Opcodes.INVOKESTATIC, "com/gtnewhorizons/angelica/glsm/TessellatorManager", "get", "()Lnet/minecraft/client/renderer/Tessellator;", false)); + changed = true; + } } } if (ASSERT_MAIN_THREAD && redirectInMethod) { diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java deleted file mode 100644 index 2ea268a91..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/TessellatorTransformer.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -import net.minecraft.launchwrapper.IClassTransformer; -import org.spongepowered.asm.lib.ClassReader; -import org.spongepowered.asm.lib.ClassWriter; -import org.spongepowered.asm.lib.Opcodes; -import org.spongepowered.asm.lib.tree.*; - -/** - * Redirects all Tessellator.instance field accesses to go through our TessellatorManager. - */ -public class TessellatorTransformer implements IClassTransformer { - - private static final ClassConstantPoolParser parser = new ClassConstantPoolParser("net/minecraft/client/renderer/Tessellator"); - - @Override - public byte[] transform(final String className, String transformedName, byte[] basicClass) { - if (basicClass == null) return null; - - // Ignore classes that are excluded from transformation - for (String exclusion : GLStateManagerTransformer.TransformerExclusions) { - if (className.startsWith(exclusion)) { - return basicClass; - } - } - - if (!parser.find(basicClass)) { - return basicClass; - } - - final ClassReader cr = new ClassReader(basicClass); - ClassNode cn = new ClassNode(); - cr.accept(cn, 0); - boolean changed = false; - - for (MethodNode mn : cn.methods) { - for (AbstractInsnNode node : mn.instructions) { - if (node.getOpcode() == Opcodes.GETSTATIC && node instanceof FieldInsnNode fNode) { - if ((fNode.name.equals("field_78398_a") || fNode.name.equals("instance")) && fNode.owner.equals("net/minecraft/client/renderer/Tessellator")) { - MethodInsnNode getNode = new MethodInsnNode(Opcodes.INVOKESTATIC, "com/gtnewhorizons/angelica/glsm/TessellatorManager", "get", "()Lnet/minecraft/client/renderer/Tessellator;", false); - mn.instructions.set(fNode, getNode); - changed = true; - } - } - } - } - - if (changed) { - ClassWriter cw = new ClassWriter(0); - cn.accept(cw); - return cw.toByteArray(); - } - return basicClass; - - } -} From bc9c741f68ea519a9415c4c46a4381a6ed7ab47d Mon Sep 17 00:00:00 2001 From: rjnasers Date: Sun, 26 Nov 2023 23:25:47 -0600 Subject: [PATCH 158/301] Fixed smooth lighting rendering --- .../mods/sodium/client/model/light/EntityLighter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java index 0832ecec9..6c419bd29 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/EntityLighter.java @@ -84,7 +84,7 @@ public static int getBlendedLight(Entity entity, float tickDelta) { sl += weight * (entity.worldObj.getSkyBlockTypeBrightness(EnumSkyBlock.Sky, pos.x, pos.y, pos.z) / MAX_LIGHT_VAL); if (calcBlockLight) { - bl += weight * (entity.worldObj.getBlockLightValue(pos.x, pos.y, pos.z) / MAX_LIGHT_VAL); + bl += weight * (entity.worldObj.getSkyBlockTypeBrightness(EnumSkyBlock.Block, pos.x, pos.y, pos.z) / MAX_LIGHT_VAL); } else { bl += weight; } From 2eb07856512f49641f1e5f5a59985586db85047b Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 26 Nov 2023 21:34:45 -0800 Subject: [PATCH 159/301] Iris block_id Mixins & BlockStateIdMap initial impl for 1.7.10 --- .../transform/RedirectorTransformer.java | 1 - .../chunk/compile/ChunkBuildBuffers.java | 47 +++++++- .../chunk/tasks/ChunkRenderRebuildTask.java | 6 + .../block_rendering/BlockMaterialMapping.java | 114 +++++++----------- .../BlockRenderingSettings.java | 31 ++--- .../DeferredWorldRenderingPipeline.java | 2 +- .../net/coderbot/iris/shaderpack/IdMap.java | 6 +- .../coderbot/iris/shaderpack/LegacyIdMap.java | 2 +- .../coderbot/iris/shaderpack/ShaderPack.java | 9 +- .../shaderpack/materialmap/BlockEntry.java | 95 ++++++++------- .../shaderpack/materialmap/BlockMatch.java | 17 +++ .../java/net/coderbot/iris/sodium/Mixins.txt | 4 +- .../block_context/BlockContextHolder.java | 15 +-- .../block_context/ChunkBuildBuffersExt.java | 4 +- 14 files changed, 189 insertions(+), 164 deletions(-) create mode 100644 src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockMatch.java diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 59ca5ccd8..8d5e41d6e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -18,7 +18,6 @@ /** * This transformer redirects all Tessellator.instance field accesses to go through our TessellatorManager. * As well as redirect some GL calls to our custom GLStateManager - * NOTE: Still need to verify compatibility with Mixins and Lwjgl3ify */ public class RedirectorTransformer implements IClassTransformer { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java index c3c206c7e..60ff9863c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java @@ -1,5 +1,8 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; +import com.gtnewhorizons.angelica.config.AngelicaConfig; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import lombok.Getter; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.buffer.VertexData; import me.jellysquid.mods.sodium.client.gl.util.BufferSlice; @@ -12,7 +15,14 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkMeshData; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkModelOffset; +import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; +import net.coderbot.iris.shaderpack.materialmap.BlockMatch; +import net.coderbot.iris.sodium.block_context.BlockContextHolder; +import net.coderbot.iris.sodium.block_context.ChunkBuildBuffersExt; +import net.coderbot.iris.sodium.block_context.ContextAwareVertexWriter; +import net.minecraft.block.Block; import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; @@ -23,13 +33,16 @@ * passes. This makes a best-effort attempt to pick a suitable size for each scratch buffer, but will never try to * shrink a buffer. */ -public class ChunkBuildBuffers { +public class ChunkBuildBuffers implements ChunkBuildBuffersExt { private final ChunkModelBuffers[] delegates; private final VertexBufferBuilder[][] buffersByLayer; + @Getter private final ChunkVertexType vertexType; private final ChunkModelOffset offset; + private BlockContextHolder iris$contextHolder; + private static final int EXPECTED_BUFFER_SIZE = 2097152; public ChunkBuildBuffers(ChunkVertexType vertexType) { @@ -49,6 +62,16 @@ public ChunkBuildBuffers(ChunkVertexType vertexType) { buffers[facing.ordinal()] = new VertexBufferBuilder(vertexType.getBufferVertexFormat(), EXPECTED_BUFFER_SIZE / ModelQuadFacing.COUNT); } } + + if(AngelicaConfig.enableIris) { + Object2IntMap blockMatches = BlockRenderingSettings.INSTANCE.getBlockMatches(); + + if (blockMatches != null) { + this.iris$contextHolder = new BlockContextHolder(blockMatches); + } else { + this.iris$contextHolder = new BlockContextHolder(); + } + } } public void init(ChunkRenderData.Builder renderData) { @@ -56,7 +79,11 @@ public void init(ChunkRenderData.Builder renderData) { ChunkModelVertexTransformer[] writers = new ChunkModelVertexTransformer[ModelQuadFacing.COUNT]; for (ModelQuadFacing facing : ModelQuadFacing.VALUES) { - writers[facing.ordinal()] = new ChunkModelVertexTransformer(this.vertexType.createBufferWriter(this.buffersByLayer[i][facing.ordinal()], SodiumClientMod.isDirectMemoryAccessEnabled()), this.offset); + final ModelVertexSink sink = this.vertexType.createBufferWriter(this.buffersByLayer[i][facing.ordinal()], SodiumClientMod.isDirectMemoryAccessEnabled()); + if (AngelicaConfig.enableIris && sink instanceof ContextAwareVertexWriter) { + ((ContextAwareVertexWriter) sink).iris$setContextHolder(iris$contextHolder); + } + writers[facing.ordinal()] = new ChunkModelVertexTransformer(sink, this.offset); } this.delegates[i] = new BakedChunkModelBuffers(writers, renderData); @@ -125,7 +152,19 @@ public void setRenderOffset(int x, int y, int z) { this.offset.set(x, y, z); } - public ChunkVertexType getVertexType() { - return this.vertexType; + // Iris Compat + public void iris$setLocalPos(int localPosX, int localPosY, int localPosZ) { + if(!AngelicaConfig.enableIris) return; + this.iris$contextHolder.setLocalPos(localPosX, localPosY, localPosZ); + } + + public void iris$setMaterialId(Block block, short renderType) { + if(!AngelicaConfig.enableIris) return; + this.iris$contextHolder.set(block, renderType); + } + + public void iris$resetBlockContext() { + if(!AngelicaConfig.enableIris) return; + this.iris$contextHolder.reset(); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 2df5aff27..636c96f4b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -2,6 +2,7 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionDataBuilder; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.glsm.TessellatorManager; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; @@ -18,6 +19,7 @@ import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import me.jellysquid.mods.sodium.common.config.SodiumConfig; +import net.coderbot.iris.vertices.ExtendedDataHelper; import net.minecraft.block.Block; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.Tessellator; @@ -121,11 +123,13 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB pos.set(baseX + relX, baseY + relY, baseZ + relZ); buffers.setRenderOffset(pos.x - renderOffset.getX(), pos.y - renderOffset.getY(), pos.z - renderOffset.getZ()); + if(AngelicaConfig.enableIris) buffers.iris$setLocalPos(relX, relY, relZ); // Do regular block rendering for (BlockRenderPass pass : BlockRenderPass.VALUES) { if (block.canRenderInPass(pass.ordinal()) && (!SodiumConfig.ENABLE_FLUID_RENDERER || !(block instanceof IFluidBlock))) { long seed = MathUtil.hashPos(pos.x, pos.y, pos.z); + if(AngelicaConfig.enableIris) buffers.iris$setMaterialId(block, ExtendedDataHelper.BLOCK_RENDER_TYPE); if (cache.getBlockRenderer().renderModel(cache.getWorldSlice(), tessellator, renderBlocks, block, meta, pos, buffers.get(pass), true, seed)) { bounds.addBlock(relX, relY, relZ); @@ -137,6 +141,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB if (SodiumConfig.ENABLE_FLUID_RENDERER && block instanceof IFluidBlock) { for (BlockRenderPass pass : BlockRenderPass.VALUES) { if (block.canRenderInPass(pass.ordinal())) { + if(AngelicaConfig.enableIris) buffers.iris$setMaterialId(block, ExtendedDataHelper.FLUID_RENDER_TYPE); if (cache.getFluidRenderer().render(slice, cache.getWorldSlice(), block, pos, buffers.get(pass))) { bounds.addBlock(relX, relY, relZ); @@ -145,6 +150,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB } } + if(AngelicaConfig.enableIris) buffers.iris$resetBlockContext(); if (block.hasTileEntity(meta)) { TileEntity entity = slice.getTileEntity(pos.x, pos.y, pos.z); diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java index 65386884a..280c4ca26 100644 --- a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java @@ -1,31 +1,33 @@ package net.coderbot.iris.block_rendering; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import net.coderbot.iris.shaderpack.materialmap.BlockEntry; +import net.coderbot.iris.shaderpack.materialmap.BlockMatch; import net.coderbot.iris.shaderpack.materialmap.BlockRenderType; import net.coderbot.iris.shaderpack.materialmap.NamespacedId; import net.minecraft.block.Block; +import net.minecraft.init.Blocks; import net.minecraft.util.ResourceLocation; import java.util.List; import java.util.Map; +import java.util.Set; public class BlockMaterialMapping { - public static Object2IntMap createBlockStateIdMap(Int2ObjectMap> blockPropertiesMap) { - Object2IntMap blockStateIds = new Object2IntOpenHashMap<>(); + public static Object2IntMap createBlockStateIdMap(Int2ObjectMap> blockPropertiesMap) { + Object2IntMap blockMatches = new Object2IntOpenHashMap<>(); - // TODO: BlockStateIdMap -// blockPropertiesMap.forEach((intId, entries) -> { -// for (BlockEntry entry : entries) { -// addBlockStates(entry, blockStateIds, intId); -// } -// }); + blockPropertiesMap.forEach((intId, entries) -> { + for (BlockEntry entry : entries) { + addBlock(entry, blockMatches, intId); + } + }); - return blockStateIds; + return blockMatches; } public static Map createBlockTypeMap(Map blockPropertiesMap) { @@ -48,72 +50,40 @@ private static RenderLayer convertBlockToRenderType(BlockRenderType type) { } return switch (type) { - // TODO: RenderType -// case SOLID -> RenderType.solid(); -// case CUTOUT -> RenderType.cutout(); -// case CUTOUT_MIPPED -> RenderType.cutoutMipped(); -// case TRANSLUCENT -> RenderType.translucent(); + // Everything renders in cutout or translucent in 1.7.10 + case SOLID, CUTOUT, CUTOUT_MIPPED -> RenderLayer.cutout(); + // case SOLID -> RenderLayer.solid(); + // case CUTOUT_MIPPED -> RenderLayer.cutoutMipped(); + case TRANSLUCENT -> RenderLayer.translucent(); default -> null; }; } - // TODO: BlockStateIdMap -// private static void addBlockStates(BlockEntry entry, Object2IntMap idMap, int intId) { -// NamespacedId id = entry.getId(); -// ResourceLocation resourceLocation = new ResourceLocation(id.getNamespace(), id.getName()); -// -// Block block = Registry.BLOCK.get(resourceLocation); -// -// // If the block doesn't exist, by default the registry will return AIR. That probably isn't what we want. -// // TODO: Assuming that Registry.BLOCK.getDefaultId() == "minecraft:air" here -// if (block == Blocks.air) { -// return; -// } -// -// Map propertyPredicates = entry.getPropertyPredicates(); -// -// if (propertyPredicates.isEmpty()) { -// // Just add all the states if there aren't any predicates -// for (BlockState state : block.getStateDefinition().getPossibleStates()) { -// // NB: Using putIfAbsent means that the first successful mapping takes precedence -// // Needed for OptiFine parity: -// // https://github.com/IrisShaders/Iris/issues/1327 -// idMap.putIfAbsent(state, intId); -// } -// -// return; -// } -// -// // As a result, we first collect each key=value pair in order to determine what properties we need to filter on. -// // We already get this from BlockEntry, but we convert the keys to `Property`s to ensure they exist and to avoid -// // string comparisons later. -// Map, String> properties = new HashMap<>(); -// StateDefinition stateManager = block.getStateDefinition(); -// -// propertyPredicates.forEach((key, value) -> { -// Property property = stateManager.getProperty(key); -// -// if (property == null) { -// Iris.logger.warn("Error while parsing the block ID map entry for \"" + "block." + intId + "\":"); -// Iris.logger.warn("- The block " + resourceLocation + " has no property with the name " + key + ", ignoring!"); -// -// return; -// } -// -// properties.put(property, value); -// }); -// -// // Once we have a list of properties and their expected values, we iterate over every possible state of this -// // block and check for ones that match the filters. This isn't particularly efficient, but it works! -// for (BlockState state : stateManager.getPossibleStates()) { -// if (checkState(state, properties)) { -// // NB: Using putIfAbsent means that the first successful mapping takes precedence -// // Needed for OptiFine parity: -// // https://github.com/IrisShaders/Iris/issues/1327 -// idMap.putIfAbsent(state, intId); -// } -// } -// } + private static void addBlock(BlockEntry entry, Object2IntMap idMap, int intId) { + final NamespacedId id = entry.getId(); + final ResourceLocation resourceLocation = new ResourceLocation(id.getNamespace(), id.getName()); + + Block block = (Block) Block.blockRegistry.getObject(resourceLocation.toString()); + + // If the block doesn't exist, by default the registry will return AIR. That probably isn't what we want. + // TODO: Assuming that Registry.BLOCK.getDefaultId() == "minecraft:air" here + if (block == null || block == Blocks.air) { + return; + } + + Set metas = entry.getMetas(); + + // All metas match + if (metas.isEmpty()) { + idMap.putIfAbsent(new BlockMatch(block, null), intId); + return; + } + + // A subset of metas match + for(int meta : metas) { + idMap.putIfAbsent(new BlockMatch(block, meta), intId); + } + } // We ignore generics here, the actual types don't matter because we just convert // them to strings anyways, and the compiler checks just get in the way. diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java index 8850e26d3..7c3432f52 100644 --- a/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java @@ -3,6 +3,8 @@ import it.unimi.dsi.fastutil.objects.Object2IntFunction; import it.unimi.dsi.fastutil.objects.Object2IntMap; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import lombok.Getter; +import net.coderbot.iris.shaderpack.materialmap.BlockMatch; import net.coderbot.iris.shaderpack.materialmap.NamespacedId; import net.minecraft.block.Block; import org.jetbrains.annotations.Nullable; @@ -12,9 +14,9 @@ public class BlockRenderingSettings { public static final BlockRenderingSettings INSTANCE = new BlockRenderingSettings(); - private boolean reloadRequired; - // TODO: BlockStateIdMap - private Object2IntMap blockStateIds; + @Getter + private boolean reloadRequired; + private Object2IntMap blockMatches; private Map blockTypeIds; private Object2IntFunction entityIds; private float ambientOcclusionLevel; @@ -24,7 +26,7 @@ public class BlockRenderingSettings { public BlockRenderingSettings() { reloadRequired = false; - blockStateIds = null; + blockMatches = null; blockTypeIds = null; ambientOcclusionLevel = 1.0F; disableDirectionalShading = false; @@ -32,18 +34,13 @@ public BlockRenderingSettings() { useExtendedVertexFormat = false; } - public boolean isReloadRequired() { - return reloadRequired; - } - - public void clearReloadRequired() { + public void clearReloadRequired() { reloadRequired = false; } - // TODO: BlockStateIdMap - @Nullable - public Object2IntMap getBlockStateIds() { - return blockStateIds; + @Nullable + public Object2IntMap getBlockMatches() { + return blockMatches; } @Nullable @@ -51,20 +48,18 @@ public Map getBlockTypeIds() { return blockTypeIds; } - // TODO (coderbot): This doesn't belong here. But I couldn't think of a nicer place to put it. @Nullable public Object2IntFunction getEntityIds() { return entityIds; } - // TODO: BlockStateIdMap - public void setBlockStateIds(Object2IntMap blockStateIds) { - if (this.blockStateIds != null && this.blockStateIds.equals(blockStateIds)) { + public void setBlockMatches(Object2IntMap blockIds) { + if (this.blockMatches != null && this.blockMatches.equals(blockIds)) { return; } this.reloadRequired = true; - this.blockStateIds = blockStateIds; + this.blockMatches = blockIds; } public void setBlockTypeIds(Map blockTypeIds) { diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index c8494f096..37d7b8d77 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -192,7 +192,7 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { } // TODO: BlockStateIdMap - BlockRenderingSettings.INSTANCE.setBlockStateIds(BlockMaterialMapping.createBlockStateIdMap(programs.getPack().getIdMap().getBlockProperties())); + BlockRenderingSettings.INSTANCE.setBlockMatches(BlockMaterialMapping.createBlockStateIdMap(programs.getPack().getIdMap().getBlockProperties())); BlockRenderingSettings.INSTANCE.setBlockTypeIds(BlockMaterialMapping.createBlockTypeMap(programs.getPack().getIdMap().getBlockRenderTypeMap())); BlockRenderingSettings.INSTANCE.setEntityIds(programs.getPack().getIdMap().getEntityIdMap()); diff --git a/src/main/java/net/coderbot/iris/shaderpack/IdMap.java b/src/main/java/net/coderbot/iris/shaderpack/IdMap.java index 836c0aba1..61286a573 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/IdMap.java +++ b/src/main/java/net/coderbot/iris/shaderpack/IdMap.java @@ -54,11 +54,9 @@ public class IdMap { private Map blockRenderTypeMap; IdMap(Path shaderPath, ShaderPackOptions shaderPackOptions, Iterable environmentDefines) { - itemIdMap = loadProperties(shaderPath, "item.properties", shaderPackOptions, environmentDefines) - .map(IdMap::parseItemIdMap).orElse(Object2IntMaps.emptyMap()); + itemIdMap = loadProperties(shaderPath, "item.properties", shaderPackOptions, environmentDefines).map(IdMap::parseItemIdMap).orElse(Object2IntMaps.emptyMap()); - entityIdMap = loadProperties(shaderPath, "entity.properties", shaderPackOptions, environmentDefines) - .map(IdMap::parseEntityIdMap).orElse(Object2IntMaps.emptyMap()); + entityIdMap = loadProperties(shaderPath, "entity.properties", shaderPackOptions, environmentDefines).map(IdMap::parseEntityIdMap).orElse(Object2IntMaps.emptyMap()); loadProperties(shaderPath, "block.properties", shaderPackOptions, environmentDefines).ifPresent(blockProperties -> { blockPropertiesMap = parseBlockMap(blockProperties, "block.", "block.properties"); diff --git a/src/main/java/net/coderbot/iris/shaderpack/LegacyIdMap.java b/src/main/java/net/coderbot/iris/shaderpack/LegacyIdMap.java index 73a7d5e4b..615091caa 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/LegacyIdMap.java +++ b/src/main/java/net/coderbot/iris/shaderpack/LegacyIdMap.java @@ -79,7 +79,7 @@ public static void addLegacyValues(Int2ObjectMap> blockIdMap) { } private static BlockEntry block(String name) { - return new BlockEntry(new NamespacedId("minecraft", name), Collections.emptyMap()); + return new BlockEntry(new NamespacedId("minecraft", name), Collections.emptySet()); } private static void addMany(Int2ObjectMap> blockIdMap, int id, List prefixes, Function toId) { diff --git a/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java b/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java index 3f76073ba..0371dff8a 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java +++ b/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java @@ -215,12 +215,9 @@ public ShaderPack(Path root, Map changedConfigs, Iterable propertyPredicates; + private final Set metas; - public BlockEntry(NamespacedId id, Map propertyPredicates) { + public BlockEntry(NamespacedId id, Set metas) { this.id = id; - this.propertyPredicates = propertyPredicates; + this.metas = metas; } /** @@ -33,69 +34,71 @@ public static BlockEntry parse(@NotNull String entry) { // Trivial case: no states, no namespace if (splitStates.length == 1) { - return new BlockEntry(new NamespacedId("minecraft", entry), Collections.emptyMap()); + return new BlockEntry(new NamespacedId("minecraft", entry), Collections.emptySet()); } - // Less trivial case: no states involved, just a namespace + // Examples of what we'll accept + // stone + // stone:0 + // minecraft:stone:0 + // minecraft:stone:0,1,2 # Theoretically valid, but I haven't seen any examples in actual shaders + + // Examples of what we don't (Yet?) accept - Seems to be from MC 1.8+ + // minecraft:farmland:moisture=0 + // minecraft:farmland:moisture=1 + // minecraft:double_plant:half=lower + // minecraft:double_plant:half=upper + // minecraft:grass:snowy=true + // minecraft:unpowered_comparator:powered=false + + + // Less trivial case: no metas involved, just a namespace // - // The first term MUST be a valid ResourceLocation component without an equals sign - // The second term, if it does not contain an equals sign, must be a valid ResourceLocation component. - if (splitStates.length == 2 && !splitStates[1].contains("=")) { - return new BlockEntry(new NamespacedId(splitStates[0], splitStates[1]), Collections.emptyMap()); + // The first term MUST be a valid ResourceLocation component + // The second term, if it is not numeric, must be a valid ResourceLocation component. + if (splitStates.length == 2 && !StringUtils.isNumeric(splitStates[1].substring(0, 1))) { + return new BlockEntry(new NamespacedId(splitStates[0], splitStates[1]), Collections.emptySet()); } // Complex case: One or more states involved... int statesStart; NamespacedId id; - if (splitStates[1].contains("=")) { - // We have an entry of the form "tall_grass:half=upper" + if (StringUtils.isNumeric(splitStates[1].substring(0, 1))) { + // We have an entry of the form "stone:0" statesStart = 1; id = new NamespacedId("minecraft", splitStates[0]); } else { - // We have an entry of the form "minecraft:tall_grass:half=upper" + // We have an entry of the form "minecraft:stone:0" statesStart = 2; id = new NamespacedId(splitStates[0], splitStates[1]); } - // We must parse each property key=value pair from the state entry. - // - // These pairs act as a filter on the block states. Thus, the shader pack does not have to specify all the - // individual block properties itself; rather, it only specifies the parts of the block state that it wishes - // to filter in/out. - // - // For example, some shader packs may make it so that hanging lantern blocks wave. They will put something of - // the form "lantern:hanging=false" in the ID map as a result. Note, however, that there are also waterlogged - // hanging lanterns, which would have "lantern:hanging=false:waterlogged=true". We must make sure that when the - // shader pack author writes "lantern:hanging=false", that we do not just match that individual state, but that - // we also match the waterlogged variant too. - Map map = new HashMap<>(); + Set metas = new HashSet<>(); for (int index = statesStart; index < splitStates.length; index++) { - // Split "key=value" into the key and value - String[] propertyParts = splitStates[index].split("="); - - if (propertyParts.length != 2) { - Iris.logger.warn("Warning: the block ID map entry \"" + entry + "\" could not be fully parsed:"); - Iris.logger.warn("- Block state property filters must be of the form \"key=value\", but " - + splitStates[index] + " is not of that form!"); - - // Continue and ignore the invalid entry. - continue; - } - - map.put(propertyParts[0], propertyParts[1]); - } - - return new BlockEntry(id, map); + // Parse out one or more metadata ids + String[] metaParts = splitStates[index].split(", "); + + for (String metaPart : metaParts) { + try { + metas.add(Integer.parseInt(metaPart)); + } catch (NumberFormatException e) { + Iris.logger.warn("Warning: the block ID map entry \"" + entry + "\" could not be fully parsed:"); + Iris.logger.warn("- Metadata ids must be a comma separated list of one or more integers, but "+ splitStates[index] + " is not of that form!"); + } + } + } + + return new BlockEntry(id, metas); } public NamespacedId getId() { return id; } - public Map getPropertyPredicates() { - return propertyPredicates; + public Set getMetas() { + return metas; } @Override @@ -103,11 +106,11 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; BlockEntry that = (BlockEntry) o; - return Objects.equals(id, that.id) && Objects.equals(propertyPredicates, that.propertyPredicates); + return Objects.equals(id, that.id) && Objects.equals(metas, that.metas); } @Override public int hashCode() { - return Objects.hash(id, propertyPredicates); + return Objects.hash(id, metas); } } diff --git a/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockMatch.java b/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockMatch.java new file mode 100644 index 000000000..06800592c --- /dev/null +++ b/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockMatch.java @@ -0,0 +1,17 @@ +package net.coderbot.iris.shaderpack.materialmap; + +import net.minecraft.block.Block; + +public class BlockMatch { + private final Block block; + private final Integer meta; + + public BlockMatch(Block block, Integer meta) { + this.block = block; + this.meta = meta; + } + + public boolean matches(Block block, int meta) { + return this.block == block && (this.meta == null || this.meta == meta); + } +} diff --git a/src/main/java/net/coderbot/iris/sodium/Mixins.txt b/src/main/java/net/coderbot/iris/sodium/Mixins.txt index 3a76d7698..5c804ee35 100644 --- a/src/main/java/net/coderbot/iris/sodium/Mixins.txt +++ b/src/main/java/net/coderbot/iris/sodium/Mixins.txt @@ -12,8 +12,8 @@ Y directional_shading * MixinGameRendererContext.java * MixinChunkRenderManager.java * block_id - * MixinChunkRenderRebuildTask.java - * MixinChunkBuildBuffers.java + X MixinChunkRenderRebuildTask.java + X MixinChunkBuildBuffers.java * pbr_animation * MixinTextureAtlasSprite.java * vertex_format diff --git a/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java b/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java index 87ce2e4fe..9f1a7a3dd 100644 --- a/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java +++ b/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java @@ -1,11 +1,12 @@ package net.coderbot.iris.sodium.block_context; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMaps; +import net.coderbot.iris.shaderpack.materialmap.BlockMatch; +import net.minecraft.block.Block; public class BlockContextHolder { - private final Object2IntMap blockStateIds; + private final Object2IntMap blockMatches; public int localPosX; public int localPosY; @@ -15,13 +16,13 @@ public class BlockContextHolder { public short renderType; public BlockContextHolder() { - this.blockStateIds = Object2IntMaps.emptyMap(); + this.blockMatches = Object2IntMaps.emptyMap(); this.blockId = -1; this.renderType = -1; } - public BlockContextHolder(Object2IntMap idMap) { - this.blockStateIds = idMap; + public BlockContextHolder(Object2IntMap idMap) { + this.blockMatches = idMap; this.blockId = -1; this.renderType = -1; } @@ -32,8 +33,8 @@ public void setLocalPos(int localPosX, int localPosY, int localPosZ) { this.localPosZ = localPosZ; } - public void set(BlockState state, short renderType) { - this.blockId = (short) this.blockStateIds.getOrDefault(state, -1); + public void set(Block block, short renderType) { + this.blockId = (short) this.blockMatches.getOrDefault(block, -1); this.renderType = renderType; } diff --git a/src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java b/src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java index 8f4545c3b..407b3cde7 100644 --- a/src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java +++ b/src/main/java/net/coderbot/iris/sodium/block_context/ChunkBuildBuffersExt.java @@ -1,11 +1,11 @@ package net.coderbot.iris.sodium.block_context; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; +import net.minecraft.block.Block; public interface ChunkBuildBuffersExt { void iris$setLocalPos(int localPosX, int localPosY, int localPosZ); - void iris$setMaterialId(BlockState state, short renderType); + void iris$setMaterialId(Block block, short renderType); void iris$resetBlockContext(); } From d04765b4e97366f72deb9542398e9aa09460c17a Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 26 Nov 2023 23:37:17 -0800 Subject: [PATCH 160/301] Fix running with lwjgl debug flag & Cleanup old ShadersMod transformers * Initialize GLStateManager via Mixins instead of all in the static block * Exclude two known safe methods from the GLStateManager check (startGame & intializeTextures) --- .../angelica/glsm/GLStateManager.java | 10 +- .../loading/MixinCompatHackTweaker.java | 33 +---- .../gtnewhorizons/angelica/mixins/Mixins.java | 17 ++- .../startup/MixinInitGLStateManager.java | 16 +++ .../angelica/transform/ACTEntityRenderer.java | 50 -------- .../transform/ACTRendererLivingEntity.java | 98 -------------- .../angelica/transform/AClassTransformer.java | 50 -------- .../angelica/transform/InitNames.java | 18 --- .../angelica/transform/Namer.java | 46 ------- .../angelica/transform/Namer1_7_10.java | 25 ---- .../angelica/transform/NamerMcf.java | 9 -- .../angelica/transform/NamerMcp.java | 121 ------------------ .../angelica/transform/NamerSrg.java | 20 --- .../angelica/transform/Names.java | 90 ------------- .../transform/RedirectorTransformer.java | 17 ++- 15 files changed, 48 insertions(+), 572 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinInitGLStateManager.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/ACTRendererLivingEntity.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/AClassTransformer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/InitNames.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/Namer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/Namer1_7_10.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/NamerMcf.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/NamerMcp.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/NamerSrg.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/Names.java diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 0caa85805..630227376 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -57,9 +57,8 @@ public class GLStateManager { private static int modelShadeMode; - // TODO: Maybe inject the iris stuff via mixins.... @Getter - private static final TextureState[] Textures; + private static TextureState[] Textures; // Iris Listeners private static Runnable blendFuncListener = null; @@ -75,6 +74,10 @@ public class GLStateManager { private static Thread MainThread; static { + MainThread = Thread.currentThread(); + } + + public static void init() { if(AngelicaConfig.enableIris) { StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener; StateUpdateNotifiers.fogToggleNotifier = listener -> fogToggleListener = listener; @@ -83,8 +86,9 @@ public class GLStateManager { StateUpdateNotifiers.fogEndNotifier = listener -> fogEndListener = listener; StateUpdateNotifiers.fogDensityNotifier = listener -> fogDensityListener = listener; } + // We want textures regardless of Iris being initialized, and using SamplerLimits is isolated enough Textures = (TextureState[]) IntStream.range(0, SamplerLimits.get().getMaxTextureUnits()).mapToObj(i -> new TextureState()).toArray(TextureState[]::new); - MainThread = Thread.currentThread(); + } public static void assertMainThread() { diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java index 8c2d828e5..59680db35 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java @@ -1,15 +1,11 @@ package com.gtnewhorizons.angelica.loading; -import com.gtnewhorizons.angelica.transform.AClassTransformer; import com.gtnewhorizons.angelica.transform.RedirectorTransformer; -import cpw.mods.fml.common.asm.transformers.TerminalTransformer; -import net.minecraft.launchwrapper.IClassTransformer; import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; import java.io.File; -import java.lang.reflect.Field; import java.util.List; @@ -17,34 +13,7 @@ public class MixinCompatHackTweaker implements ITweaker { @Override public void acceptOptions(List args, File gameDir, File assetsDir, String profile) { - LaunchClassLoader lcl = Launch.classLoader; - try { - Field xformersField = lcl.getClass().getDeclaredField("transformers"); - xformersField.setAccessible(true); - @SuppressWarnings("unchecked") - List xformers = (List) xformersField.get(lcl); - int terminalIndex; - for (terminalIndex = 1; terminalIndex < xformers.size(); terminalIndex++) { - if (xformers.get(terminalIndex) instanceof TerminalTransformer) { - break; - } - } - try { - Class.forName("me.eigenraven.lwjgl3ify.core.LwjglRedirectTransformer"); - AngelicaTweaker.LOGGER.info("LwjglRedirectTransformer found, injecting before it"); - terminalIndex -= 2; - - } catch (Exception ignored) { - AngelicaTweaker.LOGGER.info("LwjglRedirectTransformer not found, injecting near the end"); - terminalIndex -= 1; - } - - xformers.add(terminalIndex, new AClassTransformer()); - AngelicaTweaker.LOGGER.info("Hacked in asm class transformer in position {}", terminalIndex); - } catch (Exception e) { - throw new RuntimeException(e); - } } @Override @@ -59,7 +28,7 @@ public String getLaunchTarget() { @Override public String[] getLaunchArguments() { - // Run after Mixins, but hopefully before LWJGl3ify + // Run after Mixins, but before LWJGl3ify Launch.classLoader.registerTransformer(RedirectorTransformer.class.getName()); return new String[0]; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index dda61c677..0a7cefb7c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -12,12 +12,23 @@ import java.util.function.Supplier; public enum Mixins { + ANGELICA_STARTUP(new Builder("Angelica Startup").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).addMixinClasses( + "angelica.startup.MixinInitGLStateManager" + ) + ), + ANGELICA(new Builder("Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( "angelica.MixinEntityRenderer" ) ), + ANGELICA_ENABLE_DEBUG(new Builder("Angelica Debug").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaMod.lwjglDebug).addMixinClasses( + "angelica.debug.MixinSplashProgress" + ) + ), // Not compatible with the lwjgl debug callbacks, so disable if that's enabled ARCHAIC_SPLASH(new Builder("ArchaicFix Splash").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.showSplashMemoryBar && !AngelicaMod.lwjglDebug).addMixinClasses( @@ -42,12 +53,8 @@ public enum Mixins { ,"shaders.startup.MixinGuiMainMenu" ,"shaders.startup.MixinInitRenderer" ) - ), - ANGELICA_ENABLE_DEBUG(new Builder("Angelica Debug").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) - .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaMod.lwjglDebug).addMixinClasses( - "angelica.debug.MixinSplashProgress" - ) ), + SODIUM_STARTUP(new Builder("Start Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodium && !AngelicaConfig.enableIris).addMixinClasses( "sodium.startup.MixinInitDebug" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinInitGLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinInitGLStateManager.java new file mode 100644 index 000000000..f5129724c --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinInitGLStateManager.java @@ -0,0 +1,16 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.startup; + +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = OpenGlHelper.class, priority = 100) +public class MixinInitGLStateManager { + @Inject(method = "initializeTextures", at = @At("RETURN")) + private static void angelica$initializeGLStateManager(CallbackInfo ci) { + GLStateManager.init(); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java deleted file mode 100644 index 678ae799c..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/ACTEntityRenderer.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; -import net.minecraft.client.renderer.EntityRenderer; -import net.minecraft.launchwrapper.IClassTransformer; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; - -/** Transformer for {@link EntityRenderer} */ -public class ACTEntityRenderer implements IClassTransformer, Opcodes { - - @Override - public byte[] transform(String name, String transformedName, byte[] basicClass) { - if ("net.minecraft.client.renderer.EntityRenderer".equals(transformedName)) { - AngelicaTweaker.LOGGER.debug("transforming {} {}", name, transformedName); - ClassReader cr = new ClassReader(basicClass); - ClassNode cn = new ClassNode(); - cr.accept(cn, 0); - for (MethodNode mn : cn.methods) { - if (Names.entityRenderer_renderHand.equalsNameDesc(mn.name, mn.desc)) { - // Wraps the code from GL11.glPushMatrix() to GL11.glPopMatrix() in an if(!Shaders.isHandRendered) check - AngelicaTweaker.LOGGER.trace(" patching method {}.{}{}", transformedName, mn.name, mn.desc); - LabelNode label = new LabelNode(); - for (AbstractInsnNode node : mn.instructions.toArray()) { - if (node instanceof MethodInsnNode mNode) { - if (Names.equals(mNode, "org/lwjgl/opengl/GL11", "glPushMatrix", "()V")) { - InsnList list = new InsnList(); - list.add(new FieldInsnNode(GETSTATIC, "com/gtnewhorizons/angelica/client/Shaders", "isHandRendered", "Z")); - list.add(new JumpInsnNode(IFNE, label)); - mn.instructions.insertBefore(node, list); - } else if (Names.equals(mNode, "org/lwjgl/opengl/GL11", "glPopMatrix", "()V")) { - InsnList list = new InsnList(); - list.add(label); - list.add(new FrameNode(F_SAME, 0, null, 0, null)); - mn.instructions.insert(node, list); - } - } - } - } - } - ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); - cn.accept(cw); - return cw.toByteArray(); - } - return basicClass; - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/ACTRendererLivingEntity.java b/src/main/java/com/gtnewhorizons/angelica/transform/ACTRendererLivingEntity.java deleted file mode 100644 index fa8ad5c1e..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/ACTRendererLivingEntity.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -import static org.objectweb.asm.Opcodes.GETSTATIC; -import static org.objectweb.asm.Opcodes.IFNE; -import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; - -import net.minecraft.client.renderer.entity.RendererLivingEntity; -import net.minecraft.launchwrapper.IClassTransformer; - -import org.lwjgl.opengl.GL12; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; - -/** Transformer for {@link RendererLivingEntity} */ -public class ACTRendererLivingEntity implements IClassTransformer { - - @Override - public byte[] transform(String name, String transformedName, byte[] basicClass) { - AngelicaTweaker.LOGGER.debug("transforming {} {}", name, transformedName); - ClassReader cr = new ClassReader(basicClass); - ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); - CVTransform cv = new CVTransform(cw); - cr.accept(cv, 0); - return cw.toByteArray(); - } - - private static class CVTransform extends ClassVisitor { - - private String classname; - - private CVTransform(ClassVisitor cv) { - super(Opcodes.ASM4, cv); - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, - String[] interfaces) { - classname = name; - cv.visit(version, access, name, signature, superName, interfaces); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - if (Names.rendererLivingE_doRender.equalsNameDesc(name, desc)) { - AngelicaTweaker.LOGGER.trace(" patching method {}.{}{}", classname, name, desc); - return new MVdoRenderLiving(cv.visitMethod(access, name, desc, signature, exceptions)); - } - return cv.visitMethod(access, name, desc, signature, exceptions); - } - } - - /** - * Wraps everything in - * {@link RendererLivingEntity#doRender(net.minecraft.entity.EntityLivingBase, double, double, double, float, float)} - * between {@code this.renderEquippedItems(p_76986_1_, p_76986_9_);} and - * {@code GL11.glDisable(GL12.GL_RESCALE_NORMAL);} in an {@code if (!Shaders.useEntityHurtFlash)}-block - */ - private static class MVdoRenderLiving extends MethodVisitor { - - private MVdoRenderLiving(MethodVisitor mv) { - super(Opcodes.ASM4, mv); - } - - /** end of vanilla hurt rendering */ - private Label labelEndVH = null; - - @Override - public void visitLdcInsn(Object cst) { - if (cst instanceof Integer integer) { - if (integer.intValue() == GL12.GL_RESCALE_NORMAL) { - if (labelEndVH != null) { - mv.visitLabel(labelEndVH); - labelEndVH = null; - } - } - } - mv.visitLdcInsn(cst); - } - - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { - if (opcode == INVOKEVIRTUAL && Names.rendererLivingE_renderEquippedItems.equals(owner, name, desc)) { - mv.visitMethodInsn(opcode, owner, name, desc); - mv.visitFieldInsn(GETSTATIC, "com/gtnewhorizons/angelica/client/Shaders", "useEntityHurtFlash", "Z"); - labelEndVH = new Label(); - mv.visitJumpInsn(IFNE, labelEndVH); - return; - } - mv.visitMethodInsn(opcode, owner, name, desc); - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/AClassTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/AClassTransformer.java deleted file mode 100644 index cb70f042d..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/AClassTransformer.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -import java.util.HashMap; -import java.util.Map; - -import net.minecraft.launchwrapper.IClassTransformer; - -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.tree.ClassNode; - -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; - -public class AClassTransformer implements IClassTransformer { - - /** map of class transformer */ - protected Map ctMap; - - public void put(Names.Clas clas, IClassTransformer ct) { - ctMap.put(clas.clas.replace('/', '.'), ct); - } - - public AClassTransformer() { - InitNames.init(); - ctMap = new HashMap<>(); - put(Names.entityRenderer_, new ACTEntityRenderer()); - put(Names.rendererLivingE_, new ACTRendererLivingEntity()); - } - - @Override - public byte[] transform(String name, String transformedName, byte[] basicClass) { - byte[] bytecode = basicClass; - IClassTransformer ct = ctMap.get(transformedName); - if (ct != null) { - bytecode = ct.transform(name, transformedName, bytecode); - // HACK: Fix stackframes - ClassNode node = new ClassNode(); - ClassReader reader = new ClassReader(bytecode); - reader.accept(node, ClassReader.SKIP_FRAMES); - ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - node.accept(writer); - bytecode = writer.toByteArray(); - // END HACK - int oldLength = basicClass.length; - int newLength = bytecode.length; - AngelicaTweaker.LOGGER.debug(" {} (+{})", newLength, newLength - oldLength); - } - return bytecode; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/InitNames.java b/src/main/java/com/gtnewhorizons/angelica/transform/InitNames.java deleted file mode 100644 index 7fa42b22d..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/InitNames.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -import net.minecraft.launchwrapper.Launch; - -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; - -public class InitNames { - - public static void init() { - final boolean obfuscated = !(Boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment"); - AngelicaTweaker.LOGGER.info("Environment obfuscated: {}", obfuscated); - if (obfuscated) { - new NamerSrg().setNames(); - } else { - new NamerMcp().setNames(); - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/Namer.java b/src/main/java/com/gtnewhorizons/angelica/transform/Namer.java deleted file mode 100644 index 1cf2735f5..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/Namer.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -import java.util.ArrayList; - -import com.gtnewhorizons.angelica.transform.Names.Clas; -import com.gtnewhorizons.angelica.transform.Names.Fiel; -import com.gtnewhorizons.angelica.transform.Names.Meth; - -public class Namer { - - ArrayList ac = new ArrayList<>(); - ArrayList af = new ArrayList<>(); - ArrayList am = new ArrayList<>(); - - Clas c(String name) { - Clas x = new Clas(name); - if (ac != null) ac.add(x); - return x; - } - - Fiel f(Clas clas, String name, String desc) { - Fiel x = new Fiel(clas, name, desc); - if (af != null) af.add(x); - return x; - } - - Fiel f(Clas clas, Fiel fiel) { - Fiel x = new Fiel(clas, fiel.name, fiel.desc); - if (af != null) af.add(x); - return x; - } - - Meth m(Clas clas, String name, String desc) { - Meth x = new Meth(clas, name, desc); - if (am != null) am.add(x); - return x; - } - - Meth m(Clas clas, Meth meth) { - Meth x = new Meth(clas, meth.name, meth.desc); - if (am != null) am.add(x); - return x; - } - - public void setNames() {} -} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/Namer1_7_10.java b/src/main/java/com/gtnewhorizons/angelica/transform/Namer1_7_10.java deleted file mode 100644 index 42225d8c5..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/Namer1_7_10.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -import static com.gtnewhorizons.angelica.transform.Names.entityLivingBase_; -import static com.gtnewhorizons.angelica.transform.Names.entityRenderer_; -import static com.gtnewhorizons.angelica.transform.Names.entityRenderer_renderHand; -import static com.gtnewhorizons.angelica.transform.Names.rendererLivingE_; -import static com.gtnewhorizons.angelica.transform.Names.rendererLivingE_doRender; -import static com.gtnewhorizons.angelica.transform.Names.rendererLivingE_renderEquippedItems; - -public class Namer1_7_10 extends Namer { - - public void setNames() { - setNames1_7_10(); - } - - public void setNames1_7_10() { - entityRenderer_ = c("blt"); - rendererLivingE_ = c("boh"); - entityLivingBase_ = c("sv"); - - entityRenderer_renderHand = m(entityRenderer_, "b", "(FI)V"); - rendererLivingE_doRender = m(rendererLivingE_, "a", "(" + entityLivingBase_.desc + "DDDFF)V"); - rendererLivingE_renderEquippedItems = m(rendererLivingE_, "c", "(" + entityLivingBase_.desc + "F)V"); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/NamerMcf.java b/src/main/java/com/gtnewhorizons/angelica/transform/NamerMcf.java deleted file mode 100644 index 1a7f08ca2..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/NamerMcf.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -public class NamerMcf extends NamerMcp { - - public void setNames() { - setNamesSrg(); - rename("../build/unpacked/conf/"); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/NamerMcp.java b/src/main/java/com/gtnewhorizons/angelica/transform/NamerMcp.java deleted file mode 100644 index d60745e26..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/NamerMcp.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; -import com.gtnewhorizons.angelica.transform.Names.Clas; -import com.gtnewhorizons.angelica.transform.Names.Fiel; -import com.gtnewhorizons.angelica.transform.Names.Meth; - -public class NamerMcp extends NamerSrg { - - public void setNames() { - setNamesSrg(); - final String confPath = System.getProperty("net.minecraftforge.gradle.GradleStart.csvDir", "../conf") + "/"; - lookupReobfName(confPath); - rename(confPath); - } - - public void rename(String confPath) { - Map nameMap; - nameMap = loadNameMapCSV(confPath + "fields.csv"); - for (Fiel f : af) { - String s = nameMap.get(f.name); - if (s != null) { - f.name = s; - } - } - nameMap = loadNameMapCSV(confPath + "methods.csv"); - for (Meth m : am) { - String s = nameMap.get(m.name); - if (s != null) { - m.name = s; - } - } - } - - Map loadNameMapCSV(String fileName) { - Map map = new HashMap<>(); - BufferedReader rd = null; - try { - rd = new BufferedReader(new FileReader(fileName)); - String line; - rd.readLine(); // skip first line; - while ((line = rd.readLine()) != null) { - String[] tokens = line.split(","); - if (tokens.length > 1) { - map.put(tokens[0], tokens[1]); - } - } - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (rd != null) { - try { - rd.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - return map; - } - - void lookupReobfName(String confPath) { - Map nameMap; - nameMap = loadReobfMap(confPath + "packaged.srg"); - for (Clas c : ac) { - String s = nameMap.get(c.name); - AngelicaTweaker.LOGGER.trace("C {} {}", c.name, s); - } - for (Fiel f : af) { - String s = nameMap.get(f.clas + "/" + f.name); - AngelicaTweaker.LOGGER.trace("F {} {}", f.name, s); - } - for (Meth m : am) { - String s = nameMap.get(m.clas + "/" + m.name + m.desc); - AngelicaTweaker.LOGGER.trace("M {} {}", m.name, s); - } - } - - Map loadReobfMap(String fileName) { - Map map = new HashMap<>(); - BufferedReader rd = null; - try { - rd = new BufferedReader(new FileReader(fileName)); - String line; - while ((line = rd.readLine()) != null) { - String[] tokens = line.split(" "); - if (tokens.length > 1) { - if ("CL:".equals(tokens[0])) { - map.put(tokens[2], tokens[1]); - } else if ("FD:".equals(tokens[0])) { - map.put(tokens[2], tokens[1]); - } else if ("MD:".equals(tokens[0])) { - map.put(tokens[3] + tokens[4], tokens[1].substring(tokens[1].lastIndexOf('/') + 1)); - } - } - } - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (rd != null) { - try { - rd.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - return map; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/NamerSrg.java b/src/main/java/com/gtnewhorizons/angelica/transform/NamerSrg.java deleted file mode 100644 index 95e76b6ee..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/NamerSrg.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -import static com.gtnewhorizons.angelica.transform.Names.*; - -public class NamerSrg extends Namer { - - public void setNames() { - setNamesSrg(); - } - - public void setNamesSrg() { - entityRenderer_ = c("net/minecraft/client/renderer/EntityRenderer"); - rendererLivingE_ = c("net/minecraft/client/renderer/entity/RendererLivingEntity"); - entityLivingBase_ = c("net/minecraft/entity/EntityLivingBase"); - - entityRenderer_renderHand = m(entityRenderer_, "func_78476_b", "(FI)V"); - rendererLivingE_doRender = m(rendererLivingE_, "func_76986_a", "(" + entityLivingBase_.desc + "DDDFF)V"); - rendererLivingE_renderEquippedItems = m(rendererLivingE_, "func_77029_c", "(" + entityLivingBase_.desc + "F)V"); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/Names.java b/src/main/java/com/gtnewhorizons/angelica/transform/Names.java deleted file mode 100644 index 4ff1492f4..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/Names.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -import org.objectweb.asm.tree.MethodInsnNode; - -public class Names { - - public static class Name { - - String clas; - String name; - String desc; - - public Name(String clas, String name, String desc) { - this.clas = clas; - this.name = name; - this.desc = desc; - } - - public Name set(String clas, String name, String desc) { - this.clas = clas; - this.name = name; - this.desc = desc; - return this; - } - - public boolean equals(String clas, String name, String desc) { - return this.clas.equals(clas) && this.name.equals(name) && this.desc.equals(desc); - } - } - - public static class Type extends Name { - - public Type(String desc) { - super("", "", desc); - } - - public Type(String name, String desc) { - super(name, name, desc); - } - } - - public static class Clas extends Type { - - public Clas(String name) { - super(name, "L" + name + ";"); - } - - public boolean equals(String clas) { - return this.clas.equals(clas); - } - } - - public static class Fiel extends Name { - - public Fiel(Clas clas, String name, String desc) { - super(clas.clas, name, desc); - } - - public boolean equals(String clas, String name) { - return this.clas.equals(clas) && this.name.equals(name); - } - } - - public static class Meth extends Name { - - public Meth(Clas clas, String name, String desc) { - super(clas.clas, name, desc); - } - - public boolean equalsNameDesc(String name, String desc) { - return this.name.equals(name) && this.desc.equals(desc); - } - } - - static Clas entityRenderer_; - static Clas rendererLivingE_; - static Clas entityLivingBase_; - - static Meth entityRenderer_renderHand; - static Meth rendererLivingE_doRender; - static Meth rendererLivingE_renderEquippedItems; - - public static boolean equals(String clas1, String name1, String desc1, String clas2, String name2, String desc2) { - return clas1.equals(clas2) && name1.equals(name2) && desc1.equals(desc2); - } - - public static boolean equals(MethodInsnNode node, String owner, String name, String desc) { - return node.owner.equals(owner) && node.name.equals(name) && node.desc.equals(desc); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 8d5e41d6e..6774dc140 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.transform; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.coderbot.iris.IrisLogging; @@ -8,7 +9,11 @@ import org.spongepowered.asm.lib.ClassReader; import org.spongepowered.asm.lib.ClassWriter; import org.spongepowered.asm.lib.Opcodes; -import org.spongepowered.asm.lib.tree.*; +import org.spongepowered.asm.lib.tree.AbstractInsnNode; +import org.spongepowered.asm.lib.tree.ClassNode; +import org.spongepowered.asm.lib.tree.FieldInsnNode; +import org.spongepowered.asm.lib.tree.MethodInsnNode; +import org.spongepowered.asm.lib.tree.MethodNode; import java.util.Arrays; import java.util.List; @@ -28,9 +33,11 @@ public class RedirectorTransformer implements IClassTransformer { private static final String GL14 = "org/lwjgl/opengl/GL14"; private static final String EXTBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate"; private static final String ARBMultiTexture = "org/lwjgl/opengl/ARBMultitexture"; - private static final String tessellatorClass = "net/minecraft/client/renderer/Tessellator"; + private static final String TessellatorClass = "net/minecraft/client/renderer/Tessellator"; + private static final String MinecraftClient = "net.minecraft.client"; + private static final Set ExcludedMinecraftMainThreadChecks = ImmutableSet.of("startGame", "initializeTextures"); - private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, EXTBlendFunc, ARBMultiTexture, tessellatorClass); + private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, EXTBlendFunc, ARBMultiTexture, TessellatorClass); private static final Map> EnabledRedirects = ImmutableMap.of( GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", @@ -87,7 +94,7 @@ public byte[] transform(final String className, String transformedName, byte[] b remaps++; } } else if (node.getOpcode() == Opcodes.GETSTATIC && node instanceof FieldInsnNode fNode) { - if ((fNode.name.equals("field_78398_a") || fNode.name.equals("instance")) && fNode.owner.equals("net/minecraft/client/renderer/Tessellator")) { + if ((fNode.name.equals("field_78398_a") || fNode.name.equals("instance")) && fNode.owner.equals(TessellatorClass)) { if (IrisLogging.ENABLE_SPAM) { AngelicaTweaker.LOGGER.info("Redirecting Tessellator.instance field in {} to TessellatorManager.get()", transformedName); } @@ -96,7 +103,7 @@ public byte[] transform(final String className, String transformedName, byte[] b } } } - if (ASSERT_MAIN_THREAD && redirectInMethod) { + if (ASSERT_MAIN_THREAD && redirectInMethod && !(className.startsWith(MinecraftClient) && ExcludedMinecraftMainThreadChecks.contains(mn.name))) { mn.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, GLStateTracker, "assertMainThread", "()V", false)); } } From 527b1fb11bfaa3167e40e84c939e2255ef0bce9e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 27 Nov 2023 09:32:08 -0500 Subject: [PATCH 161/301] Clean up chunk load/unload tracking, fix chunks rendering without neighbors sometimes --- .../gtnewhorizons/angelica/mixins/Mixins.java | 3 +- .../sodium/MixinChunkProviderClient.java | 66 +------------------ .../sodium/MixinNetHandlerPlayClient.java | 27 -------- .../mixins/early/sodium/MixinWorldClient.java | 27 +++----- .../interfaces/IHasClientChunkProvider.java | 8 --- .../mixins/interfaces/IWorldClientExt.java | 5 -- .../client/render/SodiumWorldRenderer.java | 6 +- .../render/chunk/ChunkRenderManager.java | 11 +--- .../context/ChunkRenderCacheShared.java | 4 +- .../client/world/IChunkProviderClientExt.java | 7 -- 10 files changed, 17 insertions(+), 147 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNetHandlerPlayClient.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasClientChunkProvider.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IWorldClientExt.java delete mode 100644 src/main/java/me/jellysquid/mods/sodium/client/world/IChunkProviderClientExt.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 0a7cefb7c..218070f4e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -73,11 +73,10 @@ public enum Mixins { ,"sodium.MixinFrustrum" ,"sodium.MixinMaterial" ,"sodium.MixinMinecraft" - ,"sodium.MixinNetHandlerPlayClient" ,"sodium.MixinNibbleArray" ,"sodium.MixinRenderGlobal" - ,"sodium.MixinTessellator" ,"sodium.MixinWorldClient" + ,"sodium.MixinTessellator" ,"sodium.MixinGuiIngameForge" ,"sodium.MixinEffectRenderer" // TODO Doesn't work correctly diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java index 5af74436b..afdaa4399 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderClient.java @@ -1,78 +1,18 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; -import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; -import me.jellysquid.mods.sodium.client.world.IChunkProviderClientExt; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import net.minecraft.client.multiplayer.ChunkProviderClient; -import net.minecraft.world.chunk.Chunk; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -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.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(ChunkProviderClient.class) -public abstract class MixinChunkProviderClient implements IChunkProviderClientExt { - private ChunkStatusListener sodium$listener; - private final LongOpenHashSet sodium$loadedChunks = new LongOpenHashSet(); - @Unique private boolean sodium$needsTrackingUpdate = false; - - @Shadow private Chunk blankChunk; - @Shadow public abstract Chunk provideChunk(int x, int z); - - @Override - public void setListener(ChunkStatusListener listener) { - this.sodium$listener = listener; - } - - - public void doPostChunk(int x, int z) { - if (this.sodium$listener != null) { - this.sodium$listener.onChunkAdded(x, z); - this.sodium$loadedChunks.add(ChunkPos.toLong(x, z)); - } - } +public abstract class MixinChunkProviderClient { @Inject(method="unloadChunk", at=@At("TAIL")) private void sodium$unloadChunk(int x, int z, CallbackInfo ci) { - if (this.sodium$listener != null) { - this.sodium$listener.onChunkRemoved(x, z); - this.sodium$loadedChunks.remove(ChunkPos.toLong(x, z)); - } - } - - - @Inject(method="unloadQueuedChunks", at=@At("TAIL")) - private void afterTick(CallbackInfoReturnable cir) { - // TODO: sodium$needsTrackingUpdate - is it Relevant here? - // Gets set on Sodium by afterChunkMapCenterChanged & afterLoadDistanceChanged - if (!this.sodium$needsTrackingUpdate) { - return; - } - - LongIterator it = this.sodium$loadedChunks.iterator(); - - while (it.hasNext()) { - long pos = it.nextLong(); - - int x = ChunkPos.getPackedX(pos); - int z = ChunkPos.getPackedZ(pos); - - if (provideChunk(x, z) == blankChunk) { - it.remove(); - - if (this.sodium$listener != null) { - this.sodium$listener.onChunkRemoved(x, z); - } - } - } - - this.sodium$needsTrackingUpdate = false; + SodiumWorldRenderer.getInstance().onChunkRemoved(x, z); } - } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNetHandlerPlayClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNetHandlerPlayClient.java deleted file mode 100644 index 5bdf9e14c..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinNetHandlerPlayClient.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.sodium; - -import com.gtnewhorizons.angelica.mixins.interfaces.IWorldClientExt; -import com.llamalad7.mixinextras.sugar.Local; -import net.minecraft.client.multiplayer.WorldClient; -import net.minecraft.client.network.NetHandlerPlayClient; -import net.minecraft.network.play.server.S21PacketChunkData; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(NetHandlerPlayClient.class) -public class MixinNetHandlerPlayClient { - @Shadow private WorldClient clientWorldController; - - @Inject(method = "handleChunkData", at= @At(value="INVOKE", target="Lnet/minecraft/client/multiplayer/WorldClient;markBlockRangeForRenderUpdate(IIIIII)V", shift = At.Shift.AFTER)) - private void sodium$afterChunkData(S21PacketChunkData packetIn, CallbackInfo ci) { - ((IWorldClientExt)this.clientWorldController).doPostChunk(packetIn.func_149273_e(), packetIn.func_149271_f()); - } - - @Inject(method = "handleMapChunkBulk", at= @At(value="INVOKE", target="Lnet/minecraft/client/multiplayer/WorldClient;markBlockRangeForRenderUpdate(IIIIII)V", shift = At.Shift.AFTER)) - private void sodium$afterMapChunkBulk(CallbackInfo ci, @Local(name = "j") int x, @Local(name = "k") int z) { - ((IWorldClientExt)this.clientWorldController).doPostChunk(x, z); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java index 0189adf4c..2fce47c04 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinWorldClient.java @@ -1,26 +1,17 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.mixins.interfaces.IHasClientChunkProvider; -import com.gtnewhorizons.angelica.mixins.interfaces.IWorldClientExt; -import me.jellysquid.mods.sodium.client.world.IChunkProviderClientExt; -import net.minecraft.client.multiplayer.ChunkProviderClient; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import net.minecraft.client.multiplayer.WorldClient; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(WorldClient.class) -public abstract class MixinWorldClient implements BlockRenderView, IHasClientChunkProvider, IWorldClientExt { - @Shadow - private ChunkProviderClient clientChunkProvider; - - @Override - public ChunkProviderClient getClientChunkProvider() { - return clientChunkProvider; - } - - @Override - public void doPostChunk(int x, int z) { - ((IChunkProviderClientExt)this.clientChunkProvider).doPostChunk(x, z); +public class MixinWorldClient { + @Inject(method = "doPreChunk", at = @At("TAIL")) + private void sodium$loadChunk(int x, int z, boolean load, CallbackInfo ci) { + if(load) + SodiumWorldRenderer.getInstance().onChunkAdded(x, z); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasClientChunkProvider.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasClientChunkProvider.java deleted file mode 100644 index dafe4e950..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IHasClientChunkProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.interfaces; - -import net.minecraft.client.multiplayer.ChunkProviderClient; - -public interface IHasClientChunkProvider { - ChunkProviderClient getClientChunkProvider(); - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IWorldClientExt.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IWorldClientExt.java deleted file mode 100644 index e52d7ec27..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IWorldClientExt.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.interfaces; - -public interface IWorldClientExt { - void doPostChunk(int x, int z); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 3363c727e..ad55ce2f5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -6,7 +6,6 @@ import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.glsm.GLStateManager; -import com.gtnewhorizons.angelica.mixins.interfaces.IHasClientChunkProvider; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; @@ -26,7 +25,6 @@ import me.jellysquid.mods.sodium.client.render.pipeline.context.ChunkRenderCacheShared; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; -import me.jellysquid.mods.sodium.client.world.IChunkProviderClientExt; import me.jellysquid.mods.sodium.common.util.ListUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; @@ -130,12 +128,10 @@ private void loadWorld(WorldClient world) { ChunkRenderCacheShared.createRenderContext(this.world); this.initRenderer(); - - ((IChunkProviderClientExt) ((IHasClientChunkProvider)world).getClientChunkProvider()).setListener(this); } private void unloadWorld() { - ChunkRenderCacheShared.destroyRenderContext((BlockRenderView)this.world); + ChunkRenderCacheShared.destroyRenderContext(this.world); if (this.chunkRenderManager != null) { this.chunkRenderManager.destroy(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index a38d3e147..1df235fa3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -615,18 +615,9 @@ public void scheduleRebuild(int x, int y, int z, boolean important) { important = important || this.isChunkPrioritized(render); // Only enqueue chunks for updates if they aren't already enqueued for an update - // - // We should avoid rebuilding chunks that aren't visible by using data from the occlusion culler, however - // that is not currently feasible because occlusion culling data is only ever updated when chunks are - // rebuilt. Computation of occlusion data needs to be isolated from chunk rebuilds for that to be feasible. - // - // TODO: Avoid rebuilding chunks that aren't visible to the player if (render.scheduleRebuild(important)) { - (render.needsImportantRebuild() ? this.importantRebuildQueue : this.rebuildQueue) - .enqueue(render); + this.dirty = true; } - - this.dirty = true; } this.builder.onChunkDataChanged(x, y, z); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java index 8274f6ece..9eff8c618 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java @@ -34,7 +34,7 @@ private void resetCache() { this.lightCache.clearCache(); } - public static ChunkRenderCacheShared getInstance(BlockRenderView world) { + public static ChunkRenderCacheShared getInstance(WorldClient world) { ChunkRenderCacheShared instance = INSTANCES.get(world); if (instance == null) { @@ -44,7 +44,7 @@ public static ChunkRenderCacheShared getInstance(BlockRenderView world) { return instance; } - public static void destroyRenderContext(BlockRenderView world) { + public static void destroyRenderContext(WorldClient world) { if (INSTANCES.remove(world) == null) { throw new IllegalStateException("No render context exists for world: " + world); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/IChunkProviderClientExt.java b/src/main/java/me/jellysquid/mods/sodium/client/world/IChunkProviderClientExt.java deleted file mode 100644 index fca2d2440..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/IChunkProviderClientExt.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.world; - -public interface IChunkProviderClientExt { - // TODO: allow multiple listeners to be added? - void setListener(ChunkStatusListener listener); - void doPostChunk(int x, int z); -} From bc44f716f0d70f04f6e538dadd3ef59f2001f404 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 27 Nov 2023 09:38:20 -0500 Subject: [PATCH 162/301] Fix occlusion culler not re-running after important uploads Backport of https://github.com/CaffeineMC/sodium-fabric/pull/755 --- .../mods/sodium/client/render/chunk/ChunkRenderManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 1df235fa3..21f885eda 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -539,6 +539,7 @@ public void updateChunks() { this.dirty |= this.builder.performPendingUploads(); if (!futures.isEmpty()) { + this.dirty = true; this.backend.upload(RenderDevice.INSTANCE.createCommandList(), new FutureDequeDrain<>(futures)); } } From 106e694b7f767153e39670ba9acebdb806a36884 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 27 Nov 2023 09:43:53 -0500 Subject: [PATCH 163/301] Add chunks to queues without going through occlusion culler Partially reverts the previous chunk tracking commit, because that logic will reintroduce https://github.com/CaffeineMC/sodium-fabric/issues/605 As long as we only rebuild with neighbors present, we shouldn't see the visual seams --- .../sodium/client/render/chunk/ChunkRenderManager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 21f885eda..87edcdfeb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -616,9 +616,12 @@ public void scheduleRebuild(int x, int y, int z, boolean important) { important = important || this.isChunkPrioritized(render); // Only enqueue chunks for updates if they aren't already enqueued for an update - if (render.scheduleRebuild(important)) { - this.dirty = true; + if (render.scheduleRebuild(important) && render.canRebuild()) { + (render.needsImportantRebuild() ? this.importantRebuildQueue : this.rebuildQueue) + .enqueue(render); } + + this.dirty = true; } this.builder.onChunkDataChanged(x, y, z); From 33f35be73baa64c2207c0dcbaf46a7934d5ca366 Mon Sep 17 00:00:00 2001 From: Asek3 <64613894+Asek3@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:50:38 +0200 Subject: [PATCH 164/301] Correct air checking --- .../client/render/chunk/tasks/ChunkRenderRebuildTask.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 636c96f4b..800db1c8c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -21,6 +21,7 @@ import me.jellysquid.mods.sodium.common.config.SodiumConfig; import net.coderbot.iris.vertices.ExtendedDataHelper; import net.minecraft.block.Block; +import net.minecraft.block.material.Material; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; @@ -115,7 +116,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB // If the block is vanilla air, assume it renders nothing. Don't use isAir because mods // can abuse it for all sorts of things - if (block == Blocks.air) { + if (block.getMaterial() == Material.air) { continue; } From 183a553072aa1f313adf61b71342e5eddc7edc0e Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Mon, 27 Nov 2023 20:20:19 +0100 Subject: [PATCH 165/301] fix obfuscation in RedirectorTransformer --- .../angelica/transform/RedirectorTransformer.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 6774dc140..26aea67c3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -35,7 +35,10 @@ public class RedirectorTransformer implements IClassTransformer { private static final String ARBMultiTexture = "org/lwjgl/opengl/ARBMultitexture"; private static final String TessellatorClass = "net/minecraft/client/renderer/Tessellator"; private static final String MinecraftClient = "net.minecraft.client"; - private static final Set ExcludedMinecraftMainThreadChecks = ImmutableSet.of("startGame", "initializeTextures"); + private static final Set ExcludedMinecraftMainThreadChecks = ImmutableSet.of( + "startGame", "func_71384_a", + "initializeTextures", "func_77474_a" + ); private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, EXTBlendFunc, ARBMultiTexture, TessellatorClass); @@ -103,7 +106,7 @@ public byte[] transform(final String className, String transformedName, byte[] b } } } - if (ASSERT_MAIN_THREAD && redirectInMethod && !(className.startsWith(MinecraftClient) && ExcludedMinecraftMainThreadChecks.contains(mn.name))) { + if (ASSERT_MAIN_THREAD && redirectInMethod && !(transformedName.startsWith(MinecraftClient) && ExcludedMinecraftMainThreadChecks.contains(mn.name))) { mn.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, GLStateTracker, "assertMainThread", "()V", false)); } } From d6fa44213eaf71cc973a3ca7ca7c0c8f5ba50b8e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 27 Nov 2023 14:40:32 -0500 Subject: [PATCH 166/301] Extremely primitive synchronization approach for ISBRH --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../early/sodium/MixinRenderingRegistry.java | 21 +++++++ .../AngelicaBlockRenderingHandler.java | 56 +++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderingRegistry.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockRenderingHandler.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 218070f4e..01892e928 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -79,6 +79,7 @@ public enum Mixins { ,"sodium.MixinTessellator" ,"sodium.MixinGuiIngameForge" ,"sodium.MixinEffectRenderer" + ,"sodium.MixinRenderingRegistry" // TODO Doesn't work correctly //,"sodium.MixinTextureAtlasSprite" //,"sodium.MixinTextureMap" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderingRegistry.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderingRegistry.java new file mode 100644 index 000000000..0008bf28e --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderingRegistry.java @@ -0,0 +1,21 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.rendering.AngelicaBlockRenderingHandler; +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; +import cpw.mods.fml.client.registry.RenderingRegistry; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(RenderingRegistry.class) +public class MixinRenderingRegistry { + @ModifyVariable(method = "registerBlockHandler(Lcpw/mods/fml/client/registry/ISimpleBlockRenderingHandler;)V", at = @At("HEAD"), index = 0, argsOnly = true, remap = false) + private static ISimpleBlockRenderingHandler getThreadSafeWrapper(ISimpleBlockRenderingHandler handler) { + return AngelicaBlockRenderingHandler.forHandler(handler); + } + + @ModifyVariable(method = "registerBlockHandler(ILcpw/mods/fml/client/registry/ISimpleBlockRenderingHandler;)V", at = @At("HEAD"), index = 1, argsOnly = true, remap = false) + private static ISimpleBlockRenderingHandler getThreadSafeWrapper2(ISimpleBlockRenderingHandler handler) { + return AngelicaBlockRenderingHandler.forHandler(handler); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockRenderingHandler.java b/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockRenderingHandler.java new file mode 100644 index 000000000..0bfc054d6 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockRenderingHandler.java @@ -0,0 +1,56 @@ +package com.gtnewhorizons.angelica.rendering; + +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.world.IBlockAccess; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Map; + +public class AngelicaBlockRenderingHandler implements ISimpleBlockRenderingHandler { + private final ISimpleBlockRenderingHandler delegate; + private static final Map HANDLERS = Collections.synchronizedMap(new IdentityHashMap<>()); + private static final Logger LOGGER = LogManager.getLogger("Angelica"); + + public static ISimpleBlockRenderingHandler forHandler(ISimpleBlockRenderingHandler delegate) { + return HANDLERS.computeIfAbsent(delegate, h -> { + // TODO add whitelist + LOGGER.warn("Renderer {} will be synchronized, which may degrade performance", h.getClass().getName()); + return new AngelicaBlockRenderingHandler(h); + }); + } + + private AngelicaBlockRenderingHandler(ISimpleBlockRenderingHandler delegate) { + this.delegate = delegate; + } + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelId, RenderBlocks renderer) { + synchronized (AngelicaBlockRenderingHandler.class) { + this.delegate.renderInventoryBlock(block, metadata, modelId, renderer); + } + } + + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { + synchronized (AngelicaBlockRenderingHandler.class) { + return this.delegate.renderWorldBlock(world, x, y, z, block, modelId, renderer); + } + } + + @Override + public boolean shouldRender3DInInventory(int modelId) { + synchronized (AngelicaBlockRenderingHandler.class) { + return this.delegate.shouldRender3DInInventory(modelId); + } + } + + @Override + public int getRenderId() { + return this.delegate.getRenderId(); + } +} From f73f03682829ff3f13b14b8e1ecfb6e36c25018a Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Mon, 27 Nov 2023 23:22:07 +0100 Subject: [PATCH 167/301] add flag -Dangelica.dumpClass to dump the classes transformed by the RedirectorTransformer --- .../transform/RedirectorTransformer.java | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 26aea67c3..063610d40 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -6,6 +6,8 @@ import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.coderbot.iris.IrisLogging; import net.minecraft.launchwrapper.IClassTransformer; +import net.minecraft.launchwrapper.Launch; +import org.apache.commons.io.FileUtils; import org.spongepowered.asm.lib.ClassReader; import org.spongepowered.asm.lib.ClassWriter; import org.spongepowered.asm.lib.Opcodes; @@ -15,6 +17,10 @@ import org.spongepowered.asm.lib.tree.MethodInsnNode; import org.spongepowered.asm.lib.tree.MethodNode; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -27,6 +33,7 @@ public class RedirectorTransformer implements IClassTransformer { private static final boolean ASSERT_MAIN_THREAD = Boolean.parseBoolean(System.getProperty("angelica.assertMainThread", "false")); + private static final boolean DUMP_CLASSES = Boolean.parseBoolean(System.getProperty("angelica.dumpClass", "false")); private static final String GLStateTracker = "com/gtnewhorizons/angelica/glsm/GLStateManager"; private static final String GL11 = "org/lwjgl/opengl/GL11"; private static final String GL13 = "org/lwjgl/opengl/GL13"; @@ -114,9 +121,45 @@ public byte[] transform(final String className, String transformedName, byte[] b if (changed) { ClassWriter cw = new ClassWriter(0); cn.accept(cw); - return cw.toByteArray(); + final byte[] bytes = cw.toByteArray(); + saveTransformedClass(bytes, transformedName); + return bytes; } return basicClass; } + private File outputDir = null; + + private void saveTransformedClass(final byte[] data, final String transformedName) { + if (!DUMP_CLASSES) { + return; + } + if (outputDir == null) { + outputDir = new File(Launch.minecraftHome, "ASM_REDIRECTOR"); + try { + FileUtils.deleteDirectory(outputDir); + } catch (IOException ignored) {} + if (!outputDir.exists()) { + //noinspection ResultOfMethodCallIgnored + outputDir.mkdirs(); + } + } + final String fileName = transformedName.replace('.', File.separatorChar); + final File classFile = new File(outputDir, fileName + ".class"); + final File outDir = classFile.getParentFile(); + if (!outDir.exists()) { + //noinspection ResultOfMethodCallIgnored + outDir.mkdirs(); + } + if (classFile.exists()) { + //noinspection ResultOfMethodCallIgnored + classFile.delete(); + } + try (final OutputStream output = Files.newOutputStream(classFile.toPath())) { + output.write(data); + } catch (IOException e) { + AngelicaTweaker.LOGGER.error("Could not save transformed class (byte[]) " + transformedName, e); + } + } + } From d8cf17e4a722988364b764bb313536dc4e7f800e Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Tue, 28 Nov 2023 00:46:31 +0100 Subject: [PATCH 168/301] rename some GLStateManager stuff --- .../angelica/glsm/GLStateManager.java | 147 ++++++++---------- .../sodium/client/gl/compat/FogHelper.java | 12 +- .../iris/gl/blending/AlphaTestStorage.java | 2 +- .../iris/gl/blending/DepthColorStorage.java | 2 +- .../DeferredWorldRenderingPipeline.java | 8 +- .../iris/uniforms/CommonUniforms.java | 2 +- 6 files changed, 77 insertions(+), 96 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 630227376..61d7e4629 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -35,25 +35,15 @@ @SuppressWarnings("unused") // Used in ASM public class GLStateManager { // GLStateManager State Trackers - @Getter - private static int activeTexture; - - @Getter - private static final BlendState Blend = new BlendState(); - @Getter - private static final DepthState Depth = new DepthState(); - @Getter - private static final FogState Fog = new FogState(); - @Getter - private static final Color4 Color = new Color4(); - @Getter - private static final Color4 ClearColor = new Color4(); - @Getter - private static final GLColorMask ColorMask = new GLColorMask(); - @Getter - private static final BooleanState Cull = new BooleanState(GL11.GL_CULL_FACE); - @Getter - private static final AlphaState Alpha = new AlphaState(); + @Getter private static int activeTexture; + @Getter private static final BlendState blendState = new BlendState(); + @Getter private static final DepthState depthState = new DepthState(); + @Getter private static final FogState fogState = new FogState(); + @Getter private static final Color4 Color = new Color4(); + @Getter private static final Color4 ClearColor = new Color4(); + @Getter private static final GLColorMask ColorMask = new GLColorMask(); + @Getter private static final BooleanState cullState = new BooleanState(GL11.GL_CULL_FACE); + @Getter private static final AlphaState alphaState = new AlphaState(); private static int modelShadeMode; @@ -62,7 +52,6 @@ public class GLStateManager { // Iris Listeners private static Runnable blendFuncListener = null; - private static Runnable fogToggleListener = null; private static Runnable fogModeListener = null; private static Runnable fogStartListener = null; @@ -71,14 +60,10 @@ public class GLStateManager { // Thread Checking @Getter - private static Thread MainThread; - - static { - MainThread = Thread.currentThread(); - } + private static final Thread MainThread = Thread.currentThread(); public static void init() { - if(AngelicaConfig.enableIris) { + if (AngelicaConfig.enableIris) { StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener; StateUpdateNotifiers.fogToggleNotifier = listener -> fogToggleListener = listener; StateUpdateNotifiers.fogModeNotifier = listener -> fogModeListener = listener; @@ -87,8 +72,7 @@ public static void init() { StateUpdateNotifiers.fogDensityNotifier = listener -> fogDensityListener = listener; } // We want textures regardless of Iris being initialized, and using SamplerLimits is isolated enough - Textures = (TextureState[]) IntStream.range(0, SamplerLimits.get().getMaxTextureUnits()).mapToObj(i -> new TextureState()).toArray(TextureState[]::new); - + Textures = IntStream.range(0, SamplerLimits.get().getMaxTextureUnits()).mapToObj(i -> new TextureState()).toArray(TextureState[]::new); } public static void assertMainThread() { @@ -97,10 +81,9 @@ public static void assertMainThread() { } } - // LWJGL Overrides public static void glEnable(int cap) { - switch(cap) { + switch (cap) { case GL11.GL_ALPHA_TEST -> enableAlphaTest(); case GL11.GL_BLEND -> enableBlend(); case GL11.GL_DEPTH_TEST -> enableDepthTest(); @@ -111,7 +94,6 @@ public static void glEnable(int cap) { } } - public static void glDisable(int cap) { switch (cap) { case GL11.GL_ALPHA_TEST -> disableAlphaTest(); @@ -133,7 +115,7 @@ public static void enableBlend() { return; } } - Blend.mode.enable(); + blendState.mode.enable(); } public static void disableBlend() { @@ -143,7 +125,7 @@ public static void disableBlend() { return; } } - Blend.mode.disable(); + blendState.mode.disable(); } public static void glBlendFunc(int srcFactor, int dstFactor) { @@ -153,8 +135,8 @@ public static void glBlendFunc(int srcFactor, int dstFactor) { return; } } - Blend.srcRgb = srcFactor; - Blend.dstRgb = dstFactor; + blendState.srcRgb = srcFactor; + blendState.dstRgb = dstFactor; GL11.glBlendFunc(srcFactor, dstFactor); // Iris @@ -168,10 +150,10 @@ public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int return; } } - Blend.srcRgb = srcRgb; - Blend.dstRgb = dstRgb; - Blend.srcAlpha = srcAlpha; - Blend.dstAlpha = dstAlpha; + blendState.srcRgb = srcRgb; + blendState.dstRgb = dstRgb; + blendState.srcAlpha = srcAlpha; + blendState.dstAlpha = dstAlpha; GL14.glBlendFuncSeparate(srcRgb, dstRgb, srcAlpha, dstAlpha); // Iris @@ -179,8 +161,8 @@ public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int } public static void glDepthFunc(int func) { - if(func != Depth.func) { - Depth.func = func; + if (func != depthState.func) { + depthState.func = func; GL11.glDepthFunc(func); } } @@ -193,13 +175,14 @@ public static void glDepthMask(boolean mask) { } } - if(mask != Depth.mask) { - Depth.mask = mask; + if (mask != depthState.mask) { + depthState.mask = mask; GL11.glDepthMask(mask); } } + public static void glColor4f(float red, float green, float blue, float alpha) { - if(red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { + if (red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { Color.red = red; Color.green = green; Color.blue = blue; @@ -226,7 +209,7 @@ public static void glColorMask(boolean red, boolean green, boolean blue, boolean return; } } - if(red != ColorMask.red || green != ColorMask.green || blue != ColorMask.blue || alpha != ColorMask.alpha) { + if (red != ColorMask.red || green != ColorMask.green || blue != ColorMask.blue || alpha != ColorMask.alpha) { ColorMask.red = red; ColorMask.green = green; ColorMask.blue = blue; @@ -237,7 +220,7 @@ public static void glColorMask(boolean red, boolean green, boolean blue, boolean // Clear Color public static void glClearColor(float red, float green, float blue, float alpha) { - if(red != ClearColor.red || green != ClearColor.green || blue != ClearColor.blue || alpha != ClearColor.alpha) { + if (red != ClearColor.red || green != ClearColor.green || blue != ClearColor.blue || alpha != ClearColor.alpha) { ClearColor.red = red; ClearColor.green = green; ClearColor.blue = blue; @@ -254,7 +237,7 @@ public static void enableAlphaTest() { return; } } - Alpha.mode.enable(); + alphaState.mode.enable(); } public static void disableAlphaTest() { @@ -264,7 +247,7 @@ public static void disableAlphaTest() { return; } } - Alpha.mode.disable(); + alphaState.mode.disable(); } public static void glAlphaFunc(int function, float reference) { @@ -274,8 +257,8 @@ public static void glAlphaFunc(int function, float reference) { return; } } - Alpha.function = function; - Alpha.reference = reference; + alphaState.function = function; + alphaState.reference = reference; GL11.glAlphaFunc(function, reference); } @@ -287,6 +270,7 @@ public static void glActiveTexture(int texture) { GL13.glActiveTexture(texture); } } + public static void glActiveTextureARB(int texture) { final int newTexture = texture - GL13.GL_TEXTURE0; if (activeTexture != newTexture) { @@ -296,7 +280,7 @@ public static void glActiveTextureARB(int texture) { } public static void glBindTexture(int target, int texture) { - if(Textures[activeTexture].binding != texture) { + if (Textures[activeTexture].binding != texture) { Textures[activeTexture].binding = texture; GL11.glBindTexture(target, texture); if (AngelicaConfig.enableIris) { @@ -312,6 +296,7 @@ public static void glTexImage2D(int target, int level, int internalformat, int w } GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } + public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, ByteBuffer pixels) { if (AngelicaConfig.enableIris) { TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels != null ? pixels.asIntBuffer() : (IntBuffer) null); @@ -325,6 +310,7 @@ public static void glDeleteTextures(int id) { } GL11.glDeleteTextures(id); } + public static void glDeleteTextures(IntBuffer ids) { if (AngelicaConfig.enableIris) { for (int id : ids.array()) { @@ -353,7 +339,6 @@ public static void enableTexture() { Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setInputs(StateTracker.INSTANCE.getInputs())); } } - Textures[activeTexture].mode.enable(); } @@ -376,7 +361,6 @@ public static void disableTexture() { Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setInputs(StateTracker.INSTANCE.getInputs())); } } - Textures[activeTexture].mode.disable(); } @@ -394,44 +378,41 @@ public static void setFilter(boolean bilinear, boolean mipmap) { GL11.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() -// Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram); - + // Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram); GL11.glDrawArrays(mode, first, count); } - public static void defaultBlendFunc() { glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); } public static void enableCull() { - Cull.enable(); + cullState.enable(); } public static void disableCull() { - Cull.disable(); + cullState.disable(); } public static void enableDepthTest() { - Depth.mode.enable(); + depthState.mode.enable(); } public static void disableDepthTest() { - Depth.mode.disable(); + depthState.mode.disable(); } public static void enableFog() { - Fog.mode.enable(); + fogState.mode.enable(); if (fogToggleListener != null) { fogToggleListener.run(); } } public static void disableFog() { - Fog.mode.disable(); + fogState.mode.disable(); if (fogToggleListener != null) { fogToggleListener.run(); } @@ -440,59 +421,60 @@ public static void disableFog() { public static void glFog(int pname, FloatBuffer param) { // TODO: Iris Notifier GL11.glFog(pname, param); - if(pname == GL11.GL_FOG_COLOR) { + if (pname == GL11.GL_FOG_COLOR) { final float red = param.get(0); final float green = param.get(1); final float blue = param.get(2); - Fog.fogColor.set(red, green, blue); - Fog.fogAlpha = param.get(3); - Fog.fogColorBuffer.clear(); - Fog.fogColorBuffer.put((FloatBuffer) param.position(0)).flip(); + fogState.fogColor.set(red, green, blue); + fogState.fogAlpha = param.get(3); + fogState.fogColorBuffer.clear(); + fogState.fogColorBuffer.put((FloatBuffer) param.position(0)).flip(); } } public static Vector3d getFogColor() { - return Fog.fogColor; + return fogState.fogColor; } - public static void fogColor(float red, float green, float blue, float alpha) { - if(red != Fog.fogColor.x || green != Fog.fogColor.y || blue != Fog.fogColor.z || alpha != Fog.fogAlpha) { - Fog.fogColor.set(red, green, blue); - Fog.fogAlpha = alpha; - Fog.fogColorBuffer.clear(); - Fog.fogColorBuffer.put(red).put(green).put(blue).put(alpha).flip(); - GL11.glFog(GL11.GL_FOG_COLOR, Fog.fogColorBuffer); + if (red != fogState.fogColor.x || green != fogState.fogColor.y || blue != fogState.fogColor.z || alpha != fogState.fogAlpha) { + fogState.fogColor.set(red, green, blue); + fogState.fogAlpha = alpha; + fogState.fogColorBuffer.clear(); + fogState.fogColorBuffer.put(red).put(green).put(blue).put(alpha).flip(); + GL11.glFog(GL11.GL_FOG_COLOR, fogState.fogColorBuffer); } } + public static void glFogf(int pname, float param) { GL11.glFogf(pname, param); - switch(pname) { + switch (pname) { case GL11.GL_FOG_DENSITY -> { - Fog.density = param; + fogState.density = param; if (fogDensityListener != null) { fogDensityListener.run(); } } case GL11.GL_FOG_START -> { - Fog.start = param; + fogState.start = param; if (fogStartListener != null) { fogStartListener.run(); } } case GL11.GL_FOG_END -> { - Fog.end = param; + fogState.end = param; if (fogEndListener != null) { fogEndListener.run(); } } } } + public static void glFogi(int pname, int param) { GL11.glFogi(pname, param); - if(pname == GL11.GL_FOG_MODE) { - Fog.fogMode = param; + if (pname == GL11.GL_FOG_MODE) { + fogState.fogMode = param; if (fogModeListener != null) { fogModeListener.run(); } @@ -501,7 +483,6 @@ public static void glFogi(int pname, int param) { public static void setFogBlack() { glFogf(GL11.GL_FOG_COLOR, 0.0F); - } public static void glShadeModel(int mode) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java index f325e9c1f..8254916fb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/compat/FogHelper.java @@ -11,24 +11,24 @@ public class FogHelper { public static float red, green, blue; public static float getFogEnd() { - return GLStateManager.getFog().end; + return GLStateManager.getFogState().end; } public static float getFogStart() { - return GLStateManager.getFog().start; + return GLStateManager.getFogState().start; } public static float getFogDensity() { - return GLStateManager.getFog().density; + return GLStateManager.getFogState().density; } /** * Retrieves the current fog mode from the fixed-function pipeline. */ public static ChunkFogMode getFogMode() { - int mode = GLStateManager.getFog().fogMode; + int mode = GLStateManager.getFogState().fogMode; - if(mode == 0 || !GLStateManager.getFog().mode.isEnabled()) + if(mode == 0 || !GLStateManager.getFogState().mode.isEnabled()) return ChunkFogMode.NONE; return switch (mode) { @@ -39,7 +39,7 @@ public static ChunkFogMode getFogMode() { } public static float getFogCutoff() { - int mode = GLStateManager.getFog().fogMode; + int mode = GLStateManager.getFogState().fogMode; return switch (mode) { case GL11.GL_LINEAR -> getFogEnd(); diff --git a/src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java b/src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java index a4af6a6fd..f8ef2ba67 100644 --- a/src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java +++ b/src/main/java/net/coderbot/iris/gl/blending/AlphaTestStorage.java @@ -12,7 +12,7 @@ public class AlphaTestStorage { public static void overrideAlphaTest(AlphaTest override) { if (!alphaTestLocked) { - final AlphaState alphaState = GLStateManager.getAlpha(); + final AlphaState alphaState = GLStateManager.getAlphaState(); // Only save the previous state if the alpha test wasn't already locked originalAlphaTestEnable = alphaState.mode.isEnabled(); diff --git a/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java b/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java index 33344874d..70086ef3f 100644 --- a/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java +++ b/src/main/java/net/coderbot/iris/gl/blending/DepthColorStorage.java @@ -15,7 +15,7 @@ public static void disableDepthColor() { if (!depthColorLocked) { // Only save the previous state if the depth and color mask wasn't already locked GLColorMask colorMask = GLStateManager.getColorMask(); - final DepthState depthState = GLStateManager.getDepth(); + final DepthState depthState = GLStateManager.getDepthState(); originalDepthEnable = depthState.mask; originalColor = new ColorMask(colorMask.red, colorMask.green, colorMask.blue, colorMask.alpha); diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 37d7b8d77..03ec7e096 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -508,10 +508,10 @@ private RenderCondition getCondition(WorldRenderingPhase phase) { case TERRAIN_SOLID, TERRAIN_CUTOUT, TERRAIN_CUTOUT_MIPPED: return RenderCondition.TERRAIN_OPAQUE; case ENTITIES: - if (GLStateManager.getBlend().srcRgb == SRC_ALPHA && - GLStateManager.getBlend().srcAlpha == ONE_MINUS_SRC_ALPHA && - GLStateManager.getBlend().dstRgb == ONE && - GLStateManager.getBlend().dstAlpha == ONE_MINUS_SRC_ALPHA) + if (GLStateManager.getBlendState().srcRgb == SRC_ALPHA && + GLStateManager.getBlendState().srcAlpha == ONE_MINUS_SRC_ALPHA && + GLStateManager.getBlendState().dstRgb == ONE && + GLStateManager.getBlendState().dstAlpha == ONE_MINUS_SRC_ALPHA) { return RenderCondition.ENTITIES_TRANSLUCENT; } else { diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index 9a1775217..3d008e977 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -80,7 +80,7 @@ public static void addCommonUniforms(DynamicUniformHolder uniforms, IdMap idMap, // }, StateUpdateNotifiers.bindTextureNotifier); uniforms.uniform4i("blendFunc", () -> { - final BlendState blend = GLStateManager.getBlend(); + final BlendState blend = GLStateManager.getBlendState(); if(blend.mode.isEnabled()) { return new Vector4i(blend.srcRgb, blend.dstRgb, blend.srcAlpha, blend.dstAlpha); } From 71317141b8b88f27a7092c82df72e67b9a6bc122 Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Tue, 28 Nov 2023 01:14:11 +0100 Subject: [PATCH 169/301] check current blend state in GLStateManager before calling GL method --- .../angelica/glsm/GLStateManager.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 61d7e4629..8db8a6914 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -135,9 +135,11 @@ public static void glBlendFunc(int srcFactor, int dstFactor) { return; } } - blendState.srcRgb = srcFactor; - blendState.dstRgb = dstFactor; - GL11.glBlendFunc(srcFactor, dstFactor); + if (blendState.srcRgb != srcFactor || blendState.dstRgb != dstFactor) { + blendState.srcRgb = srcFactor; + blendState.dstRgb = dstFactor; + GL11.glBlendFunc(srcFactor, dstFactor); + } // Iris if (blendFuncListener != null) blendFuncListener.run(); @@ -150,11 +152,13 @@ public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int return; } } - blendState.srcRgb = srcRgb; - blendState.dstRgb = dstRgb; - blendState.srcAlpha = srcAlpha; - blendState.dstAlpha = dstAlpha; - GL14.glBlendFuncSeparate(srcRgb, dstRgb, srcAlpha, dstAlpha); + if (blendState.srcRgb != srcRgb || blendState.dstRgb != dstRgb || blendState.srcAlpha != srcAlpha || blendState.dstAlpha != dstAlpha) { + blendState.srcRgb = srcRgb; + blendState.dstRgb = dstRgb; + blendState.srcAlpha = srcAlpha; + blendState.dstAlpha = dstAlpha; + GL14.glBlendFuncSeparate(srcRgb, dstRgb, srcAlpha, dstAlpha); + } // Iris if (blendFuncListener != null) blendFuncListener.run(); From 90bfac5a9d7f37d566dccd695b53fb6c8282df1c Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Tue, 28 Nov 2023 02:23:06 +0100 Subject: [PATCH 170/301] directly redirect certain glEnable/Disable calls to the appropriate method in GLStateManager --- .../transform/RedirectorTransformer.java | 60 ++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 063610d40..db0556737 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -14,6 +14,8 @@ import org.spongepowered.asm.lib.tree.AbstractInsnNode; import org.spongepowered.asm.lib.tree.ClassNode; import org.spongepowered.asm.lib.tree.FieldInsnNode; +import org.spongepowered.asm.lib.tree.IntInsnNode; +import org.spongepowered.asm.lib.tree.LdcInsnNode; import org.spongepowered.asm.lib.tree.MethodInsnNode; import org.spongepowered.asm.lib.tree.MethodNode; @@ -22,6 +24,7 @@ import java.io.OutputStream; import java.nio.file.Files; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -50,13 +53,14 @@ public class RedirectorTransformer implements IClassTransformer { private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, EXTBlendFunc, ARBMultiTexture, TessellatorClass); private static final Map> EnabledRedirects = ImmutableMap.of( - GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glEnable", "glDisable", "glDepthFunc", "glDepthMask", + GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glDepthFunc", "glDepthMask", "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor3f", "glColor4f", "glShadeModel", "glFog", "glFogi", "glFogf", "glClearColor") , GL13, Sets.newHashSet("glActiveTexture") , GL14, Sets.newHashSet("glBlendFuncSeparate") , EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") , ARBMultiTexture, Sets.newHashSet("glActiveTextureARB") ); + private static final Map glCapRedirects = new HashMap<>(); private static final List TransformerExclusions = Arrays.asList( "org.lwjgl", @@ -67,6 +71,15 @@ public class RedirectorTransformer implements IClassTransformer { ); private static int remaps = 0; + static { + glCapRedirects.put(org.lwjgl.opengl.GL11.GL_ALPHA_TEST, "AlphaTest"); + glCapRedirects.put(org.lwjgl.opengl.GL11.GL_BLEND, "Blend"); + glCapRedirects.put(org.lwjgl.opengl.GL11.GL_DEPTH_TEST, "DepthTest"); + glCapRedirects.put(org.lwjgl.opengl.GL11.GL_CULL_FACE, "Cull"); + glCapRedirects.put(org.lwjgl.opengl.GL11.GL_TEXTURE_2D, "Texture"); + glCapRedirects.put(org.lwjgl.opengl.GL11.GL_FOG, "Fog"); + } + @Override public byte[] transform(final String className, String transformedName, byte[] basicClass) { if (basicClass == null) return null; @@ -92,16 +105,49 @@ public byte[] transform(final String className, String transformedName, byte[] b boolean redirectInMethod = false; for (AbstractInsnNode node : mn.instructions.toArray()) { if (node instanceof MethodInsnNode mNode) { - final Set redirects = EnabledRedirects.get(mNode.owner); - if (redirects != null && redirects.contains(mNode.name)) { + if (mNode.owner.equals(GL11) && (mNode.name.equals("glEnable") || mNode.name.equals("glDisable")) && mNode.desc.equals("(I)V")) { + final AbstractInsnNode prevNode = node.getPrevious(); + String name = null; + if (prevNode instanceof LdcInsnNode ldcNode) { + name = glCapRedirects.get(((Integer) ldcNode.cst)); + } else if (prevNode instanceof IntInsnNode intNode) { + name = glCapRedirects.get(intNode.operand); + } + if (name != null) { + if (mNode.name.equals("glEnable")) { + name = "enable" + name; + } else { + name = "disable" + name; + } + } if (IrisLogging.ENABLE_SPAM) { - final String shortOwner = mNode.owner.substring(mNode.owner.lastIndexOf("/") + 1); - AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", transformedName, shortOwner, mNode.name, mNode.desc, mNode.name, mNode.desc); + if (name == null) { + AngelicaTweaker.LOGGER.info("Redirecting call in {} from GL11.{}(I)V to GLStateManager.{}(I)V", transformedName, mNode.name, mNode.name); + } else { + AngelicaTweaker.LOGGER.info("Redirecting call in {} from GL11.{}(I)V to GLStateManager.{}()V", transformedName, mNode.name, name); + } + } + mNode.owner = GLStateTracker; + if (name != null) { + mNode.name = name; + mNode.desc = "()V"; + mn.instructions.remove(prevNode); } - ((MethodInsnNode) node).owner = GLStateTracker; changed = true; redirectInMethod = true; remaps++; + } else { + final Set redirects = EnabledRedirects.get(mNode.owner); + if (redirects != null && redirects.contains(mNode.name)) { + if (IrisLogging.ENABLE_SPAM) { + final String shortOwner = mNode.owner.substring(mNode.owner.lastIndexOf("/") + 1); + AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", transformedName, shortOwner, mNode.name, mNode.desc, mNode.name, mNode.desc); + } + mNode.owner = GLStateTracker; + changed = true; + redirectInMethod = true; + remaps++; + } } } else if (node.getOpcode() == Opcodes.GETSTATIC && node instanceof FieldInsnNode fNode) { if ((fNode.name.equals("field_78398_a") || fNode.name.equals("instance")) && fNode.owner.equals(TessellatorClass)) { @@ -119,7 +165,7 @@ public byte[] transform(final String className, String transformedName, byte[] b } if (changed) { - ClassWriter cw = new ClassWriter(0); + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cn.accept(cw); final byte[] bytes = cw.toByteArray(); saveTransformedClass(bytes, transformedName); From d366b438730b9c529cac5fc80e910d58d338c8ab Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Tue, 28 Nov 2023 02:43:10 +0100 Subject: [PATCH 171/301] add GL11.GL_LIGHTING to GLStateManager redirects --- .../gtnewhorizons/angelica/glsm/GLStateManager.java | 11 +++++++++++ .../angelica/transform/RedirectorTransformer.java | 1 + 2 files changed, 12 insertions(+) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 8db8a6914..a8e495a05 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -44,6 +44,7 @@ public class GLStateManager { @Getter private static final GLColorMask ColorMask = new GLColorMask(); @Getter private static final BooleanState cullState = new BooleanState(GL11.GL_CULL_FACE); @Getter private static final AlphaState alphaState = new AlphaState(); + @Getter private static final BooleanState lightingState = new BooleanState(GL11.GL_LIGHTING); private static int modelShadeMode; @@ -88,6 +89,7 @@ public static void glEnable(int cap) { case GL11.GL_BLEND -> enableBlend(); case GL11.GL_DEPTH_TEST -> enableDepthTest(); case GL11.GL_CULL_FACE -> enableCull(); + case GL11.GL_LIGHTING -> enableLighting(); case GL11.GL_TEXTURE_2D -> enableTexture(); case GL11.GL_FOG -> enableFog(); default -> GL11.glEnable(cap); @@ -100,6 +102,7 @@ public static void glDisable(int cap) { case GL11.GL_BLEND -> disableBlend(); case GL11.GL_DEPTH_TEST -> disableDepthTest(); case GL11.GL_CULL_FACE -> disableCull(); + case GL11.GL_LIGHTING -> disableLighting(); case GL11.GL_TEXTURE_2D -> disableTexture(); case GL11.GL_FOG -> disableFog(); default -> GL11.glDisable(cap); @@ -408,6 +411,14 @@ public static void disableDepthTest() { depthState.mode.disable(); } + public static void enableLighting() { + lightingState.enable(); + } + + public static void disableLighting() { + lightingState.disable(); + } + public static void enableFog() { fogState.mode.enable(); if (fogToggleListener != null) { diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index db0556737..ecc0387c5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -76,6 +76,7 @@ public class RedirectorTransformer implements IClassTransformer { glCapRedirects.put(org.lwjgl.opengl.GL11.GL_BLEND, "Blend"); glCapRedirects.put(org.lwjgl.opengl.GL11.GL_DEPTH_TEST, "DepthTest"); glCapRedirects.put(org.lwjgl.opengl.GL11.GL_CULL_FACE, "Cull"); + glCapRedirects.put(org.lwjgl.opengl.GL11.GL_LIGHTING, "Lighting"); glCapRedirects.put(org.lwjgl.opengl.GL11.GL_TEXTURE_2D, "Texture"); glCapRedirects.put(org.lwjgl.opengl.GL11.GL_FOG, "Fog"); } From 187c3144fd82ea142795c83f8eb6f5b3987bc860 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Mon, 27 Nov 2023 18:55:55 -0800 Subject: [PATCH 172/301] Fix silly --- .../java/com/gtnewhorizons/angelica/glsm/GLStateManager.java | 5 +---- .../mods/sodium/client/render/SodiumWorldRenderer.java | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index a8e495a05..d269b0aa1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -203,10 +203,7 @@ public static void glColor3f(float red, float green, float blue) { } public static void clearCurrentColor() { - Color.red = -1.0F; - Color.green = -1.0F; - Color.blue = -1.0F; - Color.alpha = -1.0F; + glColor4f(-1.0F, -1.0F, -1.0F, -1.0F); } public static void glColorMask(boolean red, boolean green, boolean blue, boolean alpha) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index ad55ce2f5..753fb1b53 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -1,11 +1,9 @@ package me.jellysquid.mods.sodium.client.render; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; -import com.gtnewhorizons.angelica.glsm.GLStateManager; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; @@ -242,7 +240,8 @@ public void drawChunkLayer(BlockRenderPass pass, MatrixStack matrixStack, double //pass.endDrawing(); - GLStateManager.clearCurrentColor(); + // Hmm, is this needed? It wasn't doing anything before, and doesn't seem to make a difference when fixed... +// GLStateManager.clearCurrentColor(); } public void reload() { From 22657c95f6aa57ff9968b379846f69e527a1ba9d Mon Sep 17 00:00:00 2001 From: jss2a98aj Date: Tue, 28 Nov 2023 06:11:17 -0500 Subject: [PATCH 173/301] Use factory for Spdium menu createElement outputs This will allow NotFine to use Sodium menu elements and vice versa in a future commit. --- .../client/gui/SodiumGameOptionPages.java | 28 +- .../sodium/client/gui/SodiumGameOptions.java | 51 +--- .../sodium/client/gui/SodiumOptionsGUI.java | 8 +- .../client/gui/options/control/Control.java | 3 +- .../gui/options/control/ControlElement.java | 52 +--- .../gui/options/control/CyclingControl.java | 53 +--- .../gui/options/control/SliderControl.java | 124 +-------- .../gui/options/control/TickBoxControl.java | 69 +---- .../element/ControlElementFactory.java | 16 ++ .../control/element/SodiumControlElement.java | 60 +++++ .../element/SodiumControlElementFactory.java | 253 ++++++++++++++++++ .../gui/options/named/GraphicsMode.java | 26 ++ .../gui/options/named/GraphicsQuality.java | 26 ++ .../client/gui/options/named/NamedState.java | 5 + 14 files changed, 426 insertions(+), 348 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/ControlElementFactory.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElement.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElementFactory.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/GraphicsMode.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/GraphicsQuality.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/NamedState.java diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index cde4225f1..a1db7d2da 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -10,6 +10,8 @@ import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl; import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl; import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl; +import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsMode; +import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsQuality; import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage; import me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw.MultidrawChunkRenderBackend; @@ -116,37 +118,37 @@ public static OptionPage quality() { List groups = new ArrayList<>(); groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsMode.class, vanillaOpts) + .add(OptionImpl.createBuilder(GraphicsMode.class, vanillaOpts) .setName(I18n.format("options.graphics")) .setTooltip(I18n.format("sodium.options.graphics_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsMode.class)) + .setControl(option -> new CyclingControl<>(option, GraphicsMode.class)) .setBinding( (opts, value) -> opts.fancyGraphics = value.isFancy(), - opts -> SodiumGameOptions.GraphicsMode.fromBoolean(opts.fancyGraphics)) + opts -> GraphicsMode.fromBoolean(opts.fancyGraphics)) .setImpact(OptionImpact.HIGH) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build()) .build()); groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .add(OptionImpl.createBuilder(GraphicsQuality.class, sodiumOpts) .setName(I18n.format("options.renderClouds")) .setTooltip(I18n.format("sodium.options.clouds_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setControl(option -> new CyclingControl<>(option, GraphicsQuality.class)) .setBinding((opts, value) -> opts.quality.cloudQuality = value, opts -> opts.quality.cloudQuality) .setImpact(OptionImpact.LOW) .build()) - .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .add(OptionImpl.createBuilder(GraphicsQuality.class, sodiumOpts) .setName(I18n.format("soundCategory.weather")) .setTooltip(I18n.format("sodium.options.weather_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setControl(option -> new CyclingControl<>(option, GraphicsQuality.class)) .setBinding((opts, value) -> opts.quality.weatherQuality = value, opts -> opts.quality.weatherQuality) .setImpact(OptionImpact.MEDIUM) .build()) - .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .add(OptionImpl.createBuilder(GraphicsQuality.class, sodiumOpts) .setName(I18n.format("sodium.options.leaves_quality.name")) .setTooltip(I18n.format("sodium.options.leaves_quality.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setControl(option -> new CyclingControl<>(option, GraphicsQuality.class)) .setBinding((opts, value) -> opts.quality.leavesQuality = value, opts -> opts.quality.leavesQuality) .setImpact(OptionImpact.MEDIUM) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) @@ -183,17 +185,17 @@ public static OptionPage quality() { .setImpact(OptionImpact.MEDIUM) .build() )*/ - .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .add(OptionImpl.createBuilder(GraphicsQuality.class, sodiumOpts) .setName(I18n.format("options.entityShadows")) .setTooltip(I18n.format("sodium.options.entity_shadows.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setControl(option -> new CyclingControl<>(option, GraphicsQuality.class)) .setBinding((opts, value) -> opts.quality.entityShadows = value, opts -> opts.quality.entityShadows) .setImpact(OptionImpact.LOW) .build()) - .add(OptionImpl.createBuilder(SodiumGameOptions.GraphicsQuality.class, sodiumOpts) + .add(OptionImpl.createBuilder(GraphicsQuality.class, sodiumOpts) .setName(I18n.format("sodium.options.vignette.name")) .setTooltip(I18n.format("sodium.options.vignette.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.GraphicsQuality.class)) + .setControl(option -> new CyclingControl<>(option, GraphicsQuality.class)) .setBinding((opts, value) -> opts.quality.enableVignette = value, opts -> opts.quality.enableVignette) .setImpact(OptionImpact.LOW) .build()) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 1078122d9..507a45531 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -5,6 +5,8 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; import me.jellysquid.mods.sodium.client.SodiumClientMod; +import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsQuality; +import me.jellysquid.mods.sodium.client.gui.options.named.NamedState; import net.minecraft.client.Minecraft; @@ -66,10 +68,6 @@ public static class NotificationSettings { public boolean hideDonationButton = false; } - public interface NamedState { - String getKey(); - } - public enum ParticleMode implements NamedState { ALL("options.particles.all"), DECREASED("options.particles.decreased"), @@ -93,51 +91,6 @@ public static ParticleMode fromOrdinal(int ordinal) { } } - public enum GraphicsMode implements NamedState { - FANCY("options.graphics.fancy"), - FAST("options.graphics.fast"); - - private final String name; - - GraphicsMode(String name) { - this.name = name; - } - - @Override - public String getKey() { - return this.name; - } - - public boolean isFancy() { - return this == FANCY; - } - - public static GraphicsMode fromBoolean(boolean isFancy) { - return isFancy ? FANCY : FAST; - } - } - - public enum GraphicsQuality implements NamedState { - DEFAULT("generator.default"), - FANCY("options.graphics.fancy"), - FAST("options.graphics.fast"); - - private final String name; - - GraphicsQuality(String name) { - this.name = name; - } - - @Override - public String getKey() { - return this.name; - } - - public boolean isFancy() { - return this == FANCY || (this == DEFAULT && Minecraft.getMinecraft().gameSettings.fancyGraphics); - } - } - public enum LightingQuality implements NamedState { OFF("options.ao.off"), LOW("options.ao.min"), diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java index c56af7603..f7860366a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java @@ -13,6 +13,7 @@ import me.jellysquid.mods.sodium.client.gui.options.OptionPage; import me.jellysquid.mods.sodium.client.gui.options.control.Control; import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; +import me.jellysquid.mods.sodium.client.gui.options.control.element.SodiumControlElementFactory; import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; import me.jellysquid.mods.sodium.client.gui.utils.Drawable; import me.jellysquid.mods.sodium.client.gui.utils.Element; @@ -36,6 +37,8 @@ public class SodiumOptionsGUI extends GuiScreen { + private static final SodiumControlElementFactory elementFactory = new SodiumControlElementFactory(); + private final List children = new CopyOnWriteArrayList<>(); private final List pages = new ArrayList<>(); @@ -167,10 +170,11 @@ private void rebuildGUIOptions() { // Add each option's control element for (Option option : group.getOptions()) { Control control = option.getControl(); - ControlElement element = control.createElement(new Dim2i(x, y, 200, 18)); + ControlElement element = control.createElement(new Dim2i(x, y, 200, 18), elementFactory); this.controls.add(element); - this.children.add(element); + //Safe if SodiumControlElementFactory or a compatible ControlElementFactory is used to create element. + this.children.add((Element)element); // Move down to the next option y += 18; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java index 28931db82..509f27a5f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java @@ -1,12 +1,13 @@ package me.jellysquid.mods.sodium.client.gui.options.control; import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.control.element.ControlElementFactory; import me.jellysquid.mods.sodium.client.util.Dim2i; public interface Control { Option getOption(); - ControlElement createElement(Dim2i dim); + ControlElement createElement(Dim2i dim, ControlElementFactory factory); int getMaxWidth(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java index 0b3cadfeb..d64a4eac6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java @@ -5,53 +5,9 @@ import me.jellysquid.mods.sodium.client.util.Dim2i; import net.minecraft.util.EnumChatFormatting; -public class ControlElement extends AbstractWidget { - protected final Option option; +public interface ControlElement { + public boolean isHovered(); + public Option getOption(); + public Dim2i getDimensions(); - protected final Dim2i dim; - - protected boolean hovered; - - public ControlElement(Option option, Dim2i dim) { - this.option = option; - this.dim = dim; - } - - public boolean isHovered() { - return this.hovered; - } - - @Override - public void render(int mouseX, int mouseY, float delta) { - String name = this.option.getName(); - String label; - - if (this.hovered && this.font.getStringWidth(name) > (this.dim.getWidth() - this.option.getControl().getMaxWidth())) { - name = name.substring(0, Math.min(name.length(), 10)) + "..."; - } - - if (this.option.isAvailable()) { - if (this.option.hasChanged()) { - label = EnumChatFormatting.ITALIC + name + " *"; - } else { - label = EnumChatFormatting.WHITE + name; - } - } else { - label = String.valueOf(EnumChatFormatting.GRAY) + EnumChatFormatting.STRIKETHROUGH + name; - } - - this.hovered = this.dim.containsCursor(mouseX, mouseY); - - - this.drawRect(this.dim.getOriginX(), this.dim.getOriginY(), this.dim.getLimitX(), this.dim.getLimitY(), this.hovered ? 0xE0000000 : 0x90000000); - this.drawString(label, this.dim.getOriginX() + 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); - } - - public Option getOption() { - return this.option; - } - - public Dim2i getDimensions() { - return this.dim; - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java index 981f980bd..3b87e1e1d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java @@ -1,7 +1,8 @@ package me.jellysquid.mods.sodium.client.gui.options.control; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.control.element.ControlElementFactory; +import me.jellysquid.mods.sodium.client.gui.options.named.NamedState; import me.jellysquid.mods.sodium.client.util.Dim2i; import net.minecraft.client.resources.I18n; import org.apache.commons.lang3.Validate; @@ -37,7 +38,7 @@ public CyclingControl(Option option, Class enumType, T[] allowedValues) { String name; T value = universe[i]; - name = I18n.format(value instanceof SodiumGameOptions.NamedState namedState ? namedState.getKey() : value.name()); + name = I18n.format(value instanceof NamedState namedState ? namedState.getKey() : value.name()); this.names[i] = name; } @@ -49,8 +50,8 @@ public Option getOption() { } @Override - public ControlElement createElement(Dim2i dim) { - return new CyclingControlElement<>(this.option, dim, this.allowedValues, this.names); + public ControlElement createElement(Dim2i dim, ControlElementFactory factory) { + return factory.cyclingControlElement(this.option, dim, this.allowedValues, this.names); } @Override @@ -58,48 +59,4 @@ public int getMaxWidth() { return 70; } - private static class CyclingControlElement> extends ControlElement { - private final T[] allowedValues; - private final String[] names; - private int currentIndex; - - public CyclingControlElement(Option option, Dim2i dim, T[] allowedValues, String[] names) { - super(option, dim); - - this.allowedValues = allowedValues; - this.names = names; - this.currentIndex = 0; - - for (int i = 0; i < allowedValues.length; i++) { - if (allowedValues[i] == option.getValue()) { - this.currentIndex = i; - break; - } - } - } - - @Override - public void render(int mouseX, int mouseY, float delta) { - super.render(mouseX, mouseY, delta); - - Enum value = this.option.getValue(); - String name = this.names[value.ordinal()]; - - int strWidth = this.getTextWidth(name); - this.drawString(name, this.dim.getLimitX() - strWidth - 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { - this.currentIndex = (this.option.getValue().ordinal() + 1) % this.allowedValues.length; - this.option.setValue(this.allowedValues[this.currentIndex]); - this.playClickSound(); - - return true; - } - - return false; - } - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java index e95ae893f..d7b5b8f5b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.gui.options.control; import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.control.element.ControlElementFactory; import me.jellysquid.mods.sodium.client.gui.utils.Rect2i; import me.jellysquid.mods.sodium.client.util.Dim2i; import net.minecraft.util.MathHelper; @@ -27,8 +28,8 @@ public SliderControl(Option option, int min, int max, int interval, Con } @Override - public ControlElement createElement(Dim2i dim) { - return new Button(this.option, dim, this.min, this.max, this.interval, this.mode); + public ControlElement createElement(Dim2i dim, ControlElementFactory factory) { + return factory.sliderControlElement(this.option, dim, this.min, this.max, this.interval, this.mode); } @Override @@ -41,123 +42,4 @@ public int getMaxWidth() { return 130; } - private static class Button extends ControlElement { - private static final int THUMB_WIDTH = 2, TRACK_HEIGHT = 1; - - private final Rect2i sliderBounds; - private final ControlValueFormatter formatter; - - private final int min; - private final int range; - private final int interval; - - private double thumbPosition; - - public Button(Option option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter) { - super(option, dim); - - this.min = min; - this.range = max - min; - this.interval = interval; - this.thumbPosition = this.getThumbPositionForValue(option.getValue()); - this.formatter = formatter; - - this.sliderBounds = new Rect2i(dim.getLimitX() - 96, dim.getCenterY() - 5, 90, 10); - } - - @Override - public void render(int mouseX, int mouseY, float delta) { - super.render(mouseX, mouseY, delta); - - if (this.option.isAvailable() && this.hovered) { - this.renderSlider(); - } else { - this.renderStandaloneValue(); - } - } - - private void renderStandaloneValue() { - int sliderX = this.sliderBounds.getX(); - int sliderY = this.sliderBounds.getY(); - int sliderWidth = this.sliderBounds.getWidth(); - int sliderHeight = this.sliderBounds.getHeight(); - - String label = this.formatter.format(this.option.getValue()); - int labelWidth = this.font.getStringWidth(label); - - this.drawString(label, sliderX + sliderWidth - labelWidth, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); - } - - private void renderSlider() { - int sliderX = this.sliderBounds.getX(); - int sliderY = this.sliderBounds.getY(); - int sliderWidth = this.sliderBounds.getWidth(); - int sliderHeight = this.sliderBounds.getHeight(); - - this.thumbPosition = this.getThumbPositionForValue(option.getValue()); - - double thumbOffset = MathHelper.clamp_double((double) (this.getIntValue() - this.min) / this.range * sliderWidth, 0, sliderWidth); - - double thumbX = sliderX + thumbOffset - THUMB_WIDTH; - double trackY = sliderY + (sliderHeight / 2) - ((double) TRACK_HEIGHT / 2); - - this.drawRect(thumbX, sliderY, thumbX + (THUMB_WIDTH * 2), sliderY + sliderHeight, 0xFFFFFFFF); - this.drawRect(sliderX, trackY, sliderX + sliderWidth, trackY + TRACK_HEIGHT, 0xFFFFFFFF); - - String label = String.valueOf(this.getIntValue()); - - int labelWidth = this.font.getStringWidth(label); - - this.drawString(label, sliderX - labelWidth - 6, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); - } - - public int getIntValue() { - return this.min + (this.interval * (int) Math.round(this.getSnappedThumbPosition() / this.interval)); - } - - public double getSnappedThumbPosition() { - return this.thumbPosition / (1.0D / this.range); - } - - public double getThumbPositionForValue(int value) { - return (value - this.min) * (1.0D / this.range); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (this.option.isAvailable() && button == 0 && this.sliderBounds.contains((int) mouseX, (int) mouseY)) { - this.setValueFromMouse(mouseX); - - return true; - } - - return false; - } - - private void setValueFromMouse(double d) { - this.setValue((d - (double) this.sliderBounds.getX()) / (double) this.sliderBounds.getWidth()); - } - - private void setValue(double d) { - this.thumbPosition = MathHelper.clamp_double(d, 0.0D, 1.0D); - - int value = this.getIntValue(); - - if (this.option.getValue() != value) { - this.option.setValue(value); - } - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY) { - if (this.option.isAvailable() && this.sliderBounds.contains((int) mouseX, (int) mouseY)) { - this.setValueFromMouse(mouseX); - - return true; - } - - return false; - } - } - } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java index 8b5cd3cab..fd6144505 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.gui.options.control; import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.control.element.ControlElementFactory; import me.jellysquid.mods.sodium.client.gui.utils.Rect2i; import me.jellysquid.mods.sodium.client.util.Dim2i; @@ -12,8 +13,8 @@ public TickBoxControl(Option option) { } @Override - public ControlElement createElement(Dim2i dim) { - return new TickBoxControlElement(this.option, dim); + public ControlElement createElement(Dim2i dim, ControlElementFactory factory) { + return factory.tickBoxElement(this.option, dim); } @Override @@ -26,68 +27,4 @@ public Option getOption() { return this.option; } - private static class TickBoxControlElement extends ControlElement { - private final Rect2i button; - - public TickBoxControlElement(Option option, Dim2i dim) { - super(option, dim); - - this.button = new Rect2i(dim.getLimitX() - 16, dim.getCenterY() - 5, 10, 10); - } - - @Override - public void render(int mouseX, int mouseY, float delta) { - super.render(mouseX, mouseY, delta); - - final int x = this.button.getX(); - final int y = this.button.getY(); - final int w = x + this.button.getWidth(); - final int h = y + this.button.getHeight(); - - final boolean enabled = this.option.isAvailable(); - final boolean ticked = enabled && this.option.getValue(); - - final int color; - - if (enabled) { - color = ticked ? 0xFF94E4D3 : 0xFFFFFFFF; - } else { - color = 0xFFAAAAAA; - } - - if (ticked) { - this.drawRect(x + 2, y + 2, w - 2, h - 2, color); - } - - this.drawRectOutline(x, y, w, h, color); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { - this.option.setValue(!this.option.getValue()); - this.playClickSound(); - - return true; - } - - return false; - } - - protected void drawRectOutline(int x, int y, int w, int h, int color) { - final float a = (float) (color >> 24 & 255) / 255.0F; - final float r = (float) (color >> 16 & 255) / 255.0F; - final float g = (float) (color >> 8 & 255) / 255.0F; - final float b = (float) (color & 255) / 255.0F; - - this.drawQuads(vertices -> { - addQuad(vertices, x, y, w, y + 1, a, r, g, b); - addQuad(vertices, x, h - 1, w, h, a, r, g, b); - addQuad(vertices, x, y, x + 1, h, a, r, g, b); - addQuad(vertices, w - 1, y, w, h, a, r, g, b); - }); - } - } - - } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/ControlElementFactory.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/ControlElementFactory.java new file mode 100644 index 000000000..75517192e --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/ControlElementFactory.java @@ -0,0 +1,16 @@ +package me.jellysquid.mods.sodium.client.gui.options.control.element; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; +import me.jellysquid.mods.sodium.client.util.Dim2i; + +public interface ControlElementFactory { + + > ControlElement cyclingControlElement(Option option, Dim2i dim, T[] allowedValues, String[] names); + + ControlElement sliderControlElement(Option option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter); + + ControlElement tickBoxElement(Option option, Dim2i dim); + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElement.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElement.java new file mode 100644 index 000000000..8cc8dc905 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElement.java @@ -0,0 +1,60 @@ +package me.jellysquid.mods.sodium.client.gui.options.control.element; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; +import me.jellysquid.mods.sodium.client.gui.widgets.AbstractWidget; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.util.EnumChatFormatting; + +public class SodiumControlElement extends AbstractWidget implements ControlElement { + protected final Option option; + protected final Dim2i dim; + protected boolean hovered; + + public SodiumControlElement(Option option, Dim2i dim) { + this.option = option; + this.dim = dim; + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + String name = this.option.getName(); + String label; + + if (this.hovered && this.font.getStringWidth(name) > (this.dim.getWidth() - this.option.getControl().getMaxWidth())) { + name = name.substring(0, Math.min(name.length(), 10)) + "..."; + } + + if (this.option.isAvailable()) { + if (this.option.hasChanged()) { + label = EnumChatFormatting.ITALIC + name + " *"; + } else { + label = EnumChatFormatting.WHITE + name; + } + } else { + label = String.valueOf(EnumChatFormatting.GRAY) + EnumChatFormatting.STRIKETHROUGH + name; + } + + this.hovered = this.dim.containsCursor(mouseX, mouseY); + + + this.drawRect(this.dim.getOriginX(), this.dim.getOriginY(), this.dim.getLimitX(), this.dim.getLimitY(), this.hovered ? 0xE0000000 : 0x90000000); + this.drawString(label, this.dim.getOriginX() + 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); + } + + @Override + public boolean isHovered() { + return this.hovered; + } + + @Override + public Option getOption() { + return this.option; + } + + @Override + public Dim2i getDimensions() { + return this.dim; + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElementFactory.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElementFactory.java new file mode 100644 index 000000000..8cf67f74a --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/element/SodiumControlElementFactory.java @@ -0,0 +1,253 @@ +package me.jellysquid.mods.sodium.client.gui.options.control.element; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; +import me.jellysquid.mods.sodium.client.gui.utils.Rect2i; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.util.MathHelper; + +public class SodiumControlElementFactory implements ControlElementFactory { + @Override + public > ControlElement cyclingControlElement(Option option, Dim2i dim, T[] allowedValues, String[] names) { + return new CyclingControlElement(option, dim, allowedValues, names); + } + + @Override + public ControlElement sliderControlElement(Option option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter) { + return new SliderControlElement(option, dim, min, max, interval, formatter); + } + + @Override + public ControlElement tickBoxElement(Option option, Dim2i dim) { + return new TickBoxControlElement(option, dim); + } + + private static class CyclingControlElement> extends SodiumControlElement { + private final T[] allowedValues; + private final String[] names; + private int currentIndex; + + public CyclingControlElement(Option option, Dim2i dim, T[] allowedValues, String[] names) { + super(option, dim); + + this.allowedValues = allowedValues; + this.names = names; + this.currentIndex = 0; + + for (int i = 0; i < allowedValues.length; i++) { + if (allowedValues[i] == option.getValue()) { + this.currentIndex = i; + break; + } + } + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + super.render(mouseX, mouseY, delta); + + Enum value = this.option.getValue(); + String name = this.names[value.ordinal()]; + + int strWidth = this.getTextWidth(name); + this.drawString(name, this.dim.getLimitX() - strWidth - 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { + this.currentIndex = (this.option.getValue().ordinal() + 1) % this.allowedValues.length; + this.option.setValue(this.allowedValues[this.currentIndex]); + this.playClickSound(); + + return true; + } + + return false; + } + } + + private static class SliderControlElement extends SodiumControlElement { + private static final int THUMB_WIDTH = 2, TRACK_HEIGHT = 1; + + private final Rect2i sliderBounds; + private final ControlValueFormatter formatter; + + private final int min; + private final int range; + private final int interval; + + private double thumbPosition; + + public SliderControlElement(Option option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter) { + super(option, dim); + + this.min = min; + this.range = max - min; + this.interval = interval; + this.thumbPosition = this.getThumbPositionForValue(option.getValue()); + this.formatter = formatter; + + this.sliderBounds = new Rect2i(dim.getLimitX() - 96, dim.getCenterY() - 5, 90, 10); + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + super.render(mouseX, mouseY, delta); + + if (this.option.isAvailable() && this.hovered) { + this.renderSlider(); + } else { + this.renderStandaloneValue(); + } + } + + private void renderStandaloneValue() { + int sliderX = this.sliderBounds.getX(); + int sliderY = this.sliderBounds.getY(); + int sliderWidth = this.sliderBounds.getWidth(); + int sliderHeight = this.sliderBounds.getHeight(); + + String label = this.formatter.format(this.option.getValue()); + int labelWidth = this.font.getStringWidth(label); + + this.drawString(label, sliderX + sliderWidth - labelWidth, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); + } + + private void renderSlider() { + int sliderX = this.sliderBounds.getX(); + int sliderY = this.sliderBounds.getY(); + int sliderWidth = this.sliderBounds.getWidth(); + int sliderHeight = this.sliderBounds.getHeight(); + + this.thumbPosition = this.getThumbPositionForValue(option.getValue()); + + double thumbOffset = MathHelper.clamp_double((double) (this.getIntValue() - this.min) / this.range * sliderWidth, 0, sliderWidth); + + double thumbX = sliderX + thumbOffset - THUMB_WIDTH; + double trackY = sliderY + (sliderHeight / 2) - ((double) TRACK_HEIGHT / 2); + + this.drawRect(thumbX, sliderY, thumbX + (THUMB_WIDTH * 2), sliderY + sliderHeight, 0xFFFFFFFF); + this.drawRect(sliderX, trackY, sliderX + sliderWidth, trackY + TRACK_HEIGHT, 0xFFFFFFFF); + + String label = String.valueOf(this.getIntValue()); + + int labelWidth = this.font.getStringWidth(label); + + this.drawString(label, sliderX - labelWidth - 6, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); + } + + public int getIntValue() { + return this.min + (this.interval * (int) Math.round(this.getSnappedThumbPosition() / this.interval)); + } + + public double getSnappedThumbPosition() { + return this.thumbPosition / (1.0D / this.range); + } + + public double getThumbPositionForValue(int value) { + return (value - this.min) * (1.0D / this.range); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (this.option.isAvailable() && button == 0 && this.sliderBounds.contains((int) mouseX, (int) mouseY)) { + this.setValueFromMouse(mouseX); + + return true; + } + + return false; + } + + private void setValueFromMouse(double d) { + this.setValue((d - (double) this.sliderBounds.getX()) / (double) this.sliderBounds.getWidth()); + } + + private void setValue(double d) { + this.thumbPosition = MathHelper.clamp_double(d, 0.0D, 1.0D); + + int value = this.getIntValue(); + + if (this.option.getValue() != value) { + this.option.setValue(value); + } + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY) { + if (this.option.isAvailable() && this.sliderBounds.contains((int) mouseX, (int) mouseY)) { + this.setValueFromMouse(mouseX); + + return true; + } + + return false; + } + } + + private static class TickBoxControlElement extends SodiumControlElement { + private final Rect2i button; + + public TickBoxControlElement(Option option, Dim2i dim) { + super(option, dim); + + this.button = new Rect2i(dim.getLimitX() - 16, dim.getCenterY() - 5, 10, 10); + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + super.render(mouseX, mouseY, delta); + + final int x = this.button.getX(); + final int y = this.button.getY(); + final int w = x + this.button.getWidth(); + final int h = y + this.button.getHeight(); + + final boolean enabled = this.option.isAvailable(); + final boolean ticked = enabled && this.option.getValue(); + + final int color; + + if (enabled) { + color = ticked ? 0xFF94E4D3 : 0xFFFFFFFF; + } else { + color = 0xFFAAAAAA; + } + + if (ticked) { + this.drawRect(x + 2, y + 2, w - 2, h - 2, color); + } + + this.drawRectOutline(x, y, w, h, color); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { + this.option.setValue(!this.option.getValue()); + this.playClickSound(); + + return true; + } + + return false; + } + + protected void drawRectOutline(int x, int y, int w, int h, int color) { + final float a = (float) (color >> 24 & 255) / 255.0F; + final float r = (float) (color >> 16 & 255) / 255.0F; + final float g = (float) (color >> 8 & 255) / 255.0F; + final float b = (float) (color & 255) / 255.0F; + + this.drawQuads(vertices -> { + addQuad(vertices, x, y, w, y + 1, a, r, g, b); + addQuad(vertices, x, h - 1, w, h, a, r, g, b); + addQuad(vertices, x, y, x + 1, h, a, r, g, b); + addQuad(vertices, w - 1, y, w, h, a, r, g, b); + }); + } + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/GraphicsMode.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/GraphicsMode.java new file mode 100644 index 000000000..8dac938de --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/GraphicsMode.java @@ -0,0 +1,26 @@ +package me.jellysquid.mods.sodium.client.gui.options.named; + +public enum GraphicsMode implements NamedState { + FANCY("options.graphics.fancy"), + FAST("options.graphics.fast"); + + private final String name; + + GraphicsMode(String name) { + this.name = name; + } + + @Override + public String getKey() { + return this.name; + } + + public boolean isFancy() { + return this == FANCY; + } + + public static GraphicsMode fromBoolean(boolean isFancy) { + return isFancy ? FANCY : FAST; + } + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/GraphicsQuality.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/GraphicsQuality.java new file mode 100644 index 000000000..ebe46003c --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/GraphicsQuality.java @@ -0,0 +1,26 @@ +package me.jellysquid.mods.sodium.client.gui.options.named; + +import net.minecraft.client.Minecraft; + +public enum GraphicsQuality implements NamedState { + DEFAULT("generator.default"), + FANCY("options.graphics.fancy"), + FAST("options.graphics.fast"); + + private final String name; + + GraphicsQuality(String name) { + this.name = name; + } + + @Override + public String getKey() { + return this.name; + } + + public boolean isFancy() { + return this == FANCY || (this == DEFAULT && Minecraft.getMinecraft().gameSettings.fancyGraphics); + } + +} + diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/NamedState.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/NamedState.java new file mode 100644 index 000000000..b1384b602 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/NamedState.java @@ -0,0 +1,5 @@ +package me.jellysquid.mods.sodium.client.gui.options.named; + +public interface NamedState { + String getKey(); +} From b44f8c53a3b0763f72fa62073d132eb208534a16 Mon Sep 17 00:00:00 2001 From: jss2a98aj Date: Tue, 28 Nov 2023 06:15:36 -0500 Subject: [PATCH 174/301] Remove some unused imports (oops) --- .../mods/sodium/client/gui/options/control/SliderControl.java | 2 -- .../mods/sodium/client/gui/options/control/TickBoxControl.java | 1 - 2 files changed, 3 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java index d7b5b8f5b..05e71dc51 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java @@ -2,9 +2,7 @@ import me.jellysquid.mods.sodium.client.gui.options.Option; import me.jellysquid.mods.sodium.client.gui.options.control.element.ControlElementFactory; -import me.jellysquid.mods.sodium.client.gui.utils.Rect2i; import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.util.MathHelper; import org.apache.commons.lang3.Validate; public class SliderControl implements Control { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java index fd6144505..ba5783609 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java @@ -2,7 +2,6 @@ import me.jellysquid.mods.sodium.client.gui.options.Option; import me.jellysquid.mods.sodium.client.gui.options.control.element.ControlElementFactory; -import me.jellysquid.mods.sodium.client.gui.utils.Rect2i; import me.jellysquid.mods.sodium.client.util.Dim2i; public class TickBoxControl implements Control { From e68907b7b4ff1cecc0b5f6f2dd93678fbafad5c3 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 28 Nov 2023 09:36:18 -0800 Subject: [PATCH 175/301] Splash Screen Compat * Hacky workaround for glDepthFunc not being applied properly after splash * better glColor() support with helper function. (Still not complete) --- .../angelica/glsm/GLStateManager.java | 37 +++++++++++++++---- .../gtnewhorizons/angelica/mixins/Mixins.java | 3 +- .../angelica/startup/MixinSplashProgress.java | 21 +++++++++++ .../transform/RedirectorTransformer.java | 36 +++++++++++++----- .../java/net/coderbot/iris/sodium/Mixins.txt | 4 +- 5 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinSplashProgress.java diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index d269b0aa1..3e950ef21 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -62,6 +62,7 @@ public class GLStateManager { // Thread Checking @Getter private static final Thread MainThread = Thread.currentThread(); + private static boolean runningSplash = false; public static void init() { if (AngelicaConfig.enableIris) { @@ -77,7 +78,7 @@ public static void init() { } public static void assertMainThread() { - if (Thread.currentThread() != MainThread) { + if (Thread.currentThread() != MainThread || runningSplash) { throw new IllegalStateException("Not on the main thread!"); } } @@ -168,7 +169,8 @@ public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int } public static void glDepthFunc(int func) { - if (func != depthState.func) { + // Hacky workaround for now, need to figure out why this isn't being applied... + if (func != depthState.func || GLStateManager.runningSplash) { depthState.func = func; GL11.glDepthFunc(func); } @@ -189,17 +191,33 @@ public static void glDepthMask(boolean mask) { } public static void glColor4f(float red, float green, float blue, float alpha) { - if (red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { - Color.red = red; - Color.green = green; - Color.blue = blue; - Color.alpha = alpha; + if (changeColor(red, green, blue, alpha)) { GL11.glColor4f(red, green, blue, alpha); } } public static void glColor3f(float red, float green, float blue) { - glColor4f(red, green, blue, 1.0f); + if(changeColor(red, green, blue, 1.0F)) { + GL11.glColor3f(red, green, blue); + } + } + + public static void glColor3ub(byte red, byte green, byte blue) { + if(changeColor(red, green, blue, 1.0F)) { + GL11.glColor3ub(red, green, blue); + } + } + + private static boolean changeColor(float red, float green, float blue, float alpha) { + // Helper function for glColor* + if(red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { + Color.red = red; + Color.green = green; + Color.blue = blue; + Color.alpha = alpha; + return true; + } + return false; } public static void clearCurrentColor() { @@ -513,4 +531,7 @@ public static void glShadeModel(int mode) { } } + public static void setRunningSplash(boolean runningSplash) { + GLStateManager.runningSplash = runningSplash; + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 01892e928..98403beef 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -14,7 +14,8 @@ public enum Mixins { ANGELICA_STARTUP(new Builder("Angelica Startup").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( - "angelica.startup.MixinInitGLStateManager" + "angelica.startup.MixinInitGLStateManager" + ,"angelica.startup.MixinSplashProgress" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinSplashProgress.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinSplashProgress.java new file mode 100644 index 000000000..dd12d2316 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinSplashProgress.java @@ -0,0 +1,21 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.startup; + +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(targets="cpw/mods/fml/client/SplashProgress$3", remap = false) +public abstract class MixinSplashProgress { + @Inject(method = "setGL", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/locks/Lock;lock()V", shift = At.Shift.AFTER)) + private void angelica$startSplash(CallbackInfo ci) { + GLStateManager.setRunningSplash(true); + } + + @Inject(method = "clearGL", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/locks/Lock;unlock()V", shift = At.Shift.BEFORE)) + private void angelica$endSplash(CallbackInfo ci) { + GLStateManager.setRunningSplash(false); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index ecc0387c5..5d10ddaa7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -45,16 +45,35 @@ public class RedirectorTransformer implements IClassTransformer { private static final String ARBMultiTexture = "org/lwjgl/opengl/ARBMultitexture"; private static final String TessellatorClass = "net/minecraft/client/renderer/Tessellator"; private static final String MinecraftClient = "net.minecraft.client"; + private static final String SplashProgress = "cpw.mods.fml.client.SplashProgress"; private static final Set ExcludedMinecraftMainThreadChecks = ImmutableSet.of( "startGame", "func_71384_a", - "initializeTextures", "func_77474_a" + "initializeTextures", "func_77474_a", + "start" // SplashProgress ); private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, EXTBlendFunc, ARBMultiTexture, TessellatorClass); private static final Map> EnabledRedirects = ImmutableMap.of( - GL11, Sets.newHashSet("glBindTexture", "glTexImage2D", "glDeleteTextures", "glDepthFunc", "glDepthMask", - "glColorMask", "glAlphaFunc", "glDrawArrays", "glColor3f", "glColor4f", "glShadeModel", "glFog", "glFogi", "glFogf", "glClearColor") + GL11, Sets.newHashSet( + "glAlphaFunc" + ,"glBlendFunc" + ,"glClearColor" + ,"glColor3f" + ,"glColor4f" + ,"glColor3ub" + ,"glColorMask" + ,"glDeleteTextures" + ,"glDepthFunc" + ,"glDepthMask" + ,"glDrawArrays" + ,"glFog" + ,"glFogf" + ,"glFogi" + ,"glShadeModel" + ,"glTexImage2D" + ,"glBindTexture" + ) , GL13, Sets.newHashSet("glActiveTexture") , GL14, Sets.newHashSet("glBlendFuncSeparate") , EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") @@ -63,11 +82,10 @@ public class RedirectorTransformer implements IClassTransformer { private static final Map glCapRedirects = new HashMap<>(); private static final List TransformerExclusions = Arrays.asList( - "org.lwjgl", - "com.gtnewhorizons.angelica.glsm.", - "com.gtnewhorizons.angelica.transform", - "me.eigenraven.lwjgl3ify", - "cpw.mods.fml.client.SplashProgress" + "org.lwjgl" + ,"com.gtnewhorizons.angelica.glsm." + ,"com.gtnewhorizons.angelica.transform" + ,"me.eigenraven.lwjgl3ify" ); private static int remaps = 0; @@ -160,7 +178,7 @@ public byte[] transform(final String className, String transformedName, byte[] b } } } - if (ASSERT_MAIN_THREAD && redirectInMethod && !(transformedName.startsWith(MinecraftClient) && ExcludedMinecraftMainThreadChecks.contains(mn.name))) { + if (ASSERT_MAIN_THREAD && redirectInMethod && !((transformedName.startsWith(MinecraftClient) || transformedName.startsWith(SplashProgress)) && ExcludedMinecraftMainThreadChecks.contains(mn.name))) { mn.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, GLStateTracker, "assertMainThread", "()V", false)); } } diff --git a/src/main/java/net/coderbot/iris/sodium/Mixins.txt b/src/main/java/net/coderbot/iris/sodium/Mixins.txt index 5c804ee35..f24e84c43 100644 --- a/src/main/java/net/coderbot/iris/sodium/Mixins.txt +++ b/src/main/java/net/coderbot/iris/sodium/Mixins.txt @@ -12,8 +12,8 @@ Y directional_shading * MixinGameRendererContext.java * MixinChunkRenderManager.java * block_id - X MixinChunkRenderRebuildTask.java - X MixinChunkBuildBuffers.java + Y MixinChunkRenderRebuildTask.java + Y MixinChunkBuildBuffers.java * pbr_animation * MixinTextureAtlasSprite.java * vertex_format From 6125ad85e6f096878266955fdafe0b58ab0eb6ee Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Tue, 28 Nov 2023 23:00:11 +0100 Subject: [PATCH 176/301] add GL12.GL_RESCALE_NORMAL to GLStateManager redirects --- .../gtnewhorizons/angelica/glsm/GLStateManager.java | 12 ++++++++++++ .../angelica/transform/RedirectorTransformer.java | 1 + 2 files changed, 13 insertions(+) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 3e950ef21..b748e0dd1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -24,6 +24,7 @@ import org.joml.Vector3d; import org.lwjgl.opengl.ARBMultitexture; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL14; @@ -45,6 +46,7 @@ public class GLStateManager { @Getter private static final BooleanState cullState = new BooleanState(GL11.GL_CULL_FACE); @Getter private static final AlphaState alphaState = new AlphaState(); @Getter private static final BooleanState lightingState = new BooleanState(GL11.GL_LIGHTING); + @Getter private static final BooleanState rescaleNormalState = new BooleanState(GL12.GL_RESCALE_NORMAL); private static int modelShadeMode; @@ -91,6 +93,7 @@ public static void glEnable(int cap) { case GL11.GL_DEPTH_TEST -> enableDepthTest(); case GL11.GL_CULL_FACE -> enableCull(); case GL11.GL_LIGHTING -> enableLighting(); + case GL12.GL_RESCALE_NORMAL -> enableRescaleNormal(); case GL11.GL_TEXTURE_2D -> enableTexture(); case GL11.GL_FOG -> enableFog(); default -> GL11.glEnable(cap); @@ -104,6 +107,7 @@ public static void glDisable(int cap) { case GL11.GL_DEPTH_TEST -> disableDepthTest(); case GL11.GL_CULL_FACE -> disableCull(); case GL11.GL_LIGHTING -> disableLighting(); + case GL12.GL_RESCALE_NORMAL -> disableRescaleNormal(); case GL11.GL_TEXTURE_2D -> disableTexture(); case GL11.GL_FOG -> disableFog(); default -> GL11.glDisable(cap); @@ -434,6 +438,14 @@ public static void disableLighting() { lightingState.disable(); } + public static void enableRescaleNormal() { + rescaleNormalState.enable(); + } + + public static void disableRescaleNormal() { + rescaleNormalState.disable(); + } + public static void enableFog() { fogState.mode.enable(); if (fogToggleListener != null) { diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 5d10ddaa7..d567fc44e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -97,6 +97,7 @@ public class RedirectorTransformer implements IClassTransformer { glCapRedirects.put(org.lwjgl.opengl.GL11.GL_LIGHTING, "Lighting"); glCapRedirects.put(org.lwjgl.opengl.GL11.GL_TEXTURE_2D, "Texture"); glCapRedirects.put(org.lwjgl.opengl.GL11.GL_FOG, "Fog"); + glCapRedirects.put(org.lwjgl.opengl.GL12.GL_RESCALE_NORMAL, "RescaleNormal"); } @Override From da946b3604b57a08b28e9f59b4d28ef795530a8f Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Wed, 29 Nov 2023 00:52:27 +0100 Subject: [PATCH 177/301] move getMixins method to Mixins enum --- .../angelica/loading/AngelicaLateMixins.java | 14 +- .../angelica/loading/AngelicaTweaker.java | 14 +- .../gtnewhorizons/angelica/mixins/Mixins.java | 145 +++++++++++------- 3 files changed, 89 insertions(+), 84 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java index bb83cdf6c..d04451c00 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java @@ -35,22 +35,10 @@ public String getMixinConfig() { @Override public List getMixins(Set loadedMods) { - final List mixins = new ArrayList<>(); - final List notLoading = new ArrayList<>(); - for (Mixins mixin : Mixins.values()) { - if (mixin.phase == Mixins.Phase.LATE) { - if (mixin.shouldLoad(Collections.emptySet(), loadedMods)) { - mixins.addAll(mixin.mixinClasses); - } else { - notLoading.addAll(mixin.mixinClasses); - } - } - } - AngelicaTweaker.LOGGER.info("Not loading the following LATE mixins: {}", notLoading.toString()); + return Mixins.getLateMixins(loadedMods); // TODO: Sodium // mixins.addAll(getNotFineMixins(loadedMods)); // mixins.addAll(getArchaicMixins(loadedMods)); - return mixins; } private List getNotFineMixins(Set loadedMods) { diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index b56356876..e7aa27a7d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -85,22 +85,10 @@ public String getMixinConfig() { @Override public List getMixins(Set loadedCoreMods) { - final List mixins = new ArrayList<>(); - final List notLoading = new ArrayList<>(); - for (Mixins mixin : Mixins.values()) { - if (mixin.phase == Mixins.Phase.EARLY) { - if (mixin.shouldLoad(loadedCoreMods, Collections.emptySet())) { - mixins.addAll(mixin.mixinClasses); - } else { - notLoading.addAll(mixin.mixinClasses); - } - } - } - LOGGER.info("Not loading the following EARLY mixins: {}", notLoading); // TODO: Sodium // mixins.addAll(getNotFineMixins(loadedCoreMods)); // mixins.addAll(getArchaicMixins(loadedCoreMods)); - return mixins; + return Mixins.getEarlyMixins(loadedCoreMods); } private List getNotFineMixins(Set loadedCoreMods) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 98403beef..7ff90317e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -2,11 +2,13 @@ import com.gtnewhorizons.angelica.AngelicaMod; import com.gtnewhorizons.angelica.config.AngelicaConfig; +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import cpw.mods.fml.relauncher.FMLLaunchHandler; import me.jellysquid.mods.sodium.common.config.SodiumConfig; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Set; import java.util.function.Supplier; @@ -129,61 +131,14 @@ public enum Mixins { ; - public final String name; - public final List mixinClasses; + private final List mixinClasses; private final Supplier applyIf; - public final Phase phase; + private final Phase phase; private final Side side; - public final List targetedMods; - public final List excludedMods; - - private static class Builder { - - private final String name; - private final List mixinClasses = new ArrayList<>(); - private Supplier applyIf = () -> true; - private Side side = Side.BOTH; - private Phase phase = Phase.LATE; - private final List targetedMods = new ArrayList<>(); - private final List excludedMods = new ArrayList<>(); - - public Builder(String name) { - this.name = name; - } - - public Builder addMixinClasses(String... mixinClasses) { - this.mixinClasses.addAll(Arrays.asList(mixinClasses)); - return this; - } - - public Builder setPhase(Phase phase) { - this.phase = phase; - return this; - } - - public Builder setSide(Side side) { - this.side = side; - return this; - } - - public Builder setApplyIf(Supplier applyIf) { - this.applyIf = applyIf; - return this; - } - - public Builder addTargetedMod(TargetedMod mod) { - this.targetedMods.add(mod); - return this; - } - - public Builder addExcludedMod(TargetedMod mod) { - this.excludedMods.add(mod); - return this; - } - } + private final List targetedMods; + private final List excludedMods; Mixins(Builder builder) { - this.name = builder.name; this.mixinClasses = builder.mixinClasses; this.applyIf = builder.applyIf; this.side = builder.side; @@ -191,16 +146,48 @@ public Builder addExcludedMod(TargetedMod mod) { this.excludedMods = builder.excludedMods; this.phase = builder.phase; if (this.targetedMods.isEmpty()) { - throw new RuntimeException("No targeted mods specified for " + this.name); + throw new RuntimeException("No targeted mods specified for " + this.name()); } if (this.applyIf == null) { - throw new RuntimeException("No ApplyIf function specified for " + this.name); + throw new RuntimeException("No ApplyIf function specified for " + this.name()); + } + } + + public static List getEarlyMixins(Set loadedCoreMods) { + final List mixins = new ArrayList<>(); + final List notLoading = new ArrayList<>(); + for (Mixins mixin : Mixins.values()) { + if (mixin.phase == Mixins.Phase.EARLY) { + if (mixin.shouldLoad(loadedCoreMods, Collections.emptySet())) { + mixins.addAll(mixin.mixinClasses); + } else { + notLoading.addAll(mixin.mixinClasses); + } + } } + AngelicaTweaker.LOGGER.info("Not loading the following EARLY mixins: {}", notLoading); + return mixins; + } + + public static List getLateMixins(Set loadedMods) { + final List mixins = new ArrayList<>(); + final List notLoading = new ArrayList<>(); + for (Mixins mixin : Mixins.values()) { + if (mixin.phase == Mixins.Phase.LATE) { + if (mixin.shouldLoad(Collections.emptySet(), loadedMods)) { + mixins.addAll(mixin.mixinClasses); + } else { + notLoading.addAll(mixin.mixinClasses); + } + } + } + AngelicaTweaker.LOGGER.info("Not loading the following LATE mixins: {}", notLoading.toString()); + return mixins; } private boolean shouldLoadSide() { - return (side == Side.BOTH || (side == Side.SERVER && FMLLaunchHandler.side().isServer()) - || (side == Side.CLIENT && FMLLaunchHandler.side().isClient())); + return side == Side.BOTH || (side == Side.SERVER && FMLLaunchHandler.side().isServer()) + || (side == Side.CLIENT && FMLLaunchHandler.side().isClient()); } private boolean allModsLoaded(List targetedMods, Set loadedCoreMods, Set loadedMods) { @@ -235,19 +222,61 @@ private boolean noModsLoaded(List targetedMods, Set loadedC return true; } - public boolean shouldLoad(Set loadedCoreMods, Set loadedMods) { + private boolean shouldLoad(Set loadedCoreMods, Set loadedMods) { return (shouldLoadSide() && applyIf.get() && allModsLoaded(targetedMods, loadedCoreMods, loadedMods) && noModsLoaded(excludedMods, loadedCoreMods, loadedMods)); } - enum Side { + private static class Builder { + + private final List mixinClasses = new ArrayList<>(); + private Supplier applyIf = () -> true; + private Side side = Side.BOTH; + private Phase phase = Phase.LATE; + private final List targetedMods = new ArrayList<>(); + private final List excludedMods = new ArrayList<>(); + + public Builder(@SuppressWarnings("unused") String description) {} + + public Builder addMixinClasses(String... mixinClasses) { + this.mixinClasses.addAll(Arrays.asList(mixinClasses)); + return this; + } + + public Builder setPhase(Phase phase) { + this.phase = phase; + return this; + } + + public Builder setSide(Side side) { + this.side = side; + return this; + } + + public Builder setApplyIf(Supplier applyIf) { + this.applyIf = applyIf; + return this; + } + + public Builder addTargetedMod(TargetedMod mod) { + this.targetedMods.add(mod); + return this; + } + + public Builder addExcludedMod(TargetedMod mod) { + this.excludedMods.add(mod); + return this; + } + } + + private enum Side { BOTH, CLIENT, SERVER } - public enum Phase { + private enum Phase { EARLY, LATE, } From abf2f3604eb64cae33d3bbfda0c7f863a05f7d32 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 28 Nov 2023 16:16:11 -0800 Subject: [PATCH 178/301] More glColor variants found in mods --- .../angelica/glsm/GLStateManager.java | 31 ++++++++++++++++++- .../angelica/glsm/states/Color4.java | 8 ++--- .../transform/RedirectorTransformer.java | 7 ++++- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index b748e0dd1..653d9cae5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -199,6 +199,23 @@ public static void glColor4f(float red, float green, float blue, float alpha) { GL11.glColor4f(red, green, blue, alpha); } } + public static void glColor4d(double red, double green, double blue, double alpha) { + if (changeColor(red, green, blue, alpha)) { + GL11.glColor4d(red, green, blue, alpha); + } + } + + public static void glColor4b(byte red, byte green, byte blue, byte alpha) { + if (changeColor(red, green, blue, alpha)) { + GL11.glColor4b(red, green, blue, alpha); + } + } + + public static void glColor4ub(byte red, byte green, byte blue, byte alpha) { + if (changeColor(red, green, blue, alpha)) { + GL11.glColor4ub(red, green, blue, alpha); + } + } public static void glColor3f(float red, float green, float blue) { if(changeColor(red, green, blue, 1.0F)) { @@ -206,13 +223,25 @@ public static void glColor3f(float red, float green, float blue) { } } + public static void glColor3d(double red, double green, double blue) { + if(changeColor(red, green, blue, 1.0F)) { + GL11.glColor3d(red, green, blue); + } + } + + public static void glColor3b(byte red, byte green, byte blue) { + if(changeColor(red, green, blue, 1.0F)) { + GL11.glColor3b(red, green, blue); + } + } + public static void glColor3ub(byte red, byte green, byte blue) { if(changeColor(red, green, blue, 1.0F)) { GL11.glColor3ub(red, green, blue); } } - private static boolean changeColor(float red, float green, float blue, float alpha) { + private static boolean changeColor(double red, double green, double blue, double alpha) { // Helper function for glColor* if(red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { Color.red = red; diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java index c86b0af44..783e73218 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java @@ -1,9 +1,9 @@ package com.gtnewhorizons.angelica.glsm.states; public class Color4 { - public float red = 1.0F; - public float green = 1.0F; - public float blue = 1.0F; - public float alpha = 1.0F; + public double red = 1.0F; + public double green = 1.0F; + public double blue = 1.0F; + public double alpha = 1.0F; } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index d567fc44e..53a4239f6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -60,8 +60,13 @@ public class RedirectorTransformer implements IClassTransformer { ,"glBlendFunc" ,"glClearColor" ,"glColor3f" - ,"glColor4f" + ,"glColor3d" + ,"glColor3b" ,"glColor3ub" + ,"glColor4f" + ,"glColor4d" + ,"glColor4b" + ,"glColor4ub" ,"glColorMask" ,"glDeleteTextures" ,"glDepthFunc" From cd34781f710cc084f089039edcede430e98f166c Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 28 Nov 2023 16:39:46 -0800 Subject: [PATCH 179/301] glBlendFuncSeparateEXT --- .../angelica/glsm/GLStateManager.java | 20 +++++++++++++++++++ .../transform/RedirectorTransformer.java | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 653d9cae5..fb8fa58fe 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -23,6 +23,7 @@ import net.coderbot.iris.texture.pbr.PBRTextureManager; import org.joml.Vector3d; import org.lwjgl.opengl.ARBMultitexture; +import org.lwjgl.opengl.EXTBlendFuncSeparate; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL13; @@ -172,6 +173,25 @@ public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int if (blendFuncListener != null) blendFuncListener.run(); } + public static void glBlendFuncSeparateEXT(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { + if (AngelicaConfig.enableIris) { + if (BlendModeStorage.isBlendLocked()) { + BlendModeStorage.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); + return; + } + } + if (blendState.srcRgb != srcRgb || blendState.dstRgb != dstRgb || blendState.srcAlpha != srcAlpha || blendState.dstAlpha != dstAlpha) { + blendState.srcRgb = srcRgb; + blendState.dstRgb = dstRgb; + blendState.srcAlpha = srcAlpha; + blendState.dstAlpha = dstAlpha; + EXTBlendFuncSeparate.glBlendFuncSeparateEXT(srcRgb, dstRgb, srcAlpha, dstAlpha); + } + + // Iris + if (blendFuncListener != null) blendFuncListener.run(); + } + public static void glDepthFunc(int func) { // Hacky workaround for now, need to figure out why this isn't being applied... if (func != depthState.func || GLStateManager.runningSplash) { diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 53a4239f6..ca4858814 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -81,7 +81,7 @@ public class RedirectorTransformer implements IClassTransformer { ) , GL13, Sets.newHashSet("glActiveTexture") , GL14, Sets.newHashSet("glBlendFuncSeparate") - , EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparate") + , EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparateEXT") , ARBMultiTexture, Sets.newHashSet("glActiveTextureARB") ); private static final Map glCapRedirects = new HashMap<>(); From fb3198ee0bbe65b3b14ceff0aed18ab274a74ecd Mon Sep 17 00:00:00 2001 From: jss2a98aj Date: Tue, 28 Nov 2023 22:51:22 -0500 Subject: [PATCH 180/301] Separate remaining NamedState enums --- .../early/sodium/MixinRenderManager.java | 5 +- .../client/gui/SodiumGameOptionPages.java | 14 ++--- .../sodium/client/gui/SodiumGameOptions.java | 53 ------------------- .../gui/options/control/ControlElement.java | 2 - .../gui/options/named/LightingQuality.java | 31 +++++++++++ .../gui/options/named/ParticleMode.java | 24 +++++++++ 6 files changed, 65 insertions(+), 64 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/LightingQuality.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/ParticleMode.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java index b7a1ffa47..5484c81a8 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderManager.java @@ -1,7 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; +import me.jellysquid.mods.sodium.client.gui.options.named.LightingQuality; import me.jellysquid.mods.sodium.client.model.light.EntityLighter; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.entity.RenderManager; @@ -18,7 +17,7 @@ public class MixinRenderManager { */ @Redirect(method = "renderEntityStatic", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;getBrightnessForRender(F)I")) private int sodium$getBrightnessForRender(Entity self, float partialTicks) { - if (Minecraft.getMinecraft().gameSettings.ambientOcclusion == SodiumGameOptions.LightingQuality.HIGH.getVanilla()) { + if (Minecraft.getMinecraft().gameSettings.ambientOcclusion == LightingQuality.HIGH.getVanilla()) { return EntityLighter.getBlendedLight(self, partialTicks); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index a1db7d2da..942af23c0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -12,6 +12,8 @@ import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl; import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsMode; import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsQuality; +import me.jellysquid.mods.sodium.client.gui.options.named.LightingQuality; +import me.jellysquid.mods.sodium.client.gui.options.named.ParticleMode; import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage; import me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw.MultidrawChunkRenderBackend; @@ -153,18 +155,18 @@ public static OptionPage quality() { .setImpact(OptionImpact.MEDIUM) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build()) - .add(OptionImpl.createBuilder(SodiumGameOptions.ParticleMode.class, vanillaOpts) + .add(OptionImpl.createBuilder(ParticleMode.class, vanillaOpts) .setName(I18n.format("options.particles")) .setTooltip(I18n.format("sodium.options.particle_quality.tooltip")) - .setControl(opt -> new CyclingControl<>(opt, SodiumGameOptions.ParticleMode.class)) - .setBinding((opts, value) -> opts.particleSetting = value.ordinal(), (opts) -> SodiumGameOptions.ParticleMode.fromOrdinal(opts.particleSetting)) + .setControl(opt -> new CyclingControl<>(opt, ParticleMode.class)) + .setBinding((opts, value) -> opts.particleSetting = value.ordinal(), (opts) -> ParticleMode.fromOrdinal(opts.particleSetting)) .setImpact(OptionImpact.LOW) .build()) - .add(OptionImpl.createBuilder(SodiumGameOptions.LightingQuality.class, vanillaOpts) + .add(OptionImpl.createBuilder(LightingQuality.class, vanillaOpts) .setName(I18n.format("options.ao")) .setTooltip(I18n.format("sodium.options.smooth_lighting.tooltip")) - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.LightingQuality.class)) - .setBinding((opts, value) -> opts.ambientOcclusion = value.getVanilla(), opts -> SodiumGameOptions.LightingQuality.fromOrdinal(opts.ambientOcclusion)) + .setControl(option -> new CyclingControl<>(option, LightingQuality.class)) + .setBinding((opts, value) -> opts.ambientOcclusion = value.getVanilla(), opts -> LightingQuality.fromOrdinal(opts.ambientOcclusion)) .setImpact(OptionImpact.MEDIUM) .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) .build()) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 507a45531..18ebd8af2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -68,59 +68,6 @@ public static class NotificationSettings { public boolean hideDonationButton = false; } - public enum ParticleMode implements NamedState { - ALL("options.particles.all"), - DECREASED("options.particles.decreased"), - MINIMAL("options.particles.minimal"); - - private static final ParticleMode[] VALUES = values(); - - private final String name; - - ParticleMode(String name) { - this.name = name; - } - - @Override - public String getKey() { - return this.name; - } - - public static ParticleMode fromOrdinal(int ordinal) { - return VALUES[ordinal]; - } - } - - public enum LightingQuality implements NamedState { - OFF("options.ao.off"), - LOW("options.ao.min"), - HIGH("options.ao.max"); - - private static final LightingQuality[] VALUES = values(); - - private final String name; - - private final int vanilla; - - LightingQuality(String name) { - this.name = name; - this.vanilla = ordinal(); - } - - @Override - public String getKey() { - return this.name; - } - - public int getVanilla() { - return vanilla; - } - - public static LightingQuality fromOrdinal(int ordinal) { - return VALUES[ordinal]; - } - } - private static final Gson GSON = new GsonBuilder() .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .setPrettyPrinting() diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java index d64a4eac6..b8a09e6fd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java @@ -1,9 +1,7 @@ package me.jellysquid.mods.sodium.client.gui.options.control; import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.gui.widgets.AbstractWidget; import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.util.EnumChatFormatting; public interface ControlElement { public boolean isHovered(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/LightingQuality.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/LightingQuality.java new file mode 100644 index 000000000..dbcbe6321 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/LightingQuality.java @@ -0,0 +1,31 @@ +package me.jellysquid.mods.sodium.client.gui.options.named; + +public enum LightingQuality implements NamedState { + OFF("options.ao.off"), + LOW("options.ao.min"), + HIGH("options.ao.max"); + + private static final LightingQuality[] VALUES = values(); + + private final String name; + + private final int vanilla; + + LightingQuality(String name) { + this.name = name; + this.vanilla = ordinal(); + } + + @Override + public String getKey() { + return this.name; + } + + public int getVanilla() { + return vanilla; + } + + public static LightingQuality fromOrdinal(int ordinal) { + return VALUES[ordinal]; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/ParticleMode.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/ParticleMode.java new file mode 100644 index 000000000..d22dd679d --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/named/ParticleMode.java @@ -0,0 +1,24 @@ +package me.jellysquid.mods.sodium.client.gui.options.named; + +public enum ParticleMode implements NamedState { + ALL("options.particles.all"), + DECREASED("options.particles.decreased"), + MINIMAL("options.particles.minimal"); + + private static final ParticleMode[] VALUES = values(); + + private final String name; + + ParticleMode(String name) { + this.name = name; + } + + @Override + public String getKey() { + return this.name; + } + + public static ParticleMode fromOrdinal(int ordinal) { + return VALUES[ordinal]; + } +} From 0f493c738e133a99f96bd2d60b79b0ce2ac7b926 Mon Sep 17 00:00:00 2001 From: jss2a98aj Date: Tue, 28 Nov 2023 23:36:03 -0500 Subject: [PATCH 181/301] NotFine but it loads Sodium pages --- .../AngelicaEntityRenderDistanceSetting.java | 31 -- .../client/gui/AngelicaVideoSettings.java | 3 +- .../gui/GuiEntityRenderDistanceSlider.java | 11 - .../notfine/clouds/MixinRenderGlobal.java | 13 +- .../early/notfine/clouds/MixinWorldType.java | 2 +- .../notfine/faceculling/MixinBlockStairs.java | 4 +- .../notfine/glint/MixinItemRenderer.java | 2 +- .../early/notfine/glint/MixinRenderBiped.java | 2 +- .../early/notfine/glint/MixinRenderItem.java | 4 +- .../notfine/glint/MixinRenderPlayer.java | 2 +- .../early/notfine/gui/MixinGuiSlot.java | 2 +- .../notfine/leaves/MixinBlockLeaves.java | 5 +- .../notfine/leaves/MixinBlockLeavesBase.java | 2 +- .../particles/MixinBlockEnchantmentTable.java | 32 +- .../notfine/particles/MixinWorldClient.java | 2 +- .../notfine/particles/MixinWorldProvider.java | 2 +- .../notfine/renderer/MixinRenderGlobal.java | 2 +- .../thaumcraft/MixinBlockMagicalLeaves.java | 3 +- .../twilightforest/MixinBlockTFLeaves.java | 3 +- .../twilightforest/MixinBlockTFLeaves3.java | 3 +- .../MixinBlockTFMagicLeaves.java | 3 +- .../witchery/MixinBlockWitchLeaves.java | 3 +- .../angelica/proxy/ClientProxy.java | 16 - src/main/java/jss/notfine/NotFine.java | 10 +- .../jss/notfine/config/VideoSettings.java | 58 ++++ .../notfine/config/VideoSettingsConfig.java | 52 --- .../jss/notfine/core/LoadMenuButtons.java | 34 -- src/main/java/jss/notfine/core/Settings.java | 300 ++++++++++++------ .../jss/notfine/core/SettingsManager.java | 127 +++----- .../java/jss/notfine/gui/GuiCustomMenu.java | 85 ++--- .../jss/notfine/gui/GuiCustomMenuButton.java | 17 +- ...List.java => GuiCustomOptionsRowList.java} | 49 ++- .../notfine/gui/GuiCustomSettingButton.java | 27 -- .../notfine/gui/GuiCustomSettingSlider.java | 65 ---- .../notfine/gui/GuiVanillaSettingButton.java | 27 -- .../notfine/gui/GuiVanillaSettingSlider.java | 68 ---- .../java/jss/notfine/gui/ISettingHandler.java | 7 - .../java/jss/notfine/gui/ISettingsEnum.java | 17 - .../java/jss/notfine/gui/MenuButtonLists.java | 116 ------- .../notfine/gui/NotFineGameOptionPages.java | 223 +++++++++++++ .../control/NotFineControlValueFormatter.java | 15 + .../element/CyclingControlElement.java | 42 +++ .../element/NotFineControlElement.java | 76 +++++ .../element/NotFineControlElementFactory.java | 26 ++ .../control/element/SliderControlElement.java | 85 +++++ .../element/TickBoxControlElement.java | 28 ++ .../gui/options/named/AlwaysNever.java | 21 ++ .../gui/options/named/BackgroundSelect.java | 26 ++ .../gui/options/named/DownfallQuality.java | 23 ++ .../gui/options/named/GraphicsQualityOff.java | 22 ++ .../gui/options/named/GraphicsToggle.java | 21 ++ .../gui/options/named/LeavesQuality.java | 24 ++ .../NotFineMinecraftOptionsStorage.java | 23 ++ .../options/storage/OptionStorageDummy.java | 4 + .../java/jss/notfine/render/RenderStars.java | 2 +- .../java/jss/notfine/util/ILeafBlock.java | 9 +- .../java/jss/notfine/util/LeafRenderUtil.java | 7 +- .../mods/sodium/client/SodiumClientMod.java | 5 +- .../sodium/client/gui/SodiumOptionsGUI.java | 6 +- 59 files changed, 1110 insertions(+), 789 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaEntityRenderDistanceSetting.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/gui/GuiEntityRenderDistanceSlider.java create mode 100644 src/main/java/jss/notfine/config/VideoSettings.java delete mode 100644 src/main/java/jss/notfine/config/VideoSettingsConfig.java delete mode 100644 src/main/java/jss/notfine/core/LoadMenuButtons.java rename src/main/java/jss/notfine/gui/{GuiCustomSettingsRowList.java => GuiCustomOptionsRowList.java} (50%) delete mode 100644 src/main/java/jss/notfine/gui/GuiCustomSettingButton.java delete mode 100644 src/main/java/jss/notfine/gui/GuiCustomSettingSlider.java delete mode 100644 src/main/java/jss/notfine/gui/GuiVanillaSettingButton.java delete mode 100644 src/main/java/jss/notfine/gui/GuiVanillaSettingSlider.java delete mode 100644 src/main/java/jss/notfine/gui/ISettingHandler.java delete mode 100644 src/main/java/jss/notfine/gui/ISettingsEnum.java delete mode 100644 src/main/java/jss/notfine/gui/MenuButtonLists.java create mode 100644 src/main/java/jss/notfine/gui/NotFineGameOptionPages.java create mode 100644 src/main/java/jss/notfine/gui/options/control/NotFineControlValueFormatter.java create mode 100644 src/main/java/jss/notfine/gui/options/control/element/CyclingControlElement.java create mode 100644 src/main/java/jss/notfine/gui/options/control/element/NotFineControlElement.java create mode 100644 src/main/java/jss/notfine/gui/options/control/element/NotFineControlElementFactory.java create mode 100644 src/main/java/jss/notfine/gui/options/control/element/SliderControlElement.java create mode 100644 src/main/java/jss/notfine/gui/options/control/element/TickBoxControlElement.java create mode 100644 src/main/java/jss/notfine/gui/options/named/AlwaysNever.java create mode 100644 src/main/java/jss/notfine/gui/options/named/BackgroundSelect.java create mode 100644 src/main/java/jss/notfine/gui/options/named/DownfallQuality.java create mode 100644 src/main/java/jss/notfine/gui/options/named/GraphicsQualityOff.java create mode 100644 src/main/java/jss/notfine/gui/options/named/GraphicsToggle.java create mode 100644 src/main/java/jss/notfine/gui/options/named/LeavesQuality.java create mode 100644 src/main/java/jss/notfine/gui/options/storage/NotFineMinecraftOptionsStorage.java create mode 100644 src/main/java/jss/notfine/gui/options/storage/OptionStorageDummy.java diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaEntityRenderDistanceSetting.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaEntityRenderDistanceSetting.java deleted file mode 100644 index 52307d84d..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaEntityRenderDistanceSetting.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gtnewhorizons.angelica.client.gui; - -import cpw.mods.fml.client.config.GuiSlider; -import jss.notfine.gui.ISettingsEnum; -import net.minecraft.client.resources.I18n; - -import static jss.notfine.core.Settings.RENDER_DISTANCE_ENTITIES; - -public enum AngelicaEntityRenderDistanceSetting implements ISettingsEnum { - - ENTITY_RENDER_DISTANCE("options.button.entityRenderDistance"); - private final String unlocalizedButton; - - AngelicaEntityRenderDistanceSetting(String unlocalizedButton) { - this.unlocalizedButton = unlocalizedButton; - } - - @Override - public java.lang.String getButtonLabel() { - return I18n.format(unlocalizedButton); - } - - @Override - public String getTitleLabel() { - return null; - } - - public GuiEntityRenderDistanceSlider createButton(int xPosition, int yPosition, Object setting) { - return new GuiEntityRenderDistanceSlider(xPosition, yPosition, RENDER_DISTANCE_ENTITIES); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java index b63fd1278..f4a1f3961 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java @@ -1,10 +1,9 @@ package com.gtnewhorizons.angelica.client.gui; -import jss.notfine.gui.ISettingsEnum; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.resources.I18n; -public enum AngelicaVideoSettings implements ISettingsEnum { +public enum AngelicaVideoSettings { SHADERS("options.button.shader"); private final String unlocalizedButton; diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiEntityRenderDistanceSlider.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiEntityRenderDistanceSlider.java deleted file mode 100644 index abb058202..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiEntityRenderDistanceSlider.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.gtnewhorizons.angelica.client.gui; - -import jss.notfine.core.Settings; -import jss.notfine.gui.GuiCustomSettingSlider; - -public class GuiEntityRenderDistanceSlider extends GuiCustomSettingSlider { - - public GuiEntityRenderDistanceSlider(int xPosition, int yPosition, Settings setting) { - super(xPosition, yPosition, setting); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java index 133137afc..7fdb20883 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.mixins.early.notfine.clouds; import jss.notfine.core.Settings; +import jss.notfine.gui.options.named.GraphicsQualityOff; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.EntityRenderer; @@ -33,8 +34,8 @@ public void renderClouds(float partialTicks) { return; } if(mc.theWorld.provider.isSurfaceWorld()) { - int cloudMode = (int)Settings.MODE_CLOUDS.getValue(); - if(cloudMode == 0 || cloudMode == -1 && mc.gameSettings.fancyGraphics) { + GraphicsQualityOff cloudMode = (GraphicsQualityOff)Settings.MODE_CLOUDS.option.getStore(); + if(cloudMode == GraphicsQualityOff.FANCY || cloudMode == GraphicsQualityOff.DEFAULT && mc.gameSettings.fancyGraphics) { renderCloudsFancy(partialTicks); } else { renderCloudsFast(partialTicks); @@ -68,7 +69,7 @@ public void renderCloudsFancy(float partialTicks) { } double cloudTick = ((float)cloudTickCounter + partialTicks); - float cloudScale = Settings.CLOUD_SCALE.getValue(); + float cloudScale = (int)Settings.CLOUD_SCALE.option.getStore() * 0.25f; float cloudInteriorWidth = 12.0F * cloudScale; float cloudInteriorHeight = 4.0F * cloudScale; float cameraOffsetY = (float)(mc.renderViewEntity.lastTickPosY + (mc.renderViewEntity.posY - mc.renderViewEntity.lastTickPosY) * (double)partialTicks); @@ -86,7 +87,7 @@ public void renderCloudsFancy(float partialTicks) { float cloudScrollingZ = (float)MathHelper.floor_double(cameraOffsetZ) * scrollSpeed; float cloudWidth = 8f; - int renderRadius = (int)(Settings.RENDER_DISTANCE_CLOUDS.getValue() / (cloudScale * 2f)); + int renderRadius = (int)((int)Settings.RENDER_DISTANCE_CLOUDS.option.getStore() / (cloudScale * 2f)); float edgeOverlap = 0.0001f;//0.001F; GL11.glScalef(cloudInteriorWidth, 1.0F, cloudInteriorWidth); @@ -214,8 +215,8 @@ public void renderCloudsFast(float partialTicks) { cameraOffsetX -= MathHelper.floor_double(cameraOffsetX / 2048.0D) * 2048; cameraOffsetZ -= MathHelper.floor_double(cameraOffsetZ / 2048.0D) * 2048; - float renderRadius = 32 * Settings.RENDER_DISTANCE_CLOUDS.getValue(); - double uvScale = 0.0005D / Settings.CLOUD_SCALE.getValue(); + float renderRadius = 32 * (int)Settings.RENDER_DISTANCE_CLOUDS.option.getStore(); + double uvScale = 0.0005D / (int)Settings.CLOUD_SCALE.option.getStore() * 0.25f; float uvShiftX = (float)(cameraOffsetX * uvScale); float uvShiftZ = (float)(cameraOffsetZ * uvScale); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinWorldType.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinWorldType.java index 7c6d8faae..8adce4cfe 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinWorldType.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinWorldType.java @@ -14,7 +14,7 @@ public abstract class MixinWorldType { */ @Overwrite(remap = false) public float getCloudHeight() { - return Settings.CLOUD_HEIGHT.getValue(); + return (int)Settings.CLOUD_HEIGHT.option.getStore(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockStairs.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockStairs.java index 7f81d2ad8..526d2ae62 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockStairs.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/faceculling/MixinBlockStairs.java @@ -25,6 +25,8 @@ public boolean isFaceNonObstructing(IBlockAccess worldIn, int x, int y, int z, i }; } - protected MixinBlockStairs(Material materialIn) { super(materialIn); } + private MixinBlockStairs(Material materialIn) { + super(materialIn); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinItemRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinItemRenderer.java index dd4a11a06..c5ee0efbf 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinItemRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinItemRenderer.java @@ -19,7 +19,7 @@ public abstract class MixinItemRenderer { remap = false ) private boolean notFine$toggleGlint(ItemStack stack, int pass) { - return Settings.MODE_GLINT_WORLD.isValueBase() && stack.hasEffect(pass); + return (boolean)Settings.MODE_GLINT_WORLD.option.getStore() && stack.hasEffect(pass); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderBiped.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderBiped.java index 8d69cba81..62c5d73ed 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderBiped.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderBiped.java @@ -18,7 +18,7 @@ public abstract class MixinRenderBiped { ) ) private boolean notFine$toggleGlint(ItemStack stack) { - return Settings.MODE_GLINT_WORLD.isValueBase() && stack.isItemEnchanted(); + return (boolean)Settings.MODE_GLINT_WORLD.option.getStore() && stack.isItemEnchanted(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java index 59b6feb63..a327caeab 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java @@ -22,7 +22,7 @@ public abstract class MixinRenderItem { */ @Overwrite private void renderGlint(int unused, int posX, int posY, int width, int height) { - if(!Settings.MODE_GLINT_INV.isValueBase()) { + if(!(boolean)Settings.MODE_GLINT_INV.option.getStore()) { return; } final float timeUVSpeed = 0.00390625F; @@ -71,7 +71,7 @@ private void renderGlint(int unused, int posX, int posY, int width, int height) remap = false ) private boolean notFine$toggleGlint(ItemStack stack, int pass) { - return Settings.MODE_GLINT_WORLD.isValueBase() && stack.hasEffect(pass); + return stack.hasEffect(pass) && (boolean)Settings.MODE_GLINT_WORLD.option.getStore(); } @Shadow public float zLevel; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderPlayer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderPlayer.java index e06315bc1..c73b84c08 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderPlayer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderPlayer.java @@ -18,7 +18,7 @@ public abstract class MixinRenderPlayer { ) ) private boolean notFine$toggleGlint(ItemStack stack) { - return Settings.MODE_GLINT_WORLD.isValueBase() && stack.isItemEnchanted(); + return stack.isItemEnchanted() && (boolean)Settings.MODE_GLINT_WORLD.option.getStore(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/gui/MixinGuiSlot.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/gui/MixinGuiSlot.java index 3e2e01528..e97cbd1bc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/gui/MixinGuiSlot.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/gui/MixinGuiSlot.java @@ -13,7 +13,7 @@ public abstract class MixinGuiSlot { @Inject(method = "drawContainerBackground", at = @At("HEAD"), cancellable = true, remap = false) private void notFine$toggleContainerBackground(CallbackInfo ci) { - if(!Settings.MODE_GUI_BACKGROUND.isValueBase() && Minecraft.getMinecraft().theWorld != null) { + if(!(boolean)Settings.MODE_GUI_BACKGROUND.option.getStore() && Minecraft.getMinecraft().theWorld != null) { ci.cancel(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java index 2b06318ba..ba1194887 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeaves.java @@ -2,6 +2,7 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; +import jss.notfine.gui.options.named.LeavesQuality; import jss.notfine.util.ILeafBlock; import net.minecraft.block.BlockLeaves; import net.minecraft.block.BlockLeavesBase; @@ -30,7 +31,7 @@ public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { //A mod dev had no idea what they were doing. return getIcon(side, world.getBlockMetadata(x, y, z)); } - int renderMode = (int)Settings.MODE_LEAVES.getValue(); + int renderMode = ((LeavesQuality)Settings.MODE_LEAVES.option.getStore()).ordinal() - 1; int maskedMeta = world.getBlockMetadata(x, y, z) & 3; renderMode = switch (renderMode) { case -1 -> SettingsManager.leavesOpaque ? 1 : 0; @@ -47,7 +48,7 @@ public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { @Shadow protected IIcon[][] field_150129_M; - protected MixinBlockLeaves(Material material, boolean overridden) { + private MixinBlockLeaves(Material material, boolean overridden) { super(material, overridden); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java index 555c0591b..8583e3c4f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/leaves/MixinBlockLeavesBase.java @@ -16,7 +16,7 @@ public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int return LeafRenderUtil.shouldSideBeRendered(world, x, y, z, side); } - protected MixinBlockLeavesBase(Material material) { + private MixinBlockLeavesBase(Material material) { super(material); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinBlockEnchantmentTable.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinBlockEnchantmentTable.java index dc8f38bb6..2e165daac 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinBlockEnchantmentTable.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinBlockEnchantmentTable.java @@ -15,10 +15,6 @@ @Mixin(value = BlockEnchantmentTable.class) public abstract class MixinBlockEnchantmentTable extends BlockContainer { - private MixinBlockEnchantmentTable(Material material) { - super(material); - } - /** * @author jss2a98aj * @reason Makes anything with enchantment power cause enchantment particles. @@ -27,10 +23,10 @@ private MixinBlockEnchantmentTable(Material material) { public void randomDisplayTick(World world, int x, int y, int z, Random rand) { //Unneeded in vanilla as the super call is empty. //super.randomDisplayTick(world, x, y, z, rand); - float particleChance = Settings.PARTICLES_ENC_TABLE.getValue(); - if(particleChance <= 0f) { - return; - } + float particleChance = (int)Settings.PARTICLES_ENC_TABLE.option.getStore(); + if(particleChance <= 0f) { + return; + } for (int xPos = x - 2; xPos <= x + 2; ++xPos) { for (int zPos = z - 2; zPos <= z + 2; ++zPos) { if (xPos > x - 2 && xPos < x + 2 && zPos == z - 1) { @@ -43,14 +39,14 @@ public void randomDisplayTick(World world, int x, int y, int z, Random rand) { break; } world.spawnParticle( - "enchantmenttable", - (double)x + 0.5D, - (double)y + 2.0D, - (double)z + 0.5D, - (double)((float)(xPos - x) + rand.nextFloat()) - 0.5D, - (float)(yPos - y) - rand.nextFloat() - 1.0F, - (double)((float)(zPos - z) + rand.nextFloat()) - 0.5D - ); + "enchantmenttable", + (double)x + 0.5D, + (double)y + 2.0D, + (double)z + 0.5D, + (double)((float)(xPos - x) + rand.nextFloat()) - 0.5D, + (float)(yPos - y) - rand.nextFloat() - 1.0F, + (double)((float)(zPos - z) + rand.nextFloat()) - 0.5D + ); } } } @@ -58,4 +54,8 @@ public void randomDisplayTick(World world, int x, int y, int z, Random rand) { } } + private MixinBlockEnchantmentTable(Material material) { + super(material); + } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldClient.java index 26d458bd6..b0bf70020 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldClient.java @@ -16,7 +16,7 @@ public abstract class MixinWorldClient { * @author jss2a98aj * @reason Xoshiro256** is faster than Random. */ - @Redirect(method = "doVoidFogParticles", at = @At(value = "NEW", target = "java/util/Random", ordinal = 0)) + @Redirect(method = "doVoidFogParticles(III)V", at = @At(value = "NEW", target = "java/util/Random", ordinal = 0)) private Random notFine$redirectDoVoidFogParticlesRandom() { return new RandomXoshiro256StarStar(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldProvider.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldProvider.java index 6e6d7b518..c5043a06b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldProvider.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinWorldProvider.java @@ -16,7 +16,7 @@ public class MixinWorldProvider { */ @Overwrite public boolean getWorldHasVoidParticles() { - return Settings.PARTICLES_VOID.isValueBase() && terrainType.hasVoidParticles(hasNoSky); + return (boolean)Settings.PARTICLES_VOID.option.getStore() && terrainType.hasVoidParticles(hasNoSky); } @Shadow public WorldType terrainType; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/renderer/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/renderer/MixinRenderGlobal.java index 21e69564f..b060d308a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/renderer/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/renderer/MixinRenderGlobal.java @@ -14,7 +14,7 @@ public abstract class MixinRenderGlobal { @Inject(method = "renderSky", at = @At("HEAD"), cancellable = true) void notFine$toggleSky(CallbackInfo ci) { - if(!Settings.MODE_SKY.isValueBase()) ci.cancel(); + if(!(boolean)Settings.MODE_SKY.option.getStore()) ci.cancel(); } /** diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java index 8cf7ad6f4..51226d65f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/thaumcraft/MixinBlockMagicalLeaves.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.mixins.late.notfine.leaves.thaumcraft; +import jss.notfine.gui.options.named.LeavesQuality; import jss.notfine.util.ILeafBlock; import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; @@ -19,7 +20,7 @@ public abstract class MixinBlockMagicalLeaves extends Block implements ILeafBloc @Override public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { - int renderMode = (int) Settings.MODE_LEAVES.getValue(); + int renderMode = ((LeavesQuality)Settings.MODE_LEAVES.option.getStore()).ordinal() - 1; int maskedMeta = world.getBlockMetadata(x, y, z) & 3; renderMode = switch (renderMode) { case -1 -> SettingsManager.leavesOpaque ? 1 : 0; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves.java index 29673e275..a9a51afe4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves.java @@ -2,6 +2,7 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; +import jss.notfine.gui.options.named.LeavesQuality; import jss.notfine.util.ILeafBlock; import net.minecraft.block.BlockLeaves; import net.minecraft.init.Blocks; @@ -16,7 +17,7 @@ public abstract class MixinBlockTFLeaves extends BlockLeaves { @Override public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { - int renderMode = (int)Settings.MODE_LEAVES.getValue(); + int renderMode = ((LeavesQuality)Settings.MODE_LEAVES.option.getStore()).ordinal() - 1; int maskedMeta = world.getBlockMetadata(x, y, z) & 3; renderMode = switch (renderMode) { case -1 -> SettingsManager.leavesOpaque ? 1 : 0; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves3.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves3.java index 42a2b7610..cab3d6c45 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves3.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFLeaves3.java @@ -2,6 +2,7 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; +import jss.notfine.gui.options.named.LeavesQuality; import jss.notfine.util.ILeafBlock; import net.minecraft.block.BlockLeaves; import net.minecraft.init.Blocks; @@ -16,7 +17,7 @@ public abstract class MixinBlockTFLeaves3 extends BlockLeaves { @Override public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { - int renderMode = (int)Settings.MODE_LEAVES.getValue(); + int renderMode = ((LeavesQuality)Settings.MODE_LEAVES.option.getStore()).ordinal() - 1; renderMode = switch (renderMode) { case -1 -> SettingsManager.leavesOpaque ? 1 : 0; case 4 -> world.getBlock( diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFMagicLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFMagicLeaves.java index fe50c78d0..a1eea3b40 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFMagicLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/twilightforest/MixinBlockTFMagicLeaves.java @@ -2,6 +2,7 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; +import jss.notfine.gui.options.named.LeavesQuality; import jss.notfine.util.ILeafBlock; import net.minecraft.block.BlockLeaves; import net.minecraft.util.Facing; @@ -15,7 +16,7 @@ public abstract class MixinBlockTFMagicLeaves extends BlockLeaves { @Override public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { - int renderMode = (int) Settings.MODE_LEAVES.getValue(); + int renderMode = ((LeavesQuality)Settings.MODE_LEAVES.option.getStore()).ordinal() - 1; int maskedMeta = world.getBlockMetadata(x, y, z) & 3; renderMode = switch (renderMode) { case -1 -> SettingsManager.leavesOpaque ? 1 : 0; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java index a491ac783..1b7e172c5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/notfine/leaves/witchery/MixinBlockWitchLeaves.java @@ -3,6 +3,7 @@ import com.emoniph.witchery.blocks.BlockWitchLeaves; import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; +import jss.notfine.gui.options.named.LeavesQuality; import jss.notfine.util.ILeafBlock; import net.minecraft.block.BlockLeavesBase; import net.minecraft.block.material.Material; @@ -27,7 +28,7 @@ public boolean isOpaqueCube() { @Override public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { - int renderMode = (int) Settings.MODE_LEAVES.getValue(); + int renderMode = ((LeavesQuality)Settings.MODE_LEAVES.option.getStore()).ordinal() - 1; int maskedMeta = world.getBlockMetadata(x, y, z) & 3; renderMode = switch (renderMode) { case -1 -> SettingsManager.leavesOpaque ? 1 : 0; diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index 2380311f1..8e4cd3670 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -1,8 +1,6 @@ package com.gtnewhorizons.angelica.proxy; import com.google.common.base.Objects; -import com.gtnewhorizons.angelica.client.gui.AngelicaEntityRenderDistanceSetting; -import com.gtnewhorizons.angelica.client.gui.AngelicaVideoSettings; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import cpw.mods.fml.common.FMLCommonHandler; @@ -11,9 +9,6 @@ import cpw.mods.fml.common.eventhandler.EventPriority; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.gameevent.TickEvent; -import jss.notfine.gui.GuiCustomMenu; -import jss.notfine.gui.ISettingsEnum; -import jss.notfine.gui.MenuButtonLists; import me.jellysquid.mods.sodium.client.SodiumDebugScreenHandler; import net.coderbot.iris.client.IrisDebugScreenHandler; import net.minecraft.block.Block; @@ -38,17 +33,6 @@ public class ClientProxy extends CommonProxy { public void preInit(FMLPreInitializationEvent event) { FMLCommonHandler.instance().bus().register(this); MinecraftForge.EVENT_BUS.register(this); - - MenuButtonLists.addAdditionalEntry(MenuButtonLists.VIDEO, AngelicaVideoSettings.SHADERS); - GuiCustomMenu.addButtonHandler(AngelicaVideoSettings.class, (xPosition, yPosition, setting) -> { - ISettingsEnum settingsEnum = (ISettingsEnum) setting; - return settingsEnum.createButton(xPosition, yPosition, setting); - }); - MenuButtonLists.addAdditionalEntry(MenuButtonLists.VIDEO, AngelicaEntityRenderDistanceSetting.ENTITY_RENDER_DISTANCE); - GuiCustomMenu.addButtonHandler(AngelicaEntityRenderDistanceSetting.class, (xPosition, yPosition, setting) ->{ - ISettingsEnum settingsEnum = (ISettingsEnum) setting; - return settingsEnum.createButton(xPosition, yPosition, setting); - }); } @Override diff --git a/src/main/java/jss/notfine/NotFine.java b/src/main/java/jss/notfine/NotFine.java index 54d053578..3c6f029be 100644 --- a/src/main/java/jss/notfine/NotFine.java +++ b/src/main/java/jss/notfine/NotFine.java @@ -1,17 +1,15 @@ package jss.notfine; import com.gtnewhorizons.angelica.Tags; -import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.relauncher.Side; import jss.notfine.config.NotFineConfig; -import jss.notfine.core.LoadMenuButtons; +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 org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -30,8 +28,6 @@ public class NotFine { @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { if(event.getSide() == Side.CLIENT) { - FMLCommonHandler.instance().bus().register(LoadMenuButtons.INSTANCE); - MinecraftForge.EVENT_BUS.register(LoadMenuButtons.INSTANCE); GameSettings.Options.FRAMERATE_LIMIT.valueStep = 1f; } NotFineConfig config = new NotFineConfig(); @@ -40,6 +36,10 @@ public void preInit(FMLPreInitializationEvent event) { if(!NotFineConfig.allowAdvancedOpenGL) { Minecraft.getMinecraft().gameSettings.advancedOpengl = false; } + + for(Settings setting : Settings.values()) { + setting.ready(); + } } @Mod.EventHandler diff --git a/src/main/java/jss/notfine/config/VideoSettings.java b/src/main/java/jss/notfine/config/VideoSettings.java new file mode 100644 index 000000000..06b666847 --- /dev/null +++ b/src/main/java/jss/notfine/config/VideoSettings.java @@ -0,0 +1,58 @@ +package jss.notfine.config; + +import cpw.mods.fml.client.FMLClientHandler; +import jss.notfine.NotFine; +import jss.notfine.core.Settings; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.PrintWriter; + +public class VideoSettings { + private final File optionsFile; + + public VideoSettings(File optionsFile) { + this.optionsFile = optionsFile; + } + + public void loadSettings() { + try { + if (!optionsFile.exists()) { + return; + } + BufferedReader bufferedreader = new BufferedReader(new FileReader(optionsFile)); + String settingString; + + while((settingString = bufferedreader.readLine()) != null) { + try { + String[] fragments = settingString.split(":"); + Settings setting = Settings.valueOf(fragments[0]); + setting.option.deserialize(fragments[1]); + setting.applyChanges(); + } catch (Exception exception) { + NotFine.logger.warn("Skipping bad option: " + settingString); + } + + } + bufferedreader.close(); + } catch (Exception exception) { + NotFine.logger.error("Failed to load options", exception); + } + } + + public void saveSettings() { + if (FMLClientHandler.instance().isLoading()) return; + try { + PrintWriter printwriter = new PrintWriter(new FileWriter(optionsFile)); + for(Settings setting : Settings.values()) { + printwriter.println(setting.name() + ':' + setting.option.getStore()); + } + printwriter.close(); + } catch(Exception exception) { + NotFine.logger.error("Failed to save options", exception); + } + } + +} diff --git a/src/main/java/jss/notfine/config/VideoSettingsConfig.java b/src/main/java/jss/notfine/config/VideoSettingsConfig.java deleted file mode 100644 index 55a3ef7fa..000000000 --- a/src/main/java/jss/notfine/config/VideoSettingsConfig.java +++ /dev/null @@ -1,52 +0,0 @@ -package jss.notfine.config; - -import jss.notfine.core.Settings; -import net.minecraftforge.common.config.Configuration; - -import java.io.File; - -public class VideoSettingsConfig { - private final Configuration settingsConfig; - - public VideoSettingsConfig(File userSettingsFile) { - settingsConfig = new Configuration(userSettingsFile); - } - - public void loadSettings() { - for(Settings setting : Settings.values()) { - - float value = settingsConfig.getFloat( - setting.name(), - ("Settings"), - setting.base, - setting.minimum, - setting.maximum, - setting.configComment - ); - - if(setting.step > 0f) { - value = setting.step * (float)Math.round(value / setting.step); - } - - setting.setValue(value); - } - if(settingsConfig.hasChanged()) { - settingsConfig.save(); - } - } - - public void saveSettings() { - for(Settings setting : Settings.values()) { - settingsConfig.get( - ("Settings"), - setting.name(), - setting.base, - setting.configComment, - setting.minimum, - setting.maximum - ).set(setting.getValue()); - } - settingsConfig.save(); - } - -} diff --git a/src/main/java/jss/notfine/core/LoadMenuButtons.java b/src/main/java/jss/notfine/core/LoadMenuButtons.java deleted file mode 100644 index 032c713d8..000000000 --- a/src/main/java/jss/notfine/core/LoadMenuButtons.java +++ /dev/null @@ -1,34 +0,0 @@ -package jss.notfine.core; - -import cpw.mods.fml.common.eventhandler.EventPriority; -import cpw.mods.fml.common.eventhandler.SubscribeEvent; -import jss.notfine.gui.GuiCustomMenuButton; -import jss.notfine.gui.MenuButtonLists; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiOptions; -import net.minecraftforge.client.event.GuiScreenEvent.InitGuiEvent; - -import java.util.List; - -public class LoadMenuButtons { - - public static final LoadMenuButtons INSTANCE = new LoadMenuButtons(); - - //@SubscribeEvent(priority = EventPriority.LOWEST) - public void onGui(InitGuiEvent.Post event) { - if(event.gui instanceof GuiOptions) { - GuiButton videoSettings = ((List)event.buttonList).stream().filter(button -> button.id == 101).findFirst().get(); - //Hide vanilla video settings button - videoSettings.visible = false; - //Add new video settings button - event.buttonList.add( - new GuiCustomMenuButton( - videoSettings.xPosition, videoSettings.yPosition, - videoSettings.width, videoSettings.height, - MenuButtonLists.VIDEO - ) - ); - } - } - -} diff --git a/src/main/java/jss/notfine/core/Settings.java b/src/main/java/jss/notfine/core/Settings.java index 1e93c9a20..42b65f35e 100644 --- a/src/main/java/jss/notfine/core/Settings.java +++ b/src/main/java/jss/notfine/core/Settings.java @@ -1,175 +1,281 @@ package jss.notfine.core; +import jss.notfine.gui.options.control.NotFineControlValueFormatter; +import jss.notfine.gui.options.named.AlwaysNever; +import jss.notfine.gui.options.named.BackgroundSelect; +import jss.notfine.gui.options.named.DownfallQuality; +import jss.notfine.gui.options.named.GraphicsQualityOff; +import jss.notfine.gui.options.named.LeavesQuality; +import jss.notfine.gui.options.named.GraphicsToggle; import jss.notfine.render.RenderStars; +import jss.notfine.gui.options.storage.NotFineMinecraftOptionsStorage; +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; +import me.jellysquid.mods.sodium.client.gui.options.OptionImpact; +import me.jellysquid.mods.sodium.client.gui.options.control.Control; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; +import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl; +import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl; +import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl; +import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsQuality; +import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.I18n; import net.minecraft.util.MathHelper; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; + public enum Settings { - CLOUD_HEIGHT(true, 128f, 96f, 384f, 8f) { + CLOUD_HEIGHT(new NotFineOptionSlider(128, 96, 384, 8, null)) { @Override - public void updateSetting() { + public void applyChanges() { SettingsManager.cloudsUpdated(); } }, - CLOUD_SCALE(true, 1f, 0.5f, 5f, 0.25f), - DOWNFALL_DISTANCE(false, -1f, -1f, 3f, 1f, "-1:Default, 0:Fancy, 1:Fast, 2:Ultra, 2:Off") { + CLOUD_SCALE(new NotFineOptionSlider(4, 2, 20, 1, null)), + DOWNFALL_DISTANCE(new NotFineOptionCycling<>(DownfallQuality.DEFAULT, OptionImpact.MEDIUM)) { @Override - public void updateSetting() { + public void applyChanges() { SettingsManager.downfallDistanceUpdated(); } }, - FOG_DEPTH(false,0f, 0f, 1f, 1f, "0:On, 1:Off"), - GUI_BACKGROUND(false, -1f, -1f, 5f, 1f, "-1:Default, 0:Sand, 1:Mycelium, 2:Stonebrick, 3:Mossy Stonebrick, 4:Oak Planks, 5: Birch Planks") { + GUI_BACKGROUND(new NotFineOptionCycling<>(BackgroundSelect.DEFAULT, null)) { @Override - public void updateSetting() { + public void applyChanges() { SettingsManager.backgroundUpdated(); } }, - MODE_CLOUD_TRANSLUCENCY(false, -1f,-1f,1f, 1f, "-1:Default, 0:Always, 1:Never") { + MODE_CLOUD_TRANSLUCENCY(new NotFineOptionCycling<>(AlwaysNever.DEFAULT, null)) { @Override - public void updateSetting() { + public void applyChanges() { SettingsManager.cloudsUpdated(); } }, - MODE_CLOUDS(false, -1f, -1f, 2f, 1f, "-1:Default, 0:Fancy, 1:Fast, 2:Off") { + MODE_CLOUDS(new NotFineOptionCycling<>(GraphicsQualityOff.DEFAULT, OptionImpact.MEDIUM)) { @Override - public void updateSetting() { + public void applyChanges() { SettingsManager.cloudsUpdated(); } }, - MODE_DROPPED_ITEMS(false, -1f,-1f,1f, 1f, "-1:Default, 0:On, 1:Off") { + MODE_DROPPED_ITEMS(new NotFineOptionCycling<>(GraphicsQuality.DEFAULT, OptionImpact.LOW)) { @Override - public void updateSetting() { + public void applyChanges() { SettingsManager.droppedItemDetailUpdated(); } }, - MODE_GLINT_INV(false, 0f, 0f, 1f, 1f, "0:On, 1:Off"), - MODE_GLINT_WORLD(false, 0f, 0f, 1f, 1f, "0:On, 1:Off"), - MODE_GUI_BACKGROUND(false, 0f, 0f, 1f, 1f, "0:On, 1:Off"), - MODE_LEAVES(false,-1f, -1f, 4f,1f,"-1:Default, 0:Fancy, 1:Fast, 2:Smart, 3:Hybrid Fancy, 4:Hybrid Fast") { + MODE_GLINT_INV(new NotFineOptionTickBox(true, OptionImpact.VARIES)), + MODE_GLINT_WORLD(new NotFineOptionTickBox(true, OptionImpact.VARIES)), + MODE_GUI_BACKGROUND(new NotFineOptionTickBox(true, null)), + MODE_LEAVES(new NotFineOptionCycling<>(LeavesQuality.DEFAULT, OptionImpact.VARIES, OptionFlag.REQUIRES_RENDERER_RELOAD)) { @Override - public void updateSetting() { + public void applyChanges() { SettingsManager.leavesUpdated(); } }, - MODE_SHADOWS(false, -1f,-1f,1f, 1f, "-1:Default, 0:On, 1:Off") { + MODE_SHADOWS(new NotFineOptionCycling<>(GraphicsToggle.DEFAULT, OptionImpact.LOW)) { @Override - public void updateSetting() { + public void applyChanges() { SettingsManager.shadowsUpdated(); } }, - MODE_SKY(false,0f, 0f, 1f, 1f, "0:On, 1:Off"), - MODE_WATER(false, -1f,-1f,1f, 1f, "-1:Default, 0:Fancy, 1:Fast") { + MODE_SKY(new NotFineOptionTickBox(true, OptionImpact.MEDIUM)), + MODE_WATER(new NotFineOptionCycling<>(GraphicsQuality.DEFAULT, OptionImpact.LOW)) { @Override - public void updateSetting() { + public void applyChanges() { SettingsManager.waterDetailUpdated(); } }, - MODE_VIGNETTE(false, -1f,-1f,1f, 1f, "-1:Default, 0:On, 1:Off") { + MODE_VIGNETTE(new NotFineOptionCycling<>(GraphicsToggle.DEFAULT, OptionImpact.LOW)) { @Override - public void updateSetting() { + public void applyChanges() { SettingsManager.vignetteUpdated(); } }, - PARTICLES_ENC_TABLE(true, 1f, 0f, 16f, 1f), - PARTICLES_VOID(false, 0f, 0f, 1f, 1f, "0:On, 1:Off"), - RENDER_DISTANCE_CLOUDS(true, 4f, 4f, 64f, 2f) { + PARTICLES_ENC_TABLE(new NotFineOptionSlider(1, 0, 16, 1, OptionImpact.LOW)), + PARTICLES_VOID(new NotFineOptionTickBox(true, OptionImpact.LOW)), + RENDER_DISTANCE_CLOUDS(new NotFineOptionSlider(4, 4, 64, 2, OptionImpact.VARIES)) { @Override - public void updateSetting() { + public void applyChanges() { SettingsManager.cloudsUpdated(); } }, - TOTAL_STARS(true, 1500f, 0f, 32000f, 500f) { + TOTAL_STARS(new NotFineOptionSlider(1500, 0, 32000, 500, OptionImpact.LOW)) { @Override - public void updateSetting() { + public void applyChanges() { RenderStars.reloadStarRenderList(Minecraft.getMinecraft().renderGlobal); } - }, - RENDER_DISTANCE_ENTITIES(true, 1.0f, 0.5f, 5.0f, 0.25f) { - @Override - public void updateSetting() { - SettingsManager.entityRenderDistanceUpdated(); - } }; - public final boolean slider; - public final float base; - public final float minimum; - public final float maximum; - public final float step; - public final String configComment; - private float value; - - Settings(boolean slider, float base, float minimum, float maximum, float step, String configComment) { - this.slider = slider; - this.base = base; - this.minimum = minimum; - this.maximum = maximum; - this.step = step; - this.configComment = configComment; - value = base; - } + public final NotFineOption option; - Settings(boolean slider, float base, float minimum, float maximum, float step) { - this(slider, base, minimum, maximum, step, "Increments in steps of " + step); + Settings(NotFineOption option) { + this.option = option; } - public void setValue(float value) { - value = MathHelper.clamp_float(value, minimum, maximum); - if(step > 0f) { - value = step * (float)Math.round(value / step); - } - this.value = value; - updateSetting(); + public void ready() { + option.setting = this; } - public void setValueNormalized(float value) { - setValue(minimum + (maximum - minimum) * MathHelper.clamp_float(value, 0f, 1f)); + public void applyChanges() { + } - public void incrementValue() { - value += step; - if(value > maximum) { - value = minimum; + public static class NotFineOptionCycling> extends NotFineOption { + + protected NotFineOptionCycling(T base, OptionImpact impact, OptionFlag... optionFlags) { + super(base, impact, optionFlags); } - updateSetting(); - } - public float getValue() { - return value; - } + @Override + public void deserialize(String fragment) { + store = T.valueOf(value.getDeclaringClass(), fragment); + value = store; + modifiedValue = store; + } - public float getValueNormalized() { - return MathHelper.clamp_float((value - minimum) / (maximum - minimum), 0f, 1f); - } + @Override + public Control getControl() { + return new CyclingControl<>(this, value.getDeclaringClass()); + } - public boolean isValueBase() { - return value == base; } - public String getLocalization() { - String localized = I18n.format("options." + name().toLowerCase()) + ": "; - if(slider) { - if(step % 1f == 0f) { - localized += (int)value; - } else { - localized += value; - } - } else if(step == 1f && minimum == 0f && maximum == 1f) { - if(value == 0f) { - localized += I18n.format("options.on"); - } else { - localized += I18n.format("options.off"); + public static class NotFineOptionSlider extends NotFineOption { + public final int min, max, step; + + protected NotFineOptionSlider(int base, int min, int max, int step, OptionImpact impact, OptionFlag... optionFlags) { + super(base, impact, optionFlags); + this.min = min; + this.max = max; + this.step = step; + } + + @Override + public Control getControl() { + //TODO: Don't hardcode CLOUD_SCALE check. + return new SliderControl(this, min, max, step, setting != Settings.CLOUD_SCALE ? ControlValueFormatter.number() : NotFineControlValueFormatter.multiplied(0.25f)); + } + + @Override + public void deserialize(String fragment) { + int deserialized = Integer.parseInt(fragment); + deserialized = MathHelper.clamp_int(deserialized, min, max); + if(step > 1) { + deserialized = step * Math.round((float)deserialized / (float)step); } - } else { - localized += I18n.format("options." + name().toLowerCase() + '.' + (int)value); + store = deserialized; + value = store; + modifiedValue = store; } - return localized; } - public void updateSetting() { + public static class NotFineOptionTickBox extends NotFineOption { + + protected NotFineOptionTickBox(boolean base, OptionImpact impact, OptionFlag... optionFlags) { + super(base, impact, optionFlags); + } + + @Override + public Control getControl() { + return new TickBoxControl(this); + } + + @Override + public void deserialize(String fragment) { + store = Boolean.parseBoolean(fragment); + value = store; + modifiedValue = store; + } + + } + + + public static abstract class NotFineOption implements Option { + private static final NotFineMinecraftOptionsStorage optionStorage = new NotFineMinecraftOptionsStorage(); + private final OptionImpact impact; + private final EnumSet optionFlags = EnumSet.noneOf(OptionFlag.class); + protected final T base; + + protected T value, modifiedValue, store; + protected Settings setting; + + protected NotFineOption(T base, OptionImpact impact, OptionFlag... optionFlags) { + value = base; + modifiedValue = base; + store = base; + this.base = base; + this.impact = impact; + Collections.addAll(this.optionFlags, optionFlags); + } + + public abstract void deserialize(String fragment); + + public T getStore() { + return store; + } + + @Override + public String getName() { + return I18n.format("options." + setting.name().toLowerCase()); + } + + @Override + public String getTooltip() { + return I18n.format("options." + setting.name().toLowerCase() + ".tooltip"); + } + + @Override + public OptionImpact getImpact() { + return impact; + } + + @Override + public T getValue() { + return modifiedValue; + } + + @Override + public void setValue(T value) { + modifiedValue = value; + } + + @Override + public void reset() { + value = store; + modifiedValue = store; + } + + @Override + public OptionStorage getStorage() { + return optionStorage; + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public boolean hasChanged() { + return !this.value.equals(this.modifiedValue); + } + + @Override + public void applyChanges() { + store = modifiedValue; + value = modifiedValue; + setting.applyChanges(); + } + + @Override + public Collection getFlags() { + return optionFlags; + } } } + + diff --git a/src/main/java/jss/notfine/core/SettingsManager.java b/src/main/java/jss/notfine/core/SettingsManager.java index 86cd0b276..1dfcc3276 100644 --- a/src/main/java/jss/notfine/core/SettingsManager.java +++ b/src/main/java/jss/notfine/core/SettingsManager.java @@ -1,6 +1,13 @@ package jss.notfine.core; -import jss.notfine.config.VideoSettingsConfig; +import jss.notfine.config.VideoSettings; +import jss.notfine.gui.options.named.AlwaysNever; +import jss.notfine.gui.options.named.BackgroundSelect; +import jss.notfine.gui.options.named.DownfallQuality; +import jss.notfine.gui.options.named.GraphicsQualityOff; +import jss.notfine.gui.options.named.GraphicsToggle; +import jss.notfine.gui.options.named.LeavesQuality; +import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsQuality; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Gui; import net.minecraft.init.Blocks; @@ -13,8 +20,8 @@ public class SettingsManager { private static final Minecraft mc = Minecraft.getMinecraft(); - public static VideoSettingsConfig settingsFile = new VideoSettingsConfig( - new File(Launch.minecraftHome + File.separator + "optionsGraphics.cfg") + public static VideoSettings settingsFile = new VideoSettings( + new File(Launch.minecraftHome + File.separator + "optionsnf.txt") ); public static int minimumFarPlaneDistance; @@ -38,123 +45,81 @@ public class SettingsManager { }; public static void backgroundUpdated() { - int value = (int)Settings.GUI_BACKGROUND.getValue(); - if(value < 0 || value >= extraBackgrounds.length) { + int value = ((BackgroundSelect)Settings.GUI_BACKGROUND.option.getStore()).ordinal(); + if(value == 0) { Gui.optionsBackground = defaultBackground; } else { - Gui.optionsBackground = extraBackgrounds[(int)Settings.GUI_BACKGROUND.getValue()]; + Gui.optionsBackground = extraBackgrounds[((BackgroundSelect)Settings.GUI_BACKGROUND.option.getStore()).ordinal() - 1]; } } public static void cloudsUpdated() { - if(Settings.MODE_CLOUDS.getValue() != 2f) { - minimumFarPlaneDistance = (int)(32f * Settings.RENDER_DISTANCE_CLOUDS.getValue()); - minimumFarPlaneDistance += Math.abs(Settings.CLOUD_HEIGHT.getValue()); + if(Settings.MODE_CLOUDS.option.getStore() != GraphicsQualityOff.OFF) { + minimumFarPlaneDistance = 32 * (int)Settings.RENDER_DISTANCE_CLOUDS.option.getStore(); + minimumFarPlaneDistance += Math.abs((int)Settings.CLOUD_HEIGHT.option.getStore()); mc.gameSettings.clouds = true; } else { minimumFarPlaneDistance = 128; mc.gameSettings.clouds = false; } - switch((int) Settings.MODE_CLOUD_TRANSLUCENCY.getValue()) { - case -1: - cloudTranslucencyCheck = Settings.CLOUD_HEIGHT.getValue(); - break; - case 0: - cloudTranslucencyCheck = Double.NEGATIVE_INFINITY; - break; - case 1: - cloudTranslucencyCheck = Double.POSITIVE_INFINITY; - break; + switch((AlwaysNever)Settings.MODE_CLOUD_TRANSLUCENCY.option.getStore()) { + case DEFAULT -> cloudTranslucencyCheck = (int)Settings.CLOUD_HEIGHT.option.getStore(); + case ALWAYS -> cloudTranslucencyCheck = Double.NEGATIVE_INFINITY; + case NEVER -> cloudTranslucencyCheck = Double.POSITIVE_INFINITY; } } public static void downfallDistanceUpdated() { - switch((int)Settings.DOWNFALL_DISTANCE.getValue()) { - case -1: - downfallDistance = (byte)(mc.gameSettings.fancyGraphics ? 10 : 5); - break; - case 0: - downfallDistance = (byte)5; - break; - case 1: - downfallDistance = (byte)10; - break; - case 2: - downfallDistance = (byte)15; - break; - case 3: - downfallDistance = (byte)0; - break; + switch((DownfallQuality)Settings.DOWNFALL_DISTANCE.option.getStore()) { + case DEFAULT -> downfallDistance = (byte) (mc.gameSettings.fancyGraphics ? 10 : 5); + case FAST -> downfallDistance = (byte) 5; + case FANCY -> downfallDistance = (byte) 10; + case ULTRA -> downfallDistance = (byte) 15; + case OFF -> downfallDistance = (byte) 0; } } public static void leavesUpdated() { - mc.renderGlobal.loadRenderers(); - leavesOpaque = Settings.MODE_LEAVES.getValue() == 1 || (Settings.MODE_LEAVES.getValue() == -1 && !mc.gameSettings.fancyGraphics); + //Do not re-enable, see MixinBlockLeaves workaround for Angelica/Sodium style menus. + //mc.renderGlobal.loadRenderers(); + LeavesQuality value = (LeavesQuality)Settings.MODE_LEAVES.option.getStore(); + leavesOpaque = value == LeavesQuality.FANCY || (value == LeavesQuality.DEFAULT && !mc.gameSettings.fancyGraphics); Blocks.leaves.setGraphicsLevel(!leavesOpaque); Blocks.leaves2.setGraphicsLevel(!leavesOpaque); } public static void shadowsUpdated() { - switch((int)Settings.MODE_SHADOWS.getValue()) { - case -1: - shadows = mc.gameSettings.fancyGraphics; - break; - case 0: - shadows = true; - break; - case 1: - shadows = false; - break; + switch((GraphicsToggle)Settings.MODE_SHADOWS.option.getStore()) { + case DEFAULT -> shadows = mc.gameSettings.fancyGraphics; + case ON-> shadows = true; + case OFF -> shadows = false; } } public static void droppedItemDetailUpdated() { - switch((int)Settings.MODE_DROPPED_ITEMS.getValue()) { - case -1: - droppedItemDetail = mc.gameSettings.fancyGraphics; - break; - case 0: - droppedItemDetail = true; - break; - case 1: - droppedItemDetail = false; - break; + switch((GraphicsQuality)Settings.MODE_DROPPED_ITEMS.option.getStore()) { + case DEFAULT -> droppedItemDetail = mc.gameSettings.fancyGraphics; + case FANCY -> droppedItemDetail = true; + case FAST -> droppedItemDetail = false; } } public static void waterDetailUpdated() { - switch((int)Settings.MODE_DROPPED_ITEMS.getValue()) { - case -1: - waterDetail = mc.gameSettings.fancyGraphics; - break; - case 0: - waterDetail = true; - break; - case 1: - waterDetail = false; - break; + switch((GraphicsQuality)Settings.MODE_WATER.option.getStore()) { + case DEFAULT -> waterDetail = mc.gameSettings.fancyGraphics; + case FANCY -> waterDetail = true; + case FAST -> waterDetail = false; } } public static void vignetteUpdated() { - switch((int)Settings.MODE_VIGNETTE.getValue()) { - case -1: - vignette = mc.gameSettings.fancyGraphics; - break; - case 0: - vignette = true; - break; - case 1: - vignette = false; - break; + switch((GraphicsToggle)Settings.MODE_VIGNETTE.option.getStore()) { + case DEFAULT -> vignette = mc.gameSettings.fancyGraphics; + case ON -> vignette = true; + case OFF -> vignette = false; } } - public static void entityRenderDistanceUpdated() { - entityRenderScaleFactor = Settings.RENDER_DISTANCE_ENTITIES.getValue(); - } - public static void graphicsUpdated() { downfallDistanceUpdated(); leavesUpdated(); diff --git a/src/main/java/jss/notfine/gui/GuiCustomMenu.java b/src/main/java/jss/notfine/gui/GuiCustomMenu.java index 55c16ce2c..ff8e7ea92 100644 --- a/src/main/java/jss/notfine/gui/GuiCustomMenu.java +++ b/src/main/java/jss/notfine/gui/GuiCustomMenu.java @@ -1,81 +1,58 @@ package jss.notfine.gui; -import jss.notfine.NotFine; import jss.notfine.core.Settings; -import jss.notfine.core.SettingsManager; +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; +import me.jellysquid.mods.sodium.client.gui.options.OptionPage; +import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiListExtended; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.resources.I18n; -import net.minecraft.client.settings.GameSettings; import org.lwjgl.input.Keyboard; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Stream; public class GuiCustomMenu extends GuiScreen { - private static final HashMap, ISettingHandler> buttonHandlers = new HashMap<>(); + public static GuiCustomMenu instance; + public static HashSet> dirtyStorages = new HashSet<>(); private final GuiScreen parentGuiScreen; - private final MenuButtonLists buttonEnum; + private final OptionPage optionPage; + private final OptionPage[] subPages; protected String screenTitle; - private GuiListExtended optionsRowList; - static { - addButtonHandler(Settings.class, (xPosition, yPosition, setting) -> { - Settings customSetting = (Settings)setting; - if(customSetting.slider) - return (new GuiCustomSettingSlider(xPosition, yPosition, customSetting)); - else - return (new GuiCustomSettingButton(xPosition, yPosition, customSetting)); - }); - addButtonHandler(GameSettings.Options.class, (xPosition, yPosition, setting) -> { - GameSettings.Options vanillaSetting = (GameSettings.Options)setting; - if (vanillaSetting.getEnumFloat()) - return (new GuiVanillaSettingSlider(xPosition, yPosition, vanillaSetting)); - else - return (new GuiVanillaSettingButton(xPosition, yPosition, vanillaSetting)); - }); - addButtonHandler(MenuButtonLists.class, (xPosition, yPosition, setting) -> { - MenuButtonLists menuType = (MenuButtonLists)setting; - return new GuiCustomMenuButton(xPosition, yPosition, menuType); - }); - } + private GuiListExtended optionsRowList; - public GuiCustomMenu(GuiScreen parentGuiScreen, MenuButtonLists buttonEnum) { + public GuiCustomMenu(GuiScreen parentGuiScreen, OptionPage optionPage, OptionPage... subPages) { this.parentGuiScreen = parentGuiScreen; - this.screenTitle = buttonEnum.getTitleLabel(); - this.buttonEnum = buttonEnum; - } - - public static void addButtonHandler(Class cls, ISettingHandler handler) { - buttonHandlers.put(cls, handler); - } - - public static GuiButton createButton(int xPosition, int yPosition, Enum setting) { - if(setting == null) return null; + this.screenTitle = optionPage.getName(); + this.optionPage = optionPage; + this.subPages = subPages; - final ISettingHandler buttonHandler = buttonHandlers.get((setting).getDeclaringClass()); - if (buttonHandler == null) { - NotFine.logger.debug("No handler for setting: " + setting.getClass().getName()); - return null; - } - return buttonHandler.createButton(xPosition, yPosition, setting); } @Override public void initGui() { buttonList.clear(); - buttonList.add(new GuiButton(200, width / 2 - 100, height - 27, I18n.format("gui.done"))); - - optionsRowList = new GuiCustomSettingsRowList(mc, width, height, 32, height - 32, 25, buttonEnum); + buttonList.add(new GuiButton(200, width / 2 - 110, height - 27, I18n.format("gui.done"))); + optionsRowList = new GuiCustomOptionsRowList(mc, width, height, 32, height - 32, 25, optionPage, subPages); + instance = this; } @Override protected void actionPerformed(GuiButton button) { if(button.enabled && button.id == 200) { if(!(parentGuiScreen instanceof GuiCustomMenu)) { - saveSettings(); + saveChanges(); } mc.displayGuiScreen(parentGuiScreen); } @@ -120,15 +97,17 @@ public void drawScreen(int mouseX, int mouseY, float partialTicks) { @Override protected void keyTyped(char typedChar, int keyCode) { - if(keyCode == Keyboard.KEY_ESCAPE) { - saveSettings(); + if(keyCode == Keyboard.KEY_ESCAPE && !(parentGuiScreen instanceof GuiCustomMenu)) { + saveChanges(); } super.keyTyped(typedChar, keyCode); } - private void saveSettings() { - mc.gameSettings.saveOptions(); - SettingsManager.settingsFile.saveSettings(); + private void saveChanges() { + for(OptionStorage storage : dirtyStorages) { + storage.save(); + } + dirtyStorages = new HashSet<>(); } } diff --git a/src/main/java/jss/notfine/gui/GuiCustomMenuButton.java b/src/main/java/jss/notfine/gui/GuiCustomMenuButton.java index 71d59a52d..b793e75bb 100644 --- a/src/main/java/jss/notfine/gui/GuiCustomMenuButton.java +++ b/src/main/java/jss/notfine/gui/GuiCustomMenuButton.java @@ -1,26 +1,29 @@ package jss.notfine.gui; +import me.jellysquid.mods.sodium.client.gui.options.OptionPage; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; public class GuiCustomMenuButton extends GuiButton { - private final MenuButtonLists linkedList; + private final OptionPage optionPage; + private final OptionPage[] subPages; - public GuiCustomMenuButton(int xPosition, int yPosition, int width, int height, MenuButtonLists list) { - super(-list.ordinal(), xPosition, yPosition, width, height, list.getButtonLabel()); - linkedList = list; + public GuiCustomMenuButton(int xPosition, int yPosition, int width, int height, OptionPage optionPage, OptionPage... subPages) { + super(-10, xPosition, yPosition, width, height, optionPage.getName()); + this.optionPage = optionPage; + this.subPages = subPages; } - public GuiCustomMenuButton(int xPosition, int yPosition, MenuButtonLists list) { - this(xPosition, yPosition, 150, 20, list); + public GuiCustomMenuButton(int xPosition, int yPosition, OptionPage optionPage, OptionPage... subPages) { + this(xPosition, yPosition, 150, 20, optionPage, subPages); } @Override public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { boolean load = super.mousePressed(mc, mouseX, mouseY); if(load) { - mc.displayGuiScreen(new GuiCustomMenu(mc.currentScreen, linkedList)); + mc.displayGuiScreen(new GuiCustomMenu(mc.currentScreen, optionPage, subPages)); } return load; } diff --git a/src/main/java/jss/notfine/gui/GuiCustomSettingsRowList.java b/src/main/java/jss/notfine/gui/GuiCustomOptionsRowList.java similarity index 50% rename from src/main/java/jss/notfine/gui/GuiCustomSettingsRowList.java rename to src/main/java/jss/notfine/gui/GuiCustomOptionsRowList.java index daa5e9247..f0a5373ef 100644 --- a/src/main/java/jss/notfine/gui/GuiCustomSettingsRowList.java +++ b/src/main/java/jss/notfine/gui/GuiCustomOptionsRowList.java @@ -3,34 +3,49 @@ import com.google.common.collect.Lists; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; +import jss.notfine.gui.options.control.element.NotFineControlElementFactory; +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.OptionGroup; +import me.jellysquid.mods.sodium.client.gui.options.OptionPage; +import me.jellysquid.mods.sodium.client.util.Dim2i; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiListExtended; import net.minecraft.client.renderer.Tessellator; +import java.util.Iterator; import java.util.List; @SideOnly(Side.CLIENT) -public class GuiCustomSettingsRowList extends GuiListExtended { +public class GuiCustomOptionsRowList extends GuiListExtended { + private static final NotFineControlElementFactory factory = new NotFineControlElementFactory(); private final List settingsList = Lists.newArrayList(); - public GuiCustomSettingsRowList(Minecraft mc, int width, int height, int top, int bottom, int slotHeight, MenuButtonLists buttonEnum) { + public GuiCustomOptionsRowList(Minecraft mc, int width, int height, int top, int bottom, int slotHeight, OptionPage optionPage, OptionPage... subPages) { super(mc, width, height, top, bottom, slotHeight); field_148163_i = false; - Enum[] settings = MenuButtonLists.getEntries(buttonEnum); - - for(int i = 0; i < settings.length; i += 2) { - Enum settingOne = settings[i]; - Enum settingTwo = i < settings.length - 1 ? settings[i + 1] : null; - GuiButton buttonOne = GuiCustomMenu.createButton(width / 2 - 155, 0, settingOne); - GuiButton buttonTwo = GuiCustomMenu.createButton(width / 2 - 155 + 160, 0, settingTwo); + for(OptionGroup optionGroup : optionPage.getGroups()) { + Iterator settings = optionGroup.getOptions().stream().iterator(); + while(settings.hasNext()) { + Option optionOne = (Option)settings.next(); + Option optionTwo = settings.hasNext() ? (Option)settings.next() : null; + GuiButton buttonOne = (GuiButton)optionOne.getControl().createElement(new Dim2i(width / 2 - 155,0,150,20), factory); + GuiButton buttonTwo = optionTwo == null ? null : (GuiButton)optionTwo.getControl().createElement(new Dim2i(width / 2 - 155 + 160,0,150,20), factory); + settingsList.add(new GuiCustomOptionsRowList.Row(buttonOne, buttonTwo)); + } + } + for(int i = 0; i < subPages.length; i += 2) { + OptionPage pageOne = subPages[i]; + OptionPage pageTwo = i < subPages.length - 1 ? subPages[i + 1] : null; + GuiButton buttonOne = new GuiCustomMenuButton(width / 2 - 155, 0, pageOne); + GuiButton buttonTwo = pageTwo == null ? null : new GuiCustomMenuButton(width / 2 - 155 + 160, 0, pageTwo); settingsList.add(new Row(buttonOne, buttonTwo)); } } @Override - public Row getListEntry(int index) { + public GuiCustomOptionsRowList.Row getListEntry(int index) { return settingsList.get(index); } @@ -50,7 +65,7 @@ protected int getScrollBarX() { } @SideOnly(Side.CLIENT) - public static class Row implements IGuiListEntry { + public static class Row implements GuiListExtended.IGuiListEntry { private final Minecraft mc = Minecraft.getMinecraft(); private final GuiButton buttonOne, buttonTwo; @@ -65,10 +80,9 @@ public Row(GuiButton one, GuiButton two) { @Override public void drawEntry(int varU1, int x, int y, int varU2, int varU3, Tessellator tessellator, int mouseX, int mouseY, boolean varU4) { - if(buttonOne != null) { - buttonOne.yPosition = y; - buttonOne.drawButton(mc, mouseX, mouseY); - } + buttonOne.yPosition = y; + buttonOne.drawButton(mc, mouseX, mouseY); + if(buttonTwo != null) { buttonTwo.yPosition = y; @@ -78,9 +92,10 @@ public void drawEntry(int varU1, int x, int y, int varU2, int varU3, Tessellator @Override public boolean mousePressed(int index, int x, int y, int mouseEvent, int relativeX, int relativeY) { - if(buttonOne != null && buttonOne.mousePressed(mc, x, y)) { + if(buttonOne.mousePressed(mc, x, y)) { return true; - } else if(buttonTwo != null && buttonTwo.mousePressed(mc, x, y)) { + } + if(buttonTwo != null && buttonTwo.mousePressed(mc, x, y)) { return true; } return false; diff --git a/src/main/java/jss/notfine/gui/GuiCustomSettingButton.java b/src/main/java/jss/notfine/gui/GuiCustomSettingButton.java deleted file mode 100644 index 76dd904be..000000000 --- a/src/main/java/jss/notfine/gui/GuiCustomSettingButton.java +++ /dev/null @@ -1,27 +0,0 @@ -package jss.notfine.gui; - -import jss.notfine.core.Settings; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiButton; - -public class GuiCustomSettingButton extends GuiButton { - - private final Settings linkedSetting; - - public GuiCustomSettingButton(int xPosition, int yPosition, Settings setting) { - super(setting.ordinal(), xPosition, yPosition, 150, 20, setting.getLocalization()); - linkedSetting = setting; - } - - @Override - public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { - if(super.mousePressed(mc, mouseX, mouseY)) { - linkedSetting.incrementValue(); - displayString = linkedSetting.getLocalization(); - return true; - } else { - return false; - } - } - -} diff --git a/src/main/java/jss/notfine/gui/GuiCustomSettingSlider.java b/src/main/java/jss/notfine/gui/GuiCustomSettingSlider.java deleted file mode 100644 index c712f8d75..000000000 --- a/src/main/java/jss/notfine/gui/GuiCustomSettingSlider.java +++ /dev/null @@ -1,65 +0,0 @@ -package jss.notfine.gui; - -import jss.notfine.core.Settings; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.util.MathHelper; -import org.lwjgl.opengl.GL11; - -public class GuiCustomSettingSlider extends GuiButton { - - private final Settings linkedSetting; - private float value; - public boolean mousePressed; - - public GuiCustomSettingSlider(int xPosition, int yPosition, Settings setting) { - super(setting.ordinal(), xPosition, yPosition, 150, 20, ""); - linkedSetting = setting; - value = setting.getValueNormalized(); - displayString = setting.getLocalization(); - } - - @Override - public int getHoverState(boolean mouseOver) { - return 0; - } - - @Override - protected void mouseDragged(Minecraft mc, int mouseX, int mouseY) { - if(visible) { - if(mousePressed) { - updateSlider(mouseX); - } - GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)), yPosition, 0, 66, 4, 20); - drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)) + 4, yPosition, 196, 66, 4, 20); - } - } - - @Override - public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { - if(super.mousePressed(mc, mouseX, mouseY)) { - updateSlider(mouseX); - mousePressed = true; - return true; - } else { - return false; - } - } - - @Override - public void mouseReleased(int mouseX, int mouseY) { - mousePressed = false; - } - - private void updateSlider(int mouseX) { - value = (float)(mouseX - (xPosition + 4)) / (float)(width - 8); - value = MathHelper.clamp_float(value, 0f, 1f); - - linkedSetting.setValueNormalized(value); - value = linkedSetting.getValueNormalized(); - - displayString = linkedSetting.getLocalization(); - } - -} diff --git a/src/main/java/jss/notfine/gui/GuiVanillaSettingButton.java b/src/main/java/jss/notfine/gui/GuiVanillaSettingButton.java deleted file mode 100644 index 3a160b6d3..000000000 --- a/src/main/java/jss/notfine/gui/GuiVanillaSettingButton.java +++ /dev/null @@ -1,27 +0,0 @@ -package jss.notfine.gui; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.settings.GameSettings; - -public class GuiVanillaSettingButton extends GuiButton { - - private final GameSettings.Options linkedSetting; - - public GuiVanillaSettingButton(int xPosition, int yPosition, GameSettings.Options setting) { - super(setting.ordinal(), xPosition, yPosition, 150, 20, Minecraft.getMinecraft().gameSettings.getKeyBinding(setting)); - linkedSetting = setting; - } - - @Override - public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { - if(super.mousePressed(mc, mouseX, mouseY)) { - mc.gameSettings.setOptionValue(linkedSetting, 1); - displayString = mc.gameSettings.getKeyBinding(linkedSetting); - return true; - } else { - return false; - } - } - -} diff --git a/src/main/java/jss/notfine/gui/GuiVanillaSettingSlider.java b/src/main/java/jss/notfine/gui/GuiVanillaSettingSlider.java deleted file mode 100644 index 112ca8ad6..000000000 --- a/src/main/java/jss/notfine/gui/GuiVanillaSettingSlider.java +++ /dev/null @@ -1,68 +0,0 @@ -package jss.notfine.gui; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.settings.GameSettings; -import net.minecraft.util.MathHelper; -import org.lwjgl.opengl.GL11; - -public class GuiVanillaSettingSlider extends GuiButton { - - private final GameSettings.Options linkedSetting; - private float value; - public boolean mousePressed; - - public GuiVanillaSettingSlider(int xPosition, int yPosition, GameSettings.Options setting) { - super(setting.ordinal(), xPosition, yPosition, 150, 20, ""); - linkedSetting = setting; - - Minecraft mc = Minecraft.getMinecraft(); - value = linkedSetting.normalizeValue(Minecraft.getMinecraft().gameSettings.getOptionFloatValue(linkedSetting)); - displayString = mc.gameSettings.getKeyBinding(setting); - } - - @Override - public int getHoverState(boolean mouseOver) { - return 0; - } - - @Override - protected void mouseDragged(Minecraft mc, int mouseX, int mouseY) { - if(visible) { - if(mousePressed) { - updateSlider(mc, mouseX); - } - GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)), yPosition, 0, 66, 4, 20); - drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)) + 4, yPosition, 196, 66, 4, 20); - } - } - - @Override - public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { - if(super.mousePressed(mc, mouseX, mouseY)) { - updateSlider(mc, mouseX); - mousePressed = true; - return true; - } else { - return false; - } - } - - @Override - public void mouseReleased(int mouseX, int mouseY) { - mousePressed = false; - } - - private void updateSlider(Minecraft mc, int mouseX) { - value = (float)(mouseX - (xPosition + 4)) / (float)(width - 8); - value = MathHelper.clamp_float(value, 0f, 1f); - - value = linkedSetting.denormalizeValue(value); - mc.gameSettings.setOptionFloatValue(linkedSetting, value); - value = linkedSetting.normalizeValue(value); - - displayString = mc.gameSettings.getKeyBinding(linkedSetting); - } - -} diff --git a/src/main/java/jss/notfine/gui/ISettingHandler.java b/src/main/java/jss/notfine/gui/ISettingHandler.java deleted file mode 100644 index e65eaca93..000000000 --- a/src/main/java/jss/notfine/gui/ISettingHandler.java +++ /dev/null @@ -1,7 +0,0 @@ -package jss.notfine.gui; - -import net.minecraft.client.gui.GuiButton; - -public interface ISettingHandler { - GuiButton createButton(int xPosition, int yPosition, Object setting); -} diff --git a/src/main/java/jss/notfine/gui/ISettingsEnum.java b/src/main/java/jss/notfine/gui/ISettingsEnum.java deleted file mode 100644 index 94c0190f1..000000000 --- a/src/main/java/jss/notfine/gui/ISettingsEnum.java +++ /dev/null @@ -1,17 +0,0 @@ -package jss.notfine.gui; - -import net.minecraft.client.gui.GuiButton; - -import java.util.Collections; -import java.util.List; - -public interface ISettingsEnum { - String getButtonLabel(); - String getTitleLabel(); - - // If this button has it's own page - Entries that go on this page - or Empty - default List> entries() { return Collections.emptyList(); } - - // If this button does something custom - create the button - default GuiButton createButton(int xPosition, int yPosition, Object setting) { return null; } -} diff --git a/src/main/java/jss/notfine/gui/MenuButtonLists.java b/src/main/java/jss/notfine/gui/MenuButtonLists.java deleted file mode 100644 index 6a47f33e0..000000000 --- a/src/main/java/jss/notfine/gui/MenuButtonLists.java +++ /dev/null @@ -1,116 +0,0 @@ -package jss.notfine.gui; - -import jss.notfine.config.NotFineConfig; -import jss.notfine.core.Settings; -import net.minecraft.client.renderer.OpenGlHelper; -import net.minecraft.client.resources.I18n; -import net.minecraft.client.settings.GameSettings; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -public enum MenuButtonLists implements ISettingsEnum { - VIDEO("options.video") { - @Override - public List> entries() { - ArrayList> list = new ArrayList<>(); - - list.add(GameSettings.Options.GRAPHICS); list.add(GameSettings.Options.RENDER_DISTANCE); - list.add(GameSettings.Options.ENABLE_VSYNC); list.add(GameSettings.Options.USE_FULLSCREEN); - list.add(GameSettings.Options.FRAMERATE_LIMIT); list.add(null); - list.add(GameSettings.Options.GUI_SCALE); list.add(GameSettings.Options.VIEW_BOBBING); - list.add(GameSettings.Options.AMBIENT_OCCLUSION); list.add(GameSettings.Options.GAMMA); - list.add(GameSettings.Options.ANISOTROPIC_FILTERING); list.add(GameSettings.Options.MIPMAP_LEVELS); - - list.add(DETAIL); list.add(SKY); - list.add(PARTICLE); list.add(OTHER); - - return list; - } - }, - DETAIL("options.button.detail") { - @Override - public List> entries() { - ArrayList> list = new ArrayList<>(); - - list.add(Settings.MODE_LEAVES); list.add(Settings.MODE_WATER); - list.add(Settings.DOWNFALL_DISTANCE); list.add(Settings.MODE_VIGNETTE); - list.add(Settings.MODE_SHADOWS); list.add(Settings.MODE_DROPPED_ITEMS); - list.add(Settings.MODE_GLINT_WORLD); list.add(Settings.MODE_GLINT_INV); - - return list; - } - }, - SKY("options.button.sky") { - @Override - public List> entries() { - ArrayList> list = new ArrayList<>(); - - list.add(Settings.MODE_SKY); list.add(Settings.MODE_CLOUDS); - list.add(Settings.RENDER_DISTANCE_CLOUDS); list.add(Settings.CLOUD_HEIGHT); - list.add(Settings.CLOUD_SCALE); list.add(Settings.MODE_CLOUD_TRANSLUCENCY); - list.add(Settings.TOTAL_STARS); - - return list; - } - }, - PARTICLE("options.button.particle") { - @Override - public List> entries() { - ArrayList> list = new ArrayList<>(); - - list.add(GameSettings.Options.PARTICLES); list.add(Settings.PARTICLES_VOID); - list.add(Settings.PARTICLES_ENC_TABLE); - - return list; - } - }, - OTHER("options.button.other") { - @Override - public List> entries() { - ArrayList> list = new ArrayList<>(); - if(OpenGlHelper.field_153197_d && NotFineConfig.allowAdvancedOpenGL) { - list.add(GameSettings.Options.ADVANCED_OPENGL); - } else { - list.add(null); - } - list.add(GameSettings.Options.ANAGLYPH); - list.add(Settings.MODE_GUI_BACKGROUND); list.add(GameSettings.Options.SHOW_CAPE); - list.add(null); list.add(GameSettings.Options.FBO_ENABLE); - list.add(Settings.GUI_BACKGROUND); - - return list; - } - }; - - private final String unlocalizedButton; - private static final HashMap, List >> additionalEntries = new HashMap<>(); - - public static void addAdditionalEntry(Enum entry, Enum button) { - List> list = additionalEntries.computeIfAbsent(entry, k -> new ArrayList<>()); - list.add(button); - } - MenuButtonLists(String button) { - unlocalizedButton = button; - } - - public String getButtonLabel() { - return I18n.format(unlocalizedButton); - } - - public String getTitleLabel() { - return I18n.format("options.title." + name().toLowerCase()); - } - - public abstract List> entries(); - - public static Enum[] getEntries(MenuButtonLists button) { - List> entries = button.entries(); - List> additional = additionalEntries.get(button); - if(additional != null) { - entries.addAll(additional); - } - return entries.toArray(new Enum[0]); - } -} diff --git a/src/main/java/jss/notfine/gui/NotFineGameOptionPages.java b/src/main/java/jss/notfine/gui/NotFineGameOptionPages.java new file mode 100644 index 000000000..a3789c89b --- /dev/null +++ b/src/main/java/jss/notfine/gui/NotFineGameOptionPages.java @@ -0,0 +1,223 @@ +package jss.notfine.gui; + +import com.google.common.collect.ImmutableList; +import jss.notfine.config.NotFineConfig; +import jss.notfine.core.Settings; +import jss.notfine.gui.options.control.NotFineControlValueFormatter; +import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; +import me.jellysquid.mods.sodium.client.gui.options.OptionGroup; +import me.jellysquid.mods.sodium.client.gui.options.OptionImpact; +import me.jellysquid.mods.sodium.client.gui.options.OptionImpl; +import me.jellysquid.mods.sodium.client.gui.options.OptionPage; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; +import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl; +import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl; +import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl; +import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsMode; +import me.jellysquid.mods.sodium.client.gui.options.named.LightingQuality; +import me.jellysquid.mods.sodium.client.gui.options.named.ParticleMode; +import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.settings.GameSettings; +import net.minecraft.util.MathHelper; +import org.lwjgl.opengl.Display; + +import java.util.ArrayList; +import java.util.List; + +public class NotFineGameOptionPages { + private static final MinecraftOptionsStorage vanillaOpts = new MinecraftOptionsStorage(); + + public static OptionPage general() { + List groups = new ArrayList<>(); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(GraphicsMode.class, vanillaOpts) + .setName(I18n.format("options.graphics")) + .setTooltip(I18n.format("sodium.options.graphics_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, GraphicsMode.class)) + .setBinding( + (opts, value) -> opts.fancyGraphics = value.isFancy(), + opts -> GraphicsMode.fromBoolean(opts.fancyGraphics)) + .setImpact(OptionImpact.HIGH) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.renderDistance")) + .setTooltip(I18n.format("sodium.options.view_distance.tooltip")) + .setControl(option -> new SliderControl(option, 2, (int)GameSettings.Options.RENDER_DISTANCE.getValueMax(), 1, ControlValueFormatter.quantity("options.chunks"))) + .setBinding((options, value) -> options.renderDistanceChunks = value, options -> options.renderDistanceChunks) + .setImpact(OptionImpact.HIGH) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("options.vsync")) + .setTooltip(I18n.format("sodium.options.v_sync.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> { + opts.enableVsync = value; + Display.setVSyncEnabled(opts.enableVsync); + }, opts -> opts.enableVsync) + .setImpact(OptionImpact.VARIES) + .build()) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("options.fullscreen")) + .setTooltip(I18n.format("sodium.options.fullscreen.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> { + opts.fullScreen = value; + Minecraft client = Minecraft.getMinecraft(); + if (client.isFullScreen() != opts.fullScreen) { + client.toggleFullscreen(); + //The client might not be able to enter full-screen mode + opts.fullScreen = client.isFullScreen(); + } + }, (opts) -> opts.fullScreen) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.framerateLimit")) + .setTooltip(I18n.format("sodium.options.fps_limit.tooltip")) + .setControl(option -> new SliderControl(option, 5, 260, 1, ControlValueFormatter.fpsLimit())) + .setBinding((opts, value) -> opts.limitFramerate = value, opts -> opts.limitFramerate) + .build()) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.guiScale")) + .setTooltip(I18n.format("sodium.options.gui_scale.tooltip")) + .setControl(option -> new SliderControl(option, 0, 4, 1, ControlValueFormatter.guiScale())) + .setBinding((opts, value) -> opts.guiScale = value, opts -> opts.guiScale) + .build()) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("options.viewBobbing")) + .setTooltip(I18n.format("sodium.options.view_bobbing.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.viewBobbing = value, opts -> opts.viewBobbing) + .build()) + .add(OptionImpl.createBuilder(LightingQuality.class, vanillaOpts) + .setName(I18n.format("options.ao")) + .setTooltip(I18n.format("sodium.options.smooth_lighting.tooltip")) + .setControl(option -> new CyclingControl<>(option, LightingQuality.class)) + .setBinding((opts, value) -> opts.ambientOcclusion = value.getVanilla(), opts -> LightingQuality.fromOrdinal(opts.ambientOcclusion)) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.gamma")) + .setTooltip(I18n.format("sodium.options.brightness.tooltip")) + .setControl(opt -> new SliderControl(opt, 0, 100, 1, ControlValueFormatter.brightness())) + .setBinding((opts, value) -> opts.gammaSetting = value * 0.01F, (opts) -> (int) (opts.gammaSetting / 0.01F)) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.mipmapLevels")) + .setTooltip(I18n.format("sodium.options.mipmap_levels.tooltip")) + .setControl(option -> new SliderControl(option, 0, 4, 1, ControlValueFormatter.multiplier())) + .setBinding((opts, value) -> opts.mipmapLevels = value, opts -> opts.mipmapLevels) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_ASSET_RELOAD) + .build()) + .add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.anisotropicFiltering")) + .setTooltip(I18n.format("sodium.options.anisotropic_filtering.tooltip")) + .setControl(option -> new SliderControl(option, 0, 4, 1, NotFineControlValueFormatter.powerOfTwo())) + .setBinding( + (opts, value) -> opts.anisotropicFiltering = value == 0 ? 1 : (int)Math.pow(2, value), + (opts) -> opts.anisotropicFiltering == 1 ? 0 : (int)(Math.log(opts.anisotropicFiltering) / Math.log(2))) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_ASSET_RELOAD) + .build()) + .build()); + return new OptionPage(I18n.format("options.video"), ImmutableList.copyOf(groups)); + } + + + public static OptionPage detail() { + List groups = new ArrayList<>(); + groups.add(OptionGroup.createBuilder() + .add(Settings.MODE_LEAVES.option) + .add(Settings.MODE_WATER.option) + .add(Settings.DOWNFALL_DISTANCE.option) + .add(Settings.MODE_VIGNETTE.option) + .add(Settings.MODE_SHADOWS.option) + .add(Settings.MODE_DROPPED_ITEMS.option) + .add(Settings.MODE_GLINT_WORLD.option) + .add(Settings.MODE_GLINT_INV.option) + .build()); + return new OptionPage(I18n.format("options.button.detail"), ImmutableList.copyOf(groups)); + } + + public static OptionPage atmosphere() { + List groups = new ArrayList<>(); + groups.add(OptionGroup.createBuilder() + .add(Settings.MODE_SKY.option) + .add(Settings.MODE_CLOUDS.option) + .add(Settings.RENDER_DISTANCE_CLOUDS.option) + .add(Settings.CLOUD_HEIGHT.option) + .add(Settings.CLOUD_SCALE.option) + .add(Settings.MODE_CLOUD_TRANSLUCENCY.option) + .add(Settings.TOTAL_STARS.option) + .build()); + return new OptionPage(I18n.format("options.button.sky"), ImmutableList.copyOf(groups)); + } + + public static OptionPage particles() { + List groups = new ArrayList<>(); + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(ParticleMode.class, vanillaOpts) + .setName(I18n.format("options.particles")) + .setTooltip(I18n.format("sodium.options.particle_quality.tooltip")) + .setControl(opt -> new CyclingControl<>(opt, ParticleMode.class)) + .setBinding((opts, value) -> opts.particleSetting = value.ordinal(), (opts) -> ParticleMode.fromOrdinal(opts.particleSetting)) + .setImpact(OptionImpact.LOW) + .build()) + .add(Settings.PARTICLES_VOID.option) + .add(Settings.PARTICLES_ENC_TABLE.option) + .build()); + return new OptionPage(I18n.format("options.button.particle"), ImmutableList.copyOf(groups)); + } + + public static OptionPage other() { + List groups = new ArrayList<>(); + + groups.add(OptionGroup.createBuilder() + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("options.advancedOpengl")) + .setTooltip(I18n.format("sodium.options.advanced_opengl.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.advancedOpengl = value, opts -> opts.advancedOpengl) + .setImpact(OptionImpact.VARIES) + .setEnabled(NotFineConfig.allowAdvancedOpenGL) + .build()) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("options.fboEnable")) + .setTooltip(I18n.format("sodium.options.fbo.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.fboEnable = value, opts -> opts.fboEnable) + .build()) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("options.anaglyph")) + .setTooltip(I18n.format("sodium.options.anaglyph.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.anaglyph = value, opts -> opts.anaglyph) + .setImpact(OptionImpact.HIGH) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) + .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("options.showCape")) + .setTooltip(I18n.format("sodium.options.show_cape.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.showCape = value, opts -> opts.showCape) + .build()) + .add(Settings.MODE_GUI_BACKGROUND.option) + .build()); + + groups.add(OptionGroup.createBuilder() + .add(Settings.GUI_BACKGROUND.option) + .build()); + + return new OptionPage(I18n.format("options.button.other"), ImmutableList.copyOf(groups)); + } + +} diff --git a/src/main/java/jss/notfine/gui/options/control/NotFineControlValueFormatter.java b/src/main/java/jss/notfine/gui/options/control/NotFineControlValueFormatter.java new file mode 100644 index 000000000..0d20b5b8d --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/control/NotFineControlValueFormatter.java @@ -0,0 +1,15 @@ +package jss.notfine.gui.options.control; + +import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; +import net.minecraft.client.resources.I18n; + +public class NotFineControlValueFormatter { + public static ControlValueFormatter multiplied(float multiplier) { + return (value) -> String.valueOf((value * multiplier)); + } + + public static ControlValueFormatter powerOfTwo() { + return (v) -> (v == 0) ? I18n.format("options.off") : I18n.format((int)Math.pow(2, v) + "x"); + } + +} diff --git a/src/main/java/jss/notfine/gui/options/control/element/CyclingControlElement.java b/src/main/java/jss/notfine/gui/options/control/element/CyclingControlElement.java new file mode 100644 index 000000000..e65465004 --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/control/element/CyclingControlElement.java @@ -0,0 +1,42 @@ +package jss.notfine.gui.options.control.element; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.Minecraft; + +public class CyclingControlElement> extends NotFineControlElement { + private final T[] allowedValues; + private final String[] names; + private int currentIndex = 0; + + public CyclingControlElement(Option option, Dim2i dim, T[] allowedValues, String[] names) { + super(option, dim); + this.allowedValues = allowedValues; + this.names = names; + + for(int i = 0; i < allowedValues.length; ++i) { + if(allowedValues[i] == option.getValue()) { + currentIndex = i; + break; + } + } + } + + public String getLabel() { + Enum value = option.getValue(); + return super.getLabel() + names[value.ordinal()]; + } + + @Override + public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { + if(super.mousePressed(mc, mouseX, mouseY)) { + currentIndex = (option.getValue().ordinal() + 1) % allowedValues.length; + option.setValue(allowedValues[currentIndex]); + onOptionValueChanged(); + return true; + } else { + return false; + } + } + +} diff --git a/src/main/java/jss/notfine/gui/options/control/element/NotFineControlElement.java b/src/main/java/jss/notfine/gui/options/control/element/NotFineControlElement.java new file mode 100644 index 000000000..434d7136e --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/control/element/NotFineControlElement.java @@ -0,0 +1,76 @@ +package jss.notfine.gui.options.control.element; + +import jss.notfine.core.Settings; +import jss.notfine.gui.GuiCustomMenu; +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.util.EnumChatFormatting; + +import java.util.Collection; + +public class NotFineControlElement extends GuiButton implements ControlElement { + protected final Option option; + protected final Dim2i dim; + + public NotFineControlElement(Option option, Dim2i dim) { + super(-5, dim.getOriginX(), dim.getOriginY(), dim.getWidth(), dim.getHeight(), option.getName()); + this.option = option; + this.dim = dim; + enabled = option.isAvailable(); + } + + @Override + public void drawButton(Minecraft mc, int mouseX, int mouseY) { + displayString = getLabel(); + //TODO: tooltips + //hovered + super.drawButton(mc, mouseX, mouseY); + } + + public String getLabel() { + String name = option.getName(); + String label; + enabled = option.isAvailable(); + if(enabled && option.hasChanged()) { + label = EnumChatFormatting.ITALIC + name; + } else { + label = name; + } + label += ": "; + return label; + } + + protected void onOptionValueChanged() { + option.applyChanges(); + + Collection flags = option.getFlags(); + Minecraft mc = Minecraft.getMinecraft(); + if(flags.contains(OptionFlag.REQUIRES_RENDERER_RELOAD)) { + mc.renderGlobal.loadRenderers(); + } + if(flags.contains(OptionFlag.REQUIRES_ASSET_RELOAD)) { + mc.getTextureMapBlocks().setMipmapLevels(mc.gameSettings.mipmapLevels); + mc.refreshResources(); + } + GuiCustomMenu.dirtyStorages.add(option.getStorage()); + } + + @Override + public boolean isHovered() { + return false; + } + + @Override + public Option getOption() { + return this.option; + } + + @Override + public Dim2i getDimensions() { + return this.dim; + } +} diff --git a/src/main/java/jss/notfine/gui/options/control/element/NotFineControlElementFactory.java b/src/main/java/jss/notfine/gui/options/control/element/NotFineControlElementFactory.java new file mode 100644 index 000000000..9e460e46d --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/control/element/NotFineControlElementFactory.java @@ -0,0 +1,26 @@ +package jss.notfine.gui.options.control.element; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; +import me.jellysquid.mods.sodium.client.gui.options.control.element.ControlElementFactory; +import me.jellysquid.mods.sodium.client.util.Dim2i; + +public class NotFineControlElementFactory implements ControlElementFactory { + + @Override + public > ControlElement cyclingControlElement(Option option, Dim2i dim, T[] allowedValues, String[] names) { + return new CyclingControlElement(option, dim, allowedValues, names); + } + + @Override + public ControlElement sliderControlElement(Option option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter) { + return new SliderControlElement(option, dim, min, max, interval, formatter); + } + + @Override + public ControlElement tickBoxElement(Option option, Dim2i dim) { + return new TickBoxControlElement(option, dim); + } + +} diff --git a/src/main/java/jss/notfine/gui/options/control/element/SliderControlElement.java b/src/main/java/jss/notfine/gui/options/control/element/SliderControlElement.java new file mode 100644 index 000000000..d1f8547be --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/control/element/SliderControlElement.java @@ -0,0 +1,85 @@ +package jss.notfine.gui.options.control.element; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.Minecraft; +import net.minecraft.util.MathHelper; +import org.lwjgl.opengl.GL11; + +public class SliderControlElement extends NotFineControlElement { + private final ControlValueFormatter formatter; + private final int min, max, interval; + + private float value; + private boolean mousePressed; + + public SliderControlElement(Option option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter) { + super(option, dim); + this.min = min; + this.max = max; + this.interval = interval; + this.formatter = formatter; + value = option.getValue(); + //Normalize value + value = MathHelper.clamp_float((value - min) / (max - min), 0f, 1f); + } + + public String getLabel() { + return super.getLabel() + formatter.format(option.getValue()); + } + + @Override + public int getHoverState(boolean mouseOver) { + return 0; + } + + @Override + protected void mouseDragged(Minecraft mc, int mouseX, int mouseY) { + if(visible) { + if(mousePressed) { + updateSlider(mouseX); + } + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)), yPosition, 0, 66, 4, 20); + drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)) + 4, yPosition, 196, 66, 4, 20); + } + } + + @Override + public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { + if(super.mousePressed(mc, mouseX, mouseY)) { + updateSlider(mouseX); + mousePressed = true; + return true; + } else { + return false; + } + } + + @Override + public void mouseReleased(int mouseX, int mouseY) { + mousePressed = false; + } + + private void updateSlider(int mouseX) { + value = (float)(mouseX - (xPosition + 4)) / (float)(width - 8); + //Clamp normalized value + value = MathHelper.clamp_float(value, 0f, 1f); + //Un-normalize value + value = min + (max - min) * MathHelper.clamp_float(value, 0f, 1f); + //Clamp value + value = MathHelper.clamp_float(value, min, max); + //Snap value + if(interval > 0) { + value = interval * (float)Math.round(value / interval); + } + //Commit value + option.setValue((int)value); + //Normalize value + value = MathHelper.clamp_float((value - min) / (max - min), 0f, 1f); + + onOptionValueChanged(); + } + +} diff --git a/src/main/java/jss/notfine/gui/options/control/element/TickBoxControlElement.java b/src/main/java/jss/notfine/gui/options/control/element/TickBoxControlElement.java new file mode 100644 index 000000000..f5647f4a2 --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/control/element/TickBoxControlElement.java @@ -0,0 +1,28 @@ +package jss.notfine.gui.options.control.element; + +import me.jellysquid.mods.sodium.client.gui.options.Option; +import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; + +public class TickBoxControlElement extends NotFineControlElement { + public TickBoxControlElement(Option option, Dim2i dim) { + super(option, dim); + } + + public String getLabel() { + return super.getLabel() + I18n.format(option.getValue() ? "options.on" : "options.off"); + } + + @Override + public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { + if(super.mousePressed(mc, mouseX, mouseY)) { + option.setValue(!option.getValue()); + onOptionValueChanged(); + return true; + } else { + return false; + } + } + +} diff --git a/src/main/java/jss/notfine/gui/options/named/AlwaysNever.java b/src/main/java/jss/notfine/gui/options/named/AlwaysNever.java new file mode 100644 index 000000000..64eb404a4 --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/named/AlwaysNever.java @@ -0,0 +1,21 @@ +package jss.notfine.gui.options.named; + +import me.jellysquid.mods.sodium.client.gui.options.named.NamedState; + +public enum AlwaysNever implements NamedState { + DEFAULT("generator.default"), + ALWAYS("options.stream.chat.enabled.always"), + NEVER("options.stream.chat.enabled.never"); + + private final String name; + + AlwaysNever(String name) { + this.name = name; + } + + @Override + public String getKey() { + return this.name; + } + +} diff --git a/src/main/java/jss/notfine/gui/options/named/BackgroundSelect.java b/src/main/java/jss/notfine/gui/options/named/BackgroundSelect.java new file mode 100644 index 000000000..783c523fa --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/named/BackgroundSelect.java @@ -0,0 +1,26 @@ +package jss.notfine.gui.options.named; + +import me.jellysquid.mods.sodium.client.gui.options.named.NamedState; + +public enum BackgroundSelect implements NamedState { + DEFAULT("generator.default"), + SAND("tile.sand.default.name"), + MYCELIUM("tile.mycel.name"), + STONEBRICK("tile.stonebricksmooth.name"), + MOSSY_STONEBRICK("tile.stonebricksmooth.mossy.name"), + OAK_PLANKS("tile.wood.oak.name"), + BIRCH_PLANKS("tile.wood.birch.name"); + + private final String name; + + BackgroundSelect(String name) { + this.name = name; + } + + @Override + public String getKey() { + return this.name; + } + +} + diff --git a/src/main/java/jss/notfine/gui/options/named/DownfallQuality.java b/src/main/java/jss/notfine/gui/options/named/DownfallQuality.java new file mode 100644 index 000000000..fe78ec064 --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/named/DownfallQuality.java @@ -0,0 +1,23 @@ +package jss.notfine.gui.options.named; + +import me.jellysquid.mods.sodium.client.gui.options.named.NamedState; + +public enum DownfallQuality implements NamedState { + DEFAULT("generator.default"), + FANCY("options.graphics.fancy"), + FAST("options.graphics.fast"), + ULTRA("options.graphics.ultra"), + OFF("options.off"); + + private final String name; + + DownfallQuality(String name) { + this.name = name; + } + + @Override + public String getKey() { + return this.name; + } + +} diff --git a/src/main/java/jss/notfine/gui/options/named/GraphicsQualityOff.java b/src/main/java/jss/notfine/gui/options/named/GraphicsQualityOff.java new file mode 100644 index 000000000..cf833291b --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/named/GraphicsQualityOff.java @@ -0,0 +1,22 @@ +package jss.notfine.gui.options.named; + +import me.jellysquid.mods.sodium.client.gui.options.named.NamedState; + +public enum GraphicsQualityOff implements NamedState { + DEFAULT("generator.default"), + FANCY("options.graphics.fancy"), + FAST("options.graphics.fast"), + OFF("options.off"); + + private final String name; + + GraphicsQualityOff(String name) { + this.name = name; + } + + @Override + public String getKey() { + return this.name; + } + +} diff --git a/src/main/java/jss/notfine/gui/options/named/GraphicsToggle.java b/src/main/java/jss/notfine/gui/options/named/GraphicsToggle.java new file mode 100644 index 000000000..4c8900dc8 --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/named/GraphicsToggle.java @@ -0,0 +1,21 @@ +package jss.notfine.gui.options.named; + +import me.jellysquid.mods.sodium.client.gui.options.named.NamedState; + +public enum GraphicsToggle implements NamedState { + DEFAULT("generator.default"), + ON("options.on"), + OFF("options.off"); + + private final String name; + + GraphicsToggle(String name) { + this.name = name; + } + + @Override + public String getKey() { + return this.name; + } + +} diff --git a/src/main/java/jss/notfine/gui/options/named/LeavesQuality.java b/src/main/java/jss/notfine/gui/options/named/LeavesQuality.java new file mode 100644 index 000000000..fdbb1da15 --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/named/LeavesQuality.java @@ -0,0 +1,24 @@ +package jss.notfine.gui.options.named; + +import me.jellysquid.mods.sodium.client.gui.options.named.NamedState; + +public enum LeavesQuality implements NamedState { + DEFAULT("generator.default"), + FANCY("options.graphics.fancy"), + FAST("options.graphics.fast"), + SMART("options.graphics.smart"), + SHELLED_FANCY("options.graphics.shelledfancy"), + SHELLED_FAST("options.graphics.shelledfast"); + + private final String name; + + LeavesQuality(String name) { + this.name = name; + } + + @Override + public String getKey() { + return this.name; + } + +} diff --git a/src/main/java/jss/notfine/gui/options/storage/NotFineMinecraftOptionsStorage.java b/src/main/java/jss/notfine/gui/options/storage/NotFineMinecraftOptionsStorage.java new file mode 100644 index 000000000..f5ae66046 --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/storage/NotFineMinecraftOptionsStorage.java @@ -0,0 +1,23 @@ +package jss.notfine.gui.options.storage; + +import jss.notfine.NotFine; +import jss.notfine.core.SettingsManager; +import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; + +public class NotFineMinecraftOptionsStorage implements OptionStorage { + + private final OptionStorageDummy dummy = new OptionStorageDummy(); + + @Override + public OptionStorageDummy getData() { + return dummy; + } + + @Override + public void save() { + SettingsManager.settingsFile.saveSettings(); + + NotFine.logger.info("Flushed changes to NotFine configuration"); + } + +} diff --git a/src/main/java/jss/notfine/gui/options/storage/OptionStorageDummy.java b/src/main/java/jss/notfine/gui/options/storage/OptionStorageDummy.java new file mode 100644 index 000000000..0868c7613 --- /dev/null +++ b/src/main/java/jss/notfine/gui/options/storage/OptionStorageDummy.java @@ -0,0 +1,4 @@ +package jss.notfine.gui.options.storage; + +public class OptionStorageDummy { +} diff --git a/src/main/java/jss/notfine/render/RenderStars.java b/src/main/java/jss/notfine/render/RenderStars.java index 442ba7ec5..fe76673eb 100644 --- a/src/main/java/jss/notfine/render/RenderStars.java +++ b/src/main/java/jss/notfine/render/RenderStars.java @@ -19,7 +19,7 @@ public static void reloadStarRenderList(RenderGlobal render) { } public static void renderStars() { - final int totalStars = (int) Settings.TOTAL_STARS.getValue(); + final int totalStars = (int)Settings.TOTAL_STARS.option.getStore(); if(totalStars <= 0) { return; } diff --git a/src/main/java/jss/notfine/util/ILeafBlock.java b/src/main/java/jss/notfine/util/ILeafBlock.java index ad8561fc9..8c88e2c10 100644 --- a/src/main/java/jss/notfine/util/ILeafBlock.java +++ b/src/main/java/jss/notfine/util/ILeafBlock.java @@ -2,6 +2,7 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; +import jss.notfine.gui.options.named.LeavesQuality; import net.minecraft.block.Block; import net.minecraft.world.IBlockAccess; @@ -9,7 +10,8 @@ public interface ILeafBlock extends IFaceObstructionCheckHelper { @Override() default boolean isFaceNonObstructing(IBlockAccess worldIn, int x, int y, int z, int side, double otherMinX, double otherMinY, double otherMinZ, double otherMaxX, double otherMaxY, double otherMaxZ) { - if((int) Settings.MODE_LEAVES.getValue() == 4) { + + if(Settings.MODE_LEAVES.option.getStore() == LeavesQuality.SHELLED_FAST) { Block otherBlock; otherBlock = worldIn.getBlock(x + 1, y, z); if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { @@ -32,10 +34,7 @@ default boolean isFaceNonObstructing(IBlockAccess worldIn, int x, int y, int z, return true; } otherBlock = worldIn.getBlock(x, y, z - 1); - if(!(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube())) { - return true; - } - return false; + return !(otherBlock instanceof ILeafBlock || otherBlock.isOpaqueCube()); } else { return !SettingsManager.leavesOpaque; } diff --git a/src/main/java/jss/notfine/util/LeafRenderUtil.java b/src/main/java/jss/notfine/util/LeafRenderUtil.java index 20d560c4b..849b08427 100644 --- a/src/main/java/jss/notfine/util/LeafRenderUtil.java +++ b/src/main/java/jss/notfine/util/LeafRenderUtil.java @@ -2,6 +2,7 @@ import jss.notfine.core.Settings; import jss.notfine.core.SettingsManager; +import jss.notfine.gui.options.named.LeavesQuality; import net.minecraft.block.Block; import net.minecraft.util.Facing; import net.minecraft.world.IBlockAccess; @@ -30,11 +31,11 @@ public static boolean shouldSideBeRendered(IBlockAccess worldIn, int x, int y, i return false; } if(otherBlock instanceof ILeafBlock) { - switch ((int) Settings.MODE_LEAVES.getValue()) { - case 1, 2 -> { + switch ((LeavesQuality)Settings.MODE_LEAVES.option.getStore()) { + case FANCY, SMART -> { return false; } - case 3, 4 -> { + case SHELLED_FANCY, SHELLED_FAST -> { x -= Facing.offsetsXForSide[side]; y -= Facing.offsetsYForSide[side]; z -= Facing.offsetsZForSide[side]; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index 42b3b71e4..a807b72a7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -4,8 +4,8 @@ import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import jss.notfine.gui.GuiCustomMenu; -import jss.notfine.gui.MenuButtonLists; import lombok.Getter; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptionPages; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; import net.minecraft.client.Minecraft; @@ -48,7 +48,8 @@ public void onGui(GuiScreenEvent.InitGuiEvent.Pre event) { if(event.gui instanceof GuiVideoSettings eventGui) { event.setCanceled(true); if(GuiScreen.isShiftKeyDown()) { - Minecraft.getMinecraft().displayGuiScreen(new GuiCustomMenu(eventGui.parentGuiScreen, MenuButtonLists.VIDEO)); + Minecraft.getMinecraft().displayGuiScreen(new GuiCustomMenu(eventGui.parentGuiScreen, SodiumGameOptionPages.general(), + SodiumGameOptionPages.quality(), SodiumGameOptionPages.advanced(), SodiumGameOptionPages.performance())); } else { Minecraft.getMinecraft().displayGuiScreen(new SodiumOptionsGUI(eventGui.parentGuiScreen)); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java index f7860366a..0ebeabf70 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java @@ -4,7 +4,6 @@ import com.gtnewhorizons.angelica.client.gui.GuiShaders; import com.gtnewhorizons.angelica.config.AngelicaConfig; import jss.notfine.gui.GuiCustomMenu; -import jss.notfine.gui.MenuButtonLists; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gui.options.Option; import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; @@ -21,13 +20,11 @@ import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget; import me.jellysquid.mods.sodium.client.util.Dim2i; import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.gui.GuiVideoSettings; import net.minecraft.client.resources.I18n; import net.minecraft.util.EnumChatFormatting; import org.lwjgl.input.Keyboard; import java.io.IOException; -import java.net.URI; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; @@ -318,7 +315,8 @@ public void keyTyped(char typedChar, int keyCode) { } if (keyCode == Keyboard.KEY_P && isShiftKeyDown()) { - this.mc.displayGuiScreen(new GuiCustomMenu(this.prevScreen, MenuButtonLists.VIDEO)); + this.mc.displayGuiScreen(new GuiCustomMenu(this.prevScreen, SodiumGameOptionPages.general(), + SodiumGameOptionPages.quality(), SodiumGameOptionPages.advanced(), SodiumGameOptionPages.performance())); } } From f57021da471e0eb16d2f81ec43634505289ec6bf Mon Sep 17 00:00:00 2001 From: jss2a98aj Date: Wed, 29 Nov 2023 00:05:56 -0500 Subject: [PATCH 182/301] Hook up NotFine optimizations --- .../com/gtnewhorizons/angelica/config/AngelicaConfig.java | 5 +++++ .../gtnewhorizons/angelica/loading/AngelicaTweaker.java | 5 +---- .../java/com/gtnewhorizons/angelica/mixins/Mixins.java | 7 +++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index 265d799f5..eb2404fc7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -12,6 +12,11 @@ public class AngelicaConfig { @Config.RequiresMcRestart public static boolean enableIris; + @Config.Comment("Enable NotFine optimizations") + @Config.DefaultBoolean(true) + @Config.RequiresMcRestart + public static boolean enableNotFineOptimizations; + @Config.Comment("Tweak F3 screen to be closer to modern versions. [From ArchaicFix]") @Config.DefaultBoolean(true) public static boolean modernizeF3Screen; diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index e7aa27a7d..36a22c054 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -101,10 +101,7 @@ private List getNotFineMixins(Set loadedCoreMods) { mixins.add("notfine.clouds.MixinRenderGlobal"); mixins.add("notfine.clouds.MixinWorldType"); - mixins.add("notfine.faceculling.MixinBlock"); - mixins.add("notfine.faceculling.MixinBlockSlab"); - mixins.add("notfine.faceculling.MixinBlockSnow"); - mixins.add("notfine.faceculling.MixinBlockStairs"); + mixins.add("notfine.glint.MixinItemRenderer"); mixins.add("notfine.glint.MixinRenderBiped"); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 7ff90317e..cd6bf6c1e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -129,6 +129,13 @@ public enum Mixins { // SHADERSMOD_COMPAT_SMART_RENDER(new Builder("Smart Render compat").addTargetedMod(TargetedMod.SMART_RENDER).setSide(Side.CLIENT) // .addMixinClasses("compat.MixinModelRotationRenderer")) + NOTFINE_OPTIMIZATION(new Builder("NotFine Optimizations").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableNotFineOptimizations).addMixinClasses( + "notfine.faceculling.MixinBlock" + ,"notfine.faceculling.MixinBlockSlab" + ,"notfine.faceculling.MixinBlockSnow" + ,"notfine.faceculling.MixinBlockStairs" + )), ; private final List mixinClasses; From 25b136d9b1dcde13e96fbf176fa92c038de41315 Mon Sep 17 00:00:00 2001 From: jss2a98aj Date: Wed, 29 Nov 2023 00:56:47 -0500 Subject: [PATCH 183/301] Hook up some NotFine features --- .../angelica/config/AngelicaConfig.java | 5 +++++ .../angelica/loading/AngelicaTweaker.java | 12 ------------ .../com/gtnewhorizons/angelica/mixins/Mixins.java | 11 +++++++++++ src/main/java/jss/notfine/core/Settings.java | 3 ++- .../java/jss/notfine/core/SettingsManager.java | 4 +++- .../sodium/client/gui/SodiumGameOptionPages.java | 14 +++++++++++++- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index eb2404fc7..c39b31889 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -17,6 +17,11 @@ public class AngelicaConfig { @Config.RequiresMcRestart public static boolean enableNotFineOptimizations; + @Config.Comment("Enable NotFine features") + @Config.DefaultBoolean(true) + @Config.RequiresMcRestart + public static boolean enableNotFineFeatures; + @Config.Comment("Tweak F3 screen to be closer to modern versions. [From ArchaicFix]") @Config.DefaultBoolean(true) public static boolean modernizeF3Screen; diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java index 36a22c054..d247461ea 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaTweaker.java @@ -101,15 +101,6 @@ private List getNotFineMixins(Set loadedCoreMods) { mixins.add("notfine.clouds.MixinRenderGlobal"); mixins.add("notfine.clouds.MixinWorldType"); - - - mixins.add("notfine.glint.MixinItemRenderer"); - mixins.add("notfine.glint.MixinRenderBiped"); - mixins.add("notfine.glint.MixinRenderItem"); - mixins.add("notfine.glint.MixinRenderPlayer"); - - mixins.add("notfine.gui.MixinGuiSlot"); - mixins.add("notfine.leaves.MixinBlockLeaves"); mixins.add("notfine.leaves.MixinBlockLeavesBase"); @@ -122,9 +113,6 @@ private List getNotFineMixins(Set loadedCoreMods) { mixins.add("notfine.toggle.MixinEntityRenderer"); mixins.add("notfine.toggle.MixinRender"); mixins.add("notfine.toggle.MixinRenderItem"); - - mixins.add("notfine.settings.MixinGameSettings"); - mixins.add("notfine.renderer.MixinRenderGlobal"); return mixins; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index cd6bf6c1e..211860c55 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -136,6 +136,17 @@ public enum Mixins { ,"notfine.faceculling.MixinBlockSnow" ,"notfine.faceculling.MixinBlockStairs" )), + + NOTFINE_FEATURES(new Builder("NotFine Features").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableNotFineFeatures).addMixinClasses( + "notfine.glint.MixinItemRenderer" + ,"notfine.glint.MixinRenderBiped" + ,"notfine.glint.MixinRenderItem" + ,"notfine.glint.MixinRenderPlayer" + ,"notfine.gui.MixinGuiSlot" + ,"notfine.renderer.MixinRenderGlobal" + ,"notfine.settings.MixinGameSettings" + )) ; private final List mixinClasses; diff --git a/src/main/java/jss/notfine/core/Settings.java b/src/main/java/jss/notfine/core/Settings.java index 42b65f35e..5d1d601b0 100644 --- a/src/main/java/jss/notfine/core/Settings.java +++ b/src/main/java/jss/notfine/core/Settings.java @@ -1,5 +1,6 @@ package jss.notfine.core; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import jss.notfine.gui.options.control.NotFineControlValueFormatter; import jss.notfine.gui.options.named.AlwaysNever; import jss.notfine.gui.options.named.BackgroundSelect; @@ -254,7 +255,7 @@ public OptionStorage getStorage() { @Override public boolean isAvailable() { - return true; + return AngelicaConfig.enableNotFineFeatures; } @Override diff --git a/src/main/java/jss/notfine/core/SettingsManager.java b/src/main/java/jss/notfine/core/SettingsManager.java index 1dfcc3276..e63bd6cec 100644 --- a/src/main/java/jss/notfine/core/SettingsManager.java +++ b/src/main/java/jss/notfine/core/SettingsManager.java @@ -32,7 +32,9 @@ public class SettingsManager { public static boolean waterDetail; public static boolean vignette; public static byte downfallDistance; - public static double entityRenderScaleFactor; + + //TODO: Hook up using sodium system + public static double entityRenderScaleFactor = 20000; public static ResourceLocation defaultBackground = Gui.optionsBackground; public static ResourceLocation[] extraBackgrounds = new ResourceLocation[] { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index 942af23c0..944baa1ff 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.gui; import com.google.common.collect.ImmutableList; +import jss.notfine.core.Settings; import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; import me.jellysquid.mods.sodium.client.gui.options.OptionGroup; import me.jellysquid.mods.sodium.client.gui.options.OptionImpact; @@ -47,6 +48,7 @@ public static OptionPage general() { .setControl(opt -> new SliderControl(opt, 0, 100, 1, ControlValueFormatter.brightness())) .setBinding((opts, value) -> opts.gammaSetting = value * 0.01F, (opts) -> (int) (opts.gammaSetting / 0.01F)) .build()) + .add(Settings.MODE_SKY.option) .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) .setName(I18n.format("sodium.options.clouds.name")) .setTooltip(I18n.format("sodium.options.clouds.tooltip")) @@ -133,6 +135,7 @@ public static OptionPage quality() { .build()); groups.add(OptionGroup.createBuilder() + .add(Settings.MODE_GUI_BACKGROUND.option) .add(OptionImpl.createBuilder(GraphicsQuality.class, sodiumOpts) .setName(I18n.format("options.renderClouds")) .setTooltip(I18n.format("sodium.options.clouds_quality.tooltip")) @@ -201,6 +204,7 @@ public static OptionPage quality() { .setBinding((opts, value) -> opts.quality.enableVignette = value, opts -> opts.quality.enableVignette) .setImpact(OptionImpact.LOW) .build()) + .add(Settings.TOTAL_STARS.option) .build()); @@ -214,7 +218,10 @@ public static OptionPage quality() { .setFlags(OptionFlag.REQUIRES_ASSET_RELOAD) .build()) .build()); - + groups.add(OptionGroup.createBuilder() + .add(Settings.MODE_GLINT_INV.option) + .add(Settings.MODE_GLINT_WORLD.option) + .build()); return new OptionPage(I18n.format("sodium.options.pages.quality"), ImmutableList.copyOf(groups)); } @@ -326,6 +333,11 @@ public static OptionPage advanced() { ) .build()); + groups.add(OptionGroup.createBuilder() + .add(Settings.MODE_GUI_BACKGROUND.option) + .add(Settings.GUI_BACKGROUND.option) + .build()); + return new OptionPage(I18n.format("sodium.options.pages.advanced"), ImmutableList.copyOf(groups)); } From 53f39ff31b9ab9f6d2bd072aacc08222811dbb3f Mon Sep 17 00:00:00 2001 From: jss2a98aj Date: Wed, 29 Nov 2023 00:58:37 -0500 Subject: [PATCH 184/301] Don't use MODE_GUI_BACKGROUND twice oops --- .../jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index 944baa1ff..e21d8d9d6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -135,7 +135,6 @@ public static OptionPage quality() { .build()); groups.add(OptionGroup.createBuilder() - .add(Settings.MODE_GUI_BACKGROUND.option) .add(OptionImpl.createBuilder(GraphicsQuality.class, sodiumOpts) .setName(I18n.format("options.renderClouds")) .setTooltip(I18n.format("sodium.options.clouds_quality.tooltip")) From 96dcd740a6dafd9bafdaddc72609e48e40857bfb Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 29 Nov 2023 08:31:30 -0800 Subject: [PATCH 185/301] Don't enable NotFine features by default until Sodium & Iris are fully working in isolation --- .../com/gtnewhorizons/angelica/config/AngelicaConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index c39b31889..5fa045763 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -13,12 +13,12 @@ public class AngelicaConfig { public static boolean enableIris; @Config.Comment("Enable NotFine optimizations") - @Config.DefaultBoolean(true) + @Config.DefaultBoolean(false) @Config.RequiresMcRestart public static boolean enableNotFineOptimizations; @Config.Comment("Enable NotFine features") - @Config.DefaultBoolean(true) + @Config.DefaultBoolean(false) @Config.RequiresMcRestart public static boolean enableNotFineFeatures; From 31cbdd002ca0c8edb54cc0b2db1dc2a0d83cadeb Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 29 Nov 2023 08:55:37 -0800 Subject: [PATCH 186/301] Transform byte values into floats for caching --- .../angelica/glsm/GLStateManager.java | 21 ++++++++++++------- .../angelica/glsm/states/Color4.java | 8 +++---- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index fb8fa58fe..aac387262 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -220,19 +220,19 @@ public static void glColor4f(float red, float green, float blue, float alpha) { } } public static void glColor4d(double red, double green, double blue, double alpha) { - if (changeColor(red, green, blue, alpha)) { + if (changeColor((float)red, (float)green, (float)blue, (float)alpha)) { GL11.glColor4d(red, green, blue, alpha); } } public static void glColor4b(byte red, byte green, byte blue, byte alpha) { - if (changeColor(red, green, blue, alpha)) { + if (changeColor(b2f(red), b2f(green), b2f(blue), b2f(alpha))) { GL11.glColor4b(red, green, blue, alpha); } } public static void glColor4ub(byte red, byte green, byte blue, byte alpha) { - if (changeColor(red, green, blue, alpha)) { + if (changeColor(ub2f(red), ub2f(green), ub2f(blue), ub2f(alpha))) { GL11.glColor4ub(red, green, blue, alpha); } } @@ -244,24 +244,31 @@ public static void glColor3f(float red, float green, float blue) { } public static void glColor3d(double red, double green, double blue) { - if(changeColor(red, green, blue, 1.0F)) { + if(changeColor((float)red, (float)green, (float)blue, 1.0F)) { GL11.glColor3d(red, green, blue); } } public static void glColor3b(byte red, byte green, byte blue) { - if(changeColor(red, green, blue, 1.0F)) { + if(changeColor(b2f(red), b2f(green), b2f(blue), 1.0F)) { GL11.glColor3b(red, green, blue); } } public static void glColor3ub(byte red, byte green, byte blue) { - if(changeColor(red, green, blue, 1.0F)) { + if(changeColor(ub2f(red), ub2f(green), ub2f(blue), 1.0F)) { GL11.glColor3ub(red, green, blue); } } + private static float ub2f(byte b) { + return (b & 0xFF) / 255.0F; + } + + private static float b2f(byte b) { + return ((b - Byte.MIN_VALUE) & 0xFF) / 255.0F; + } - private static boolean changeColor(double red, double green, double blue, double alpha) { + private static boolean changeColor(float red, float green, float blue, float alpha) { // Helper function for glColor* if(red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { Color.red = red; diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java index 783e73218..c86b0af44 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/Color4.java @@ -1,9 +1,9 @@ package com.gtnewhorizons.angelica.glsm.states; public class Color4 { - public double red = 1.0F; - public double green = 1.0F; - public double blue = 1.0F; - public double alpha = 1.0F; + public float red = 1.0F; + public float green = 1.0F; + public float blue = 1.0F; + public float alpha = 1.0F; } From aac5bc9563454b0645c2079c26efe3ffb862962f Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 29 Nov 2023 12:36:15 -0500 Subject: [PATCH 187/301] Partially neuter GlStateTracker to avoid pipeline stalls --- .../client/gl/state/GlStateTracker.java | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java index 8ffd079a1..1358ba1b9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java @@ -13,10 +13,10 @@ public class GlStateTracker { private static final int UNASSIGNED_HANDLE = -1; private final int[] bufferState = new int[GlBufferTarget.COUNT]; - private final int[] bufferRestoreState = new int[GlBufferTarget.COUNT]; + //private final int[] bufferRestoreState = new int[GlBufferTarget.COUNT]; private int vertexArrayState; - private int vertexArrayRestoreState; + //private int vertexArrayRestoreState; public GlStateTracker() { this.clearRestoreState(); @@ -29,10 +29,6 @@ public boolean makeBufferActive(GlBufferTarget target, GlBuffer buffer) { private boolean makeBufferActive(GlBufferTarget target, int buffer) { int prevBuffer = this.bufferState[target.ordinal()]; - if (prevBuffer == UNASSIGNED_HANDLE) { - this.bufferRestoreState[target.ordinal()] = GL11.glGetInteger(target.getBindingParameter()); - } - this.bufferState[target.ordinal()] = buffer; return prevBuffer != buffer; @@ -45,10 +41,6 @@ public boolean makeVertexArrayActive(GlVertexArray array) { private boolean makeVertexArrayActive(int array) { int prevArray = this.vertexArrayState; - if (prevArray == UNASSIGNED_HANDLE) { - this.vertexArrayRestoreState = GL11.glGetInteger(GL30.GL_VERTEX_ARRAY_BINDING); - } - this.vertexArrayState = array; return prevArray != array; @@ -56,21 +48,17 @@ private boolean makeVertexArrayActive(int array) { public void applyRestoreState() { for (int i = 0; i < GlBufferTarget.COUNT; i++) { - if (this.bufferState[i] != this.bufferRestoreState[i] && this.bufferRestoreState[i] != UNASSIGNED_HANDLE) { - GL15.glBindBuffer(GlBufferTarget.VALUES[i].getTargetParameter(), this.bufferRestoreState[i]); - } + GL15.glBindBuffer(GlBufferTarget.VALUES[i].getTargetParameter(), 0); } - if (this.vertexArrayState != this.vertexArrayRestoreState && this.vertexArrayRestoreState != UNASSIGNED_HANDLE) { - GL30.glBindVertexArray(this.vertexArrayRestoreState); - } + GL30.glBindVertexArray(0); } public void clearRestoreState() { Arrays.fill(this.bufferState, UNASSIGNED_HANDLE); - Arrays.fill(this.bufferRestoreState, UNASSIGNED_HANDLE); + //Arrays.fill(this.bufferRestoreState, UNASSIGNED_HANDLE); this.vertexArrayState = UNASSIGNED_HANDLE; - this.vertexArrayRestoreState = UNASSIGNED_HANDLE; + //this.vertexArrayRestoreState = UNASSIGNED_HANDLE; } } From 969995b48f23a052c38c016c1ef33616c1c05a88 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 29 Nov 2023 19:06:52 -0500 Subject: [PATCH 188/301] Add grass quality --- .../angelica/mixins/early/sodium/MixinMinecraft.java | 6 ++++++ .../mods/sodium/client/gui/SodiumGameOptionPages.java | 8 ++++++++ .../mods/sodium/client/gui/SodiumGameOptions.java | 1 + src/main/resources/assets/angelica/lang/en_US.lang | 2 ++ 4 files changed, 17 insertions(+) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java index a1cfbc827..269edd32e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java @@ -5,6 +5,7 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.settings.GameSettings; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -29,6 +30,11 @@ public class MixinMinecraft { return ((IRenderGlobalExt)this.renderGlobal).getChunksSubmitted(); } + @Redirect(method = "runGameLoop", at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;fancyGraphics:Z")) + private boolean sodium$overrideFancyGrass(GameSettings gameSettings) { + return SodiumClientMod.options().quality.grassQuality.isFancy(); + } + @Inject(method = "checkGLError", at = @At(value = "HEAD"), cancellable = true) private void sodium$checkGLError(CallbackInfo ci) { if(SodiumClientMod.options().performance.useNoErrorGLContext) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index e21d8d9d6..58b3a2485 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -164,6 +164,14 @@ public static OptionPage quality() { .setBinding((opts, value) -> opts.particleSetting = value.ordinal(), (opts) -> ParticleMode.fromOrdinal(opts.particleSetting)) .setImpact(OptionImpact.LOW) .build()) + .add(OptionImpl.createBuilder(GraphicsQuality.class, sodiumOpts) + .setName(I18n.format("sodium.options.grass_quality.name")) + .setTooltip(I18n.format("sodium.options.grass_quality.tooltip")) + .setControl(option -> new CyclingControl<>(option, GraphicsQuality.class)) + .setBinding((opts, value) -> opts.quality.grassQuality = value, opts -> opts.quality.grassQuality) + .setImpact(OptionImpact.MEDIUM) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()) .add(OptionImpl.createBuilder(LightingQuality.class, vanillaOpts) .setName(I18n.format("options.ao")) .setTooltip(I18n.format("sodium.options.smooth_lighting.tooltip")) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 18ebd8af2..6c3aef180 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -60,6 +60,7 @@ public static class QualitySettings { public GraphicsQuality cloudQuality = GraphicsQuality.DEFAULT; public GraphicsQuality weatherQuality = GraphicsQuality.DEFAULT; public GraphicsQuality leavesQuality = GraphicsQuality.DEFAULT; + public GraphicsQuality grassQuality = GraphicsQuality.DEFAULT; public GraphicsQuality entityShadows = GraphicsQuality.DEFAULT; public GraphicsQuality enableVignette = GraphicsQuality.DEFAULT; } diff --git a/src/main/resources/assets/angelica/lang/en_US.lang b/src/main/resources/assets/angelica/lang/en_US.lang index ff4d50724..c37b9e90a 100644 --- a/src/main/resources/assets/angelica/lang/en_US.lang +++ b/src/main/resources/assets/angelica/lang/en_US.lang @@ -27,6 +27,8 @@ sodium.options.clouds_quality.tooltip=Controls the quality of rendered clouds in sodium.options.weather_quality.tooltip=Controls the quality of rain and snow effects. sodium.options.leaves_quality.name=Leaves Quality sodium.options.leaves_quality.tooltip=Controls the quality of leaves. +sodium.options.grass_quality.name=Grass Quality +sodium.options.grass_quality.tooltip=Controls the quality of grass block sides. sodium.options.particle_quality.name=Particle Quality sodium.options.particle_quality.tooltip=Controls the maximum number of particles which can be present on screen at any one time. sodium.options.smooth_lighting.tooltip=Controls whether blocks will be smoothly lit and shaded. This slightly increases the amount of time needed to re-build a chunk, but doesn't affect frame rates. From fa624c7fcdac870a915cd09560a08810cf3f5a0e Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Wed, 29 Nov 2023 01:38:44 +0100 Subject: [PATCH 189/301] copy over hud caching code from hodgepodge --- .../angelica/hudcaching/HUDCaching.java | 184 ++++++++++++++++++ .../gtnewhorizons/angelica/mixins/Mixins.java | 11 ++ .../hudcaching/GuiIngameForgeAccessor.java | 12 ++ .../MixinEntityRenderer_HUDCaching.java | 26 +++ .../MixinFramebuffer_HUDCaching.java | 23 +++ .../MixinGuiIngameForge_HUDCaching.java | 19 ++ .../hudcaching/MixinGuiIngame_HUDCaching.java | 19 ++ .../MixinOpenGlHelper_HUDCaching.java | 44 +++++ 8 files changed, 338 insertions(+) create mode 100644 src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/GuiIngameForgeAccessor.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinFramebuffer_HUDCaching.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngameForge_HUDCaching.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngame_HUDCaching.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinOpenGlHelper_HUDCaching.java diff --git a/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java new file mode 100644 index 000000000..1af87e807 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java @@ -0,0 +1,184 @@ +package com.gtnewhorizons.angelica.hudcaching; + +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.glsm.TessellatorManager; +import com.gtnewhorizons.angelica.mixins.early.angelica.hudcaching.GuiIngameForgeAccessor; +import cpw.mods.fml.client.registry.ClientRegistry; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.InputEvent; +import cpw.mods.fml.common.gameevent.TickEvent; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiIngame; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.settings.KeyBinding; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.client.GuiIngameForge; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.common.MinecraftForge; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; + +// TODO add license from Sk1er/patcher with special credit to Moulberry https://github.com/Moulberry + +public class HUDCaching { + + private static final Minecraft mc = Minecraft.getMinecraft(); + public static Framebuffer framebuffer; + private static boolean dirty = true; + public static boolean renderingCacheOverride; + + static { + final HUDCaching hudCaching = new HUDCaching(); + FMLCommonHandler.instance().bus().register(hudCaching); + MinecraftForge.EVENT_BUS.register(hudCaching);// TODO remove debug stuff, unsued registration + } + + private HUDCaching() {} + + /* TODO START REMOVE DEBUG STUFF */ + + private final List updateTimeList = new ArrayList<>(21); + private static boolean isEnabled = true; + private static final KeyBinding toggle = new KeyBinding("Toggle HUDCaching", 0, "Debug"); + + static { + ClientRegistry.registerKeyBinding(toggle); + } + +// @SubscribeEvent +// public void onFrame(RenderGameOverlayEvent.Post event) { +// if (event.type == RenderGameOverlayEvent.ElementType.TEXT) { +// final long currentTimeMillis = System.currentTimeMillis(); +// updateTimeList.removeIf(time -> currentTimeMillis - time > 1000L); +// String text = EnumChatFormatting.GREEN + "HUD Fps : " + updateTimeList.size(); +// mc.fontRenderer.drawStringWithShadow( +// text, +// event.resolution.getScaledWidth() / 4, +// event.resolution.getScaledHeight() / 4, +// 0xFFFFFF); +// updateTimeList.add(currentTimeMillis); +// } +// } + + @SubscribeEvent + public void onKeypress(InputEvent.KeyInputEvent event) { + if (toggle.isPressed()) { + isEnabled = !isEnabled; + final String msg = isEnabled ? "Enabled HUDCaching" : "Disabled HUDCaching"; + if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText(msg)); + } + } + + /* END REMOVE DEBUG STUFF */ + + @SubscribeEvent + public void onTick(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.END) { + dirty = true; + } + } + + @SuppressWarnings("unused") + public static void renderCachedHud(EntityRenderer renderer, GuiIngame ingame, float partialTicks, boolean p_73830_2_, int p_73830_3_, int p_73830_4_) { + + if (!OpenGlHelper.isFramebufferEnabled() || !isEnabled) { + ingame.renderGameOverlay(partialTicks, p_73830_2_, p_73830_3_, p_73830_4_); + return; + } + + GLStateManager.enableDepthTest(); + ScaledResolution resolution = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); + int width = resolution.getScaledWidth(); + int height = resolution.getScaledHeight(); + renderer.setupOverlayRendering(); + GLStateManager.enableBlend(); + + if (framebuffer != null) { + Tessellator tessellator = TessellatorManager.get(); + if (ingame instanceof GuiIngameForge) { + ((GuiIngameForgeAccessor) ingame).callRenderCrosshairs(width, height); + } else if (GuiIngameForge.renderCrosshairs) { + mc.getTextureManager().bindTexture(Gui.icons); + GLStateManager.enableBlend(); + OpenGlHelper.glBlendFunc(GL11.GL_ONE_MINUS_DST_COLOR, GL11.GL_ONE_MINUS_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO); + GLStateManager.enableAlphaTest(); + drawTexturedModalRect(tessellator, (width >> 1) - 7, (height >> 1) - 7); + OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + } + + GLStateManager.enableBlend(); + OpenGlHelper.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GLStateManager.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + framebuffer.bindFramebufferTexture(); + drawTexturedRect(tessellator, (float) resolution.getScaledWidth_double(), (float) resolution.getScaledHeight_double()); + OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + } + + if (framebuffer == null || dirty) { + dirty = false; + framebuffer = checkFramebufferSizes(framebuffer, mc.displayWidth, mc.displayHeight); + framebuffer.framebufferClear(); + framebuffer.bindFramebuffer(false); + GLStateManager.disableBlend(); + OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GLStateManager.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GLStateManager.disableLighting(); + GLStateManager.disableFog(); + renderingCacheOverride = true; + ingame.renderGameOverlay(partialTicks, p_73830_2_, p_73830_3_, p_73830_4_); + renderingCacheOverride = false; + mc.getFramebuffer().bindFramebuffer(false); + GLStateManager.enableBlend(); + } + + GLStateManager.enableDepthTest(); + } + + private static Framebuffer checkFramebufferSizes(Framebuffer framebuffer, int width, int height) { + if (framebuffer == null || framebuffer.framebufferWidth != width || framebuffer.framebufferHeight != height) { + if (framebuffer == null) { + framebuffer = new Framebuffer(width, height, true); + framebuffer.framebufferColor[0] = 0.0F; + framebuffer.framebufferColor[1] = 0.0F; + framebuffer.framebufferColor[2] = 0.0F; + } else { + framebuffer.createBindFramebuffer(width, height); + } + framebuffer.setFramebufferFilter(GL11.GL_NEAREST); + } + return framebuffer; + } + + private static void drawTexturedRect(Tessellator tessellator, float width, float height) { + GLStateManager.enableTexture(); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(0, height, 0.0, 0, 0); + tessellator.addVertexWithUV(width, height, 0.0, 1, 0); + tessellator.addVertexWithUV(width, 0, 0.0, 1, 1); + tessellator.addVertexWithUV(0, 0, 0.0, 0, 1); + tessellator.draw(); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + } + + private static void drawTexturedModalRect(Tessellator tessellator, int x, int y) { + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(x, y + 16, 100.0, 0.0, 0.0625); + tessellator.addVertexWithUV(x + 16, y + 16, 100.0, 0.0625, 0.0625); + tessellator.addVertexWithUV(x + 16, y, 100.0, 0.0625, 0.0); + tessellator.addVertexWithUV(x, y, 100.0, 0.0, 0.0); + tessellator.draw(); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 211860c55..ee1530bda 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -121,6 +121,17 @@ public enum Mixins { "angelica.textures.MixinTextureAtlasSprite" )), + HUD_CACHING(new Builder("Renders the HUD elements 20 times per second maximum to improve performance") + .addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT).setPhase(Phase.EARLY) + .addMixinClasses( + "angelica.hudcaching.GuiIngameForgeAccessor", + "angelica.hudcaching.MixinEntityRenderer_HUDCaching", + "angelica.hudcaching.MixinFramebuffer_HUDCaching", + "angelica.hudcaching.MixinGuiIngame_HUDCaching", + "angelica.hudcaching.MixinGuiIngameForge_HUDCaching", + "angelica.hudcaching.MixinOpenGlHelper_HUDCaching") + .setApplyIf(() -> true)), // TODO add config + // TODO: Iris // SHADERSMOD_COMPAT_PR_ILLUMINATION( // new Builder("ProjectRed Illumination compat").addTargetedMod(TargetedMod.PROJECTRED_ILLUMINATION) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/GuiIngameForgeAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/GuiIngameForgeAccessor.java new file mode 100644 index 000000000..8761bb0e9 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/GuiIngameForgeAccessor.java @@ -0,0 +1,12 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.hudcaching; + +import net.minecraftforge.client.GuiIngameForge; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(GuiIngameForge.class) +public interface GuiIngameForgeAccessor { + + @Invoker(remap = false) + void callRenderCrosshairs(int width, int height); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java new file mode 100644 index 000000000..9c46832da --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java @@ -0,0 +1,26 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.hudcaching; + +import com.gtnewhorizons.angelica.hudcaching.HUDCaching; +import net.minecraft.client.gui.GuiIngame; +import net.minecraft.client.renderer.EntityRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(value = EntityRenderer.class) +public class MixinEntityRenderer_HUDCaching { + + @Redirect( + method = "updateCameraAndRender", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiIngame;renderGameOverlay(FZII)V")) + public void hodgepodge$renderCachedHUD(GuiIngame guiIngame, float partialTicks, boolean p_73830_2_, int p_73830_3_, + int p_73830_4_) { + HUDCaching.renderCachedHud( + (EntityRenderer) (Object) this, + guiIngame, + partialTicks, + p_73830_2_, + p_73830_3_, + p_73830_4_); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinFramebuffer_HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinFramebuffer_HUDCaching.java new file mode 100644 index 000000000..7aca70cff --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinFramebuffer_HUDCaching.java @@ -0,0 +1,23 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.hudcaching; + +import com.gtnewhorizons.angelica.hudcaching.HUDCaching; +import net.minecraft.client.Minecraft; +import net.minecraft.client.shader.Framebuffer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Framebuffer.class) +public class MixinFramebuffer_HUDCaching { + + @Inject(method = "bindFramebuffer", at = @At("HEAD"), cancellable = true) + public void hodgepodge$bindHUDCachingBuffer(boolean viewport, CallbackInfo ci) { + final Framebuffer framebuffer = (Framebuffer) (Object) this; + if (HUDCaching.renderingCacheOverride && framebuffer == Minecraft.getMinecraft().getFramebuffer()) { + HUDCaching.framebuffer.bindFramebuffer(viewport); + ci.cancel(); + } + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngameForge_HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngameForge_HUDCaching.java new file mode 100644 index 000000000..2e170e3c1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngameForge_HUDCaching.java @@ -0,0 +1,19 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.hudcaching; + +import com.gtnewhorizons.angelica.hudcaching.HUDCaching; +import net.minecraftforge.client.GuiIngameForge; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GuiIngameForge.class) +public class MixinGuiIngameForge_HUDCaching { + + @Inject(method = "renderCrosshairs", at = @At("HEAD"), cancellable = true, remap = false) + private void hodgepodge$cancelCrosshair(CallbackInfo ci) { + if (HUDCaching.renderingCacheOverride) { + ci.cancel(); + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngame_HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngame_HUDCaching.java new file mode 100644 index 000000000..12ab12da2 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngame_HUDCaching.java @@ -0,0 +1,19 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.hudcaching; + +import com.gtnewhorizons.angelica.hudcaching.HUDCaching; +import net.minecraft.client.gui.GuiIngame; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GuiIngame.class) +public class MixinGuiIngame_HUDCaching { + + @Inject(method = "renderVignette", at = @At("HEAD"), cancellable = true) + private void hodgepodge$cancelVignette(CallbackInfo ci) { + if (HUDCaching.renderingCacheOverride) { + ci.cancel(); + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinOpenGlHelper_HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinOpenGlHelper_HUDCaching.java new file mode 100644 index 000000000..aab4c9b18 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinOpenGlHelper_HUDCaching.java @@ -0,0 +1,44 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.hudcaching; + +import com.gtnewhorizons.angelica.hudcaching.HUDCaching; +import net.minecraft.client.renderer.OpenGlHelper; +import org.lwjgl.opengl.EXTBlendFuncSeparate; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(OpenGlHelper.class) +public class MixinOpenGlHelper_HUDCaching { + + @Shadow + private static boolean openGL14; + + @Shadow + public static boolean field_153211_u; + + // TODO don't override, do modify variable or inject via ASM with GlStateManager + + /** + * @author ee + * @reason eee + */ + @Overwrite + public static void glBlendFunc(int srcFactor, int dstFactor, int srcFactorAlpha, int dstFactorAlpha) { + if (HUDCaching.renderingCacheOverride && dstFactorAlpha != GL11.GL_ONE_MINUS_SRC_ALPHA) { + srcFactorAlpha = GL11.GL_ONE; + dstFactorAlpha = GL11.GL_ONE_MINUS_SRC_ALPHA; + } + if (openGL14) { + if (field_153211_u) { + EXTBlendFuncSeparate.glBlendFuncSeparateEXT(srcFactor, dstFactor, srcFactorAlpha, dstFactorAlpha); + } else { + GL14.glBlendFuncSeparate(srcFactor, dstFactor, srcFactorAlpha, dstFactorAlpha); + } + } else { + GL11.glBlendFunc(srcFactor, dstFactor); + } + } + +} From 808500fd4f4d66dbc0214f4f8bb1080def365f77 Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Wed, 29 Nov 2023 03:30:13 +0100 Subject: [PATCH 190/301] backport glstatemanager mixin --- .../angelica/glsm/GLStateManager.java | 38 ++++++++++++++++ .../angelica/hudcaching/HUDCaching.java | 2 + .../gtnewhorizons/angelica/mixins/Mixins.java | 3 +- .../MixinEntityRenderer_HUDCaching.java | 2 +- .../MixinFramebuffer_HUDCaching.java | 2 +- .../MixinGuiIngameForge_HUDCaching.java | 2 +- .../hudcaching/MixinGuiIngame_HUDCaching.java | 2 +- .../MixinOpenGlHelper_HUDCaching.java | 44 ------------------- 8 files changed, 45 insertions(+), 50 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinOpenGlHelper_HUDCaching.java diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index aac387262..3d829d62a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -9,6 +9,7 @@ import com.gtnewhorizons.angelica.glsm.states.FogState; import com.gtnewhorizons.angelica.glsm.states.GLColorMask; import com.gtnewhorizons.angelica.glsm.states.TextureState; +import com.gtnewhorizons.angelica.hudcaching.HUDCaching; import lombok.Getter; import net.coderbot.iris.Iris; import net.coderbot.iris.gbuffer_overrides.state.StateTracker; @@ -21,6 +22,7 @@ import net.coderbot.iris.texture.TextureInfoCache; import net.coderbot.iris.texture.TextureTracker; import net.coderbot.iris.texture.pbr.PBRTextureManager; +import net.minecraft.client.renderer.OpenGlHelper; import org.joml.Vector3d; import org.lwjgl.opengl.ARBMultitexture; import org.lwjgl.opengl.EXTBlendFuncSeparate; @@ -67,6 +69,8 @@ public class GLStateManager { private static final Thread MainThread = Thread.currentThread(); private static boolean runningSplash = false; + private static boolean hudCaching$blendEnabled; + public static void init() { if (AngelicaConfig.enableIris) { StateUpdateNotifiers.blendFuncNotifier = listener -> blendFuncListener = listener; @@ -118,6 +122,9 @@ public static void glDisable(int cap) { // GLStateManager Functions public static void enableBlend() { + if (HUDCaching.renderingCacheOverride) { + hudCaching$blendEnabled = true; + } if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendModeToggle(true); @@ -128,6 +135,9 @@ public static void enableBlend() { } public static void disableBlend() { + if (HUDCaching.renderingCacheOverride) { + hudCaching$blendEnabled = false; + } if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendModeToggle(false); @@ -138,6 +148,10 @@ public static void disableBlend() { } public static void glBlendFunc(int srcFactor, int dstFactor) { + if (HUDCaching.renderingCacheOverride) { + GL14.glBlendFuncSeparate(srcFactor, dstFactor, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + return; + } if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendFunc(srcFactor, dstFactor, srcFactor, dstFactor); @@ -155,6 +169,10 @@ public static void glBlendFunc(int srcFactor, int dstFactor) { } public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { + if (HUDCaching.renderingCacheOverride && dstAlpha != GL11.GL_ONE_MINUS_SRC_ALPHA) { + GL14.glBlendFuncSeparate(srcRgb, dstRgb, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + return; + } if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); @@ -174,6 +192,10 @@ public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int } public static void glBlendFuncSeparateEXT(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { + if (HUDCaching.renderingCacheOverride && dstAlpha != GL11.GL_ONE_MINUS_SRC_ALPHA) { + EXTBlendFuncSeparate.glBlendFuncSeparateEXT(srcRgb, dstRgb, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + return; + } if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); @@ -215,23 +237,39 @@ public static void glDepthMask(boolean mask) { } public static void glColor4f(float red, float green, float blue, float alpha) { + if (!hudCaching$blendEnabled && HUDCaching.renderingCacheOverride && alpha < 1f) { + GL11.glColor4f(red, green, blue, 1f); + return; + } if (changeColor(red, green, blue, alpha)) { GL11.glColor4f(red, green, blue, alpha); } } public static void glColor4d(double red, double green, double blue, double alpha) { + if (!hudCaching$blendEnabled && HUDCaching.renderingCacheOverride && alpha < 1d) { + GL11.glColor4d(red, green, blue, 1d); + return; + } if (changeColor((float)red, (float)green, (float)blue, (float)alpha)) { GL11.glColor4d(red, green, blue, alpha); } } public static void glColor4b(byte red, byte green, byte blue, byte alpha) { + if (!hudCaching$blendEnabled && HUDCaching.renderingCacheOverride && alpha < Byte.MAX_VALUE) { + GL11.glColor4b(red, green, blue, Byte.MAX_VALUE); + return; + } if (changeColor(b2f(red), b2f(green), b2f(blue), b2f(alpha))) { GL11.glColor4b(red, green, blue, alpha); } } public static void glColor4ub(byte red, byte green, byte blue, byte alpha) { + if (!hudCaching$blendEnabled && HUDCaching.renderingCacheOverride && alpha < Byte.MAX_VALUE) { + GL11.glColor4b(red, green, blue, Byte.MAX_VALUE); + return; + } if (changeColor(ub2f(red), ub2f(green), ub2f(blue), ub2f(alpha))) { GL11.glColor4ub(red, green, blue, alpha); } diff --git a/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java index 1af87e807..338318f8a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java +++ b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java @@ -87,6 +87,8 @@ public void onTick(TickEvent.ClientTickEvent event) { } } + // TODO draw vignette + @SuppressWarnings("unused") public static void renderCachedHud(EntityRenderer renderer, GuiIngame ingame, float partialTicks, boolean p_73830_2_, int p_73830_3_, int p_73830_4_) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index ee1530bda..3ecd5931a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -128,8 +128,7 @@ public enum Mixins { "angelica.hudcaching.MixinEntityRenderer_HUDCaching", "angelica.hudcaching.MixinFramebuffer_HUDCaching", "angelica.hudcaching.MixinGuiIngame_HUDCaching", - "angelica.hudcaching.MixinGuiIngameForge_HUDCaching", - "angelica.hudcaching.MixinOpenGlHelper_HUDCaching") + "angelica.hudcaching.MixinGuiIngameForge_HUDCaching") .setApplyIf(() -> true)), // TODO add config // TODO: Iris diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java index 9c46832da..0303d2203 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java @@ -13,7 +13,7 @@ public class MixinEntityRenderer_HUDCaching { @Redirect( method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiIngame;renderGameOverlay(FZII)V")) - public void hodgepodge$renderCachedHUD(GuiIngame guiIngame, float partialTicks, boolean p_73830_2_, int p_73830_3_, + public void angelica$renderCachedHUD(GuiIngame guiIngame, float partialTicks, boolean p_73830_2_, int p_73830_3_, int p_73830_4_) { HUDCaching.renderCachedHud( (EntityRenderer) (Object) this, diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinFramebuffer_HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinFramebuffer_HUDCaching.java index 7aca70cff..68d4599c6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinFramebuffer_HUDCaching.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinFramebuffer_HUDCaching.java @@ -12,7 +12,7 @@ public class MixinFramebuffer_HUDCaching { @Inject(method = "bindFramebuffer", at = @At("HEAD"), cancellable = true) - public void hodgepodge$bindHUDCachingBuffer(boolean viewport, CallbackInfo ci) { + public void angelica$bindHUDCachingBuffer(boolean viewport, CallbackInfo ci) { final Framebuffer framebuffer = (Framebuffer) (Object) this; if (HUDCaching.renderingCacheOverride && framebuffer == Minecraft.getMinecraft().getFramebuffer()) { HUDCaching.framebuffer.bindFramebuffer(viewport); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngameForge_HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngameForge_HUDCaching.java index 2e170e3c1..337825adb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngameForge_HUDCaching.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngameForge_HUDCaching.java @@ -11,7 +11,7 @@ public class MixinGuiIngameForge_HUDCaching { @Inject(method = "renderCrosshairs", at = @At("HEAD"), cancellable = true, remap = false) - private void hodgepodge$cancelCrosshair(CallbackInfo ci) { + private void angelica$cancelCrosshair(CallbackInfo ci) { if (HUDCaching.renderingCacheOverride) { ci.cancel(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngame_HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngame_HUDCaching.java index 12ab12da2..f90120dea 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngame_HUDCaching.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinGuiIngame_HUDCaching.java @@ -11,7 +11,7 @@ public class MixinGuiIngame_HUDCaching { @Inject(method = "renderVignette", at = @At("HEAD"), cancellable = true) - private void hodgepodge$cancelVignette(CallbackInfo ci) { + private void angelica$cancelVignette(CallbackInfo ci) { if (HUDCaching.renderingCacheOverride) { ci.cancel(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinOpenGlHelper_HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinOpenGlHelper_HUDCaching.java deleted file mode 100644 index aab4c9b18..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinOpenGlHelper_HUDCaching.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.angelica.hudcaching; - -import com.gtnewhorizons.angelica.hudcaching.HUDCaching; -import net.minecraft.client.renderer.OpenGlHelper; -import org.lwjgl.opengl.EXTBlendFuncSeparate; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL14; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -@Mixin(OpenGlHelper.class) -public class MixinOpenGlHelper_HUDCaching { - - @Shadow - private static boolean openGL14; - - @Shadow - public static boolean field_153211_u; - - // TODO don't override, do modify variable or inject via ASM with GlStateManager - - /** - * @author ee - * @reason eee - */ - @Overwrite - public static void glBlendFunc(int srcFactor, int dstFactor, int srcFactorAlpha, int dstFactorAlpha) { - if (HUDCaching.renderingCacheOverride && dstFactorAlpha != GL11.GL_ONE_MINUS_SRC_ALPHA) { - srcFactorAlpha = GL11.GL_ONE; - dstFactorAlpha = GL11.GL_ONE_MINUS_SRC_ALPHA; - } - if (openGL14) { - if (field_153211_u) { - EXTBlendFuncSeparate.glBlendFuncSeparateEXT(srcFactor, dstFactor, srcFactorAlpha, dstFactorAlpha); - } else { - GL14.glBlendFuncSeparate(srcFactor, dstFactor, srcFactorAlpha, dstFactorAlpha); - } - } else { - GL11.glBlendFunc(srcFactor, dstFactor); - } - } - -} From 71871c2ecece8ec67808898c4984e189c11154ce Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Wed, 29 Nov 2023 23:03:20 +0100 Subject: [PATCH 191/301] fix hud caching integration point in GLStateManager --- .../angelica/glsm/GLStateManager.java | 39 +++++++++---------- .../transform/RedirectorTransformer.java | 8 ++-- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 3d829d62a..d47c0873c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -22,7 +22,6 @@ import net.coderbot.iris.texture.TextureInfoCache; import net.coderbot.iris.texture.TextureTracker; import net.coderbot.iris.texture.pbr.PBRTextureManager; -import net.minecraft.client.renderer.OpenGlHelper; import org.joml.Vector3d; import org.lwjgl.opengl.ARBMultitexture; import org.lwjgl.opengl.EXTBlendFuncSeparate; @@ -122,42 +121,42 @@ public static void glDisable(int cap) { // GLStateManager Functions public static void enableBlend() { - if (HUDCaching.renderingCacheOverride) { - hudCaching$blendEnabled = true; - } if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendModeToggle(true); return; } } + if (HUDCaching.renderingCacheOverride) { + hudCaching$blendEnabled = true; + } blendState.mode.enable(); } public static void disableBlend() { - if (HUDCaching.renderingCacheOverride) { - hudCaching$blendEnabled = false; - } if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendModeToggle(false); return; } } + if (HUDCaching.renderingCacheOverride) { + hudCaching$blendEnabled = false; + } blendState.mode.disable(); } public static void glBlendFunc(int srcFactor, int dstFactor) { - if (HUDCaching.renderingCacheOverride) { - GL14.glBlendFuncSeparate(srcFactor, dstFactor, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); - return; - } if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendFunc(srcFactor, dstFactor, srcFactor, dstFactor); return; } } + if (HUDCaching.renderingCacheOverride) { + GL14.glBlendFuncSeparate(srcFactor, dstFactor, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + return; + } if (blendState.srcRgb != srcFactor || blendState.dstRgb != dstFactor) { blendState.srcRgb = srcFactor; blendState.dstRgb = dstFactor; @@ -169,16 +168,16 @@ public static void glBlendFunc(int srcFactor, int dstFactor) { } public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { - if (HUDCaching.renderingCacheOverride && dstAlpha != GL11.GL_ONE_MINUS_SRC_ALPHA) { - GL14.glBlendFuncSeparate(srcRgb, dstRgb, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); - return; - } if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); return; } } + if (HUDCaching.renderingCacheOverride && dstAlpha != GL11.GL_ONE_MINUS_SRC_ALPHA) { + GL14.glBlendFuncSeparate(srcRgb, dstRgb, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + return; + } if (blendState.srcRgb != srcRgb || blendState.dstRgb != dstRgb || blendState.srcAlpha != srcAlpha || blendState.dstAlpha != dstAlpha) { blendState.srcRgb = srcRgb; blendState.dstRgb = dstRgb; @@ -192,16 +191,16 @@ public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int } public static void glBlendFuncSeparateEXT(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { - if (HUDCaching.renderingCacheOverride && dstAlpha != GL11.GL_ONE_MINUS_SRC_ALPHA) { - EXTBlendFuncSeparate.glBlendFuncSeparateEXT(srcRgb, dstRgb, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); - return; - } if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); return; } } + if (HUDCaching.renderingCacheOverride && dstAlpha != GL11.GL_ONE_MINUS_SRC_ALPHA) { + EXTBlendFuncSeparate.glBlendFuncSeparateEXT(srcRgb, dstRgb, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + return; + } if (blendState.srcRgb != srcRgb || blendState.dstRgb != dstRgb || blendState.srcAlpha != srcAlpha || blendState.dstAlpha != dstAlpha) { blendState.srcRgb = srcRgb; blendState.dstRgb = dstRgb; @@ -267,7 +266,7 @@ public static void glColor4b(byte red, byte green, byte blue, byte alpha) { public static void glColor4ub(byte red, byte green, byte blue, byte alpha) { if (!hudCaching$blendEnabled && HUDCaching.renderingCacheOverride && alpha < Byte.MAX_VALUE) { - GL11.glColor4b(red, green, blue, Byte.MAX_VALUE); + GL11.glColor4ub(red, green, blue, Byte.MAX_VALUE); return; } if (changeColor(ub2f(red), ub2f(green), ub2f(blue), ub2f(alpha))) { diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index ca4858814..309c6afdf 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -37,7 +37,7 @@ public class RedirectorTransformer implements IClassTransformer { private static final boolean ASSERT_MAIN_THREAD = Boolean.parseBoolean(System.getProperty("angelica.assertMainThread", "false")); private static final boolean DUMP_CLASSES = Boolean.parseBoolean(System.getProperty("angelica.dumpClass", "false")); - private static final String GLStateTracker = "com/gtnewhorizons/angelica/glsm/GLStateManager"; + private static final String GLStateManager = "com/gtnewhorizons/angelica/glsm/GLStateManager"; private static final String GL11 = "org/lwjgl/opengl/GL11"; private static final String GL13 = "org/lwjgl/opengl/GL13"; private static final String GL14 = "org/lwjgl/opengl/GL14"; @@ -152,7 +152,7 @@ public byte[] transform(final String className, String transformedName, byte[] b AngelicaTweaker.LOGGER.info("Redirecting call in {} from GL11.{}(I)V to GLStateManager.{}()V", transformedName, mNode.name, name); } } - mNode.owner = GLStateTracker; + mNode.owner = GLStateManager; if (name != null) { mNode.name = name; mNode.desc = "()V"; @@ -168,7 +168,7 @@ public byte[] transform(final String className, String transformedName, byte[] b final String shortOwner = mNode.owner.substring(mNode.owner.lastIndexOf("/") + 1); AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", transformedName, shortOwner, mNode.name, mNode.desc, mNode.name, mNode.desc); } - mNode.owner = GLStateTracker; + mNode.owner = GLStateManager; changed = true; redirectInMethod = true; remaps++; @@ -185,7 +185,7 @@ public byte[] transform(final String className, String transformedName, byte[] b } } if (ASSERT_MAIN_THREAD && redirectInMethod && !((transformedName.startsWith(MinecraftClient) || transformedName.startsWith(SplashProgress)) && ExcludedMinecraftMainThreadChecks.contains(mn.name))) { - mn.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, GLStateTracker, "assertMainThread", "()V", false)); + mn.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, GLStateManager, "assertMainThread", "()V", false)); } } From b3e5827732dab3cac12040c28b20ac67c3dd5e9a Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Thu, 30 Nov 2023 01:09:40 +0100 Subject: [PATCH 192/301] allow methods redirected by RedirectorTransformer to have a separate name to handle obfuscation but not only --- .../transform/RedirectorTransformer.java | 93 +++++++++++-------- 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 309c6afdf..aed2268d7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -1,8 +1,6 @@ package com.gtnewhorizons.angelica.transform; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.coderbot.iris.IrisLogging; import net.minecraft.launchwrapper.IClassTransformer; @@ -53,44 +51,13 @@ public class RedirectorTransformer implements IClassTransformer { ); private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, EXTBlendFunc, ARBMultiTexture, TessellatorClass); - - private static final Map> EnabledRedirects = ImmutableMap.of( - GL11, Sets.newHashSet( - "glAlphaFunc" - ,"glBlendFunc" - ,"glClearColor" - ,"glColor3f" - ,"glColor3d" - ,"glColor3b" - ,"glColor3ub" - ,"glColor4f" - ,"glColor4d" - ,"glColor4b" - ,"glColor4ub" - ,"glColorMask" - ,"glDeleteTextures" - ,"glDepthFunc" - ,"glDepthMask" - ,"glDrawArrays" - ,"glFog" - ,"glFogf" - ,"glFogi" - ,"glShadeModel" - ,"glTexImage2D" - ,"glBindTexture" - ) - , GL13, Sets.newHashSet("glActiveTexture") - , GL14, Sets.newHashSet("glBlendFuncSeparate") - , EXTBlendFunc, Sets.newHashSet("glBlendFuncSeparateEXT") - , ARBMultiTexture, Sets.newHashSet("glActiveTextureARB") - ); + private static final Map> methodRedirects = new HashMap<>(); private static final Map glCapRedirects = new HashMap<>(); - private static final List TransformerExclusions = Arrays.asList( - "org.lwjgl" - ,"com.gtnewhorizons.angelica.glsm." - ,"com.gtnewhorizons.angelica.transform" - ,"me.eigenraven.lwjgl3ify" + "org.lwjgl", + "com.gtnewhorizons.angelica.glsm.", + "com.gtnewhorizons.angelica.transform", + "me.eigenraven.lwjgl3ify" ); private static int remaps = 0; @@ -103,6 +70,33 @@ public class RedirectorTransformer implements IClassTransformer { glCapRedirects.put(org.lwjgl.opengl.GL11.GL_TEXTURE_2D, "Texture"); glCapRedirects.put(org.lwjgl.opengl.GL11.GL_FOG, "Fog"); glCapRedirects.put(org.lwjgl.opengl.GL12.GL_RESCALE_NORMAL, "RescaleNormal"); + methodRedirects.put(GL11, RedirectMap.newMap() + .add("glAlphaFunc") + .add("glBlendFunc") + .add("glClearColor") + .add("glColor3f") + .add("glColor3d") + .add("glColor3b") + .add("glColor3ub") + .add("glColor4f") + .add("glColor4d") + .add("glColor4b") + .add("glColor4ub") + .add("glColorMask") + .add("glDeleteTextures") + .add("glDepthFunc") + .add("glDepthMask") + .add("glDrawArrays") + .add("glFog") + .add("glFogf") + .add("glFogi") + .add("glShadeModel") + .add("glTexImage2D") + .add("glBindTexture")); + methodRedirects.put(GL13, RedirectMap.newMap().add("glActiveTexture")); + methodRedirects.put(GL14, RedirectMap.newMap().add("glBlendFuncSeparate")); + methodRedirects.put(EXTBlendFunc, RedirectMap.newMap().add("glBlendFuncSeparateEXT")); + methodRedirects.put(ARBMultiTexture, RedirectMap.newMap().add("glActiveTextureARB")); } @Override @@ -162,13 +156,14 @@ public byte[] transform(final String className, String transformedName, byte[] b redirectInMethod = true; remaps++; } else { - final Set redirects = EnabledRedirects.get(mNode.owner); - if (redirects != null && redirects.contains(mNode.name)) { + final Map redirects = methodRedirects.get(mNode.owner); + if (redirects != null && redirects.containsKey(mNode.name)) { if (IrisLogging.ENABLE_SPAM) { final String shortOwner = mNode.owner.substring(mNode.owner.lastIndexOf("/") + 1); - AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", transformedName, shortOwner, mNode.name, mNode.desc, mNode.name, mNode.desc); + AngelicaTweaker.LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", transformedName, shortOwner, mNode.name, mNode.desc, redirects.get(mNode.name), mNode.desc); } mNode.owner = GLStateManager; + mNode.name = redirects.get(mNode.name); changed = true; redirectInMethod = true; remaps++; @@ -233,4 +228,20 @@ private void saveTransformedClass(final byte[] data, final String transformedNam } } + private static class RedirectMap extends HashMap { + public static RedirectMap newMap() { + return new RedirectMap<>(); + } + + public RedirectMap add(K name) { + this.put(name, name); + return this; + } + + public RedirectMap add(K name, K newName) { + this.put(name, newName); + return this; + } + } + } From 841e2814b301e0aa9c0794b4792c70bb1ec5b655 Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Thu, 30 Nov 2023 01:12:27 +0100 Subject: [PATCH 193/301] redirect all OpenGlHelper.glBlendFunc and other blend fonction call to the same blend fonction in GLStateManager --- .../angelica/compat/mojang/RenderPhase.java | 6 +- .../angelica/glsm/GLStateManager.java | 76 ++++++------------- .../angelica/hudcaching/HUDCaching.java | 10 +-- .../transform/RedirectorTransformer.java | 13 +++- 4 files changed, 43 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index 397328803..48490fa58 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -36,21 +36,21 @@ public abstract class RenderPhase { }); protected static final Transparency GLINT_TRANSPARENCY = new Transparency("glint_transparency", () -> { GLStateManager.enableBlend(); - GLStateManager.glBlendFuncSeparate(GL11.GL_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE); + GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE); }, () -> { GLStateManager.disableBlend(); GLStateManager.defaultBlendFunc(); }); protected static final Transparency CRUMBLING_TRANSPARENCY = new Transparency("crumbling_transparency", () -> { GLStateManager.enableBlend(); - GLStateManager.glBlendFuncSeparate(GL11.GL_DST_COLOR, GL11.GL_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO); + GLStateManager.tryBlendFuncSeparate(GL11.GL_DST_COLOR, GL11.GL_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO); }, () -> { GLStateManager.disableBlend(); GLStateManager.defaultBlendFunc(); }); protected static final Transparency TRANSLUCENT_TRANSPARENCY = new Transparency("translucent_transparency", () -> { GLStateManager.enableBlend(); - GLStateManager.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); }, () -> { GLStateManager.disableBlend(); GLStateManager.defaultBlendFunc(); diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index d47c0873c..f4c632116 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -22,13 +22,12 @@ import net.coderbot.iris.texture.TextureInfoCache; import net.coderbot.iris.texture.TextureTracker; import net.coderbot.iris.texture.pbr.PBRTextureManager; +import net.minecraft.client.renderer.OpenGlHelper; import org.joml.Vector3d; import org.lwjgl.opengl.ARBMultitexture; -import org.lwjgl.opengl.EXTBlendFuncSeparate; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL13; -import org.lwjgl.opengl.GL14; import java.nio.ByteBuffer; import java.nio.FloatBuffer; @@ -127,9 +126,7 @@ public static void enableBlend() { return; } } - if (HUDCaching.renderingCacheOverride) { - hudCaching$blendEnabled = true; - } + hudCaching$blendEnabled = true; blendState.mode.enable(); } @@ -140,9 +137,7 @@ public static void disableBlend() { return; } } - if (HUDCaching.renderingCacheOverride) { - hudCaching$blendEnabled = false; - } + hudCaching$blendEnabled = false; blendState.mode.disable(); } @@ -154,7 +149,11 @@ public static void glBlendFunc(int srcFactor, int dstFactor) { } } if (HUDCaching.renderingCacheOverride) { - GL14.glBlendFuncSeparate(srcFactor, dstFactor, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + blendState.srcRgb = srcFactor; + blendState.dstRgb = dstFactor; + blendState.srcAlpha = GL11.GL_ONE; + blendState.dstAlpha = GL11.GL_ONE_MINUS_SRC_ALPHA; + OpenGlHelper.glBlendFunc(srcFactor, dstFactor, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); return; } if (blendState.srcRgb != srcFactor || blendState.dstRgb != dstFactor) { @@ -167,7 +166,7 @@ public static void glBlendFunc(int srcFactor, int dstFactor) { if (blendFuncListener != null) blendFuncListener.run(); } - public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { + public static void tryBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { if (AngelicaConfig.enableIris) { if (BlendModeStorage.isBlendLocked()) { BlendModeStorage.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); @@ -175,38 +174,15 @@ public static void glBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int } } if (HUDCaching.renderingCacheOverride && dstAlpha != GL11.GL_ONE_MINUS_SRC_ALPHA) { - GL14.glBlendFuncSeparate(srcRgb, dstRgb, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); - return; + srcAlpha = GL11.GL_ONE; + dstAlpha = GL11.GL_ONE_MINUS_SRC_ALPHA; } if (blendState.srcRgb != srcRgb || blendState.dstRgb != dstRgb || blendState.srcAlpha != srcAlpha || blendState.dstAlpha != dstAlpha) { blendState.srcRgb = srcRgb; blendState.dstRgb = dstRgb; blendState.srcAlpha = srcAlpha; blendState.dstAlpha = dstAlpha; - GL14.glBlendFuncSeparate(srcRgb, dstRgb, srcAlpha, dstAlpha); - } - - // Iris - if (blendFuncListener != null) blendFuncListener.run(); - } - - public static void glBlendFuncSeparateEXT(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) { - if (AngelicaConfig.enableIris) { - if (BlendModeStorage.isBlendLocked()) { - BlendModeStorage.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); - return; - } - } - if (HUDCaching.renderingCacheOverride && dstAlpha != GL11.GL_ONE_MINUS_SRC_ALPHA) { - EXTBlendFuncSeparate.glBlendFuncSeparateEXT(srcRgb, dstRgb, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); - return; - } - if (blendState.srcRgb != srcRgb || blendState.dstRgb != dstRgb || blendState.srcAlpha != srcAlpha || blendState.dstAlpha != dstAlpha) { - blendState.srcRgb = srcRgb; - blendState.dstRgb = dstRgb; - blendState.srcAlpha = srcAlpha; - blendState.dstAlpha = dstAlpha; - EXTBlendFuncSeparate.glBlendFuncSeparateEXT(srcRgb, dstRgb, srcAlpha, dstAlpha); + OpenGlHelper.glBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha); } // Iris @@ -237,27 +213,25 @@ public static void glDepthMask(boolean mask) { public static void glColor4f(float red, float green, float blue, float alpha) { if (!hudCaching$blendEnabled && HUDCaching.renderingCacheOverride && alpha < 1f) { - GL11.glColor4f(red, green, blue, 1f); - return; + alpha = 1f; } if (changeColor(red, green, blue, alpha)) { GL11.glColor4f(red, green, blue, alpha); } } + public static void glColor4d(double red, double green, double blue, double alpha) { if (!hudCaching$blendEnabled && HUDCaching.renderingCacheOverride && alpha < 1d) { - GL11.glColor4d(red, green, blue, 1d); - return; + alpha = 1d; } - if (changeColor((float)red, (float)green, (float)blue, (float)alpha)) { + if (changeColor((float) red, (float) green, (float) blue, (float) alpha)) { GL11.glColor4d(red, green, blue, alpha); } } public static void glColor4b(byte red, byte green, byte blue, byte alpha) { if (!hudCaching$blendEnabled && HUDCaching.renderingCacheOverride && alpha < Byte.MAX_VALUE) { - GL11.glColor4b(red, green, blue, Byte.MAX_VALUE); - return; + alpha = Byte.MAX_VALUE; } if (changeColor(b2f(red), b2f(green), b2f(blue), b2f(alpha))) { GL11.glColor4b(red, green, blue, alpha); @@ -266,8 +240,7 @@ public static void glColor4b(byte red, byte green, byte blue, byte alpha) { public static void glColor4ub(byte red, byte green, byte blue, byte alpha) { if (!hudCaching$blendEnabled && HUDCaching.renderingCacheOverride && alpha < Byte.MAX_VALUE) { - GL11.glColor4ub(red, green, blue, Byte.MAX_VALUE); - return; + alpha = Byte.MAX_VALUE; } if (changeColor(ub2f(red), ub2f(green), ub2f(blue), ub2f(alpha))) { GL11.glColor4ub(red, green, blue, alpha); @@ -275,28 +248,29 @@ public static void glColor4ub(byte red, byte green, byte blue, byte alpha) { } public static void glColor3f(float red, float green, float blue) { - if(changeColor(red, green, blue, 1.0F)) { + if (changeColor(red, green, blue, 1.0F)) { GL11.glColor3f(red, green, blue); } } public static void glColor3d(double red, double green, double blue) { - if(changeColor((float)red, (float)green, (float)blue, 1.0F)) { + if (changeColor((float) red, (float) green, (float) blue, 1.0F)) { GL11.glColor3d(red, green, blue); } } public static void glColor3b(byte red, byte green, byte blue) { - if(changeColor(b2f(red), b2f(green), b2f(blue), 1.0F)) { + if (changeColor(b2f(red), b2f(green), b2f(blue), 1.0F)) { GL11.glColor3b(red, green, blue); } } public static void glColor3ub(byte red, byte green, byte blue) { - if(changeColor(ub2f(red), ub2f(green), ub2f(blue), 1.0F)) { + if (changeColor(ub2f(red), ub2f(green), ub2f(blue), 1.0F)) { GL11.glColor3ub(red, green, blue); } } + private static float ub2f(byte b) { return (b & 0xFF) / 255.0F; } @@ -307,7 +281,7 @@ private static float b2f(byte b) { private static boolean changeColor(float red, float green, float blue, float alpha) { // Helper function for glColor* - if(red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { + if (red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { Color.red = red; Color.green = green; Color.blue = blue; @@ -504,7 +478,7 @@ public static void glDrawArrays(int mode, int first, int count) { } public static void defaultBlendFunc() { - glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); } public static void enableCull() { diff --git a/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java index 338318f8a..d7daf3680 100644 --- a/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java +++ b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java @@ -111,18 +111,18 @@ public static void renderCachedHud(EntityRenderer renderer, GuiIngame ingame, fl } else if (GuiIngameForge.renderCrosshairs) { mc.getTextureManager().bindTexture(Gui.icons); GLStateManager.enableBlend(); - OpenGlHelper.glBlendFunc(GL11.GL_ONE_MINUS_DST_COLOR, GL11.GL_ONE_MINUS_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO); + GLStateManager.tryBlendFuncSeparate(GL11.GL_ONE_MINUS_DST_COLOR, GL11.GL_ONE_MINUS_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO); GLStateManager.enableAlphaTest(); drawTexturedModalRect(tessellator, (width >> 1) - 7, (height >> 1) - 7); - OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); } GLStateManager.enableBlend(); - OpenGlHelper.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GLStateManager.tryBlendFuncSeparate(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); GLStateManager.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); framebuffer.bindFramebufferTexture(); drawTexturedRect(tessellator, (float) resolution.getScaledWidth_double(), (float) resolution.getScaledHeight_double()); - OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); } if (framebuffer == null || dirty) { @@ -131,7 +131,7 @@ public static void renderCachedHud(EntityRenderer renderer, GuiIngame ingame, fl framebuffer.framebufferClear(); framebuffer.bindFramebuffer(false); GLStateManager.disableBlend(); - OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); GLStateManager.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); GLStateManager.disableLighting(); GLStateManager.disableFog(); diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index aed2268d7..326fa4364 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -39,6 +39,7 @@ public class RedirectorTransformer implements IClassTransformer { private static final String GL11 = "org/lwjgl/opengl/GL11"; private static final String GL13 = "org/lwjgl/opengl/GL13"; private static final String GL14 = "org/lwjgl/opengl/GL14"; + private static final String OpenGlHelper = "net/minecraft/client/renderer/OpenGlHelper"; private static final String EXTBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate"; private static final String ARBMultiTexture = "org/lwjgl/opengl/ARBMultitexture"; private static final String TessellatorClass = "net/minecraft/client/renderer/Tessellator"; @@ -50,7 +51,7 @@ public class RedirectorTransformer implements IClassTransformer { "start" // SplashProgress ); - private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, EXTBlendFunc, ARBMultiTexture, TessellatorClass); + private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, OpenGlHelper, EXTBlendFunc, ARBMultiTexture, TessellatorClass); private static final Map> methodRedirects = new HashMap<>(); private static final Map glCapRedirects = new HashMap<>(); private static final List TransformerExclusions = Arrays.asList( @@ -94,8 +95,11 @@ public class RedirectorTransformer implements IClassTransformer { .add("glTexImage2D") .add("glBindTexture")); methodRedirects.put(GL13, RedirectMap.newMap().add("glActiveTexture")); - methodRedirects.put(GL14, RedirectMap.newMap().add("glBlendFuncSeparate")); - methodRedirects.put(EXTBlendFunc, RedirectMap.newMap().add("glBlendFuncSeparateEXT")); + methodRedirects.put(GL14, RedirectMap.newMap().add("glBlendFuncSeparate", "tryBlendFuncSeparate")); + methodRedirects.put(OpenGlHelper, RedirectMap.newMap() + .add("glBlendFunc", "tryBlendFuncSeparate") + .add("func_148821_a", "tryBlendFuncSeparate")); + methodRedirects.put(EXTBlendFunc, RedirectMap.newMap().add("glBlendFuncSeparateEXT", "tryBlendFuncSeparate")); methodRedirects.put(ARBMultiTexture, RedirectMap.newMap().add("glActiveTextureARB")); } @@ -121,6 +125,9 @@ public byte[] transform(final String className, String transformedName, byte[] b boolean changed = false; for (MethodNode mn : cn.methods) { + if (transformedName.equals("net.minecraft.client.renderer.OpenGlHelper") && (mn.name.equals("glBlendFunc") || mn.name.equals("func_148821_a"))) { + continue; + } boolean redirectInMethod = false; for (AbstractInsnNode node : mn.instructions.toArray()) { if (node instanceof MethodInsnNode mNode) { From a54d23ae0445312591143d4753390d01221423aa Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Thu, 30 Nov 2023 01:32:11 +0100 Subject: [PATCH 194/301] disable HUD caching, add TODO --- .../com/gtnewhorizons/angelica/hudcaching/HUDCaching.java | 2 +- src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java index d7daf3680..05a606150 100644 --- a/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java +++ b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java @@ -78,7 +78,7 @@ public void onKeypress(InputEvent.KeyInputEvent event) { } } - /* END REMOVE DEBUG STUFF */ + /* TODO END REMOVE DEBUG STUFF */ @SubscribeEvent public void onTick(TickEvent.ClientTickEvent event) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 3ecd5931a..af96d5bba 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -129,7 +129,9 @@ public enum Mixins { "angelica.hudcaching.MixinFramebuffer_HUDCaching", "angelica.hudcaching.MixinGuiIngame_HUDCaching", "angelica.hudcaching.MixinGuiIngameForge_HUDCaching") - .setApplyIf(() -> true)), // TODO add config + .setApplyIf(() -> false)), + // TODO add config for HUD caching + // disabled for now as it doesn't render items with an enchantment glint in the hotbar properlu as well as doesn't render the vignette // TODO: Iris // SHADERSMOD_COMPAT_PR_ILLUMINATION( From 74618a597d97423b7bf6d5b00d5c2765b83cee08 Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Thu, 30 Nov 2023 01:54:25 +0100 Subject: [PATCH 195/301] add config for HUDCaching --- .../com/gtnewhorizons/angelica/config/AngelicaConfig.java | 5 +++++ src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java | 4 +--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index 5fa045763..1b05b74b9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -36,4 +36,9 @@ public class AngelicaConfig { @Config.Comment("Show memory usage during game load. [From ArchaicFix]") @Config.DefaultBoolean(true) public static boolean showSplashMemoryBar; + + + @Config.Comment("Renders the HUD elements once per tick and reuses the pixels to improve performance") + @Config.DefaultBoolean(false) + public static boolean hudCaching; // TODO disabled for now as it doesn't render items with an enchantment glint in the hotbar properly as well as doesn't render the vignette } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index af96d5bba..4a9a8ad02 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -129,9 +129,7 @@ public enum Mixins { "angelica.hudcaching.MixinFramebuffer_HUDCaching", "angelica.hudcaching.MixinGuiIngame_HUDCaching", "angelica.hudcaching.MixinGuiIngameForge_HUDCaching") - .setApplyIf(() -> false)), - // TODO add config for HUD caching - // disabled for now as it doesn't render items with an enchantment glint in the hotbar properlu as well as doesn't render the vignette + .setApplyIf(() -> AngelicaConfig.hudCaching)), // TODO: Iris // SHADERSMOD_COMPAT_PR_ILLUMINATION( From 4166c92737248cba8ffe6d038eddbaa20006536f Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 29 Nov 2023 17:15:28 -0800 Subject: [PATCH 196/301] Track thread that currently owns the GL Context in addition to the main thread. * Log instead of crash, for now --- .../angelica/config/AngelicaConfig.java | 6 ++++-- .../angelica/glsm/GLStateManager.java | 17 +++++++++++++++-- .../angelica/hudcaching/HUDCaching.java | 8 +++----- .../gtnewhorizons/angelica/mixins/Mixins.java | 2 +- .../angelica/debug/MixinSplashProgress.java | 2 ++ .../MixinEntityRenderer_HUDCaching.java | 11 ++--------- .../transform/RedirectorTransformer.java | 15 ++++++++++++--- 7 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index 1b05b74b9..091471d30 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -38,7 +38,9 @@ public class AngelicaConfig { public static boolean showSplashMemoryBar; - @Config.Comment("Renders the HUD elements once per tick and reuses the pixels to improve performance") + @Config.Comment("Renders the HUD elements once per tick and reuses the pixels to improve performance. [Experimental]") @Config.DefaultBoolean(false) - public static boolean hudCaching; // TODO disabled for now as it doesn't render items with an enchantment glint in the hotbar properly as well as doesn't render the vignette + @Config.RequiresMcRestart + // TODO disabled for now as it doesn't render items with an enchantment glint in the hotbar properly as well as doesn't render the vignette + public static boolean enableHudCaching; } diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index f4c632116..a79fcaefe 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -24,7 +24,9 @@ import net.coderbot.iris.texture.pbr.PBRTextureManager; import net.minecraft.client.renderer.OpenGlHelper; import org.joml.Vector3d; +import org.lwjgl.LWJGLException; import org.lwjgl.opengl.ARBMultitexture; +import org.lwjgl.opengl.Drawable; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL13; @@ -34,6 +36,8 @@ import java.nio.IntBuffer; import java.util.stream.IntStream; +import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER; + @SuppressWarnings("unused") // Used in ASM public class GLStateManager { // GLStateManager State Trackers @@ -65,6 +69,7 @@ public class GLStateManager { // Thread Checking @Getter private static final Thread MainThread = Thread.currentThread(); + private static Thread CurrentThread = MainThread; private static boolean runningSplash = false; private static boolean hudCaching$blendEnabled; @@ -83,8 +88,8 @@ public static void init() { } public static void assertMainThread() { - if (Thread.currentThread() != MainThread || runningSplash) { - throw new IllegalStateException("Not on the main thread!"); + if (Thread.currentThread() != CurrentThread && !runningSplash) { + LOGGER.info("Call from not the Current Thread! - " + Thread.currentThread().getName() + " Current thread: " + CurrentThread.getName()); } } @@ -613,4 +618,12 @@ public static void glShadeModel(int mode) { public static void setRunningSplash(boolean runningSplash) { GLStateManager.runningSplash = runningSplash; } + + public static void makeCurrent(Drawable drawable) throws LWJGLException { + drawable.makeCurrent(); + final Thread currentThread = Thread.currentThread(); + + CurrentThread = currentThread; + LOGGER.info("Current thread: {}", currentThread.getName()); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java index 05a606150..af2bf6ef1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java +++ b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java @@ -18,9 +18,7 @@ import net.minecraft.client.settings.KeyBinding; import net.minecraft.client.shader.Framebuffer; import net.minecraft.util.ChatComponentText; -import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.client.GuiIngameForge; -import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.common.MinecraftForge; import org.lwjgl.opengl.GL11; @@ -90,10 +88,10 @@ public void onTick(TickEvent.ClientTickEvent event) { // TODO draw vignette @SuppressWarnings("unused") - public static void renderCachedHud(EntityRenderer renderer, GuiIngame ingame, float partialTicks, boolean p_73830_2_, int p_73830_3_, int p_73830_4_) { + public static void renderCachedHud(EntityRenderer renderer, GuiIngame ingame, float partialTicks, boolean b, int i, int j) { if (!OpenGlHelper.isFramebufferEnabled() || !isEnabled) { - ingame.renderGameOverlay(partialTicks, p_73830_2_, p_73830_3_, p_73830_4_); + ingame.renderGameOverlay(partialTicks, b, i, j); return; } @@ -136,7 +134,7 @@ public static void renderCachedHud(EntityRenderer renderer, GuiIngame ingame, fl GLStateManager.disableLighting(); GLStateManager.disableFog(); renderingCacheOverride = true; - ingame.renderGameOverlay(partialTicks, p_73830_2_, p_73830_3_, p_73830_4_); + ingame.renderGameOverlay(partialTicks, b, i, j); renderingCacheOverride = false; mc.getFramebuffer().bindFramebuffer(false); GLStateManager.enableBlend(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 4a9a8ad02..77bb3270f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -129,7 +129,7 @@ public enum Mixins { "angelica.hudcaching.MixinFramebuffer_HUDCaching", "angelica.hudcaching.MixinGuiIngame_HUDCaching", "angelica.hudcaching.MixinGuiIngameForge_HUDCaching") - .setApplyIf(() -> AngelicaConfig.hudCaching)), + .setApplyIf(() -> AngelicaConfig.enableHudCaching)), // TODO: Iris // SHADERSMOD_COMPAT_PR_ILLUMINATION( diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/debug/MixinSplashProgress.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/debug/MixinSplashProgress.java index 482e71efa..2634b1a95 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/debug/MixinSplashProgress.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/debug/MixinSplashProgress.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.angelica.debug; +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import cpw.mods.fml.client.SplashProgress; @@ -10,6 +11,7 @@ public class MixinSplashProgress { @WrapOperation(method="Lcpw/mods/fml/client/SplashProgress;start()V", at=@At(value="INVOKE", target="Lcpw/mods/fml/client/SplashProgress;getBool(Ljava/lang/String;Z)Z")) private static boolean angelica$disableSplashProgress(String name, boolean def, Operation original) { + AngelicaTweaker.LOGGER.info("Forcibly disabling splash progress because LWJGL debug has been set"); // Forcibly disable splash progress until we can figure out why it's not working with our debug callback if(name.equals("enabled")) return false; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java index 0303d2203..4aa3c30a7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinEntityRenderer_HUDCaching.java @@ -13,14 +13,7 @@ public class MixinEntityRenderer_HUDCaching { @Redirect( method = "updateCameraAndRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiIngame;renderGameOverlay(FZII)V")) - public void angelica$renderCachedHUD(GuiIngame guiIngame, float partialTicks, boolean p_73830_2_, int p_73830_3_, - int p_73830_4_) { - HUDCaching.renderCachedHud( - (EntityRenderer) (Object) this, - guiIngame, - partialTicks, - p_73830_2_, - p_73830_3_, - p_73830_4_); + public void angelica$renderCachedHUD(GuiIngame guiIngame, float partialTicks, boolean b, int i, int j) { + HUDCaching.renderCachedHud((EntityRenderer) (Object) this, guiIngame, partialTicks, b, i, j); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 326fa4364..b3e6aab1f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -35,6 +35,7 @@ public class RedirectorTransformer implements IClassTransformer { private static final boolean ASSERT_MAIN_THREAD = Boolean.parseBoolean(System.getProperty("angelica.assertMainThread", "false")); private static final boolean DUMP_CLASSES = Boolean.parseBoolean(System.getProperty("angelica.dumpClass", "false")); + private static final String Drawable = "org/lwjgl/opengl/Drawable"; private static final String GLStateManager = "com/gtnewhorizons/angelica/glsm/GLStateManager"; private static final String GL11 = "org/lwjgl/opengl/GL11"; private static final String GL13 = "org/lwjgl/opengl/GL13"; @@ -47,8 +48,7 @@ public class RedirectorTransformer implements IClassTransformer { private static final String SplashProgress = "cpw.mods.fml.client.SplashProgress"; private static final Set ExcludedMinecraftMainThreadChecks = ImmutableSet.of( "startGame", "func_71384_a", - "initializeTextures", "func_77474_a", - "start" // SplashProgress + "initializeTextures", "func_77474_a" ); private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, OpenGlHelper, EXTBlendFunc, ARBMultiTexture, TessellatorClass); @@ -162,6 +162,15 @@ public byte[] transform(final String className, String transformedName, byte[] b changed = true; redirectInMethod = true; remaps++; + } else if (mNode.owner.startsWith(Drawable) && mNode.name.equals("makeCurrent")) { + mNode.setOpcode(Opcodes.INVOKESTATIC); + mNode.owner = GLStateManager; + mNode.desc = "(L" + Drawable + ";)V"; + mNode.itf = false; + changed = true; + if (IrisLogging.ENABLE_SPAM) { + AngelicaTweaker.LOGGER.info("Redirecting call in {} to GLStateManager.makeCurrent()", transformedName); + } } else { final Map redirects = methodRedirects.get(mNode.owner); if (redirects != null && redirects.containsKey(mNode.name)) { @@ -186,7 +195,7 @@ public byte[] transform(final String className, String transformedName, byte[] b } } } - if (ASSERT_MAIN_THREAD && redirectInMethod && !((transformedName.startsWith(MinecraftClient) || transformedName.startsWith(SplashProgress)) && ExcludedMinecraftMainThreadChecks.contains(mn.name))) { + if (ASSERT_MAIN_THREAD && redirectInMethod && !transformedName.startsWith(SplashProgress) && !(transformedName.startsWith(MinecraftClient) && ExcludedMinecraftMainThreadChecks.contains(mn.name))) { mn.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, GLStateManager, "assertMainThread", "()V", false)); } } From 2e1c43ddb0691404d096bf299833e0cfc1cf6fc8 Mon Sep 17 00:00:00 2001 From: Raven Szewczyk Date: Sat, 25 Nov 2023 12:50:12 +0000 Subject: [PATCH 197/301] First pass over FontRenderer, 1300->1400 FPS on my GPU when showing F3 Done: - A batching vertex buffer builder for font output - Reduction in drawcalls from 1-3 per character to 1 per font atlas switch - Mixin to draw the entire F3 screen in one batch, instead of separate batches per line TODO: - Switch drawing to a VBO - Cache string meshes across frames - Cache string width calculations used for layouts - Multidraw to reduce draw calls even further --- .../client/font/BatchingFontRenderer.java | 576 ++++++++++++++++++ .../compat/lwjgl/CompatMemoryUtil.java | 20 + .../gtnewhorizons/angelica/mixins/Mixins.java | 2 + .../early/angelica/MixinFontRenderer.java | 171 ++++++ .../early/angelica/MixinGuiIngameForge.java | 36 ++ .../interfaces/FontRendererAccessor.java | 7 + 6 files changed, 812 insertions(+) create mode 100644 src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinFontRenderer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinGuiIngameForge.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/FontRendererAccessor.java diff --git a/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java b/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java new file mode 100644 index 000000000..828f69043 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java @@ -0,0 +1,576 @@ +package com.gtnewhorizons.angelica.client.font; + +import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import it.unimi.dsi.fastutil.chars.Char2ShortOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import jss.util.RandomXoshiro256StarStar; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.util.MathHelper; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.BufferUtils; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Objects; + +import static org.lwjgl.opengl.GL11.*; + +/** + * A batching replacement for {@code FontRenderer} + * + * @author eigenraven + */ +public class BatchingFontRenderer { + + /** The underlying FontRenderer object that's being accelerated */ + protected FontRenderer underlying; + /** Cached locations for each unicode page atlas */ + private final ResourceLocation[] unicodePageLocations; + /** Array of width of all the characters in default.png */ + protected int[] charWidth = new int[256]; + /** Array of the start/end column (in upper/lower nibble) for every glyph in the /font directory. */ + protected byte[] glyphWidth; + /** + * Array of RGB triplets defining the 16 standard chat colors followed by 16 darker version of the same colors for + * drop shadows. + */ + private int[] colorCode; + /** Location of the primary font atlas to bind. */ + protected final ResourceLocation locationFontTexture; + /** The RenderEngine used to load and setup glyph textures. */ + private final TextureManager renderEngine; + private final RandomXoshiro256StarStar fontRandom = new RandomXoshiro256StarStar(); + + /** The full list of characters present in the default Minecraft font, excluding the Unicode font */ + @SuppressWarnings("UnnecessaryUnicodeEscape") + private static final String MCFONT_CHARS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000"; + + private static final short[] MCFONT_ASCII_LUT = new short[512]; + private static final Char2ShortOpenHashMap MCFONT_UNI_LUT = new Char2ShortOpenHashMap(); + + static { + Arrays.fill(MCFONT_ASCII_LUT, (short) -1); + for (short i = 0; i < MCFONT_CHARS.length(); i++) { + char ch = MCFONT_CHARS.charAt(i); + if (ch < MCFONT_ASCII_LUT.length) { + MCFONT_ASCII_LUT[ch] = i; + } else { + MCFONT_UNI_LUT.put(ch, i); + } + } + } + + public static int lookupMcFontPosition(char ch) { + if (ch < MCFONT_ASCII_LUT.length) { + return MCFONT_ASCII_LUT[ch]; + } else { + return MCFONT_UNI_LUT.getOrDefault(ch, (short) -1); + } + } + + public BatchingFontRenderer(FontRenderer underlying, ResourceLocation[] unicodePageLocations, int[] charWidth, + byte[] glyphWidth, int[] colorCode, ResourceLocation locationFontTexture, TextureManager renderEngine) { + this.underlying = underlying; + this.unicodePageLocations = unicodePageLocations; + this.charWidth = charWidth; + this.glyphWidth = glyphWidth; + this.colorCode = colorCode; + this.locationFontTexture = locationFontTexture; + this.renderEngine = renderEngine; + + for (int i = 0; i < 64; i++) { + batchCommandPool.add(new FontDrawCmd()); + } + } + + // === Batched rendering + + private int batchDepth = 0; + + private int vtxWriterIndex = 0; + private int idxWriterIndex = 0; + private static final int INITIAL_BATCH_SIZE = 256; + private static final ResourceLocation DUMMY_RESOURCE_LOCATION = new ResourceLocation("angelica$dummy", + "this is invalid!"); + private FloatBuffer batchVtxPositions = BufferUtils.createFloatBuffer(INITIAL_BATCH_SIZE * 2); + private ByteBuffer batchVtxColors = BufferUtils.createByteBuffer(INITIAL_BATCH_SIZE * 4); + private FloatBuffer batchVtxTexCoords = BufferUtils.createFloatBuffer(INITIAL_BATCH_SIZE * 2); + private IntBuffer batchIndices = BufferUtils.createIntBuffer(INITIAL_BATCH_SIZE / 2 * 3); + private final ObjectArrayList batchCommands = ObjectArrayList.wrap(new FontDrawCmd[64], 0); + private final ObjectArrayList batchCommandPool = ObjectArrayList.wrap(new FontDrawCmd[64], 0); + + /** */ + private void pushVtx(float x, float y, int rgba, float u, float v) { + final int oldCap = batchVtxPositions.capacity() / 2; + if (vtxWriterIndex >= oldCap) { + final int newCap = oldCap * 2; + batchVtxPositions = CompatMemoryUtil.memReallocDirect(batchVtxPositions, newCap * 2); + batchVtxColors = CompatMemoryUtil.memReallocDirect(batchVtxColors, newCap * 4); + batchVtxTexCoords = CompatMemoryUtil.memReallocDirect(batchVtxTexCoords, newCap * 2); + final int oldIdxCap = batchIndices.capacity(); + final int newIdxCap = oldIdxCap * 2; + batchIndices = CompatMemoryUtil.memReallocDirect(batchIndices, newIdxCap); + } + final int idx = vtxWriterIndex; + final int idx2 = idx * 2; + final int idx4 = idx * 4; + batchVtxPositions.put(idx2, x); + batchVtxPositions.put(idx2 + 1, y); + // 0xAARRGGBB + batchVtxColors.put(idx4, (byte) ((rgba >> 16) & 0xFF)); + batchVtxColors.put(idx4 + 1, (byte) ((rgba >> 8) & 0xFF)); + batchVtxColors.put(idx4 + 2, (byte) (rgba & 0xFF)); + batchVtxColors.put(idx4 + 3, (byte) ((rgba >> 24) & 0xFF)); + batchVtxTexCoords.put(idx2, u); + batchVtxTexCoords.put(idx2 + 1, v); + vtxWriterIndex++; + } + + private void pushUntexRect(float x, float y, float w, float h, int rgba) { + final int vtxId = vtxWriterIndex; + pushVtx(x, y, rgba, 0, 0); + pushVtx(x, y + h, rgba, 0, 0); + pushVtx(x + w, y, rgba, 0, 0); + pushVtx(x + w, y + h, rgba, 0, 0); + pushQuadIdx(vtxId); + } + + private int pushQuadIdx(int startV) { + final int idx = idxWriterIndex; + batchIndices.put(idx, startV); + batchIndices.put(idx + 1, startV + 1); + batchIndices.put(idx + 2, startV + 2); + // + batchIndices.put(idx + 3, startV + 2); + batchIndices.put(idx + 4, startV + 1); + batchIndices.put(idx + 5, startV + 3); + idxWriterIndex += 6; + return idx; + } + + private void pushDrawCmd(int startIdx, int idxCount, ResourceLocation texture) { + if (!batchCommands.isEmpty()) { + final FontDrawCmd lastCmd = batchCommands.get(batchCommands.size() - 1); + final int prevEndVtx = lastCmd.startVtx + lastCmd.idxCount; + if (prevEndVtx == startIdx && lastCmd.texture == texture) { + // Coalesce into one + lastCmd.idxCount += idxCount; + return; + } + } + if (batchCommandPool.isEmpty()) { + for (int i = 0; i < 64; i++) { + batchCommandPool.add(new FontDrawCmd()); + } + } + final FontDrawCmd cmd = batchCommandPool.pop(); + cmd.reset(startIdx, idxCount, texture); + batchCommands.add(cmd); + } + + private static final class FontDrawCmd { + + public int startVtx; + public int idxCount; + public ResourceLocation texture; + + public void reset(int startVtx, int vtxCount, ResourceLocation texture) { + this.startVtx = startVtx; + this.idxCount = vtxCount; + this.texture = texture; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (FontDrawCmd) obj; + return this.startVtx == that.startVtx && this.idxCount == that.idxCount && Objects.equals(this.texture, + that.texture); + } + + @Override + public int hashCode() { + return Objects.hash(startVtx, idxCount, texture); + } + + @Override + public String toString() { + return "FontDrawCmd[" + + "startVtx=" + + startVtx + + ", " + + "vtxCount=" + + idxCount + + ", " + + "texture=" + + texture + + ']'; + } + + public static final Comparator DRAW_ORDER_COMPARATOR = Comparator.comparing((FontDrawCmd fdc) -> fdc.texture, + Comparator.nullsLast(Comparator.comparing(ResourceLocation::getResourceDomain) + .thenComparing(ResourceLocation::getResourcePath))).thenComparing(fdc -> fdc.startVtx); + } + + /** + * Starts a new batch of font rendering operations. Can be called from within another batch with a matching end, to + * allow for easier optimizing of blocks of font rendering code. + */ + public void beginBatch() { + if (batchDepth == Integer.MAX_VALUE) { + throw new StackOverflowError("More than Integer.MAX_VALUE nested font rendering batch operations"); + } + batchDepth++; + } + + public void endBatch() { + if (batchDepth <= 0) { + batchDepth = 0; + return; + } + batchDepth--; + if (batchDepth == 0) { + // We finished any nested batches + flushBatch(); + } + } + + private void flushBatch() { + // Sort&Draw + batchCommands.sort(FontDrawCmd.DRAW_ORDER_COMPARATOR); + + ResourceLocation lastTexture = DUMMY_RESOURCE_LOCATION; + GLStateManager.enableTexture(); + GLStateManager.enableAlphaTest(); + GLStateManager.enableBlend(); + GLStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); + GLStateManager.glShadeModel(GL_FLAT); + + glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); + glTexCoordPointer(2, 0, batchVtxTexCoords); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, batchVtxColors); + glEnableClientState(GL_COLOR_ARRAY); + glVertexPointer(2, 0, batchVtxPositions); + glEnableClientState(GL_VERTEX_ARRAY); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + // Use plain for loop to avoid allocations + final FontDrawCmd[] cmdsData = batchCommands.elements(); + final int cmdsSize = batchCommands.size(); + for (int i = 0; i < cmdsSize; i++) { + final FontDrawCmd cmd = cmdsData[i]; + if (!Objects.equals(lastTexture, cmd.texture)) { + if (lastTexture == null) { + GLStateManager.enableTexture(); + } else if (cmd.texture == null) { + GLStateManager.disableTexture(); + } + if (cmd.texture != null) { + renderEngine.bindTexture(cmd.texture); + } + lastTexture = cmd.texture; + } + batchIndices.limit(cmd.startVtx + cmd.idxCount); + batchIndices.position(cmd.startVtx); + glDrawElements(GL_TRIANGLES, batchIndices); + } + + glPopClientAttrib(); + + // Clear for the next batch + batchCommandPool.addAll(batchCommands); + batchCommands.clear(); + vtxWriterIndex = 0; + idxWriterIndex = 0; + batchIndices.limit(batchIndices.capacity()); + batchIndices.position(0); + } + + // === Actual text mesh generation + + public static boolean charInRange(char what, char fromInclusive, char toInclusive) { + return (what >= fromInclusive) && (what <= toInclusive); + } + + private ResourceLocation getUnicodePageLocation(int page) { + final ResourceLocation lookup = unicodePageLocations[page]; + if (lookup == null) { + final ResourceLocation rl = new ResourceLocation(String.format( + "textures/font/unicode_page_%02x.png", + page)); + unicodePageLocations[page] = rl; + return rl; + } else { + return lookup; + } + } + + private static final char FORMATTING_CHAR = 167; // § + + public float drawString(final float anchorX, final float anchorY, final int color, final boolean enableShadow, + final boolean unicodeFlag, final CharSequence string, int stringOffset, int stringLength) { + // noinspection SizeReplaceableByIsEmpty + if (string == null || string.length() == 0) { + return 0.0f; + } + final int shadowColor = (color & 0xfcfcfc) >> 2 | color & 0xff000000; + ; + this.beginBatch(); + float curX = anchorX; + try { + final int totalStringLength = string.length(); + stringOffset = MathHelper.clamp_int(stringOffset, 0, totalStringLength); + stringLength = MathHelper.clamp_int(stringLength, 0, totalStringLength - stringOffset); + if (stringLength <= 0) { + return 0; + } + final int stringEnd = stringOffset + stringLength; + + int curColor = color; + int curShadowColor = shadowColor; + boolean curItalic = false; + boolean curRandom = false; + boolean curBold = false; + boolean curStrikethrough = false; + boolean curUnderline = false; + + final float underlineY = anchorY + underlying.FONT_HEIGHT - 1.0f; + float underlineStartX = 0.0f; + float underlineEndX = 0.0f; + final float strikethroughY = anchorY + (float) (underlying.FONT_HEIGHT / 2); + float strikethroughStartX = 0.0f; + float strikethroughEndX = 0.0f; + + for (int charIdx = stringOffset; charIdx < stringEnd; charIdx++) { + char chr = string.charAt(charIdx); + if (chr == FORMATTING_CHAR && (charIdx + 1) < stringEnd) { + final char fmtCode = Character.toLowerCase(string.charAt(charIdx + 1)); + charIdx++; + + if (curUnderline && underlineStartX != underlineEndX) { + final int ulIdx = idxWriterIndex; + pushUntexRect(underlineStartX, underlineY, underlineEndX - underlineStartX, 1.0f, curColor); + pushDrawCmd(ulIdx, 6, null); + underlineStartX = underlineEndX; + } + if (curStrikethrough && strikethroughStartX != strikethroughEndX) { + final int ulIdx = idxWriterIndex; + pushUntexRect( + strikethroughStartX, + strikethroughY, + strikethroughEndX - strikethroughStartX, + 1.0f, + curColor); + pushDrawCmd(ulIdx, 6, null); + strikethroughStartX = strikethroughEndX; + } + + final boolean is09 = charInRange(fmtCode, '0', '9'); + final boolean isAF = charInRange(fmtCode, 'a', 'f'); + if (is09 || isAF) { + curRandom = false; + curBold = false; + curStrikethrough = false; + curUnderline = false; + curItalic = false; + + final int colorIdx = is09 ? (fmtCode - '0') : (fmtCode - 'a' + 10); + final int rgb = this.colorCode[colorIdx]; + curColor = (curColor & 0xFF000000) | (rgb & 0x00FFFFFF); + final int shadowRgb = this.colorCode[colorIdx + 16]; + curShadowColor = (curShadowColor & 0xFF000000) | (shadowRgb & 0x00FFFFFF); + } else if (fmtCode == 'k') { + curRandom = true; + } else if (fmtCode == 'l') { + curBold = true; + } else if (fmtCode == 'm') { + curStrikethrough = true; + strikethroughStartX = curX - 1.0f; + strikethroughEndX = strikethroughStartX; + } else if (fmtCode == 'n') { + curUnderline = true; + underlineStartX = curX - 1.0f; + underlineEndX = underlineStartX; + } else if (fmtCode == 'o') { + curItalic = true; + } else if (fmtCode == 'r') { + curRandom = false; + curBold = false; + curStrikethrough = false; + curUnderline = false; + curItalic = false; + curColor = color; + curShadowColor = shadowColor; + } + + continue; + } + + int lutIndex = lookupMcFontPosition(chr); + if (curRandom && lutIndex != -1) { + int randomReplacementIndex; + do { + randomReplacementIndex = fontRandom.nextInt(this.charWidth.length); + } while (this.charWidth[lutIndex] != this.charWidth[randomReplacementIndex]); + + lutIndex = randomReplacementIndex; + 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; + continue; + } + + final float uStart; + final float vStart; + final float xAdvance; + final float glyphW; + final float uSz; + final float vSz; + final float itOff = curItalic ? 1.0F : 0.0F; // italic offset + final ResourceLocation texture; + + if (lutIndex == -1 || unicodeFlag) { + if (glyphWidth[chr] == 0) { + continue; + } + // Draw unicode char + final int uniPage = chr / 256; + texture = getUnicodePageLocation(uniPage); + final int startColumn = this.glyphWidth[chr] >>> 4; + final int endColumn = this.glyphWidth[chr] & 15; + final float startColumnF = (float) startColumn; + final float endColumnF = (float) (endColumn + 1); + uStart = ((float) (chr % 16 * 16) + startColumnF) / 256.0f; + vStart = ((float) ((chr & 255) / 16 * 16)) / 256.0f; + final float chrWidth = endColumnF - startColumnF - 0.02F; + glyphW = chrWidth / 2.0f + 1.0f; + xAdvance = (endColumnF - startColumnF) / 2.0F + 1.0F; + uSz = chrWidth / 256.0f; + vSz = 15.98f / 256.0f; + + } else { + // Draw "ASCII" char + uStart = ((lutIndex % 16) * 8) / 128.0F; + vStart = (float) ((lutIndex / 16) * 8) / 128.0F; + xAdvance = this.charWidth[lutIndex]; + if (xAdvance == 0) { + continue; + } + glyphW = xAdvance - 0.01F; + uSz = (glyphW - 1.0F) / 128.0F; + vSz = 7.99F / 128.0F; + texture = locationFontTexture; + } + + final int vtxId = vtxWriterIndex; + final int idxId = idxWriterIndex; + + int vtxCount = 0; + + if (enableShadow) { + pushVtx(curX + itOff + shadowOffset, anchorY + shadowOffset, curShadowColor, uStart, vStart); + pushVtx( + curX - itOff + shadowOffset, + anchorY + 7.99F + shadowOffset, + curShadowColor, + uStart, + vStart + vSz); + pushVtx(curX + glyphW - 1.0F + itOff + shadowOffset, + anchorY + shadowOffset, + curShadowColor, + uStart + uSz, + vStart); + pushVtx(curX + glyphW - 1.0F - itOff + shadowOffset, + anchorY + 7.99F + shadowOffset, + curShadowColor, + uStart + uSz, + vStart + vSz); + pushQuadIdx(vtxId + vtxCount); + vtxCount += 4; + + if (curBold) { + final float shadowOffset2 = 2.0f * shadowOffset; + pushVtx(curX + itOff + shadowOffset2, anchorY + shadowOffset, curShadowColor, uStart, vStart); + pushVtx( + curX - itOff + shadowOffset2, + anchorY + 7.99F + shadowOffset, + curShadowColor, + uStart, + vStart + vSz); + pushVtx( + curX + glyphW - 1.0F + itOff + shadowOffset2, + anchorY + shadowOffset, + curShadowColor, + uStart + uSz, + vStart); + pushVtx(curX + glyphW - 1.0F - itOff + shadowOffset2, + anchorY + 7.99F + shadowOffset, + curShadowColor, + uStart + uSz, + vStart + vSz); + pushQuadIdx(vtxId + vtxCount); + vtxCount += 4; + } + } + + pushVtx(curX + itOff, anchorY, curColor, uStart, vStart); + pushVtx(curX - itOff, anchorY + 7.99F, curColor, uStart, vStart + vSz); + pushVtx(curX + glyphW - 1.0F + itOff, anchorY, curColor, uStart + uSz, vStart); + pushVtx(curX + glyphW - 1.0F - itOff, anchorY + 7.99F, curColor, uStart + uSz, vStart + vSz); + pushQuadIdx(vtxId + vtxCount); + vtxCount += 4; + + if (curBold) { + pushVtx(shadowOffset + curX + itOff, anchorY, curColor, uStart, vStart); + pushVtx(shadowOffset + curX - itOff, anchorY + 7.99F, curColor, uStart, vStart + vSz); + pushVtx(shadowOffset + curX + glyphW - 1.0F + itOff, anchorY, curColor, uStart + uSz, vStart); + pushVtx(shadowOffset + curX + glyphW - 1.0F - itOff, + anchorY + 7.99F, + curColor, + uStart + uSz, + vStart + vSz); + pushQuadIdx(vtxId + vtxCount); + vtxCount += 4; + } + + pushDrawCmd(idxId, vtxCount / 2 * 3, texture); + curX += xAdvance + (curBold ? shadowOffset : 0.0f); + underlineEndX = curX; + strikethroughEndX = curX; + } + + if (curUnderline && underlineStartX != underlineEndX) { + final int ulIdx = idxWriterIndex; + pushUntexRect(underlineStartX, underlineY, underlineEndX - underlineStartX, 1.0f, curColor); + pushDrawCmd(ulIdx, 6, null); + } + if (curStrikethrough && strikethroughStartX != strikethroughEndX) { + final int ulIdx = idxWriterIndex; + pushUntexRect( + strikethroughStartX, + strikethroughY, + strikethroughEndX - strikethroughStartX, + 1.0f, + curColor); + pushDrawCmd(ulIdx, 6, null); + } + + } finally { + this.endBatch(); + } + return curX; + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java index 0cfc3c7c1..6b311ca88 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java @@ -3,6 +3,8 @@ import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; public class CompatMemoryUtil { public static ByteBuffer memReallocDirect(ByteBuffer old, int capacity) { @@ -14,6 +16,24 @@ public static ByteBuffer memReallocDirect(ByteBuffer old, int capacity) { return newBuf; } + public static IntBuffer memReallocDirect(IntBuffer old, int capacity) { + IntBuffer newBuf = BufferUtils.createIntBuffer(capacity); + int oldPos = old.position(); + old.rewind(); + newBuf.put(old); + newBuf.position(Math.min(capacity, oldPos)); + return newBuf; + } + + public static FloatBuffer memReallocDirect(FloatBuffer old, int capacity) { + FloatBuffer newBuf = BufferUtils.createFloatBuffer(capacity); + int oldPos = old.position(); + old.rewind(); + newBuf.put(old); + newBuf.position(Math.min(capacity, oldPos)); + return newBuf; + } + /** * Backported from LWJGL3 under the BSD 3-Clause "New" or "Revised" License license * diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 77bb3270f..9ab16d84d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -24,6 +24,8 @@ public enum Mixins { ANGELICA(new Builder("Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( "angelica.MixinEntityRenderer" + ,"angelica.MixinGuiIngameForge" + ,"angelica.MixinFontRenderer" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinFontRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinFontRenderer.java new file mode 100644 index 000000000..2e185c503 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinFontRenderer.java @@ -0,0 +1,171 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica; + +import com.gtnewhorizons.angelica.client.font.BatchingFontRenderer; +import com.gtnewhorizons.angelica.mixins.interfaces.FontRendererAccessor; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.settings.GameSettings; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +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.CallbackInfo; + +import java.util.Random; + +/** + * Fixes the horrible performance of FontRenderer + * @author eigenraven + */ +@Mixin(FontRenderer.class) +public abstract class MixinFontRenderer implements FontRendererAccessor { + + @Shadow + private boolean randomStyle; + + @Shadow + private boolean boldStyle; + + @Shadow + private boolean strikethroughStyle; + + @Shadow + private boolean underlineStyle; + + @Shadow + private boolean italicStyle; + + @Shadow + private int[] colorCode; + + @Shadow + private int textColor; + + @Shadow(remap = false) + protected abstract void setColor(float r, float g, float b, float a); + + @Shadow + private float alpha; + + @Shadow + private float red; + + /** Actually green */ + @Shadow + private float blue; + + /** Actually blue */ + @Shadow + private float green; + + @Shadow + public Random fontRandom; + + @Shadow + protected int[] charWidth; + + @Shadow + private boolean unicodeFlag; + + @Shadow + protected float posX; + + @Shadow + protected float posY; + + @Shadow + protected abstract float renderCharAtPos(int p_78278_1_, char p_78278_2_, boolean p_78278_3_); + + @Shadow(remap = false) + protected abstract void doDraw(float f); + + @Shadow + @Final + private static ResourceLocation[] unicodePageLocations; + @Shadow + protected byte[] glyphWidth; + @Shadow + @Final + protected ResourceLocation locationFontTexture; + @Shadow + @Final + private TextureManager renderEngine; + @Shadow + private boolean bidiFlag; + + @Shadow + protected abstract String bidiReorder(String p_147647_1_); + + @Unique + public BatchingFontRenderer angelica$batcher; + + @Unique + private static final char angelica$FORMATTING_CHAR = 167; // § + + @Unique + private static final float angelica$1_over_255 = 1.0f/255.0f; // § + + @Inject(method = "", at = @At("TAIL")) + private void angelica$injectBatcher(GameSettings settings, ResourceLocation fontLocation, TextureManager texManager, + boolean unicodeMode, CallbackInfo ci) { + angelica$batcher = new BatchingFontRenderer((FontRenderer) (Object) this, unicodePageLocations, this.charWidth, this.glyphWidth, this.colorCode, this.locationFontTexture, this.renderEngine); + } + + @Unique + private static boolean angelica$charInRange(char what, char fromInclusive, char toInclusive) { + return (what >= fromInclusive) && (what <= toInclusive); + } + + /** + * @author eigenraven + * @reason Replace with more sensible batched rendering and optimize some operations + */ + @Overwrite + public int drawString(String text, int x, int y, int argb, boolean dropShadow) + { + if (text == null) + { + return 0; + } + else + { + if (this.bidiFlag) + { + text = this.bidiReorder(text); + } + + if ((argb & 0xfc000000) == 0) + { + argb |= 0xff000000; + } + + this.red = (float)(argb >> 16 & 255) / 255.0F; + this.blue = (float)(argb >> 8 & 255) / 255.0F; + this.green = (float)(argb & 255) / 255.0F; + this.alpha = (float)(argb >> 24 & 255) / 255.0F; + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + this.posX = (float)x; + this.posY = (float)y; + return (int) angelica$batcher.drawString(x, y, argb, dropShadow, unicodeFlag, text, 0, text.length()); + } + } + + /** + * @author eigenraven + * @reason Replace with more sensible batched rendering and optimize some operations + */ + @Overwrite + private int renderString(String text, int x, int y, int argb, boolean dropShadow) { + return drawString(text, x, y, argb, dropShadow); + } + + @Override + public BatchingFontRenderer angelica$getBatcher() { + return angelica$batcher; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinGuiIngameForge.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinGuiIngameForge.java new file mode 100644 index 000000000..193f410ed --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinGuiIngameForge.java @@ -0,0 +1,36 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica; + +import com.gtnewhorizons.angelica.mixins.interfaces.FontRendererAccessor; +import net.minecraft.client.gui.FontRenderer; +import net.minecraftforge.client.GuiIngameForge; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GuiIngameForge.class) +public class MixinGuiIngameForge { + + @Shadow(remap = false) + private FontRenderer fontrenderer; + + @Inject( + method = "renderHUDText", + at = @At( + value = "INVOKE", + target = "net/minecraftforge/client/event/RenderGameOverlayEvent$Text.(Lnet/minecraftforge/client/event/RenderGameOverlayEvent;Ljava/util/ArrayList;Ljava/util/ArrayList;)V"), + remap = false) + private void angelica$startF3TextBatching(int width, int height, CallbackInfo ci) { + FontRendererAccessor fra = (FontRendererAccessor) (Object) fontrenderer; + fra.angelica$getBatcher().beginBatch(); + } + + @Inject( + method = "renderHUDText", + at = @At(value = "INVOKE", target = "net/minecraft/profiler/Profiler.endSection()V")) + private void angelica$endF3TextBatching(int width, int height, CallbackInfo ci) { + FontRendererAccessor fra = (FontRendererAccessor) (Object) fontrenderer; + fra.angelica$getBatcher().endBatch(); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/FontRendererAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/FontRendererAccessor.java new file mode 100644 index 000000000..9376c6a8c --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/FontRendererAccessor.java @@ -0,0 +1,7 @@ +package com.gtnewhorizons.angelica.mixins.interfaces; + +import com.gtnewhorizons.angelica.client.font.BatchingFontRenderer; + +public interface FontRendererAccessor { + BatchingFontRenderer angelica$getBatcher(); +} From bea285054de714324e4e631568d870b883024ce1 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 30 Nov 2023 18:32:24 -0500 Subject: [PATCH 198/301] Add JVM flag to bypass GL state caching --- .../angelica/glsm/GLStateManager.java | 24 ++++++++++--------- .../angelica/glsm/states/BooleanState.java | 3 ++- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index a79fcaefe..ffeba4dc2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -40,6 +40,8 @@ @SuppressWarnings("unused") // Used in ASM public class GLStateManager { + public static final boolean BYPASS_CACHE = Boolean.parseBoolean(System.getProperty("angelica.disableGlCache", "false")); + // GLStateManager State Trackers @Getter private static int activeTexture; @Getter private static final BlendState blendState = new BlendState(); @@ -161,7 +163,7 @@ public static void glBlendFunc(int srcFactor, int dstFactor) { OpenGlHelper.glBlendFunc(srcFactor, dstFactor, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); return; } - if (blendState.srcRgb != srcFactor || blendState.dstRgb != dstFactor) { + if (GLStateManager.BYPASS_CACHE || blendState.srcRgb != srcFactor || blendState.dstRgb != dstFactor) { blendState.srcRgb = srcFactor; blendState.dstRgb = dstFactor; GL11.glBlendFunc(srcFactor, dstFactor); @@ -182,7 +184,7 @@ public static void tryBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, in srcAlpha = GL11.GL_ONE; dstAlpha = GL11.GL_ONE_MINUS_SRC_ALPHA; } - if (blendState.srcRgb != srcRgb || blendState.dstRgb != dstRgb || blendState.srcAlpha != srcAlpha || blendState.dstAlpha != dstAlpha) { + if (GLStateManager.BYPASS_CACHE || blendState.srcRgb != srcRgb || blendState.dstRgb != dstRgb || blendState.srcAlpha != srcAlpha || blendState.dstAlpha != dstAlpha) { blendState.srcRgb = srcRgb; blendState.dstRgb = dstRgb; blendState.srcAlpha = srcAlpha; @@ -196,7 +198,7 @@ public static void tryBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, in public static void glDepthFunc(int func) { // Hacky workaround for now, need to figure out why this isn't being applied... - if (func != depthState.func || GLStateManager.runningSplash) { + if (GLStateManager.BYPASS_CACHE || func != depthState.func || GLStateManager.runningSplash) { depthState.func = func; GL11.glDepthFunc(func); } @@ -286,7 +288,7 @@ private static float b2f(byte b) { private static boolean changeColor(float red, float green, float blue, float alpha) { // Helper function for glColor* - if (red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { + if (GLStateManager.BYPASS_CACHE || red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { Color.red = red; Color.green = green; Color.blue = blue; @@ -307,7 +309,7 @@ public static void glColorMask(boolean red, boolean green, boolean blue, boolean return; } } - if (red != ColorMask.red || green != ColorMask.green || blue != ColorMask.blue || alpha != ColorMask.alpha) { + if (GLStateManager.BYPASS_CACHE || red != ColorMask.red || green != ColorMask.green || blue != ColorMask.blue || alpha != ColorMask.alpha) { ColorMask.red = red; ColorMask.green = green; ColorMask.blue = blue; @@ -318,7 +320,7 @@ public static void glColorMask(boolean red, boolean green, boolean blue, boolean // Clear Color public static void glClearColor(float red, float green, float blue, float alpha) { - if (red != ClearColor.red || green != ClearColor.green || blue != ClearColor.blue || alpha != ClearColor.alpha) { + if (GLStateManager.BYPASS_CACHE || red != ClearColor.red || green != ClearColor.green || blue != ClearColor.blue || alpha != ClearColor.alpha) { ClearColor.red = red; ClearColor.green = green; ClearColor.blue = blue; @@ -363,7 +365,7 @@ public static void glAlphaFunc(int function, float reference) { // Textures public static void glActiveTexture(int texture) { final int newTexture = texture - GL13.GL_TEXTURE0; - if (activeTexture != newTexture) { + if (GLStateManager.BYPASS_CACHE || activeTexture != newTexture) { activeTexture = newTexture; GL13.glActiveTexture(texture); } @@ -371,14 +373,14 @@ public static void glActiveTexture(int texture) { public static void glActiveTextureARB(int texture) { final int newTexture = texture - GL13.GL_TEXTURE0; - if (activeTexture != newTexture) { + if (GLStateManager.BYPASS_CACHE || activeTexture != newTexture) { activeTexture = newTexture; ARBMultitexture.glActiveTextureARB(texture); } } public static void glBindTexture(int target, int texture) { - if (Textures[activeTexture].binding != texture) { + if (GLStateManager.BYPASS_CACHE || Textures[activeTexture].binding != texture) { Textures[activeTexture].binding = texture; GL11.glBindTexture(target, texture); if (AngelicaConfig.enableIris) { @@ -552,7 +554,7 @@ public static Vector3d getFogColor() { } public static void fogColor(float red, float green, float blue, float alpha) { - if (red != fogState.fogColor.x || green != fogState.fogColor.y || blue != fogState.fogColor.z || alpha != fogState.fogAlpha) { + if (GLStateManager.BYPASS_CACHE || red != fogState.fogColor.x || green != fogState.fogColor.y || blue != fogState.fogColor.z || alpha != fogState.fogAlpha) { fogState.fogColor.set(red, green, blue); fogState.fogAlpha = alpha; fogState.fogColorBuffer.clear(); @@ -600,7 +602,7 @@ public static void setFogBlack() { } public static void glShadeModel(int mode) { - if (modelShadeMode != mode) { + if (GLStateManager.BYPASS_CACHE || modelShadeMode != mode) { modelShadeMode = mode; GL11.glShadeModel(mode); } diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/BooleanState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/BooleanState.java index 1c9057604..f341405ae 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/states/BooleanState.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/BooleanState.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.glsm.states; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import lombok.Getter; import org.lwjgl.opengl.GL11; @@ -22,7 +23,7 @@ public void enable() { } public void setEnabled(boolean enabled) { - if (enabled != this.enabled) { + if (GLStateManager.BYPASS_CACHE || enabled != this.enabled) { this.enabled = enabled; if (enabled) { GL11.glEnable(this.cap); From 9a6436021320dd287aaba1772e2c4f7c2d5ca76c Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 30 Nov 2023 19:47:18 -0500 Subject: [PATCH 199/301] Make block bounds fields thread-safe TODO: Check if this impacts performance --- .../angelica/glsm/ThreadedBlockData.java | 30 +++++++++ .../gtnewhorizons/angelica/mixins/Mixins.java | 3 +- .../mixins/early/sodium/MixinBlock.java | 43 +++++++++++++ .../transform/RedirectorTransformer.java | 63 ++++++++++++++++--- 4 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/ThreadedBlockData.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinBlock.java diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/ThreadedBlockData.java b/src/main/java/com/gtnewhorizons/angelica/glsm/ThreadedBlockData.java new file mode 100644 index 000000000..843b6c0d2 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/ThreadedBlockData.java @@ -0,0 +1,30 @@ +package com.gtnewhorizons.angelica.glsm; + +import net.minecraft.block.Block; + +/** + * Used to store the block bounds fields in a thread-safe manner, as instance fields don't work correctly + * on multiple threads. + */ +public class ThreadedBlockData { + public double minX, minY, minZ, maxX, maxY, maxZ; + + public ThreadedBlockData() {} + + public ThreadedBlockData(ThreadedBlockData other) { + this.minX = other.minX; + this.minY = other.minY; + this.minZ = other.minZ; + this.maxX = other.maxX; + this.maxY = other.maxY; + this.maxZ = other.maxZ; + } + + public static ThreadedBlockData get(Block block) { + return ((Getter)block).angelica$getThreadData(); + } + + public interface Getter { + ThreadedBlockData angelica$getThreadData(); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 9ab16d84d..62ced6bea 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -68,7 +68,8 @@ public enum Mixins { SODIUM(new Builder("Sodium").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodium).addMixinClasses( - "sodium.MixinChunkProviderClient" + "sodium.MixinChunkProviderClient" + ,"sodium.MixinBlock" ,"sodium.MixinEntity" ,"sodium.MixinRenderManager" ,"sodium.MixinExtendedBlockStorage" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinBlock.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinBlock.java new file mode 100644 index 000000000..a0929c288 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinBlock.java @@ -0,0 +1,43 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import com.gtnewhorizons.angelica.glsm.ThreadedBlockData; +import net.minecraft.block.Block; +import org.spongepowered.asm.mixin.Mixin; + +/** + * Store thread-safe block data here. + * + * We need to be careful - blocks will initialize some stuff in the constructor, so the first ThreadedBlockData + * instance should be used as the clone for all others. This will ensure the block bounds are set correctly + * for blocks that don't change their bounds at runtime. + */ +@Mixin(Block.class) +public class MixinBlock implements ThreadedBlockData.Getter { + private final ThreadLocal angelica$threadData = ThreadLocal.withInitial(() -> null); + private volatile ThreadedBlockData angelica$initialData; + + @Override + public ThreadedBlockData angelica$getThreadData() { + ThreadedBlockData data = angelica$threadData.get(); + if(data != null) + return data; + + return createThreadedBlockData(); + } + + private ThreadedBlockData createThreadedBlockData() { + ThreadedBlockData data; + + synchronized (this) { + if(angelica$initialData == null) { + data = angelica$initialData = new ThreadedBlockData(); + } else { + data = new ThreadedBlockData(angelica$initialData); + } + } + + angelica$threadData.set(data); + + return data; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index b3e6aab1f..956566497 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -1,21 +1,17 @@ package com.gtnewhorizons.angelica.transform; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.coderbot.iris.IrisLogging; import net.minecraft.launchwrapper.IClassTransformer; import net.minecraft.launchwrapper.Launch; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.tuple.Pair; import org.spongepowered.asm.lib.ClassReader; import org.spongepowered.asm.lib.ClassWriter; import org.spongepowered.asm.lib.Opcodes; -import org.spongepowered.asm.lib.tree.AbstractInsnNode; -import org.spongepowered.asm.lib.tree.ClassNode; -import org.spongepowered.asm.lib.tree.FieldInsnNode; -import org.spongepowered.asm.lib.tree.IntInsnNode; -import org.spongepowered.asm.lib.tree.LdcInsnNode; -import org.spongepowered.asm.lib.tree.MethodInsnNode; -import org.spongepowered.asm.lib.tree.MethodNode; +import org.spongepowered.asm.lib.tree.*; import java.io.File; import java.io.IOException; @@ -44,14 +40,25 @@ public class RedirectorTransformer implements IClassTransformer { private static final String EXTBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate"; private static final String ARBMultiTexture = "org/lwjgl/opengl/ARBMultitexture"; private static final String TessellatorClass = "net/minecraft/client/renderer/Tessellator"; + private static final String BlockClass = "net/minecraft/block/Block"; private static final String MinecraftClient = "net.minecraft.client"; private static final String SplashProgress = "cpw.mods.fml.client.SplashProgress"; + private static final String ThreadedBlockData = "com/gtnewhorizons/angelica/glsm/ThreadedBlockData"; private static final Set ExcludedMinecraftMainThreadChecks = ImmutableSet.of( "startGame", "func_71384_a", "initializeTextures", "func_77474_a" ); - private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, OpenGlHelper, EXTBlendFunc, ARBMultiTexture, TessellatorClass); + private static final List> BlockBoundsFields = ImmutableList.of( + Pair.of("minX", "field_149759_B"), + Pair.of("minY", "field_149760_C"), + Pair.of("minZ", "field_149754_D"), + Pair.of("maxX", "field_149755_E"), + Pair.of("maxY", "field_149756_F"), + Pair.of("maxZ", "field_149757_G") + ); + + private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL13, GL14, OpenGlHelper, EXTBlendFunc, ARBMultiTexture, TessellatorClass, BlockClass); private static final Map> methodRedirects = new HashMap<>(); private static final Map glCapRedirects = new HashMap<>(); private static final List TransformerExclusions = Arrays.asList( @@ -193,6 +200,46 @@ public byte[] transform(final String className, String transformedName, byte[] b mn.instructions.set(node, new MethodInsnNode(Opcodes.INVOKESTATIC, "com/gtnewhorizons/angelica/glsm/TessellatorManager", "get", "()Lnet/minecraft/client/renderer/Tessellator;", false)); changed = true; } + } else if ((node.getOpcode() == Opcodes.GETFIELD || node.getOpcode() == Opcodes.PUTFIELD) && node instanceof FieldInsnNode fNode) { + if(fNode.owner.equals(BlockClass)) { + Pair fieldToRedirect = null; + for(Pair blockPairs : BlockBoundsFields) { + if(fNode.name.equals(blockPairs.getLeft()) || fNode.name.equals(blockPairs.getRight())) { + fieldToRedirect = blockPairs; + break; + } + } + if(fieldToRedirect != null) { + if (IrisLogging.ENABLE_SPAM) { + AngelicaTweaker.LOGGER.info("Redirecting Block.{} in {} to thread-safe wrapper", fNode.name, transformedName); + } + // Perform the redirect + fNode.name = fieldToRedirect.getLeft(); // use unobfuscated name + fNode.owner = ThreadedBlockData; + // Inject getter before the field access, to turn Block -> ThreadedBlockData + MethodInsnNode getter = new MethodInsnNode(Opcodes.INVOKESTATIC, ThreadedBlockData, "get", "(L" + BlockClass + ";)L" + ThreadedBlockData + ";", false); + if(node.getOpcode() == Opcodes.GETFIELD) { + mn.instructions.insertBefore(fNode, getter); + } else if(node.getOpcode() == Opcodes.PUTFIELD) { + // FIXME: this code assumes doubles + // Stack: Block, double + InsnList beforePut = new InsnList(); + beforePut.add(new InsnNode(Opcodes.DUP2_X1)); + // Stack: double, Block, double + beforePut.add(new InsnNode(Opcodes.POP2)); + // Stack: double, Block + beforePut.add(getter); + // Stack: double, ThreadedBlockData + beforePut.add(new InsnNode(Opcodes.DUP_X2)); + // Stack: ThreadedBlockData, double, ThreadedBlockData + beforePut.add(new InsnNode(Opcodes.POP)); + // Stack: ThreadedBlockData, double + mn.instructions.insertBefore(fNode, beforePut); + } + changed = true; + } + + } } } if (ASSERT_MAIN_THREAD && redirectInMethod && !transformedName.startsWith(SplashProgress) && !(transformedName.startsWith(MinecraftClient) && ExcludedMinecraftMainThreadChecks.contains(mn.name))) { From 023c1d089ef1e6ff49e1a644e3875fb274942fb5 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 30 Nov 2023 16:59:37 -0800 Subject: [PATCH 200/301] Put FontRenderer behind a config --- .../gtnewhorizons/angelica/config/AngelicaConfig.java | 5 +++++ .../java/com/gtnewhorizons/angelica/mixins/Mixins.java | 10 ++++++++-- .../angelica/{ => fontrenderer}/MixinFontRenderer.java | 2 +- .../{ => fontrenderer}/MixinGuiIngameForge.java | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/{ => fontrenderer}/MixinFontRenderer.java (98%) rename src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/{ => fontrenderer}/MixinGuiIngameForge.java (95%) diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index 091471d30..f189687d6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -43,4 +43,9 @@ public class AngelicaConfig { @Config.RequiresMcRestart // TODO disabled for now as it doesn't render items with an enchantment glint in the hotbar properly as well as doesn't render the vignette public static boolean enableHudCaching; + + @Config.Comment("Batch render fonts [Experimental]") + @Config.DefaultBoolean(false) + @Config.RequiresMcRestart + public static Boolean enableFontRenderer; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 62ced6bea..c8a306099 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -24,8 +24,14 @@ public enum Mixins { ANGELICA(new Builder("Angelica").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).addMixinClasses( "angelica.MixinEntityRenderer" - ,"angelica.MixinGuiIngameForge" - ,"angelica.MixinFontRenderer" + + ) + ), + + ANGELICA_FONT_RENDERER(new Builder("Angelica Font Renderer").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableFontRenderer).addMixinClasses( + "angelica.fontrenderer.MixinGuiIngameForge" + ,"angelica.fontrenderer.MixinFontRenderer" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinFontRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java similarity index 98% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinFontRenderer.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java index 2e185c503..16928626b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinFontRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.angelica; +package com.gtnewhorizons.angelica.mixins.early.angelica.fontrenderer; import com.gtnewhorizons.angelica.client.font.BatchingFontRenderer; import com.gtnewhorizons.angelica.mixins.interfaces.FontRendererAccessor; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinGuiIngameForge.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinGuiIngameForge.java similarity index 95% rename from src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinGuiIngameForge.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinGuiIngameForge.java index 193f410ed..1754bd240 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinGuiIngameForge.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinGuiIngameForge.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.mixins.early.angelica; +package com.gtnewhorizons.angelica.mixins.early.angelica.fontrenderer; import com.gtnewhorizons.angelica.mixins.interfaces.FontRendererAccessor; import net.minecraft.client.gui.FontRenderer; From 0002f2b9a78ae4ca7b60b88063001ca35b724287 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 30 Nov 2023 19:37:23 -0800 Subject: [PATCH 201/301] State Tracker Enhancements * Keep track of inGLNewList * Clear binding on delete texture * Push/Pop Attrib Hacks -- to be evolved later --- .../angelica/glsm/GLStateManager.java | 46 +++++++++++++++++-- .../gtnewhorizons/angelica/mixins/Mixins.java | 3 +- .../angelica/textures/MixinTextureUtil.java | 15 ++++++ .../transform/RedirectorTransformer.java | 15 ++++-- 4 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureUtil.java diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index ffeba4dc2..c27fc7726 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -74,6 +74,8 @@ public class GLStateManager { private static Thread CurrentThread = MainThread; private static boolean runningSplash = false; + private static boolean inGLNewList = false; + private static boolean hudCaching$blendEnabled; public static void init() { @@ -380,9 +382,17 @@ public static void glActiveTextureARB(int texture) { } public static void glBindTexture(int target, int texture) { - if (GLStateManager.BYPASS_CACHE || Textures[activeTexture].binding != texture) { - Textures[activeTexture].binding = texture; + if(inGLNewList) { + // Binding a texture, while building a list, is not allowed and is a silent noop + Throwable throwable = new Throwable(); + LOGGER.info("Naughty naughty, someone's making a texture binding in a display list!", throwable); + return; + } + + if (GLStateManager.BYPASS_CACHE || Textures[activeTexture].binding != texture || runningSplash) { GL11.glBindTexture(target, texture); + + Textures[activeTexture].binding = texture; if (AngelicaConfig.enableIris) { TextureTracker.INSTANCE.onBindTexture(texture); } @@ -408,6 +418,7 @@ public static void glDeleteTextures(int id) { if (AngelicaConfig.enableIris) { iris$onDeleteTexture(id); } + Textures[activeTexture].binding = -1; GL11.glDeleteTextures(id); } @@ -417,6 +428,7 @@ public static void glDeleteTextures(IntBuffer ids) { iris$onDeleteTexture(id); } } + Textures[activeTexture].binding = -1; GL11.glDeleteTextures(ids); } @@ -465,8 +477,7 @@ public static void disableTexture() { } public static void setFilter(boolean bilinear, boolean mipmap) { - int j; - int i; + int i, j; if (bilinear) { i = mipmap ? GL11.GL_LINEAR_MIPMAP_LINEAR : GL11.GL_LINEAR; j = GL11.GL_LINEAR; @@ -628,4 +639,31 @@ public static void makeCurrent(Drawable drawable) throws LWJGLException { CurrentThread = currentThread; LOGGER.info("Current thread: {}", currentThread.getName()); } + + public static void glNewList(int list, int mode) { + if(inGLNewList) { + throw new RuntimeException("glNewList called inside of a display list!"); + } + inGLNewList = true; + GL11.glNewList(list, mode); + } + + public static void glEndList() { + if(!inGLNewList) { + throw new RuntimeException("glEndList called outside of a display list!"); + } + inGLNewList = false; + GL11.glEndList(); + } + + public static void glPushAttrib(int mask) { + // TODO: Proper state tracking; but at least for now the current cases of this didn't do anything related to textures and + // just overly broadly set ALL_BITS :facepalm: + GL11.glPushAttrib(mask & ~(GL11.GL_TEXTURE_BIT)); + } + + public static void glPopAttrib() { + GL11.glPopAttrib(); + } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index c8a306099..0c22f1e37 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -127,7 +127,8 @@ public enum Mixins { ANGELICA_TEXTURE(new Builder("Textures").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableIris || AngelicaConfig.enableSodium).addMixinClasses( - "angelica.textures.MixinTextureAtlasSprite" + "angelica.textures.MixinTextureAtlasSprite" + ,"angelica.textures.MixinTextureUtil" )), HUD_CACHING(new Builder("Renders the HUD elements 20 times per second maximum to improve performance") diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureUtil.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureUtil.java new file mode 100644 index 000000000..dc030cb5f --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureUtil.java @@ -0,0 +1,15 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.textures; + +import net.minecraft.client.renderer.texture.TextureUtil; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(TextureUtil.class) +public class MixinTextureUtil { + + @Redirect(method = "allocateTextureImpl", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/texture/TextureUtil;deleteTexture(I)V")) + private static void angelica$dontDeleteTexture(int textureId) { + // NO-OP - Not sure why it's deleting a texture that was just generated and subsequently being bound... + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 956566497..32c37d8d7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -80,27 +80,32 @@ public class RedirectorTransformer implements IClassTransformer { glCapRedirects.put(org.lwjgl.opengl.GL12.GL_RESCALE_NORMAL, "RescaleNormal"); methodRedirects.put(GL11, RedirectMap.newMap() .add("glAlphaFunc") + .add("glBindTexture") .add("glBlendFunc") .add("glClearColor") - .add("glColor3f") - .add("glColor3d") .add("glColor3b") + .add("glColor3d") + .add("glColor3f") .add("glColor3ub") - .add("glColor4f") - .add("glColor4d") .add("glColor4b") + .add("glColor4d") + .add("glColor4f") .add("glColor4ub") .add("glColorMask") .add("glDeleteTextures") .add("glDepthFunc") .add("glDepthMask") .add("glDrawArrays") + .add("glEndList") .add("glFog") .add("glFogf") .add("glFogi") + .add("glNewList") + .add("glPushAttrib") + .add("glPopAttrib") .add("glShadeModel") .add("glTexImage2D") - .add("glBindTexture")); + ); methodRedirects.put(GL13, RedirectMap.newMap().add("glActiveTexture")); methodRedirects.put(GL14, RedirectMap.newMap().add("glBlendFuncSeparate", "tryBlendFuncSeparate")); methodRedirects.put(OpenGlHelper, RedirectMap.newMap() From 1123b6d4bf1bb069fe409144b6dd381d810df111 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 30 Nov 2023 20:33:37 -0800 Subject: [PATCH 202/301] ayfkm --- .../java/com/gtnewhorizons/angelica/config/AngelicaConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index f189687d6..766a73629 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -47,5 +47,5 @@ public class AngelicaConfig { @Config.Comment("Batch render fonts [Experimental]") @Config.DefaultBoolean(false) @Config.RequiresMcRestart - public static Boolean enableFontRenderer; + public static boolean enableFontRenderer; } From 6dd3078f05a8e831aea2dbb3ff041941308ff3e6 Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 1 Dec 2023 15:17:44 +0100 Subject: [PATCH 203/301] Fix double initialization that occasionally caused a race condition Why it happened: - setWorldAndLoadRenderers has a hook at the beginning that initializes Sodium if it hasn't been already - loadRenderers has a hook at the end that always initializes Sodium - setWorldAndLoadRenderers calls loadRenderers at the end This caused a race condition sometimes because Sodium's thread scheduler is not prepared to be able to stop the instant after it has started. The issue was resolved by moving the setWorldAndLoadRenderers hook to the end of the method (the same place as it is in Sodium/Embeddium 1.16) --- .../angelica/mixins/early/sodium/MixinRenderGlobal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 5393a69e7..0f2dc79e1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -67,7 +67,7 @@ public int getChunksSubmitted() { this.renderer = SodiumWorldRenderer.create(mc); } - @Inject(method="Lnet/minecraft/client/renderer/RenderGlobal;setWorldAndLoadRenderers(Lnet/minecraft/client/multiplayer/WorldClient;)V", at=@At("HEAD")) + @Inject(method="Lnet/minecraft/client/renderer/RenderGlobal;setWorldAndLoadRenderers(Lnet/minecraft/client/multiplayer/WorldClient;)V", at=@At("RETURN")) private void sodium$setWorldAndLoadRenderers(WorldClient world, CallbackInfo ci) { RenderDevice.enterManagedCode(); try { From 7e6a9ad0c1ea33b8d5deee59c33900e009637702 Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 1 Dec 2023 17:21:40 +0100 Subject: [PATCH 204/301] Don't shadow jetbrains annotations No reason to since it's a compile-time dep. Fixes ASMModParser yelling about module-info.class --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 8b58e3e4b..5ef6e179b 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -41,7 +41,7 @@ dependencies { annotationProcessor("org.projectlombok:lombok:1.18.22") // Iris Shaders - shadowImplementation('org.jetbrains:annotations:24.0.1') // Apache 2.0 + compileOnly('org.jetbrains:annotations:24.0.1') shadowImplementation("it.unimi.dsi:fastutil:8.2.1") // Apache 2.0 shadowImplementation("org.joml:joml:1.10.5") // MIT shadowImplementation("org.anarres:jcpp:1.4.14") // Apache 2.0 From 815012a46f594d99b13c69bba3a6c37ae6a0c9a0 Mon Sep 17 00:00:00 2001 From: makamys Date: Fri, 1 Dec 2023 17:27:30 +0100 Subject: [PATCH 205/301] Fix checkstyle violation --- .../angelica/transform/RedirectorTransformer.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index 32c37d8d7..a4b8d25a6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -11,7 +11,15 @@ import org.spongepowered.asm.lib.ClassReader; import org.spongepowered.asm.lib.ClassWriter; import org.spongepowered.asm.lib.Opcodes; -import org.spongepowered.asm.lib.tree.*; +import org.spongepowered.asm.lib.tree.AbstractInsnNode; +import org.spongepowered.asm.lib.tree.ClassNode; +import org.spongepowered.asm.lib.tree.FieldInsnNode; +import org.spongepowered.asm.lib.tree.InsnList; +import org.spongepowered.asm.lib.tree.InsnNode; +import org.spongepowered.asm.lib.tree.IntInsnNode; +import org.spongepowered.asm.lib.tree.LdcInsnNode; +import org.spongepowered.asm.lib.tree.MethodInsnNode; +import org.spongepowered.asm.lib.tree.MethodNode; import java.io.File; import java.io.IOException; From 6a88b52cd670c59f61b5af9bfc75233c1d01a846 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 1 Dec 2023 16:27:44 -0800 Subject: [PATCH 206/301] Dirty bits --- .../gtnewhorizons/angelica/glsm/Dirty.java | 42 ++++++++++++++++++ .../angelica/glsm/GLStateManager.java | 44 ++++++++++++++----- .../angelica/glsm/states/BooleanState.java | 6 ++- .../fontrenderer/MixinFontRenderer.java | 2 +- 4 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/glsm/Dirty.java diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/Dirty.java b/src/main/java/com/gtnewhorizons/angelica/glsm/Dirty.java new file mode 100644 index 000000000..0cb15815a --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/Dirty.java @@ -0,0 +1,42 @@ +package com.gtnewhorizons.angelica.glsm; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +public class Dirty { + private Dirty() {} + + public static final long + ALPHA_TEST = 1L << 0, + BLEND = 1L << 1, + DEPTH_TEST = 1L << 2, + CULL = 1L << 3, + LIGHTING = 1L << 4, + RESCALE_NORMAL = 1L << 5, + TEXTURE_2D = 1L << 6, + FOG = 1L << 7, + BLEND_STATE = 1L << 8, + DEPTH_FUNC = 1L << 9, + DEPTH_MASK = 1L << 10, + COLOR = 1L << 11, + COLOR_MASK = 1L << 12, + CLEAR_COLOR = 1L << 13, + ACTIVE_TEXTURE = 1L << 14, + BOUND_TEXTURE = 1L << 15, + SHADE_MODEL = 1L << 16, + ALL = ALPHA_TEST | BLEND | DEPTH_TEST | CULL | LIGHTING | RESCALE_NORMAL | TEXTURE_2D | FOG | BLEND_STATE | DEPTH_FUNC | DEPTH_MASK | COLOR | COLOR_MASK | CLEAR_COLOR | ACTIVE_TEXTURE | BOUND_TEXTURE | SHADE_MODEL; + + public static long getFlagFromCap(int cap) { + return switch (cap) { + case GL11.GL_ALPHA_TEST -> ALPHA_TEST; + case GL11.GL_BLEND -> BLEND; + case GL11.GL_DEPTH_TEST -> DEPTH_TEST; + case GL11.GL_CULL_FACE -> CULL; + case GL11.GL_LIGHTING -> LIGHTING; + case GL12.GL_RESCALE_NORMAL -> RESCALE_NORMAL; + case GL11.GL_TEXTURE_2D -> TEXTURE_2D; + case GL11.GL_FOG -> FOG; + default -> throw new RuntimeException("Invalid cap: " + cap); + }; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index c27fc7726..8a3fd6f01 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -55,6 +55,8 @@ public class GLStateManager { @Getter private static final BooleanState lightingState = new BooleanState(GL11.GL_LIGHTING); @Getter private static final BooleanState rescaleNormalState = new BooleanState(GL12.GL_RESCALE_NORMAL); + private static long dirty = 0; + private static int modelShadeMode; @Getter @@ -163,9 +165,10 @@ public static void glBlendFunc(int srcFactor, int dstFactor) { blendState.srcAlpha = GL11.GL_ONE; blendState.dstAlpha = GL11.GL_ONE_MINUS_SRC_ALPHA; OpenGlHelper.glBlendFunc(srcFactor, dstFactor, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + clean(Dirty.BLEND_STATE); return; } - if (GLStateManager.BYPASS_CACHE || blendState.srcRgb != srcFactor || blendState.dstRgb != dstFactor) { + if (GLStateManager.BYPASS_CACHE || blendState.srcRgb != srcFactor || blendState.dstRgb != dstFactor || checkDirty(Dirty.BLEND_STATE)) { blendState.srcRgb = srcFactor; blendState.dstRgb = dstFactor; GL11.glBlendFunc(srcFactor, dstFactor); @@ -186,7 +189,7 @@ public static void tryBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, in srcAlpha = GL11.GL_ONE; dstAlpha = GL11.GL_ONE_MINUS_SRC_ALPHA; } - if (GLStateManager.BYPASS_CACHE || blendState.srcRgb != srcRgb || blendState.dstRgb != dstRgb || blendState.srcAlpha != srcAlpha || blendState.dstAlpha != dstAlpha) { + if (GLStateManager.BYPASS_CACHE || blendState.srcRgb != srcRgb || blendState.dstRgb != dstRgb || blendState.srcAlpha != srcAlpha || blendState.dstAlpha != dstAlpha || checkDirty(Dirty.BLEND_STATE)) { blendState.srcRgb = srcRgb; blendState.dstRgb = dstRgb; blendState.srcAlpha = srcAlpha; @@ -200,7 +203,7 @@ public static void tryBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, in public static void glDepthFunc(int func) { // Hacky workaround for now, need to figure out why this isn't being applied... - if (GLStateManager.BYPASS_CACHE || func != depthState.func || GLStateManager.runningSplash) { + if (GLStateManager.BYPASS_CACHE || func != depthState.func || GLStateManager.runningSplash || checkDirty(Dirty.DEPTH_FUNC)) { depthState.func = func; GL11.glDepthFunc(func); } @@ -214,7 +217,7 @@ public static void glDepthMask(boolean mask) { } } - if (mask != depthState.mask) { + if (mask != depthState.mask || checkDirty(Dirty.DEPTH_MASK)) { depthState.mask = mask; GL11.glDepthMask(mask); } @@ -290,7 +293,7 @@ private static float b2f(byte b) { private static boolean changeColor(float red, float green, float blue, float alpha) { // Helper function for glColor* - if (GLStateManager.BYPASS_CACHE || red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha) { + if (GLStateManager.BYPASS_CACHE || red != Color.red || green != Color.green || blue != Color.blue || alpha != Color.alpha || checkDirty(Dirty.COLOR)) { Color.red = red; Color.green = green; Color.blue = blue; @@ -301,7 +304,8 @@ private static boolean changeColor(float red, float green, float blue, float alp } public static void clearCurrentColor() { - glColor4f(-1.0F, -1.0F, -1.0F, -1.0F); + // Marks the cache dirty, doesn't actually reset the color + dirty(Dirty.COLOR); } public static void glColorMask(boolean red, boolean green, boolean blue, boolean alpha) { @@ -311,7 +315,7 @@ public static void glColorMask(boolean red, boolean green, boolean blue, boolean return; } } - if (GLStateManager.BYPASS_CACHE || red != ColorMask.red || green != ColorMask.green || blue != ColorMask.blue || alpha != ColorMask.alpha) { + if (GLStateManager.BYPASS_CACHE || red != ColorMask.red || green != ColorMask.green || blue != ColorMask.blue || alpha != ColorMask.alpha || checkDirty(Dirty.COLOR_MASK)) { ColorMask.red = red; ColorMask.green = green; ColorMask.blue = blue; @@ -322,7 +326,7 @@ public static void glColorMask(boolean red, boolean green, boolean blue, boolean // Clear Color public static void glClearColor(float red, float green, float blue, float alpha) { - if (GLStateManager.BYPASS_CACHE || red != ClearColor.red || green != ClearColor.green || blue != ClearColor.blue || alpha != ClearColor.alpha) { + if (GLStateManager.BYPASS_CACHE || red != ClearColor.red || green != ClearColor.green || blue != ClearColor.blue || alpha != ClearColor.alpha || checkDirty(Dirty.CLEAR_COLOR)) { ClearColor.red = red; ClearColor.green = green; ClearColor.blue = blue; @@ -367,7 +371,7 @@ public static void glAlphaFunc(int function, float reference) { // Textures public static void glActiveTexture(int texture) { final int newTexture = texture - GL13.GL_TEXTURE0; - if (GLStateManager.BYPASS_CACHE || activeTexture != newTexture) { + if (GLStateManager.BYPASS_CACHE || activeTexture != newTexture || checkDirty(Dirty.ACTIVE_TEXTURE)) { activeTexture = newTexture; GL13.glActiveTexture(texture); } @@ -375,7 +379,7 @@ public static void glActiveTexture(int texture) { public static void glActiveTextureARB(int texture) { final int newTexture = texture - GL13.GL_TEXTURE0; - if (GLStateManager.BYPASS_CACHE || activeTexture != newTexture) { + if (GLStateManager.BYPASS_CACHE || activeTexture != newTexture || checkDirty(Dirty.ACTIVE_TEXTURE)) { activeTexture = newTexture; ARBMultitexture.glActiveTextureARB(texture); } @@ -389,7 +393,8 @@ public static void glBindTexture(int target, int texture) { return; } - if (GLStateManager.BYPASS_CACHE || Textures[activeTexture].binding != texture || runningSplash) { + // TODO: Do we need to do the check dirty for each bound texture? + if (GLStateManager.BYPASS_CACHE || Textures[activeTexture].binding != texture || runningSplash || checkDirty(Dirty.BOUND_TEXTURE)) { GL11.glBindTexture(target, texture); Textures[activeTexture].binding = texture; @@ -613,7 +618,7 @@ public static void setFogBlack() { } public static void glShadeModel(int mode) { - if (GLStateManager.BYPASS_CACHE || modelShadeMode != mode) { + if (GLStateManager.BYPASS_CACHE || modelShadeMode != mode || checkDirty(Dirty.SHADE_MODEL)) { modelShadeMode = mode; GL11.glShadeModel(mode); } @@ -663,7 +668,22 @@ public static void glPushAttrib(int mask) { } public static void glPopAttrib() { + dirty = Dirty.ALL; GL11.glPopAttrib(); } + public static boolean checkDirty(long flag) { + if((dirty & flag ) == flag) { + dirty &= ~flag; + return true; + } + return false; + } + public static void clean(long dirtyFlag) { + dirty &= ~dirtyFlag; + } + + public static void dirty(long dirtyFlag) { + dirty |= dirtyFlag; + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/states/BooleanState.java b/src/main/java/com/gtnewhorizons/angelica/glsm/states/BooleanState.java index f341405ae..4a2aee43e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/states/BooleanState.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/states/BooleanState.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.glsm.states; +import com.gtnewhorizons.angelica.glsm.Dirty; import com.gtnewhorizons.angelica.glsm.GLStateManager; import lombok.Getter; import org.lwjgl.opengl.GL11; @@ -7,11 +8,14 @@ public class BooleanState { private final int cap; + private final long dirtyFlag; + @Getter private boolean enabled; public BooleanState(int cap) { this.cap = cap; + this.dirtyFlag = Dirty.getFlagFromCap(this.cap); } public void disable() { @@ -23,7 +27,7 @@ public void enable() { } public void setEnabled(boolean enabled) { - if (GLStateManager.BYPASS_CACHE || enabled != this.enabled) { + if (GLStateManager.BYPASS_CACHE || enabled != this.enabled || GLStateManager.checkDirty(this.dirtyFlag)) { this.enabled = enabled; if (enabled) { GL11.glEnable(this.cap); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java index 16928626b..9ab15f17c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java @@ -160,7 +160,7 @@ public int drawString(String text, int x, int y, int argb, boolean dropShadow) * @reason Replace with more sensible batched rendering and optimize some operations */ @Overwrite - private int renderString(String text, int x, int y, int argb, boolean dropShadow) { + protected int renderString(String text, int x, int y, int argb, boolean dropShadow) { return drawString(text, x, y, argb, dropShadow); } From 971728afbd791596544fabb2b1c84eed00b3b1d0 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 1 Dec 2023 19:09:15 -0800 Subject: [PATCH 207/301] Iris Mixins - MixinSodiumWorldRenderer --- .../client/render/SodiumWorldRenderer.java | 80 ++++++++++++++++--- .../render/chunk/ChunkRenderManager.java | 10 +-- .../java/net/coderbot/iris/gl/GLDebug.java | 5 -- .../java/net/coderbot/iris/sodium/Mixins.txt | 2 +- 4 files changed, 75 insertions(+), 22 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 753fb1b53..fca82c4ee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -4,6 +4,8 @@ import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.config.AngelicaConfig; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; @@ -24,6 +26,9 @@ import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; import me.jellysquid.mods.sodium.common.util.ListUtil; +import net.coderbot.iris.pipeline.ShadowRenderer; +import net.coderbot.iris.shadows.ShadowRenderingState; +import net.coderbot.iris.sodium.shadow_map.SwappableChunkRenderManager; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.WorldRenderer; @@ -62,16 +67,15 @@ public class SodiumWorldRenderer implements ChunkStatusListener { private final LongSet loadedChunkPositions = new LongOpenHashSet(); private final Set globalTileEntities = new ObjectOpenHashSet<>(); - /** - * -- GETTER -- - * - * @return The frustum of the current player's camera used to cull chunks - */ - @Getter - private Frustrum frustum; + + @Getter private Frustrum frustum; private ChunkRenderManager chunkRenderManager; private ChunkRenderBackend chunkRenderBackend; + // Iris + private boolean wasRenderingShadows = false; + + private double iris$swapLastCameraX, iris$swapLastCameraY, iris$swapLastCameraZ, iris$swapLastCameraPitch, iris$swapLastCameraYaw; /** * Instantiates Sodium's world renderer. This should be called at the time of the world renderer initialization. */ @@ -159,6 +163,7 @@ public int getVisibleChunkCount() { */ public void scheduleTerrainUpdate() { if (this.chunkRenderManager != null) { + if(AngelicaConfig.enableIris) iris$ensureStateSwapped(); this.chunkRenderManager.markDirty(); } } @@ -200,6 +205,12 @@ public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrust boolean dirty = pos.x != this.lastCameraX || pos.y != this.lastCameraY || pos.z != this.lastCameraZ || pitch != this.lastCameraPitch || yaw != this.lastCameraYaw; + if(AngelicaConfig.enableIris) { + iris$ensureStateSwapped(); + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + dirty = true; + } + } if (dirty) { this.chunkRenderManager.markDirty(); } @@ -227,21 +238,25 @@ public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrust profiler.endSection(); SodiumGameOptions.EntityRenderDistance.setRenderDistanceMult(MathHelper.clamp_double((double) this.client.gameSettings.renderDistanceChunks / 8.0D, 1.0D, 2.5D) * (double) 1.0F * (SettingsManager.entityRenderScaleFactor)); + if(AngelicaConfig.enableIris) { + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + ShadowRenderer.visibleTileEntities.addAll(this.chunkRenderManager.getVisibleTileEntities()); + } + } } /** * Performs a render pass for the given {@link RenderLayer} and draws all visible chunks for it. */ public void drawChunkLayer(BlockRenderPass pass, MatrixStack matrixStack, double x, double y, double z) { + if(AngelicaConfig.enableIris) iris$ensureStateSwapped(); // startDrawing/endDrawing are handled by 1.7 already //pass.startDrawing(); this.chunkRenderManager.renderLayer(matrixStack, pass, x, y, z); //pass.endDrawing(); - - // Hmm, is this needed? It wasn't doing anything before, and doesn't seem to make a difference when fixed... -// GLStateManager.clearCurrentColor(); + GLStateManager.clearCurrentColor(); } public void reload() { @@ -315,7 +330,7 @@ private void renderTE(TileEntity tileEntity, int pass, float partialTicks) { public void renderTileEntities(EntityLivingBase entity, ICamera camera, float partialTicks) { int pass = MinecraftForgeClient.getRenderPass(); - for (TileEntity tileEntity : this.chunkRenderManager.getVisibleBlockEntities()) { + for (TileEntity tileEntity : this.chunkRenderManager.getVisibleTileEntities()) { renderTE(tileEntity, pass, partialTicks); } @@ -431,4 +446,47 @@ public void scheduleRebuildForChunk(int x, int y, int z, boolean important) { public ChunkRenderBackend getChunkRenderer() { return this.chunkRenderBackend; } + + // Iris + private void swapCachedCameraPositions() { + double tmp; + + tmp = lastCameraX; + lastCameraX = iris$swapLastCameraX; + iris$swapLastCameraX = tmp; + + tmp = lastCameraY; + lastCameraY = iris$swapLastCameraY; + iris$swapLastCameraY = tmp; + + tmp = lastCameraZ; + lastCameraZ = iris$swapLastCameraZ; + iris$swapLastCameraZ = tmp; + + tmp = lastCameraPitch; + lastCameraPitch = iris$swapLastCameraPitch; + iris$swapLastCameraPitch = tmp; + + tmp = lastCameraYaw; + lastCameraYaw = iris$swapLastCameraYaw; + iris$swapLastCameraYaw = tmp; + } + + private void iris$ensureStateSwapped() { + if (!wasRenderingShadows && ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + if (this.chunkRenderManager instanceof SwappableChunkRenderManager) { + ((SwappableChunkRenderManager) this.chunkRenderManager).iris$swapVisibilityState(); + swapCachedCameraPositions(); + } + + wasRenderingShadows = true; + } else if (wasRenderingShadows && !ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + if (this.chunkRenderManager instanceof SwappableChunkRenderManager) { + ((SwappableChunkRenderManager) this.chunkRenderManager).iris$swapVisibilityState(); + swapCachedCameraPositions(); + } + + wasRenderingShadows = false; + } + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 87edcdfeb..9184cb73c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -81,7 +81,7 @@ public class ChunkRenderManager implements ChunkSt private final ChunkRenderList[] chunkRenderLists = new ChunkRenderList[BlockRenderPass.COUNT]; private final ObjectList> tickableChunks = new ObjectArrayList<>(); - private final ObjectList visibleBlockEntities = new ObjectArrayList<>(); + private final ObjectList visibleTileEntities = new ObjectArrayList<>(); private final SodiumWorldRenderer renderer; private final WorldClient world; @@ -305,7 +305,7 @@ private void addEntitiesToRenderLists(ChunkRenderContainer render) { Collection tileEntities = render.getData().getTileEntities(); if (!tileEntities.isEmpty()) { - this.visibleBlockEntities.addAll(tileEntities); + this.visibleTileEntities.addAll(tileEntities); } } @@ -324,7 +324,7 @@ private void reset() { this.importantRebuildQueue.clear(); this.sortQueue.clear(); - this.visibleBlockEntities.clear(); + this.visibleTileEntities.clear(); for (ChunkRenderList list : this.chunkRenderLists) { list.reset(); @@ -342,8 +342,8 @@ private void unloadPending() { } } - public Collection getVisibleBlockEntities() { - return this.visibleBlockEntities; + public Collection getVisibleTileEntities() { + return this.visibleTileEntities; } @Override diff --git a/src/main/java/net/coderbot/iris/gl/GLDebug.java b/src/main/java/net/coderbot/iris/gl/GLDebug.java index a1c869aaa..2e040240d 100644 --- a/src/main/java/net/coderbot/iris/gl/GLDebug.java +++ b/src/main/java/net/coderbot/iris/gl/GLDebug.java @@ -5,7 +5,6 @@ package net.coderbot.iris.gl; -import com.gtnewhorizons.angelica.AngelicaMod; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.coderbot.iris.Iris; @@ -318,10 +317,6 @@ public void popGroup() { } public static void initRenderer() { - // Only enable if debug is enabled, and also forcibly disable the splash screen - if(!AngelicaMod.lwjglDebug) - return; - if (Iris.capabilities.GL_KHR_debug || Iris.capabilities.OpenGL43) { debugState = new KHRDebugState(); } else { diff --git a/src/main/java/net/coderbot/iris/sodium/Mixins.txt b/src/main/java/net/coderbot/iris/sodium/Mixins.txt index f24e84c43..b04986733 100644 --- a/src/main/java/net/coderbot/iris/sodium/Mixins.txt +++ b/src/main/java/net/coderbot/iris/sodium/Mixins.txt @@ -8,7 +8,7 @@ Y directional_shading * MixinChunkProgram.java * MixinChunkRenderManager.java * shadow_map - * MixinSodiumWorldRenderer.java + Y MixinSodiumWorldRenderer.java * MixinGameRendererContext.java * MixinChunkRenderManager.java * block_id From 0d40af258161f301cb480941f5e3421f4471edf8 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 1 Dec 2023 20:25:03 -0800 Subject: [PATCH 208/301] Iris Mixins - MixinChunkRenderManager & MixinGameRendererContext --- .../client/render/GameRendererContext.java | 4 +- .../render/chunk/ChunkRenderManager.java | 78 +++++++++++++++++-- .../java/net/coderbot/iris/sodium/Mixins.txt | 4 +- 3 files changed, 76 insertions(+), 10 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java index a2c2d4236..032d8039f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java @@ -2,6 +2,7 @@ import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.rendering.RenderingState; +import net.coderbot.iris.shadows.ShadowRenderingState; import org.joml.Matrix4f; import org.lwjgl.BufferUtils; @@ -17,7 +18,8 @@ public class GameRendererContext { // TODO get rid of matrices, it's unnecessary in 1.7 public static FloatBuffer getModelViewProjectionMatrix(MatrixStack.Entry matrices) { final FloatBuffer bufModelViewProjection = BufferUtils.createFloatBuffer(16); - final Matrix4f matrix = new Matrix4f(RenderingState.INSTANCE.getProjectionMatrix()); + final Matrix4f projectionMatrix = ShadowRenderingState.areShadowsCurrentlyBeingRendered() ? ShadowRenderingState.getShadowOrthoMatrix() : RenderingState.INSTANCE.getProjectionMatrix(); + final Matrix4f matrix = new Matrix4f(projectionMatrix); matrix.mul(RenderingState.INSTANCE.getModelViewMatrix()); matrix.mul(matrices.getModel()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 9184cb73c..4c4259283 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -3,6 +3,7 @@ import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -33,6 +34,7 @@ import me.jellysquid.mods.sodium.common.util.DirectionUtil; 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.minecraft.client.multiplayer.WorldClient; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; @@ -78,10 +80,10 @@ public class ChunkRenderManager implements ChunkSt private final ObjectArrayFIFOQueue> unloadQueue = new ObjectArrayFIFOQueue<>(); @SuppressWarnings("unchecked") - private final ChunkRenderList[] chunkRenderLists = new ChunkRenderList[BlockRenderPass.COUNT]; - private final ObjectList> tickableChunks = new ObjectArrayList<>(); + private ChunkRenderList[] chunkRenderLists = new ChunkRenderList[BlockRenderPass.COUNT]; + private ObjectList> tickableChunks = new ObjectArrayList<>(); - private final ObjectList visibleTileEntities = new ObjectArrayList<>(); + private ObjectList visibleTileEntities = new ObjectArrayList<>(); private final SodiumWorldRenderer renderer; private final WorldClient world; @@ -108,6 +110,22 @@ public class ChunkRenderManager implements ChunkSt private boolean alwaysDeferChunkUpdates; + // Iris + + private ChunkRenderList[] chunkRenderListsSwap; + + private ObjectList> tickableChunksSwap; + + private ObjectList visibleTileEntitiesSwap; + + private int visibleChunkCountSwap; + + private boolean dirtySwap; + + private static final ObjectArrayFIFOQueue EMPTY_QUEUE = new ObjectArrayFIFOQueue<>(); + + + public ChunkRenderManager(SodiumWorldRenderer renderer, ChunkRenderBackend backend, WorldClient world, int renderDistance) { this.backend = backend; this.renderer = renderer; @@ -127,6 +145,18 @@ public ChunkRenderManager(SodiumWorldRenderer renderer, ChunkRenderBackend ba this.translucencyBlockRenderDistance = Math.min(9216, (renderDistance << 4) * (renderDistance << 4)); this.useBlockFaceCulling = SodiumClientMod.options().advanced.useBlockFaceCulling; + + if(AngelicaConfig.enableIris) { + this.chunkRenderListsSwap = new ChunkRenderList[BlockRenderPass.COUNT]; + this.tickableChunksSwap = new ObjectArrayList<>(); + this.visibleTileEntitiesSwap = new ObjectArrayList<>(); + + for (int i = 0; i < this.chunkRenderListsSwap.length; i++) { + this.chunkRenderListsSwap[i] = new ChunkRenderList<>(); + } + + this.dirtySwap = true; + } } public void update(Camera camera, FrustumExtended frustum, int frame, boolean spectator) { @@ -213,13 +243,15 @@ private void checkTranslucencyCameraMoved() { } private void addChunk(ChunkRenderContainer render) { - if (render.needsRebuild() && render.canRebuild()) { + final boolean canRebuild = AngelicaConfig.enableIris ? !ShadowRenderingState.areShadowsCurrentlyBeingRendered() : render.canRebuild(); + + if (render.needsRebuild() && canRebuild) { if (!this.alwaysDeferChunkUpdates && render.needsImportantRebuild()) { this.importantRebuildQueue.enqueue(render); } else { this.rebuildQueue.enqueue(render); } - } else if (render.canRebuild() && !render.getData().isEmpty() && render.needsSort()) { + } else if (canRebuild && !render.getData().isEmpty() && render.needsSort()) { this.sortQueue.enqueue(render); } @@ -264,6 +296,12 @@ private void addChunkToRenderLists(ChunkRenderContainer render) { } private int computeVisibleFaces(ChunkRenderContainer render) { + if(AngelicaConfig.enableIris) { + // TODO: Enable chunk face culling during the shadow pass + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + return(ChunkFaceFlags.ALL); + } + } // If chunk face culling is disabled, render all faces if (!this.useBlockFaceCulling) { return ChunkFaceFlags.ALL; @@ -320,8 +358,10 @@ public ChunkRenderContainer getRender(int x, int y, int z) { } private void reset() { - this.rebuildQueue.clear(); - this.importantRebuildQueue.clear(); + if(!AngelicaConfig.enableIris || !ShadowRenderingState.areShadowsCurrentlyBeingRendered()) this.rebuildQueue.clear(); + if(!AngelicaConfig.enableIris || !ShadowRenderingState.areShadowsCurrentlyBeingRendered()) this.importantRebuildQueue.clear(); + + this.sortQueue.clear(); this.visibleTileEntities.clear(); @@ -487,6 +527,7 @@ public boolean isChunkVisible(int x, int y, int z) { } public void updateChunks() { + if (AngelicaConfig.enableIris && ShadowRenderingState.areShadowsCurrentlyBeingRendered()) return; this.builder.cleanupSectionCache(); Deque>> futures = new ArrayDeque<>(); @@ -634,4 +675,27 @@ public boolean isChunkPrioritized(ChunkRenderContainer render) { public void onChunkRenderUpdates(int x, int y, int z, ChunkRenderData data) { this.culler.onSectionStateChanged(x, y, z, data.getOcclusionData()); } + + // Iris + public void iris$swapVisibilityState() { + ChunkRenderList[] chunkRenderListsTmp = chunkRenderLists; + chunkRenderLists = chunkRenderListsSwap; + chunkRenderListsSwap = chunkRenderListsTmp; + + ObjectList> tickableChunksTmp = tickableChunks; + tickableChunks = tickableChunksSwap; + tickableChunksSwap = tickableChunksTmp; + + ObjectList visibleTileEntitiesTmp = visibleTileEntities; + visibleTileEntities = visibleTileEntitiesSwap; + visibleTileEntitiesSwap = visibleTileEntitiesTmp; + + int visibleChunkCountTmp = visibleChunkCount; + visibleChunkCount = visibleChunkCountSwap; + visibleChunkCountSwap = visibleChunkCountTmp; + + boolean dirtyTmp = dirty; + dirty = dirtySwap; + dirtySwap = dirtyTmp; + } } diff --git a/src/main/java/net/coderbot/iris/sodium/Mixins.txt b/src/main/java/net/coderbot/iris/sodium/Mixins.txt index b04986733..a54428b39 100644 --- a/src/main/java/net/coderbot/iris/sodium/Mixins.txt +++ b/src/main/java/net/coderbot/iris/sodium/Mixins.txt @@ -9,8 +9,8 @@ Y directional_shading * MixinChunkRenderManager.java * shadow_map Y MixinSodiumWorldRenderer.java - * MixinGameRendererContext.java - * MixinChunkRenderManager.java + Y MixinGameRendererContext.java + Y MixinChunkRenderManager.java * block_id Y MixinChunkRenderRebuildTask.java Y MixinChunkBuildBuffers.java From 4da0aa8e31292f361b763fbff9a5f66c4ac2e054 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 1 Dec 2023 20:52:05 -0800 Subject: [PATCH 209/301] Add basic dependency info --- src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index af0c26c71..89938449b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -11,6 +11,7 @@ modid = "angelica", name = "Angelica", version = Tags.VERSION, + dependencies = " before:lwjgl3ify@[1.5.3,);" + " after:hodgepodge@[2.3.35,);", acceptedMinecraftVersions = "[1.7.10]", acceptableRemoteVersions = "*") public class AngelicaMod { From 6dca8caed699c1e237fff51d819f4b29754ecb7f Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 2 Dec 2023 14:04:50 -0800 Subject: [PATCH 210/301] Only when iris is enabled --- .../mods/sodium/client/render/GameRendererContext.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java index 032d8039f..d325f0da3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.render; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.shadows.ShadowRenderingState; import org.joml.Matrix4f; @@ -18,7 +19,7 @@ public class GameRendererContext { // TODO get rid of matrices, it's unnecessary in 1.7 public static FloatBuffer getModelViewProjectionMatrix(MatrixStack.Entry matrices) { final FloatBuffer bufModelViewProjection = BufferUtils.createFloatBuffer(16); - final Matrix4f projectionMatrix = ShadowRenderingState.areShadowsCurrentlyBeingRendered() ? ShadowRenderingState.getShadowOrthoMatrix() : RenderingState.INSTANCE.getProjectionMatrix(); + final Matrix4f projectionMatrix = (AngelicaConfig.enableIris && ShadowRenderingState.areShadowsCurrentlyBeingRendered()) ? ShadowRenderingState.getShadowOrthoMatrix() : RenderingState.INSTANCE.getProjectionMatrix(); final Matrix4f matrix = new Matrix4f(projectionMatrix); matrix.mul(RenderingState.INSTANCE.getModelViewMatrix()); matrix.mul(matrices.getModel()); From 52f33a185873cba0ada289fd3e26e72bd1c17dcd Mon Sep 17 00:00:00 2001 From: Raven Szewczyk Date: Sat, 2 Dec 2023 22:18:41 +0000 Subject: [PATCH 211/301] Fix FontRenderer+SplashScreen combo --- .../angelica/client/font/BatchingFontRenderer.java | 3 ++- .../early/angelica/fontrenderer/MixinFontRenderer.java | 7 +++++++ .../angelica/mixins/interfaces/FontRendererAccessor.java | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java b/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java index 828f69043..7a369b6d0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java @@ -2,6 +2,7 @@ import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.mixins.interfaces.FontRendererAccessor; import it.unimi.dsi.fastutil.chars.Char2ShortOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import jss.util.RandomXoshiro256StarStar; @@ -273,7 +274,7 @@ private void flushBatch() { GLStateManager.disableTexture(); } if (cmd.texture != null) { - renderEngine.bindTexture(cmd.texture); + ((FontRendererAccessor) (Object) underlying).angelica$bindTexture(cmd.texture); } lastTexture = cmd.texture; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java index 9ab15f17c..d767e091f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java @@ -101,6 +101,9 @@ public abstract class MixinFontRenderer implements FontRendererAccessor { @Shadow protected abstract String bidiReorder(String p_147647_1_); + @Shadow + protected abstract void bindTexture(ResourceLocation location); + @Unique public BatchingFontRenderer angelica$batcher; @@ -168,4 +171,8 @@ protected int renderString(String text, int x, int y, int argb, boolean dropShad public BatchingFontRenderer angelica$getBatcher() { return angelica$batcher; } + + @Override + public void angelica$bindTexture(ResourceLocation location) { this.bindTexture(location); } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/FontRendererAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/FontRendererAccessor.java index 9376c6a8c..1a60aae6b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/FontRendererAccessor.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/FontRendererAccessor.java @@ -1,7 +1,10 @@ package com.gtnewhorizons.angelica.mixins.interfaces; import com.gtnewhorizons.angelica.client.font.BatchingFontRenderer; +import net.minecraft.util.ResourceLocation; public interface FontRendererAccessor { BatchingFontRenderer angelica$getBatcher(); + + void angelica$bindTexture(ResourceLocation location); } From 82418476bc4b3f0510d788b5d9f3b44664010c7d Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 2 Dec 2023 15:02:50 -0800 Subject: [PATCH 212/301] HUDCaching tweaks * Add license * Register the events from the angelica clientproxy to avoid registration errors --- README.MD | 2 + .../angelica/hudcaching/HUDCaching.java | 10 +- .../angelica/hudcaching/LICENSE-HUDCaching.md | 175 ++++++++++++++++++ .../angelica/proxy/ClientProxy.java | 5 + .../client/render/pipeline/BlockRenderer.java | 3 +- 5 files changed, 185 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/hudcaching/LICENSE-HUDCaching.md diff --git a/README.MD b/README.MD index 0f438079f..be602ec03 100644 --- a/README.MD +++ b/README.MD @@ -21,5 +21,7 @@ Not yet in an usable state * Embeddedt for [Embeddium](https://github.com/embeddedt/embeddium/commit/dc59ca357c25beefd6288f0d1d40b4cd8e670ab8) under the [LGPL 3.0](https://github.com/embeddedt/embeddium/blob/16.x/forge/LICENSE) * Neodymium * Makamys for [Neodymium](https://github.com/makamys/Neodymium) - Various Tessellator -> Quad functionality taken under the LGPL 3 +* HUDCaching + * Backported from https://github.com/Sk1erLLC/Patcher by Alexdoru under the CC-BY-SA-NC 4.0 license * Angelica * [Insert your name here] for helping get Angelica up and running! diff --git a/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java index af2bf6ef1..855a7c830 100644 --- a/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java +++ b/src/main/java/com/gtnewhorizons/angelica/hudcaching/HUDCaching.java @@ -4,7 +4,6 @@ import com.gtnewhorizons.angelica.glsm.TessellatorManager; import com.gtnewhorizons.angelica.mixins.early.angelica.hudcaching.GuiIngameForgeAccessor; import cpw.mods.fml.client.registry.ClientRegistry; -import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.gameevent.InputEvent; import cpw.mods.fml.common.gameevent.TickEvent; @@ -19,13 +18,12 @@ import net.minecraft.client.shader.Framebuffer; import net.minecraft.util.ChatComponentText; import net.minecraftforge.client.GuiIngameForge; -import net.minecraftforge.common.MinecraftForge; import org.lwjgl.opengl.GL11; import java.util.ArrayList; import java.util.List; -// TODO add license from Sk1er/patcher with special credit to Moulberry https://github.com/Moulberry +// See LICENSE+HUDCaching.md for license information. public class HUDCaching { @@ -33,12 +31,8 @@ public class HUDCaching { public static Framebuffer framebuffer; private static boolean dirty = true; public static boolean renderingCacheOverride; + public static final HUDCaching INSTANCE = new HUDCaching(); - static { - final HUDCaching hudCaching = new HUDCaching(); - FMLCommonHandler.instance().bus().register(hudCaching); - MinecraftForge.EVENT_BUS.register(hudCaching);// TODO remove debug stuff, unsued registration - } private HUDCaching() {} diff --git a/src/main/java/com/gtnewhorizons/angelica/hudcaching/LICENSE-HUDCaching.md b/src/main/java/com/gtnewhorizons/angelica/hudcaching/LICENSE-HUDCaching.md new file mode 100644 index 000000000..883eb6f6e --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/hudcaching/LICENSE-HUDCaching.md @@ -0,0 +1,175 @@ +HUDCaching was backported from https://github.com/Sk1erLLC/Patcher under the following license: + +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International + +Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. + +### Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. + +* __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors). + +* __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees). + +## Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +### Section 1 – Definitions. + +a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. __BY-NC-SA Compatible License__ means a license listed at [creativecommons.org/compatiblelicenses](http://creativecommons.org/compatiblelicenses), approved by Creative Commons as essentially the equivalent of this Public License. + +d. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +e. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +f. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +g. __License Elements__ means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution, NonCommercial, and ShareAlike. + +h. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +i. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +h. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License. + +i. __NonCommercial__ means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +j. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +k. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +l. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +### Section 2 – Scope. + +a. ___License grant.___ + +1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + +2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + +3. __Term.__ The term of this Public License is specified in Section 6(a). + +4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. __Downstream recipients.__ + + A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + B. __Additional offer from the Licensor – Adapted Material.__ Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply. + + C. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. ___Other rights.___ + +1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + +2. Patent and trademark rights are not licensed under this Public License. + +3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +### Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. ___Attribution.___ + +1. If You Share the Licensed Material (including in modified form), You must: + + A. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + +b. ___ShareAlike.___ + +In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + +1. The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC-SA Compatible License. + +2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + +3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +### Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. + +### Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__ + +b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__ + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +### Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + +1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + +2. upon express reinstatement by the Licensor. + +For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +### Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +### Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. + +> Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. +> +> Creative Commons may be contacted at creativecommons.org diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index 8e4cd3670..d57d1a312 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -2,6 +2,7 @@ import com.google.common.base.Objects; import com.gtnewhorizons.angelica.config.AngelicaConfig; +import com.gtnewhorizons.angelica.hudcaching.HUDCaching; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.event.FMLInitializationEvent; @@ -42,6 +43,10 @@ public void init(FMLInitializationEvent event) { @Override public void postInit(FMLInitializationEvent event) { + if(AngelicaConfig.enableHudCaching) { + FMLCommonHandler.instance().bus().register(HUDCaching.INSTANCE); + MinecraftForge.EVENT_BUS.register(HUDCaching.INSTANCE); // TODO remove debug stuff, unused registration} + } if(AngelicaConfig.enableSodium) { MinecraftForge.EVENT_BUS.register(SodiumDebugScreenHandler.INSTANCE); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index f69af446b..83922bea4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -148,8 +148,7 @@ private List tesselatorToBakedQuadList(Tessellator t, BlockPos pos) { return quads; } - private void renderQuadList(BlockPos pos, - ChunkModelBuffers buffers, List quads, ModelQuadFacing facing) { + private void renderQuadList(BlockPos pos, ChunkModelBuffers buffers, List quads, ModelQuadFacing facing) { ModelVertexSink sink = buffers.getSink(facing); sink.ensureCapacity(quads.size() * 4); From e64d5edf741c2d7a6fc1ef288f36b575c676734d Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 2 Dec 2023 23:01:51 -0800 Subject: [PATCH 213/301] Jabba Compat, and reset tesselator state even if the chunk render thread blows up --- dependencies.gradle | 1 + .../gtnewhorizons/angelica/mixins/Mixins.java | 5 +++ .../angelica/mixins/TargetedMod.java | 1 + .../fontrenderer/MixinFontRenderer.java | 2 +- .../mixins/late/compat/MixinJabba.java | 18 ++++++++ .../client/render/pipeline/BlockRenderer.java | 44 +++++-------------- 6 files changed, 37 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinJabba.java diff --git a/dependencies.gradle b/dependencies.gradle index 5ef6e179b..e1436c143 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -65,6 +65,7 @@ dependencies { compileOnly(rfg.deobf("curse.maven:dynamiclights-227874:2337326")) compileOnly("com.github.GTNewHorizons:NotEnoughIds:1.5-pre:dev") // based off https://github.com/GTNewHorizons/NotEnoughIds/pull/2 + compileOnly("com.github.GTNewHorizons:Jabba:1.3.1:dev") // HMMMMM compileOnly(rfg.deobf("curse.maven:journeymap-32274:2367915")) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 0c22f1e37..e28062f68 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -101,6 +101,11 @@ public enum Mixins { ) ), + SODIUM_JABBA_COMPAT(new Builder("Sodium Jabba Compat").addTargetedMod(TargetedMod.JABBA).setSide(Side.CLIENT) + .setPhase(Phase.LATE).setApplyIf(() -> AngelicaConfig.enableSodium) + .addMixinClasses("compat.MixinJabba") + ), + // Required for Sodium's FluidRenderer, so it treats vanilla liquids as IFluidBlocks SODIUM_WISHLIST(new Builder("Sodiumer").addTargetedMod(TargetedMod.VANILLA).setSide(Side.BOTH) .setPhase(Phase.EARLY).setApplyIf(() -> SodiumConfig.ENABLE_FLUID_RENDERER).addMixinClasses( diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java index 90d6a4646..c16039805 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java @@ -11,6 +11,7 @@ public enum TargetedMod { LWJGL3IFY("lwjgl3ify", "me.eigenraven.lwjgl3ify.core.Lwjgl3ifyCoremod", "lwjgl3ify"), CHICKENCHUNKS("ChickenChunks", null, "ChickenChunks"), MRTJPCORE("MrTJPCore", null, "MrTJPCoreMod"), + JABBA("JABBA", null, "JABBA"), BOTANIA("Botania", null, "Botania"), COFHCORE("CoFHCore", "cofh.asm.LoadingPlugin", "CoFHCore"), EXTRAUTILS("ExtraUtilities", null, "ExtraUtilities"), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java index d767e091f..df75a643e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/fontrenderer/MixinFontRenderer.java @@ -163,7 +163,7 @@ public int drawString(String text, int x, int y, int argb, boolean dropShadow) * @reason Replace with more sensible batched rendering and optimize some operations */ @Overwrite - protected int renderString(String text, int x, int y, int argb, boolean dropShadow) { + public int renderString(String text, int x, int y, int argb, boolean dropShadow) { return drawString(text, x, y, argb, dropShadow); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinJabba.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinJabba.java new file mode 100644 index 000000000..b6dbfad35 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinJabba.java @@ -0,0 +1,18 @@ +package com.gtnewhorizons.angelica.mixins.late.compat; + +import mcp.mobius.betterbarrels.client.ClientProxy; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(value = ClientProxy.class, remap = false) +public class MixinJabba { + + /** + * @author mitchej123 + * @reason We're redirecting their renderer so don't blow up + */ + @Overwrite + public void registerRenderers() { + // Do nothing + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index 83922bea4..c7f59352d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -1,22 +1,16 @@ package me.jellysquid.mods.sodium.client.render.pipeline; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.compat.nd.Quad; import com.gtnewhorizons.angelica.compat.nd.RecyclingList; import com.gtnewhorizons.angelica.mixins.interfaces.ITessellatorInstance; -import me.jellysquid.mods.sodium.client.model.light.LightMode; -import me.jellysquid.mods.sodium.client.model.light.LightPipeline; -import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadOrientation; import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; -import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; -import me.jellysquid.mods.sodium.client.util.color.ColorABGR; import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; @@ -52,39 +46,23 @@ public boolean renderModel(IBlockAccess world, Tessellator tessellator, RenderBl boolean rendered = false; -// modelData = model.getModelData(world, pos, state, modelData); + try { + tessellator.startDrawingQuads(); + renderBlocks.renderBlockByRenderType(block, pos.x, pos.y, pos.z); - tessellator.startDrawingQuads(); - renderBlocks.renderBlockByRenderType(block, pos.x, pos.y, pos.z); + this.random.setSeed(seed); -// for (ForgeDirection dir : DirectionUtil.ALL_DIRECTIONS) { -// this.random.setSeed(seed); -// -// List sided = model.getQuads(state, dir, this.random, modelData); -// -// if (sided.isEmpty()) { -// continue; -// } -// -// if (!cull || this.occlusionCache.shouldDrawSide(state, world, pos, dir)) { -// this.renderQuadList(world, state, pos, lighter, offset, buffers, sided, dir); -// -// rendered = true; -// } -// } - - this.random.setSeed(seed); + final List all = tesselatorToBakedQuadList(tessellator, pos); - final List all = tesselatorToBakedQuadList(tessellator, pos); + for (ModelQuadFacing facing : ModelQuadFacing.VALUES) { + this.renderQuadList(pos, buffers, all, facing); + } - for(ModelQuadFacing facing : ModelQuadFacing.VALUES) { - this.renderQuadList(pos, buffers, all, facing); + if (!all.isEmpty()) rendered = true; + } finally { + ((ITessellatorInstance) tessellator).discard(); } - if(!all.isEmpty()) - rendered = true; - - ((ITessellatorInstance) tessellator).discard(); return rendered; } From 7da6e05c098c83effa12b2f26397982448be2249 Mon Sep 17 00:00:00 2001 From: Caedis Date: Sun, 3 Dec 2023 05:37:00 -0600 Subject: [PATCH 214/301] Initial Xaero's World Map + Minimap Support --- .../com/gtnewhorizons/angelica/glsm/GLStateManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 8a3fd6f01..a57d90cc3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -419,6 +419,13 @@ public static void glTexImage2D(int target, int level, int internalformat, int w GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } + public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, long pixels_buffer_offset) { + if (AngelicaConfig.enableIris) { + //TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels != null ? pixels.asIntBuffer() : (IntBuffer) null); + } + GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels_buffer_offset); + } + public static void glDeleteTextures(int id) { if (AngelicaConfig.enableIris) { iris$onDeleteTexture(id); From f69e9656491d9be35aa981cd7bdd7e0ef91c5491 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 3 Dec 2023 09:51:53 -0800 Subject: [PATCH 215/301] Enable missed notfine late mixins --- .../angelica/AngelicaLateMixins.java | 22 +++++ .../angelica/loading/AngelicaLateMixins.java | 90 ------------------- .../gtnewhorizons/angelica/mixins/Mixins.java | 20 ++++- .../angelica/mixins/TargetedMod.java | 33 ++++--- 4 files changed, 59 insertions(+), 106 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/AngelicaLateMixins.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaLateMixins.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaLateMixins.java new file mode 100644 index 000000000..5635a12c7 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaLateMixins.java @@ -0,0 +1,22 @@ +package com.gtnewhorizons.angelica; + +import com.gtnewhorizon.gtnhmixins.ILateMixinLoader; +import com.gtnewhorizon.gtnhmixins.LateMixin; +import com.gtnewhorizons.angelica.mixins.Mixins; + +import java.util.List; +import java.util.Set; + +@LateMixin +public class AngelicaLateMixins implements ILateMixinLoader { + @Override + public String getMixinConfig() { + return "mixins.angelica.late.json"; + } + + @Override + public List getMixins(Set loadedMods) { + return Mixins.getLateMixins(loadedMods); + } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java b/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java deleted file mode 100644 index d04451c00..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/loading/AngelicaLateMixins.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.gtnewhorizons.angelica.loading; - -import com.gtnewhorizon.gtnhmixins.ILateMixinLoader; -import com.gtnewhorizon.gtnhmixins.LateMixin; -import com.gtnewhorizons.angelica.mixins.Mixins; -import com.gtnewhorizons.angelica.mixins.TargetedMod; -import cpw.mods.fml.common.Loader; -import cpw.mods.fml.common.ModContainer; -import cpw.mods.fml.common.versioning.ArtifactVersion; -import cpw.mods.fml.common.versioning.DefaultArtifactVersion; -import cpw.mods.fml.common.versioning.InvalidVersionSpecificationException; -import cpw.mods.fml.common.versioning.VersionRange; -import cpw.mods.fml.relauncher.FMLLaunchHandler; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.coreMods; - -@LateMixin -public class AngelicaLateMixins implements ILateMixinLoader { - - public static final String TWILIGHT_FOREST = "TwilightForest"; - public static final String THAUMCRAFT = "Thaumcraft"; - public static final String WITCHERY = "witchery"; - - @Override - public String getMixinConfig() { - return "mixins.angelica.late.json"; - } - - @Override - public List getMixins(Set loadedMods) { - return Mixins.getLateMixins(loadedMods); - // TODO: Sodium -// mixins.addAll(getNotFineMixins(loadedMods)); -// mixins.addAll(getArchaicMixins(loadedMods)); - } - - private List getNotFineMixins(Set loadedMods) { - if(FMLLaunchHandler.side().isServer()) - return Collections.emptyList(); - - final List mixins = new ArrayList<>(); - - if(loadedMods.contains(THAUMCRAFT)) { - mixins.add("leaves.thaumcraft.MixinBlockMagicalLeaves"); - } - - if(loadedMods.contains(TWILIGHT_FOREST)) { - mixins.add("leaves.twilightforest.MixinBlockTFLeaves"); - mixins.add("leaves.twilightforest.MixinBlockTFLeaves3"); - - //Non-GTNH Twilight Forest builds will break horribly with this mixin. - boolean modernBuild = false; - try { - ArtifactVersion accepted = new DefaultArtifactVersion(TWILIGHT_FOREST, VersionRange.createFromVersionSpec("[2.3.8.18,)")); - ModContainer mc = Loader.instance().getIndexedModList().get(TWILIGHT_FOREST); - if(mc != null) modernBuild = accepted.containsVersion(mc.getProcessedVersion()); - } catch (InvalidVersionSpecificationException ignored) {} - - if(modernBuild) { - mixins.add("leaves.twilightforest.MixinBlockTFMagicLeaves"); - } - } - - if(loadedMods.contains(WITCHERY)) { - mixins.add("leaves.witchery.MixinBlockWitchLeaves"); - } - return mixins; - } - - public List getArchaicMixins(Set loadedMods) { - List mixins = new ArrayList<>(); - Set validMods = new HashSet<>(coreMods); - HashMap modById = new HashMap<>(); - for(TargetedMod t : TargetedMod.values()) { - if(t.getModId() != null) modById.put(t.getModId(), t); - } - for(String modId : loadedMods) { - TargetedMod t = modById.get(modId); - if(t != null) validMods.add(t); - } - return mixins; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index e28062f68..690f5d027 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -138,13 +138,14 @@ public enum Mixins { HUD_CACHING(new Builder("Renders the HUD elements 20 times per second maximum to improve performance") .addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT).setPhase(Phase.EARLY) - .addMixinClasses( + .setApplyIf(() -> AngelicaConfig.enableHudCaching).addMixinClasses( "angelica.hudcaching.GuiIngameForgeAccessor", "angelica.hudcaching.MixinEntityRenderer_HUDCaching", "angelica.hudcaching.MixinFramebuffer_HUDCaching", "angelica.hudcaching.MixinGuiIngame_HUDCaching", "angelica.hudcaching.MixinGuiIngameForge_HUDCaching") - .setApplyIf(() -> AngelicaConfig.enableHudCaching)), + + ), // TODO: Iris // SHADERSMOD_COMPAT_PR_ILLUMINATION( @@ -171,6 +172,21 @@ public enum Mixins { ,"notfine.gui.MixinGuiSlot" ,"notfine.renderer.MixinRenderGlobal" ,"notfine.settings.MixinGameSettings" + )), + NOTFINE_LATE_TWILIGHT_FORESTLEAVES(new Builder("NotFine Mod Leaves").addTargetedMod(TargetedMod.TWILIGHT_FOREST).setSide(Side.CLIENT) + .setPhase(Phase.LATE).setApplyIf(() -> AngelicaConfig.enableNotFineFeatures).addMixinClasses( + "notfine.leaves.twilightforest.MixinBlockTFLeaves" + ,"notfine.leaves.twilightforest.MixinBlockTFLeaves3" + // TODO: Verify 2.3.8.18 or later to support non NH builds? + ,"notfine.leaves.twilightforest.MixinBlockTFMagicLeaves" + )), + NOTFINE_LATE_THAUMCRAFT_LEAVES(new Builder("NotFine Mod Leaves").addTargetedMod(TargetedMod.THAUMCRAFT).setSide(Side.CLIENT) + .setPhase(Phase.LATE).setApplyIf(() -> AngelicaConfig.enableNotFineFeatures).addMixinClasses( + "notfine.leaves.thaumcraft.MixinBlockMagicalLeaves" + )), + NOTFINE_LATE_WITCHERY_LEAVES(new Builder("NotFine Mod Leaves").addTargetedMod(TargetedMod.WITCHERY).setSide(Side.CLIENT) + .setPhase(Phase.LATE).setApplyIf(() -> AngelicaConfig.enableNotFineFeatures).addMixinClasses( + "notfine.leaves.witchery.MixinBlockWitchLeaves" )) ; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java index c16039805..a573a5e88 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java @@ -4,20 +4,25 @@ public enum TargetedMod { - VANILLA("Minecraft", null), - FASTCRAFT("FastCraft", "fastcraft.Tweaker"), - OPTIFINE("Optifine", "optifine.OptiFineForgeTweaker", "Optifine"), - GTNHLIB("GTNHLib", "com.gtnewhorizon.gtnhlib.core.GTNHLibCore", "gtnhlib"), - LWJGL3IFY("lwjgl3ify", "me.eigenraven.lwjgl3ify.core.Lwjgl3ifyCoremod", "lwjgl3ify"), - CHICKENCHUNKS("ChickenChunks", null, "ChickenChunks"), - MRTJPCORE("MrTJPCore", null, "MrTJPCoreMod"), - JABBA("JABBA", null, "JABBA"), - BOTANIA("Botania", null, "Botania"), - COFHCORE("CoFHCore", "cofh.asm.LoadingPlugin", "CoFHCore"), - EXTRAUTILS("ExtraUtilities", null, "ExtraUtilities"), - JOURNEYMAP("JourneyMap", null, "journeymap"), - PROJECTRED_ILLUMINATION("ProjectRed Illumination", null, "ProjRed|Illumination"), - SMART_RENDER("Smart Render", null, "SmartRender"); + VANILLA("Minecraft", null) + , FASTCRAFT("FastCraft", "fastcraft.Tweaker") + , OPTIFINE("Optifine", "optifine.OptiFineForgeTweaker", "Optifine") + , BOTANIA("Botania", null, "Botania") + , CHICKENCHUNKS("ChickenChunks", null, "ChickenChunks") + , COFHCORE("CoFHCore", "cofh.asm.LoadingPlugin", "CoFHCore") + , EXTRAUTILS("ExtraUtilities", null, "ExtraUtilities") + , GTNHLIB("GTNHLib", "com.gtnewhorizon.gtnhlib.core.GTNHLibCore", "gtnhlib") + , JABBA("JABBA", null, "JABBA") + , JOURNEYMAP("JourneyMap", null, "journeymap") + , LWJGL3IFY("lwjgl3ify", "me.eigenraven.lwjgl3ify.core.Lwjgl3ifyCoremod", "lwjgl3ify") + , MRTJPCORE("MrTJPCore", null, "MrTJPCoreMod") + , PROJECTRED_ILLUMINATION("ProjectRed Illumination", null, "ProjRed|Illumination") + , SMART_RENDER("Smart Render", null, "SmartRender") + , THAUMCRAFT("Thaumcraft", null, "Thaumcraft") + , TWILIGHT_FOREST("TwilightForest", null, "TwilightForest") + , WITCHERY("Witchery", null, "witchery") + ; + /** The "name" in the @Mod annotation */ @Getter From acdde9f8ae73db029f89277768680d1327a3fead Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 3 Dec 2023 10:16:48 -0800 Subject: [PATCH 216/301] Add another onTexImage2D overload. * Unclear if needed, but can remove it later if it's not --- .../gtnewhorizons/angelica/glsm/GLStateManager.java | 2 +- .../net/coderbot/iris/texture/TextureInfoCache.java | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index a57d90cc3..122af35d3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -421,7 +421,7 @@ public static void glTexImage2D(int target, int level, int internalformat, int w public static void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, long pixels_buffer_offset) { if (AngelicaConfig.enableIris) { - //TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels != null ? pixels.asIntBuffer() : (IntBuffer) null); + TextureInfoCache.INSTANCE.onTexImage2D(target, level, internalformat, width, height, border, format, type, pixels_buffer_offset); } GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels_buffer_offset); } diff --git a/src/main/java/net/coderbot/iris/texture/TextureInfoCache.java b/src/main/java/net/coderbot/iris/texture/TextureInfoCache.java index 38c25e575..da8a9a974 100644 --- a/src/main/java/net/coderbot/iris/texture/TextureInfoCache.java +++ b/src/main/java/net/coderbot/iris/texture/TextureInfoCache.java @@ -25,8 +25,16 @@ public TextureInfo getInfo(int id) { return info; } - public void onTexImage2D(int target, int level, int internalformat, int width, int height, int border, - int format, int type, @Nullable IntBuffer pixels) { + public void onTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable IntBuffer pixels) { + if (level == 0) { + int id = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + TextureInfo info = getInfo(id); + info.internalFormat = internalformat; + info.width = width; + info.height = height; + } + } + public void onTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, long pixels_buffer_offset) { if (level == 0) { int id = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); TextureInfo info = getInfo(id); From daeb9c2c858c5728906f551425afa0d9b4911c29 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 3 Dec 2023 12:58:01 -0800 Subject: [PATCH 217/301] Disable Fastcraft & Optifine if present --- dependencies.gradle | 2 +- .../loading/MixinCompatHackTweaker.java | 44 ++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index e1436c143..384bc06a9 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -35,7 +35,7 @@ */ dependencies { - api("com.github.GTNewHorizons:Hodgepodge:2.3.35") + api("com.github.GTNewHorizons:Hodgepodge:2.3.37") compileOnly("org.projectlombok:lombok:1.18.22") {transitive = false } annotationProcessor("org.projectlombok:lombok:1.18.22") diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java index 59680db35..a56f62985 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java @@ -1,19 +1,61 @@ package com.gtnewhorizons.angelica.loading; import com.gtnewhorizons.angelica.transform.RedirectorTransformer; +import cpw.mods.fml.common.Loader; +import net.minecraft.launchwrapper.IClassTransformer; import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; import java.io.File; +import java.lang.reflect.Field; import java.util.List; +import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER; public class MixinCompatHackTweaker implements ITweaker { - + public static final boolean DISABLE_OPTIFINE_AND_FASTCRAFT = true; @Override public void acceptOptions(List args, File gameDir, File assetsDir, String profile) { + if(DISABLE_OPTIFINE_AND_FASTCRAFT) { + LOGGER.info("Disabling Optifine and Fastcraft (if present)"); + disableOptifineAndFastcraft(); + } + } + private void disableOptifineAndFastcraft() { + // Remove Optifine and Fastcraft transformers & Mod Containers + try { + LaunchClassLoader lcl = Launch.classLoader; + Field xformersField = lcl.getClass().getDeclaredField("transformers"); + xformersField.setAccessible(true); + @SuppressWarnings("unchecked") + List xformers = (List) xformersField.get(lcl); + for (int idx = xformers.size() - 1; idx >= 0; idx--) { + final String name = xformers.get(idx).getClass().getName(); + if (name.startsWith("optifine") || name.startsWith("fastcraft")) { + LOGGER.info("Removing transformer " + name); + xformers.remove(idx); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + try { + Field injectedContainersField = Loader.class.getDeclaredField("injectedContainers"); + injectedContainersField.setAccessible(true); + @SuppressWarnings("unchecked") + List containers = (List ) injectedContainersField.get(Loader.class); + for (int idx = containers.size() - 1; idx >= 0; idx--) { + final String name = containers.get(idx); + if (name.startsWith("optifine") || name.startsWith("fastcraft")) { + LOGGER.info("Removing mod container " + name); + containers.remove(idx); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } } @Override From 104ba4bff46cf8b650774fcceae17ef77730dee8 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 3 Dec 2023 19:56:51 -0800 Subject: [PATCH 218/301] Non working Iris WIP --- .../angelica/compat/mojang/Camera.java | 6 +- .../angelica/glsm/GLStateManager.java | 8 +- .../early/shaders/MixinEntityRenderer.java | 19 ++- .../early/sodium/MixinRenderGlobal.java | 20 ++- .../client/gl/attribute/GlVertexFormat.java | 12 +- .../sodium/client/gl/shader/ShaderLoader.java | 2 +- .../sodium/client/gl/shader/ShaderType.java | 4 +- .../client/render/SodiumWorldRenderer.java | 6 +- .../render/chunk/ChunkRenderBackend.java | 3 + .../render/chunk/ChunkRenderManager.java | 3 +- .../MultidrawChunkRenderBackend.java | 36 ++++- .../oneshot/ChunkOneshotGraphicsState.java | 32 +++- .../chunk/format/ChunkMeshAttribute.java | 8 +- .../chunk/format/hfp/HFPModelVertexType.java | 11 +- .../chunk/format/sfp/SFPModelVertexType.java | 1 - .../render/chunk/shader/ChunkProgram.java | 10 +- .../shader/ChunkRenderShaderBackend.java | 143 ++++++++++++++++-- .../DeferredWorldRenderingPipeline.java | 8 +- .../FixedFunctionWorldRenderingPipeline.java | 6 +- .../coderbot/iris/pipeline/HandRenderer.java | 25 +-- .../iris/pipeline/ShadowRenderer.java | 34 +++-- .../iris/pipeline/WorldRenderingPipeline.java | 4 +- .../java/net/coderbot/iris/sodium/Mixins.txt | 24 +-- .../IrisChunkMeshAttributes.java | 14 -- .../terrain_xhfp/XHFPModelVertexType.java | 11 +- 25 files changed, 335 insertions(+), 115 deletions(-) delete mode 100644 src/main/java/net/coderbot/iris/sodium/vertex_format/IrisChunkMeshAttributes.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java index 5287aaca7..49fb42d7d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java @@ -18,17 +18,19 @@ public class Camera { float yaw; EntityLivingBase entity; boolean thirdPerson; + final float partialTicks; public Camera(EntityLivingBase entity, float partialTicks) { + this.partialTicks = partialTicks; 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; - + pos.set(camX, camY, camZ); blockPos.set((int)entity.posX, (int)entity.posY, (int)entity.posZ); pitch = entity.cameraPitch; diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 122af35d3..920688fc3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -18,6 +18,7 @@ import net.coderbot.iris.gl.blending.DepthColorStorage; import net.coderbot.iris.gl.sampler.SamplerLimits; import net.coderbot.iris.gl.state.StateUpdateNotifiers; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.coderbot.iris.samplers.IrisSamplers; import net.coderbot.iris.texture.TextureInfoCache; import net.coderbot.iris.texture.TextureTracker; @@ -503,8 +504,13 @@ public static void setFilter(boolean bilinear, boolean mipmap) { public static void glDrawArrays(int mode, int first, int count) { // Iris -- TODO: This doesn't seem to work and is related to matchPass() - // Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram); + Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram); GL11.glDrawArrays(mode, first, count); + // Temporary + int error = GL11.glGetError(); + if(error != GL11.GL_NO_ERROR) { + throw new RuntimeException("glDrawArrays error: " + error); + } } public static void defaultBlendFunc() { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index 7e44c7877..57c3b64fb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.shaders; +import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalRef; import net.coderbot.iris.Iris; @@ -9,16 +10,17 @@ import net.coderbot.iris.uniforms.SystemTimeUniforms; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.resources.IResourceManagerReloadListener; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(EntityRenderer.class) -public class MixinEntityRenderer { - @Inject(at = @At("HEAD"), method = "renderWorld(FJ)V") - private void iris$beginRender(float tickDelta, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { - CapturedRenderingState.INSTANCE.setTickDelta(tickDelta); +public abstract class MixinEntityRenderer implements IResourceManagerReloadListener { + @Inject(at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", args = "ldc=frustrum", shift = At.Shift.AFTER), method = "renderWorld(FJ)V") + private void iris$beginRender(float partialTicks, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + CapturedRenderingState.INSTANCE.setTickDelta(partialTicks); SystemTimeUniforms.COUNTER.beginFrame(); SystemTimeUniforms.TIMER.beginFrame(startTime); @@ -30,7 +32,7 @@ public class MixinEntityRenderer { } @Inject(method = "renderWorld(FJ)V", at = @At(value = "RETURN", shift = At.Shift.BEFORE)) - private void iris$endLevelRender(float tickDelta, long limitTime, CallbackInfo callback, @Share("pipeline") LocalRef pipeline) { + private void iris$endLevelRender(float partialTicks, long limitTime, CallbackInfo callback, @Share("pipeline") LocalRef pipeline) { // TODO: Iris // HandRenderer.INSTANCE.renderTranslucent(poseStack, tickDelta, camera, gameRenderer, pipeline); Minecraft.getMinecraft().mcProfiler.endStartSection("iris_final"); @@ -39,4 +41,11 @@ public class MixinEntityRenderer { Program.unbind(); } + @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 pipeline) { + final Minecraft mc = Minecraft.getMinecraft(); + Camera camera = new Camera(mc.renderViewEntity, partialTicks); + pipeline.get().renderShadows((EntityRenderer) (Object) this, camera); + } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 0f2dc79e1..640f955df 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -1,14 +1,17 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; -import com.google.common.collect.ImmutableList; import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; +import lombok.Getter; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import net.coderbot.iris.Iris; +import net.coderbot.iris.pipeline.HandRenderer; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.client.multiplayer.WorldClient; @@ -32,8 +35,6 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.List; - import static org.joml.Math.lerp; // Let other mixins apply, and then overwrite them @@ -48,6 +49,7 @@ public class MixinRenderGlobal implements IRenderGlobalExt { @Shadow public WorldRenderer[] worldRenderers; @Shadow public WorldRenderer[] sortedWorldRenderers; + @Getter @Unique private SodiumWorldRenderer renderer; private int sodium$frame; @@ -137,6 +139,16 @@ public boolean updateRenderers(EntityLivingBase e, boolean b){ */ @Overwrite public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) { + if(AngelicaConfig.enableIris && pass == 1) { + final Camera camera = new Camera(mc.renderViewEntity, (float)partialTicks); + final WorldRenderingPipeline pipeline = Iris.getPipelineManager().preparePipeline(Iris.getCurrentDimension()); + + // iris$beginTranslucents + pipeline.beginHand(); + HandRenderer.INSTANCE.renderSolid(null /*poseStack*/, (float)partialTicks, camera, null /*gameRenderer*/, pipeline); + mc.mcProfiler.endStartSection("iris_pre_translucent"); + pipeline.beginTranslucents(); + } // Handle view distance change if(this.renderDistanceChunks != this.mc.gameSettings.renderDistanceChunks) { this.loadRenderers(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexFormat.java index 55b1d1028..93465e1d0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexFormat.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/GlVertexFormat.java @@ -1,5 +1,7 @@ package me.jellysquid.mods.sodium.client.gl.attribute; +import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; + import java.util.EnumMap; /** @@ -9,6 +11,9 @@ * @param The enumeration over the vertex attributes */ public class GlVertexFormat> implements BufferVertexFormat { + // Iris + private static final GlVertexAttribute EMPTY = new GlVertexAttribute(GlVertexAttributeFormat.FLOAT, 0, false, 0, 0); + private final Class attributeEnum; private final EnumMap attributesKeyed; private final GlVertexAttribute[] attributesArray; @@ -105,7 +110,12 @@ public GlVertexFormat build() { GlVertexAttribute attribute = this.attributes.get(key); if (attribute == null) { - throw new NullPointerException("Generic attribute not assigned to enumeration " + key.name()); + if(key == ChunkMeshAttribute.NORMAL || key == ChunkMeshAttribute.TANGENT || key == ChunkMeshAttribute.MID_TEX_COORD || key == ChunkMeshAttribute.BLOCK_ID || key == ChunkMeshAttribute.MID_BLOCK) { + // Missing these attributes is acceptable and will be handled properly. + attribute = EMPTY; + } else { + throw new NullPointerException("Generic attribute not assigned to enumeration " + key.name()); + } } size = Math.max(size, attribute.getPointer() + attribute.getSize()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java index c637d5b81..eca711854 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderLoader.java @@ -34,7 +34,7 @@ public static GlShader loadShader(RenderDevice device, ShaderType type, Resource return new GlShader(device, type, name, getShaderSource(getShaderPath(name, type)), ShaderConstants.fromStringList(constants)); } - private static String getShaderPath(ResourceLocation name, ShaderType type) { + public static String getShaderPath(ResourceLocation name, ShaderType type) { return String.format("/assets/%s/shaders/%s.%s.glsl", name.getResourceDomain(), name.getResourcePath(), type == ShaderType.VERTEX ? "v" : "f"); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java index 9b4889b7d..23d16313b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/shader/ShaderType.java @@ -1,13 +1,15 @@ package me.jellysquid.mods.sodium.client.gl.shader; import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL32; /** * An enumeration over the supported OpenGL shader types. */ public enum ShaderType { VERTEX(GL20.GL_VERTEX_SHADER), - FRAGMENT(GL20.GL_FRAGMENT_SHADER); + FRAGMENT(GL20.GL_FRAGMENT_SHADER), + GEOMETRY(GL32.GL_GEOMETRY_SHADER); public final int id; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index fca82c4ee..3c9f30ce5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -26,9 +26,11 @@ import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.client.world.ChunkStatusListener; import me.jellysquid.mods.sodium.common.util.ListUtil; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.coderbot.iris.pipeline.ShadowRenderer; import net.coderbot.iris.shadows.ShadowRenderingState; import net.coderbot.iris.sodium.shadow_map.SwappableChunkRenderManager; +import net.coderbot.iris.sodium.vertex_format.IrisModelVertexFormats; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.WorldRenderer; @@ -286,7 +288,9 @@ private void initRenderer() { final ChunkVertexType vertexFormat; - if (opts.advanced.useCompactVertexFormat) { + if(AngelicaConfig.enableIris && BlockRenderingSettings.INSTANCE.shouldUseExtendedVertexFormat()) { + vertexFormat = IrisModelVertexFormats.MODEL_VERTEX_XHFP; + } else if (opts.advanced.useCompactVertexFormat) { vertexFormat = DefaultModelVertexFormats.MODEL_VERTEX_HFP; } else { vertexFormat = DefaultModelVertexFormats.MODEL_VERTEX_SFP; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java index 1880b76d5..8472ebc9d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java @@ -6,6 +6,7 @@ import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildResult; import me.jellysquid.mods.sodium.client.render.chunk.lists.ChunkRenderListIterator; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import java.util.Collections; import java.util.Iterator; @@ -56,4 +57,6 @@ default String getRendererName() { default List getDebugStrings() { return Collections.emptyList(); } + + void iris$begin(MatrixStack matrixStack, BlockRenderPass pass); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 4c4259283..21e201600 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -504,8 +504,9 @@ public void renderLayer(MatrixStack matrixStack, BlockRenderPass pass, double x, RenderDevice device = RenderDevice.INSTANCE; CommandList commandList = device.createCommandList(); + if(AngelicaConfig.enableIris) this.backend.iris$begin(matrixStack, pass); + else this.backend.begin(matrixStack); - this.backend.begin(matrixStack); // Ensure multidraw regions are ordered appropriately if(this.backend instanceof MultidrawChunkRenderBackend) { ((MultidrawChunkRenderBackend) this.backend).setReverseRegions(pass.isTranslucent()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java index 41d02175c..c268e2650 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import it.unimi.dsi.fastutil.objects.ObjectArrayFIFOQueue; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import me.jellysquid.mods.sodium.client.gl.arena.GlBufferArena; @@ -34,6 +35,8 @@ import me.jellysquid.mods.sodium.client.render.chunk.region.ChunkRegionManager; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkRenderShaderBackend; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderBindingPoints; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; +import net.coderbot.iris.sodium.IrisChunkShaderBindingPoints; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.Util; import org.lwjgl.opengl.GL11; @@ -184,19 +187,36 @@ public void upload(CommandList commandList, Iterator vertexFormat = (GlVertexFormat) vertexData.format; this.tessellation = commandList.createTessellation(GlPrimitiveType.QUADS, new TessellationBinding[] { - new TessellationBinding(this.vertexBuffer, new GlVertexAttributeBinding[] { - new GlVertexAttributeBinding(ChunkShaderBindingPoints.POSITION, vertexFormat.getAttribute(ChunkMeshAttribute.POSITION)), - new GlVertexAttributeBinding(ChunkShaderBindingPoints.COLOR, vertexFormat.getAttribute(ChunkMeshAttribute.COLOR)), - new GlVertexAttributeBinding(ChunkShaderBindingPoints.TEX_COORD, vertexFormat.getAttribute(ChunkMeshAttribute.TEXTURE)), - new GlVertexAttributeBinding(ChunkShaderBindingPoints.LIGHT_COORD, vertexFormat.getAttribute(ChunkMeshAttribute.LIGHT)) - }, false) + new TessellationBinding(this.vertexBuffer, getBindings(vertexFormat), false) }); this.setupModelParts(meshData, vertexData.format); @@ -86,4 +84,26 @@ public void upload(CommandList commandList, ChunkMeshData meshData) { vertexData.buffer.position(0); this.setTranslucencyData(vertexData.buffer); } + + private GlVertexAttributeBinding[] getBindings(GlVertexFormat vertexFormat) { + if(AngelicaConfig.enableIris && BlockRenderingSettings.INSTANCE.shouldUseExtendedVertexFormat()) { + return new GlVertexAttributeBinding[] { + new GlVertexAttributeBinding(ChunkShaderBindingPoints.POSITION, vertexFormat.getAttribute(ChunkMeshAttribute.POSITION)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.COLOR, vertexFormat.getAttribute(ChunkMeshAttribute.COLOR)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.TEX_COORD, vertexFormat.getAttribute(ChunkMeshAttribute.TEXTURE)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.LIGHT_COORD, vertexFormat.getAttribute(ChunkMeshAttribute.LIGHT)), + new GlVertexAttributeBinding(IrisChunkShaderBindingPoints.BLOCK_ID, vertexFormat.getAttribute(ChunkMeshAttribute.BLOCK_ID)), + new GlVertexAttributeBinding(IrisChunkShaderBindingPoints.MID_TEX_COORD, vertexFormat.getAttribute(ChunkMeshAttribute.MID_TEX_COORD)), + new GlVertexAttributeBinding(IrisChunkShaderBindingPoints.TANGENT, vertexFormat.getAttribute(ChunkMeshAttribute.TANGENT)), + new GlVertexAttributeBinding(IrisChunkShaderBindingPoints.NORMAL, vertexFormat.getAttribute(ChunkMeshAttribute.NORMAL)) + }; + } else { + return new GlVertexAttributeBinding[] { + new GlVertexAttributeBinding(ChunkShaderBindingPoints.POSITION, vertexFormat.getAttribute(ChunkMeshAttribute.POSITION)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.COLOR, vertexFormat.getAttribute(ChunkMeshAttribute.COLOR)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.TEX_COORD, vertexFormat.getAttribute(ChunkMeshAttribute.TEXTURE)), + new GlVertexAttributeBinding(ChunkShaderBindingPoints.LIGHT_COORD, vertexFormat.getAttribute(ChunkMeshAttribute.LIGHT)) }; + } + } + } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkMeshAttribute.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkMeshAttribute.java index 75df244b8..1a4d572aa 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkMeshAttribute.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/ChunkMeshAttribute.java @@ -4,5 +4,11 @@ public enum ChunkMeshAttribute { POSITION, COLOR, TEXTURE, - LIGHT + LIGHT, + // Iris + NORMAL, + TANGENT, + MID_TEX_COORD, + BLOCK_ID, + MID_BLOCK } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java index 22355e26f..28eb51845 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java @@ -8,7 +8,7 @@ import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; - +import net.coderbot.iris.sodium.vertex_format.IrisGlVertexAttributeFormat; /** * Uses half-precision floating point numbers to represent position coordinates and normalized unsigned shorts for @@ -16,12 +16,19 @@ * their centering offset), as the */ public class HFPModelVertexType implements ChunkVertexType { + // TODO Iris? + public static final int STRIDE = 44; // 20 public static final GlVertexFormat VERTEX_FORMAT = - GlVertexFormat.builder(ChunkMeshAttribute.class, 20) + GlVertexFormat.builder(ChunkMeshAttribute.class, STRIDE) .addElement(ChunkMeshAttribute.POSITION, 0, GlVertexAttributeFormat.UNSIGNED_SHORT, 3, false) .addElement(ChunkMeshAttribute.COLOR, 8, GlVertexAttributeFormat.UNSIGNED_BYTE, 4, true) .addElement(ChunkMeshAttribute.TEXTURE, 12, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, false) .addElement(ChunkMeshAttribute.LIGHT, 16, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, true) + .addElement(ChunkMeshAttribute.MID_TEX_COORD, 20, GlVertexAttributeFormat.FLOAT, 2, false) + .addElement(ChunkMeshAttribute.TANGENT, 28, IrisGlVertexAttributeFormat.BYTE, 4, true) + .addElement(ChunkMeshAttribute.NORMAL, 32, IrisGlVertexAttributeFormat.BYTE, 3, true) + .addElement(ChunkMeshAttribute.BLOCK_ID, 36, IrisGlVertexAttributeFormat.SHORT, 2, false) + .addElement(ChunkMeshAttribute.MID_BLOCK, 40, IrisGlVertexAttributeFormat.BYTE, 3, false) .build(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java index 984f1640d..b778e54ea 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java @@ -9,7 +9,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; - /** * Simple vertex format which uses single-precision floating point numbers to represent position and texture * coordinates. diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java index 07d2ec44c..b622a2310 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java @@ -39,14 +39,14 @@ protected ChunkProgram(RenderDevice owner, ResourceLocation name, int handle, Fu } public void setup(MatrixStack matrixStack, float modelScale, float textureScale) { - GL20.glUniform1i(this.uBlockTex, OpenGlHelper.defaultTexUnit - GL13.GL_TEXTURE0); - GL20.glUniform1i(this.uLightTex, OpenGlHelper.lightmapTexUnit - GL13.GL_TEXTURE0); + if(this.uBlockTex != -1) GL20.glUniform1i(this.uBlockTex, OpenGlHelper.defaultTexUnit - GL13.GL_TEXTURE0); + if(this.uLightTex != -1) GL20.glUniform1i(this.uLightTex, OpenGlHelper.lightmapTexUnit - GL13.GL_TEXTURE0); - GL20.glUniform3f(this.uModelScale, modelScale, modelScale, modelScale); - GL20.glUniform2f(this.uTextureScale, textureScale, textureScale); + if(this.uModelScale != -1) GL20.glUniform3f(this.uModelScale, modelScale, modelScale, modelScale); + if(this.uTextureScale != -1) GL20.glUniform2f(this.uTextureScale, textureScale, textureScale); this.fogShader.setup(); - GL20.glUniformMatrix4(this.uModelViewProjectionMatrix, false, GameRendererContext.getModelViewProjectionMatrix(matrixStack.peek())); + if(this.uModelViewProjectionMatrix != -1) GL20.glUniformMatrix4(this.uModelViewProjectionMatrix, false, GameRendererContext.getModelViewProjectionMatrix(matrixStack.peek())); } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java index f88773b61..79a8b8c1f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java @@ -1,22 +1,42 @@ package me.jellysquid.mods.sodium.client.render.chunk.shader; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.config.AngelicaConfig; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; import me.jellysquid.mods.sodium.client.gl.compat.FogHelper; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; import me.jellysquid.mods.sodium.client.gl.shader.GlShader; +import me.jellysquid.mods.sodium.client.gl.shader.ShaderConstants; import me.jellysquid.mods.sodium.client.gl.shader.ShaderLoader; import me.jellysquid.mods.sodium.client.gl.shader.ShaderType; import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; 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.format.ChunkMeshAttribute; +import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.program.ProgramSamplers; +import net.coderbot.iris.gl.program.ProgramUniforms; +import net.coderbot.iris.pipeline.SodiumTerrainPipeline; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.coderbot.iris.shaderpack.transform.StringTransformations; +import net.coderbot.iris.shaderpack.transform.Transformations; +import net.coderbot.iris.shadows.ShadowRenderingState; +import net.coderbot.iris.sodium.shader_overrides.IrisChunkProgramOverrides; +import net.coderbot.iris.sodium.vertex_format.IrisModelVertexFormats; import net.minecraft.util.ResourceLocation; +import org.apache.commons.io.IOUtils; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.EnumMap; +import java.util.List; public abstract class ChunkRenderShaderBackend implements ChunkRenderBackend { + private final EnumMap programs = new EnumMap<>(ChunkFogMode.class); protected final ChunkVertexType vertexType; @@ -24,32 +44,111 @@ public abstract class ChunkRenderShaderBackend imp protected ChunkProgram activeProgram; + // Iris + private IrisChunkProgramOverrides irisChunkProgramOverrides; + + private RenderDevice device; + + private ChunkProgram override; + public ChunkRenderShaderBackend(ChunkVertexType vertexType) { + if (AngelicaConfig.enableIris) { + irisChunkProgramOverrides = new IrisChunkProgramOverrides(); + } + this.vertexType = vertexType; this.vertexFormat = vertexType.getCustomVertexFormat(); } + public GlShader loadShaderRedirect(RenderDevice device, ShaderType type, ResourceLocation name, List constants) { + if (AngelicaConfig.enableIris && this.vertexType == IrisModelVertexFormats.MODEL_VERTEX_XHFP) { + String shader = getShaderSource(ShaderLoader.getShaderPath(name, type)); + shader = shader.replace("v_LightCoord = a_LightCoord", "v_LightCoord = (iris_LightmapTextureMatrix * vec4(a_LightCoord, 0, 1)).xy"); + + StringTransformations transformations = new StringTransformations(shader); + + transformations.injectLine( + Transformations.InjectionPoint.BEFORE_CODE, + "mat4 iris_LightmapTextureMatrix = mat4(vec4(0.00390625, 0.0, 0.0, 0.0), vec4(0.0, 0.00390625, 0.0, 0.0), vec4(0.0, 0.0, 0.00390625, 0.0), vec4(0.03125, 0.03125, 0.03125, 1.0));"); + + return new GlShader(device, type, name, transformations.toString(), ShaderConstants.fromStringList(constants)); + } else { + return ShaderLoader.loadShader(device, type, name, constants); + } + } + private ChunkProgram createShader(RenderDevice device, ChunkFogMode fogMode, GlVertexFormat vertexFormat) { - GlShader vertShader = ShaderLoader.loadShader(device, ShaderType.VERTEX, new ResourceLocation("sodium", "chunk_gl20"), fogMode.getDefines()); + if(AngelicaConfig.enableIris) { + this.device = device; + WorldRenderingPipeline worldRenderingPipeline = Iris.getPipelineManager().getPipelineNullable(); + SodiumTerrainPipeline sodiumTerrainPipeline = null; + + if (worldRenderingPipeline != null) { + sodiumTerrainPipeline = worldRenderingPipeline.getSodiumTerrainPipeline(); + } + + irisChunkProgramOverrides.createShaders(sodiumTerrainPipeline, device); + } + + GlShader vertShader = loadShaderRedirect(device, ShaderType.VERTEX, new ResourceLocation("sodium", "chunk_gl20"), fogMode.getDefines()); GlShader fragShader = ShaderLoader.loadShader(device, ShaderType.FRAGMENT, new ResourceLocation("sodium", "chunk_gl20"), fogMode.getDefines()); try { return GlProgram.builder(new ResourceLocation("sodium", "chunk_shader")) - .attachShader(vertShader) - .attachShader(fragShader) - .bindAttribute("a_Pos", ChunkShaderBindingPoints.POSITION) - .bindAttribute("a_Color", ChunkShaderBindingPoints.COLOR) - .bindAttribute("a_TexCoord", ChunkShaderBindingPoints.TEX_COORD) - .bindAttribute("a_LightCoord", ChunkShaderBindingPoints.LIGHT_COORD) - .bindAttribute("d_ModelOffset", ChunkShaderBindingPoints.MODEL_OFFSET) - .build((program, name) -> new ChunkProgram(device, program, name, fogMode.getFactory())); + .attachShader(vertShader) + .attachShader(fragShader) + .bindAttribute("a_Pos", ChunkShaderBindingPoints.POSITION) + .bindAttribute("a_Color", ChunkShaderBindingPoints.COLOR) + .bindAttribute("a_TexCoord", ChunkShaderBindingPoints.TEX_COORD) + .bindAttribute("a_LightCoord", ChunkShaderBindingPoints.LIGHT_COORD) + .bindAttribute("d_ModelOffset", ChunkShaderBindingPoints.MODEL_OFFSET) + .build((program, name) -> new ChunkProgram(device, program, name, fogMode.getFactory())); } finally { vertShader.delete(); fragShader.delete(); } } + + + private static String getShaderSource(String path) { + try { + InputStream in = ShaderLoader.class.getResourceAsStream(path); + Throwable throwable = null; + + String res; + try { + if (in == null) { + throw new RuntimeException("Shader not found: " + path); + } + + res = IOUtils.toString(in, StandardCharsets.UTF_8); + } catch (Throwable tr) { + throwable = tr; + throw tr; + } finally { + if (in != null) { + if (throwable != null) { + try { + in.close(); + } catch (Throwable var12) { + throwable.addSuppressed(var12); + } + } else { + in.close(); + } + } + + } + + return res; + } catch (IOException e) { + throw new RuntimeException("Could not read shader sources", e); + } + } + + @Override public final void createShaders(RenderDevice device) { this.programs.put(ChunkFogMode.NONE, this.createShader(device, ChunkFogMode.NONE, this.vertexFormat)); @@ -60,6 +159,9 @@ public final void createShaders(RenderDevice device) { @Override public void begin(MatrixStack matrixStack) { this.activeProgram = this.programs.get(FogHelper.getFogMode()); + if (AngelicaConfig.enableIris && override != null) { + this.activeProgram = override; + } this.activeProgram.bind(); this.activeProgram.setup(matrixStack, this.vertexType.getModelScale(), this.vertexType.getTextureScale()); } @@ -68,10 +170,18 @@ public void begin(MatrixStack matrixStack) { public void end(MatrixStack matrixStack) { this.activeProgram.unbind(); this.activeProgram = null; + if(AngelicaConfig.enableIris) { + ProgramUniforms.clearActiveUniforms(); + ProgramSamplers.clearActiveSamplers(); + Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::endSodiumTerrainRendering); + } } @Override public void delete() { + if(AngelicaConfig.enableIris) { + irisChunkProgramOverrides.deleteShaders(); + } for (ChunkProgram shader : this.programs.values()) { shader.delete(); } @@ -81,4 +191,19 @@ public void delete() { public ChunkVertexType getVertexType() { return this.vertexType; } + + // Iris + public void iris$begin(MatrixStack matrixStack, BlockRenderPass pass) { + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) { + // No back face culling during the shadow pass + // TODO: Hopefully this won't be necessary in the future... + GLStateManager.disableCull(); + } + + this.override = irisChunkProgramOverrides.getProgramOverride(device, pass); + + Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::beginSodiumTerrainRendering); + begin(matrixStack); + } + } diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 03ec7e096..71bc54642 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Ints; import com.gtnewhorizons.angelica.compat.mojang.Camera; -import com.gtnewhorizons.angelica.compat.mojang.LevelRenderer; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.Iris; @@ -58,6 +57,7 @@ import net.coderbot.iris.uniforms.CommonUniforms; import net.coderbot.iris.uniforms.FrameUpdateNotifier; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.shader.Framebuffer; @@ -739,8 +739,8 @@ public void use() { if (shadowViewport) { GL11.glViewport(0, 0, shadowMapResolution, shadowMapResolution); } else { - final Minecraft mc = Minecraft.getMinecraft(); - GL11.glViewport(0, 0, mc.displayWidth, mc.displayHeight); + final Framebuffer main = Minecraft.getMinecraft().getFramebuffer(); // FBO? + GL11.glViewport(0, 0, main.framebufferWidth, main.framebufferHeight); } if (program != null && !sodiumTerrainRendering) { @@ -1019,7 +1019,7 @@ public void beginTranslucents() { } @Override - public void renderShadows(LevelRenderer levelRenderer, Camera playerCamera) { + public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { if (shouldRenderPrepareBeforeShadow) { isRenderingFullScreenPass = true; diff --git a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java index 62cd5e51d..efb429135 100644 --- a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java @@ -1,14 +1,14 @@ package net.coderbot.iris.pipeline; -import net.coderbot.iris.block_rendering.BlockRenderingSettings; import com.gtnewhorizons.angelica.compat.mojang.Camera; -import com.gtnewhorizons.angelica.compat.mojang.LevelRenderer; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; import net.coderbot.iris.shaderpack.CloudSetting; import net.coderbot.iris.uniforms.FrameUpdateNotifier; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.EntityRenderer; import org.lwjgl.opengl.GL20; import java.util.List; @@ -31,7 +31,7 @@ public void beginLevelRendering() { } @Override - public void renderShadows(LevelRenderer levelRenderer, Camera camera) { + public void renderShadows(EntityRenderer levelRenderer, Camera camera) { // stub: nothing to do here } diff --git a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java index 16690d66c..320d4f0af 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java @@ -46,14 +46,16 @@ private void setupGlState(GameRenderer gameRenderer, Camera camera, MatrixStack } private boolean canRender(Camera camera, GameRenderer gameRenderer) { - return !(!gameRenderer.getRenderHand() - || camera.isThirdPerson() - || !(camera.getEntity() instanceof EntityPlayer) - || gameRenderer.getPanoramicMode() - || Minecraft.getMinecraft().gameSettings.hideGUI - || (camera.getEntity() instanceof EntityLiving && ((EntityLiving)camera.getEntity()).isPlayerSleeping()) - // TODO: SPECTATOR - /*|| Minecraft.getMinecraft().gameMode.getPlayerMode() == GameType.SPECTATOR*/); + return (camera.isThirdPerson() || !(camera.getEntity() instanceof EntityPlayer) || Minecraft.getMinecraft().gameSettings.hideGUI || (camera.getEntity() instanceof EntityLiving && ((EntityLiving)camera.getEntity()).isPlayerSleeping())); + +// return !(!gameRenderer.getRenderHand() +// || camera.isThirdPerson() +// || !(camera.getEntity() instanceof EntityPlayer) +// || gameRenderer.getPanoramicMode() +// || Minecraft.getMinecraft().gameSettings.hideGUI +// || (camera.getEntity() instanceof EntityLiving && ((EntityLiving)camera.getEntity()).isPlayerSleeping()) +// // TODO: SPECTATOR +// /*|| Minecraft.getMinecraft().gameMode.getPlayerMode() == GameType.SPECTATOR*/); } public boolean isHandTranslucent(InteractionHand hand) { @@ -83,11 +85,12 @@ public void renderSolid(MatrixStack poseStack, float tickDelta, Camera camera, G pipeline.setPhase(WorldRenderingPhase.HAND_SOLID); - poseStack.push(); +// poseStack.push(); Minecraft.getMinecraft().mcProfiler.startSection("iris_hand"); - setupGlState(gameRenderer, camera, poseStack, tickDelta); + // TODO: Iris +// setupGlState(gameRenderer, camera, poseStack, tickDelta); renderingSolid = true; // TODO: Hand @@ -98,7 +101,7 @@ public void renderSolid(MatrixStack poseStack, float tickDelta, Camera camera, G // TODO: ProjectionMatrix // gameRenderer.resetProjectionMatrix(CapturedRenderingState.INSTANCE.getGbufferProjection()); - poseStack.pop(); +// poseStack.pop(); bufferSource.endBatch(); diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 65c05eea7..40bf07b91 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -1,18 +1,16 @@ package net.coderbot.iris.pipeline; import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.angelica.compat.mojang.BufferSource; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.mojang.RenderBuffers; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.batchedentityrendering.impl.BatchingDebugMessageHelper; import net.coderbot.batchedentityrendering.impl.DrawCallTrackingRenderBuffers; import net.coderbot.batchedentityrendering.impl.RenderBuffersExt; import net.coderbot.iris.Iris; -import com.gtnewhorizons.angelica.compat.mojang.BufferSource; -import com.gtnewhorizons.angelica.compat.mojang.Camera; -import com.gtnewhorizons.angelica.compat.mojang.LevelRenderer; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; -import com.gtnewhorizons.angelica.compat.mojang.RenderBuffers; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.shaderpack.OptionalBoolean; import net.coderbot.iris.shaderpack.PackDirectives; @@ -33,6 +31,8 @@ import net.coderbot.iris.uniforms.CelestialUniforms; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.entity.Entity; import net.minecraft.profiler.Profiler; @@ -348,7 +348,7 @@ private void copyPreTranslucentDepth() { targets.copyPreTranslucentDepth(); } - private void renderEntities(LevelRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { + private void renderEntities(EntityRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { // TODO: Render // EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); @@ -387,7 +387,7 @@ private void renderEntities(LevelRenderer levelRenderer, Frustrum frustum, Buffe profiler.endSection(); } - private void renderPlayerEntity(LevelRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { + private void renderPlayerEntity(EntityRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { // TODO: Render // EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); @@ -454,8 +454,11 @@ private void renderBlockEntities(BufferSource bufferSource, MatrixStack modelVie profiler.endSection(); } - public void renderShadows(LevelRenderer levelRenderer, Camera playerCamera) { - // We have to re-query this each frame since this changes based on whether the profiler is active + public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { + final Minecraft mc = Minecraft.getMinecraft(); + final RenderGlobal rg = mc.renderGlobal; + + // We have to re-query this each frame since this changes based on whether the profiler is active // If the profiler is inactive, it will return InactiveProfiler.INSTANCE this.profiler = Minecraft.getMinecraft().mcProfiler; @@ -541,9 +544,11 @@ public void renderShadows(LevelRenderer levelRenderer, Camera playerCamera) { // Render all opaque terrain unless pack requests not to if (shouldRenderTerrain) { - levelRenderer.invokeRenderChunkLayer(RenderLayer.solid(), modelView, cameraX, cameraY, cameraZ); - levelRenderer.invokeRenderChunkLayer(RenderLayer.cutout(), modelView, cameraX, cameraY, cameraZ); - levelRenderer.invokeRenderChunkLayer(RenderLayer.cutoutMipped(), modelView, cameraX, cameraY, cameraZ); + rg.sortAndRender(mc.thePlayer, 0, playerCamera.getPartialTicks()); + rg.sortAndRender(mc.thePlayer, 1, playerCamera.getPartialTicks()); +// levelRenderer.invokeRenderChunkLayer(RenderLayer.solid(), modelView, cameraX, cameraY, cameraZ); +// levelRenderer.invokeRenderChunkLayer(RenderLayer.cutout(), modelView, cameraX, cameraY, cameraZ); +// levelRenderer.invokeRenderChunkLayer(RenderLayer.cutoutMipped(), modelView, cameraX, cameraY, cameraZ); } profiler.endStartSection("entities"); @@ -605,7 +610,8 @@ public void renderShadows(LevelRenderer levelRenderer, Camera playerCamera) { // It doesn't matter a ton, since this just means that they won't be sorted in the getNormal rendering pass. // Just something to watch out for, however... if (shouldRenderTranslucent) { - levelRenderer.invokeRenderChunkLayer(RenderLayer.translucent(), modelView, cameraX, cameraY, cameraZ); + rg.sortAndRender(mc.thePlayer, 1, playerCamera.getPartialTicks()); +// levelRenderer.invokeRenderChunkLayer(RenderLayer.translucent(), modelView, cameraX, cameraY, cameraZ); } // Note: Apparently tripwire isn't rendered in the shadow pass. diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java index a1d72f76a..4dc2904f0 100644 --- a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java @@ -1,19 +1,19 @@ package net.coderbot.iris.pipeline; import com.gtnewhorizons.angelica.compat.mojang.Camera; -import com.gtnewhorizons.angelica.compat.mojang.LevelRenderer; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; import net.coderbot.iris.shaderpack.CloudSetting; import net.coderbot.iris.uniforms.FrameUpdateNotifier; +import net.minecraft.client.renderer.EntityRenderer; import java.util.List; import java.util.OptionalInt; public interface WorldRenderingPipeline { void beginLevelRendering(); - void renderShadows(LevelRenderer levelRenderer, Camera camera); + void renderShadows(EntityRenderer levelRenderer, Camera camera); void addDebugText(List messages); OptionalInt getForcedShadowRenderDistanceChunksForDisplay(); diff --git a/src/main/java/net/coderbot/iris/sodium/Mixins.txt b/src/main/java/net/coderbot/iris/sodium/Mixins.txt index a54428b39..0dc133c82 100644 --- a/src/main/java/net/coderbot/iris/sodium/Mixins.txt +++ b/src/main/java/net/coderbot/iris/sodium/Mixins.txt @@ -3,10 +3,10 @@ Y directional_shading Y MixinFlatLightPipeline.java * shader_overrides * ShaderTypeAccessor.java - * MixinChunkRenderShaderBackend.java - * MixinShaderType.java - * MixinChunkProgram.java - * MixinChunkRenderManager.java + Y MixinChunkRenderShaderBackend.java + Y MixinShaderType.java + Y MixinChunkProgram.java + Y MixinChunkRenderManager.java * shadow_map Y MixinSodiumWorldRenderer.java Y MixinGameRendererContext.java @@ -18,14 +18,14 @@ Y directional_shading * MixinTextureAtlasSprite.java * vertex_format * entity - * MixinBufferBuilder_ExtendedVertexFormatCompat.java - * MixinSodiumWorldRenderer.java - * MixinChunkOneshotGraphicsState.java - * GlVertexAttributeFormatAccessor.java - * MixinMultidrawChunkRenderBackend.java - * MixinChunkMeshAttribute.java - * MixinGlVertexFormatBuilder.java - * ChunkMeshAttributeAccessor.java + * MixinBufferBuilder_ExtendedVertexFormatCompat.java // Unclear + Y MixinSodiumWorldRenderer.java + Y MixinChunkOneshotGraphicsState.java + N GlVertexAttributeFormatAccessor.java + Y MixinMultidrawChunkRenderBackend.java + Y MixinChunkMeshAttribute.java + Y MixinGlVertexFormatBuilder.java + N ChunkMeshAttributeAccessor.java * separate_ao * MixinBlockRenderer.java * MixinFluidRenderer.java diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisChunkMeshAttributes.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisChunkMeshAttributes.java deleted file mode 100644 index 1b987124f..000000000 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/IrisChunkMeshAttributes.java +++ /dev/null @@ -1,14 +0,0 @@ -package net.coderbot.iris.sodium.vertex_format; - -import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; - -/** - * Initialized by {@link net.coderbot.iris.compat.sodium.mixin.vertex_format.MixinChunkMeshAttribute} - */ -public class IrisChunkMeshAttributes { - public static ChunkMeshAttribute NORMAL; - public static ChunkMeshAttribute TANGENT; - public static ChunkMeshAttribute MID_TEX_COORD; - public static ChunkMeshAttribute BLOCK_ID; - public static ChunkMeshAttribute MID_BLOCK; -} diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java index 6e1e83a15..6de447e7d 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java @@ -8,7 +8,6 @@ import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; import me.jellysquid.mods.sodium.client.render.chunk.format.ChunkMeshAttribute; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; -import net.coderbot.iris.sodium.vertex_format.IrisChunkMeshAttributes; import net.coderbot.iris.sodium.vertex_format.IrisGlVertexAttributeFormat; /** @@ -21,11 +20,11 @@ public class XHFPModelVertexType implements ChunkVertexType { .addElement(ChunkMeshAttribute.COLOR, 8, GlVertexAttributeFormat.UNSIGNED_BYTE, 4, true) .addElement(ChunkMeshAttribute.TEXTURE, 12, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, false) .addElement(ChunkMeshAttribute.LIGHT, 16, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, false) - .addElement(IrisChunkMeshAttributes.MID_TEX_COORD, 20, GlVertexAttributeFormat.FLOAT, 2, false) - .addElement(IrisChunkMeshAttributes.TANGENT, 28, IrisGlVertexAttributeFormat.BYTE, 4, true) - .addElement(IrisChunkMeshAttributes.NORMAL, 32, IrisGlVertexAttributeFormat.BYTE, 3, true) - .addElement(IrisChunkMeshAttributes.BLOCK_ID, 36, IrisGlVertexAttributeFormat.SHORT, 2, false) - .addElement(IrisChunkMeshAttributes.MID_BLOCK, 40, IrisGlVertexAttributeFormat.BYTE, 3, false) + .addElement(ChunkMeshAttribute.MID_TEX_COORD, 20, GlVertexAttributeFormat.FLOAT, 2, false) + .addElement(ChunkMeshAttribute.TANGENT, 28, IrisGlVertexAttributeFormat.BYTE, 4, true) + .addElement(ChunkMeshAttribute.NORMAL, 32, IrisGlVertexAttributeFormat.BYTE, 3, true) + .addElement(ChunkMeshAttribute.BLOCK_ID, 36, IrisGlVertexAttributeFormat.SHORT, 2, false) + .addElement(ChunkMeshAttribute.MID_BLOCK, 40, IrisGlVertexAttributeFormat.BYTE, 3, false) .build(); public static final float MODEL_SCALE = (32.0f / 65536.0f); From ede3a44607b9a57872377af1afe643f2e6e8e135 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 5 Dec 2023 08:33:20 -0800 Subject: [PATCH 219/301] Iris Progress --- .../compat/mojang/DefaultVertexFormat.java | 6 +- .../angelica/compat/mojang/VertexBuffer.java | 59 ++++++--- .../angelica/compat/nd/BufferWriter.java | 2 +- .../angelica/compat/nd/Quad.java | 46 +------ .../angelica/compat/nd/RecyclingList.java | 2 +- .../early/shaders/MixinFramebuffer.java | 53 ++++++++ .../client/render/pipeline/BlockRenderer.java | 4 +- .../coderbot/iris/gl/IrisRenderSystem.java | 27 ++-- .../iris/gl/framebuffer/GlFramebuffer.java | 7 +- .../iris/gl/program/ComputeProgram.java | 15 ++- .../iris/gl/texture/DepthCopyStrategy.java | 18 +-- .../DeferredWorldRenderingPipeline.java | 18 ++- .../iris/pipeline/HorizonRenderer.java | 120 ++++++++++-------- .../iris/pipeline/ShadowRenderer.java | 11 +- .../iris/rendertarget/IRenderTargetExt.java | 3 + .../iris/rendertarget/RenderTargets.java | 5 +- .../texture/util/TextureManipulationUtil.java | 19 ++- .../iris/uniforms/MatrixUniforms.java | 6 +- 18 files changed, 244 insertions(+), 177 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java index e93050691..c6e126c4c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java @@ -16,11 +16,13 @@ public class DefaultVertexFormat { public static final VertexFormat POSITION_COLOR_TEXTURE_LIGHT_NORMAL = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).add(TEXTURE_0_ELEMENT).add(LIGHT_ELEMENT).add(NORMAL_ELEMENT).add(PADDING_ELEMENT).build()); public static final VertexFormat POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).add(TEXTURE_0_ELEMENT).add(OVERLAY_ELEMENT).add(LIGHT_ELEMENT).add(NORMAL_ELEMENT).add(PADDING_ELEMENT).build()); public static final VertexFormat POSITION_TEXTURE_COLOR_LIGHT = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(TEXTURE_0_ELEMENT).add(COLOR_ELEMENT).add(LIGHT_ELEMENT).build()); - public static final VertexFormat POSITION = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).build()), POSITION_COLOR = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).build()); + public static final VertexFormat POSITION = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).build()); + public static final VertexFormat POSITION_COLOR = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).build()); public static final VertexFormat POSITION_COLOR_LIGHT = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).add(LIGHT_ELEMENT).build()); public static final VertexFormat POSITION_TEXTURE = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(TEXTURE_0_ELEMENT).build()); public static final VertexFormat POSITION_COLOR_TEXTURE = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).add(TEXTURE_0_ELEMENT).build()); - public static final VertexFormat POSITION_TEXTURE_COLOR = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(TEXTURE_0_ELEMENT).add(COLOR_ELEMENT).build()), POSITION_COLOR_TEX_LIGHTMAP = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).add(TEXTURE_0_ELEMENT).add(LIGHT_ELEMENT).build()); + public static final VertexFormat POSITION_TEXTURE_COLOR = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(TEXTURE_0_ELEMENT).add(COLOR_ELEMENT).build()); + public static final VertexFormat POSITION_COLOR_TEX_LIGHTMAP = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(COLOR_ELEMENT).add(TEXTURE_0_ELEMENT).add(LIGHT_ELEMENT).build()); public static final VertexFormat POSITION_TEXTURE_LIGHT_COLOR = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(TEXTURE_0_ELEMENT).add(LIGHT_ELEMENT).add(COLOR_ELEMENT).build()); public static final VertexFormat POSITION_TEXTURE_COLOR_NORMAL = new VertexFormat(new ImmutableList.Builder().add(POSITION_ELEMENT).add(TEXTURE_0_ELEMENT).add(COLOR_ELEMENT).add(NORMAL_ELEMENT).add(PADDING_ELEMENT).build()); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java index 1819196f2..8a7d0661b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java @@ -1,18 +1,47 @@ package com.gtnewhorizons.angelica.compat.mojang; -import org.joml.Matrix4f; - -public class VertexBuffer { - - public VertexBuffer(VertexFormat position) {} - - public static void unbind() {} - - public void bind() {} - - public void upload(BufferBuilder buffer) {} - - public void close() {} - - public void draw(Matrix4f matrix, int glQuads) {} +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL15; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; + +public class VertexBuffer implements AutoCloseable { + private int id; + private int vertexCount; + + public VertexBuffer() { + this.id = GL15.glGenBuffers(); + } + + public void bind() { + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.id); + } + + public void unbind() { + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); + } + + public void upload(ByteBuffer buffer, int vertexCount) { + if (this.id == -1) return; + this.vertexCount = vertexCount; + this.bind(); + GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW); + this.unbind(); + } + + public void close() { + if (this.id >= 0) { + GL15.glDeleteBuffers(this.id); + this.id = -1; + } + } + + public void draw(FloatBuffer floatBuffer, int mode) { + GL11.glPushMatrix(); + GL11.glLoadIdentity(); + GL11.glMultMatrix(floatBuffer); + GL11.glDrawArrays(mode, 0, this.vertexCount); + GL11.glPopMatrix(); + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/BufferWriter.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/BufferWriter.java index 2fbf3c3af..9d5681669 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/nd/BufferWriter.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/BufferWriter.java @@ -6,7 +6,7 @@ import java.nio.ShortBuffer; public class BufferWriter { - // Temporarily borrowed from Neodymium + // Adapted from Neodymium private final ByteBuffer buf; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java index 951f1a9f3..7d155a736 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/Quad.java @@ -10,11 +10,10 @@ import java.io.IOException; import java.util.Arrays; -import java.util.Comparator; import java.util.Locale; public class Quad implements ModelQuadView { - // Temporarily borrowed from Neodymium + // Adapted from Neodymium private final static int DEFAULT_BRIGHTNESS = 15 << 20 | 15 << 4; private final static int DEFAULT_COLOR = 0xFFFFFFFF; @@ -34,7 +33,6 @@ public class Quad implements ModelQuadView { public int[] cs = new int[4]; // TODO normals? public boolean deleted; - public boolean noMerge; public ModelQuadFacing normal; public int offset; @@ -47,11 +45,7 @@ public class Quad implements ModelQuadView { // 0: quads glued together on edge 1-2 or 3-0 ("megaquad row length") // 1: quads glued together on edge 0-1 or 2-3 ("megaquad column length") - private int[] quadCountByDirection = {1, 1}; - - // When we merge with another quad, we forget what we used to be like. - // Keep a reference to the quad we first merged with, and use it as a reminder. - public Quad mergeReference; + private final int[] quadCountByDirection = {1, 1}; private final Vector3f vectorA = new Vector3f(), vectorB = new Vector3f(), vectorC = new Vector3f(); @@ -179,10 +173,6 @@ public void setState(int[] rawBuffer, int offset, BlockRenderer.Flags flags, int updateMinMaxXYZ(); updateIsRectangle(); - if(!isRectangle) { - // merging non-rectangles (e.g. Carpenter's Blocks wedge) is buggy, don't do it - noMerge = true; - } vectorA.set(xs[1] - xs[0], ys[1] - ys[0], zs[1] - zs[0]); vectorB.set(xs[2] - xs[1], ys[2] - ys[1], zs[2] - zs[1]); @@ -207,13 +197,12 @@ private void resetState() { maxY = Float.NEGATIVE_INFINITY; maxZ = Float.NEGATIVE_INFINITY; - deleted = noMerge = false; + deleted = false; normal = null; offset = 0; flags = null; uDirectionIs01 = false; Arrays.fill(quadCountByDirection, 1); - mergeReference = null; } public void writeToBuffer(BufferWriter out) throws IOException { @@ -232,13 +221,8 @@ public void writeToBuffer(BufferWriter out) throws IOException { float u = us[vi]; float v = vs[vi]; - if(false/*Config.shortUV*/) { - out.writeShort((short)(Math.round(u * 32768f))); - out.writeShort((short)(Math.round(v * 32768f))); - } else { - out.writeFloat(u); - out.writeFloat(v); - } + out.writeFloat(u); + out.writeFloat(v); int b = bs[vi]; @@ -248,21 +232,6 @@ public void writeToBuffer(BufferWriter out) throws IOException { out.writeInt(c); - if(false/*Config.simplifyChunkMeshes*/) { - if((quadCountByUVDirection(false) == 1 && quadCountByUVDirection(true) == 1)) { - // let the fragment shader know this is not a megaquad - out.writeByte((byte)255); - out.writeByte((byte)255); - out.writeByte((byte)255); - out.writeByte((byte)255); - } else { - out.writeByte(us[vi] == us[provokingI] ? 0 : (byte)quadCountByUVDirection(false)); - out.writeByte(vs[vi] == vs[provokingI] ? 0 : (byte)quadCountByUVDirection(true)); - out.writeByte(us[vi] == us[provokingI] ? (byte)0 : 1); - out.writeByte(vs[vi] == vs[provokingI] ? (byte)0 : 1); - } - } - assert out.position() % getStride() == 0; //System.out.println("[" + vertexI + "] x: " + x + ", y: " + y + " z: " + z + ", u: " + u + ", v: " + v + ", b: " + b + ", c: " + c); @@ -283,17 +252,12 @@ public static int getStride() { + 2 * (/*Config.shortUV*/false ? 2 : 4) // UV (float) + 4 // B (int) + 4 // C (int) - + (/*Config.simplifyChunkMeshes*/ false ? 4 : 0) // megaquad XY (byte) ; } private boolean isTranslatedCopyOf(Quad o, boolean checkValid) { if((!isValid(this) && checkValid) || !isValid(o) || normal != o.normal) return false; - if(mergeReference != null) { - return mergeReference.isTranslatedCopyOf(o, false); - } - for(int i = 1; i < 4; i++) { double relX = xs[i] - xs[0]; double relY = ys[i] - ys[0]; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java b/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java index 0bb37785b..362cccc35 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/nd/RecyclingList.java @@ -5,7 +5,7 @@ import java.util.function.Supplier; public class RecyclingList { - // Temporarily borrowed from Neodymium + // Adapted from Neodymium private Supplier constructor; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java index 038f5153d..94bdd81cc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java @@ -1,18 +1,32 @@ package com.gtnewhorizons.angelica.mixins.early.shaders; +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import lombok.Getter; import net.coderbot.iris.rendertarget.IRenderTargetExt; +import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.shader.Framebuffer; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; +import org.lwjgl.opengl.GL30; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.nio.IntBuffer; + @Mixin(Framebuffer.class) public abstract class MixinFramebuffer implements IRenderTargetExt { private int iris$depthBufferVersion; private int iris$colorBufferVersion; + @Getter public boolean iris$useDepth; + @Getter public int iris$depthTextureId = -1; + + @Shadow public boolean useDepth; + @Inject(method = "deleteFramebuffer()V", at = @At(value="INVOKE", target="Lnet/minecraft/client/shader/Framebuffer;unbindFramebuffer()V", shift = At.Shift.AFTER)) private void iris$onDestroyBuffers(CallbackInfo ci) { @@ -30,4 +44,43 @@ public abstract class MixinFramebuffer implements IRenderTargetExt { return iris$colorBufferVersion; } + // Use a depth texture instead of a depth render buffer + @Inject(method="Lnet/minecraft/client/shader/Framebuffer;createBindFramebuffer(II)V", at=@At(value="HEAD")) + private void iris$useDepthTexture(int width, int height, CallbackInfo ci) { + if(this.useDepth) { + this.useDepth = false; + this.iris$useDepth = true; + } + } + + @Inject(method="deleteFramebuffer()V", at=@At(value="FIELD", target="Lnet/minecraft/client/shader/Framebuffer;depthBuffer:I", shift = At.Shift.BEFORE, ordinal = 0), remap = false) + private void iris$deleteDepthBuffer(CallbackInfo ci) { + if(this.iris$depthTextureId > -1 ) { + GLStateManager.glDeleteTextures(this.iris$depthTextureId); + this.iris$depthTextureId = -1; + } + } + + @Inject(method="createFramebuffer(II)V", at=@At(value="FIELD", target="Lnet/minecraft/client/shader/Framebuffer;useDepth:Z", shift=At.Shift.BEFORE, ordinal = 0)) + private void iris$createDepthTextureID(int width, int height, CallbackInfo ci) { + if (this.iris$useDepth) { + this.iris$depthTextureId = GL11.glGenTextures(); + } + } + + @Inject(method="createFramebuffer(II)V", at=@At(value="FIELD", target="Lnet/minecraft/client/shader/Framebuffer;useDepth:Z", shift=At.Shift.BEFORE, ordinal = 1)) + private void iris$createDepthTexture(int width, int height, CallbackInfo ci) { + if(this.iris$useDepth) { + GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, this.iris$depthTextureId); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_COMPARE_MODE, 0); + GLStateManager.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_DEPTH_COMPONENT, width, height, 0, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (IntBuffer) null); + OpenGlHelper.func_153188_a/*glFramebufferTexture2D*/(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, this.iris$depthTextureId, 0); + } + } + } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index c7f59352d..ab1c1f844 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -52,7 +52,7 @@ public boolean renderModel(IBlockAccess world, Tessellator tessellator, RenderBl this.random.setSeed(seed); - final List all = tesselatorToBakedQuadList(tessellator, pos); + final List all = tessellatorToQuadList(tessellator, pos); for (ModelQuadFacing facing : ModelQuadFacing.VALUES) { this.renderQuadList(pos, buffers, all, facing); @@ -68,7 +68,7 @@ public boolean renderModel(IBlockAccess world, Tessellator tessellator, RenderBl } private int tesselatorDataCount; - private List tesselatorToBakedQuadList(Tessellator t, BlockPos pos) { + private List tessellatorToQuadList(Tessellator t, BlockPos pos) { // Adapted from Neodymium tesselatorDataCount++; diff --git a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java index 044239dae..374918fb6 100644 --- a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java +++ b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java @@ -4,7 +4,9 @@ import net.coderbot.iris.Iris; import net.minecraft.client.renderer.OpenGlHelper; import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4f; import org.joml.Vector3i; +import org.lwjgl.BufferUtils; import org.lwjgl.opengl.ARBDirectStateAccess; import org.lwjgl.opengl.EXTShaderImageLoadStore; import org.lwjgl.opengl.GL11; @@ -46,14 +48,12 @@ public static void initRenderer() { supportsCompute = supportsCompute(); } - public static void getIntegerv(int pname, int[] params) { - // TODO: Iris Shaders - IntBuffer - GL11.glGetInteger(pname, IntBuffer.wrap(params)); + public static void getIntegerv(int pname, IntBuffer params) { + GL11.glGetInteger(pname, params); } - public static void getFloatv(int pname, float[] params) { - // TODO: Iris Shaders - FloatBuffer - GL11.glGetFloat(pname, FloatBuffer.wrap(params)); + public static void getFloatv(int pname, FloatBuffer params) { + GL11.glGetFloat(pname, params); } public static void generateMipmaps(int texture, int mipmapTarget) { @@ -149,8 +149,8 @@ public static String getActiveUniform(int program, int index, int maxLength, Int return GL20.glGetActiveUniform(program, index, maxLength, sizeType); } - public static void readPixels(int x, int y, int width, int height, int format, int type, float[] pixels) { - GL11.glReadPixels(x, y, width, height, format, type, FloatBuffer.wrap(pixels)); + public static void readPixels(int x, int y, int width, int height, int format, int type, FloatBuffer pixels) { + GL11.glReadPixels(x, y, width, height, format, type, pixels); } public static void bufferData(int target, FloatBuffer data, int usage) { @@ -195,8 +195,8 @@ public static int getMaxImageUnits() { } } - public static void getProgramiv(int program, int value, int[] storage) { - GL20.glGetProgram(program, value, IntBuffer.wrap(storage)); + public static void getProgramiv(int program, int value, IntBuffer storage) { + GL20.glGetProgram(program, value, storage); } public static void dispatchCompute(int workX, int workY, int workZ) { @@ -233,10 +233,13 @@ public static void bindTextureToUnit(int unit, int texture) { dsaState.bindTextureToUnit(unit, texture); } - public static void setupProjectionMatrix(float[] matrix) { + public static void setupProjectionMatrix(Matrix4f matrix) { GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glPushMatrix(); - GL11.glLoadMatrix(FloatBuffer.wrap(matrix)); + // TODO: allocations + FloatBuffer buffer = BufferUtils.createFloatBuffer(16); + matrix.get(buffer); + GL11.glLoadMatrix(buffer); GL11.glMatrixMode(GL11.GL_MODELVIEW); } diff --git a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java index eaea1105f..249bd0a48 100644 --- a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java +++ b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java @@ -40,7 +40,9 @@ public void addDepthAttachment(int texture) { } else { IrisRenderSystem.framebufferTexture2D(fb, GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, texture, 0); } - + if(!isComplete()) { + throw new RuntimeException("Framebuffer incomplete"); + } this.hasDepthAttachment = true; } @@ -103,9 +105,8 @@ protected void destroyInternal() { public boolean isComplete() { bind(); - int status = OpenGlHelper.func_153167_i/*glCheckFramebufferStatus*/(GL30.GL_FRAMEBUFFER); - return status == GL30.GL_FRAMEBUFFER_COMPLETE; + return OpenGlHelper.func_153167_i/*glCheckFramebufferStatus*/(GL30.GL_FRAMEBUFFER) == GL30.GL_FRAMEBUFFER_COMPLETE; } public int getId() { diff --git a/src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java b/src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java index d543b4484..3018e643d 100644 --- a/src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java +++ b/src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java @@ -6,16 +6,20 @@ import net.coderbot.iris.pipeline.WorldRenderingPipeline; import org.joml.Vector2f; import org.joml.Vector3i; +import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL43; +import java.nio.IntBuffer; + public final class ComputeProgram extends GlResource { private final ProgramUniforms uniforms; private final ProgramSamplers samplers; private final ProgramImages images; private Vector3i absoluteWorkGroups; private Vector2f relativeWorkGroups; - private int[] localSize; +// private int[] localSize; + private IntBuffer localSizeBuffer; private float cachedWidth; private float cachedHeight; private Vector3i cachedWorkGroups; @@ -23,8 +27,9 @@ public final class ComputeProgram extends GlResource { ComputeProgram(int program, ProgramUniforms uniforms, ProgramSamplers samplers, ProgramImages images) { super(program); - localSize = new int[3]; - IrisRenderSystem.getProgramiv(program, GL43.GL_COMPUTE_WORK_GROUP_SIZE, localSize); + localSizeBuffer = BufferUtils.createIntBuffer(3); +// localSize = new int[3]; + IrisRenderSystem.getProgramiv(program, GL43.GL_COMPUTE_WORK_GROUP_SIZE, localSizeBuffer); this.uniforms = uniforms; this.samplers = samplers; this.images = images; @@ -44,9 +49,9 @@ public Vector3i getWorkGroups(float width, float height) { } else if (relativeWorkGroups != null) { // TODO: This is my best guess at what Optifine does. Can this be confirmed? // Do not use actual localSize here, apparently that's not what we want. - this.cachedWorkGroups = new Vector3i((int) Math.ceil(Math.ceil((width * relativeWorkGroups.x)) / localSize[0]), (int) Math.ceil(Math.ceil((height * relativeWorkGroups.y)) / localSize[1]), 1); + this.cachedWorkGroups = new Vector3i((int) Math.ceil(Math.ceil((width * relativeWorkGroups.x)) / localSizeBuffer.get(0)), (int) Math.ceil(Math.ceil((height * relativeWorkGroups.y)) / localSizeBuffer.get(1)), 1); } else { - this.cachedWorkGroups = new Vector3i((int) Math.ceil(width / localSize[0]), (int) Math.ceil(height / localSize[1]), 1); + this.cachedWorkGroups = new Vector3i((int) Math.ceil(width / localSizeBuffer.get(0)), (int) Math.ceil(height / localSizeBuffer.get(1)), 1); } } diff --git a/src/main/java/net/coderbot/iris/gl/texture/DepthCopyStrategy.java b/src/main/java/net/coderbot/iris/gl/texture/DepthCopyStrategy.java index 169e177d5..e189fec1c 100644 --- a/src/main/java/net/coderbot/iris/gl/texture/DepthCopyStrategy.java +++ b/src/main/java/net/coderbot/iris/gl/texture/DepthCopyStrategy.java @@ -73,23 +73,7 @@ public boolean needsDestFramebuffer() { @Override public void copy(GlFramebuffer sourceFb, int sourceTexture, GlFramebuffer destFb, int destTexture, int width, int height) { - GL43.glCopyImageSubData( - sourceTexture, - GL11.GL_TEXTURE_2D, - 0, - 0, - 0, - 0, - destTexture, - GL11.GL_TEXTURE_2D, - 0, - 0, - 0, - 0, - width, - height, - 1 - ); + GL43.glCopyImageSubData(sourceTexture, GL11.GL_TEXTURE_2D, 0, 0, 0, 0, destTexture, GL11.GL_TEXTURE_2D, 0, 0, 0, 0, width, height, 1); } } diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 71bc54642..6213ce08e 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -49,6 +49,7 @@ import net.coderbot.iris.shaderpack.loading.ProgramId; import net.coderbot.iris.shaderpack.texture.TextureStage; import net.coderbot.iris.shadows.ShadowRenderTargets; +import net.coderbot.iris.texture.TextureInfoCache; import net.coderbot.iris.texture.format.TextureFormat; import net.coderbot.iris.texture.format.TextureFormatLoader; import net.coderbot.iris.texture.pbr.PBRTextureHolder; @@ -171,9 +172,12 @@ public DeferredWorldRenderingPipeline(ProgramSet programs) { final Framebuffer main = Minecraft.getMinecraft().getFramebuffer(); + final int depthTextureId = ((IRenderTargetExt)main).getIris$depthTextureId(); + final int internalFormat = TextureInfoCache.INSTANCE.getInfo(depthTextureId).getInternalFormat(); + final DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); - this.renderTargets = new RenderTargets(main.framebufferWidth, main.framebufferHeight, main.depthBuffer, - ((IRenderTargetExt)main).iris$getDepthBufferVersion(), + this.renderTargets = new RenderTargets(main.framebufferWidth, main.framebufferHeight, depthTextureId, + ((IRenderTargetExt)main).iris$getDepthBufferVersion(), depthBufferFormat, programs.getPackDirectives().getRenderTargetDirectives().getRenderTargetSettings(), programs.getPackDirectives()); this.sunPathRotation = programs.getPackDirectives().getSunPathRotation(); @@ -890,8 +894,12 @@ private void prepareRenderTargets() { final Framebuffer main = Minecraft.getMinecraft().getFramebuffer(); - final boolean changed = renderTargets.resizeIfNeeded(((IRenderTargetExt)main).iris$getDepthBufferVersion(), main.depthBuffer, main.framebufferWidth, - main.framebufferHeight, DepthBufferFormat.DEPTH, packDirectives); + final int depthTextureId = ((IRenderTargetExt)main).getIris$depthTextureId(); + final int internalFormat = TextureInfoCache.INSTANCE.getInfo(depthTextureId).getInternalFormat(); + final DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); + + final boolean changed = renderTargets.resizeIfNeeded(((IRenderTargetExt)main).iris$getDepthBufferVersion(), depthTextureId, main.framebufferWidth, + main.framebufferHeight, depthBufferFormat, packDirectives); if (changed) { prepareRenderer.recalculateSizes(); @@ -1109,7 +1117,7 @@ public void beginLevelRendering() { final Vector3d fogColor = GLStateManager.getFogColor(); GL11.glColor4f((float) fogColor.x, (float) fogColor.y, (float) fogColor.z, 1.0F); - horizonRenderer.renderHorizon(RenderingState.INSTANCE.getModelViewMatrix()); + horizonRenderer.renderHorizon(RenderingState.INSTANCE.getModelViewBuffer()); GL11.glDepthMask(true); GL11.glEnable(GL11.GL_TEXTURE_2D); diff --git a/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java index 71bdc25a6..13f0da275 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java @@ -1,13 +1,15 @@ package net.coderbot.iris.pipeline; -import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; -import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; import com.gtnewhorizons.angelica.compat.mojang.VertexBuffer; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.mixins.interfaces.ITessellatorInstance; import net.minecraft.client.Minecraft; -import org.joml.Matrix4f; +import net.minecraft.client.renderer.Tessellator; +import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; + /** * Renders the sky horizon. Vanilla Minecraft simply uses the "clear color" for its horizon, and then draws a plane * above the player. This class extends the sky rendering so that an octagonal prism is drawn around the player instead, @@ -39,7 +41,7 @@ public class HorizonRenderer { * Sine of 22.5 degrees. */ private static final double SIN_22_5 = Math.sin(Math.toRadians(22.5)); - private VertexBuffer buffer; + private VertexBuffer vertexBuffer; private int currentRenderDistance; public HorizonRenderer() { @@ -49,36 +51,49 @@ public HorizonRenderer() { } private void rebuildBuffer() { - if (this.buffer != null) { - this.buffer.close(); + if (this.vertexBuffer != null) { + this.vertexBuffer.close(); } - -// BufferBuilder buffer = Tesselator.getInstance().getBuilder(); - BufferBuilder buffer = new BufferBuilder(); + Tessellator tessellator = Tessellator.instance; // Build the horizon quads into a buffer - buffer.begin(GL11.GL_QUADS, DefaultVertexFormat.POSITION); - buildHorizon(currentRenderDistance * 16, buffer); - buffer.end(); - - this.buffer = new VertexBuffer(DefaultVertexFormat.POSITION); - this.buffer.bind(); - this.buffer.upload(buffer); - VertexBuffer.unbind(); + tessellator.startDrawingQuads(); //(GL11.GL_QUADS, DefaultVertexFormat.POSITION); + buildHorizon(currentRenderDistance * 16, tessellator); + ByteBuffer buf = tessellatorToBuffer(tessellator); + ((ITessellatorInstance) tessellator).discard(); + + this.vertexBuffer = new VertexBuffer(); + this.vertexBuffer.bind(); + this.vertexBuffer.upload(buf, tessellator.vertexCount); + this.vertexBuffer.unbind(); } - private void buildQuad(VertexConsumer consumer, double x1, double z1, double x2, double z2) { - consumer.vertex(x1, BOTTOM, z1); - consumer.next(); - consumer.vertex(x1, TOP, z1); - consumer.next(); - consumer.vertex(x2, TOP, z2); - consumer.next(); - consumer.vertex(x2, BOTTOM, z2); - consumer.next(); + /* Convert the tessellator's data into a buffer that can be uploaded to the GPU. */ + private ByteBuffer tessellatorToBuffer(Tessellator tessellator) { + final int[] rawBuffer = tessellator.rawBuffer; + final int byteSize = (tessellator.vertexCount * 3) << 2; + ByteBuffer byteBuffer = BufferUtils.createByteBuffer(byteSize); + + for(int quadI = 0 ; quadI < tessellator.vertexCount / 4 ; quadI++) { + for(int vertexI = 0 ; vertexI < 4 ; vertexI++) { + int i = (quadI * 4 * 8 ) + (vertexI * 8); + byteBuffer.putFloat(Float.intBitsToFloat(rawBuffer[i + 0])); + byteBuffer.putFloat(Float.intBitsToFloat(rawBuffer[i + 1])); + byteBuffer.putFloat(Float.intBitsToFloat(rawBuffer[i + 2])); + } + } + + return (ByteBuffer) byteBuffer.rewind(); + } + + private void buildQuad(Tessellator consumer, double x1, double z1, double x2, double z2) { + consumer.addVertex(x1, BOTTOM, z1); + consumer.addVertex(x1, TOP, z1); + consumer.addVertex(x2, TOP, z2); + consumer.addVertex(x2, BOTTOM, z2); } - private void buildHalf(VertexConsumer consumer, double adjacent, double opposite, boolean invert) { + private void buildHalf(Tessellator consumer, double adjacent, double opposite, boolean invert) { if (invert) { adjacent = -adjacent; opposite = -opposite; @@ -104,49 +119,41 @@ private void buildHalf(VertexConsumer consumer, double adjacent, double opposite * @param opposite the opposite side length of the a triangle with a hypotenuse extending from the center of the * octagon to a given vertex on the perimeter. */ - private void buildOctagonalPrism(VertexConsumer consumer, double adjacent, double opposite) { + private void buildOctagonalPrism(Tessellator consumer, double adjacent, double opposite) { buildHalf(consumer, adjacent, opposite, false); buildHalf(consumer, adjacent, opposite, true); } - private void buildRegularOctagonalPrism(VertexConsumer consumer, double radius) { + private void buildRegularOctagonalPrism(Tessellator consumer, double radius) { buildOctagonalPrism(consumer, radius * COS_22_5, radius * SIN_22_5); } - private void buildBottomPlane(VertexConsumer consumer, int radius) { + private void buildBottomPlane(Tessellator consumer, int radius) { for (int x = -radius; x <= radius; x += 64) { for (int z = -radius; z <= radius; z += 64) { - consumer.vertex(x + 64, BOTTOM, z); - consumer.next(); - consumer.vertex(x, BOTTOM, z); - consumer.next(); - consumer.vertex(x, BOTTOM, z + 64); - consumer.next(); - consumer.vertex(x + 64, BOTTOM, z + 64); - consumer.next(); + consumer.addVertex(x + 64, BOTTOM, z); + consumer.addVertex(x, BOTTOM, z); + consumer.addVertex(x, BOTTOM, z + 64); + consumer.addVertex(x + 64, BOTTOM, z + 64); } } } - private void buildTopPlane(VertexConsumer consumer, int radius) { + private void buildTopPlane(Tessellator consumer, int radius) { // You might be tempted to try to combine this with buildBottomPlane to avoid code duplication, // but that won't work since the winding order has to be reversed or else one of the planes will be // discarded by back face culling. for (int x = -radius; x <= radius; x += 64) { for (int z = -radius; z <= radius; z += 64) { - consumer.vertex(x + 64, TOP, z); - consumer.next(); - consumer.vertex(x + 64, TOP, z + 64); - consumer.next(); - consumer.vertex(x, TOP, z + 64); - consumer.next(); - consumer.vertex(x, TOP, z); - consumer.next(); + consumer.addVertex(x + 64, TOP, z); + consumer.addVertex(x + 64, TOP, z + 64); + consumer.addVertex(x, TOP, z + 64); + consumer.addVertex(x, TOP, z); } } } - private void buildHorizon(int radius, VertexConsumer consumer) { + private void buildHorizon(int radius, Tessellator consumer) { if (radius > 256) { // Prevent the prism from getting too large, this causes issues on some shader packs that modify the vanilla // sky if we don't do this. @@ -163,20 +170,21 @@ private void buildHorizon(int radius, VertexConsumer consumer) { buildBottomPlane(consumer, 384); } - public void renderHorizon(Matrix4f matrix) { + public void renderHorizon(FloatBuffer floatBuffer) { if (currentRenderDistance != Minecraft.getMinecraft().gameSettings.renderDistanceChunks) { currentRenderDistance = Minecraft.getMinecraft().gameSettings.renderDistanceChunks; rebuildBuffer(); } - buffer.bind(); - DefaultVertexFormat.POSITION.setupBufferState(0L); - buffer.draw(matrix, GL11.GL_QUADS); - DefaultVertexFormat.POSITION.clearBufferState(); - VertexBuffer.unbind(); + vertexBuffer.bind(); + GL11.glVertexPointer(3, GL11.GL_FLOAT, 12, 0L); + GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); + vertexBuffer.draw(floatBuffer, GL11.GL_QUADS); + GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY); + vertexBuffer.unbind(); } public void destroy() { - buffer.close(); + vertexBuffer.close(); } } diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 40bf07b91..3b46a8a78 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -18,7 +18,6 @@ import net.coderbot.iris.shaderpack.ProgramSource; import net.coderbot.iris.shadow.ShadowMatrices; import net.coderbot.iris.shadows.CullingDataCache; -import net.coderbot.iris.shadows.Matrix4fAccess; import net.coderbot.iris.shadows.ShadowRenderTargets; import net.coderbot.iris.shadows.frustum.BoxCuller; import net.coderbot.iris.shadows.frustum.CullEverythingFrustum; @@ -320,7 +319,7 @@ private FrustumHolder createShadowFrustum(float renderMultiplier, FrustumHolder return holder; } - private void setupGlState(float[] projMatrix) { + private void setupGlState(Matrix4f projMatrix) { // Set up our projection matrix and load it into the legacy matrix stack IrisRenderSystem.setupProjectionMatrix(projMatrix); @@ -477,7 +476,7 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // Create our camera MatrixStack modelView = createShadowModelView(this.sunPathRotation, this.intervalSize); // TODO: Render -// MODELVIEW = modelView.peek().getModel().copy(); + MODELVIEW = new Matrix4f(modelView.peek().getModel()); float[] projMatrix; if (this.fov != null) { // If FOV is not null, the pack wants a perspective based projection matrix. (This is to support legacy packs) @@ -486,8 +485,8 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { projMatrix = ShadowMatrices.createOrthoMatrix(halfPlaneLength); } - PROJECTION = new Matrix4f(); - ((Matrix4fAccess) (Object) PROJECTION).copyFromArray(projMatrix); + // TODO: Allocations + PROJECTION = new Matrix4f().set(projMatrix); profiler.startSection("terrain_setup"); @@ -540,7 +539,7 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { profiler.endStartSection("terrain"); - setupGlState(projMatrix); + setupGlState(PROJECTION); // Render all opaque terrain unless pack requests not to if (shouldRenderTerrain) { diff --git a/src/main/java/net/coderbot/iris/rendertarget/IRenderTargetExt.java b/src/main/java/net/coderbot/iris/rendertarget/IRenderTargetExt.java index 332cd73fa..976e62efc 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/IRenderTargetExt.java +++ b/src/main/java/net/coderbot/iris/rendertarget/IRenderTargetExt.java @@ -4,4 +4,7 @@ public interface IRenderTargetExt { int iris$getDepthBufferVersion(); int iris$getColorBufferVersion(); + + public boolean getIris$useDepth(); + public int getIris$depthTextureId(); } diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java index 77e162846..feb4cdbcb 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java @@ -39,7 +39,7 @@ public class RenderTargets { private int cachedDepthBufferVersion; - public RenderTargets(int width, int height, int depthTexture, int depthBufferVersion, Map renderTargets, PackDirectives packDirectives) { + public RenderTargets(int width, int height, int depthTexture, int depthBufferVersion, DepthBufferFormat depthFormat, Map renderTargets, PackDirectives packDirectives) { targets = new RenderTarget[renderTargets.size()]; renderTargets.forEach((index, settings) -> { @@ -49,9 +49,8 @@ public RenderTargets(int width, int height, int depthTexture, int depthBufferVe .setInternalFormat(settings.getInternalFormat()) .setPixelFormat(settings.getInternalFormat().getPixelFormat()).build(); }); - // TODO: currentDepthFormat... :hmmm: -- NEED GL_TEXTURE_INTERNAL_FORMAT ?? - this.currentDepthFormat = DepthBufferFormat.DEPTH; this.currentDepthTexture = depthTexture; + this.currentDepthFormat = depthFormat; this.copyStrategy = DepthCopyStrategy.fastest(currentDepthFormat.isCombinedStencil()); this.cachedWidth = width; diff --git a/src/main/java/net/coderbot/iris/texture/util/TextureManipulationUtil.java b/src/main/java/net/coderbot/iris/texture/util/TextureManipulationUtil.java index 2d2a4f24a..9b5ab5bf4 100644 --- a/src/main/java/net/coderbot/iris/texture/util/TextureManipulationUtil.java +++ b/src/main/java/net/coderbot/iris/texture/util/TextureManipulationUtil.java @@ -4,9 +4,13 @@ import net.coderbot.iris.gl.IrisRenderSystem; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.OpenGlHelper; +import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL30; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + public class TextureManipulationUtil { private static int colorFillFBO = -1; @@ -16,11 +20,14 @@ public static void fillWithColor(int textureId, int maxLevel, int rgba) { } int previousFramebufferId = GL11.glGetInteger(GL30.GL_FRAMEBUFFER_BINDING); - float[] previousClearColor = new float[4]; - IrisRenderSystem.getFloatv(GL11.GL_COLOR_CLEAR_VALUE, previousClearColor); + // TODO: allocations + FloatBuffer previousClearColorBuffer = BufferUtils.createFloatBuffer(4); +// float[] previousClearColor = new float[4]; + IrisRenderSystem.getFloatv(GL11.GL_COLOR_CLEAR_VALUE, previousClearColorBuffer); int previousTextureId = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); - int[] previousViewport = new int[4]; - IrisRenderSystem.getIntegerv(GL11.GL_VIEWPORT, previousViewport); + IntBuffer previousViewportBuffer = BufferUtils.createIntBuffer(4); +// int[] previousViewport = new int[4]; + IrisRenderSystem.getIntegerv(GL11.GL_VIEWPORT, previousViewportBuffer); OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, colorFillFBO); GL11.glClearColor( @@ -45,8 +52,8 @@ public static void fillWithColor(int textureId, int maxLevel, int rgba) { } OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_FRAMEBUFFER, previousFramebufferId); - GL11.glClearColor(previousClearColor[0], previousClearColor[1], previousClearColor[2], previousClearColor[3]); + GL11.glClearColor(previousClearColorBuffer.get(0), previousClearColorBuffer.get(1), previousClearColorBuffer.get(2), previousClearColorBuffer.get(3)); GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, previousTextureId); - GL11.glViewport(previousViewport[0], previousViewport[1], previousViewport[2], previousViewport[3]); + GL11.glViewport(previousViewportBuffer.get(0), previousViewportBuffer.get(1), previousViewportBuffer.get(2), previousViewportBuffer.get(3)); } } diff --git a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java index 94e49f012..c4dcb2237 100644 --- a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java @@ -6,6 +6,7 @@ import net.coderbot.iris.shaderpack.PackDirectives; import net.coderbot.iris.shadow.ShadowMatrices; import org.joml.Matrix4f; +import org.lwjgl.BufferUtils; import java.nio.FloatBuffer; import java.util.function.Supplier; @@ -71,10 +72,11 @@ private static class InvertedArrayMatrix implements Supplier { @Override public Matrix4f get() { - FloatBuffer buffer = FloatBuffer.allocate(16); + // TODO: How can we not do this? + FloatBuffer buffer = BufferUtils.createFloatBuffer(16); +// new Matrix4f(parent.get()); buffer.put(parent.get()); buffer.rewind(); - final Matrix4f matrix4f = new Matrix4f(buffer); matrix4f.invert(); From 01ce7432312fd1dd1763ece8bc32f6a1107dd60c Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 5 Dec 2023 22:02:30 -0800 Subject: [PATCH 220/301] It "runs", but doesn't do much --- .../angelica/compat/mojang/RenderBuffers.java | 8 --- src/main/java/net/coderbot/iris/Iris.java | 1 + .../DeferredWorldRenderingPipeline.java | 17 ++--- .../iris/pipeline/ShadowRenderer.java | 68 ++++++++++--------- .../iris/rendertarget/RenderTargets.java | 12 ++-- 5 files changed, 49 insertions(+), 57 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderBuffers.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderBuffers.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderBuffers.java deleted file mode 100644 index 721da4902..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderBuffers.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -public class RenderBuffers { - - public BufferSource bufferSource() { - return null; - } -} diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index c4022e5cb..737b3c3fc 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -609,6 +609,7 @@ private static WorldRenderingPipeline createPipeline(DimensionId dimensionId) { ProgramSet programs = currentPack.getProgramSet(dimensionId); + try { return new DeferredWorldRenderingPipeline(programs); } catch (Exception e) { diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 6213ce08e..518ce9bdc 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -5,7 +5,6 @@ import com.google.common.primitives.Ints; import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.glsm.GLStateManager; -import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.Iris; import net.coderbot.iris.block_rendering.BlockMaterialMapping; import net.coderbot.iris.block_rendering.BlockRenderingSettings; @@ -743,7 +742,7 @@ public void use() { if (shadowViewport) { GL11.glViewport(0, 0, shadowMapResolution, shadowMapResolution); } else { - final Framebuffer main = Minecraft.getMinecraft().getFramebuffer(); // FBO? + final Framebuffer main = Minecraft.getMinecraft().getFramebuffer(); GL11.glViewport(0, 0, main.framebufferWidth, main.framebufferHeight); } @@ -1011,8 +1010,8 @@ public void beginTranslucents() { deferredRenderer.renderAll(); - GL11.glEnable(GL11.GL_BLEND); - GL11.glEnable(GL11.GL_ALPHA_TEST); + GLStateManager.enableBlend(); + GLStateManager.enableAlphaTest(); // note: we are careful not to touch the lightmap texture unit or overlay color texture unit here, // so we don't need to do anything to restore them if needed. @@ -1028,6 +1027,8 @@ public void beginTranslucents() { @Override public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { + if (true) return; + if (shouldRenderPrepareBeforeShadow) { isRenderingFullScreenPass = true; @@ -1117,7 +1118,7 @@ public void beginLevelRendering() { final Vector3d fogColor = GLStateManager.getFogColor(); GL11.glColor4f((float) fogColor.x, (float) fogColor.y, (float) fogColor.z, 1.0F); - horizonRenderer.renderHorizon(RenderingState.INSTANCE.getModelViewBuffer()); + //horizonRenderer.renderHorizon(RenderingState.INSTANCE.getModelViewBuffer()); GL11.glDepthMask(true); GL11.glEnable(GL11.GL_TEXTURE_2D); @@ -1141,10 +1142,10 @@ public void finalizeLevelRendering() { isRenderingFullScreenPass = true; - centerDepthSampler.sampleCenterDepth(); +// centerDepthSampler.sampleCenterDepth(); - compositeRenderer.renderAll(); - finalPassRenderer.renderFinalPass(); +// compositeRenderer.renderAll(); +// finalPassRenderer.renderFinalPass(); isRenderingFullScreenPass = false; } diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 3b46a8a78..49070ffd2 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -4,12 +4,8 @@ import com.gtnewhorizons.angelica.compat.mojang.BufferSource; import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; -import com.gtnewhorizons.angelica.compat.mojang.RenderBuffers; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.rendering.RenderingState; -import net.coderbot.batchedentityrendering.impl.BatchingDebugMessageHelper; -import net.coderbot.batchedentityrendering.impl.DrawCallTrackingRenderBuffers; -import net.coderbot.batchedentityrendering.impl.RenderBuffersExt; import net.coderbot.iris.Iris; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.shaderpack.OptionalBoolean; @@ -72,8 +68,8 @@ public class ShadowRenderer { private final boolean shouldRenderPlayer; private final boolean shouldRenderBlockEntities; private final float sunPathRotation; - private final RenderBuffers buffers; - private final RenderBuffersExt renderBuffersExt; +// private final RenderBuffers buffers; +// private final RenderBuffersExt renderBuffersExt; private final List mipmapPasses = new ArrayList<>(); private final String debugStringOverall; private FrustumHolder terrainFrustumHolder; @@ -120,13 +116,13 @@ public ShadowRenderer(ProgramSource shadow, PackDirectives directives, ShadowRen this.sunPathRotation = directives.getSunPathRotation(); - this.buffers = new RenderBuffers(); - - if (this.buffers instanceof RenderBuffersExt) { - this.renderBuffersExt = (RenderBuffersExt) buffers; - } else { - this.renderBuffersExt = null; - } +// this.buffers = new RenderBuffers(); +// +// if (this.buffers instanceof RenderBuffersExt) { +// this.renderBuffersExt = (RenderBuffersExt) buffers; +// } else { +// this.renderBuffersExt = null; +// } configureSamplingSettings(shadowDirectives); } @@ -210,6 +206,7 @@ private void configureDepthSampler(int glTextureId, PackShadowDirectives.DepthSa // Workaround for issues with old shader packs like Chocapic v4. // They expected the driver to put the depth value in z, but it's supposed to only // be available in r. So we set up the swizzle to fix that. + // TODO: allocations IntBuffer swizzleBuf = BufferUtils.createIntBuffer(4); swizzleBuf.put(new int[] { GL11.GL_RED, GL11.GL_RED, GL11.GL_RED, GL11.GL_ONE }).rewind(); IrisRenderSystem.texParameteriv(glTextureId, GL11.GL_TEXTURE_2D, ARBTextureSwizzle.GL_TEXTURE_SWIZZLE_RGBA, swizzleBuf); @@ -454,6 +451,8 @@ private void renderBlockEntities(BufferSource bufferSource, MatrixStack modelVie } public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { + if(true) return; + final Minecraft mc = Minecraft.getMinecraft(); final RenderGlobal rg = mc.renderGlobal; @@ -543,8 +542,10 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // Render all opaque terrain unless pack requests not to if (shouldRenderTerrain) { - rg.sortAndRender(mc.thePlayer, 0, playerCamera.getPartialTicks()); - rg.sortAndRender(mc.thePlayer, 1, playerCamera.getPartialTicks()); + // TODO: Render +// rg.sortAndRender(mc.thePlayer, 0, playerCamera.getPartialTicks()); +// rg.sortAndRender(mc.thePlayer, 1, playerCamera.getPartialTicks()); + // levelRenderer.invokeRenderChunkLayer(RenderLayer.solid(), modelView, cameraX, cameraY, cameraZ); // levelRenderer.invokeRenderChunkLayer(RenderLayer.cutout(), modelView, cameraX, cameraY, cameraZ); // levelRenderer.invokeRenderChunkLayer(RenderLayer.cutoutMipped(), modelView, cameraX, cameraY, cameraZ); @@ -574,24 +575,24 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // // Note: We must use a separate BuilderBufferStorage object here, or else very weird things will happen during // rendering. - if (renderBuffersExt != null) { - renderBuffersExt.beginLevelRendering(); - } +// if (renderBuffersExt != null) { +// renderBuffersExt.beginLevelRendering(); +// } - if (buffers instanceof DrawCallTrackingRenderBuffers) { - ((DrawCallTrackingRenderBuffers) buffers).resetDrawCounts(); - } +// if (buffers instanceof DrawCallTrackingRenderBuffers) { +// ((DrawCallTrackingRenderBuffers) buffers).resetDrawCounts(); +// } - BufferSource bufferSource = buffers.bufferSource(); +// BufferSource bufferSource = buffers.bufferSource(); if (shouldRenderEntities) { - renderEntities(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); +// renderEntities(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); } else if (shouldRenderPlayer) { - renderPlayerEntity(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); +// renderPlayerEntity(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); } if (shouldRenderBlockEntities) { - renderBlockEntities(bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta, hasEntityFrustum); +// renderBlockEntities(bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta, hasEntityFrustum); } profiler.endStartSection("draw entities"); @@ -599,7 +600,7 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // NB: Don't try to draw the translucent parts of entities afterwards. It'll cause problems since some // shader packs assume that everything drawn afterwards is actually translucent and should cast a colored // shadow... - bufferSource.endBatch(); +// bufferSource.endBatch(); copyPreTranslucentDepth(); @@ -609,16 +610,17 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // It doesn't matter a ton, since this just means that they won't be sorted in the getNormal rendering pass. // Just something to watch out for, however... if (shouldRenderTranslucent) { - rg.sortAndRender(mc.thePlayer, 1, playerCamera.getPartialTicks()); + // TODO: Render +// rg.sortAndRender(mc.thePlayer, 1, playerCamera.getPartialTicks()); // levelRenderer.invokeRenderChunkLayer(RenderLayer.translucent(), modelView, cameraX, cameraY, cameraZ); } // Note: Apparently tripwire isn't rendered in the shadow pass. // worldRenderer.invokeRenderType(RenderType.getTripwire(), modelView, cameraX, cameraY, cameraZ); - if (renderBuffersExt != null) { - renderBuffersExt.endLevelRendering(); - } +// if (renderBuffersExt != null) { +// renderBuffersExt.endLevelRendering(); +// } // TODO: Render // debugStringTerrain = ((LevelRenderer) levelRenderer).getChunkStatistics(); @@ -651,9 +653,9 @@ public void addDebugText(List messages) { messages.add("[" + Iris.MODNAME + "] Shadow Entities: " + getEntitiesDebugString()); messages.add("[" + Iris.MODNAME + "] Shadow Block Entities: " + getTileEntitiesDebugString()); - if (buffers instanceof DrawCallTrackingRenderBuffers drawCallTracker && (shouldRenderEntities || shouldRenderPlayer)) { - messages.add("[" + Iris.MODNAME + "] Shadow Entity Batching: " + BatchingDebugMessageHelper.getDebugMessage(drawCallTracker)); - } +// if (buffers instanceof DrawCallTrackingRenderBuffers drawCallTracker && (shouldRenderEntities || shouldRenderPlayer)) { +// messages.add("[" + Iris.MODNAME + "] Shadow Entity Batching: " + BatchingDebugMessageHelper.getDebugMessage(drawCallTracker)); +// } } private String getEntitiesDebugString() { diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java index feb4cdbcb..f5c53c50b 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java @@ -33,7 +33,8 @@ public class RenderTargets { private int cachedWidth; private int cachedHeight; - private boolean fullClearRequired; + @Getter + private boolean fullClearRequired; private boolean translucentDepthDirty; private boolean handDepthDirty; @@ -178,8 +179,7 @@ public void copyPreTranslucentDepth() { depthSourceFb.bindAsReadBuffer(); IrisRenderSystem.copyTexImage2D(GL11.GL_TEXTURE_2D, 0, currentDepthFormat.getGlInternalFormat(), 0, 0, cachedWidth, cachedHeight, 0); } else { - copyStrategy.copy(depthSourceFb, getDepthTexture(), noTranslucentsDestFb, noTranslucents.getTextureId(), - getCurrentWidth(), getCurrentHeight()); + copyStrategy.copy(depthSourceFb, getDepthTexture(), noTranslucentsDestFb, noTranslucents.getTextureId(), getCurrentWidth(), getCurrentHeight()); } } @@ -194,11 +194,7 @@ public void copyPreHandDepth() { } } - public boolean isFullClearRequired() { - return fullClearRequired; - } - - public void onFullClear() { + public void onFullClear() { fullClearRequired = false; } From 6187b7c80f561d8d0419e1d82c2047f6fb0db637 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 5 Dec 2023 23:58:24 -0800 Subject: [PATCH 221/301] Wire up more Iris mixins, informing pipeline stages. Still not rendering anything visible. --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../early/shaders/MixinEntityRenderer.java | 48 +++++++++++++++- .../early/shaders/MixinRenderGlobal.java | 56 +++++++++++++++++++ .../early/sodium/MixinRenderGlobal.java | 30 +++++++--- .../iris/gl/framebuffer/GlFramebuffer.java | 4 +- .../DeferredWorldRenderingPipeline.java | 11 ++-- .../iris/pipeline/ShadowRenderer.java | 2 - 7 files changed, 131 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 690f5d027..3034b6aff 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -117,6 +117,7 @@ public enum Mixins { ,"shaders.MixinFramebuffer" ,"shaders.MixinItem" ,"shaders.MixinOpenGlHelper" + ,"shaders.MixinRenderGlobal" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index 57c3b64fb..a9fc6d3aa 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -1,24 +1,31 @@ package com.gtnewhorizons.angelica.mixins.early.shaders; import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalRef; import net.coderbot.iris.Iris; import net.coderbot.iris.gl.program.Program; +import net.coderbot.iris.pipeline.WorldRenderingPhase; import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.coderbot.iris.uniforms.CapturedRenderingState; import net.coderbot.iris.uniforms.SystemTimeUniforms; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.resources.IResourceManagerReloadListener; +import net.minecraft.client.settings.GameSettings; +import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(EntityRenderer.class) public abstract class MixinEntityRenderer implements IResourceManagerReloadListener { - @Inject(at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", args = "ldc=frustrum", shift = At.Shift.AFTER), method = "renderWorld(FJ)V") + @Inject(at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glClear(I)V", shift = At.Shift.AFTER, ordinal = 0), method = "renderWorld(FJ)V") private void iris$beginRender(float partialTicks, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { CapturedRenderingState.INSTANCE.setTickDelta(partialTicks); SystemTimeUniforms.COUNTER.beginFrame(); @@ -48,4 +55,43 @@ public abstract class MixinEntityRenderer implements IResourceManagerReloadListe pipeline.get().renderShadows((EntityRenderer) (Object) this, camera); } + + @Redirect(method = "renderWorld(FJ)V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;renderDistanceChunks:I") ) + /*slice = @Slice(from = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;clear(IZ)V"))*/ + private int iris$alwaysRenderSky(GameSettings instance) { + return Math.max(instance.renderDistanceChunks, 4); + } + @Inject(method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(F)V")) + private void iris$beginSky(float partialTicks, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + // Use CUSTOM_SKY until levelFogColor is called as a heuristic to catch FabricSkyboxes. + pipeline.get().setPhase(WorldRenderingPhase.CUSTOM_SKY); + } + + + @Inject(method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(F)V", shift = At.Shift.AFTER)) + private void iris$endSky(float partialTicks, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + pipeline.get().setPhase(WorldRenderingPhase.NONE); + } + + @WrapOperation(method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/EntityRenderer;renderCloudsCheck(Lnet/minecraft/client/renderer/RenderGlobal;F)V")) + private void iris$clouds(EntityRenderer instance, RenderGlobal rg, float partialTicks, Operation original, @Share("pipeline") LocalRef pipeline) { + pipeline.get().setPhase(WorldRenderingPhase.CLOUDS); + original.call(instance, rg, partialTicks); + pipeline.get().setPhase(WorldRenderingPhase.NONE); + } + + + @Inject(method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/EntityRenderer;renderRainSnow(F)V")) + private void iris$beginWeatherAndwriteRainAndSnowToDepthBuffer(float partialTicks, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + pipeline.get().setPhase(WorldRenderingPhase.RAIN_SNOW); + if (pipeline.get().shouldWriteRainAndSnowToDepthBuffer()) { + GL11.glDepthMask(true); + } + } + + @Inject(method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/EntityRenderer;renderRainSnow(F)V", shift = At.Shift.AFTER)) + private void iris$endWeather(float partialTicks, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + pipeline.get().setPhase(WorldRenderingPhase.NONE); + } + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java new file mode 100644 index 000000000..c508d59fe --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java @@ -0,0 +1,56 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import net.coderbot.iris.Iris; +import net.coderbot.iris.pipeline.WorldRenderingPhase; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.minecraft.client.renderer.RenderGlobal; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(RenderGlobal.class) +public class MixinRenderGlobal { + @Inject(method = "renderSky", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;instance:Lnet/minecraft/client/renderer/Tessellator;")) + private void iris$renderSky$beginNormalSky(float partialTicks, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + // None of the vanilla sky is rendered until after this call, so if anything is rendered before, it's CUSTOM_SKY. + pipeline.set(Iris.getPipelineManager().getPipelineNullable()); + pipeline.get().setPhase(WorldRenderingPhase.SKY); + } + + @Inject(method = "renderSky", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/RenderGlobal;locationSunPng:Lnet/minecraft/util/ResourceLocation;")) + private void iris$setSunRenderStage(float p_72714_1_, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + pipeline.get().setPhase(WorldRenderingPhase.SUN); + } + + @Inject(method = "renderSky", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/RenderGlobal;locationMoonPhasesPng:Lnet/minecraft/util/ResourceLocation;")) + private void iris$setMoonRenderStage(float p_72714_1_, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + pipeline.get().setPhase(WorldRenderingPhase.MOON); + } + + @Inject(method = "renderSky", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/WorldProvider;calcSunriseSunsetColors(FF)[F")) + private void iris$setSunsetRenderStage(float p_72714_1_, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + pipeline.get().setPhase(WorldRenderingPhase.SUNSET); + } + + @Inject(method = "renderSky", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;getStarBrightness(F)F")) + private void iris$setStarRenderStage(float p_72714_1_, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + pipeline.get().setPhase(WorldRenderingPhase.STARS); + } + + @Inject(method = "renderSky", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/entity/EntityClientPlayerMP;getPosition(F)Lnet/minecraft/util/Vec3;")) + private void iris$setVoidRenderStage(float p_72714_1_, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + pipeline.get().setPhase(WorldRenderingPhase.VOID); + } + + // TODO: Inject here (line1188) + // What to translate poseStack mulPose() to? +// @Inject(method = "renderSky", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientLevel;getTimeOfDay(F)F"), +// slice = @Slice(from = @At(value = "FIELD", target = "com/mojang/math/Vector3f.YP : Lcom/mojang/math/Vector3f;"))) +// private void iris$renderSky$tiltSun(PoseStack poseStack, float tickDelta, CallbackInfo callback) { +// poseStack.mulPose(Vector3f.ZP.rotationDegrees(pipeline.getSunPathRotation())); +// } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 640f955df..579b62ce1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -11,6 +11,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import net.coderbot.iris.Iris; import net.coderbot.iris.pipeline.HandRenderer; +import net.coderbot.iris.pipeline.WorldRenderingPhase; import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.PlayerControllerMP; @@ -139,15 +140,23 @@ public boolean updateRenderers(EntityLivingBase e, boolean b){ */ @Overwrite public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) { - if(AngelicaConfig.enableIris && pass == 1) { - final Camera camera = new Camera(mc.renderViewEntity, (float)partialTicks); - final WorldRenderingPipeline pipeline = Iris.getPipelineManager().preparePipeline(Iris.getCurrentDimension()); - - // iris$beginTranslucents - pipeline.beginHand(); - HandRenderer.INSTANCE.renderSolid(null /*poseStack*/, (float)partialTicks, camera, null /*gameRenderer*/, pipeline); - mc.mcProfiler.endStartSection("iris_pre_translucent"); - pipeline.beginTranslucents(); + final WorldRenderingPipeline pipeline; + if(!AngelicaConfig.enableIris) { + pipeline = null; + } else { + pipeline = Iris.getPipelineManager().getPipelineNullable(); +// pipeline.setPhase(WorldRenderingPhase.fromTerrainRenderType(renderType)); + pipeline.setPhase(WorldRenderingPhase.TERRAIN_CUTOUT); + + if(pass == 1) { + final Camera camera = new Camera(mc.renderViewEntity, (float) partialTicks); + + // iris$beginTranslucents + pipeline.beginHand(); + HandRenderer.INSTANCE.renderSolid(null /*poseStack*/, (float) partialTicks, camera, null /*gameRenderer*/, pipeline); + mc.mcProfiler.endStartSection("iris_pre_translucent"); + pipeline.beginTranslucents(); + } } // Handle view distance change if(this.renderDistanceChunks != this.mc.gameSettings.renderDistanceChunks) { @@ -173,6 +182,9 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) RenderDevice.exitManagedCode(); this.mc.entityRenderer.disableLightmap(partialTicks); } + + if(pipeline != null) pipeline.setPhase(WorldRenderingPhase.NONE); + return 0; } diff --git a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java index 249bd0a48..2f85ba66d 100644 --- a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java +++ b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java @@ -40,9 +40,7 @@ public void addDepthAttachment(int texture) { } else { IrisRenderSystem.framebufferTexture2D(fb, GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, texture, 0); } - if(!isComplete()) { - throw new RuntimeException("Framebuffer incomplete"); - } + this.hasDepthAttachment = true; } diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 518ce9bdc..d19e1d7c3 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -5,6 +5,7 @@ import com.google.common.primitives.Ints; import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.Iris; import net.coderbot.iris.block_rendering.BlockMaterialMapping; import net.coderbot.iris.block_rendering.BlockRenderingSettings; @@ -1027,8 +1028,6 @@ public void beginTranslucents() { @Override public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { - if (true) return; - if (shouldRenderPrepareBeforeShadow) { isRenderingFullScreenPass = true; @@ -1118,7 +1117,7 @@ public void beginLevelRendering() { final Vector3d fogColor = GLStateManager.getFogColor(); GL11.glColor4f((float) fogColor.x, (float) fogColor.y, (float) fogColor.z, 1.0F); - //horizonRenderer.renderHorizon(RenderingState.INSTANCE.getModelViewBuffer()); + horizonRenderer.renderHorizon(RenderingState.INSTANCE.getModelViewBuffer()); GL11.glDepthMask(true); GL11.glEnable(GL11.GL_TEXTURE_2D); @@ -1142,10 +1141,10 @@ public void finalizeLevelRendering() { isRenderingFullScreenPass = true; -// centerDepthSampler.sampleCenterDepth(); + centerDepthSampler.sampleCenterDepth(); -// compositeRenderer.renderAll(); -// finalPassRenderer.renderFinalPass(); + compositeRenderer.renderAll(); + finalPassRenderer.renderFinalPass(); isRenderingFullScreenPass = false; } diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 49070ffd2..77cc0ed05 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -451,8 +451,6 @@ private void renderBlockEntities(BufferSource bufferSource, MatrixStack modelVie } public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { - if(true) return; - final Minecraft mc = Minecraft.getMinecraft(); final RenderGlobal rg = mc.renderGlobal; From d740458835291da388e65a156b9dd39039dafcb1 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 6 Dec 2023 09:09:13 -0800 Subject: [PATCH 222/301] Deprecate everything in compat.mojang * We'll need to replace, remove, or rewrite these * It's also likely silently hiding something that's preventing the Iris backport from rendering anything useful --- .../angelica/compat/{mojang => }/Camera.java | 3 ++- .../compat/{mojang => }/ChunkPos.java | 23 +++++++++++++++++-- .../compat/{mojang => }/ChunkSectionPos.java | 5 ++-- .../compat/{mojang => }/CompatMathHelper.java | 2 +- .../compat/{mojang => }/Constants.java | 2 +- .../compat/{mojang => }/NativeImage.java | 4 +++- .../mojang/AutoClosableAbstractTexture.java | 1 + .../angelica/compat/mojang/Axis.java | 1 + .../angelica/compat/mojang/BakedModel.java | 1 + .../angelica/compat/mojang/BakedQuad.java | 1 + .../compat/mojang/BlockBreakingInfo.java | 1 + .../angelica/compat/mojang/BlockModels.java | 1 + .../angelica/compat/mojang/BlockPos.java | 1 + .../compat/mojang/BlockRenderType.java | 1 + .../compat/mojang/BlockRenderView.java | 1 + .../angelica/compat/mojang/BlockState.java | 4 +--- .../angelica/compat/mojang/BlockView.java | 1 + .../angelica/compat/mojang/BufferBuilder.java | 1 + .../compat/mojang/BufferBuilderStorage.java | 1 + .../angelica/compat/mojang/BufferSource.java | 1 + .../mojang/ByteBufferBackedInputStream.java | 1 + .../angelica/compat/mojang/ChunkCuller.java | 5 ---- .../compat/mojang/ChunkOcclusionData.java | 2 +- .../mojang/ChunkOcclusionDataBuilder.java | 3 ++- .../angelica/compat/mojang/ColorResolver.java | 8 ------- .../compat/mojang/DefaultVertexFormat.java | 1 + .../angelica/compat/mojang/DrawState.java | 1 + .../angelica/compat/mojang/FluidState.java | 1 + .../angelica/compat/mojang/GLHelper.java | 18 --------------- .../angelica/compat/mojang/GameRenderer.java | 1 + .../angelica/compat/mojang/IdList.java | 1 + .../compat/mojang/IndexedIterable.java | 1 + .../compat/mojang/InteractionHand.java | 1 + .../compat/mojang/ItemColorProvider.java | 7 ------ .../angelica/compat/mojang/LevelRenderer.java | 6 ----- .../compat/mojang/LightingProvider.java | 10 -------- .../angelica/compat/mojang/LightingView.java | 9 -------- .../angelica/compat/mojang/MatrixStack.java | 1 + .../angelica/compat/mojang/ModelLoader.java | 9 -------- .../compat/mojang/MultiBufferSource.java | 1 + .../compat/mojang/OverlayTexture.java | 1 + .../compat/mojang/OverlayVertexConsumer.java | 1 + .../compat/mojang/PackedIntegerArray.java | 1 + .../angelica/compat/mojang/RenderLayer.java | 1 + .../angelica/compat/mojang/RenderLayers.java | 4 +--- .../angelica/compat/mojang/RenderPhase.java | 1 + .../angelica/compat/mojang/SideShapeType.java | 1 + .../angelica/compat/mojang/TextureAtlas.java | 1 + .../angelica/compat/mojang/VertexBuffer.java | 1 + .../compat/mojang/VertexConsumer.java | 1 + .../compat/mojang/VertexConsumerProvider.java | 1 + .../compat/mojang/VertexConsumers.java | 1 + .../angelica/compat/mojang/VertexFormat.java | 3 +++ .../compat/mojang/VertexFormatElement.java | 1 + .../angelica/compat/mojang/VoxelShape.java | 1 + .../angelica/compat/mojang/VoxelShapes.java | 1 + .../compat/mojang/WorldRendererExt.java | 5 ---- .../early/shaders/MixinEntityRenderer.java | 2 +- .../early/sodium/MixinRenderGlobal.java | 2 +- .../light/cache/ArrayLightDataCache.java | 2 +- .../client/render/SodiumWorldRenderer.java | 4 ++-- .../render/chunk/ChunkRenderContainer.java | 2 +- .../render/chunk/ChunkRenderManager.java | 4 ++-- .../multidraw/ChunkDrawCallBatcher.java | 2 +- .../client/render/chunk/cull/ChunkCuller.java | 2 +- .../chunk/cull/graph/ChunkGraphCuller.java | 7 ++---- .../render/chunk/data/ChunkRenderBounds.java | 2 +- .../chunk/region/ChunkRegionManager.java | 2 +- .../mods/sodium/client/world/WorldSlice.java | 8 ++----- .../world/cloned/ChunkRenderContext.java | 2 +- .../world/cloned/ClonedChunkSection.java | 3 +-- .../world/cloned/ClonedChunkSectionCache.java | 2 +- .../DeferredWorldRenderingPipeline.java | 2 +- .../FixedFunctionWorldRenderingPipeline.java | 2 +- .../coderbot/iris/pipeline/HandRenderer.java | 2 +- .../iris/pipeline/ShadowRenderer.java | 2 +- .../iris/pipeline/WorldRenderingPipeline.java | 2 +- .../iris/postprocess/CompositeRenderer.java | 17 ++++++-------- .../iris/postprocess/FinalPassRenderer.java | 2 +- .../postprocess/FullScreenQuadRenderer.java | 4 ++-- .../NativeImageBackedCustomTexture.java | 2 +- .../NativeImageBackedNoiseTexture.java | 2 +- .../NativeImageBackedSingleColorTexture.java | 2 +- .../coderbot/iris/shadow/ShadowMatrices.java | 2 +- .../mipmap/AbstractMipmapGenerator.java | 2 +- .../mipmap/ChannelMipmapGenerator.java | 2 +- .../texture/mipmap/CustomMipmapGenerator.java | 2 +- .../texture/util/ImageManipulationUtil.java | 2 +- .../iris/texture/util/TextureExporter.java | 2 +- .../iris/uniforms/CelestialUniforms.java | 2 +- 90 files changed, 120 insertions(+), 148 deletions(-) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => }/Camera.java (93%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => }/ChunkPos.java (58%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => }/ChunkSectionPos.java (92%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => }/CompatMathHelper.java (92%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => }/Constants.java (67%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => }/NativeImage.java (96%) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkCuller.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/GLHelper.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ItemColorProvider.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/LevelRenderer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingProvider.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingView.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/ModelLoader.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java b/src/main/java/com/gtnewhorizons/angelica/compat/Camera.java similarity index 93% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java rename to src/main/java/com/gtnewhorizons/angelica/compat/Camera.java index 49fb42d7d..88969231f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/Camera.java @@ -1,5 +1,6 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import lombok.Getter; import net.minecraft.client.Minecraft; import net.minecraft.entity.EntityLivingBase; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/ChunkPos.java similarity index 58% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java rename to src/main/java/com/gtnewhorizons/angelica/compat/ChunkPos.java index 1ea2651c1..afa801ae5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/ChunkPos.java @@ -1,6 +1,8 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat; -// ChunkCoordIntPair +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; + +// See if we can merge/mixin/extend ChunkCoordIntPair? public class ChunkPos { public static long INT_MASK = (1L << Integer.SIZE) - 1; @@ -37,4 +39,21 @@ public long toLong() { public static long toLong(int x, int z) { return (long)x & 4294967295L | ((long)z & 4294967295L) << 32; } + + public int hashCode() + { + int i = 1664525 * this.x + 1013904223; + int j = 1664525 * (this.z ^ -559038737) + 1013904223; + return i ^ j; + } + + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object instanceof ChunkPos lv) { + return this.x == lv.x && this.z == lv.z; + } + return false; + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/ChunkSectionPos.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java rename to src/main/java/com/gtnewhorizons/angelica/compat/ChunkSectionPos.java index 0feb82473..c20a2927a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/ChunkSectionPos.java @@ -1,8 +1,9 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import org.joml.Vector3i; -// ChunkPosition maybe? +// See if we can merge/mixin/extend ChunkPosition maybe? public class ChunkSectionPos extends Vector3i { public static int getSectionCoord(int coord) { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/CompatMathHelper.java b/src/main/java/com/gtnewhorizons/angelica/compat/CompatMathHelper.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/CompatMathHelper.java rename to src/main/java/com/gtnewhorizons/angelica/compat/CompatMathHelper.java index 1808502a3..a20ed75e3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/CompatMathHelper.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/CompatMathHelper.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat; public class CompatMathHelper { public static int smallestEncompassingPowerOfTwo(int value) { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Constants.java b/src/main/java/com/gtnewhorizons/angelica/compat/Constants.java similarity index 67% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/Constants.java rename to src/main/java/com/gtnewhorizons/angelica/compat/Constants.java index 2f1bd5ec6..04aa000ee 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Constants.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/Constants.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat; public class Constants { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java b/src/main/java/com/gtnewhorizons/angelica/compat/NativeImage.java similarity index 96% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java rename to src/main/java/com/gtnewhorizons/angelica/compat/NativeImage.java index 237d84993..3e4413216 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/NativeImage.java @@ -1,5 +1,6 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat; +import com.gtnewhorizons.angelica.compat.mojang.ByteBufferBackedInputStream; import lombok.Getter; import net.coderbot.iris.Iris; import org.lwjgl.BufferUtils; @@ -14,6 +15,7 @@ import java.nio.ByteBuffer; import java.nio.IntBuffer; +// TBD public class NativeImage extends BufferedImage { @Getter private final Format format; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java index 90f543a1a..dd3c9679e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java @@ -7,6 +7,7 @@ import java.io.IOException; +@Deprecated public abstract class AutoClosableAbstractTexture extends AbstractTexture implements AutoCloseable { public abstract void load(IResourceManager manager) throws IOException; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java index 1074e0a88..9d1dca10d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java @@ -2,6 +2,7 @@ import net.minecraftforge.common.util.ForgeDirection; +@Deprecated public enum Axis { X, Y, diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java index 1565feb3c..be0ef0d5f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Random; +@Deprecated public interface BakedModel extends IForgeBakedModel { List getQuads(BlockState state, ForgeDirection face, Random random); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java index 3eee1d139..87966cd1c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java @@ -3,6 +3,7 @@ import com.gtnewhorizons.angelica.compat.forge.VertexLighterFlat; import net.minecraftforge.common.util.ForgeDirection; +@Deprecated public class BakedQuad { public void pipe(VertexLighterFlat lighter) {} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java index a0f96c7d4..5c007e8c7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java @@ -2,6 +2,7 @@ import org.jetbrains.annotations.NotNull; +@Deprecated public class BlockBreakingInfo implements Comparable { @Override diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java index be8f69f79..4a432e064 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; +@Deprecated public class BlockModels { public BakedModel getModel(BlockState blockState) { return null; } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java index 83586a52d..0536347e6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockPos.java @@ -9,6 +9,7 @@ import static com.google.common.math.IntMath.log2; +// Should we keep this? public class BlockPos extends Vector3i { private static final int SIZE_BITS_X = 1 + log2(MathHelper.roundUpToPowerOfTwo(30000000), RoundingMode.UNNECESSARY); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java index aced71efd..186821165 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; +@Deprecated public enum BlockRenderType { INVISIBLE, ENTITYBLOCK_ANIMATED, diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java index 7a7f32840..deb8e93f1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java @@ -4,6 +4,7 @@ import net.minecraft.world.EnumSkyBlock; import net.minecraftforge.common.util.ForgeDirection; +@Deprecated public interface BlockRenderView extends BlockView { float getBrightness(ForgeDirection face, boolean shade); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java index 46238b871..874b26571 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java @@ -3,13 +3,11 @@ import com.gtnewhorizons.angelica.compat.forge.IForgeBlockState; import me.jellysquid.mods.sodium.common.util.WorldUtil; import net.minecraft.block.Block; -import net.minecraft.block.BlockLiquid; import net.minecraft.block.material.Material; import net.minecraftforge.common.util.ForgeDirection; -import net.minecraftforge.fluids.BlockFluidBase; -import net.minecraftforge.fluids.FluidRegistry; import org.joml.Vector3d; +@Deprecated public class BlockState implements IForgeBlockState { private final static Vector3d ZERO = new Vector3d(0, 0, 0); private final Block block; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java index 363712fbe..09109d8cd 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; +@Deprecated public interface BlockView { BlockState getBlockState(BlockPos adjPos); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java index cbf8fe9d4..3675b8058 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java @@ -9,6 +9,7 @@ import java.util.List; // This is the Tessellator - TODO: Merge/Overwrite +@Deprecated public class BufferBuilder implements VertexConsumer, BufferBuilderExt { private ByteBuffer buffer; private List vertexCounts; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java index 22c02ebbc..056cbae17 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java @@ -2,6 +2,7 @@ import java.util.SortedMap; +@Deprecated public class BufferBuilderStorage { private final SortedMap entityBuilders = null; private final VertexConsumerProvider.Immediate entityVertexConsumers; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java index 9322f68f2..eed8ab20d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java @@ -2,6 +2,7 @@ import java.util.Map; +@Deprecated public class BufferSource implements MultiBufferSource { public BufferSource(BufferBuilder bufferBuilder, Map kvMap) {} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java index 11269c996..8ac3f6b80 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java @@ -4,6 +4,7 @@ import java.io.InputStream; import java.nio.ByteBuffer; +@Deprecated public class ByteBufferBackedInputStream extends InputStream { ByteBuffer buf; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkCuller.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkCuller.java deleted file mode 100644 index 0a1e84b6d..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkCuller.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -public interface ChunkCuller { - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java index 34478aa08..e0d5b0c65 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java @@ -3,9 +3,9 @@ import net.minecraftforge.common.util.ForgeDirection; import java.util.BitSet; -import java.util.EnumSet; import java.util.Set; +@Deprecated public class ChunkOcclusionData { private static final int DIRECTION_COUNT = ForgeDirection.values().length; private final BitSet visibility; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java index f338b42cf..05a04b19e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java @@ -3,7 +3,6 @@ import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue; import it.unimi.dsi.fastutil.ints.IntPriorityQueue; import me.jellysquid.mods.sodium.common.util.DirectionUtil; -import net.minecraft.util.Util; import net.minecraftforge.common.util.ForgeDirection; import java.util.BitSet; @@ -13,6 +12,8 @@ /** * WARNING: Minecraft 1.16 code rip!! */ + +@Deprecated public class ChunkOcclusionDataBuilder { private static final int STEP_X = (int)Math.pow(16.0, 0.0); private static final int STEP_Z = (int)Math.pow(16.0, 1.0); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java deleted file mode 100644 index a0a2cba28..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ColorResolver.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import net.minecraft.world.biome.BiomeGenBase; - -public interface ColorResolver { - - int getColor(BiomeGenBase biome, int x, int z); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java index c6e126c4c..8faa3da21 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement.Type; import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement.Usage; +@Deprecated public class DefaultVertexFormat { public static final VertexFormatElement POSITION_ELEMENT = new VertexFormatElement(0, Type.FLOAT, Usage.POSITION, 3); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DrawState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DrawState.java index 0be23ade7..0aa8acbb9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DrawState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DrawState.java @@ -2,6 +2,7 @@ import lombok.Getter; +@Deprecated public class DrawState { @Getter private final VertexFormat format; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java index 2de6149ab..45d0e047f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java @@ -4,6 +4,7 @@ import net.minecraftforge.fluids.Fluid; import org.joml.Vector3d; +@Deprecated public class FluidState { private final Fluid fluid; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GLHelper.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GLHelper.java deleted file mode 100644 index 9a90b5c60..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GLHelper.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import net.minecraft.client.renderer.OpenGlHelper; - -public class GLHelper { - - public static void glDeleteFramebuffers(int framebuffer) { - OpenGlHelper.func_153174_h(framebuffer); - } - - public static int glCheckFramebufferStatus(int target) { - return OpenGlHelper.func_153167_i(target); - } - - public static int glGenFramebuffers() { - return OpenGlHelper.func_153165_e/*glGenFramebuffers*/(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java index 26523a9fa..098de5c2f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; +@Deprecated public class GameRenderer { public void invokeBobHurt(MatrixStack poseStack, float tickDelta) {} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java index 1e9b81115..57738b125 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java @@ -9,6 +9,7 @@ import java.util.Iterator; import java.util.List; +@Deprecated public class IdList implements IndexedIterable { protected int nextId; protected final IdentityHashMap idMap; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java index 75ea6d14a..1fecd5226 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java @@ -2,6 +2,7 @@ import javax.annotation.Nullable; +@Deprecated public interface IndexedIterable extends Iterable { int getRawId(T entry); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/InteractionHand.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/InteractionHand.java index 75af559a5..1361415b7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/InteractionHand.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/InteractionHand.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; +@Deprecated public enum InteractionHand { MAIN_HAND, OFF_HAND; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ItemColorProvider.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ItemColorProvider.java deleted file mode 100644 index 1779aca63..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ItemColorProvider.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import net.minecraft.item.ItemStack; - -public interface ItemColorProvider { - int getColor(ItemStack stack, int tintIndex); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LevelRenderer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LevelRenderer.java deleted file mode 100644 index af3781168..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LevelRenderer.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -public class LevelRenderer { - - public void invokeRenderChunkLayer(RenderLayer solid, MatrixStack modelView, double cameraX, double cameraY, double cameraZ) {} -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingProvider.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingProvider.java deleted file mode 100644 index 41ce17115..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingProvider.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -// LightingEngine from archaicfix/phosphor? -public class LightingProvider implements LightingView { - - @Override - public void setSectionStatus(ChunkSectionPos pos, boolean notReady) { - - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingView.java deleted file mode 100644 index 4e4778cfb..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/LightingView.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -public interface LightingView { - default void setSectionStatus(BlockPos pos, boolean notReady) { - this.setSectionStatus(ChunkSectionPos.from(pos), notReady); - } - - void setSectionStatus(ChunkSectionPos pos, boolean notReady); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java index fa695b453..0a52a40e4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java @@ -6,6 +6,7 @@ import java.util.Deque; +@Deprecated public class MatrixStack { private final Deque matrixStack; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ModelLoader.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ModelLoader.java deleted file mode 100644 index 5a8fbcae1..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ModelLoader.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import java.util.Collections; -import java.util.List; - -public class ModelLoader { - public static final List BLOCK_DESTRUCTION_RENDER_LAYERS = Collections.emptyList(); - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java index 6377c95a5..745f1c9b8 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java @@ -2,6 +2,7 @@ import java.util.Map; +@Deprecated public interface MultiBufferSource { static BufferSource immediateWithBuffers(Map map, BufferBuilder arg) { return new BufferSource(arg, map); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java index fd219461f..dce839dbd 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; +@Deprecated public class OverlayTexture { // This is definitely wrong diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java index 8b30554f3..6f185d545 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java @@ -4,6 +4,7 @@ import org.joml.Matrix3f; import org.joml.Matrix4f; +@Deprecated public class OverlayVertexConsumer implements VertexConsumer { public OverlayVertexConsumer(VertexConsumer buffer, Matrix4f model, Matrix3f normal) {} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java index 56115c5d4..254123d7f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; +@Deprecated public class PackedIntegerArray { public PackedIntegerArray(int paletteSize, int size, long[] storage) {} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java index aadac15ff..5594123bf 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java @@ -12,6 +12,7 @@ import java.util.Optional; import java.util.OptionalDouble; +@Deprecated public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris) private static final RenderLayer SOLID = of("solid", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 2097152, true, false, RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).build(true)); private static final RenderLayer CUTOUT_MIPPED = of("cutout_mipped", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 131072, true, false, RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).alpha(HALF_ALPHA).build(true)); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java index 13734edee..99590a273 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java @@ -1,11 +1,9 @@ package com.gtnewhorizons.angelica.compat.mojang; -import com.gtnewhorizons.angelica.mixins.early.sodium.MixinMaterial; import net.minecraft.block.Block; import net.minecraft.block.material.Material; -import net.minecraft.block.material.MaterialLiquid; -import net.minecraftforge.fluids.Fluid; +@Deprecated public class RenderLayers { public static boolean canRenderInLayer(BlockState state, RenderLayer layer) { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index 48490fa58..54874ef74 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -14,6 +14,7 @@ import java.util.OptionalDouble; +@Deprecated public abstract class RenderPhase { protected final String name; protected Runnable beginAction; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java index 92d526124..53dc98ecd 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; +@Deprecated public enum SideShapeType { FULL, CENTER, diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java index 4615a3140..21547fe3d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java @@ -5,6 +5,7 @@ import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourceManagerReloadListener; +@Deprecated public abstract class TextureAtlas extends AbstractTexture implements ITickable, IResourceManagerReloadListener { @Override diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java index 8a7d0661b..797897074 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java @@ -6,6 +6,7 @@ import java.nio.ByteBuffer; import java.nio.FloatBuffer; +@Deprecated public class VertexBuffer implements AutoCloseable { private int id; private int vertexCount; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java index 7ec104359..cc93669be 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java @@ -4,6 +4,7 @@ import javax.annotation.Nonnull; +@Deprecated public interface VertexConsumer extends IForgeVertexBuilder { VertexConsumer vertex(double d, double e, double f); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java index 138c5bebf..cb5124361 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java @@ -9,6 +9,7 @@ import java.util.Optional; import java.util.Set; +@Deprecated public interface VertexConsumerProvider { static Immediate immediate(BufferBuilder buffer) { return immediate(ImmutableMap.of(), buffer); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java index 5d6f638b5..78d0b8a3e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; +@Deprecated public class VertexConsumers { public static VertexConsumer union(VertexConsumer first, VertexConsumer second) { return new Dual(first, second); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java index a48e0042c..a28c2957a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java @@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.ints.IntList; import lombok.Getter; +@Deprecated public class VertexFormat { protected final ImmutableList elements; protected final IntList offsets = new IntArrayList(); @@ -21,8 +22,10 @@ public VertexFormat(ImmutableList elements) { vertexSize = i; } + @Deprecated public void setupBufferState(long l) {} + @Deprecated public void clearBufferState() {} } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java index a7561e989..e1d1ce286 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java @@ -7,6 +7,7 @@ import java.util.function.IntConsumer; +@Deprecated public class VertexFormatElement { @Getter protected final Type type; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java index 13fbb5c1a..3433c2ba6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; +@Deprecated public enum VoxelShape { FULL_CUBE(false), diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java index 4bcb26479..2ec1e4b5a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java @@ -2,6 +2,7 @@ import net.minecraftforge.common.util.ForgeDirection; +@Deprecated public final class VoxelShapes { public static VoxelShape fullCube() { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java deleted file mode 100644 index 36e679bfb..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/WorldRendererExt.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -public interface WorldRendererExt { - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index a9fc6d3aa..7472b7920 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -1,6 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.shaders; -import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.Camera; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Share; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 579b62ce1..7675c04de 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -1,6 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; -import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.Camera; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java index c7a445128..e15e960dd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.light.cache; -import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.ChunkSectionPos; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; import me.jellysquid.mods.sodium.client.world.WorldSlice; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 3c9f30ce5..c2f0201ed 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render; -import com.gtnewhorizons.angelica.compat.mojang.Camera; -import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; +import com.gtnewhorizons.angelica.compat.Camera; +import com.gtnewhorizons.angelica.compat.ChunkPos; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import com.gtnewhorizons.angelica.config.AngelicaConfig; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java index 3c9e1684e..fabb1298c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.ChunkSectionPos; import lombok.Getter; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 21e201600..2ff703613 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk; -import com.gtnewhorizons.angelica.compat.mojang.Camera; -import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; +import com.gtnewhorizons.angelica.compat.Camera; +import com.gtnewhorizons.angelica.compat.ChunkPos; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.config.AngelicaConfig; import it.unimi.dsi.fastutil.ints.IntIterator; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java index aeb88fbcf..a5fcbae6d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; -import com.gtnewhorizons.angelica.compat.mojang.CompatMathHelper; +import com.gtnewhorizons.angelica.compat.CompatMathHelper; import me.jellysquid.mods.sodium.client.SodiumClientMod; import org.lwjgl.MemoryUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java index c718516f4..317adad30 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.cull; -import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.Camera; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionData; import it.unimi.dsi.fastutil.ints.IntArrayList; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java index 876c34402..a24fa354f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java @@ -1,10 +1,9 @@ package me.jellysquid.mods.sodium.client.render.chunk.cull.graph; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.Camera; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionData; -import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.ChunkSectionPos; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -12,8 +11,6 @@ import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; import me.jellysquid.mods.sodium.common.util.DirectionUtil; import net.minecraft.block.Block; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import net.minecraft.util.MathHelper; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java index 4a06495ab..54430fd90 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.data; -import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.ChunkSectionPos; public class ChunkRenderBounds { public static final ChunkRenderBounds ALWAYS_FALSE = new ChunkRenderBounds(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java index 0b8845916..9dff791f8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.region; -import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.ChunkSectionPos; import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectIterator; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 4fb82730b..89d880b1f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -2,12 +2,8 @@ import java.util.Arrays; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; -import com.gtnewhorizons.angelica.compat.mojang.CompatMathHelper; -import com.gtnewhorizons.angelica.compat.mojang.FluidState; +import com.gtnewhorizons.angelica.compat.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.CompatMathHelper; import lombok.Getter; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSection; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java index 19dfd8d01..031188510 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.world.cloned; -import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.ChunkSectionPos; import net.minecraft.world.gen.structure.StructureBoundingBox; public class ChunkRenderContext { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 5819e3af5..4b591f40d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -2,12 +2,11 @@ import com.gtnewhorizons.angelica.compat.ExtendedBlockStorageExt; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.ChunkSectionPos; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import lombok.Getter; import net.minecraft.block.Block; -import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java index 3d2866520..48f358e1c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.world.cloned; -import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.ChunkSectionPos; import it.unimi.dsi.fastutil.longs.Long2ReferenceLinkedOpenHashMap; import net.minecraft.world.World; diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index d19e1d7c3..6245de3c8 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -3,7 +3,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Ints; -import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.Camera; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.Iris; diff --git a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java index efb429135..85968f8fe 100644 --- a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java @@ -1,6 +1,6 @@ package net.coderbot.iris.pipeline; -import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.Camera; import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; diff --git a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java index 320d4f0af..f642aaf73 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java @@ -1,7 +1,7 @@ package net.coderbot.iris.pipeline; import net.coderbot.batchedentityrendering.impl.FullyBufferedMultiBufferSource; -import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.Camera; import com.gtnewhorizons.angelica.compat.mojang.GameRenderer; import com.gtnewhorizons.angelica.compat.mojang.InteractionHand; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 77cc0ed05..283ce4847 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -2,7 +2,7 @@ import com.google.common.collect.ImmutableList; import com.gtnewhorizons.angelica.compat.mojang.BufferSource; -import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.Camera; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.rendering.RenderingState; diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java index 4dc2904f0..3167265fd 100644 --- a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java @@ -1,6 +1,6 @@ package net.coderbot.iris.pipeline; -import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.Camera; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; diff --git a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java index bdeba1eb7..09d5a8204 100644 --- a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java @@ -30,6 +30,7 @@ import net.coderbot.iris.uniforms.FrameUpdateNotifier; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.shader.Framebuffer; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; @@ -62,8 +63,7 @@ public CompositeRenderer(PackDirectives packDirectives, ProgramSource[] sources, this.customTextureIds = customTextureIds; final PackRenderTargetDirectives renderTargetDirectives = packDirectives.getRenderTargetDirectives(); - final Map renderTargetSettings = - renderTargetDirectives.getRenderTargetSettings(); + final Map renderTargetSettings = renderTargetDirectives.getRenderTargetSettings(); final ImmutableList.Builder passes = ImmutableList.builder(); final ImmutableSet.Builder flippedAtLeastOnce = new ImmutableSet.Builder<>(); @@ -205,21 +205,18 @@ protected void destroy() { } public void renderAll() { - GL11.glDisable(GL11.GL_BLEND); - GL11.glDisable(GL11.GL_ALPHA_TEST); + GLStateManager.disableBlend(); + GLStateManager.disableAlphaTest(); FullScreenQuadRenderer.INSTANCE.begin(); - final Minecraft mc = Minecraft.getMinecraft(); + for (Pass renderPass : passes) { boolean ranCompute = false; for (ComputeProgram computeProgram : renderPass.computes) { if (computeProgram != null) { ranCompute = true; - - // TODO: Iris -// com.mojang.blaze3d.pipeline.RenderTarget main = Minecraft.getMinecraft().getMainRenderTarget(); -// computeProgram.dispatch(main.width, main.height); - computeProgram.dispatch(mc.displayWidth, mc.displayHeight); + final Framebuffer main = Minecraft.getMinecraft().getFramebuffer(); + computeProgram.dispatch(main.framebufferWidth, main.framebufferHeight); } } diff --git a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java index 4b431bc8b..e68a7d472 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FinalPassRenderer.java @@ -170,7 +170,7 @@ public void renderFinalPass() { // // This is not a concern for depthtex1 / depthtex2 since the copy call extracts the depth values, and the // shader pack only ever uses them to read the depth values. - if (((IRenderTargetExt)main).iris$getColorBufferVersion() != lastColorTextureVersion) { + if (((IRenderTargetExt)main).iris$getColorBufferVersion() != lastColorTextureVersion || main.framebufferTexture != lastColorTextureId) { lastColorTextureVersion = ((IRenderTargetExt)main).iris$getColorBufferVersion(); this.lastColorTextureId = main.framebufferTexture; colorHolder.addColorAttachment(0, lastColorTextureId); diff --git a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java index f183630a6..b1fad6ba0 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java @@ -31,7 +31,7 @@ public void render() { @SuppressWarnings("deprecation") public void begin() { - GL11.glDisable(GL11.GL_DEPTH_TEST); + GLStateManager.disableDepthTest(); GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glPushMatrix(); @@ -59,7 +59,7 @@ public static void end() { DefaultVertexFormat.POSITION_TEXTURE.clearBufferState(); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); - GL11.glEnable(GL11.GL_DEPTH_TEST); + GLStateManager.enableDepthTest(); GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glPopMatrix(); diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java index 22d6e7f6d..9a92801ab 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java @@ -1,6 +1,6 @@ package net.coderbot.iris.rendertarget; -import com.gtnewhorizons.angelica.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.NativeImage; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.shaderpack.texture.CustomTextureData; import net.minecraft.client.renderer.texture.DynamicTexture; diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java index fbb7c232c..31cd216c8 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java @@ -1,6 +1,6 @@ package net.coderbot.iris.rendertarget; -import com.gtnewhorizons.angelica.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.NativeImage; import net.minecraft.client.renderer.texture.DynamicTexture; import org.lwjgl.opengl.GL11; diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java index 2671804d8..34d6ea970 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java @@ -1,6 +1,6 @@ package net.coderbot.iris.rendertarget; -import com.gtnewhorizons.angelica.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.NativeImage; import net.minecraft.client.renderer.texture.DynamicTexture; public class NativeImageBackedSingleColorTexture extends DynamicTexture { diff --git a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java index 63d7d557c..75f821149 100644 --- a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java +++ b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java @@ -5,7 +5,7 @@ import java.nio.FloatBuffer; -import static com.gtnewhorizons.angelica.compat.mojang.Constants.DEGREES_TO_RADIANS; +import static com.gtnewhorizons.angelica.compat.Constants.DEGREES_TO_RADIANS; public class ShadowMatrices { private static final float NEAR = 0.05f; diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java index 81d1e4ba8..e41cdfee8 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.mipmap; -import com.gtnewhorizons.angelica.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.NativeImage; public abstract class AbstractMipmapGenerator implements CustomMipmapGenerator { @Override diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java index dd92ad317..5e7f45699 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java @@ -1,5 +1,5 @@ package net.coderbot.iris.texture.mipmap; -import com.gtnewhorizons.angelica.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.NativeImage; public class ChannelMipmapGenerator extends AbstractMipmapGenerator { protected final BlendFunction redFunc; diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java index ace0d2aa2..918502422 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.mipmap; -import com.gtnewhorizons.angelica.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.NativeImage; public interface CustomMipmapGenerator { NativeImage[] generateMipLevels(NativeImage image, int mipLevel); diff --git a/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java b/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java index 365c56355..e4a7a0db0 100644 --- a/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java +++ b/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.util; -import com.gtnewhorizons.angelica.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.NativeImage; public class ImageManipulationUtil { public static NativeImage scaleNearestNeighbor(NativeImage image, int newWidth, int newHeight) { diff --git a/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java b/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java index 4a89d9583..e7bbdca1d 100644 --- a/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java +++ b/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java @@ -1,7 +1,7 @@ package net.coderbot.iris.texture.util; import com.gtnewhorizons.angelica.glsm.GLStateManager; -import com.gtnewhorizons.angelica.compat.mojang.NativeImage; +import com.gtnewhorizons.angelica.compat.NativeImage; import net.minecraft.client.Minecraft; import org.apache.commons.io.FilenameUtils; import org.lwjgl.opengl.GL11; diff --git a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java index 68db63e00..d669bb2c2 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java @@ -1,6 +1,6 @@ package net.coderbot.iris.uniforms; -import com.gtnewhorizons.angelica.compat.mojang.Constants; +import com.gtnewhorizons.angelica.compat.Constants; import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.gl.uniform.UniformHolder; import net.minecraft.client.Minecraft; From 5a20e7ade6946cd55d94344871e286e0b1e95448 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 6 Dec 2023 09:32:14 -0800 Subject: [PATCH 223/301] Don't try to transform the server --- .../angelica/loading/MixinCompatHackTweaker.java | 7 +++++-- .../angelica/mixins/early/shaders/MixinEntityRenderer.java | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java index a56f62985..933846856 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java @@ -2,6 +2,7 @@ import com.gtnewhorizons.angelica.transform.RedirectorTransformer; import cpw.mods.fml.common.Loader; +import cpw.mods.fml.relauncher.FMLLaunchHandler; import net.minecraft.launchwrapper.IClassTransformer; import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.Launch; @@ -70,8 +71,10 @@ public String getLaunchTarget() { @Override public String[] getLaunchArguments() { - // Run after Mixins, but before LWJGl3ify - Launch.classLoader.registerTransformer(RedirectorTransformer.class.getName()); + if (FMLLaunchHandler.side().isClient()) { + // Run after Mixins, but before LWJGl3ify + Launch.classLoader.registerTransformer(RedirectorTransformer.class.getName()); + } return new String[0]; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index 7472b7920..a3577a5a4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -25,7 +25,7 @@ @Mixin(EntityRenderer.class) public abstract class MixinEntityRenderer implements IResourceManagerReloadListener { - @Inject(at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glClear(I)V", shift = At.Shift.AFTER, ordinal = 0), method = "renderWorld(FJ)V") + @Inject(at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glClear(I)V", shift = At.Shift.AFTER, ordinal = 0), method = "renderWorld(FJ)V", remap = false) private void iris$beginRender(float partialTicks, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { CapturedRenderingState.INSTANCE.setTickDelta(partialTicks); SystemTimeUniforms.COUNTER.beginFrame(); From 86fc24660113195050a35fcd6794722c5e574f12 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 6 Dec 2023 12:42:41 -0500 Subject: [PATCH 224/301] Avoid running biome generator on client in singleplayer --- .../gtnewhorizons/angelica/mixins/Mixins.java | 2 + .../mixins/early/sodium/MixinChunk.java | 45 +++++++++++++++++++ .../sodium/MixinChunkProviderServer.java | 26 +++++++++++ 3 files changed, 73 insertions(+) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunk.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderServer.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 3034b6aff..5f744c716 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -76,6 +76,8 @@ public enum Mixins { .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodium).addMixinClasses( "sodium.MixinChunkProviderClient" ,"sodium.MixinBlock" + ,"sodium.MixinChunk" + ,"sodium.MixinChunkProviderServer" ,"sodium.MixinEntity" ,"sodium.MixinRenderManager" ,"sodium.MixinExtendedBlockStorage" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunk.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunk.java new file mode 100644 index 000000000..a24700e24 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunk.java @@ -0,0 +1,45 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import net.minecraft.client.Minecraft; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.biome.WorldChunkManager; +import net.minecraft.world.chunk.Chunk; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Chunk.class) +public abstract class MixinChunk { + @Shadow + public World worldObj; + + @Shadow + private byte[] blockBiomeArray; + + @Shadow + @Final + public int xPosition, zPosition; + + @Inject(method = "fillChunk", at = @At("RETURN")) + private void sodium$populateBiomes(CallbackInfo ci) { + if(this.worldObj.isRemote && !Minecraft.getMinecraft().isSingleplayer()) { + // We are in multiplayer, the server might not have sent all biomes to the client. + // Populate them now while we're on the main thread. + WorldChunkManager manager = this.worldObj.getWorldChunkManager(); + for(int z = 0; z < 16; z++) { + for(int x = 0; x < 16; x++) { + int idx = (z << 4) + x; + int biome = this.blockBiomeArray[idx] & 255; + if(biome == 255) { + BiomeGenBase generated = manager.getBiomeGenAt((this.xPosition << 4) + x, (this.zPosition << 4) + z); + this.blockBiomeArray[idx] = (byte)(generated.biomeID & 255); + } + } + } + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderServer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderServer.java new file mode 100644 index 000000000..83edd75c6 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinChunkProviderServer.java @@ -0,0 +1,26 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import net.minecraft.world.biome.WorldChunkManager; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.gen.ChunkProviderServer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ChunkProviderServer.class) +public class MixinChunkProviderServer { + @Redirect(method = "originalLoadChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/chunk/IChunkProvider;provideChunk(II)Lnet/minecraft/world/chunk/Chunk;", remap = true), remap = false) + private Chunk sodium$populateChunkWithBiomes(IChunkProvider instance, int chunkX, int chunkZ) { + Chunk chunk = instance.provideChunk(chunkX, chunkZ); + if(chunk != null) { + WorldChunkManager manager = chunk.worldObj.getWorldChunkManager(); + for(int z = 0; z < 16; z++) { + for(int x = 0; x < 16; x++) { + chunk.getBiomeGenForWorldCoords(x, z, manager); + } + } + } + return chunk; + } +} From 254616fdfa37e63a8206273363605fd4787f3733 Mon Sep 17 00:00:00 2001 From: mist475 <70655895+mist475@users.noreply.github.com> Date: Wed, 6 Dec 2023 18:46:17 +0100 Subject: [PATCH 225/301] Call world biome retrieval methods instead of copying array directly (#25) --- .../mods/sodium/client/world/WorldSlice.java | 9 ++++----- .../client/world/cloned/ClonedChunkSection.java | 11 +++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 89d880b1f..fcc4edff9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -68,7 +68,7 @@ public class WorldSlice implements IBlockAccess { private ClonedChunkSection[] sections; // Biome data for each chunk section - private byte[][] biomeData; + private BiomeGenBase[][] biomeData; // The starting point from which this slice captures blocks private int baseX, baseY, baseZ; @@ -126,7 +126,7 @@ public WorldSlice(WorldClient world) { this.sections = new ClonedChunkSection[SECTION_TABLE_ARRAY_SIZE]; this.blockArrays = new Block[SECTION_TABLE_ARRAY_SIZE][]; this.metadataArrays = new int[SECTION_TABLE_ARRAY_SIZE][]; - this.biomeData = new byte[SECTION_TABLE_ARRAY_SIZE][]; + this.biomeData = new BiomeGenBase[SECTION_TABLE_ARRAY_SIZE][]; for (int x = 0; x < SECTION_LENGTH; x++) { for (int y = 0; y < SECTION_LENGTH; y++) { @@ -210,9 +210,8 @@ public BiomeGenBase getBiomeGenForCoords(int x, int z) { int relY = 0; int relZ = z - this.baseZ; - final int k = this.biomeData[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] - [(x & 15) | (z & 15) << 4] & 255; - BiomeGenBase biome = BiomeGenBase.getBiome(k); + BiomeGenBase biome = this.biomeData[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] + [(x & 15) | (z & 15) << 4]; // can be null if biome wasn't generated yet return biome == null ? BiomeGenBase.plains : biome; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 4b591f40d..46b37d7e9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -15,7 +15,6 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraft.world.gen.structure.StructureBoundingBox; -import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; public class ClonedChunkSection { @@ -33,7 +32,7 @@ public class ClonedChunkSection { private ChunkSectionPos pos; @Getter - private byte[] biomeData; + private BiomeGenBase[] biomeData; private long lastUsedTimestamp = Long.MAX_VALUE; @@ -59,13 +58,13 @@ public void init(ChunkSectionPos pos) { this.pos = pos; this.data = new ExtendedBlockStorageExt(section); - this.biomeData = Arrays.copyOf(chunk.getBiomeArray(), chunk.getBiomeArray().length); + this.biomeData = new BiomeGenBase[chunk.getBiomeArray().length]; StructureBoundingBox box = new StructureBoundingBox(pos.getMinX(), pos.getMinY(), pos.getMinZ(), pos.getMaxX(), pos.getMaxY(), pos.getMaxZ()); this.tileEntities.clear(); - // Check for tile entities + // Check for tile entities & fill biome data for(int y = pos.getMinY(); y <= pos.getMaxY(); y++) { for(int z = pos.getMinZ(); z <= pos.getMaxZ(); z++) { for(int x = pos.getMinX(); x <= pos.getMaxX(); x++) { @@ -82,6 +81,7 @@ public void init(ChunkSectionPos pos) { this.tileEntities.put(ChunkSectionPos.packLocal(new BlockPos(tileentity.xCoord & 15, tileentity.yCoord & 15, tileentity.zCoord & 15)), tileentity); } } + this.biomeData[(lZ << 4) | lX] = world.getBiomeGenForCoords(x, z); } } } @@ -105,8 +105,7 @@ public int getLightLevel(EnumSkyBlock type, int x, int y, int z) { } public BiomeGenBase getBiomeForNoiseGen(int x, int y, int z) { - int k = this.biomeData[x | z << 4] & 255; - return BiomeGenBase.getBiome(k); + return this.biomeData[x | z << 4]; } From dbd8ef7d5e551601a459d92f03263d5406d77962 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 6 Dec 2023 16:23:03 -0800 Subject: [PATCH 226/301] Misc cleanup --- .../compat/ExtendedBlockStorageExt.java | 1 - .../mixins/early/sodium/MixinMinecraft.java | 1 - .../java/jss/notfine/gui/GuiCustomMenu.java | 10 ---- .../notfine/gui/NotFineGameOptionPages.java | 1 - .../element/NotFineControlElement.java | 1 - .../jss/util/RandomXoshiro256StarStar.java | 1 - .../client/gl/state/GlStateTracker.java | 1 - .../sodium/client/gui/SodiumGameOptions.java | 3 -- .../model/light/cache/HashLightDataCache.java | 1 - .../quad/properties/ModelQuadFacing.java | 50 +++++++------------ .../chunk/tasks/ChunkRenderRebuildTask.java | 1 - .../context/ChunkRenderCacheShared.java | 1 - .../sodium/common/util/DirectionUtil.java | 6 --- .../iris/gl/texture/DepthBufferFormat.java | 22 ++++---- .../iris/pipeline/CustomTextureManager.java | 18 +++---- .../pipeline/transform/PatchShaderType.java | 16 +++--- .../coderbot/iris/shaderpack/ProgramSet.java | 50 +++++++++---------- .../iris/shaderpack/texture/TextureStage.java | 22 +++----- .../frustum/CullEverythingFrustum.java | 1 - 19 files changed, 74 insertions(+), 133 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java index b631b93d0..5d636b3d5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java @@ -4,7 +4,6 @@ import com.gtnewhorizons.angelica.mixins.early.sodium.MixinExtendedBlockStorage; import com.gtnewhorizons.angelica.mixins.interfaces.ExtendedNibbleArray; import com.gtnewhorizons.neid.mixins.interfaces.IExtendedBlockStorageMixin; -import cpw.mods.fml.common.Optional; import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java index 269edd32e..3be2c920c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinMinecraft.java @@ -1,6 +1,5 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; -import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; import me.jellysquid.mods.sodium.client.SodiumClientMod; import net.minecraft.client.Minecraft; diff --git a/src/main/java/jss/notfine/gui/GuiCustomMenu.java b/src/main/java/jss/notfine/gui/GuiCustomMenu.java index ff8e7ea92..494efa4e5 100644 --- a/src/main/java/jss/notfine/gui/GuiCustomMenu.java +++ b/src/main/java/jss/notfine/gui/GuiCustomMenu.java @@ -1,11 +1,7 @@ package jss.notfine.gui; -import jss.notfine.core.Settings; -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; import me.jellysquid.mods.sodium.client.gui.options.OptionPage; import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiListExtended; import net.minecraft.client.gui.GuiScreen; @@ -13,13 +9,7 @@ import net.minecraft.client.resources.I18n; import org.lwjgl.input.Keyboard; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; import java.util.HashSet; -import java.util.List; -import java.util.stream.Stream; public class GuiCustomMenu extends GuiScreen { public static GuiCustomMenu instance; diff --git a/src/main/java/jss/notfine/gui/NotFineGameOptionPages.java b/src/main/java/jss/notfine/gui/NotFineGameOptionPages.java index a3789c89b..894cbe819 100644 --- a/src/main/java/jss/notfine/gui/NotFineGameOptionPages.java +++ b/src/main/java/jss/notfine/gui/NotFineGameOptionPages.java @@ -20,7 +20,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.resources.I18n; import net.minecraft.client.settings.GameSettings; -import net.minecraft.util.MathHelper; import org.lwjgl.opengl.Display; import java.util.ArrayList; diff --git a/src/main/java/jss/notfine/gui/options/control/element/NotFineControlElement.java b/src/main/java/jss/notfine/gui/options/control/element/NotFineControlElement.java index 434d7136e..87913ab61 100644 --- a/src/main/java/jss/notfine/gui/options/control/element/NotFineControlElement.java +++ b/src/main/java/jss/notfine/gui/options/control/element/NotFineControlElement.java @@ -1,6 +1,5 @@ package jss.notfine.gui.options.control.element; -import jss.notfine.core.Settings; import jss.notfine.gui.GuiCustomMenu; import me.jellysquid.mods.sodium.client.gui.options.Option; import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; diff --git a/src/main/java/jss/util/RandomXoshiro256StarStar.java b/src/main/java/jss/util/RandomXoshiro256StarStar.java index ff86643c3..a63fe8f31 100644 --- a/src/main/java/jss/util/RandomXoshiro256StarStar.java +++ b/src/main/java/jss/util/RandomXoshiro256StarStar.java @@ -8,7 +8,6 @@ package jss.util; -import java.io.IOException; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java index 1358ba1b9..010b8fc86 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/state/GlStateTracker.java @@ -3,7 +3,6 @@ import me.jellysquid.mods.sodium.client.gl.array.GlVertexArray; import me.jellysquid.mods.sodium.client.gl.buffer.GlBuffer; import me.jellysquid.mods.sodium.client.gl.buffer.GlBufferTarget; -import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL30; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 6c3aef180..846830fdb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -6,9 +6,6 @@ import com.google.gson.JsonSyntaxException; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsQuality; -import me.jellysquid.mods.sodium.client.gui.options.named.NamedState; -import net.minecraft.client.Minecraft; - import java.io.FileReader; import java.io.IOException; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java index 89b59f3e7..275886426 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/HashLightDataCache.java @@ -1,7 +1,6 @@ package me.jellysquid.mods.sodium.client.model.light.cache; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import it.unimi.dsi.fastutil.longs.Long2LongLinkedOpenHashMap; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; import me.jellysquid.mods.sodium.client.world.WorldSlice; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index c2d04f5ab..881a1b990 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -16,22 +16,15 @@ public enum ModelQuadFacing { public static final int COUNT = VALUES.length; public static ModelQuadFacing fromDirection(ForgeDirection dir) { - switch (dir) { - case DOWN: - return DOWN; - case UP: - return UP; - case NORTH: - return NORTH; - case SOUTH: - return SOUTH; - case WEST: - return WEST; - case EAST: - return EAST; - default: - return UNASSIGNED; - } + return switch (dir) { + case DOWN -> DOWN; + case UP -> UP; + case NORTH -> NORTH; + case SOUTH -> SOUTH; + case WEST -> WEST; + case EAST -> EAST; + default -> UNASSIGNED; + }; } public static ModelQuadFacing fromVector(Vector3f normal) { @@ -60,21 +53,14 @@ public static ModelQuadFacing fromVector(Vector3f normal) { } public ModelQuadFacing getOpposite() { - switch (this) { - case UP: - return DOWN; - case DOWN: - return UP; - case EAST: - return WEST; - case WEST: - return EAST; - case SOUTH: - return NORTH; - case NORTH: - return SOUTH; - default: - return UNASSIGNED; - } + return switch (this) { + case UP -> DOWN; + case DOWN -> UP; + case EAST -> WEST; + case WEST -> EAST; + case SOUTH -> NORTH; + case NORTH -> SOUTH; + default -> UNASSIGNED; + }; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 800db1c8c..6af457ff9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -26,7 +26,6 @@ import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; -import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraftforge.fluids.IFluidBlock; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java index 9eff8c618..aafa2a19c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java @@ -1,6 +1,5 @@ package me.jellysquid.mods.sodium.client.render.pipeline.context; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import me.jellysquid.mods.sodium.client.model.light.cache.HashLightDataCache; import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java b/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java index 84c709f58..be03e7245 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/DirectionUtil.java @@ -1,13 +1,7 @@ package me.jellysquid.mods.sodium.common.util; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraftforge.common.util.ForgeDirection; -import javax.annotation.Nullable; -import java.util.Arrays; -import java.util.stream.Collectors; - /** * Contains a number of cached arrays to avoid allocations since calling Enum#values() requires the backing array to * be cloned every time. diff --git a/src/main/java/net/coderbot/iris/gl/texture/DepthBufferFormat.java b/src/main/java/net/coderbot/iris/gl/texture/DepthBufferFormat.java index d0e9316d4..6b06c2472 100644 --- a/src/main/java/net/coderbot/iris/gl/texture/DepthBufferFormat.java +++ b/src/main/java/net/coderbot/iris/gl/texture/DepthBufferFormat.java @@ -23,17 +23,17 @@ public enum DepthBufferFormat { @Nullable public static DepthBufferFormat fromGlEnum(int glenum) { - switch (glenum) { - case GL11.GL_DEPTH_COMPONENT: return DepthBufferFormat.DEPTH; - case GL14.GL_DEPTH_COMPONENT16: return DepthBufferFormat.DEPTH16; - case GL14.GL_DEPTH_COMPONENT24: return DepthBufferFormat.DEPTH24; - case GL14.GL_DEPTH_COMPONENT32: return DepthBufferFormat.DEPTH32; - case GL30.GL_DEPTH_COMPONENT32F: return DepthBufferFormat.DEPTH32F; - case GL30.GL_DEPTH_STENCIL: return DepthBufferFormat.DEPTH_STENCIL; - case GL30.GL_DEPTH24_STENCIL8: return DepthBufferFormat.DEPTH24_STENCIL8; - case GL30.GL_DEPTH32F_STENCIL8: return DepthBufferFormat.DEPTH32F_STENCIL8; - default: return null; - } + return switch (glenum) { + case GL11.GL_DEPTH_COMPONENT -> DepthBufferFormat.DEPTH; + case GL14.GL_DEPTH_COMPONENT16 -> DepthBufferFormat.DEPTH16; + case GL14.GL_DEPTH_COMPONENT24 -> DepthBufferFormat.DEPTH24; + case GL14.GL_DEPTH_COMPONENT32 -> DepthBufferFormat.DEPTH32; + case GL30.GL_DEPTH_COMPONENT32F -> DepthBufferFormat.DEPTH32F; + case GL30.GL_DEPTH_STENCIL -> DepthBufferFormat.DEPTH_STENCIL; + case GL30.GL_DEPTH24_STENCIL8 -> DepthBufferFormat.DEPTH24_STENCIL8; + case GL30.GL_DEPTH32F_STENCIL8 -> DepthBufferFormat.DEPTH32F_STENCIL8; + default -> null; + }; } public static DepthBufferFormat fromGlEnumOrDefault(int glenum) { diff --git a/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java b/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java index 69a9cd0a4..a56b7d716 100644 --- a/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java +++ b/src/main/java/net/coderbot/iris/pipeline/CustomTextureManager.java @@ -131,19 +131,13 @@ else if (textureData instanceof CustomTextureData.ResourceData) { if (texture != null) { int id = texture.getGlTextureId(); PBRTextureHolder pbrHolder = PBRTextureManager.INSTANCE.getOrLoadHolder(id); - AbstractTexture pbrTexture; - switch (pbrType) { - case NORMAL: - pbrTexture = pbrHolder.getNormalTexture(); - break; - case SPECULAR: - pbrTexture = pbrHolder.getSpecularTexture(); - break; - default: - throw new Error("Unknown PBRType '" + pbrType + "'"); - } + AbstractTexture pbrTexture = switch (pbrType) { + case NORMAL -> pbrHolder.getNormalTexture(); + case SPECULAR -> pbrHolder.getSpecularTexture(); + default -> throw new Error("Unknown PBRType '" + pbrType + "'"); + }; - TextureFormat textureFormat = TextureFormatLoader.getFormat(); + TextureFormat textureFormat = TextureFormatLoader.getFormat(); if (textureFormat != null) { int previousBinding = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, pbrTexture.getGlTextureId()); diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/PatchShaderType.java b/src/main/java/net/coderbot/iris/pipeline/transform/PatchShaderType.java index 7c0357706..d11797dba 100644 --- a/src/main/java/net/coderbot/iris/pipeline/transform/PatchShaderType.java +++ b/src/main/java/net/coderbot/iris/pipeline/transform/PatchShaderType.java @@ -14,15 +14,11 @@ private PatchShaderType(ShaderType glShaderType) { } public static PatchShaderType[] fromGlShaderType(ShaderType glShaderType) { - switch (glShaderType) { - case VERTEX: - return new PatchShaderType[] { VERTEX }; - case GEOMETRY: - return new PatchShaderType[] { GEOMETRY }; - case FRAGMENT: - return new PatchShaderType[] { FRAGMENT }; - default: - throw new IllegalArgumentException("Unknown shader type: " + glShaderType); - } + return switch (glShaderType) { + case VERTEX -> new PatchShaderType[] { VERTEX }; + case GEOMETRY -> new PatchShaderType[] { GEOMETRY }; + case FRAGMENT -> new PatchShaderType[] { FRAGMENT }; + default -> throw new IllegalArgumentException("Unknown shader type: " + glShaderType); + }; } } diff --git a/src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java b/src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java index d8b32f9f2..ca6d01a7f 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java +++ b/src/main/java/net/coderbot/iris/shaderpack/ProgramSet.java @@ -336,31 +336,31 @@ public Optional getGbuffersHand() { } public Optional get(ProgramId programId) { - switch (programId) { - case Shadow: return getShadow(); - case Basic: return getGbuffersBasic(); - case Line: return gbuffersLine.requireValid(); - case Textured: return getGbuffersTextured(); - case TexturedLit: return getGbuffersTexturedLit(); - case SkyBasic: return getGbuffersSkyBasic(); - case SkyTextured: return getGbuffersSkyTextured(); - case Clouds: return getGbuffersClouds(); - case Terrain: return getGbuffersTerrain(); - case DamagedBlock: return getGbuffersDamagedBlock(); - case Block: return getGbuffersBlock(); - case BeaconBeam: return getGbuffersBeaconBeam(); - case Entities: return getGbuffersEntities(); - case EntitiesTrans: return getGbuffersEntitiesTrans(); - case EntitiesGlowing: return getGbuffersEntitiesGlowing(); - case ArmorGlint: return getGbuffersGlint(); - case SpiderEyes: return getGbuffersEntityEyes(); - case Hand: return getGbuffersHand(); - case Weather: return getGbuffersWeather(); - case Water: return getGbuffersWater(); - case HandWater: return getGbuffersHandWater(); - case Final: return getCompositeFinal(); - default: return Optional.empty(); - } + return switch (programId) { + case Shadow -> getShadow(); + case Basic -> getGbuffersBasic(); + case Line -> gbuffersLine.requireValid(); + case Textured -> getGbuffersTextured(); + case TexturedLit -> getGbuffersTexturedLit(); + case SkyBasic -> getGbuffersSkyBasic(); + case SkyTextured -> getGbuffersSkyTextured(); + case Clouds -> getGbuffersClouds(); + case Terrain -> getGbuffersTerrain(); + case DamagedBlock -> getGbuffersDamagedBlock(); + case Block -> getGbuffersBlock(); + case BeaconBeam -> getGbuffersBeaconBeam(); + case Entities -> getGbuffersEntities(); + case EntitiesTrans -> getGbuffersEntitiesTrans(); + case EntitiesGlowing -> getGbuffersEntitiesGlowing(); + case ArmorGlint -> getGbuffersGlint(); + case SpiderEyes -> getGbuffersEntityEyes(); + case Hand -> getGbuffersHand(); + case Weather -> getGbuffersWeather(); + case Water -> getGbuffersWater(); + case HandWater -> getGbuffersHandWater(); + case Final -> getCompositeFinal(); + default -> Optional.empty(); + }; } public ProgramSource[] getDeferred() { diff --git a/src/main/java/net/coderbot/iris/shaderpack/texture/TextureStage.java b/src/main/java/net/coderbot/iris/shaderpack/texture/TextureStage.java index 687f7e178..3fe872988 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/texture/TextureStage.java +++ b/src/main/java/net/coderbot/iris/shaderpack/texture/TextureStage.java @@ -29,19 +29,13 @@ public enum TextureStage { COMPOSITE_AND_FINAL; public static Optional parse(String name) { - switch (name) { - case "shadowcomp": - return Optional.of(SHADOWCOMP); - case "prepare": - return Optional.of(PREPARE); - case "gbuffers": - return Optional.of(GBUFFERS_AND_SHADOW); - case "deferred": - return Optional.of(DEFERRED); - case "composite": - return Optional.of(COMPOSITE_AND_FINAL); - default: - return Optional.empty(); - } + return switch (name) { + case "shadowcomp" -> Optional.of(SHADOWCOMP); + case "prepare" -> Optional.of(PREPARE); + case "gbuffers" -> Optional.of(GBUFFERS_AND_SHADOW); + case "deferred" -> Optional.of(DEFERRED); + case "composite" -> Optional.of(COMPOSITE_AND_FINAL); + default -> Optional.empty(); + }; } } diff --git a/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java b/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java index 7f17cf0d4..8cbef5a5c 100644 --- a/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java +++ b/src/main/java/net/coderbot/iris/shadows/frustum/CullEverythingFrustum.java @@ -2,7 +2,6 @@ import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.util.AxisAlignedBB; -import org.joml.Matrix4f; public class CullEverythingFrustum extends Frustrum { From 4b3e1425c71278b9857a306181ce16b5dc51af07 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 6 Dec 2023 16:55:05 -0800 Subject: [PATCH 227/301] No more running client things on the server * Why would someone run Angelica on a server? --- .../gtnewhorizons/angelica/AngelicaMod.java | 3 +- .../angelica/proxy/ClientProxy.java | 12 +++-- .../angelica/proxy/CommonProxy.java | 3 +- src/main/java/jss/notfine/NotFine.java | 36 ++++++-------- src/main/java/jss/notfine/core/Settings.java | 3 ++ .../java/jss/notfine/proxy/ClientProxy.java | 44 +++++++++++++++++ .../java/jss/notfine/proxy/CommonProxy.java | 16 ++++++ .../mods/sodium/client/SodiumClientMod.java | 48 +++++++++--------- .../mods/sodium/proxy/ClientProxy.java | 49 +++++++++++++++++++ .../mods/sodium/proxy/CommonProxy.java | 16 ++++++ 10 files changed, 176 insertions(+), 54 deletions(-) create mode 100644 src/main/java/jss/notfine/proxy/ClientProxy.java create mode 100644 src/main/java/jss/notfine/proxy/CommonProxy.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/proxy/ClientProxy.java create mode 100644 src/main/java/me/jellysquid/mods/sodium/proxy/CommonProxy.java diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index 89938449b..8a35c0905 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -5,6 +5,7 @@ import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.SidedProxy; import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; @Mod( @@ -32,7 +33,7 @@ public void init(FMLInitializationEvent event) { } @Mod.EventHandler - public void postInit(FMLInitializationEvent event) { + public void postInit(FMLPostInitializationEvent event) { proxy.postInit(event); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index d57d1a312..b8d4793c9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -6,6 +6,7 @@ import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.eventhandler.EventPriority; import cpw.mods.fml.common.eventhandler.SubscribeEvent; @@ -38,11 +39,6 @@ public void preInit(FMLPreInitializationEvent event) { @Override public void init(FMLInitializationEvent event) { - // Nothing to do here (yet) - } - - @Override - public void postInit(FMLInitializationEvent event) { if(AngelicaConfig.enableHudCaching) { FMLCommonHandler.instance().bus().register(HUDCaching.INSTANCE); MinecraftForge.EVENT_BUS.register(HUDCaching.INSTANCE); // TODO remove debug stuff, unused registration} @@ -54,6 +50,12 @@ public void postInit(FMLInitializationEvent event) { MinecraftForge.EVENT_BUS.register(IrisDebugScreenHandler.INSTANCE); } } + + @Override + public void postInit(FMLPostInitializationEvent event) { + // Nothing to do here (yet) + } + float lastIntegratedTickTime; @SubscribeEvent public void onTick(TickEvent.ServerTickEvent event) { diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java index 8810f5758..bf06acc3d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/CommonProxy.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.proxy; import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; public class CommonProxy { @@ -11,5 +12,5 @@ public void preInit(FMLPreInitializationEvent event) { public void init(FMLInitializationEvent event) {} - public void postInit(FMLInitializationEvent event) {} + public void postInit(FMLPostInitializationEvent event) {} } diff --git a/src/main/java/jss/notfine/NotFine.java b/src/main/java/jss/notfine/NotFine.java index 3c6f029be..babd270f3 100644 --- a/src/main/java/jss/notfine/NotFine.java +++ b/src/main/java/jss/notfine/NotFine.java @@ -2,14 +2,11 @@ import com.gtnewhorizons.angelica.Tags; import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; -import cpw.mods.fml.relauncher.Side; -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 jss.notfine.proxy.CommonProxy; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -25,28 +22,23 @@ public class NotFine { public static final String VERSION = Tags.VERSION; public static final Logger logger = LogManager.getLogger(NAME); + @SidedProxy(clientSide = "jss.notfine.proxy.ClientProxy", serverSide = "jss.notfine.proxy.CommonProxy") + public static CommonProxy proxy; + + @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { - if(event.getSide() == Side.CLIENT) { - GameSettings.Options.FRAMERATE_LIMIT.valueStep = 1f; - } - NotFineConfig config = new NotFineConfig(); - config.loadSettings(); - - if(!NotFineConfig.allowAdvancedOpenGL) { - Minecraft.getMinecraft().gameSettings.advancedOpengl = false; - } - - for(Settings setting : Settings.values()) { - setting.ready(); - } + proxy.preInit(event); + } + + @Mod.EventHandler + public void init(FMLInitializationEvent event) { + proxy.init(event); } @Mod.EventHandler public void postInit(FMLPostInitializationEvent event) { - if(event.getSide() == Side.CLIENT) { - SettingsManager.settingsFile.loadSettings(); - } + proxy.postInit(event); } } diff --git a/src/main/java/jss/notfine/core/Settings.java b/src/main/java/jss/notfine/core/Settings.java index 5d1d601b0..cd07bd4d0 100644 --- a/src/main/java/jss/notfine/core/Settings.java +++ b/src/main/java/jss/notfine/core/Settings.java @@ -1,6 +1,8 @@ package jss.notfine.core; import com.gtnewhorizons.angelica.config.AngelicaConfig; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; import jss.notfine.gui.options.control.NotFineControlValueFormatter; import jss.notfine.gui.options.named.AlwaysNever; import jss.notfine.gui.options.named.BackgroundSelect; @@ -28,6 +30,7 @@ import java.util.Collections; import java.util.EnumSet; +@SideOnly(Side.CLIENT) public enum Settings { CLOUD_HEIGHT(new NotFineOptionSlider(128, 96, 384, 8, null)) { @Override diff --git a/src/main/java/jss/notfine/proxy/ClientProxy.java b/src/main/java/jss/notfine/proxy/ClientProxy.java new file mode 100644 index 000000000..f724de880 --- /dev/null +++ b/src/main/java/jss/notfine/proxy/ClientProxy.java @@ -0,0 +1,44 @@ +package jss.notfine.proxy; + +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.relauncher.Side; +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; + +public class ClientProxy extends CommonProxy { + + @Override + public void preInit(FMLPreInitializationEvent event) { + if(event.getSide() == Side.CLIENT) { + GameSettings.Options.FRAMERATE_LIMIT.valueStep = 1f; + } + NotFineConfig config = new NotFineConfig(); + config.loadSettings(); + + if(!NotFineConfig.allowAdvancedOpenGL) { + Minecraft.getMinecraft().gameSettings.advancedOpengl = false; + } + + for(Settings setting : Settings.values()) { + setting.ready(); + } + } + + @Override + public void init(FMLInitializationEvent event) { + // Nothing to do here (yet) + } + + @Override + public void postInit(FMLPostInitializationEvent event) { + if(event.getSide() == Side.CLIENT) { + SettingsManager.settingsFile.loadSettings(); + } + } + +} diff --git a/src/main/java/jss/notfine/proxy/CommonProxy.java b/src/main/java/jss/notfine/proxy/CommonProxy.java new file mode 100644 index 000000000..5c86a5746 --- /dev/null +++ b/src/main/java/jss/notfine/proxy/CommonProxy.java @@ -0,0 +1,16 @@ +package jss.notfine.proxy; + +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; + +public class CommonProxy { + + public void preInit(FMLPreInitializationEvent event) { + + } + + public void init(FMLInitializationEvent event) {} + + public void postInit(FMLPostInitializationEvent event) {} +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index a807b72a7..db33397b5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -2,17 +2,14 @@ import com.gtnewhorizons.angelica.Tags; import cpw.mods.fml.common.Mod; -import cpw.mods.fml.common.eventhandler.SubscribeEvent; -import jss.notfine.gui.GuiCustomMenu; +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; import lombok.Getter; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptionPages; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; -import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; +import me.jellysquid.mods.sodium.proxy.CommonProxy; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.gui.GuiVideoSettings; -import net.minecraftforge.client.event.GuiScreenEvent; -import net.minecraftforge.common.MinecraftForge; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -22,6 +19,9 @@ acceptedMinecraftVersions = "[1.7.10]", acceptableRemoteVersions = "*") public class SodiumClientMod { + @SidedProxy(clientSide = "me.jellysquid.mods.sodium.proxy.ClientProxy", serverSide = "me.jellysquid.mods.sodium.proxy.CommonProxy") + public static CommonProxy proxy; + private static SodiumGameOptions CONFIG; public static Logger LOGGER = LogManager.getLogger("Embeddium"); @@ -35,26 +35,9 @@ public class SodiumClientMod { public SodiumClientMod() { MainThread = Thread.currentThread(); - - MinecraftForge.EVENT_BUS.register(this); -// FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onInitializeClient); -// -// ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); } - @SubscribeEvent - public void onGui(GuiScreenEvent.InitGuiEvent.Pre event) { - if(event.gui instanceof GuiVideoSettings eventGui) { - event.setCanceled(true); - if(GuiScreen.isShiftKeyDown()) { - Minecraft.getMinecraft().displayGuiScreen(new GuiCustomMenu(eventGui.parentGuiScreen, SodiumGameOptionPages.general(), - SodiumGameOptionPages.quality(), SodiumGameOptionPages.advanced(), SodiumGameOptionPages.performance())); - } else { - Minecraft.getMinecraft().displayGuiScreen(new SodiumOptionsGUI(eventGui.parentGuiScreen)); - } - } - } public static SodiumGameOptions options() { if (CONFIG == null) { @@ -84,6 +67,21 @@ public static String getVersion() { return MOD_VERSION; } + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent event) { + proxy.preInit(event); + } + + @Mod.EventHandler + public void init(FMLInitializationEvent event) { + proxy.init(event); + } + + @Mod.EventHandler + public void postInit(FMLPostInitializationEvent event) { + proxy.postInit(event); + } + public static boolean isDirectMemoryAccessEnabled() { return options().advanced.allowDirectMemoryAccess; } diff --git a/src/main/java/me/jellysquid/mods/sodium/proxy/ClientProxy.java b/src/main/java/me/jellysquid/mods/sodium/proxy/ClientProxy.java new file mode 100644 index 000000000..bf7092d0f --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/proxy/ClientProxy.java @@ -0,0 +1,49 @@ +package me.jellysquid.mods.sodium.proxy; + +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import jss.notfine.gui.GuiCustomMenu; +import me.jellysquid.mods.sodium.client.gui.SodiumGameOptionPages; +import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiVideoSettings; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.common.MinecraftForge; + +public class ClientProxy extends CommonProxy { + + @Override + public void preInit(FMLPreInitializationEvent event) { +// FMLCommonHandler.instance().bus().register(this); + MinecraftForge.EVENT_BUS.register(this); + } + + @SubscribeEvent + public void onGui(GuiScreenEvent.InitGuiEvent.Pre event) { + if(event.gui instanceof GuiVideoSettings eventGui) { + event.setCanceled(true); + if(GuiScreen.isShiftKeyDown()) { + Minecraft.getMinecraft().displayGuiScreen(new GuiCustomMenu(eventGui.parentGuiScreen, SodiumGameOptionPages.general(), + SodiumGameOptionPages.quality(), SodiumGameOptionPages.advanced(), SodiumGameOptionPages.performance())); + } else { + Minecraft.getMinecraft().displayGuiScreen(new SodiumOptionsGUI(eventGui.parentGuiScreen)); + } + } + } + + @Override + public void init(FMLInitializationEvent event) { + // Nothing to do here (yet) + } + + @Override + public void postInit(FMLPostInitializationEvent event) { + // Nothing to do here (yet) + } + + + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/proxy/CommonProxy.java b/src/main/java/me/jellysquid/mods/sodium/proxy/CommonProxy.java new file mode 100644 index 000000000..96363eba5 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/proxy/CommonProxy.java @@ -0,0 +1,16 @@ +package me.jellysquid.mods.sodium.proxy; + +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; + +public class CommonProxy { + + public void preInit(FMLPreInitializationEvent event) { + + } + + public void init(FMLInitializationEvent event) {} + + public void postInit(FMLPostInitializationEvent event) {} +} From 3d03dc818c5ad9eb7eab9726d5c480b84aabbd3d Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 6 Dec 2023 19:47:51 -0800 Subject: [PATCH 228/301] Add Iris Keybinds, remove some deprecated compat --- .../angelica/compat/{mojang => }/Axis.java | 7 ++- .../compat/forge/IForgeBakedModel.java | 23 --------- .../angelica/compat/mojang/BakedModel.java | 18 ------- .../angelica/compat/mojang/BakedQuad.java | 22 -------- .../angelica/compat/mojang/BlockModels.java | 7 --- .../shaders/startup/MixinGameSettings.java | 5 +- .../angelica/proxy/ClientProxy.java | 6 +++ .../model/quad/properties/ModelQuadFlags.java | 12 ++--- .../context/ChunkRenderCacheLocal.java | 24 ++------- src/main/java/net/coderbot/iris/Iris.java | 50 ++++++++++++++++++- 10 files changed, 68 insertions(+), 106 deletions(-) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => }/Axis.java (55%) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBakedModel.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java b/src/main/java/com/gtnewhorizons/angelica/compat/Axis.java similarity index 55% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java rename to src/main/java/com/gtnewhorizons/angelica/compat/Axis.java index 9d1dca10d..27fffa8e5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/Axis.java @@ -1,14 +1,13 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat; -import net.minecraftforge.common.util.ForgeDirection; +import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; -@Deprecated public enum Axis { X, Y, Z; - public static Axis fromDirection(ForgeDirection dir) { + public static Axis fromDirection(ModelQuadFacing dir) { return switch (dir) { case DOWN, UP -> Y; case NORTH, SOUTH -> Z; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBakedModel.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBakedModel.java deleted file mode 100644 index 01a7eb8a8..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBakedModel.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -import com.gtnewhorizons.angelica.compat.mojang.BakedModel; -import com.gtnewhorizons.angelica.compat.mojang.BakedQuad; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import net.minecraftforge.common.util.ForgeDirection; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Random; - -public interface IForgeBakedModel { - default BakedModel getBakedModel() - { - return (BakedModel) this; - } - - default List getQuads(@Nullable BlockState state, @Nullable ForgeDirection side, @NotNull Random rand, @NotNull IModelData extraData) - { - return getBakedModel().getQuads(state, side, rand); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java deleted file mode 100644 index be0ef0d5f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedModel.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import com.gtnewhorizons.angelica.compat.forge.IForgeBakedModel; -import com.gtnewhorizons.angelica.compat.forge.IModelData; -import net.minecraftforge.common.util.ForgeDirection; - -import java.util.List; -import java.util.Random; - -@Deprecated -public interface BakedModel extends IForgeBakedModel { - - List getQuads(BlockState state, ForgeDirection face, Random random); - - IModelData getModelData(BlockRenderView world, BlockPos pos, BlockState state, IModelData modelData); - - boolean isAmbientOcclusion(BlockState state); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java deleted file mode 100644 index 87966cd1c..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BakedQuad.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import com.gtnewhorizons.angelica.compat.forge.VertexLighterFlat; -import net.minecraftforge.common.util.ForgeDirection; - -@Deprecated -public class BakedQuad { - - public void pipe(VertexLighterFlat lighter) {} - - public boolean hasColor() { - return true; - } - - public ForgeDirection getFace() { - return ForgeDirection.UNKNOWN; - } - - public boolean hasShade() { - return true; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java deleted file mode 100644 index 4a432e064..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockModels.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -@Deprecated -public class BlockModels { - - public BakedModel getModel(BlockState blockState) { return null; } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGameSettings.java index d465a800e..3eb97abd9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGameSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinGameSettings.java @@ -13,8 +13,6 @@ public abstract class MixinGameSettings { @Unique private static boolean iris$shadersInitialized; - private static Iris iris$Instance; - @Inject(method="Lnet/minecraft/client/settings/GameSettings;loadOptions()V", at=@At("HEAD")) private void angelica$InitializeShaders(CallbackInfo ci) { if (iris$shadersInitialized) { @@ -22,8 +20,7 @@ public abstract class MixinGameSettings { } iris$shadersInitialized = true; - iris$Instance =new Iris(); - iris$Instance.onEarlyInitialize(); + Iris.INSTANCE.onEarlyInitialize(); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index b8d4793c9..b4b3fca92 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -12,6 +12,7 @@ import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.gameevent.TickEvent; import me.jellysquid.mods.sodium.client.SodiumDebugScreenHandler; +import net.coderbot.iris.Iris; import net.coderbot.iris.client.IrisDebugScreenHandler; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; @@ -48,6 +49,11 @@ public void init(FMLInitializationEvent event) { } if(AngelicaConfig.enableIris) { MinecraftForge.EVENT_BUS.register(IrisDebugScreenHandler.INSTANCE); + + Iris.INSTANCE.registerKeybindings(); + FMLCommonHandler.instance().bus().register(Iris.INSTANCE); + MinecraftForge.EVENT_BUS.register(Iris.INSTANCE); + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java index 6f082ce9f..3a55ed8db 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java @@ -1,8 +1,7 @@ package me.jellysquid.mods.sodium.client.model.quad.properties; -import com.gtnewhorizons.angelica.compat.mojang.Axis; -import com.gtnewhorizons.angelica.compat.mojang.BakedQuad; -import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; +import com.gtnewhorizons.angelica.compat.Axis; +import com.gtnewhorizons.angelica.compat.nd.Quad; import net.minecraftforge.common.util.ForgeDirection; public class ModelQuadFlags { @@ -33,10 +32,9 @@ public static boolean contains(int flags, int mask) { * Calculates the properties of the given quad. This data is used later by the light pipeline in order to make * certain optimizations. */ - public static int getQuadFlags(BakedQuad bakedQuad) { - final ModelQuadView quad = (ModelQuadView) bakedQuad; - final ForgeDirection face = bakedQuad.getFace(); - final Axis axis = Axis.fromDirection(face); + public static int getQuadFlags(Quad quad) { + final ForgeDirection face = quad.getFace(); + final Axis axis = Axis.fromDirection(quad.normal); float minX = 32.0F; float minY = 32.0F; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java index 76bbab8c8..22d3bc052 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.pipeline.context; -import com.gtnewhorizons.angelica.compat.mojang.BlockModels; +import lombok.Getter; import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.cache.ArrayLightDataCache; import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; @@ -14,10 +14,11 @@ public class ChunkRenderCacheLocal extends ChunkRenderCache { private final ArrayLightDataCache lightDataCache; + @Getter private final BlockRenderer blockRenderer; + @Getter private final FluidRenderer fluidRenderer; - - private final BlockModels blockModels; + @Getter private final WorldSlice worldSlice; public ChunkRenderCacheLocal(Minecraft client, WorldClient world) { @@ -29,20 +30,6 @@ public ChunkRenderCacheLocal(Minecraft client, WorldClient world) { this.blockRenderer = new BlockRenderer(client); this.fluidRenderer = new FluidRenderer(lpp); - // TODO: Sodium - this.blockModels = null; // client.getBakedModelManager().getBlockModels(); - } - - public BlockModels getBlockModels() { - return this.blockModels; - } - - public BlockRenderer getBlockRenderer() { - return this.blockRenderer; - } - - public FluidRenderer getFluidRenderer() { - return this.fluidRenderer; } public void init(ChunkRenderContext context) { @@ -50,7 +37,4 @@ public void init(ChunkRenderContext context) { this.worldSlice.copyData(context); } - public WorldSlice getWorldSlice() { - return this.worldSlice; - } } diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 737b3c3fc..2f667ed45 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -1,7 +1,11 @@ package net.coderbot.iris; +import com.google.common.base.Throwables; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.mojang.realmsclient.gui.ChatFormatting; +import cpw.mods.fml.client.registry.ClientRegistry; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.InputEvent; import lombok.Getter; import net.coderbot.iris.config.IrisConfig; import net.coderbot.iris.gl.GLDebug; @@ -23,7 +27,9 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.resources.I18n; +import net.minecraft.client.settings.KeyBinding; import net.minecraft.launchwrapper.Launch; +import net.minecraft.util.ChatComponentText; import org.jetbrains.annotations.NotNull; import org.lwjgl.opengl.ContextCapabilities; import org.lwjgl.opengl.GLContext; @@ -87,8 +93,14 @@ public class Iris { private static String IRIS_VERSION; private static boolean fallback; + private static final KeyBinding reloadKeybind = new KeyBinding("Reload Shaders", 0, "Iris Keybinds"); + private static final KeyBinding toggleShadersKeybind = new KeyBinding("Toggle Shaders", 0, "Iris Keybinds"); + private static final KeyBinding shaderpackScreenKeybind = new KeyBinding("Shaderpack Selection Screen", 0, "Iris Keybinds"); + + public static Iris INSTANCE = new Iris(); + // Wrapped in try-catch due to early initializing class - public Iris() { + private Iris() { isDevelopmentEnvironment = (boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment"); // TODO: Iris Backport // try { @@ -99,6 +111,36 @@ public Iris() { // }catch(Exception ignored) {} } + @SubscribeEvent + public void onKeypress(InputEvent.KeyInputEvent event) { + if (reloadKeybind.isPressed()) { + final Minecraft mc = Minecraft.getMinecraft(); + try { + reload(); + if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText("Shaders Reloaded!")); + + } catch (Exception e) { + logger.error("Error while reloading Shaders for Iris!", e); + if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText( "Failed tgo reload shaders! Reason: " + Throwables.getRootCause(e).getMessage())); + } + } else if (toggleShadersKeybind.isPressed()) { + final Minecraft mc = Minecraft.getMinecraft(); + try { + toggleShaders(mc, !irisConfig.areShadersEnabled()); + } catch (Exception e) { + logger.error("Error while toggling shaders!", e); + + if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText( "Failed tgo toggle shaders! Reason: " + Throwables.getRootCause(e).getMessage())); + setShadersDisabled(); + fallback = true; + } + } else if (shaderpackScreenKeybind.isPressed()) { + final Minecraft mc = Minecraft.getMinecraft(); + if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText( "Shaderpack selection screen is not implemented yet!")); +// minecraft.setScreen(new ShaderPackScreen(null)); + } + + } /** * Called very early on in Minecraft initialization. At this point we *cannot* safely access OpenGL, but we can do some very basic setup, config loading, * and environment checks. @@ -692,4 +734,10 @@ public static ShaderpackDirectoryManager getShaderpacksDirectoryManager() { return shaderpacksDirectoryManager; } + + public void registerKeybindings() { + ClientRegistry.registerKeyBinding(reloadKeybind); + ClientRegistry.registerKeyBinding(toggleShadersKeybind); + ClientRegistry.registerKeyBinding(shaderpackScreenKeybind); + } } From df0d2373e38b11a8a4e172e66551650bd33a721a Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 6 Dec 2023 20:25:54 -0800 Subject: [PATCH 229/301] More code cleanup --- .../angelica/compat/Constants.java | 1 - .../compat/forge/IForgeVertexBuilder.java | 5 - .../compat/forge/VertexLighterFlat.java | 23 ----- .../compat/mojang/BlockBreakingInfo.java | 16 --- .../compat/mojang/BlockRenderType.java | 8 -- .../compat/mojang/BlockRenderView.java | 14 +-- .../angelica/compat/mojang/BlockState.java | 99 ------------------- .../angelica/compat/mojang/BlockView.java | 7 -- .../compat/mojang/BufferBuilderStorage.java | 22 ----- .../angelica/compat/mojang/IdList.java | 62 ------------ .../compat/mojang/IndexedIterable.java | 11 --- .../compat/mojang/OverlayVertexConsumer.java | 51 ---------- .../compat/mojang/PackedIntegerArray.java | 19 ---- .../angelica/compat/mojang/RenderLayers.java | 5 - .../angelica/compat/mojang/SideShapeType.java | 8 -- .../angelica/compat/mojang/VertexBuffer.java | 2 +- .../compat/mojang/VertexConsumer.java | 4 +- .../compat/mojang/VertexConsumerProvider.java | 92 ----------------- .../model/light/flat/FlatLightPipeline.java | 5 +- .../impl/BufferSegment.java | 6 +- src/main/java/net/coderbot/iris/Iris.java | 6 -- 21 files changed, 6 insertions(+), 460 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeVertexBuilder.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/Constants.java b/src/main/java/com/gtnewhorizons/angelica/compat/Constants.java index 04aa000ee..d039dd1b8 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/Constants.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/Constants.java @@ -1,6 +1,5 @@ package com.gtnewhorizons.angelica.compat; public class Constants { - public final static float DEGREES_TO_RADIANS = (float)Math.PI / 180.0F; } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeVertexBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeVertexBuilder.java deleted file mode 100644 index 83f9f066c..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeVertexBuilder.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -public interface IForgeVertexBuilder { - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java deleted file mode 100644 index 4a216853a..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexLighterFlat.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; - -public class VertexLighterFlat { - - public void setParent(VertexBufferConsumer consumer) {} - - public void setTransform(MatrixStack.Entry peek) {} - - public void setWorld(BlockRenderView world) {} - - public void setState(BlockState state) {} - - public void setBlockPos(BlockPos pos) {} - - public void updateBlockInfo() {} - - public void resetBlockInfo() {} -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java deleted file mode 100644 index 5c007e8c7..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockBreakingInfo.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import org.jetbrains.annotations.NotNull; - -@Deprecated -public class BlockBreakingInfo implements Comparable { - - @Override - public int compareTo(@NotNull BlockBreakingInfo o) { - return 0; - } - - public int getStage() { - return 0; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java deleted file mode 100644 index 186821165..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderType.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -@Deprecated -public enum BlockRenderType { - INVISIBLE, - ENTITYBLOCK_ANIMATED, - MODEL -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java index deb8e93f1..1020f8d96 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java @@ -1,17 +1,5 @@ package com.gtnewhorizons.angelica.compat.mojang; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.world.EnumSkyBlock; -import net.minecraftforge.common.util.ForgeDirection; - @Deprecated -public interface BlockRenderView extends BlockView { - - float getBrightness(ForgeDirection face, boolean shade); - - TileEntity getTileEntity(BlockPos pos); - - int getLightLevel(EnumSkyBlock type, BlockPos pos); - - FluidState getFluidState(BlockPos set); +public interface BlockRenderView { } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java deleted file mode 100644 index 874b26571..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockState.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import com.gtnewhorizons.angelica.compat.forge.IForgeBlockState; -import me.jellysquid.mods.sodium.common.util.WorldUtil; -import net.minecraft.block.Block; -import net.minecraft.block.material.Material; -import net.minecraftforge.common.util.ForgeDirection; -import org.joml.Vector3d; - -@Deprecated -public class BlockState implements IForgeBlockState { - private final static Vector3d ZERO = new Vector3d(0, 0, 0); - private final Block block; - private final int meta; - - public BlockState(Block block, int meta) { - this.block = block; - this.meta = meta; - } - public Block getBlock() { - return block; - } - - public int getMetadata() { - return meta; - } - - public boolean isSideInvisible(BlockState adjState, ForgeDirection facing) { - return false; - } - - public boolean isOpaque() { - return block.getMaterial().isOpaque(); - } - - public VoxelShape getCullingFace(BlockView view, BlockPos pos, ForgeDirection facing) { - return null; - } - - public int getLightValue(BlockRenderView world, BlockPos pos) { return 15;} - - public float getAmbientOcclusionLightLevel(BlockRenderView world, BlockPos pos) { return 1.0f; } - - public boolean hasEmissiveLighting(BlockRenderView world, BlockPos pos) { - return false; - } - - public boolean shouldBlockVision(BlockRenderView world, BlockPos pos) { return true;} - - public int getOpacity(BlockRenderView world, BlockPos pos) { - return 15; - } - - public boolean isOpaqueFullCube(BlockRenderView world, BlockPos pos) { - return true; - } - - public boolean isFullCube(BlockRenderView world, BlockPos pos) { return true; } - - public Vector3d getModelOffset(BlockRenderView world, BlockPos pos) { - return ZERO; - } - - public boolean isAir() { - return(block != null && block.isAir( null, 0, 0, 0)); - } - - public BlockRenderType getRenderType() { - return BlockRenderType.MODEL; - } - - public boolean hasTileEntity() { - return block.hasTileEntity(meta); - } - - public long getRenderingSeed(BlockPos.Mutable pos) { - return 0; - } - - public FluidState getFluidState() { - return new FluidState(WorldUtil.getFluid(block), meta); - } - - public boolean shouldDisplayFluidOverlay(BlockRenderView world, BlockPos adjPos, FluidState fluidState) { - return true; - } - - public Material getMaterial() { - return block.getMaterial(); - } - - public boolean isSideSolid(BlockRenderView world, BlockPos pos, ForgeDirection dir, SideShapeType sideShapeType) { - return true; - } - - public VoxelShape getCullingShape(BlockRenderView world, BlockPos pos) { - return null; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java deleted file mode 100644 index 09109d8cd..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockView.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -@Deprecated -public interface BlockView { - - BlockState getBlockState(BlockPos adjPos); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java deleted file mode 100644 index 056cbae17..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilderStorage.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import java.util.SortedMap; - -@Deprecated -public class BufferBuilderStorage { - private final SortedMap entityBuilders = null; - private final VertexConsumerProvider.Immediate entityVertexConsumers; - - public BufferBuilderStorage() { - this.entityVertexConsumers = VertexConsumerProvider.immediate(this.entityBuilders, new BufferBuilder(256)); - } - - - public VertexConsumerProvider.Immediate getEntityVertexConsumers() { - return null; - } - - public MultiBufferSource getEffectVertexConsumers() { - return null; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java deleted file mode 100644 index 57738b125..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IdList.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import com.google.common.base.Predicates; -import com.google.common.collect.Iterators; -import com.google.common.collect.Lists; - -import javax.annotation.Nullable; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; - -@Deprecated -public class IdList implements IndexedIterable { - protected int nextId; - protected final IdentityHashMap idMap; - protected final List list; - - public IdList() { - this(512); - } - - public IdList(int initialSize) { - this.list = Lists.newArrayListWithExpectedSize(initialSize); - this.idMap = new IdentityHashMap(initialSize); - } - - public void set(T value, int id) { - this.idMap.put(value, id); - - while(this.list.size() <= id) { - this.list.add(null); - } - - this.list.set(id, value); - if (this.nextId <= id) { - this.nextId = id + 1; - } - - } - - public void add(T value) { - this.set(value, this.nextId); - } - - public int getRawId(T entry) { - Integer integer = (Integer)this.idMap.get(entry); - return integer == null ? -1 : integer; - } - - @Nullable - public final T get(int index) { - return index >= 0 && index < this.list.size() ? this.list.get(index) : null; - } - - public Iterator iterator() { - return Iterators.filter(this.list.iterator(), Predicates.notNull()); - } - - public int size() { - return this.idMap.size(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java deleted file mode 100644 index 1fecd5226..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/IndexedIterable.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import javax.annotation.Nullable; - -@Deprecated -public interface IndexedIterable extends Iterable { - int getRawId(T entry); - - @Nullable - T get(int index); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java deleted file mode 100644 index 6f185d545..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayVertexConsumer.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import org.jetbrains.annotations.NotNull; -import org.joml.Matrix3f; -import org.joml.Matrix4f; - -@Deprecated -public class OverlayVertexConsumer implements VertexConsumer { - - public OverlayVertexConsumer(VertexConsumer buffer, Matrix4f model, Matrix3f normal) {} - - @Override - public VertexConsumer vertex(double d, double e, double f) { - return null; - } - - @NotNull - @Override - public VertexConsumer color(int r, int g, int b, int a) { - return null; - } - - @NotNull - @Override - public VertexConsumer texture(float u, float v) { - return null; - } - - @NotNull - @Override - public VertexConsumer overlay(int u, int v) { - return null; - } - - @NotNull - @Override - public VertexConsumer light(int u, int v) { - return null; - } - - @NotNull - @Override - public VertexConsumer normal(float x, float y, float z) { - return null; - } - - @Override - public void next() { - - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java deleted file mode 100644 index 254123d7f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/PackedIntegerArray.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -@Deprecated -public class PackedIntegerArray { - - public PackedIntegerArray(int paletteSize, int size, long[] storage) {} - - public int get(int i) { - return 0; - } - - public long[] getStorage() { - return new long[0]; - } - - public int getSize() { - return 0; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java index 99590a273..9cf81c8b6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java @@ -5,11 +5,6 @@ @Deprecated public class RenderLayers { - public static boolean canRenderInLayer(BlockState state, RenderLayer layer) { - - return canRenderInLayer(state.getBlock(), layer); - } - public static boolean canRenderInLayer(Block block, RenderLayer layer) { if(layer == RenderLayer.translucent()) return block.canRenderInPass(1); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java deleted file mode 100644 index 53dc98ecd..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/SideShapeType.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -@Deprecated -public enum SideShapeType { - FULL, - CENTER, - RIGID; -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java index 797897074..a72452e39 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexBuffer.java @@ -6,7 +6,7 @@ import java.nio.ByteBuffer; import java.nio.FloatBuffer; -@Deprecated + public class VertexBuffer implements AutoCloseable { private int id; private int vertexCount; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java index cc93669be..69245cc54 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java @@ -1,11 +1,9 @@ package com.gtnewhorizons.angelica.compat.mojang; -import com.gtnewhorizons.angelica.compat.forge.IForgeVertexBuilder; - import javax.annotation.Nonnull; @Deprecated -public interface VertexConsumer extends IForgeVertexBuilder { +public interface VertexConsumer { VertexConsumer vertex(double d, double e, double f); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java deleted file mode 100644 index cb5124361..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumerProvider.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Sets; - -import java.util.Iterator; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -@Deprecated -public interface VertexConsumerProvider { - static Immediate immediate(BufferBuilder buffer) { - return immediate(ImmutableMap.of(), buffer); - } - - static Immediate immediate(Map layerBuffers, BufferBuilder fallbackBuffer) { - return new Immediate(fallbackBuffer, layerBuffers); - } - - VertexConsumer getBuffer(RenderLayer layer); - - public static class Immediate implements VertexConsumerProvider { - protected final BufferBuilder fallbackBuffer; - protected final Map layerBuffers; - protected Optional currentLayer = Optional.empty(); - protected final Set activeConsumers = Sets.newHashSet(); - - protected Immediate(BufferBuilder fallbackBuffer, Map layerBuffers) { - this.fallbackBuffer = fallbackBuffer; - this.layerBuffers = layerBuffers; - } - - public VertexConsumer getBuffer(RenderLayer arg) { - Optional optional = arg.asOptional(); - BufferBuilder lv = this.getBufferInternal(arg); - if (!Objects.equals(this.currentLayer, optional)) { - if (this.currentLayer.isPresent()) { - RenderLayer lv2 = (RenderLayer)this.currentLayer.get(); - if (!this.layerBuffers.containsKey(lv2)) { - this.draw(lv2); - } - } - - if (this.activeConsumers.add(lv)) { - lv.begin(arg.getDrawMode(), arg.getVertexFormat()); - } - - this.currentLayer = optional; - } - - return lv; - } - - private BufferBuilder getBufferInternal(RenderLayer layer) { - return (BufferBuilder)this.layerBuffers.getOrDefault(layer, this.fallbackBuffer); - } - - public void draw() { - this.currentLayer.ifPresent((arg) -> { - VertexConsumer lv = this.getBuffer(arg); - if (lv == this.fallbackBuffer) { - this.draw(arg); - } - - }); - Iterator var1 = this.layerBuffers.keySet().iterator(); - - while(var1.hasNext()) { - RenderLayer lv = (RenderLayer)var1.next(); - this.draw(lv); - } - - } - - public void draw(RenderLayer layer) { - BufferBuilder lv = this.getBufferInternal(layer); - boolean bl = Objects.equals(this.currentLayer, layer.asOptional()); - if (bl || lv != this.fallbackBuffer) { - if (this.activeConsumers.remove(lv)) { - layer.draw(lv, 0, 0, 0); - if (bl) { - this.currentLayer = Optional.empty(); - } - - } - } - } - } -} - diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java index 3f3a3119e..5d85b4f23 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/flat/FlatLightPipeline.java @@ -1,8 +1,6 @@ package me.jellysquid.mods.sodium.client.model.light.flat; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.BlockRenderView; -import com.gtnewhorizons.angelica.compat.mojang.BlockState; import com.gtnewhorizons.angelica.config.AngelicaConfig; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; @@ -10,7 +8,6 @@ import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFlags; import net.coderbot.iris.block_rendering.BlockRenderingSettings; -import net.minecraft.client.renderer.WorldRenderer; import net.minecraftforge.common.util.ForgeDirection; import java.util.Arrays; @@ -55,7 +52,7 @@ public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Forge /** * When vanilla computes an offset lightmap with flat lighting, it passes the original BlockState but the - * offset BlockPos to {@link WorldRenderer#getLightmapCoordinates(BlockRenderView, BlockState, BlockPos)}. + * offset BlockPos to WorldRenderer#getLightmapCoordinates(BlockRenderView, BlockState, BlockPos) * This does not make much sense but fixes certain issues, primarily dark quads on light-emitting blocks * behind tinted glass. {@link LightDataAccess} cannot efficiently store lightmaps computed with * inconsistent values so this method exists to mirror vanilla behavior as closely as possible. diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java index 99153fbc6..95743c818 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java @@ -2,11 +2,13 @@ import com.gtnewhorizons.angelica.compat.mojang.DrawState; import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import lombok.Getter; import java.nio.ByteBuffer; public class BufferSegment { private final ByteBuffer slice; + @Getter private final DrawState drawState; private final RenderLayer type; @@ -20,10 +22,6 @@ public ByteBuffer getSlice() { return slice; } - public DrawState getDrawState() { - return drawState; - } - public RenderLayer getRenderType() { return type; } diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 2f667ed45..0d095eeeb 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -71,8 +71,6 @@ public class Iris { private static ShaderPack currentPack; private static String currentPackName; - // TODO: Iris Backport - Tie this to archaicfix - private static final boolean sodiumInstalled = true; // FMLLoader.getLoadingModList().getModFileById("rubidium") != null; @Getter private static boolean initialized; @@ -715,10 +713,6 @@ public static String getFormattedVersion() { return color + version; } - public static boolean isSodiumInstalled() { - return sodiumInstalled; - } - public static Path getShaderpacksDirectory() { if (shaderpacksDirectory == null) { shaderpacksDirectory = Minecraft.getMinecraft().mcDataDir.toPath().resolve("shaderpacks"); From fe14d19cb7aa3df5f0d04faba38453b5fe1e9f47 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 6 Dec 2023 21:20:25 -0800 Subject: [PATCH 230/301] Remove some deprecated code, and remove some deprecations that don't need immediate cleanup --- .../compat/mojang/ChunkOcclusionData.java | 1 - .../mojang/ChunkOcclusionDataBuilder.java | 1 - .../compat/mojang/DefaultVertexFormat.java | 2 +- .../angelica/compat/mojang/GameRenderer.java | 17 ----------------- .../angelica/compat/mojang/InteractionHand.java | 2 +- .../angelica/compat/mojang/MatrixStack.java | 2 +- .../angelica/compat/mojang/RenderLayer.java | 1 - .../angelica/compat/mojang/RenderPhase.java | 1 - .../angelica/compat/mojang/VertexConsumer.java | 1 - .../angelica/compat/mojang/VertexFormat.java | 2 +- .../compat/mojang/VertexFormatElement.java | 2 +- .../coderbot/iris/pipeline/HandRenderer.java | 14 +++++++------- 12 files changed, 12 insertions(+), 34 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java index e0d5b0c65..4ed46a3d5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionData.java @@ -5,7 +5,6 @@ import java.util.BitSet; import java.util.Set; -@Deprecated public class ChunkOcclusionData { private static final int DIRECTION_COUNT = ForgeDirection.values().length; private final BitSet visibility; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java index 05a04b19e..9a91cc87a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java @@ -13,7 +13,6 @@ * WARNING: Minecraft 1.16 code rip!! */ -@Deprecated public class ChunkOcclusionDataBuilder { private static final int STEP_X = (int)Math.pow(16.0, 0.0); private static final int STEP_Z = (int)Math.pow(16.0, 1.0); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java index 8faa3da21..7c8c3e1a8 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java @@ -4,7 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement.Type; import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement.Usage; -@Deprecated + public class DefaultVertexFormat { public static final VertexFormatElement POSITION_ELEMENT = new VertexFormatElement(0, Type.FLOAT, Usage.POSITION, 3); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java deleted file mode 100644 index 098de5c2f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/GameRenderer.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -@Deprecated -public class GameRenderer { - - public void invokeBobHurt(MatrixStack poseStack, float tickDelta) {} - - public void invokeBobView(MatrixStack poseStack, float tickDelta) {} - - public boolean getRenderHand() { - return true; - } - - public boolean getPanoramicMode() { - return true; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/InteractionHand.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/InteractionHand.java index 1361415b7..98618563c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/InteractionHand.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/InteractionHand.java @@ -1,6 +1,6 @@ package com.gtnewhorizons.angelica.compat.mojang; -@Deprecated + public enum InteractionHand { MAIN_HAND, OFF_HAND; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java index 0a52a40e4..765299bf0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java @@ -6,7 +6,7 @@ import java.util.Deque; -@Deprecated + public class MatrixStack { private final Deque matrixStack; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java index 5594123bf..aadac15ff 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java @@ -12,7 +12,6 @@ import java.util.Optional; import java.util.OptionalDouble; -@Deprecated public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris) private static final RenderLayer SOLID = of("solid", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 2097152, true, false, RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).build(true)); private static final RenderLayer CUTOUT_MIPPED = of("cutout_mipped", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 131072, true, false, RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).alpha(HALF_ALPHA).build(true)); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index 54874ef74..48490fa58 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -14,7 +14,6 @@ import java.util.OptionalDouble; -@Deprecated public abstract class RenderPhase { protected final String name; protected Runnable beginAction; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java index 69245cc54..daf481e5b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java @@ -2,7 +2,6 @@ import javax.annotation.Nonnull; -@Deprecated public interface VertexConsumer { VertexConsumer vertex(double d, double e, double f); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java index a28c2957a..f2de5561f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java @@ -5,7 +5,7 @@ import it.unimi.dsi.fastutil.ints.IntList; import lombok.Getter; -@Deprecated + public class VertexFormat { protected final ImmutableList elements; protected final IntList offsets = new IntArrayList(); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java index e1d1ce286..b065c85d5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java @@ -7,7 +7,7 @@ import java.util.function.IntConsumer; -@Deprecated + public class VertexFormatElement { @Getter protected final Type type; diff --git a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java index f642aaf73..7f9938cf9 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java @@ -2,11 +2,11 @@ import net.coderbot.batchedentityrendering.impl.FullyBufferedMultiBufferSource; import com.gtnewhorizons.angelica.compat.Camera; -import com.gtnewhorizons.angelica.compat.mojang.GameRenderer; import com.gtnewhorizons.angelica.compat.mojang.InteractionHand; import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import net.irisshaders.iris.api.v0.IrisApi; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; @@ -22,7 +22,7 @@ public class HandRenderer { public static final float DEPTH = 0.125F; - private void setupGlState(GameRenderer gameRenderer, Camera camera, MatrixStack poseStack, float tickDelta) { + private void setupGlState(RenderGlobal gameRenderer, Camera camera, MatrixStack poseStack, float tickDelta) { final MatrixStack.Entry pose = poseStack.peek(); // We need to scale the matrix by 0.125 so the hand doesn't clip through blocks. @@ -38,14 +38,14 @@ private void setupGlState(GameRenderer gameRenderer, Camera camera, MatrixStack pose.getModel().identity(); pose.getNormal().identity(); - gameRenderer.invokeBobHurt(poseStack, tickDelta); +// gameRenderer.invokeBobHurt(poseStack, tickDelta); if (Minecraft.getMinecraft().gameSettings.viewBobbing) { - gameRenderer.invokeBobView(poseStack, tickDelta); +// gameRenderer.invokeBobView(poseStack, tickDelta); } } - private boolean canRender(Camera camera, GameRenderer gameRenderer) { + private boolean canRender(Camera camera, RenderGlobal gameRenderer) { return (camera.isThirdPerson() || !(camera.getEntity() instanceof EntityPlayer) || Minecraft.getMinecraft().gameSettings.hideGUI || (camera.getEntity() instanceof EntityLiving && ((EntityLiving)camera.getEntity()).isPlayerSleeping())); // return !(!gameRenderer.getRenderHand() @@ -76,7 +76,7 @@ public boolean isAnyHandTranslucent() { return isHandTranslucent(InteractionHand.MAIN_HAND) || isHandTranslucent(InteractionHand.OFF_HAND); } - public void renderSolid(MatrixStack poseStack, float tickDelta, Camera camera, GameRenderer gameRenderer, WorldRenderingPipeline pipeline) { + public void renderSolid(MatrixStack poseStack, float tickDelta, Camera camera, RenderGlobal gameRenderer, WorldRenderingPipeline pipeline) { if (!canRender(camera, gameRenderer) || !IrisApi.getInstance().isShaderPackInUse()) { return; } @@ -112,7 +112,7 @@ public void renderSolid(MatrixStack poseStack, float tickDelta, Camera camera, G ACTIVE = false; } - public void renderTranslucent(MatrixStack poseStack, float tickDelta, Camera camera, GameRenderer gameRenderer, WorldRenderingPipeline pipeline) { + public void renderTranslucent(MatrixStack poseStack, float tickDelta, Camera camera, RenderGlobal gameRenderer, WorldRenderingPipeline pipeline) { if (!canRender(camera, gameRenderer) || !isAnyHandTranslucent() || !IrisApi.getInstance().isShaderPackInUse()) { return; } From 8c04be7495b5ec9be692c1949c86144f4bee4c14 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 7 Dec 2023 09:00:14 -0800 Subject: [PATCH 231/301] Shaders now do something! --- .../mojang/AutoClosableAbstractTexture.java | 1 - .../compat/mojang/OverlayTexture.java | 1 - .../angelica/compat/mojang/TextureAtlas.java | 1 - .../compat/mojang/VertexConsumers.java | 1 + .../angelica/compat/mojang/VertexFormat.java | 18 ++++++++++++++++-- .../compat/mojang/VertexFormatElement.java | 8 ++++++++ .../angelica/glsm/GLStateManager.java | 4 ++-- src/main/java/net/coderbot/iris/Iris.java | 2 +- .../iris/postprocess/CompositeRenderer.java | 19 ++++++++----------- .../postprocess/FullScreenQuadRenderer.java | 2 +- .../iris/rendertarget/RenderTarget.java | 6 ++++-- .../iris/rendertarget/RenderTargets.java | 10 +++++----- .../resources/assets/angelica/lang/en_US.lang | 4 +++- 13 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java index dd3c9679e..90f543a1a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java @@ -7,7 +7,6 @@ import java.io.IOException; -@Deprecated public abstract class AutoClosableAbstractTexture extends AbstractTexture implements AutoCloseable { public abstract void load(IResourceManager manager) throws IOException; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java index dce839dbd..fd219461f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java @@ -1,6 +1,5 @@ package com.gtnewhorizons.angelica.compat.mojang; -@Deprecated public class OverlayTexture { // This is definitely wrong diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java index 21547fe3d..4615a3140 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java @@ -5,7 +5,6 @@ import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourceManagerReloadListener; -@Deprecated public abstract class TextureAtlas extends AbstractTexture implements ITickable, IResourceManagerReloadListener { @Override diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java index 78d0b8a3e..49ed27793 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java @@ -6,6 +6,7 @@ public static VertexConsumer union(VertexConsumer first, VertexConsumer second) return new Dual(first, second); } + @Deprecated static class Dual implements VertexConsumer { private final VertexConsumer first; private final VertexConsumer second; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java index f2de5561f..6636b1287 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java @@ -1,12 +1,15 @@ package com.gtnewhorizons.angelica.compat.mojang; import com.google.common.collect.ImmutableList; +import com.google.common.collect.UnmodifiableIterator; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import lombok.Getter; +import java.util.List; public class VertexFormat { + @Getter protected final ImmutableList elements; protected final IntList offsets = new IntArrayList(); @Getter @@ -23,9 +26,20 @@ public VertexFormat(ImmutableList elements) { } @Deprecated - public void setupBufferState(long l) {} + public void setupBufferState(long l) { + final int i = this.getVertexSize(); + final List list = this.getElements(); + + for(int j = 0; j < list.size(); ++j) { + ((VertexFormatElement)list.get(j)).setupBufferState(l + (long)this.offsets.getInt(j), i); + } + } @Deprecated - public void clearBufferState() {} + public void clearBufferState() { + for (VertexFormatElement vertexformatelement : this.getElements()) { + vertexformatelement.clearBufferState(); + } + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java index b065c85d5..5a0deb064 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java @@ -28,6 +28,14 @@ public VertexFormatElement(int index, Type type, Usage usage, int count) { this.byteSize = type.getSize() * count; } + public void setupBufferState(long l, int i) { + this.usage.setupBufferState(this.count, this.type.getGlType(), i, l, this.index); + } + + public void clearBufferState() { + this.usage.clearBufferState(this.index); + } + public enum Usage { POSITION("Position", (i, j, k, l, m) -> { GL11.glVertexPointer(i, j, k, l); diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 920688fc3..575ef7887 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -437,8 +437,8 @@ public static void glDeleteTextures(int id) { public static void glDeleteTextures(IntBuffer ids) { if (AngelicaConfig.enableIris) { - for (int id : ids.array()) { - iris$onDeleteTexture(id); + for(int i = 0; i < ids.capacity(); i++) { + iris$onDeleteTexture(ids.get(i)); } } Textures[activeTexture].binding = -1; diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 0d095eeeb..7b7007a16 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -268,7 +268,7 @@ public static void toggleShaders(Minecraft minecraft, boolean enabled) throws IO reload(); if (minecraft.thePlayer != null) { - minecraft.thePlayer.sendChatMessage(enabled ? I18n.format("iris.shaders.toggled", currentPackName) : I18n.format("iris.shaders.disabled")); + minecraft.thePlayer.addChatMessage(new ChatComponentText(enabled ? I18n.format("iris.shaders.toggled", currentPackName) : I18n.format("iris.shaders.disabled"))); } } diff --git a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java index 09d5a8204..3780d5186 100644 --- a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java @@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableSet; import com.gtnewhorizons.angelica.glsm.GLStateManager; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import lombok.Getter; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.framebuffer.GlFramebuffer; import net.coderbot.iris.gl.program.ComputeProgram; @@ -49,7 +50,8 @@ public class CompositeRenderer { private final FrameUpdateNotifier updateNotifier; private final CenterDepthSampler centerDepthSampler; private final Object2ObjectMap customTextureIds; - private final ImmutableSet flippedAtLeastOnceFinal; + @Getter + private final ImmutableSet flippedAtLeastOnceFinal; public CompositeRenderer(PackDirectives packDirectives, ProgramSource[] sources, ComputeSource[][] computes, RenderTargets renderTargets, IntSupplier noiseTexture, FrameUpdateNotifier updateNotifier, @@ -76,7 +78,7 @@ public CompositeRenderer(PackDirectives packDirectives, ProgramSource[] sources, }); for (int i = 0; i < sources.length; i++) { - ProgramSource source = sources[i]; + final ProgramSource source = sources[i]; ImmutableSet flipped = bufferFlipper.snapshot(); ImmutableSet flippedAtLeastOnceSnapshot = flippedAtLeastOnce.build(); @@ -145,19 +147,14 @@ public CompositeRenderer(PackDirectives packDirectives, ProgramSource[] sources, OpenGlHelper.func_153171_g/*glBindFramebuffer*/(GL30.GL_READ_FRAMEBUFFER, 0); } - public ImmutableSet getFlippedAtLeastOnceFinal() { - return this.flippedAtLeastOnceFinal; - } - - - public void recalculateSizes() { + public void recalculateSizes() { for (Pass pass : passes) { if (pass instanceof ComputeOnlyPass) { continue; } int passWidth = 0, passHeight = 0; for (int buffer : pass.drawBuffers) { - RenderTarget target = renderTargets.get(buffer); + final RenderTarget target = renderTargets.get(buffer); if ((passWidth > 0 && passWidth != target.getWidth()) || (passHeight > 0 && passHeight != target.getHeight())) { throw new IllegalStateException("Pass widths must match"); } @@ -238,8 +235,8 @@ public void renderAll() { } } - float scaledWidth = renderPass.viewWidth * renderPass.viewportScale; - float scaledHeight = renderPass.viewHeight * renderPass.viewportScale; + final float scaledWidth = renderPass.viewWidth * renderPass.viewportScale; + final float scaledHeight = renderPass.viewHeight * renderPass.viewportScale; GL11.glViewport(0, 0, (int) scaledWidth, (int) scaledHeight); renderPass.framebuffer.bind(); diff --git a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java index b1fad6ba0..d7dcb844a 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java @@ -71,7 +71,7 @@ public static void end() { * Creates and uploads a vertex buffer containing a single full-screen quad */ private static int createQuad() { - FloatBuffer vertices = BufferUtils.createFloatBuffer(20); + final FloatBuffer vertices = BufferUtils.createFloatBuffer(20); vertices.put(new float[] { // Vertex 0: Top right corner 1.0F, 1.0F, 0.0F, 1.0F, 1.0F, diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java index c0d8fb0a1..f900323d0 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java @@ -99,11 +99,13 @@ public int getAltTexture() { return altTexture; } + private final IntBuffer deleteBuffer = BufferUtils.createIntBuffer(2); public void destroy() { requireValid(); isValid = false; - GLStateManager.glDeleteTextures(mainTexture); - GLStateManager.glDeleteTextures(altTexture); + deleteBuffer.put(0, mainTexture); + deleteBuffer.put(1, altTexture); + GLStateManager.glDeleteTextures(deleteBuffer); } private void requireValid() { diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java index f5c53c50b..38fad1c26 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTargets.java @@ -268,7 +268,7 @@ private GlFramebuffer createFullFramebuffer(boolean clearsAlt, int[] drawBuffers } public GlFramebuffer createColorFramebufferWithDepth(ImmutableSet stageWritesToMain, int[] drawBuffers) { - GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); + final GlFramebuffer framebuffer = createColorFramebuffer(stageWritesToMain, drawBuffers); framebuffer.addDepthAttachment(currentDepthTexture); return framebuffer; @@ -279,10 +279,10 @@ public GlFramebuffer createColorFramebuffer(ImmutableSet stageWritesToM throw new IllegalArgumentException("Framebuffer must have at least one color buffer"); } - GlFramebuffer framebuffer = new GlFramebuffer(); + final GlFramebuffer framebuffer = new GlFramebuffer(); ownedFramebuffers.add(framebuffer); - int[] actualDrawBuffers = new int[drawBuffers.length]; + final int[] actualDrawBuffers = new int[drawBuffers.length]; for (int i = 0; i < drawBuffers.length; i++) { actualDrawBuffers[i] = i; @@ -293,9 +293,9 @@ public GlFramebuffer createColorFramebuffer(ImmutableSet stageWritesToM + getRenderTargetCount() + " render targets are supported."); } - RenderTarget target = this.get(drawBuffers[i]); + final RenderTarget target = this.get(drawBuffers[i]); - int textureId = stageWritesToMain.contains(drawBuffers[i]) ? target.getMainTexture() : target.getAltTexture(); + final int textureId = stageWritesToMain.contains(drawBuffers[i]) ? target.getMainTexture() : target.getAltTexture(); framebuffer.addColorAttachment(i, textureId); } diff --git a/src/main/resources/assets/angelica/lang/en_US.lang b/src/main/resources/assets/angelica/lang/en_US.lang index c37b9e90a..d34456d29 100644 --- a/src/main/resources/assets/angelica/lang/en_US.lang +++ b/src/main/resources/assets/angelica/lang/en_US.lang @@ -81,6 +81,8 @@ sodium.options.use_no_error_context.name=Use No Error Context sodium.options.use_no_error_context.tooltip=If enabled, the OpenGL context will be created with error checking disabled. This may slightly improve performance, but it also increases the risk that the game will crash instead of gracefully handling OpenGL errors. You should disable this option if you are experiencing sudden unexplained crashes. sodium.options.threads.value=%s thread(s) sodium.options.default=Default -sodium.options.buttons.undo=Undo +sodium.options.buttons.undo=Undot sodium.options.buttons.apply=Apply sodium.options.buttons.donate=Buy coffee for JellySquid! +iris.shaders.toggled=Toggled shaders to %s! +iris.shaders.disabled=Shaders disabled! From bf51422bcf3d10c0f1f4bd4c0c792062914463a6 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 7 Dec 2023 09:08:12 -0800 Subject: [PATCH 232/301] formatting --- .../compat/mojang/VertexFormatElement.java | 46 +++++-------------- .../iris/rendertarget/RenderTarget.java | 9 ++-- 2 files changed, 15 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java index 5a0deb064..7ba91e0eb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormatElement.java @@ -8,16 +8,12 @@ import java.util.function.IntConsumer; +@Getter public class VertexFormatElement { - @Getter protected final Type type; - @Getter protected final Usage usage; - @Getter protected final int index; - @Getter protected final int count; - @Getter protected final int byteSize; public VertexFormatElement(int index, Type type, Usage usage, int count) { @@ -40,43 +36,32 @@ public enum Usage { POSITION("Position", (i, j, k, l, m) -> { GL11.glVertexPointer(i, j, k, l); GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); - }, (i) -> { - GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY); - }), + }, (i) -> GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY)), NORMAL("Normal", (i, j, k, l, m) -> { GL11.glNormalPointer(j, k, l); GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY); - }, (i) -> { - GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY); - }), + }, (i) -> GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY)), COLOR("Vertex Color", (i, j, k, l, m) -> { GL11.glColorPointer(i, j, k, l); GL11.glEnableClientState(GL11.GL_COLOR_ARRAY); - }, (i) -> { - GL11.glDisableClientState(GL11.GL_COLOR_ARRAY); - }), + }, i -> GL11.glDisableClientState(GL11.GL_COLOR_ARRAY)), UV("UV", (i, j, k, l, m) -> { - GL13.glClientActiveTexture('蓀' + m); + GL13.glClientActiveTexture(GL13.GL_TEXTURE0 + m); GL11.glTexCoordPointer(i, j, k, l); GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); GL13.glClientActiveTexture(GL13.GL_TEXTURE0); - }, (i) -> { - GL13.glClientActiveTexture('蓀' + i); + }, i -> { + GL13.glClientActiveTexture(GL13.GL_TEXTURE0 + i); GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); GL13.glClientActiveTexture(GL13.GL_TEXTURE0); }), - PADDING("Padding", (i, j, k, l, m) -> { - }, (i) -> { - }), + PADDING("Padding", (i, j, k, l, m) -> {}, i-> {}), GENERIC("Generic", (i, j, k, l, m) -> { GL20.glEnableVertexAttribArray(m); GL20.glVertexAttribPointer(m, i, j, false, k, l); - }, (i) -> { - // blah - GL20.glDisableVertexAttribArray(i); - }); + }, GL20::glDisableVertexAttribArray); - private final String name; + @Getter private final String name; private final SetupState setupState; private final IntConsumer clearState; @@ -94,17 +79,13 @@ public void clearBufferState(int i) { this.clearState.accept(i); } - public String getName() { - return this.name; - } - - interface SetupState { void setupBufferState(int i, int j, int k, long l, int m); } } - public static enum Type { + @Getter + public enum Type { FLOAT(4, "Float", GL11.GL_FLOAT), UBYTE(1, "Unsigned Byte", GL11.GL_UNSIGNED_BYTE), BYTE(1, "Byte", GL11.GL_BYTE), @@ -113,11 +94,8 @@ public static enum Type { UINT(4, "Unsigned Int", GL11.GL_UNSIGNED_INT), INT(4, "Int", GL11.GL_INT); - @Getter private final int size; - @Getter private final String name; - @Getter private final int glType; Type(int size, String name, int glType) { diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java index f900323d0..db8f3dde4 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java @@ -15,7 +15,8 @@ import java.nio.IntBuffer; public class RenderTarget { - private final InternalTextureFormat internalFormat; + @Getter + private final InternalTextureFormat internalFormat; private final PixelFormat format; private final PixelType type; @Getter @@ -83,11 +84,7 @@ void resize(int width, int height) { resizeTexture(altTexture, width, height); } - public InternalTextureFormat getInternalFormat() { - return internalFormat; - } - - public int getMainTexture() { + public int getMainTexture() { requireValid(); return mainTexture; From 18536727639a5faf4822d37be81fddd090e08021 Mon Sep 17 00:00:00 2001 From: makamys Date: Thu, 7 Dec 2023 22:31:17 +0100 Subject: [PATCH 233/301] Initialize MatrixStack with model-view matrix Fixes Iris camera transform --- .../gtnewhorizons/angelica/compat/mojang/MatrixStack.java | 6 ++++++ .../angelica/mixins/early/sodium/MixinRenderGlobal.java | 4 +++- .../mods/sodium/client/render/GameRendererContext.java | 5 ++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java index 765299bf0..385af6fba 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java @@ -14,6 +14,12 @@ public MatrixStack() { this.matrixStack = Queues.newArrayDeque(); matrixStack.add(new Entry(new Matrix4f().identity(), new Matrix3f().identity())); } + + public MatrixStack(Matrix4f initial) { + this.matrixStack = Queues.newArrayDeque(); + Matrix3f normal = new Matrix3f(); + matrixStack.add(new Entry(initial, initial.normal(normal))); + } public Entry peek() { return (Entry)this.matrixStack.getLast(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 7675c04de..125ffff3d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -4,6 +4,8 @@ import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; +import com.gtnewhorizons.angelica.rendering.RenderingState; + import lombok.Getter; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; @@ -176,7 +178,7 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) final double z = lerp(entity.lastTickPosZ, entity.posZ, partialTicks); try { - MatrixStack matrixStack = new MatrixStack(); + MatrixStack matrixStack = new MatrixStack(RenderingState.INSTANCE.getModelViewMatrix()); this.renderer.drawChunkLayer(BlockRenderPass.VALUES[pass], matrixStack, x, y, z); } finally { RenderDevice.exitManagedCode(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java index d325f0da3..6950359c9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java @@ -11,17 +11,16 @@ public class GameRendererContext { /** - * Obtains a model-view-projection matrix by multiplying the projection matrix with the model-view matrix. + * Obtains a model-view-projection matrix by multiplying the projection matrix with the model-view matrix + * from {@param matrices}. * * @return A float-buffer on the stack containing the model-view-projection matrix in a format suitable for * uploading as uniform state */ - // TODO get rid of matrices, it's unnecessary in 1.7 public static FloatBuffer getModelViewProjectionMatrix(MatrixStack.Entry matrices) { final FloatBuffer bufModelViewProjection = BufferUtils.createFloatBuffer(16); final Matrix4f projectionMatrix = (AngelicaConfig.enableIris && ShadowRenderingState.areShadowsCurrentlyBeingRendered()) ? ShadowRenderingState.getShadowOrthoMatrix() : RenderingState.INSTANCE.getProjectionMatrix(); final Matrix4f matrix = new Matrix4f(projectionMatrix); - matrix.mul(RenderingState.INSTANCE.getModelViewMatrix()); matrix.mul(matrices.getModel()); matrix.get(bufModelViewProjection); From 2028557436ffb4cc97a72bfcbaa5e57c0c283759 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 7 Dec 2023 13:47:03 -0800 Subject: [PATCH 234/301] Less silly, and add sun angle mixin --- .../mixins/early/shaders/MixinRenderGlobal.java | 14 +++++++------- .../net/coderbot/iris/uniforms/MatrixUniforms.java | 11 +++-------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java index c508d59fe..b2f73e68d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java @@ -6,9 +6,11 @@ import net.coderbot.iris.pipeline.WorldRenderingPhase; import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.minecraft.client.renderer.RenderGlobal; +import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(RenderGlobal.class) @@ -45,12 +47,10 @@ public class MixinRenderGlobal { pipeline.get().setPhase(WorldRenderingPhase.VOID); } - // TODO: Inject here (line1188) - // What to translate poseStack mulPose() to? -// @Inject(method = "renderSky", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientLevel;getTimeOfDay(F)F"), -// slice = @Slice(from = @At(value = "FIELD", target = "com/mojang/math/Vector3f.YP : Lcom/mojang/math/Vector3f;"))) -// private void iris$renderSky$tiltSun(PoseStack poseStack, float tickDelta, CallbackInfo callback) { -// poseStack.mulPose(Vector3f.ZP.rotationDegrees(pipeline.getSunPathRotation())); -// } + @Inject(method = "renderSky", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;getCelestialAngle(F)F"), + slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;getRainStrength(F)F"))) + private void iris$renderSky$tiltSun(float p_72714_1_, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { + GL11.glRotatef(pipeline.get().getSunPathRotation(), 1.0F, 0.0F, 0.0F); + } } diff --git a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java index c4dcb2237..c968cd5e2 100644 --- a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java @@ -72,12 +72,7 @@ private static class InvertedArrayMatrix implements Supplier { @Override public Matrix4f get() { - // TODO: How can we not do this? - FloatBuffer buffer = BufferUtils.createFloatBuffer(16); -// new Matrix4f(parent.get()); - buffer.put(parent.get()); - buffer.rewind(); - final Matrix4f matrix4f = new Matrix4f(buffer); + final Matrix4f matrix4f = new Matrix4f().set(parent.get()); matrix4f.invert(); return matrix4f; @@ -97,11 +92,11 @@ private static class Previous implements Supplier { public Matrix4f get() { // PERF: Don't copy + allocate these matrices every time? final Matrix4f copy = new Matrix4f(parent.get()); - final Matrix4f previous = new Matrix4f(this.previous); + final Matrix4f prev = new Matrix4f(this.previous); this.previous = copy; - return previous; + return prev; } } } From 4e3f782da670571f495b10440401477e6d3b8430 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 7 Dec 2023 21:58:42 -0800 Subject: [PATCH 235/301] Shadow Pass work * First shadow pass renders; however it moves all around when moving the camera... * Second shadow pass not running because it makes everything very very dark instead of just rendering translucents --- .../iris/pipeline/ShadowRenderer.java | 75 +++++++-------- .../coderbot/iris/shadow/ShadowMatrices.java | 91 +++++-------------- .../iris/uniforms/MatrixUniforms.java | 8 +- 3 files changed, 60 insertions(+), 114 deletions(-) diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 283ce4847..2fe4aa266 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -6,6 +6,7 @@ import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.rendering.RenderingState; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import net.coderbot.iris.Iris; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.shaderpack.OptionalBoolean; @@ -29,6 +30,7 @@ import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.culling.Frustrum; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.entity.Entity; import net.minecraft.profiler.Profiler; import net.minecraft.tileentity.TileEntity; @@ -76,7 +78,7 @@ public class ShadowRenderer { private FrustumHolder entityFrustumHolder; private String debugStringTerrain = "(unavailable)"; private int renderedShadowEntities = 0; - private int renderedShadowBlockEntities = 0; + private int renderedShadowTileEntities = 0; private Profiler profiler; public ShadowRenderer(ProgramSource shadow, PackDirectives directives, ShadowRenderTargets shadowRenderTargets) { @@ -151,8 +153,7 @@ private static WorldClient getLevel() { } private static float getSkyAngle() { - return getLevel().getWorldTime(); -// return getLevel().getTimeOfDay(CapturedRenderingState.INSTANCE.getTickDelta()); + return Minecraft.getMinecraft().theWorld.getCelestialAngle(CapturedRenderingState.INSTANCE.getTickDelta()); } private static float getSunAngle() { @@ -197,6 +198,7 @@ private void configureSamplingSettings(PackShadowDirectives shadowDirectives) { GLStateManager.glActiveTexture(GL13.GL_TEXTURE0); } + private final IntBuffer swizzleBuf = BufferUtils.createIntBuffer(4); private void configureDepthSampler(int glTextureId, PackShadowDirectives.DepthSamplingSettings settings) { if (settings.getHardwareFiltering()) { // We have to do this or else shadow hardware filtering breaks entirely! @@ -206,8 +208,7 @@ private void configureDepthSampler(int glTextureId, PackShadowDirectives.DepthSa // Workaround for issues with old shader packs like Chocapic v4. // They expected the driver to put the depth value in z, but it's supposed to only // be available in r. So we set up the swizzle to fix that. - // TODO: allocations - IntBuffer swizzleBuf = BufferUtils.createIntBuffer(4); + swizzleBuf.rewind(); swizzleBuf.put(new int[] { GL11.GL_RED, GL11.GL_RED, GL11.GL_RED, GL11.GL_ONE }).rewind(); IrisRenderSystem.texParameteriv(glTextureId, GL11.GL_TEXTURE_2D, ARBTextureSwizzle.GL_TEXTURE_SWIZZLE_RGBA, swizzleBuf); @@ -216,7 +217,7 @@ private void configureDepthSampler(int glTextureId, PackShadowDirectives.DepthSa private void configureSampler(int glTextureId, PackShadowDirectives.SamplingSettings settings) { if (settings.getMipmap()) { - int filteringMode = settings.getNearest() ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR; + final int filteringMode = settings.getNearest() ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR; mipmapPasses.add(new MipmapPass(glTextureId, filteringMode)); } @@ -420,32 +421,29 @@ private void renderPlayerEntity(EntityRenderer levelRenderer, Frustrum frustum, profiler.endSection(); } - private void renderBlockEntities(BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta, boolean hasEntityFrustum) { + private void renderTileEntities(BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float partialTicks, boolean hasEntityFrustum) { profiler.startSection("build blockentities"); - int shadowBlockEntities = 0; + int shadowTileEntities = 0; BoxCuller culler = null; if (hasEntityFrustum) { culler = new BoxCuller(halfPlaneLength * (renderDistanceMultiplier * entityShadowDistanceMultiplier)); culler.setPosition(cameraX, cameraY, cameraZ); } - for (TileEntity entity : visibleTileEntities) { - if (hasEntityFrustum) { - if (culler.isCulled(entity.xCoord - 1, entity.yCoord - 1, entity.zCoord - 1, entity.xCoord + 1, entity.yCoord + 1, entity.zCoord + 1)) { - continue; - } + for (TileEntity tileEntity : visibleTileEntities) { + if (hasEntityFrustum && (culler.isCulled(tileEntity.xCoord - 1, tileEntity.yCoord - 1, tileEntity.zCoord - 1, tileEntity.xCoord + 1, tileEntity.yCoord + 1, tileEntity.zCoord + 1))) { + continue; } modelView.push(); - // TODO: Render - modelView.translate(entity.xCoord - cameraX, entity.yCoord - cameraY, entity.zCoord - cameraZ); -// BlockEntityRenderDispatcher.instance.render(entity, tickDelta, modelView, bufferSource); + modelView.translate(tileEntity.xCoord - cameraX, tileEntity.yCoord - cameraY, tileEntity.zCoord - cameraZ); + TileEntityRendererDispatcher.instance.renderTileEntity(tileEntity, partialTicks); modelView.pop(); - shadowBlockEntities++; + shadowTileEntities++; } - renderedShadowBlockEntities = shadowBlockEntities; + renderedShadowTileEntities = shadowTileEntities; profiler.endSection(); } @@ -471,19 +469,20 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { visibleTileEntities = new ArrayList<>(); // Create our camera - MatrixStack modelView = createShadowModelView(this.sunPathRotation, this.intervalSize); + final MatrixStack modelView = createShadowModelView(this.sunPathRotation, this.intervalSize); // TODO: Render MODELVIEW = new Matrix4f(modelView.peek().getModel()); - float[] projMatrix; + + final Matrix4f shadowProjection; if (this.fov != null) { // If FOV is not null, the pack wants a perspective based projection matrix. (This is to support legacy packs) - projMatrix = ShadowMatrices.createPerspectiveMatrix(this.fov); + shadowProjection = ShadowMatrices.createPerspectiveMatrix(this.fov); } else { - projMatrix = ShadowMatrices.createOrthoMatrix(halfPlaneLength); + shadowProjection = ShadowMatrices.createOrthoMatrix(halfPlaneLength); } // TODO: Allocations - PROJECTION = new Matrix4f().set(projMatrix); + PROJECTION = new Matrix4f().set(shadowProjection); profiler.startSection("terrain_setup"); @@ -496,26 +495,18 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { terrainFrustumHolder = createShadowFrustum(renderDistanceMultiplier, terrainFrustumHolder); // Determine the player camera position - Vector3d cameraPos = CameraUniforms.getUnshiftedCameraPosition(); + final Vector3d cameraPos = CameraUniforms.getUnshiftedCameraPosition(); - double cameraX = cameraPos.x(); - double cameraY = cameraPos.y(); - double cameraZ = cameraPos.z(); + final double cameraX = cameraPos.x(); + final double cameraY = cameraPos.y(); + final double cameraZ = cameraPos.z(); // Center the frustum on the player camera position // TODO: Render -// terrainFrustumHolder.getFrustum().prepare(cameraX, cameraY, cameraZ); + terrainFrustumHolder.getFrustum().setPosition(cameraX, cameraY, cameraZ); profiler.endSection(); - // Disable chunk occlusion culling - it's a bit complex to get this properly working with shadow rendering - // as-is, however in the future it will be good to work on restoring it for a nice performance boost. - // - // TODO: Get chunk occlusion working with shadows - // TODO: Render -// boolean wasChunkCullingEnabled = client.smartCull; -// client.smartCull = false; - // Always schedule a terrain update // TODO: Only schedule a terrain update if the sun / moon is moving, or the shadow map camera moved. // We have to ensure that we don't regenerate clouds every frame, since that's what needsUpdate ends up doing. @@ -525,6 +516,7 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // levelRenderer.setShouldRegenerateClouds(regenerateClouds); // Execute the vanilla terrain setup / culling routines using our shadow frustum. + mc.renderGlobal.clipRenderersByFrustum(terrainFrustumHolder.getFrustum(), playerCamera.getPartialTicks()); // levelRenderer.invokeSetupRender(playerCamera, terrainFrustumHolder.getFrustum(), false, levelRenderer.getFrameId(), false); // Don't forget to increment the frame counter! This variable is arbitrary and only used in terrain setup, @@ -541,8 +533,7 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // Render all opaque terrain unless pack requests not to if (shouldRenderTerrain) { // TODO: Render -// rg.sortAndRender(mc.thePlayer, 0, playerCamera.getPartialTicks()); -// rg.sortAndRender(mc.thePlayer, 1, playerCamera.getPartialTicks()); + rg.sortAndRender(mc.thePlayer, 0, playerCamera.getPartialTicks()); // levelRenderer.invokeRenderChunkLayer(RenderLayer.solid(), modelView, cameraX, cameraY, cameraZ); // levelRenderer.invokeRenderChunkLayer(RenderLayer.cutout(), modelView, cameraX, cameraY, cameraZ); @@ -590,7 +581,7 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { } if (shouldRenderBlockEntities) { -// renderBlockEntities(bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta, hasEntityFrustum); +// renderTileEntities(bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta, hasEntityFrustum); } profiler.endStartSection("draw entities"); @@ -609,7 +600,9 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // Just something to watch out for, however... if (shouldRenderTranslucent) { // TODO: Render + // TODO -- This makes everything look... weird // rg.sortAndRender(mc.thePlayer, 1, playerCamera.getPartialTicks()); + // levelRenderer.invokeRenderChunkLayer(RenderLayer.translucent(), modelView, cameraX, cameraY, cameraZ); } @@ -621,7 +614,7 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // } // TODO: Render -// debugStringTerrain = ((LevelRenderer) levelRenderer).getChunkStatistics(); + debugStringTerrain = SodiumWorldRenderer.getInstance().getChunksDebugString(); profiler.endStartSection("generate mipmaps"); @@ -661,7 +654,7 @@ private String getEntitiesDebugString() { } private String getTileEntitiesDebugString() { - return shouldRenderBlockEntities ? (renderedShadowBlockEntities + "/" + Minecraft.getMinecraft().theWorld.loadedTileEntityList.size()) : "disabled by pack"; + return shouldRenderBlockEntities ? (renderedShadowTileEntities + "/" + Minecraft.getMinecraft().theWorld.loadedTileEntityList.size()) : "disabled by pack"; } private static class MipmapPass { diff --git a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java index 75f821149..c53220a00 100644 --- a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java +++ b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java @@ -13,8 +13,8 @@ public class ShadowMatrices { // NB: These matrices are in column-major order, not row-major order like what you'd expect! - public static float[] createOrthoMatrix(float halfPlaneLength) { - return new float[] { + public static Matrix4f createOrthoMatrix(float halfPlaneLength) { + return new Matrix4f( // column 1 1.0f / halfPlaneLength, 0f, 0f, 0f, // column 2 @@ -23,13 +23,13 @@ public static float[] createOrthoMatrix(float halfPlaneLength) { 0f, 0f, 2.0f / (NEAR - FAR), 0f, // column 4 0f, 0f, -(FAR + NEAR) / (FAR - NEAR), 1f - }; + ); } - public static float[] createPerspectiveMatrix(float fov) { + public static Matrix4f createPerspectiveMatrix(float fov) { // This converts from degrees to radians. - float yScale = (float) (1.0f / Math.tan(Math.toRadians(fov) * 0.5f)); - return new float[] { + final float yScale = (float) (1.0f / Math.tan(Math.toRadians(fov) * 0.5f)); + return new Matrix4f( // column 1 yScale, 0f, 0f, 0f, // column 2 @@ -38,11 +38,11 @@ public static float[] createPerspectiveMatrix(float fov) { 0f, 0f, (FAR + NEAR) / (NEAR - FAR), -1.0F, // column 4 0f, 0f, 2.0F * FAR * NEAR / (NEAR - FAR), 1f - }; + ); } public static void createBaselineModelViewMatrix(MatrixStack target, float shadowAngle, float sunPathRotation) { - float skyAngle; + final float skyAngle; if (shadowAngle < 0.25f) { skyAngle = shadowAngle + 0.75f; @@ -55,9 +55,9 @@ public static void createBaselineModelViewMatrix(MatrixStack target, float shado target.peek().getModel().translate(0.0f, 0.0f, -100.0f); target.rotateX(90F * DEGREES_TO_RADIANS); - target.rotateZ(sunPathRotation * DEGREES_TO_RADIANS); target.rotateZ(skyAngle * -360.0f * DEGREES_TO_RADIANS); - } + target.rotateX(sunPathRotation * DEGREES_TO_RADIANS); + } public static void snapModelViewToGrid(MatrixStack target, float shadowIntervalSize, double cameraX, double cameraY, double cameraZ) { if (Math.abs(shadowIntervalSize) == 0.0F) { @@ -76,7 +76,7 @@ public static void snapModelViewToGrid(MatrixStack target, float shadowIntervalS float offsetZ = (float) cameraZ % shadowIntervalSize; // Halve the size of each grid cell in order to move to the center of it. - float halfIntervalSize = shadowIntervalSize / 2.0f; + final float halfIntervalSize = shadowIntervalSize / 2.0f; // Shift by -halfIntervalSize // @@ -90,8 +90,7 @@ public static void snapModelViewToGrid(MatrixStack target, float shadowIntervalS target.peek().getModel().translate(offsetX, offsetY, offsetZ); } - public static void createModelViewMatrix(MatrixStack target, float shadowAngle, float shadowIntervalSize, - float sunPathRotation, double cameraX, double cameraY, double cameraZ) { + public static void createModelViewMatrix(MatrixStack target, float shadowAngle, float shadowIntervalSize, float sunPathRotation, double cameraX, double cameraY, double cameraZ) { createBaselineModelViewMatrix(target, shadowAngle, sunPathRotation); snapModelViewToGrid(target, shadowIntervalSize, cameraX, cameraY, cameraZ); } @@ -100,36 +99,36 @@ private static final class Tests { public static void main(String[] args) { // const float shadowDistance = 32.0; // /* SHADOWHPL:32.0 */ - float[] expected = new float[] { + Matrix4f expected = new Matrix4f( 0.03125f, 0f, 0f, 0f, 0f, 0.03125f, 0f, 0f, 0f, 0f, -0.007814026437699795f, 0f, 0f, 0f, -1.000390648841858f, 1f - }; + ); test("ortho projection hpl=32", expected, createOrthoMatrix(32.0f)); // const float shadowDistance = 110.0; // /* SHADOWHPL:110.0 */ - float[] expected110 = new float[] { + Matrix4f expected110 = new Matrix4f( 0.00909090880304575f, 0, 0, 0, 0, 0.00909090880304575f, 0, 0, 0, 0, -0.007814026437699795f, 0, 0, 0, -1.000390648841858f, 1 - }; + ); test("ortho projection hpl=110", expected110, createOrthoMatrix(110.0f)); - float[] expected90Proj = new float[] { + Matrix4f expected90Proj = new Matrix4f( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0003906f, -1.0f, 0.0f, 0.0f, -0.10001954f, 0.0f - }; + ); test("perspective projection fov=90", expected90Proj, createPerspectiveMatrix(90.0f)); - float[] expectedModelViewAtDawn = new float[] { + Matrix4f expectedModelViewAtDawn = new Matrix4f( // column 1 0.21545040607452393f, 5.820481518981069E-8f, @@ -150,7 +149,7 @@ public static void main(String[] args) { 1.0264281034469604f, -100.4463119506836f, 1 - }; + ); MatrixStack modelView = new MatrixStack(); @@ -160,59 +159,19 @@ public static void main(String[] args) { createModelViewMatrix(modelView, 0.03451777f, 2.0f, 0.0f, 0.646045982837677f, 82.53274536132812f, -514.0264282226562f); - test("model view at dawn", expectedModelViewAtDawn, toFloatArray(modelView.peek().getModel())); + test("model view at dawn", expectedModelViewAtDawn, modelView.peek().getModel()); } - private static float[] toFloatArray(Matrix4f matrix4f) { - final FloatBuffer buffer = FloatBuffer.allocate(16); - matrix4f.get((FloatBuffer) buffer); - - return buffer.array(); - } - - private static void test(String name, float[] expected, float[] created) { - if (!areMatricesEqualWithinEpsilon(expected, created)) { + private static void test(String name, Matrix4f expected, Matrix4f created) { + if (expected.equals(created, 0.0005f)) { System.err.println("test " + name + " failed: "); System.err.println(" expected: "); - System.err.print(printMatrix(expected, 8)); + System.err.print(expected.toString()); System.err.println(" created: "); - System.err.print(printMatrix(created, 8)); + System.err.print(created.toString()); } else { System.out.println("test " + name + " passed"); } } - - private static boolean areMatricesEqualWithinEpsilon(float[] expected, float[] created) { - for (int i = 0; i < 16; i++) { - if (Math.abs(expected[i] - created[i]) > 0.0005f) { - return false; - } - } - - return true; - } - - private static String printMatrix(float[] matrix, int spaces) { - StringBuilder lines = new StringBuilder(); - - for (int row = 0; row < 4; row++) { - for (int i = 0; i < spaces; i++) { - lines.append(' '); - } - - lines.append('['); - - for (int column = 0; column < 4; column++) { - lines.append(' '); - lines.append(matrix[column * 4 + row]); - } - - lines.append(" ]"); - - lines.append('\n'); - } - - return lines.toString(); - } } } diff --git a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java index c968cd5e2..89e2e11c9 100644 --- a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java @@ -23,7 +23,7 @@ public static void addMatrixUniforms(UniformHolder uniforms, PackDirectives dire // We need to audit Mojang's linear algebra. addMatrix(uniforms, "Projection", RenderingState.INSTANCE::getProjectionMatrix); addShadowMatrix(uniforms, "ModelView", () -> ShadowRenderer.createShadowModelView(directives.getSunPathRotation(), directives.getShadowDirectives().getIntervalSize()).peek().getModel()); - addShadowArrayMatrix(uniforms, "Projection", () -> ShadowMatrices.createOrthoMatrix(directives.getShadowDirectives().getDistance())); + addShadowMatrix(uniforms, "Projection", () -> ShadowMatrices.createOrthoMatrix(directives.getShadowDirectives().getDistance())); } private static void addMatrix(UniformHolder uniforms, String name, Supplier supplier) { @@ -39,12 +39,6 @@ private static void addShadowMatrix(UniformHolder uniforms, String name, Supplie .uniformMatrix(PER_FRAME, "shadow" + name + "Inverse", new Inverted(supplier)); } - private static void addShadowArrayMatrix(UniformHolder uniforms, String name, Supplier supplier) { - uniforms - .uniformMatrixFromArray(PER_FRAME, "shadow" + name, supplier) - .uniformMatrix(PER_FRAME, "shadow" + name + "Inverse", new InvertedArrayMatrix(supplier)); - } - private static class Inverted implements Supplier { private final Supplier parent; From 35632dfa6afd43d856fe882762522a0f10b23f66 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 7 Dec 2023 22:45:01 -0800 Subject: [PATCH 236/301] Actually use the ShadowRenderer Model View when running the shadow pass... --- .../mixins/early/sodium/MixinRenderGlobal.java | 3 ++- src/main/java/net/coderbot/iris/Iris.java | 2 +- .../net/coderbot/iris/pipeline/ShadowRenderer.java | 11 ++++------- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 125ffff3d..037b5b46a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -13,6 +13,7 @@ import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import net.coderbot.iris.Iris; import net.coderbot.iris.pipeline.HandRenderer; +import net.coderbot.iris.pipeline.ShadowRenderer; import net.coderbot.iris.pipeline.WorldRenderingPhase; import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.minecraft.client.Minecraft; @@ -178,7 +179,7 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) final double z = lerp(entity.lastTickPosZ, entity.posZ, partialTicks); try { - MatrixStack matrixStack = new MatrixStack(RenderingState.INSTANCE.getModelViewMatrix()); + final MatrixStack matrixStack = new MatrixStack(ShadowRenderer.ACTIVE ? ShadowRenderer.MODELVIEW : RenderingState.INSTANCE.getModelViewMatrix()); this.renderer.drawChunkLayer(BlockRenderPass.VALUES[pass], matrixStack, x, y, z); } finally { RenderDevice.exitManagedCode(); diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 7b7007a16..aab422d29 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -64,7 +64,7 @@ public class Iris { */ public static final String MODNAME = "AngelicaShaders"; - public static final IrisLogging logger = new IrisLogging(MODNAME + "Shaders"); + public static final IrisLogging logger = new IrisLogging(MODNAME); private static Path shaderpacksDirectory; private static ShaderpackDirectoryManager shaderpacksDirectoryManager; diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 2fe4aa266..e0a0734cc 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -51,8 +51,8 @@ import java.util.Objects; public class ShadowRenderer { - public static Matrix4f MODELVIEW; - public static Matrix4f PROJECTION; + public static final Matrix4f MODELVIEW = new Matrix4f(); + public static final Matrix4f PROJECTION = new Matrix4f(); public static List visibleTileEntities; public static boolean ACTIVE = false; private final float halfPlaneLength; @@ -470,8 +470,7 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // Create our camera final MatrixStack modelView = createShadowModelView(this.sunPathRotation, this.intervalSize); - // TODO: Render - MODELVIEW = new Matrix4f(modelView.peek().getModel()); + MODELVIEW.set(modelView.peek().getModel()); final Matrix4f shadowProjection; if (this.fov != null) { @@ -481,8 +480,7 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { shadowProjection = ShadowMatrices.createOrthoMatrix(halfPlaneLength); } - // TODO: Allocations - PROJECTION = new Matrix4f().set(shadowProjection); + PROJECTION.set(shadowProjection); profiler.startSection("terrain_setup"); @@ -502,7 +500,6 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { final double cameraZ = cameraPos.z(); // Center the frustum on the player camera position - // TODO: Render terrainFrustumHolder.getFrustum().setPosition(cameraX, cameraY, cameraZ); profiler.endSection(); From 900cf65f6c0c425fde339c4e6f083c6300496b88 Mon Sep 17 00:00:00 2001 From: Caedis Date: Fri, 8 Dec 2023 12:04:42 -0600 Subject: [PATCH 237/301] initial asm neid compat --- addon.gradle | 9 +++++++++ dependencies.gradle | 4 +++- repositories.gradle | 1 + .../com/gtnewhorizons/angelica/AngelicaMod.java | 4 ++++ .../angelica/compat/ExtendedBlockStorageExt.java | 13 ++++++++++++- .../gtnewhorizons/angelica/mixins/TargetedMod.java | 1 + .../early/angelica/MixinExtendedBlockStorage.java | 9 +++++++++ 7 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinExtendedBlockStorage.java diff --git a/addon.gradle b/addon.gradle index 58cadb25b..85dabb8ae 100644 --- a/addon.gradle +++ b/addon.gradle @@ -5,3 +5,12 @@ allprojects { } } } +minecraft { + extraRunJvmArguments.addAll([ + "-Dfml.debugAccessTransformer=true", + "-Dlegacy.debugClassLoading=true", + "-Dlegacy.debugClassLoadingFiner=true", + "-Dlegacy.debugClassLoadingSave=true", + "-noverify" + ]) +} diff --git a/dependencies.gradle b/dependencies.gradle index 384bc06a9..b3b502dbf 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -64,7 +64,9 @@ dependencies { compileOnly(rfg.deobf("curse.maven:extrautils-225561:2264383")) compileOnly(rfg.deobf("curse.maven:dynamiclights-227874:2337326")) - compileOnly("com.github.GTNewHorizons:NotEnoughIds:1.5-pre:dev") // based off https://github.com/GTNewHorizons/NotEnoughIds/pull/2 + compileOnly("com.github.GTNewHorizons:NotEnoughIds:1.5.3:dev") // Mixin Version + devOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughIds:1.4.7:dev") // ASM Version (local build with COMPUTE_FRAMES) + compileOnly("com.github.GTNewHorizons:Jabba:1.3.1:dev") // HMMMMM compileOnly(rfg.deobf("curse.maven:journeymap-32274:2367915")) diff --git a/repositories.gradle b/repositories.gradle index 4333d1d9a..ce179e75b 100644 --- a/repositories.gradle +++ b/repositories.gradle @@ -9,4 +9,5 @@ repositories { artifact() } } + mavenLocal() } diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index 8a35c0905..256b1a2b0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -18,12 +18,16 @@ public class AngelicaMod { @SidedProxy(clientSide = "com.gtnewhorizons.angelica.proxy.ClientProxy", serverSide = "com.gtnewhorizons.angelica.proxy.CommonProxy") public static CommonProxy proxy; + /** Mixin Version */ public static boolean isNEIDLoaded; + /** ASM Version */ + public static boolean isOldNEIDLoaded; public static final boolean lwjglDebug = Boolean.parseBoolean(System.getProperty("org.lwjgl.util.Debug", "false")); @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { isNEIDLoaded = Loader.isModLoaded("neid"); + isOldNEIDLoaded = Loader.isModLoaded("notenoughIDs"); proxy.preInit(event); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java index 5d636b3d5..8302b1e86 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java @@ -6,6 +6,7 @@ import com.gtnewhorizons.neid.mixins.interfaces.IExtendedBlockStorageMixin; import net.minecraft.world.chunk.NibbleArray; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import ru.fewizz.idextender.Hooks; public class ExtendedBlockStorageExt extends ExtendedBlockStorage { public boolean hasSky; @@ -27,7 +28,17 @@ public ExtendedBlockStorageExt(ExtendedBlockStorage storage) { copyNibbleArray((ExtendedNibbleArray) storage.getBlockMSBArray(), (ExtendedNibbleArray) this.getBlockMSBArray()); } arrayLen = block16BArray.length; - }else { + } + else if (AngelicaMod.isOldNEIDLoaded){ + final byte[] blockLSBArray = Hooks. + System.arraycopy(storage.getBlockLSBArray(), 0, blockLSBArray, 0, blockLSBArray.length); + if(storage.getBlockMSBArray() != null) { + this.setBlockMSBArray(new NibbleArray(blockLSBArray.length, 4)); + copyNibbleArray((ExtendedNibbleArray) storage.getBlockMSBArray(), (ExtendedNibbleArray) this.getBlockMSBArray()); + } + arrayLen = blockLSBArray.length; + } + else { final byte[] blockLSBArray = this.getBlockLSBArray(); System.arraycopy(storage.getBlockLSBArray(), 0, blockLSBArray, 0, blockLSBArray.length); if(storage.getBlockMSBArray() != null) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java index a573a5e88..9aff9d128 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java @@ -21,6 +21,7 @@ public enum TargetedMod { , THAUMCRAFT("Thaumcraft", null, "Thaumcraft") , TWILIGHT_FOREST("TwilightForest", null, "TwilightForest") , WITCHERY("Witchery", null, "witchery") + , NEID_ASM("notenoughIDs", "ru.fewizz.idextender.IEPlugin", "notenoughIDs") ; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinExtendedBlockStorage.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinExtendedBlockStorage.java new file mode 100644 index 000000000..89dc647a8 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinExtendedBlockStorage.java @@ -0,0 +1,9 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica; + +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(ExtendedBlockStorage.class) +public class MixinExtendedBlockStorage { + +} From e58bc1ffff02caf6434008945b9f80b92d05eeb2 Mon Sep 17 00:00:00 2001 From: Caedis Date: Fri, 8 Dec 2023 12:59:21 -0600 Subject: [PATCH 238/301] fully implement --- .../angelica/compat/ExtendedBlockStorageExt.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java index 8302b1e86..15993bc9d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/ExtendedBlockStorageExt.java @@ -30,12 +30,9 @@ public ExtendedBlockStorageExt(ExtendedBlockStorage storage) { arrayLen = block16BArray.length; } else if (AngelicaMod.isOldNEIDLoaded){ - final byte[] blockLSBArray = Hooks. - System.arraycopy(storage.getBlockLSBArray(), 0, blockLSBArray, 0, blockLSBArray.length); - if(storage.getBlockMSBArray() != null) { - this.setBlockMSBArray(new NibbleArray(blockLSBArray.length, 4)); - copyNibbleArray((ExtendedNibbleArray) storage.getBlockMSBArray(), (ExtendedNibbleArray) this.getBlockMSBArray()); - } + final short[] blockLSBArray = Hooks.get(this); + System.arraycopy(Hooks.get(storage), 0, blockLSBArray, 0, blockLSBArray.length); + // getBlockMSBArray is nuked in asm version arrayLen = blockLSBArray.length; } else { From 93237724038a22d4619258c9561e1488a441b4ac Mon Sep 17 00:00:00 2001 From: Caedis Date: Fri, 8 Dec 2023 12:59:27 -0600 Subject: [PATCH 239/301] clean up --- addon.gradle | 9 --------- dependencies.gradle | 2 +- .../com/gtnewhorizons/angelica/mixins/TargetedMod.java | 1 - .../mixins/early/angelica/MixinExtendedBlockStorage.java | 9 --------- 4 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinExtendedBlockStorage.java diff --git a/addon.gradle b/addon.gradle index 85dabb8ae..58cadb25b 100644 --- a/addon.gradle +++ b/addon.gradle @@ -5,12 +5,3 @@ allprojects { } } } -minecraft { - extraRunJvmArguments.addAll([ - "-Dfml.debugAccessTransformer=true", - "-Dlegacy.debugClassLoading=true", - "-Dlegacy.debugClassLoadingFiner=true", - "-Dlegacy.debugClassLoadingSave=true", - "-noverify" - ]) -} diff --git a/dependencies.gradle b/dependencies.gradle index b3b502dbf..bd85c8860 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -65,7 +65,7 @@ dependencies { compileOnly(rfg.deobf("curse.maven:dynamiclights-227874:2337326")) compileOnly("com.github.GTNewHorizons:NotEnoughIds:1.5.3:dev") // Mixin Version - devOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughIds:1.4.7:dev") // ASM Version (local build with COMPUTE_FRAMES) + devOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughIds-Legacy:1.4.7:dev") // ASM Version compileOnly("com.github.GTNewHorizons:Jabba:1.3.1:dev") // HMMMMM diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java index 9aff9d128..a573a5e88 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java @@ -21,7 +21,6 @@ public enum TargetedMod { , THAUMCRAFT("Thaumcraft", null, "Thaumcraft") , TWILIGHT_FOREST("TwilightForest", null, "TwilightForest") , WITCHERY("Witchery", null, "witchery") - , NEID_ASM("notenoughIDs", "ru.fewizz.idextender.IEPlugin", "notenoughIDs") ; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinExtendedBlockStorage.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinExtendedBlockStorage.java deleted file mode 100644 index 89dc647a8..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/MixinExtendedBlockStorage.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.angelica; - -import net.minecraft.world.chunk.storage.ExtendedBlockStorage; -import org.spongepowered.asm.mixin.Mixin; - -@Mixin(ExtendedBlockStorage.class) -public class MixinExtendedBlockStorage { - -} From ee8d80130b18ec3db448030a52e2e99280877dbe Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 8 Dec 2023 21:52:00 -0800 Subject: [PATCH 240/301] Enable Sodium SmoothLightPipeline & Iris useSeparateAo --- .../angelica/client/Shaders.java | 2 +- .../angelica/compat/mojang/VertexFormat.java | 22 ++++ .../angelica/config/AngelicaConfig.java | 5 + .../gtnewhorizons/angelica/mixins/Mixins.java | 3 +- .../early/sodium/MixinRenderBlocks.java | 34 ++++++ .../sodium/client/gui/SodiumGameOptions.java | 2 +- .../model/light/data/LightDataAccess.java | 18 +-- .../quad/properties/ModelQuadFacing.java | 12 ++ .../chunk/tasks/ChunkRenderRebuildTask.java | 4 +- .../client/render/pipeline/BlockRenderer.java | 83 +++++++++---- .../client/render/pipeline/FluidRenderer.java | 14 ++- .../context/ChunkRenderCacheLocal.java | 6 +- .../context/ChunkRenderCacheShared.java | 4 +- .../sodium/client/util/ModelQuadUtil.java | 12 +- .../sodium/common/config/SodiumConfig.java | 112 +----------------- src/main/java/net/coderbot/iris/Iris.java | 2 + 16 files changed, 176 insertions(+), 159 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index 14bb1166d..6ab4688dc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -2234,7 +2234,7 @@ public static void setCamera(float tickDelta) { // GL11.glMatrixMode(GL11.GL_MODELVIEW); // GL11.glLoadIdentity(); // GL11.glTranslatef(0.0f, 0.0f, -100.0f); -// GL11.glRotatef(90.0f, 1.0f, 0.0f, 0.0f); +// GL11.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);- float celestialAngle = mc.theWorld.getCelestialAngle(tickDelta); sunAngle = (celestialAngle < 0.75f) ? celestialAngle + 0.25f : celestialAngle - 0.75f; float angle = celestialAngle * (-360.0f); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java index 6636b1287..f6fd42101 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java @@ -5,6 +5,9 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import lombok.Getter; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; +import net.coderbot.iris.vertices.ImmediateState; +import net.coderbot.iris.vertices.IrisVertexFormats; import java.util.List; @@ -27,6 +30,16 @@ public VertexFormat(ImmutableList elements) { @Deprecated public void setupBufferState(long l) { + if (BlockRenderingSettings.INSTANCE.shouldUseExtendedVertexFormat() && ImmediateState.renderWithExtendedVertexFormat) { + if (this == DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL || this == DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP) { + IrisVertexFormats.TERRAIN.setupBufferState(l); + return; + } else if (this == DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL) { + IrisVertexFormats.ENTITY.setupBufferState(l); + return; + } + } + final int i = this.getVertexSize(); final List list = this.getElements(); @@ -37,6 +50,15 @@ public void setupBufferState(long l) { @Deprecated public void clearBufferState() { + if (BlockRenderingSettings.INSTANCE.shouldUseExtendedVertexFormat() && ImmediateState.renderWithExtendedVertexFormat) { + if (this == DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL || this == DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP) { + IrisVertexFormats.TERRAIN.clearBufferState(); + return; + } else if ( this == DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL) { + IrisVertexFormats.ENTITY.clearBufferState(); + return; + } + } for (VertexFormatElement vertexformatelement : this.getElements()) { vertexformatelement.clearBufferState(); } diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index 766a73629..a03f87db5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -7,6 +7,11 @@ public class AngelicaConfig { @Config.RequiresMcRestart public static boolean enableSodium; + @Config.Comment("Enable Sodium fluid rendering") + @Config.DefaultBoolean(false) + @Config.RequiresMcRestart + public static boolean enableSodiumFluidRendering; + @Config.Comment("Enable Iris Shaders [Requires Sodium]") @Config.DefaultBoolean(false) @Config.RequiresMcRestart diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 5f744c716..8ac5b84e1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -88,6 +88,7 @@ public enum Mixins { ,"sodium.MixinMaterial" ,"sodium.MixinMinecraft" ,"sodium.MixinNibbleArray" + ,"sodium.MixinRenderBlocks" ,"sodium.MixinRenderGlobal" ,"sodium.MixinWorldClient" ,"sodium.MixinTessellator" @@ -110,7 +111,7 @@ public enum Mixins { // Required for Sodium's FluidRenderer, so it treats vanilla liquids as IFluidBlocks SODIUM_WISHLIST(new Builder("Sodiumer").addTargetedMod(TargetedMod.VANILLA).setSide(Side.BOTH) - .setPhase(Phase.EARLY).setApplyIf(() -> SodiumConfig.ENABLE_FLUID_RENDERER).addMixinClasses( + .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodiumFluidRendering).addMixinClasses( "sodium.MixinBlockLiquid")), IRIS_RENDERING(new Builder("Iris Shaders").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java new file mode 100644 index 000000000..7b3849a93 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java @@ -0,0 +1,34 @@ +package com.gtnewhorizons.angelica.mixins.early.sodium; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(RenderBlocks.class) +public abstract class MixinRenderBlocks { + @Shadow + public abstract boolean renderStandardBlockWithColorMultiplier(Block block, int x, int y, int z, float f, float f1, float f2); + + /** + * @author mitchej123 + * @reason Let sodium handle AO + */ + @Overwrite + public boolean renderStandardBlockWithAmbientOcclusion(Block block, int x, int y, int z, float f, float f1, float f2) { + return renderStandardBlockWithColorMultiplier(block, x, y, z, f, f1, f2); + } + + /** + * @author mitchej123 + * @reason Let sodium handle AO + */ + @Overwrite + public boolean renderStandardBlockWithAmbientOcclusionPartial(Block block, int x, int y, int z, float f, float f1, float f2) { + return renderStandardBlockWithColorMultiplier(block, x, y, z, f, f1, f2); + } + + + +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 846830fdb..5155f2d90 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -34,7 +34,7 @@ public static class AdvancedSettings { public boolean useBlockFaceCulling = true; public boolean allowDirectMemoryAccess = true; public boolean ignoreDriverBlacklist = false; - public boolean translucencySorting = false; + public boolean translucencySorting = true; } public static class PerformanceSettings { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java index 4282fa7d8..246530460 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/data/LightDataAccess.java @@ -47,13 +47,13 @@ public long get(BlockPos pos) { public abstract long get(int x, int y, int z); protected long compute(int x, int y, int z) { - BlockPos pos = this.pos.set(x, y, z); - WorldSlice world = this.world; + final BlockPos pos = this.pos.set(x, y, z); + final WorldSlice world = this.world; - Block block = world.getBlock(x, y, z); + final Block block = world.getBlock(x, y, z); - float ao; - boolean em; + final float ao; + final boolean em; if (block.getLightValue() == 0) { ao = block.getAmbientOcclusionLightValue(); @@ -64,14 +64,14 @@ protected long compute(int x, int y, int z) { } // First is shouldBlockVision, but I can't find if any transparent objects set it - boolean op = /*state.shouldBlockVision(world, pos) ||*/ block.getLightOpacity() == 0; - boolean fo = block.isOpaqueCube(); + final boolean op = /*state.shouldBlockVision(world, pos) ||*/ block.getLightOpacity() == 0; + final boolean fo = block.isOpaqueCube(); // Should be isFullCube, but this is probably close enough - boolean fc = block.renderAsNormalBlock(); + final boolean fc = block.renderAsNormalBlock(); // OPTIMIZE: Do not calculate lightmap data if the block is full and opaque. // FIX: Calculate lightmap data for light-emitting or emissive blocks, even though they are full and opaque. - int lm = (fo && !em) ? 0 : block.getMixedBrightnessForBlock(world, x, y, z); + final int lm = (fo && !em) ? 0 : block.getMixedBrightnessForBlock(world, x, y, z); return packAO(ao) | packLM(lm) | packOP(op) | packFO(fo) | packFC(fc) | (1L << 60); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java index 881a1b990..c8f740508 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFacing.java @@ -27,6 +27,18 @@ public static ModelQuadFacing fromDirection(ForgeDirection dir) { }; } + public static ForgeDirection toDirection(ModelQuadFacing dir) { + return switch (dir) { + case DOWN -> ForgeDirection.DOWN; + case UP -> ForgeDirection.UP; + case NORTH -> ForgeDirection.NORTH; + case SOUTH -> ForgeDirection.SOUTH; + case WEST -> ForgeDirection.WEST; + case EAST -> ForgeDirection.EAST; + default -> ForgeDirection.UNKNOWN; + }; + } + public static ModelQuadFacing fromVector(Vector3f normal) { if(normal.x == 0f) { if(normal.y == 0f) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 6af457ff9..abb37cc7c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -127,7 +127,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB // Do regular block rendering for (BlockRenderPass pass : BlockRenderPass.VALUES) { - if (block.canRenderInPass(pass.ordinal()) && (!SodiumConfig.ENABLE_FLUID_RENDERER || !(block instanceof IFluidBlock))) { + if (block.canRenderInPass(pass.ordinal()) && (!AngelicaConfig.enableSodiumFluidRendering || !(block instanceof IFluidBlock))) { long seed = MathUtil.hashPos(pos.x, pos.y, pos.z); if(AngelicaConfig.enableIris) buffers.iris$setMaterialId(block, ExtendedDataHelper.BLOCK_RENDER_TYPE); @@ -138,7 +138,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB } // Do fluid rendering without RenderBlocks - if (SodiumConfig.ENABLE_FLUID_RENDERER && block instanceof IFluidBlock) { + if (AngelicaConfig.enableSodiumFluidRendering && block instanceof IFluidBlock) { for (BlockRenderPass pass : BlockRenderPass.VALUES) { if (block.canRenderInPass(pass.ordinal())) { if(AngelicaConfig.enableIris) buffers.iris$setMaterialId(block, ExtendedDataHelper.FLUID_RENDER_TYPE); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index ab1c1f844..c0120ecb3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -4,20 +4,28 @@ import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; import com.gtnewhorizons.angelica.compat.nd.Quad; import com.gtnewhorizons.angelica.compat.nd.RecyclingList; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.mixins.interfaces.ITessellatorInstance; +import me.jellysquid.mods.sodium.client.model.light.LightMode; +import me.jellysquid.mods.sodium.client.model.light.LightPipeline; +import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.data.QuadLightData; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadOrientation; import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuffers; import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; +import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; +import me.jellysquid.mods.sodium.client.util.color.ColorABGR; import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.util.ForgeDirection; import org.joml.Vector3d; import org.lwjgl.opengl.GL11; @@ -33,16 +41,25 @@ public class BlockRenderer { private final QuadLightData cachedQuadLightData = new QuadLightData(); private final boolean useAmbientOcclusion; + private boolean useSeparateAo; + + private final LightPipelineProvider lighters; private final Flags FLAGS = new Flags(true, true, true, false); private final RecyclingList quadBuf = new RecyclingList<>(Quad::new); - public BlockRenderer(Minecraft client) { + + public BlockRenderer(LightPipelineProvider lighters) { + this.lighters = lighters; // TODO: Sodium - AO Setting this.useAmbientOcclusion = Minecraft.getMinecraft().gameSettings.ambientOcclusion > 0; } public boolean renderModel(IBlockAccess world, Tessellator tessellator, RenderBlocks renderBlocks, Block block, int meta, BlockPos pos, ChunkModelBuffers buffers, boolean cull, long seed) { + final LightMode mode = this.getLightingMode(block); + final LightPipeline lighter = this.lighters.getLighter(mode); + + this.useSeparateAo = AngelicaConfig.enableIris && BlockRenderingSettings.INSTANCE.shouldUseSeparateAo(); boolean rendered = false; @@ -50,12 +67,12 @@ public boolean renderModel(IBlockAccess world, Tessellator tessellator, RenderBl tessellator.startDrawingQuads(); renderBlocks.renderBlockByRenderType(block, pos.x, pos.y, pos.z); - this.random.setSeed(seed); final List all = tessellatorToQuadList(tessellator, pos); for (ModelQuadFacing facing : ModelQuadFacing.VALUES) { - this.renderQuadList(pos, buffers, all, facing); + this.random.setSeed(seed); + this.renderQuadList(pos, lighter, buffers, all, facing); } if (!all.isEmpty()) rendered = true; @@ -95,7 +112,7 @@ private List tessellatorToQuadList(Tessellator t, BlockPos pos) { int verticesPerPrimitive = t.drawMode == GL11.GL_QUADS ? 4 : 3; for(int quadI = 0; quadI < t.vertexCount / verticesPerPrimitive; quadI++) { - Quad quad = quadBuf.next(); + final Quad quad = quadBuf.next(); // RenderBlocks adds the subchunk-relative coordinates as the offset, cancel it out here quad.setState(t.rawBuffer, quadI * (verticesPerPrimitive * 8), FLAGS, t.drawMode, -pos.x, -pos.y, -pos.z); @@ -126,32 +143,34 @@ private List tessellatorToQuadList(Tessellator t, BlockPos pos) { return quads; } - private void renderQuadList(BlockPos pos, ChunkModelBuffers buffers, List quads, ModelQuadFacing facing) { + private void renderQuadList(BlockPos pos, LightPipeline lighter, ChunkModelBuffers buffers, List quads, ModelQuadFacing facing) { - ModelVertexSink sink = buffers.getSink(facing); + final ModelVertexSink sink = buffers.getSink(facing); sink.ensureCapacity(quads.size() * 4); + final ForgeDirection cullFace = ModelQuadFacing.toDirection(facing); - ChunkRenderData.Builder renderData = buffers.getRenderData(); + final ChunkRenderData.Builder renderData = buffers.getRenderData(); // This is a very hot allocation, iterate over it manually // noinspection ForLoopReplaceableByForEach for (int i = 0, quadsSize = quads.size(); i < quadsSize; i++) { - Quad quad = quads.get(i); + final Quad quad = quads.get(i); if(quad.normal != facing) continue; + final QuadLightData light = this.cachedQuadLightData; + lighter.calculate(quad, pos, light, cullFace, quad.getFace(), quad.hasShade()); - this.renderQuad(sink, quad, renderData); + + this.renderQuad(sink, quad, light, renderData); } sink.flush(); } - private void renderQuad(ModelVertexSink sink, - Quad quad, ChunkRenderData.Builder renderData) { + private void renderQuad(ModelVertexSink sink, Quad quad, QuadLightData light, ChunkRenderData.Builder renderData) { - // TODO reorder using packed light - ModelQuadOrientation order = ModelQuadOrientation.NORMAL; + final ModelQuadOrientation order = ModelQuadOrientation.orient(light.br);; int[] colors = null; @@ -160,29 +179,43 @@ private void renderQuad(ModelVertexSink sink, } for (int dstIndex = 0; dstIndex < 4; dstIndex++) { - int srcIndex = order.getVertexIndex(dstIndex); - - float x = quad.getX(srcIndex); - float y = quad.getY(srcIndex); - float z = quad.getZ(srcIndex); - - int color = quad.getColor(srcIndex); + final int srcIndex = order.getVertexIndex(dstIndex); + + final float x = quad.getX(srcIndex); + final float y = quad.getY(srcIndex); + final float z = quad.getZ(srcIndex); + +// int color = quad.getColor(srcIndex); + int color = colors != null ? colors[srcIndex] : quad.getColor(srcIndex); + final float ao = light.br[srcIndex]; + if (useSeparateAo) { + color &= 0x00FFFFFF; + color |= ((int) (ao * 255.0f)) << 24; + } else { + color = ColorABGR.mul(color, ao); + } - float u = quad.getTexU(srcIndex); - float v = quad.getTexV(srcIndex); + final float u = quad.getTexU(srcIndex); + final float v = quad.getTexV(srcIndex); - int lm = quad.getLight(srcIndex); + final int lm = ModelQuadUtil.mergeBakedLight(quad.getLight(srcIndex), light.lm[srcIndex]); sink.writeQuad(x, y, z, color, u, v, lm); } - TextureAtlasSprite sprite = quad.rubidium$getSprite(); + final TextureAtlasSprite sprite = quad.rubidium$getSprite(); if (sprite != null) { renderData.addSprite(sprite); } } - + private LightMode getLightingMode(Block block) { + if (this.useAmbientOcclusion && block.getAmbientOcclusionLightValue() != 1.0F && block.getLightValue() == 0) { + return LightMode.SMOOTH; + } else { + return LightMode.FLAT; + } + } public static class Flags { boolean hasTexture; public boolean hasBrightness; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java index c1de8dc24..1904deba9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java @@ -3,6 +3,7 @@ import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; import com.gtnewhorizons.angelica.compat.mojang.VoxelShapes; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import me.jellysquid.mods.sodium.client.model.light.LightMode; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; @@ -19,6 +20,7 @@ import me.jellysquid.mods.sodium.client.world.WorldSlice; import me.jellysquid.mods.sodium.common.util.DirectionUtil; import me.jellysquid.mods.sodium.common.util.WorldUtil; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -40,6 +42,7 @@ public class FluidRenderer { private final ModelQuadViewMutable quad = new ModelQuad(); private final QuadLightData quadLightData = new QuadLightData(); + private boolean useSeparateAo; private final int[] quadColors = new int[4]; public FluidRenderer(LightPipelineProvider lpp) { @@ -88,6 +91,7 @@ private boolean isSideExposed(IBlockAccess world, int x, int y, int z, ForgeDire } public boolean render(IBlockAccess world, WorldSlice slice, Block block, BlockPos pos, ChunkModelBuffers buffers) { + this.useSeparateAo = AngelicaConfig.enableIris && BlockRenderingSettings.INSTANCE.shouldUseSeparateAo(); int posX = pos.x; int posY = pos.y; @@ -358,7 +362,15 @@ private void calculateQuadColors(ModelQuadView quad, BlockPos pos, LightPipeline } for (int i = 0; i < 4; i++) { - this.quadColors[i] = ColorABGR.mul(biomeColors != null ? biomeColors[i] : 0xFFFFFFFF, light.br[i] * brightness); + int color = biomeColors != null ? biomeColors[i] : 0xFFFFFFFF; + final float ao = light.br[i] * brightness; + if (useSeparateAo) { + color &= 0x00FFFFFF; + color |= ((int) (ao * 255.0f)) << 24; + } else { + color = ColorABGR.mul(color, ao); + } + this.quadColors[i] = color; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java index 22d3bc052..1271dec7c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheLocal.java @@ -25,10 +25,10 @@ public ChunkRenderCacheLocal(Minecraft client, WorldClient world) { this.worldSlice = new WorldSlice(world); this.lightDataCache = new ArrayLightDataCache(this.worldSlice); - LightPipelineProvider lpp = new LightPipelineProvider(lightDataCache); + final LightPipelineProvider lightPipelineProvider = new LightPipelineProvider(lightDataCache); - this.blockRenderer = new BlockRenderer(client); - this.fluidRenderer = new FluidRenderer(lpp); + this.blockRenderer = new BlockRenderer(lightPipelineProvider); + this.fluidRenderer = new FluidRenderer(lightPipelineProvider); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java index aafa2a19c..38a930a84 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/context/ChunkRenderCacheShared.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.render.pipeline.context; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; +import me.jellysquid.mods.sodium.client.model.light.LightPipelineProvider; import me.jellysquid.mods.sodium.client.model.light.cache.HashLightDataCache; import me.jellysquid.mods.sodium.client.render.pipeline.BlockRenderer; import me.jellysquid.mods.sodium.client.render.pipeline.ChunkRenderCache; @@ -21,8 +22,9 @@ private ChunkRenderCacheShared(WorldSlice world) { Minecraft client = Minecraft.getMinecraft(); this.lightCache = new HashLightDataCache(world); + LightPipelineProvider lightPipelineProvider = new LightPipelineProvider(this.lightCache); - this.blockRenderer = new BlockRenderer(client); + this.blockRenderer = new BlockRenderer(lightPipelineProvider); } public BlockRenderer getBlockRenderer() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java index 460ae3469..04442b1e4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/util/ModelQuadUtil.java @@ -69,12 +69,12 @@ public static int mergeBakedLight(int packedLight, int calcLight) { if (packedLight == 0) return calcLight; - int psl = (packedLight >> 16) & 0xFF; - int csl = (calcLight >> 16) & 0xFF; - int pbl = (packedLight) & 0xFF; - int cbl = (calcLight) & 0xFF; - int bl = Math.max(pbl, cbl); - int sl = Math.max(psl, csl); + final int psl = (packedLight >> 16) & 0xFF; + final int csl = (calcLight >> 16) & 0xFF; + final int pbl = (packedLight) & 0xFF; + final int cbl = (calcLight) & 0xFF; + final int bl = Math.max(pbl, cbl); + final int sl = Math.max(psl, csl); return (sl << 16) | bl; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java b/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java index 1a2731ed8..95e0882ae 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/config/SodiumConfig.java @@ -11,9 +11,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * Documentation of these options: https://github.com/jellysquid3/sodium-fabric/wiki/Configuration-File @@ -21,68 +18,12 @@ public class SodiumConfig { private static final Logger LOGGER = LogManager.getLogger("EmbeddiumConfig"); - private static final String JSON_KEY_SODIUM_OPTIONS = "sodium:options"; - - private static final Set SYSTEM_OPTIONS = Stream.of( - "core", - "features.chunk_rendering" - ).map(SodiumConfig::getMixinRuleName).collect(Collectors.toSet()); - private final Map options = new HashMap<>(); - // Enable Sodium's fluid renderer. Part of RenderBlocks removal, postponed for now - public static final boolean ENABLE_FLUID_RENDERER = Boolean.parseBoolean(System.getProperty("sodium.enableFluidRenderer", "false")); private SodiumConfig() { - // Defines the default rules which can be configured by the user or other mods. - // You must manually add a rule for any new mixins not covered by an existing package rule. - this.addMixinRule("core", true); // TODO: Don't actually allow the user to disable this - - this.addMixinRule("features.block", true); - this.addMixinRule("features.buffer_builder", true); - this.addMixinRule("features.buffer_builder.fast_advance", true); - this.addMixinRule("features.buffer_builder.fast_sort", true); - this.addMixinRule("features.buffer_builder.intrinsics", true); - this.addMixinRule("features.chunk_rendering", true); - this.addMixinRule("features.debug", true); - this.addMixinRule("features.entity", true); - this.addMixinRule("features.entity.fast_render", true); - this.addMixinRule("features.entity.smooth_lighting", true); - this.addMixinRule("features.gui", true); - this.addMixinRule("features.gui.fast_loading_screen", true); - this.addMixinRule("features.gui.fast_status_bars", true); - this.addMixinRule("features.gui.fast_fps_pie", true); - this.addMixinRule("features.gui.font", true); - this.addMixinRule("features.item", true); - this.addMixinRule("features.matrix_stack", true); - this.addMixinRule("features.model", true); - this.addMixinRule("features.optimized_bamboo", true); - this.addMixinRule("features.options", true); - this.addMixinRule("features.particle", true); - this.addMixinRule("features.particle.cull", true); - this.addMixinRule("features.particle.fast_render", true); - this.addMixinRule("features.render_layer", true); - this.addMixinRule("features.render_layer.leaves", true); - this.addMixinRule("features.sky", true); - this.addMixinRule("features.texture_tracking", true); - this.addMixinRule("features.world_ticking", true); - this.addMixinRule("features.fast_biome_colors", true); } - /** - * Defines a Mixin rule which can be configured by users and other mods. - * @throws IllegalStateException If a rule with that name already exists - * @param mixin The name of the mixin package which will be controlled by this rule - * @param enabled True if the rule will be enabled by default, otherwise false - */ - private void addMixinRule(String mixin, boolean enabled) { - String name = getMixinRuleName(mixin); - - if (this.options.putIfAbsent(name, new Option(name, enabled, false)) != null) { - throw new IllegalStateException("Mixin rule already defined: " + mixin); - } - } - private void readProperties(Properties props) { for (Map.Entry entry : props.entrySet()) { String key = (String) entry.getKey(); @@ -116,39 +57,6 @@ private void readProperties(Properties props) { } } - /** - * Returns the effective option for the specified class name. This traverses the package path of the given mixin - * and checks each root for configuration rules. If a configuration rule disables a package, all mixins located in - * that package and its children will be disabled. The effective option is that of the highest-priority rule, either - * a enable rule at the end of the chain or a disable rule at the earliest point in the chain. - * - * @return Null if no options matched the given mixin name, otherwise the effective option for this Mixin - */ - public Option getEffectiveOptionForMixin(String mixinClassName) { - int lastSplit = 0; - int nextSplit; - - Option rule = null; - - while ((nextSplit = mixinClassName.indexOf('.', lastSplit)) != -1) { - String key = getMixinRuleName(mixinClassName.substring(0, nextSplit)); - - Option candidate = this.options.get(key); - - if (candidate != null) { - rule = candidate; - - if (!rule.isEnabled()) { - return rule; - } - } - - lastSplit = nextSplit + 1; - } - - return rule; - } - /** * Loads the configuration file from the specified location. If it does not exist, a new configuration file will be * created. The file on disk will then be updated to include any new options. @@ -164,7 +72,7 @@ public static SodiumConfig load(File file) { return new SodiumConfig(); } - Properties props = new Properties(); + final Properties props = new Properties(); try (FileInputStream fin = new FileInputStream(file)){ props.load(fin); @@ -172,14 +80,14 @@ public static SodiumConfig load(File file) { throw new RuntimeException("Could not load config file", e); } - SodiumConfig config = new SodiumConfig(); + final SodiumConfig config = new SodiumConfig(); config.readProperties(props); return config; } private static void writeDefaultConfig(File file) throws IOException { - File dir = file.getParentFile(); + final File dir = file.getParentFile(); if (!dir.exists()) { if (!dir.mkdirs()) { @@ -199,18 +107,4 @@ private static void writeDefaultConfig(File file) throws IOException { } } - private static String getMixinRuleName(String name) { - return "mixin." + name; - } - - public int getOptionCount() { - return this.options.size(); - } - - public int getOptionOverrideCount() { - return (int) this.options.values() - .stream() - .filter(Option::isOverridden) - .count(); - } } diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index aab422d29..e2634b5ea 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -594,6 +594,8 @@ public static void reload() throws IOException { if (Minecraft.getMinecraft().theWorld != null) { Iris.getPipelineManager().preparePipeline(Iris.getCurrentDimension()); } + // Reload Sodium/Invalidate Chunk Cache + Minecraft.getMinecraft().renderGlobal.loadRenderers(); } /** From 6e416947ded0d16070108ad420c1b16c46950171 Mon Sep 17 00:00:00 2001 From: mist475 <70655895+mist475@users.noreply.github.com> Date: Sat, 9 Dec 2023 17:25:21 +0100 Subject: [PATCH 241/301] Avoid repeatedly copying biome data on each Y level (#27) --- .../sodium/client/world/cloned/ClonedChunkSection.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index 46b37d7e9..d65a826b9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -64,7 +64,7 @@ public void init(ChunkSectionPos pos) { this.tileEntities.clear(); - // Check for tile entities & fill biome data + // Check for tile entities for(int y = pos.getMinY(); y <= pos.getMaxY(); y++) { for(int z = pos.getMinZ(); z <= pos.getMaxZ(); z++) { for(int x = pos.getMinX(); x <= pos.getMaxX(); x++) { @@ -81,10 +81,16 @@ public void init(ChunkSectionPos pos) { this.tileEntities.put(ChunkSectionPos.packLocal(new BlockPos(tileentity.xCoord & 15, tileentity.yCoord & 15, tileentity.zCoord & 15)), tileentity); } } - this.biomeData[(lZ << 4) | lX] = world.getBiomeGenForCoords(x, z); } } } + + // Fill biome data + for(int z = pos.getMinZ(); z <= pos.getMaxZ(); z++) { + for(int x = pos.getMinX(); x <= pos.getMaxX(); x++) { + this.biomeData[((z & 15) << 4) | (x & 15)] = world.getBiomeGenForCoords(x, z); + } + } } public Block getBlock(int x, int y, int z) { From 8a1e941e156519e13fb391ef5add0c258139dc75 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 9 Dec 2023 11:31:40 -0800 Subject: [PATCH 242/301] Remove temporary exception --- .../java/com/gtnewhorizons/angelica/glsm/GLStateManager.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 575ef7887..c996f19ac 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -506,11 +506,6 @@ public static void glDrawArrays(int mode, int first, int count) { // Iris -- TODO: This doesn't seem to work and is related to matchPass() Iris.getPipelineManager().getPipeline().ifPresent(WorldRenderingPipeline::syncProgram); GL11.glDrawArrays(mode, first, count); - // Temporary - int error = GL11.glGetError(); - if(error != GL11.GL_NO_ERROR) { - throw new RuntimeException("glDrawArrays error: " + error); - } } public static void defaultBlendFunc() { From 5403fe03f175b183972b1b57d283d037c217dab2 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 9 Dec 2023 11:56:55 -0800 Subject: [PATCH 243/301] Celestial Rotation fixes * Shaders sun location is still wrong, but the main sun image now renders correctly --- .../angelica/mixins/early/shaders/MixinRenderGlobal.java | 4 +++- src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java | 3 --- .../java/net/coderbot/iris/uniforms/CelestialUniforms.java | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java index b2f73e68d..dc63c1cce 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java @@ -13,6 +13,8 @@ import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import static com.gtnewhorizons.angelica.compat.Constants.DEGREES_TO_RADIANS; + @Mixin(RenderGlobal.class) public class MixinRenderGlobal { @Inject(method = "renderSky", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;instance:Lnet/minecraft/client/renderer/Tessellator;")) @@ -50,7 +52,7 @@ public class MixinRenderGlobal { @Inject(method = "renderSky", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;getCelestialAngle(F)F"), slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;getRainStrength(F)F"))) private void iris$renderSky$tiltSun(float p_72714_1_, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { - GL11.glRotatef(pipeline.get().getSunPathRotation(), 1.0F, 0.0F, 0.0F); + GL11.glRotatef(pipeline.get().getSunPathRotation() * DEGREES_TO_RADIANS, 0.0F, 0.0F, 1.0F); } } diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index e0a0734cc..aaa3a4dc0 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -521,15 +521,12 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // chunks during traversal, and break rendering in concerning ways. // levelRenderer.setFrameId(levelRenderer.getFrameId() + 1); -// client.smartCull = wasChunkCullingEnabled; - profiler.endStartSection("terrain"); setupGlState(PROJECTION); // Render all opaque terrain unless pack requests not to if (shouldRenderTerrain) { - // TODO: Render rg.sortAndRender(mc.thePlayer, 0, playerCamera.getPartialTicks()); // levelRenderer.invokeRenderChunkLayer(RenderLayer.solid(), modelView, cameraX, cameraY, cameraZ); diff --git a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java index d669bb2c2..91765b6a1 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java @@ -70,10 +70,10 @@ public Vector4f getShadowLightPositionInWorldSpace() { } private Vector4f getCelestialPositionInWorldSpace(float y) { - Vector4f position = new Vector4f(0.0F, y, 0.0F, 0.0F); + final Vector4f position = new Vector4f(0.0F, y, 0.0F, 0.0F); // TODO: Deduplicate / remove this function. - Matrix4f celestial = new Matrix4f().identity(); + final Matrix4f celestial = new Matrix4f().identity(); // This is the same transformation applied by renderSky, however, it's been moved to here. // This is because we need the result of it before it's actually performed in vanilla. From 7018f8241f12d3a4b2fef922bc680df81d595313 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 9 Dec 2023 12:24:46 -0800 Subject: [PATCH 244/301] Fix some uniforms, get rid of most accidently continued usages of Shaders.xxx --- .../iris/pipeline/ShadowRenderer.java | 20 ++++----- .../iris/uniforms/CameraUniforms.java | 22 +++++----- .../iris/uniforms/CommonUniforms.java | 44 +++++++++---------- .../coderbot/iris/uniforms/FogUniforms.java | 16 +++---- .../uniforms/HardcodedCustomUniforms.java | 2 +- 5 files changed, 50 insertions(+), 54 deletions(-) diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index aaa3a4dc0..b4a547d43 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -135,14 +135,14 @@ public void setUsesImages(boolean usesImages) { public static MatrixStack createShadowModelView(float sunPathRotation, float intervalSize) { // Determine the camera position - Vector3d cameraPos = CameraUniforms.getUnshiftedCameraPosition(); + final Vector3d cameraPos = CameraUniforms.getUnshiftedCameraPosition(); - double cameraX = cameraPos.x; - double cameraY = cameraPos.y; - double cameraZ = cameraPos.z; + final double cameraX = cameraPos.x; + final double cameraY = cameraPos.y; + final double cameraZ = cameraPos.z; // Set up our modelview matrix stack - MatrixStack modelView = new MatrixStack(); + final MatrixStack modelView = new MatrixStack(); ShadowMatrices.createModelViewMatrix(modelView, getShadowAngle(), intervalSize, sunPathRotation, cameraX, cameraY, cameraZ); return modelView; @@ -157,7 +157,7 @@ private static float getSkyAngle() { } private static float getSunAngle() { - float skyAngle = getSkyAngle(); + final float skyAngle = getSkyAngle(); if (skyAngle < 0.75F) { return skyAngle + 0.25F; @@ -263,7 +263,7 @@ private FrustumHolder createShadowFrustum(float renderMultiplier, FrustumHolder if (distance <= 0 || distance > Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16) { distanceInfo = Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16 - + " blocks (capped by getNormal render distance)"; + + " blocks (capped by normal render distance)"; cullingInfo = "disabled " + reason; return holder.setInfo(new NonCullingFrustum(), distanceInfo, cullingInfo); } else { @@ -287,7 +287,7 @@ private FrustumHolder createShadowFrustum(float renderMultiplier, FrustumHolder if (distance >= Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16) { distanceInfo = Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16 - + " blocks (capped by getNormal render distance)"; + + " blocks (capped by normal render distance)"; boxCuller = null; } else { distanceInfo = distance + " blocks " + setter; @@ -328,12 +328,12 @@ private void setupGlState(Matrix4f projMatrix) { // However, it only partially resolves issues of light leaking into caves. // // TODO: Better way of preventing light from leaking into places where it shouldn't - GL11.glDisable(GL11.GL_CULL_FACE); + GLStateManager.disableCull(); } private void restoreGlState() { // Restore backface culling - GL11.glEnable(GL11.GL_CULL_FACE); + GLStateManager.enableCull(); // Make sure to unload the projection matrix IrisRenderSystem.restoreProjectionMatrix(); diff --git a/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java index 17267919e..a7c7f5062 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CameraUniforms.java @@ -1,6 +1,7 @@ package net.coderbot.iris.uniforms; import com.gtnewhorizons.angelica.rendering.RenderingState; +import lombok.Getter; import net.coderbot.iris.gl.uniform.UniformHolder; import net.minecraft.client.Minecraft; import org.joml.Vector3d; @@ -18,12 +19,13 @@ private CameraUniforms() { } public static void addCameraUniforms(UniformHolder uniforms, FrameUpdateNotifier notifier) { - CameraPositionTracker tracker = new CameraPositionTracker(notifier); + final CameraPositionTracker tracker = new CameraPositionTracker(notifier); uniforms .uniform1f(ONCE, "near", () -> 0.05) .uniform1f(PER_FRAME, "far", CameraUniforms::getRenderDistanceInBlocks) .uniform3d(PER_FRAME, "cameraPosition", tracker::getCurrentCameraPosition) + .uniform1f(PER_FRAME, "eyeAltitude", tracker::getCurrentCameraPositionY) .uniform3d(PER_FRAME, "previousCameraPosition", tracker::getPreviousCameraPosition); } @@ -46,8 +48,10 @@ static class CameraPositionTracker { private static final double WALK_RANGE = 30000; private static final double TP_RANGE = 1000; - private Vector3d previousCameraPosition = new Vector3d(); - private Vector3d currentCameraPosition = new Vector3d(); + @Getter + private Vector3d previousCameraPosition = new Vector3d(); + @Getter + private Vector3d currentCameraPosition = new Vector3d(); private final Vector3d shift = new Vector3d(); CameraPositionTracker(FrameUpdateNotifier notifier) { @@ -67,8 +71,8 @@ private void update() { * around a chunk border. */ private void updateShift() { - double dX = getShift(currentCameraPosition.x, previousCameraPosition.x); - double dZ = getShift(currentCameraPosition.z, previousCameraPosition.z); + final double dX = getShift(currentCameraPosition.x, previousCameraPosition.x); + final double dZ = getShift(currentCameraPosition.z, previousCameraPosition.z); if (dX != 0.0 || dZ != 0.0) { applyShift(dX, dZ); @@ -99,12 +103,8 @@ private void applyShift(double dX, double dZ) { previousCameraPosition.z += dZ; } - public Vector3d getCurrentCameraPosition() { - return currentCameraPosition; - } - - public Vector3d getPreviousCameraPosition() { - return previousCameraPosition; + public double getCurrentCameraPositionY() { + return currentCameraPosition.y; } } } diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index 3d008e977..327f8da6c 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -1,6 +1,6 @@ package net.coderbot.iris.uniforms; -import com.gtnewhorizons.angelica.client.Shaders; +import com.gtnewhorizons.angelica.compat.mojang.TextureAtlas; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.glsm.states.BlendState; import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.EntityRendererAccessor; @@ -10,10 +10,13 @@ import net.coderbot.iris.layer.GbufferPrograms; import net.coderbot.iris.shaderpack.IdMap; import net.coderbot.iris.shaderpack.PackDirectives; +import net.coderbot.iris.texture.TextureInfoCache; +import net.coderbot.iris.texture.TextureTracker; import net.coderbot.iris.uniforms.transforms.SmoothedFloat; import net.coderbot.iris.uniforms.transforms.SmoothedVec2f; import net.minecraft.block.material.Material; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; @@ -58,26 +61,24 @@ public static void addCommonUniforms(DynamicUniformHolder uniforms, IdMap idMap, // TODO: OptiFine doesn't think that atlasSize is a "dynamic" uniform, // but we do. How will custom uniforms depending on atlasSize work? uniforms.uniform2i("atlasSize", () -> { - return new Vector2i(Shaders.atlasSizeX, Shaders.atlasSizeY); -// int glId = GlStateManagerAccessor.getTEXTURES()[0].binding; -// -// AbstractTexture texture = TextureTracker.INSTANCE.getTexture(glId); -// if (texture instanceof TextureAtlas) { -// TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId); -// return new Vector2i(info.getWidth(), info.getHeight()); -// } -// -// return ZERO_VECTOR_2i; + final int glId = GLStateManager.getTextures()[0].binding; + + final AbstractTexture texture = TextureTracker.INSTANCE.getTexture(glId); + if (texture instanceof TextureAtlas) { + final TextureInfoCache.TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId); + return new Vector2i(info.getWidth(), info.getHeight()); + } + + return ZERO_VECTOR_2i; }, StateUpdateNotifiers.bindTextureNotifier); - // TODO: gTextureSize -// uniforms.uniform2i("gtextureSize", () -> { -// int glId = GlStateManagerAccessor.getTEXTURES()[0].binding; -// -// TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId); -// return new Vector2i(info.getWidth(), info.getHeight()); -// -// }, StateUpdateNotifiers.bindTextureNotifier); + uniforms.uniform2i("gtextureSize", () -> { + final int glId = GLStateManager.getTextures()[0].binding; + + final TextureInfoCache.TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId); + return new Vector2i(info.getWidth(), info.getHeight()); + + }, StateUpdateNotifiers.bindTextureNotifier); uniforms.uniform4i("blendFunc", () -> { final BlendState blend = GLStateManager.getBlendState(); @@ -95,11 +96,10 @@ public static void addCommonUniforms(DynamicUniformHolder uniforms, IdMap idMap, public static void generalCommonUniforms(UniformHolder uniforms, FrameUpdateNotifier updateNotifier, PackDirectives directives) { ExternallyManagedUniforms.addExternallyManagedUniforms116(uniforms); - SmoothedVec2f eyeBrightnessSmooth = new SmoothedVec2f(directives.getEyeBrightnessHalfLife(), directives.getEyeBrightnessHalfLife(), CommonUniforms::getEyeBrightness, updateNotifier); + final SmoothedVec2f eyeBrightnessSmooth = new SmoothedVec2f(directives.getEyeBrightnessHalfLife(), directives.getEyeBrightnessHalfLife(), CommonUniforms::getEyeBrightness, updateNotifier); uniforms .uniform1b(PER_FRAME, "hideGUI", () -> client.gameSettings.hideGUI) - .uniform1f(PER_FRAME, "eyeAltitude", Shaders::getEyePosY) // Objects.requireNonNull(client.getCameraEntity()).getEyeY()) .uniform1i(PER_FRAME, "isEyeInWater", CommonUniforms::isEyeInWater) .uniform1f(PER_FRAME, "blindness", CommonUniforms::getBlindness) .uniform1f(PER_FRAME, "nightVision", CommonUniforms::getNightVision) @@ -118,7 +118,7 @@ public static void generalCommonUniforms(UniformHolder uniforms, FrameUpdateNoti .uniform1f(PER_TICK, "playerMood", CommonUniforms::getPlayerMood) .uniform2i(PER_FRAME, "eyeBrightness", CommonUniforms::getEyeBrightness) .uniform2i(PER_FRAME, "eyeBrightnessSmooth", () -> { - Vector2f smoothed = eyeBrightnessSmooth.get(); + final Vector2f smoothed = eyeBrightnessSmooth.get(); return new Vector2i((int) smoothed.x(),(int) smoothed.y()); }) .uniform1f(PER_TICK, "rainStrength", CommonUniforms::getRainStrength) diff --git a/src/main/java/net/coderbot/iris/uniforms/FogUniforms.java b/src/main/java/net/coderbot/iris/uniforms/FogUniforms.java index 77f8b1680..5f690e658 100644 --- a/src/main/java/net/coderbot/iris/uniforms/FogUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/FogUniforms.java @@ -1,6 +1,6 @@ package net.coderbot.iris.uniforms; -import com.gtnewhorizons.angelica.client.Shaders; +import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.iris.gl.state.StateUpdateNotifiers; import net.coderbot.iris.gl.uniform.DynamicUniformHolder; @@ -11,29 +11,25 @@ private FogUniforms() { public static void addFogUniforms(DynamicUniformHolder uniforms) { uniforms.uniform1i("fogMode", () -> { - if(!Shaders.isFogEnabled()) return 0; + if(!GLStateManager.getFogState().mode.isEnabled()) return 0; - return Shaders.fogMode; - -// GlStateManager.FogState fog = GlStateManagerAccessor.getFOG(); -// if (!((BooleanStateAccessor) fog.enable).isEnabled()) { return 0; } -// return GlStateManagerAccessor.getFOG().mode; + return GLStateManager.getFogState().fogMode; }, listener -> { StateUpdateNotifiers.fogToggleNotifier.setListener(listener); StateUpdateNotifiers.fogModeNotifier.setListener(listener); }); - uniforms.uniform1f("fogDensity", () -> Shaders.fogDensity/*GlStateManagerAccessor.getFOG().density*/, listener -> { + uniforms.uniform1f("fogDensity", () -> GLStateManager.getFogState().density, listener -> { StateUpdateNotifiers.fogToggleNotifier.setListener(listener); StateUpdateNotifiers.fogDensityNotifier.setListener(listener); }); - uniforms.uniform1f("fogStart", () -> Shaders.fogStart/*GlStateManagerAccessor.getFOG().start*/, listener -> { + uniforms.uniform1f("fogStart", () -> GLStateManager.getFogState().start, listener -> { StateUpdateNotifiers.fogToggleNotifier.setListener(listener); StateUpdateNotifiers.fogStartNotifier.setListener(listener); }); - uniforms.uniform1f("fogEnd", () -> Shaders.fogEnd/*GlStateManagerAccessor.getFOG().end*/, listener -> { + uniforms.uniform1f("fogEnd", () -> GLStateManager.getFogState().end, listener -> { StateUpdateNotifiers.fogToggleNotifier.setListener(listener); StateUpdateNotifiers.fogEndNotifier.setListener(listener); }); diff --git a/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java b/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java index ce2e30522..5f5bc7ecb 100644 --- a/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java @@ -101,7 +101,7 @@ private static float getSneakFactor() { } private static float getHurtFactor() { - EntityPlayer player = Minecraft.getMinecraft().thePlayer; + final EntityPlayer player = Minecraft.getMinecraft().thePlayer; return player.hurtTime > 0 || player.deathTime > 0 ? 0.4f : 0f; } From 34eb21f0115d542e9d5e41c3ca2c797839b7ba0e Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 9 Dec 2023 12:35:53 -0800 Subject: [PATCH 245/301] More uniforms and last of ShaderMod usage --- .../uniforms/HardcodedCustomUniforms.java | 22 +++++++++---------- src/main/resources/META-INF/angelica_at.cfg | 1 + src/main/resources/META-INF/sodium_at.cfg | 18 --------------- 3 files changed, 12 insertions(+), 29 deletions(-) delete mode 100644 src/main/resources/META-INF/sodium_at.cfg diff --git a/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java b/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java index 5f5bc7ecb..a4caf3e23 100644 --- a/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java @@ -1,12 +1,13 @@ package net.coderbot.iris.uniforms; -import com.gtnewhorizons.angelica.client.Shaders; +import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.gl.uniform.UniformHolder; import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; import net.coderbot.iris.uniforms.transforms.SmoothedFloat; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import org.joml.Math; +import org.joml.Vector3d; // These expressions are copied directly from BSL and Complementary. @@ -28,10 +29,10 @@ public static void addHardcodedCustomUniforms(UniformHolder holder, FrameUpdateN CameraUniforms.CameraPositionTracker tracker = new CameraUniforms.CameraPositionTracker(updateNotifier); - SmoothedFloat eyeInCave = new SmoothedFloat(6, 12, HardcodedCustomUniforms::getEyeInCave, updateNotifier); - SmoothedFloat rainStrengthS = rainStrengthS(updateNotifier, 15, 15); - SmoothedFloat rainStrengthShining = rainStrengthS(updateNotifier, 10, 11); - SmoothedFloat rainStrengthS2 = rainStrengthS(updateNotifier, 70, 1); + final SmoothedFloat eyeInCave = new SmoothedFloat(6, 12, HardcodedCustomUniforms::getEyeInCave, updateNotifier); + final SmoothedFloat rainStrengthS = rainStrengthS(updateNotifier, 15, 15); + final SmoothedFloat rainStrengthShining = rainStrengthS(updateNotifier, 10, 11); + final SmoothedFloat rainStrengthS2 = rainStrengthS(updateNotifier, 70, 1); holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "timeAngle", HardcodedCustomUniforms::getTimeAngle); holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "timeBrightness", HardcodedCustomUniforms::getTimeBrightness); @@ -82,7 +83,7 @@ public static void addHardcodedCustomUniforms(UniformHolder holder, FrameUpdateN holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "touchmybody", new SmoothedFloat(0f, 0.1f, HardcodedCustomUniforms::getHurtFactor, updateNotifier)); holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "sneakSmooth", new SmoothedFloat(2.0f, 0.9f, HardcodedCustomUniforms::getSneakFactor, updateNotifier)); holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "burningSmooth", new SmoothedFloat(1.0f, 2.0f, HardcodedCustomUniforms::getBurnFactor, updateNotifier)); - SmoothedFloat smoothSpeed = new SmoothedFloat(1.0f, 1.5f, () -> getVelocity(tracker) / SystemTimeUniforms.TIMER.getLastFrameTime(), updateNotifier); + final SmoothedFloat smoothSpeed = new SmoothedFloat(1.0f, 1.5f, () -> getVelocity(tracker) / SystemTimeUniforms.TIMER.getLastFrameTime(), updateNotifier); holder.uniform1f(UniformUpdateFrequency.PER_FRAME, "effectStrength", () -> getHyperSpeedStrength(smoothSpeed)); } @@ -91,9 +92,8 @@ private static float getHyperSpeedStrength(SmoothedFloat smoothSpeed) { } private static float getBurnFactor() { - // todo: thePlayer.fire > 0 && !thePlayer.fireResistance - return 0f; -// return Minecraft.getMinecraft().thePlayer.isOnFire() ? 1.0f : 0f; + final EntityPlayer player = Minecraft.getMinecraft().thePlayer; + return player.fire > 0 && !player.isImmuneToFire() ? 1.0f : 0f; } private static float getSneakFactor() { @@ -106,8 +106,8 @@ private static float getHurtFactor() { } private static float getEyeInCave() { -// if (client.getCameraEntity().getEyeY() < 5.0) { - if (Shaders.getEyePosY() < 5.0) { + final Vector3d cameraPosition = RenderingState.INSTANCE.getCameraPosition(); + if (cameraPosition.y < 5.0) { return 1.0f - getEyeSkyBrightness() / 240F; } return 0.0f; diff --git a/src/main/resources/META-INF/angelica_at.cfg b/src/main/resources/META-INF/angelica_at.cfg index b3a70addc..18b4b9ec8 100644 --- a/src/main/resources/META-INF/angelica_at.cfg +++ b/src/main/resources/META-INF/angelica_at.cfg @@ -35,3 +35,4 @@ public net.minecraft.client.renderer.texture.TextureAtlasSprite field_147966_k # public net.minecraft.client.renderer.texture.TextureMap func_147634_a(Lnet/minecraft/util/ResourceLocation;I)Lnet/minecraft/util/ResourceLocation; # ResourceLocation completeResourceLocation(ResourceLocation, int) public net.minecraft.client.gui.GuiVideoSettings field_146498_f # parentGuiScreen +public net.minecraft.entity.Entity field_70151_c # fire diff --git a/src/main/resources/META-INF/sodium_at.cfg b/src/main/resources/META-INF/sodium_at.cfg deleted file mode 100644 index 2a6b57017..000000000 --- a/src/main/resources/META-INF/sodium_at.cfg +++ /dev/null @@ -1,18 +0,0 @@ -public net.minecraft.client.renderer.model.ModelRenderer$PositionTextureVertex -public net.minecraft.client.renderer.model.ModelRenderer$TexturedQuad -public net.minecraft.client.renderer.texture.TextureAtlasSprite$InterpolationData - -public net.minecraft.client.renderer.texture.TextureAtlasSprite$InterpolationData func_229257_a_()V # uploadInterpolatedFrame -public net.minecraft.client.renderer.culling.ClippingHelper func_228953_a_(DDDDDD)Z # cubeInFrustum - -public net.minecraft.state.StateHolder field_235892_c_ # owner -public net.minecraft.client.renderer.model.WeightedBakedModel$WeightedModel -public net.minecraft.client.renderer.model.WeightedBakedModel$WeightedModel field_185281_b # model - -public com.mojang.blaze3d.platform.GlStateManager$FogState -public com.mojang.blaze3d.platform.GlStateManager field_225663_h_ # FOG -public net.minecraft.client.renderer.FogRenderer field_205093_c # fogRed -public net.minecraft.client.renderer.FogRenderer field_205094_d # fogGreen -public net.minecraft.client.renderer.FogRenderer field_205095_e # fogBlue -public com.mojang.blaze3d.platform.GlStateManager$BooleanState -public com.mojang.blaze3d.platform.GlStateManager$BooleanState field_179201_b # enabled \ No newline at end of file From 5e030ceb9ea5bb4fe2c91cbe056f3cdfd8db8e06 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 9 Dec 2023 13:21:35 -0800 Subject: [PATCH 246/301] Fix a few missing DEG <> RAD... --- .../iris/shaderpack/PackDirectives.java | 104 ++++++------------ .../iris/uniforms/CelestialUniforms.java | 4 +- 2 files changed, 35 insertions(+), 73 deletions(-) diff --git a/src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java b/src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java index c62b817af..18a5e40b2 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java +++ b/src/main/java/net/coderbot/iris/shaderpack/PackDirectives.java @@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.objects.Object2BooleanMaps; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import lombok.Getter; import net.coderbot.iris.Iris; import net.coderbot.iris.gl.texture.TextureScaleOverride; import org.joml.Vector2i; @@ -12,30 +13,43 @@ import java.util.Set; public class PackDirectives { - private int noiseTextureResolution; - private float sunPathRotation; - private float ambientOcclusionLevel; - private float wetnessHalfLife; - private float drynessHalfLife; - private float eyeBrightnessHalfLife; - private float centerDepthHalfLife; - private CloudSetting cloudSetting; + @Getter + private int noiseTextureResolution; + @Getter + private float sunPathRotation; + @Getter + private float ambientOcclusionLevel; + @Getter + private float wetnessHalfLife; + @Getter + private float drynessHalfLife; + @Getter + private float eyeBrightnessHalfLife; + @Getter + private float centerDepthHalfLife; + @Getter + private CloudSetting cloudSetting; private boolean underwaterOverlay; private boolean vignette; private boolean sun; private boolean moon; private boolean rainDepth; private boolean separateAo; - private boolean oldLighting; + @Getter + private boolean oldLighting; private boolean concurrentCompute; - private boolean oldHandLight; + @Getter + private boolean oldHandLight; private boolean particlesBeforeDeferred; - private boolean prepareBeforeShadow; + @Getter + private boolean prepareBeforeShadow; private Object2ObjectMap> explicitFlips = new Object2ObjectOpenHashMap<>(); private Object2ObjectMap scaleOverrides = new Object2ObjectOpenHashMap<>(); - private final PackRenderTargetDirectives renderTargetDirectives; - private final PackShadowDirectives shadowDirectives; + @Getter + private final PackRenderTargetDirectives renderTargetDirectives; + @Getter + private final PackShadowDirectives shadowDirectives; private PackDirectives(Set supportedRenderTargets, PackShadowDirectives packShadowDirectives) { noiseTextureResolution = 256; @@ -79,39 +93,7 @@ private PackDirectives(Set supportedRenderTargets, PackShadowDirectives prepareBeforeShadow = directives.prepareBeforeShadow; } - public int getNoiseTextureResolution() { - return noiseTextureResolution; - } - - public float getSunPathRotation() { - return sunPathRotation; - } - - public float getAmbientOcclusionLevel() { - return ambientOcclusionLevel; - } - - public float getWetnessHalfLife() { - return wetnessHalfLife; - } - - public float getDrynessHalfLife() { - return drynessHalfLife; - } - - public float getEyeBrightnessHalfLife() { - return eyeBrightnessHalfLife; - } - - public float getCenterDepthHalfLife() { - return centerDepthHalfLife; - } - - public CloudSetting getCloudSetting() { - return cloudSetting; - } - - public boolean underwaterOverlay() { + public boolean underwaterOverlay() { return underwaterOverlay; } @@ -135,15 +117,7 @@ public boolean shouldUseSeparateAo() { return separateAo; } - public boolean isOldLighting() { - return oldLighting; - } - - public boolean isOldHandLight() { - return oldHandLight; - } - - public boolean areParticlesBeforeDeferred() { + public boolean areParticlesBeforeDeferred() { return particlesBeforeDeferred; } @@ -151,19 +125,7 @@ public boolean getConcurrentCompute() { return concurrentCompute; } - public boolean isPrepareBeforeShadow() { - return prepareBeforeShadow; - } - - public PackRenderTargetDirectives getRenderTargetDirectives() { - return renderTargetDirectives; - } - - public PackShadowDirectives getShadowDirectives() { - return shadowDirectives; - } - - private static float clamp(float val, float lo, float hi) { + private static float clamp(float val, float lo, float hi) { return Math.max(lo, Math.min(hi, val)); } @@ -206,7 +168,7 @@ public ImmutableMap getExplicitFlips(String pass) { int index = PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.indexOf(buffer); if (index == -1 && buffer.startsWith("colortex")) { - String id = buffer.substring("colortex".length()); + final String id = buffer.substring("colortex".length()); try { index = Integer.parseInt(id); @@ -231,10 +193,10 @@ public Vector2i getTextureScaleOverride(int index, int dimensionX, int dimension // TODO: How do custom textures interact with aliases? - Vector2i scale = new Vector2i(); + final Vector2i scale = new Vector2i(); if (index < PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.size()) { - String legacyName = PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.get(index); + final String legacyName = PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.get(index); if (scaleOverrides.containsKey(legacyName)) { scale.set(scaleOverrides.get(legacyName).getX(dimensionX), scaleOverrides.get(legacyName).getY(dimensionY)); diff --git a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java index 91765b6a1..d3068a3e0 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java @@ -79,7 +79,7 @@ private Vector4f getCelestialPositionInWorldSpace(float y) { // This is because we need the result of it before it's actually performed in vanilla. celestial.rotateY(-90.F * Constants.DEGREES_TO_RADIANS); celestial.rotateZ(sunPathRotation * Constants.DEGREES_TO_RADIANS); - celestial.rotateX(getSkyAngle() * 360.0F); + celestial.rotateX(getSkyAngle() * 360.0F * Constants.DEGREES_TO_RADIANS); celestial.transform(position); @@ -94,7 +94,7 @@ private Vector4f getCelestialPosition(float y) { // This is because we need the result of it before it's actually performed in vanilla. celestial.rotateY(-90.F * Constants.DEGREES_TO_RADIANS); celestial.rotateZ(sunPathRotation * Constants.DEGREES_TO_RADIANS); - celestial.rotateX(getSkyAngle() * 360.0F); + celestial.rotateX(getSkyAngle() * 360.0F * Constants.DEGREES_TO_RADIANS); position = celestial.transform(position); From bf16066b91cec5af183b6126e07d5c3ed0cc9135 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 9 Dec 2023 15:49:03 -0800 Subject: [PATCH 247/301] Don't need that.... --- .../java/com/gtnewhorizons/angelica/client/Shaders.java | 8 +++----- .../angelica/mixins/early/shaders/MixinRenderGlobal.java | 2 +- .../net/coderbot/iris/uniforms/CelestialUniforms.java | 6 +++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index 6ab4688dc..7309cee1b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -2235,12 +2235,10 @@ public static void setCamera(float tickDelta) { // GL11.glLoadIdentity(); // GL11.glTranslatef(0.0f, 0.0f, -100.0f); // GL11.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);- - float celestialAngle = mc.theWorld.getCelestialAngle(tickDelta); + final float celestialAngle = mc.theWorld.getCelestialAngle(tickDelta); sunAngle = (celestialAngle < 0.75f) ? celestialAngle + 0.25f : celestialAngle - 0.75f; - float angle = celestialAngle * (-360.0f); - float angleInterval = shadowAngleInterval > 0.0f - ? (angle % shadowAngleInterval - (shadowAngleInterval * 0.5f)) - : 0.0f; + final float angle = celestialAngle * (-360.0f); + final float angleInterval = shadowAngleInterval > 0.0f ? (angle % shadowAngleInterval - (shadowAngleInterval * 0.5f)) : 0.0f; if (sunAngle <= 0.5) { // day time // GL11.glRotatef(angle - angleInterval, 0.0f, 0.0f, 1.0f); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java index dc63c1cce..d2d049eee 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java @@ -52,7 +52,7 @@ public class MixinRenderGlobal { @Inject(method = "renderSky", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;getCelestialAngle(F)F"), slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;getRainStrength(F)F"))) private void iris$renderSky$tiltSun(float p_72714_1_, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { - GL11.glRotatef(pipeline.get().getSunPathRotation() * DEGREES_TO_RADIANS, 0.0F, 0.0F, 1.0F); + GL11.glRotatef(pipeline.get().getSunPathRotation(), 0.0F, 0.0F, 1.0F); } } diff --git a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java index d3068a3e0..f17390d14 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java @@ -34,7 +34,7 @@ public void addCelestialUniforms(UniformHolder uniforms) { } public static float getSunAngle() { - float skyAngle = getSkyAngle(); + final float skyAngle = getSkyAngle(); if (skyAngle < 0.75F) { return skyAngle + 0.25F; @@ -89,7 +89,7 @@ private Vector4f getCelestialPositionInWorldSpace(float y) { private Vector4f getCelestialPosition(float y) { Vector4f position = new Vector4f(0.0F, y, 0.0F, 0.0F); - Matrix4f celestial = new Matrix4f(RenderingState.INSTANCE.getModelViewMatrix()); + final Matrix4f celestial = new Matrix4f(RenderingState.INSTANCE.getModelViewMatrix()); // This is the same transformation applied by renderSky, however, it's been moved to here. // This is because we need the result of it before it's actually performed in vanilla. celestial.rotateY(-90.F * Constants.DEGREES_TO_RADIANS); @@ -105,7 +105,7 @@ private static Vector4f getUpPosition() { Vector4f upVector = new Vector4f(0.0F, 100.0F, 0.0F, 0.0F); // Get the current model view matrix, since that is the basis of the celestial model view matrix - Matrix4f preCelestial = new Matrix4f(RenderingState.INSTANCE.getModelViewMatrix()); + final Matrix4f preCelestial = new Matrix4f(RenderingState.INSTANCE.getModelViewMatrix()); // Apply the fixed -90.0F degrees rotation to mirror the same transformation in renderSky. // But, notably, skip the rotation by the skyAngle. From 04d85c1b002e1b12f48780daefbb49aa9dc1925f Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 9 Dec 2023 23:11:40 -0800 Subject: [PATCH 248/301] Update README --- README.MD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.MD b/README.MD index be602ec03..98e7ccb2d 100644 --- a/README.MD +++ b/README.MD @@ -1,5 +1,7 @@ # Angelica The little Angle that supports shaders while saving your fps from a certain death -boubou +Is it obtuse, or accute? -Caedis +It's a cute angle -mitchej123 Not yet in an usable state From aade6b355917af69884097b0032ad46d11246ba5 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 9 Dec 2023 23:21:51 -0800 Subject: [PATCH 249/301] More credits --- README.MD | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.MD b/README.MD index 98e7ccb2d..b8d4ffc1e 100644 --- a/README.MD +++ b/README.MD @@ -26,4 +26,6 @@ Not yet in an usable state * HUDCaching * Backported from https://github.com/Sk1erLLC/Patcher by Alexdoru under the CC-BY-SA-NC 4.0 license * Angelica - * [Insert your name here] for helping get Angelica up and running! + * mitchej123, Omni, Makamys, Embeddedt, NanoLive, Caedis, Cardinalstar, Alexdoru, Eigenraven, mist475, Clepto for helping get Angelica up and running! + * IMS, jss2a98aj, || dbp ||, roadhog360 for advice and moral support + * 🖕 to the people who said it couldn't be done From 2e3270ea282f5379bd418814ab726158463ebcc2 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 9 Dec 2023 23:22:46 -0800 Subject: [PATCH 250/301] proper attribution --- README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MD b/README.MD index b8d4ffc1e..e35a2dacb 100644 --- a/README.MD +++ b/README.MD @@ -28,4 +28,4 @@ Not yet in an usable state * Angelica * mitchej123, Omni, Makamys, Embeddedt, NanoLive, Caedis, Cardinalstar, Alexdoru, Eigenraven, mist475, Clepto for helping get Angelica up and running! * IMS, jss2a98aj, || dbp ||, roadhog360 for advice and moral support - * 🖕 to the people who said it couldn't be done + * "🖕 to the people who said it couldn't be done" -GitHub Copilot From 7ea4c4d45016b36664fd1ba7362592d91259a72d Mon Sep 17 00:00:00 2001 From: Alexdoru <57050655+Alexdoru@users.noreply.github.com> Date: Sun, 10 Dec 2023 13:10:10 +0100 Subject: [PATCH 251/301] typo readme + change credits fro HUD Caching --- README.MD | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.MD b/README.MD index e35a2dacb..6e7dc38bf 100644 --- a/README.MD +++ b/README.MD @@ -1,9 +1,9 @@ # Angelica -The little Angle that supports shaders while saving your fps from a certain death -boubou +The little Angel that supports shaders while saving your fps from a certain death -boubou Is it obtuse, or accute? -Caedis -It's a cute angle -mitchej123 +It's a cute angel -mitchej123 -Not yet in an usable state +**Not yet in an usable state** # Credits * ShadersMod @@ -24,7 +24,7 @@ Not yet in an usable state * Neodymium * Makamys for [Neodymium](https://github.com/makamys/Neodymium) - Various Tessellator -> Quad functionality taken under the LGPL 3 * HUDCaching - * Backported from https://github.com/Sk1erLLC/Patcher by Alexdoru under the CC-BY-SA-NC 4.0 license + * Created by [Moulberry](https://github.com/Moulberry/MCHUDCaching), backported from [Patcher](https://github.com/Sk1erLLC/Patcher) mod by Alexdoru under the CC-BY-SA-NC 4.0 license * Angelica * mitchej123, Omni, Makamys, Embeddedt, NanoLive, Caedis, Cardinalstar, Alexdoru, Eigenraven, mist475, Clepto for helping get Angelica up and running! * IMS, jss2a98aj, || dbp ||, roadhog360 for advice and moral support From bf71bb4a944a8edd024e329d3c1e0bb2c93ce77c Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 10 Dec 2023 09:23:59 -0800 Subject: [PATCH 252/301] Restore correctly quoted typo --- README.MD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.MD b/README.MD index 6e7dc38bf..d34f629da 100644 --- a/README.MD +++ b/README.MD @@ -1,7 +1,7 @@ # Angelica -The little Angel that supports shaders while saving your fps from a certain death -boubou +The little Angle that supports shaders while saving your fps from a certain death -boubou Is it obtuse, or accute? -Caedis -It's a cute angel -mitchej123 +It's a cute angle -mitchej123 **Not yet in an usable state** From 37bd06b2ede78517885775d40d397d906471a61c Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 10 Dec 2023 09:57:21 -0800 Subject: [PATCH 253/301] Water progress * Return a block instead of a BlockMatch (at least for now) for populating mc_entity --- .../chunk/compile/ChunkBuildBuffers.java | 7 ++-- .../block_rendering/BlockMaterialMapping.java | 33 +++++++++---------- .../BlockRenderingSettings.java | 9 +++-- .../net/coderbot/iris/shaderpack/IdMap.java | 8 ++--- .../shaderpack/materialmap/BlockEntry.java | 24 +++++--------- .../block_context/BlockContextHolder.java | 5 ++- 6 files changed, 38 insertions(+), 48 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java index 60ff9863c..8705c061b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java @@ -18,7 +18,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import net.coderbot.iris.block_rendering.BlockRenderingSettings; -import net.coderbot.iris.shaderpack.materialmap.BlockMatch; import net.coderbot.iris.sodium.block_context.BlockContextHolder; import net.coderbot.iris.sodium.block_context.ChunkBuildBuffersExt; import net.coderbot.iris.sodium.block_context.ContextAwareVertexWriter; @@ -54,9 +53,9 @@ public ChunkBuildBuffers(ChunkVertexType vertexType) { this.offset = new ChunkModelOffset(); for (BlockRenderPass pass : BlockRenderPass.VALUES) { - int passId = pass.ordinal(); + final int passId = pass.ordinal(); - VertexBufferBuilder[] buffers = this.buffersByLayer[passId]; + final VertexBufferBuilder[] buffers = this.buffersByLayer[passId]; for (ModelQuadFacing facing : ModelQuadFacing.VALUES) { buffers[facing.ordinal()] = new VertexBufferBuilder(vertexType.getBufferVertexFormat(), EXPECTED_BUFFER_SIZE / ModelQuadFacing.COUNT); @@ -64,7 +63,7 @@ public ChunkBuildBuffers(ChunkVertexType vertexType) { } if(AngelicaConfig.enableIris) { - Object2IntMap blockMatches = BlockRenderingSettings.INSTANCE.getBlockMatches(); + final Object2IntMap blockMatches = BlockRenderingSettings.INSTANCE.getBlockMatches(); if (blockMatches != null) { this.iris$contextHolder = new BlockContextHolder(blockMatches); diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java index 280c4ca26..e6bee3c80 100644 --- a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java @@ -6,7 +6,6 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import net.coderbot.iris.shaderpack.materialmap.BlockEntry; -import net.coderbot.iris.shaderpack.materialmap.BlockMatch; import net.coderbot.iris.shaderpack.materialmap.BlockRenderType; import net.coderbot.iris.shaderpack.materialmap.NamespacedId; import net.minecraft.block.Block; @@ -15,11 +14,10 @@ import java.util.List; import java.util.Map; -import java.util.Set; public class BlockMaterialMapping { - public static Object2IntMap createBlockStateIdMap(Int2ObjectMap> blockPropertiesMap) { - Object2IntMap blockMatches = new Object2IntOpenHashMap<>(); + public static Object2IntMap createBlockStateIdMap(Int2ObjectMap> blockPropertiesMap) { + Object2IntMap blockMatches = new Object2IntOpenHashMap<>(); blockPropertiesMap.forEach((intId, entries) -> { for (BlockEntry entry : entries) { @@ -59,11 +57,11 @@ private static RenderLayer convertBlockToRenderType(BlockRenderType type) { }; } - private static void addBlock(BlockEntry entry, Object2IntMap idMap, int intId) { + private static void addBlock(BlockEntry entry, Object2IntMap idMap, int intId) { final NamespacedId id = entry.getId(); final ResourceLocation resourceLocation = new ResourceLocation(id.getNamespace(), id.getName()); - Block block = (Block) Block.blockRegistry.getObject(resourceLocation.toString()); + final Block block = (Block) Block.blockRegistry.getObject(resourceLocation.toString()); // If the block doesn't exist, by default the registry will return AIR. That probably isn't what we want. // TODO: Assuming that Registry.BLOCK.getDefaultId() == "minecraft:air" here @@ -71,18 +69,19 @@ private static void addBlock(BlockEntry entry, Object2IntMap idMap, return; } - Set metas = entry.getMetas(); + idMap.put(block, intId); - // All metas match - if (metas.isEmpty()) { - idMap.putIfAbsent(new BlockMatch(block, null), intId); - return; - } - - // A subset of metas match - for(int meta : metas) { - idMap.putIfAbsent(new BlockMatch(block, meta), intId); - } +// Set metas = entry.getMetas(); +// // All metas match +// if (metas.isEmpty()) { +// idMap.putIfAbsent(new BlockMatch(block, null), intId); +// return; +// } +// +// // A subset of metas match +// for(int meta : metas) { +// idMap.putIfAbsent(new BlockMatch(block, meta), intId); +// } } // We ignore generics here, the actual types don't matter because we just convert diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java index 7c3432f52..a234d6662 100644 --- a/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java @@ -1,10 +1,9 @@ package net.coderbot.iris.block_rendering; +import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import it.unimi.dsi.fastutil.objects.Object2IntFunction; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; import lombok.Getter; -import net.coderbot.iris.shaderpack.materialmap.BlockMatch; import net.coderbot.iris.shaderpack.materialmap.NamespacedId; import net.minecraft.block.Block; import org.jetbrains.annotations.Nullable; @@ -16,7 +15,7 @@ public class BlockRenderingSettings { @Getter private boolean reloadRequired; - private Object2IntMap blockMatches; + private Object2IntMap blockMatches; private Map blockTypeIds; private Object2IntFunction entityIds; private float ambientOcclusionLevel; @@ -39,7 +38,7 @@ public void clearReloadRequired() { } @Nullable - public Object2IntMap getBlockMatches() { + public Object2IntMap getBlockMatches() { return blockMatches; } @@ -53,7 +52,7 @@ public Object2IntFunction getEntityIds() { return entityIds; } - public void setBlockMatches(Object2IntMap blockIds) { + public void setBlockMatches(Object2IntMap blockIds) { if (this.blockMatches != null && this.blockMatches.equals(blockIds)) { return; } diff --git a/src/main/java/net/coderbot/iris/shaderpack/IdMap.java b/src/main/java/net/coderbot/iris/shaderpack/IdMap.java index 61286a573..b4dbd6579 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/IdMap.java +++ b/src/main/java/net/coderbot/iris/shaderpack/IdMap.java @@ -175,15 +175,15 @@ private static Int2ObjectMap> parseBlockMap(Properties properti Int2ObjectMap> entriesById = new Int2ObjectOpenHashMap<>(); properties.forEach((keyObject, valueObject) -> { - String key = (String) keyObject; - String value = (String) valueObject; + final String key = (String) keyObject; + final String value = (String) valueObject; if (!key.startsWith(keyPrefix)) { // Not a valid line, ignore it return; } - int intId; + final int intId; try { intId = Integer.parseInt(key.substring(keyPrefix.length())); @@ -193,7 +193,7 @@ private static Int2ObjectMap> parseBlockMap(Properties properti return; } - List entries = new ArrayList<>(); + final List entries = new ArrayList<>(); // Split on whitespace groups, not just single spaces for (String part : value.split("\\s+")) { diff --git a/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockEntry.java b/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockEntry.java index d20e77456..77388cea4 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockEntry.java +++ b/src/main/java/net/coderbot/iris/shaderpack/materialmap/BlockEntry.java @@ -1,5 +1,6 @@ package net.coderbot.iris.shaderpack.materialmap; +import lombok.Getter; import net.coderbot.iris.Iris; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; @@ -9,6 +10,7 @@ import java.util.Objects; import java.util.Set; +@Getter public class BlockEntry { private final NamespacedId id; private final Set metas; @@ -30,7 +32,7 @@ public static BlockEntry parse(@NotNull String entry) { } // We can assume that this array is of at least array length because the input string is non-empty. - String[] splitStates = entry.split(":"); + final String[] splitStates = entry.split(":"); // Trivial case: no states, no namespace if (splitStates.length == 1) { @@ -61,8 +63,8 @@ public static BlockEntry parse(@NotNull String entry) { } // Complex case: One or more states involved... - int statesStart; - NamespacedId id; + final int statesStart; + final NamespacedId id; if (StringUtils.isNumeric(splitStates[1].substring(0, 1))) { // We have an entry of the form "stone:0" @@ -74,11 +76,11 @@ public static BlockEntry parse(@NotNull String entry) { id = new NamespacedId(splitStates[0], splitStates[1]); } - Set metas = new HashSet<>(); + final Set metas = new HashSet<>(); for (int index = statesStart; index < splitStates.length; index++) { // Parse out one or more metadata ids - String[] metaParts = splitStates[index].split(", "); + final String[] metaParts = splitStates[index].split(", "); for (String metaPart : metaParts) { try { @@ -93,19 +95,11 @@ public static BlockEntry parse(@NotNull String entry) { return new BlockEntry(id, metas); } - public NamespacedId getId() { - return id; - } - - public Set getMetas() { - return metas; - } - - @Override + @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - BlockEntry that = (BlockEntry) o; + final BlockEntry that = (BlockEntry) o; return Objects.equals(id, that.id) && Objects.equals(metas, that.metas); } diff --git a/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java b/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java index 9f1a7a3dd..6f7e601ff 100644 --- a/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java +++ b/src/main/java/net/coderbot/iris/sodium/block_context/BlockContextHolder.java @@ -2,11 +2,10 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMaps; -import net.coderbot.iris.shaderpack.materialmap.BlockMatch; import net.minecraft.block.Block; public class BlockContextHolder { - private final Object2IntMap blockMatches; + private final Object2IntMap blockMatches; public int localPosX; public int localPosY; @@ -21,7 +20,7 @@ public BlockContextHolder() { this.renderType = -1; } - public BlockContextHolder(Object2IntMap idMap) { + public BlockContextHolder(Object2IntMap idMap) { this.blockMatches = idMap; this.blockId = -1; this.renderType = -1; From 4e6ae74e751962fac463d43ecfb16fbcbc90844c Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 10 Dec 2023 11:31:34 -0800 Subject: [PATCH 254/301] Uniforms audit --- .../early/sodium/MixinRenderGlobal.java | 2 +- .../iris/uniforms/CommonUniforms.java | 12 +++-------- .../uniforms/HardcodedCustomUniforms.java | 12 +++++------ .../iris/uniforms/IrisExclusiveUniforms.java | 12 ++++++----- .../iris/uniforms/MatrixUniforms.java | 2 -- .../iris/uniforms/SystemTimeUniforms.java | 21 +++++++------------ .../iris/uniforms/ViewportUniforms.java | 9 +++----- .../iris/uniforms/WorldTimeUniforms.java | 21 +++---------------- 8 files changed, 30 insertions(+), 61 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 037b5b46a..94e55ede4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -192,7 +192,7 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) } private boolean isSpectatorMode() { - PlayerControllerMP controller = Minecraft.getMinecraft().playerController; + final PlayerControllerMP controller = Minecraft.getMinecraft().playerController; if(controller == null) return false; return controller.currentGameType.getID() == 3; diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index 327f8da6c..6175c005a 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -141,13 +141,7 @@ private static boolean isInvisible() { } private static boolean isBurning() { - // todo: thePlayer.fire > 0 && !thePlayer.fireResistance - return false; - // if (client.thePlayer != null) { - // return client.thePlayer.isOnFire(); - // } else { - // return false; - // } + return client.thePlayer != null && client.thePlayer.fire > 0 && !client.thePlayer.isImmuneToFire(); } private static boolean isSneaking() { @@ -167,7 +161,7 @@ private static Vector3d getSkyColor() { } static float getBlindness() { - EntityLivingBase cameraEntity = client.renderViewEntity; + final EntityLivingBase cameraEntity = client.renderViewEntity; if (cameraEntity instanceof EntityLiving livingEntity && livingEntity.isPotionActive(Potion.blindness)) { final PotionEffect blindness = livingEntity.getActivePotionEffect(Potion.blindness); @@ -207,7 +201,7 @@ private static Vector2i getEyeBrightness() { if (client.renderViewEntity == null || client.theWorld == null) { return ZERO_VECTOR_2i; } - + // This is what ShadersMod did in 1.7.10 final int eyeBrightness = client.renderViewEntity.getBrightnessForRender(CapturedRenderingState.INSTANCE.getTickDelta()); return new Vector2i((eyeBrightness & 0xffff), (eyeBrightness >> 16)); diff --git a/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java b/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java index a4caf3e23..24994aeaf 100644 --- a/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/HardcodedCustomUniforms.java @@ -145,10 +145,10 @@ private static SmoothedFloat getStarter(CameraUniforms.CameraPositionTracker tra } private static float getMoving(CameraUniforms.CameraPositionTracker tracker) { - float difX = (float) (tracker.getCurrentCameraPosition().x - tracker.getPreviousCameraPosition().x); - float difY = (float) (tracker.getCurrentCameraPosition().y - tracker.getPreviousCameraPosition().y); - float difZ = (float) (tracker.getCurrentCameraPosition().z - tracker.getPreviousCameraPosition().z); - float difSum = Math.abs(difX) + Math.abs(difY) + Math.abs(difZ); + final float difX = (float) (tracker.getCurrentCameraPosition().x - tracker.getPreviousCameraPosition().x); + final float difY = (float) (tracker.getCurrentCameraPosition().y - tracker.getPreviousCameraPosition().y); + final float difZ = (float) (tracker.getCurrentCameraPosition().z - tracker.getPreviousCameraPosition().z); + final float difSum = Math.abs(difX) + Math.abs(difY) + Math.abs(difZ); return (difSum > 0.0F && difSum < 1.0F) ? 1 : 0; } @@ -157,12 +157,10 @@ private static float getTimeAngle() { } private static int getWorldDayTime() { - long timeOfDay = Minecraft.getMinecraft().theWorld.getWorldTime(); + return (int) (Minecraft.getMinecraft().theWorld.getWorldTime() % 24000L); // Level level = Minecraft.getMinecraft().theWorld; // long timeOfDay = level.getDayTime(); // long dayTime = ((DimensionTypeAccessor) level.dimensionType()).getFixedTime().orElse(timeOfDay % 24000L); - - return (int) timeOfDay; } private static float getTimeBrightness() { diff --git a/src/main/java/net/coderbot/iris/uniforms/IrisExclusiveUniforms.java b/src/main/java/net/coderbot/iris/uniforms/IrisExclusiveUniforms.java index 64f971e53..ff4ef3e20 100644 --- a/src/main/java/net/coderbot/iris/uniforms/IrisExclusiveUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/IrisExclusiveUniforms.java @@ -3,6 +3,7 @@ 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.EntityLivingBase; import org.joml.Math; @@ -91,21 +92,22 @@ private static boolean isFirstPersonCamera() { } private static boolean isSpectator() { -// return Minecraft.getMinecraft().gameMode.getPlayerMode() == GameType.SPECTATOR; - // TODO: AF? EFR? - return false; + final PlayerControllerMP controller = Minecraft.getMinecraft().playerController; + if(controller == null) + return false; + return controller.currentGameType.getID() == 3; } private static Vector3d getEyePosition() { // Objects.requireNonNull(Minecraft.getMinecraft().getCameraEntity()); // return new Vector3d(Minecraft.getMinecraft().getCameraEntity().getX(), Minecraft.getMinecraft().getCameraEntity().getEyeY(), Minecraft.getMinecraft().getCameraEntity().getZ()); - EntityLivingBase eye = Minecraft.getMinecraft().renderViewEntity; + final EntityLivingBase eye = Minecraft.getMinecraft().renderViewEntity; return new Vector3d(eye.posX, eye.posY, eye.posZ); } public static class WorldInfoUniforms { public static void addWorldInfoUniforms(UniformHolder uniforms) { - WorldClient level = Minecraft.getMinecraft().theWorld; + final WorldClient level = Minecraft.getMinecraft().theWorld; uniforms.uniform1i(UniformUpdateFrequency.PER_FRAME, "bedrockLevel", () -> 0); uniforms.uniform1f(UniformUpdateFrequency.PER_FRAME, "cloudHeight", () -> { if (level != null && level.provider != null) { diff --git a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java index 89e2e11c9..34862d742 100644 --- a/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/MatrixUniforms.java @@ -6,9 +6,7 @@ import net.coderbot.iris.shaderpack.PackDirectives; import net.coderbot.iris.shadow.ShadowMatrices; import org.joml.Matrix4f; -import org.lwjgl.BufferUtils; -import java.nio.FloatBuffer; import java.util.function.Supplier; import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME; diff --git a/src/main/java/net/coderbot/iris/uniforms/SystemTimeUniforms.java b/src/main/java/net/coderbot/iris/uniforms/SystemTimeUniforms.java index c2c9fdc66..4bf8ce6d1 100644 --- a/src/main/java/net/coderbot/iris/uniforms/SystemTimeUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/SystemTimeUniforms.java @@ -1,5 +1,6 @@ package net.coderbot.iris.uniforms; +import lombok.Getter; import net.coderbot.iris.gl.uniform.UniformHolder; import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; @@ -66,8 +67,10 @@ public void reset() { * of the first frame to the start of the current frame. Updated at the start of each frame. */ public static final class Timer { - private float frameTimeCounter; - private float lastFrameTime; + @Getter + private float frameTimeCounter; + @Getter + private float lastFrameTime; // Disabling this because OptionalLong provides a nice wrapper around (boolean valid, long value) @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @@ -80,9 +83,9 @@ public Timer() { public void beginFrame(long frameStartTime) { // Track how much time passed since the last time we began rendering a frame. // If this is the first frame, then use a value of 0. - long diffNs = frameStartTime - lastStartTime.orElse(frameStartTime); + final long diffNs = frameStartTime - lastStartTime.orElse(frameStartTime); // Convert to milliseconds - long diffMs = (diffNs / 1000) / 1000; + final long diffMs = (diffNs / 1000) / 1000; // Convert to seconds with a resolution of 1 millisecond, and store as the time taken for the last frame to complete. lastFrameTime = diffMs / 1000.0F; @@ -100,15 +103,7 @@ public void beginFrame(long frameStartTime) { lastStartTime = OptionalLong.of(frameStartTime); } - public float getFrameTimeCounter() { - return frameTimeCounter; - } - - public float getLastFrameTime() { - return lastFrameTime; - } - - public void reset() { + public void reset() { frameTimeCounter = 0.0F; lastFrameTime = 0.0F; lastStartTime = OptionalLong.empty(); diff --git a/src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java b/src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java index c70c1c201..199a1b0af 100644 --- a/src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/ViewportUniforms.java @@ -24,10 +24,8 @@ public static void addViewportUniforms(UniformHolder uniforms) { // TODO: What about the custom scale.composite3 property? // NB: It is not safe to cache the render target due to mods like Resolution Control modifying the render target field. uniforms -// .uniform1f(PER_FRAME, "viewHeight", () -> Minecraft.getMinecraft().getMainRenderTarget().height) - .uniform1f(PER_FRAME, "viewHeight", () -> Minecraft.getMinecraft().displayHeight) -// .uniform1f(PER_FRAME, "viewWidth", () -> Minecraft.getMinecraft().getMainRenderTarget().width) - .uniform1f(PER_FRAME, "viewWidth", () -> Minecraft.getMinecraft().displayWidth) + .uniform1f(PER_FRAME, "viewHeight", () -> Minecraft.getMinecraft().getFramebuffer().framebufferHeight) + .uniform1f(PER_FRAME, "viewWidth", () -> Minecraft.getMinecraft().getFramebuffer().framebufferWidth) .uniform1f(PER_FRAME, "aspectRatio", ViewportUniforms::getAspectRatio); } @@ -35,7 +33,6 @@ public static void addViewportUniforms(UniformHolder uniforms) { * @return the current viewport aspect ratio, calculated from the current Minecraft window size */ private static float getAspectRatio() { -// return ((float) Minecraft.getMinecraft().getMainRenderTarget().width) / ((float) Minecraft.getMinecraft().getMainRenderTarget().height); - return ((float) Minecraft.getMinecraft().displayWidth) / ((float) Minecraft.getMinecraft().displayHeight); + return ((float) Minecraft.getMinecraft().getFramebuffer().framebufferWidth) / ((float) Minecraft.getMinecraft().getFramebuffer().framebufferHeight); } } diff --git a/src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java b/src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java index dca8f8330..170dc9477 100644 --- a/src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/WorldTimeUniforms.java @@ -1,8 +1,6 @@ package net.coderbot.iris.uniforms; -import net.coderbot.iris.Iris; import net.coderbot.iris.gl.uniform.UniformHolder; -import net.coderbot.iris.shaderpack.DimensionId; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; @@ -27,26 +25,13 @@ public static void addWorldTimeUniforms(UniformHolder uniforms) { } static int getWorldDayTime() { - long timeOfDay = getWorld().getWorldTime(); + return (int) (getWorld().getWorldTime() % 24000L); - if (Iris.getCurrentDimension() == DimensionId.END || Iris.getCurrentDimension() == DimensionId.NETHER) { - // If the dimension is the nether or the end, don't override the fixed time. - // This was an oversight in versions before and including 1.2.5 causing inconsistencies, such as Complementary's ender beams not moving. - return (int) (timeOfDay % 24000L); - } - - long dayTime = Minecraft.getMinecraft().theWorld.getWorldTime(); -// long dayTime = ((DimensionTypeAccessor) getWorld().dimensionType()).getFixedTime() -// .orElse(timeOfDay % 24000L); - - return (int) dayTime; + // long dayTime = ((DimensionTypeAccessor) getWorld().dimensionType()).getFixedTime().orElse(timeOfDay % 24000L); } private static int getWorldDay() { - long timeOfDay = getWorld().getWorldTime(); - long day = timeOfDay / 24000L; - - return (int) day; + return (int) (getWorld().getWorldTime() / 24000L); } private static WorldClient getWorld() { From e1e9d661fa53f5162f5fa89f93ac9dda2b844eef Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 10 Dec 2023 12:50:23 -0800 Subject: [PATCH 255/301] Lightmap workaround --- src/main/java/net/coderbot/iris/samplers/IrisSamplers.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java b/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java index 7fd4941bc..e88508713 100644 --- a/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java +++ b/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java @@ -17,8 +17,9 @@ public class IrisSamplers { public static final int ALBEDO_TEXTURE_UNIT = 0; + // TODO: Find equivalent in 1.7.10 public static final int OVERLAY_TEXTURE_UNIT = 1; - public static final int LIGHTMAP_TEXTURE_UNIT = 2; + public static final int LIGHTMAP_TEXTURE_UNIT = 1; public static final ImmutableSet WORLD_RESERVED_TEXTURE_UNITS = ImmutableSet.of(0, 1, 2); @@ -140,7 +141,9 @@ public static void addLevelSamplers(SamplerHolder samplers, WorldRenderingPipeli } if (availability.overlay) { - samplers.addExternalSampler(OVERLAY_TEXTURE_UNIT, "iris_overlay"); + // TODO: Overlay equivalent in 1.7.10? +// samplers.addExternalSampler(OVERLAY_TEXTURE_UNIT, "iris_overlay"); + samplers.addDynamicSampler(whitePixel::getGlTextureId, "iris_overlay"); } else { samplers.addDynamicSampler(whitePixel::getGlTextureId, "iris_overlay"); } From adcda9e43894ec6bb11e74868893b3bb92c71e37 Mon Sep 17 00:00:00 2001 From: rjnasers Date: Mon, 11 Dec 2023 17:41:55 -0600 Subject: [PATCH 256/301] PBR compiling, stuck on Normal and Specular textures being added in --- .../gtnewhorizons/angelica/mixins/Mixins.java | 2 + .../AnimationMetadataSectionAccessor.java | 23 + .../accessors/TextureAtlasSpriteAccessor.java | 18 +- .../shaders/accessors/TextureMapAccessor.java | 21 + .../texture/format/LabPBRTextureFormat.java | 15 +- .../iris/texture/format/TextureFormat.java | 5 +- .../texture/mipmap/CustomMipmapGenerator.java | 12 +- .../iris/texture/pbr/PBRAtlasTexture.java | 11 +- .../texture/pbr/loader/AtlasPBRLoader.java | 451 ++++++++++-------- .../pbr/loader/PBRTextureLoaderRegistry.java | 11 +- .../pbr/loader/TextureAtlasSpriteInfo.java | 30 ++ 11 files changed, 374 insertions(+), 225 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/AnimationMetadataSectionAccessor.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureMapAccessor.java create mode 100644 src/main/java/net/coderbot/iris/texture/pbr/loader/TextureAtlasSpriteInfo.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 8ac5b84e1..9bb49d2c2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -130,6 +130,8 @@ public enum Mixins { ,"shaders.accessors.EntityRendererAccessor" ,"shaders.accessors.SimpleTextureAccessor" ,"shaders.accessors.TextureAtlasSpriteAccessor" + ,"shaders.accessors.TextureMapAccessor" + ,"shaders.accessors.AnimationMetadataSectionAccessor" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/AnimationMetadataSectionAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/AnimationMetadataSectionAccessor.java new file mode 100644 index 000000000..83e260c16 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/AnimationMetadataSectionAccessor.java @@ -0,0 +1,23 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders.accessors; + +import net.minecraft.client.resources.data.AnimationMetadataSection; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(AnimationMetadataSection.class) +public interface AnimationMetadataSectionAccessor { + @Accessor("frameWidth") + int getFrameWidth(); + + @Mutable + @Accessor("frameWidth") + void setFrameWidth(int frameWidth); + + @Accessor("frameHeight") + int getFrameHeight(); + + @Mutable + @Accessor("frameHeight") + void setFrameHeight(int frameHeight); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureAtlasSpriteAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureAtlasSpriteAccessor.java index fc23b9f05..d6a74e3d6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureAtlasSpriteAccessor.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureAtlasSpriteAccessor.java @@ -5,19 +5,21 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; +import java.util.List; + @Mixin(TextureAtlasSprite.class) public interface TextureAtlasSpriteAccessor { @Accessor("animationMetadata") AnimationMetadataSection getMetadata(); -// @Accessor("mainImage") -// NativeImage[] getMainImage(); -// -// @Accessor("x") -// int getX(); -// -// @Accessor("y") -// int getY(); + @Accessor("framesTextureData") + List getFramesTextureData(); + + @Accessor("originX") + int getX(); + + @Accessor("originY") + int getY(); @Accessor("frameCounter") int getFrame(); diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureMapAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureMapAccessor.java new file mode 100644 index 000000000..e9389e612 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureMapAccessor.java @@ -0,0 +1,21 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders.accessors; + +import net.minecraft.client.renderer.texture.TextureMap; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(TextureMap.class) +public interface TextureMapAccessor { + + @Accessor("mapUploadedSprites") + Map getMapUploadedSprites(); + + @Accessor("anisotropicFiltering") + int getAnisotropicFiltering(); + + @Accessor("mipmapLevels") + int getMipmapLevels(); + +} diff --git a/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java b/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java index 3bfc873b5..2e8029b4f 100644 --- a/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java +++ b/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java @@ -1,6 +1,7 @@ package net.coderbot.iris.texture.format; import net.coderbot.iris.texture.mipmap.ChannelMipmapGenerator; +import net.coderbot.iris.texture.mipmap.CustomMipmapGenerator; import net.coderbot.iris.texture.mipmap.DiscreteBlendFunction; import net.coderbot.iris.texture.mipmap.LinearBlendFunction; import net.coderbot.iris.texture.pbr.PBRType; @@ -45,13 +46,13 @@ public boolean canInterpolateValues(PBRType pbrType) { } // TODO: PBR -// @Override -// public @Nullable CustomMipmapGenerator getMipmapGenerator(PBRType pbrType) { -// if (pbrType == PBRType.SPECULAR) { -// return SPECULAR_MIPMAP_GENERATOR; -// } -// return null; -// } + @Override + public @Nullable CustomMipmapGenerator getMipmapGenerator(PBRType pbrType) { + if (pbrType == PBRType.SPECULAR) { + return SPECULAR_MIPMAP_GENERATOR; + } + return null; + } @Override public int hashCode() { diff --git a/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java b/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java index f4d4e04d2..1be75c2d8 100644 --- a/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java +++ b/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java @@ -1,6 +1,7 @@ package net.coderbot.iris.texture.format; import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.texture.mipmap.CustomMipmapGenerator; import net.coderbot.iris.texture.pbr.PBRType; import net.minecraft.client.renderer.texture.AbstractTexture; import org.jetbrains.annotations.Nullable; @@ -55,8 +56,8 @@ default void setupTextureParameters(PBRType pbrType, AbstractTexture texture) { } // TODO: PBR -// @Nullable -// CustomMipmapGenerator getMipmapGenerator(PBRType pbrType); + @Nullable + CustomMipmapGenerator getMipmapGenerator(PBRType pbrType); public interface Factory { TextureFormat createFormat(String name, @Nullable String version); diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java index 918502422..1a52e59b5 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java @@ -1,13 +1,17 @@ package net.coderbot.iris.texture.mipmap; import com.gtnewhorizons.angelica.compat.NativeImage; +import net.coderbot.iris.texture.pbr.loader.TextureAtlasSpriteInfo; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; + +import javax.annotation.Nullable; public interface CustomMipmapGenerator { NativeImage[] generateMipLevels(NativeImage image, int mipLevel); // TODO: PBR -// public interface Provider { -// @Nullable -// CustomMipmapGenerator getMipmapGenerator(TextureAtlasSprite.Info info, int atlasWidth, int atlasHeight); -// } + public interface Provider { + @Nullable + CustomMipmapGenerator getMipmapGenerator(TextureAtlasSpriteInfo info, int atlasWidth, int atlasHeight); + } } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java index 3bc112afb..99765da2b 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java @@ -6,6 +6,7 @@ import net.coderbot.iris.texture.util.TextureExporter; import net.coderbot.iris.texture.util.TextureManipulationUtil; import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.data.AnimationMetadataSection; import net.minecraft.crash.CrashReport; @@ -21,14 +22,14 @@ import java.util.Set; public class PBRAtlasTexture extends AutoClosableAbstractTexture { - protected final TextureAtlas atlasTexture; + protected final TextureMap texMap; protected final PBRType type; protected final ResourceLocation id; protected final Map sprites = new HashMap<>(); protected final Set animatedSprites = new HashSet<>(); - public PBRAtlasTexture(TextureAtlas atlasTexture, PBRType type) { - this.atlasTexture = atlasTexture; + public PBRAtlasTexture(TextureMap textureMap, PBRType type) { + this.texMap = textureMap; this.type = type; // id = type.appendToFileLocation(atlasTexture.location()); @@ -80,7 +81,7 @@ public void upload(int atlasWidth, int atlasHeight, int mipLevel) { } if (!animatedSprites.isEmpty()) { - PBRAtlasHolder pbrHolder = ((TextureAtlasExtension) atlasTexture).getOrCreatePBRHolder(); + PBRAtlasHolder pbrHolder = ((TextureAtlasExtension) texMap).getOrCreatePBRHolder(); switch (type) { case NORMAL: pbrHolder.setNormalAtlas(this); @@ -138,7 +139,7 @@ public void cycleAnimationFrames() { @Override public void close() { - PBRAtlasHolder pbrHolder = ((TextureAtlasExtension) atlasTexture).getPBRHolder(); + PBRAtlasHolder pbrHolder = ((TextureAtlasExtension) texMap).getPBRHolder(); if (pbrHolder != null) { switch (type) { case NORMAL: diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java index 4b118859a..148d11566 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java @@ -1,205 +1,268 @@ package net.coderbot.iris.texture.pbr.loader; -import com.gtnewhorizons.angelica.compat.mojang.TextureAtlas; +import com.google.common.collect.Lists; +import com.gtnewhorizons.angelica.compat.NativeImage; +import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.AnimationMetadataSectionAccessor; +import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.TextureAtlasSpriteAccessor; +import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.TextureMapAccessor; +import net.coderbot.iris.Iris; +import net.coderbot.iris.texture.TextureInfoCache; +import net.coderbot.iris.texture.format.TextureFormat; +import net.coderbot.iris.texture.format.TextureFormatLoader; import net.coderbot.iris.texture.mipmap.ChannelMipmapGenerator; +import net.coderbot.iris.texture.mipmap.CustomMipmapGenerator; import net.coderbot.iris.texture.mipmap.LinearBlendFunction; +import net.coderbot.iris.texture.pbr.PBRAtlasTexture; +import net.coderbot.iris.texture.pbr.PBRSpriteHolder; +import net.coderbot.iris.texture.pbr.PBRType; +import net.coderbot.iris.texture.pbr.TextureAtlasSpriteExtension; +import net.coderbot.iris.texture.util.ImageManipulationUtil; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.resources.IResource; import net.minecraft.client.resources.IResourceManager; +import net.minecraft.client.resources.data.AnimationMetadataSection; +import net.minecraft.util.ResourceLocation; +import org.apache.commons.lang3.tuple.Pair; -public class AtlasPBRLoader implements PBRTextureLoader { - public static final ChannelMipmapGenerator LINEAR_MIPMAP_GENERATOR = new ChannelMipmapGenerator( - LinearBlendFunction.INSTANCE, - LinearBlendFunction.INSTANCE, - LinearBlendFunction.INSTANCE, - LinearBlendFunction.INSTANCE - ); +import javax.annotation.Nullable; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Collection; - @Override - public void load(TextureAtlas atlas, IResourceManager resourceManager, PBRTextureConsumer pbrTextureConsumer) { + +public class AtlasPBRLoader implements PBRTextureLoader { + public static final ChannelMipmapGenerator LINEAR_MIPMAP_GENERATOR = new ChannelMipmapGenerator( + LinearBlendFunction.INSTANCE, + LinearBlendFunction.INSTANCE, + LinearBlendFunction.INSTANCE, + LinearBlendFunction.INSTANCE + ); + + @Override + public void load(TextureMap texMap, IResourceManager resourceManager, PBRTextureConsumer pbrTextureConsumer) { // TODO: PBR -// TextureInfo textureInfo = TextureInfoCache.INSTANCE.getInfo(atlas.getId()); -// int atlasWidth = textureInfo.getWidth(); -// int atlasHeight = textureInfo.getHeight(); -// int mipLevel = fetchAtlasMipLevel(atlas); -// -// PBRAtlasTexture normalAtlas = null; -// PBRAtlasTexture specularAtlas = null; -// for (TextureAtlasSprite sprite : atlas.getTexturesByName().values()) { -// if (!(sprite instanceof MissingTextureAtlasSprite)) { -// TextureAtlasSprite normalSprite = createPBRSprite(sprite, resourceManager, atlas, atlasWidth, atlasHeight, mipLevel, PBRType.NORMAL); -// TextureAtlasSprite specularSprite = createPBRSprite(sprite, resourceManager, atlas, atlasWidth, atlasHeight, mipLevel, PBRType.SPECULAR); -// if (normalSprite != null) { -// if (normalAtlas == null) { -// normalAtlas = new PBRAtlasTexture(atlas, PBRType.NORMAL); -// } -// normalAtlas.addSprite(normalSprite); -// PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); -// pbrSpriteHolder.setNormalSprite(normalSprite); -// } -// if (specularSprite != null) { -// if (specularAtlas == null) { -// specularAtlas = new PBRAtlasTexture(atlas, PBRType.SPECULAR); -// } -// specularAtlas.addSprite(specularSprite); -// PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); -// pbrSpriteHolder.setSpecularSprite(specularSprite); -// } -// } -// } -// -// if (normalAtlas != null) { -// if (normalAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { -// pbrTextureConsumer.acceptNormalTexture(normalAtlas); -// } -// } -// if (specularAtlas != null) { -// if (specularAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { -// pbrTextureConsumer.acceptSpecularTexture(specularAtlas); -// } -// } + TextureInfoCache.TextureInfo textureInfo = TextureInfoCache.INSTANCE.getInfo(texMap.getGlTextureId()); + int atlasWidth = textureInfo.getWidth(); + int atlasHeight = textureInfo.getHeight(); + int mipLevel = fetchAtlasMipLevel(texMap); + + PBRAtlasTexture normalAtlas = null; + PBRAtlasTexture specularAtlas = null; + for (TextureAtlasSprite sprite : (Collection) ((TextureMapAccessor) texMap).getMapUploadedSprites().values()) { + if (!(sprite.getIconName().equals("missingno"))) { + TextureAtlasSprite normalSprite = createPBRSprite(sprite, resourceManager, texMap, atlasWidth, atlasHeight, mipLevel, PBRType.NORMAL); + TextureAtlasSprite specularSprite = createPBRSprite(sprite, resourceManager, texMap, atlasWidth, atlasHeight, mipLevel, PBRType.SPECULAR); + if (normalSprite != null) { + if (normalAtlas == null) { + normalAtlas = new PBRAtlasTexture(texMap, PBRType.NORMAL); + } + normalAtlas.addSprite(normalSprite); + PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); + pbrSpriteHolder.setNormalSprite(normalSprite); + } + if (specularSprite != null) { + if (specularAtlas == null) { + specularAtlas = new PBRAtlasTexture(texMap, PBRType.SPECULAR); + } + specularAtlas.addSprite(specularSprite); + PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); + pbrSpriteHolder.setSpecularSprite(specularSprite); + } + } + } + + if (normalAtlas != null) { + if (normalAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { + pbrTextureConsumer.acceptNormalTexture(normalAtlas); + } + } + if (specularAtlas != null) { + if (specularAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { + pbrTextureConsumer.acceptSpecularTexture(specularAtlas); + } + } + } + + protected static int fetchAtlasMipLevel(TextureMap texMap) { + TextureAtlasSprite missingSprite = texMap.getAtlasSprite("missingno"); + return ((TextureAtlasSpriteAccessor) missingSprite).getFramesTextureData().size() - 1; + } + + @Nullable + protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourceManager resourceManager, TextureMap texMap, int atlasWidth, int atlasHeight, int mipLevel, PBRType pbrType) { + ResourceLocation spriteName = new ResourceLocation(sprite.getIconName()); + ResourceLocation imageLocation = texMap.completeResourceLocation(spriteName, 0); + ResourceLocation pbrImageLocation = pbrType.appendToFileLocation(imageLocation); + + TextureAtlasSprite pbrSprite = null; + + try { + // This is no longer closable. Not sure about this. + IResource resource = resourceManager.getResource(pbrImageLocation); + NativeImage nativeImage = NativeImage.read(resource.getInputStream()); + AnimationMetadataSection animationMetadata = (AnimationMetadataSection) resource.getMetadata("animation"); + if (animationMetadata == null) { + animationMetadata = new AnimationMetadataSection(Lists.newArrayList(), -1, -1, -1); + } + + + Pair frameSize = this.getFrameSize(nativeImage.getWidth(), nativeImage.getHeight(), animationMetadata); + int frameWidth = frameSize.getLeft(); + int frameHeight = frameSize.getRight(); + int targetFrameWidth = sprite.getIconWidth(); + int targetFrameHeight = sprite.getIconHeight(); + if (frameWidth != targetFrameWidth || frameHeight != targetFrameHeight) { + int imageWidth = nativeImage.getWidth(); + int imageHeight = nativeImage.getHeight(); + + // We can assume the following is always true as a result of getFrameSize's check: + // imageWidth % frameWidth == 0 && imageHeight % frameHeight == 0 + int targetImageWidth = imageWidth / frameWidth * targetFrameWidth; + int targetImageHeight = imageHeight / frameHeight * targetFrameHeight; + + NativeImage scaledImage; + if (targetImageWidth % imageWidth == 0 && targetImageHeight % imageHeight == 0) { + scaledImage = ImageManipulationUtil.scaleNearestNeighbor(nativeImage, targetImageWidth, targetImageHeight); + } else { + scaledImage = ImageManipulationUtil.scaleBilinear(nativeImage, targetImageWidth, targetImageHeight); + } + + // This is no longer closeable either +// nativeImage.close(); + nativeImage = scaledImage; + + frameWidth = targetFrameWidth; + frameHeight = targetFrameHeight; + + if (!animationMetadata.equals(new AnimationMetadataSection(Lists.newArrayList(), -1, -1, -1))) { + AnimationMetadataSectionAccessor animationAccessor = (AnimationMetadataSectionAccessor) animationMetadata; + int internalFrameWidth = animationAccessor.getFrameHeight(); + int internalFrameHeight = animationAccessor.getFrameHeight(); + if (internalFrameWidth != -1) { + animationAccessor.setFrameWidth(frameWidth); + } + if (internalFrameHeight != -1) { + animationAccessor.setFrameHeight(frameHeight); + } + } + } + + ResourceLocation pbrSpriteName = new ResourceLocation(spriteName.getResourceDomain(), spriteName.getResourcePath() + pbrType.getSuffix()); + TextureAtlasSpriteInfo pbrSpriteInfo = new PBRTextureAtlasSpriteInfo(pbrSpriteName, frameWidth, frameHeight, animationMetadata, pbrType); + + int x = ((TextureAtlasSpriteAccessor) sprite).getX(); + int y = ((TextureAtlasSpriteAccessor) sprite).getY(); + pbrSprite = new PBRTextureAtlasSprite(pbrSpriteInfo, animationMetadata, atlasWidth, atlasHeight, x, y, nativeImage, texMap); + syncAnimation(sprite, pbrSprite); + } catch (FileNotFoundException e) { + // + } catch (RuntimeException e) { + Iris.logger.error("Unable to parse metadata from {} : {}", pbrImageLocation, e); + } catch (IOException e) { + Iris.logger.error("Unable to load {} : {}", pbrImageLocation, e); + } + + return pbrSprite; + } + + + protected void syncAnimation(TextureAtlasSprite source, TextureAtlasSprite target) { + // TODO: Iris Shaders - animationMetadata && animationMetadata.getFrameCount() > 0 + if (!source.hasAnimationMetadata() || !target.hasAnimationMetadata()) { + return; + } + + TextureAtlasSpriteAccessor sourceAccessor = ((TextureAtlasSpriteAccessor) source); + AnimationMetadataSection sourceMetadata = sourceAccessor.getMetadata(); + + int ticks = 0; + for (int f = 0; f < sourceAccessor.getFrame(); f++) { + ticks += sourceMetadata.getFrameTimeSingle(f); + } + + TextureAtlasSpriteAccessor targetAccessor = ((TextureAtlasSpriteAccessor) target); + AnimationMetadataSection targetMetadata = targetAccessor.getMetadata(); + + int cycleTime = 0; + int frameCount = targetMetadata.getFrameCount(); + for (int f = 0; f < frameCount; f++) { + cycleTime += targetMetadata.getFrameTimeSingle(f); + } + ticks %= cycleTime; + + int targetFrame = 0; + while (true) { + int time = targetMetadata.getFrameTimeSingle(targetFrame); + if (ticks >= time) { + targetFrame++; + ticks -= time; + } else { + break; + } + } + + targetAccessor.setFrame(targetFrame); + targetAccessor.setSubFrame(ticks + sourceAccessor.getSubFrame()); } -// protected static int fetchAtlasMipLevel(TextureAtlas atlas) { -// TextureAtlasSprite missingSprite = atlas.getSprite(MissingTextureAtlasSprite.getLocation()); -// return ((TextureAtlasSpriteAccessor) missingSprite).getMainImage().length - 1; -// } -// -// @Nullable -// protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourceManager resourceManager, TextureAtlas atlas, int atlasWidth, int atlasHeight, int mipLevel, PBRType pbrType) { -// ResourceLocation spriteName = sprite.getName(); -// ResourceLocation imageLocation = ((TextureAtlasAccessor) atlas).callGetResourceLocation(spriteName); -// ResourceLocation pbrImageLocation = pbrType.appendToFileLocation(imageLocation); -// -// TextureAtlasSprite pbrSprite = null; -// try (IResource resource = resourceManager.getResource(pbrImageLocation)) { -// NativeImage nativeImage = NativeImage.read(resource.getInputStream()); -// AnimationMetadataSection animationMetadata = resource.getMetadata(AnimationMetadataSection.SERIALIZER); -// if (animationMetadata == null) { -// animationMetadata = AnimationMetadataSection.EMPTY; -// } -// -// Pair frameSize = animationMetadata.getFrameSize(nativeImage.getWidth(), nativeImage.getHeight()); -// int frameWidth = frameSize.getFirst(); -// int frameHeight = frameSize.getSecond(); -// int targetFrameWidth = sprite.getWidth(); -// int targetFrameHeight = sprite.getHeight(); -// if (frameWidth != targetFrameWidth || frameHeight != targetFrameHeight) { -// int imageWidth = nativeImage.getWidth(); -// int imageHeight = nativeImage.getHeight(); -// -// // We can assume the following is always true as a result of getFrameSize's check: -// // imageWidth % frameWidth == 0 && imageHeight % frameHeight == 0 -// int targetImageWidth = imageWidth / frameWidth * targetFrameWidth; -// int targetImageHeight = imageHeight / frameHeight * targetFrameHeight; -// -// NativeImage scaledImage; -// if (targetImageWidth % imageWidth == 0 && targetImageHeight % imageHeight == 0) { -// scaledImage = ImageManipulationUtil.scaleNearestNeighbor(nativeImage, targetImageWidth, targetImageHeight); -// } else { -// scaledImage = ImageManipulationUtil.scaleBilinear(nativeImage, targetImageWidth, targetImageHeight); -// } -// nativeImage.close(); -// nativeImage = scaledImage; -// -// frameWidth = targetFrameWidth; -// frameHeight = targetFrameHeight; -// -// if (animationMetadata != AnimationMetadataSection.EMPTY) { -// AnimationMetadataSectionAccessor animationAccessor = (AnimationMetadataSectionAccessor) animationMetadata; -// int internalFrameWidth = animationAccessor.getFrameWidth(); -// int internalFrameHeight = animationAccessor.getFrameHeight(); -// if (internalFrameWidth != -1) { -// animationAccessor.setFrameWidth(frameWidth); -// } -// if (internalFrameHeight != -1) { -// animationAccessor.setFrameHeight(frameHeight); -// } -// } -// } -// -// ResourceLocation pbrSpriteName = new ResourceLocation(spriteName.getNamespace(), spriteName.getPath() + pbrType.getSuffix()); -// TextureAtlasSprite.Info pbrSpriteInfo = new PBRTextureAtlasSpriteInfo(pbrSpriteName, frameWidth, frameHeight, animationMetadata, pbrType); -// -// int x = ((TextureAtlasSpriteAccessor) sprite).getX(); -// int y = ((TextureAtlasSpriteAccessor) sprite).getY(); -// pbrSprite = new PBRTextureAtlasSprite(atlas, pbrSpriteInfo, mipLevel, atlasWidth, atlasHeight, x, y, nativeImage); -// syncAnimation(sprite, pbrSprite); -// } catch (FileNotFoundException e) { -// // -// } catch (RuntimeException e) { -// Iris.logger.error("Unable to parse metadata from {} : {}", pbrImageLocation, e); -// } catch (IOException e) { -// Iris.logger.error("Unable to load {} : {}", pbrImageLocation, e); -// } -// -// return pbrSprite; -// } -// -// protected void syncAnimation(TextureAtlasSprite source, TextureAtlasSprite target) { -// // TODO: Iris Shaders - animationMetadata && animationMetadata.getFrameCount() > 0 -// if (!source.isAnimation() || !target.isAnimation()) { -// return; -// } -// -// TextureAtlasSpriteAccessor sourceAccessor = ((TextureAtlasSpriteAccessor) source); -// AnimationMetadataSection sourceMetadata = sourceAccessor.getMetadata(); -// -// int ticks = 0; -// for (int f = 0; f < sourceAccessor.getFrame(); f++) { -// ticks += sourceMetadata.getFrameTime(f); -// } -// -// TextureAtlasSpriteAccessor targetAccessor = ((TextureAtlasSpriteAccessor) target); -// AnimationMetadataSection targetMetadata = targetAccessor.getMetadata(); -// -// int cycleTime = 0; -// int frameCount = targetMetadata.getFrameCount(); -// for (int f = 0; f < frameCount; f++) { -// cycleTime += targetMetadata.getFrameTime(f); -// } -// ticks %= cycleTime; -// -// int targetFrame = 0; -// while (true) { -// int time = targetMetadata.getFrameTime(targetFrame); -// if (ticks >= time) { -// targetFrame++; -// ticks -= time; -// } else { -// break; -// } -// } -// -// targetAccessor.setFrame(targetFrame); -// targetAccessor.setSubFrame(ticks + sourceAccessor.getSubFrame()); -// } -// -// protected static class PBRTextureAtlasSpriteInfo extends TextureAtlasSprite.Info { -// protected final PBRType pbrType; -// -// public PBRTextureAtlasSpriteInfo(ResourceLocation name, int width, int height, AnimationMetadataSection metadata, PBRType pbrType) { -// super(name, width, height, metadata); -// this.pbrType = pbrType; -// } -// } -// -// public static class PBRTextureAtlasSprite extends TextureAtlasSprite implements CustomMipmapGenerator.Provider { -// protected PBRTextureAtlasSprite(TextureAtlas atlas, TextureAtlasSprite.Info info, int mipLevel, int atlasWidth, int atlasHeight, int x, int y, NativeImage nativeImage) { -// super(atlas, info, mipLevel, atlasWidth, atlasHeight, x, y, nativeImage); -// } -// -// @Override -// public CustomMipmapGenerator getMipmapGenerator(Info info, int atlasWidth, int atlasHeight) { -// if (info instanceof PBRTextureAtlasSpriteInfo) { -// PBRType pbrType = ((PBRTextureAtlasSpriteInfo) info).pbrType; -// TextureFormat format = TextureFormatLoader.getFormat(); -// if (format != null) { -// CustomMipmapGenerator generator = format.getMipmapGenerator(pbrType); -// if (generator != null) { -// return generator; -// } -// } -// } -// return LINEAR_MIPMAP_GENERATOR; -// } -// } + protected static class PBRTextureAtlasSpriteInfo extends TextureAtlasSpriteInfo { + protected final PBRType pbrType; + + public PBRTextureAtlasSpriteInfo(ResourceLocation name, int width, int height, AnimationMetadataSection metadata, PBRType pbrType) { + super(name, width, height, metadata); + this.pbrType = pbrType; + } + } + + public static class PBRTextureAtlasSprite extends TextureAtlasSprite implements CustomMipmapGenerator.Provider { + // This feels super janky + protected PBRTextureAtlasSprite(TextureAtlasSpriteInfo info, AnimationMetadataSection animationMetaDataSection,int atlasWidth, int atlasHeight, int x, int y, NativeImage nativeImage, TextureMap texMap) { + super(info.name().toString()); + super.initSprite(atlasWidth, atlasHeight, x, y, false); + super.loadSprite(getMipmapGenerator(info, atlasWidth, atlasHeight).generateMipLevels(nativeImage, ((TextureMapAccessor) texMap).getMipmapLevels()), animationMetaDataSection, ((TextureMapAccessor) texMap).getAnisotropicFiltering() == 1); + } + + @Override + public CustomMipmapGenerator getMipmapGenerator(TextureAtlasSpriteInfo info, int atlasWidth, int atlasHeight) { + if (info instanceof PBRTextureAtlasSpriteInfo) { + PBRType pbrType = ((PBRTextureAtlasSpriteInfo) info).pbrType; + TextureFormat format = TextureFormatLoader.getFormat(); + if (format != null) { + CustomMipmapGenerator generator = format.getMipmapGenerator(pbrType); + if (generator != null) { + return generator; + } + } + } + return LINEAR_MIPMAP_GENERATOR; + } + } + + private Pair getFrameSize(int i, int j, AnimationMetadataSection animationMetadataSection) { + Pair pair = this.calculateFrameSize(i, j, animationMetadataSection); + int k = (Integer)pair.getLeft(); + int l = (Integer)pair.getRight(); + if (isDivisionInteger(i, k) && isDivisionInteger(j, l)) { + return pair; + } else { + throw new IllegalArgumentException(String.format("Image size %s,%s is not multiply of frame size %s,%s", i, j, k, l)); + } + } + + private Pair calculateFrameSize(int i, int j, AnimationMetadataSection animationMetadataSection) { + if (animationMetadataSection.getFrameWidth() != -1) { + return animationMetadataSection.getFrameHeight() != -1 ? Pair.of(animationMetadataSection.getFrameWidth(), animationMetadataSection.getFrameHeight()) : Pair.of(animationMetadataSection.getFrameWidth(), j); + } else if (animationMetadataSection.getFrameHeight() != -1) { + return Pair.of(i, animationMetadataSection.getFrameHeight()); + } else { + int k = Math.min(i, j); + return Pair.of(k, k); + } + } + + private static boolean isDivisionInteger(int i, int j) { + return i / j * j == i; + } + } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java index 0d5594496..48627aceb 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/PBRTextureLoaderRegistry.java @@ -1,6 +1,8 @@ package net.coderbot.iris.texture.pbr.loader; import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.renderer.texture.SimpleTexture; +import net.minecraft.client.renderer.texture.TextureMap; import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -9,11 +11,10 @@ public class PBRTextureLoaderRegistry { public static final PBRTextureLoaderRegistry INSTANCE = new PBRTextureLoaderRegistry(); -// TODO: PBR -// static { -// INSTANCE.register(SimpleTexture.class, new SimplePBRLoader()); -// INSTANCE.register(TextureAtlas.class, new AtlasPBRLoader()); -// } + static { + INSTANCE.register(SimpleTexture.class, new SimplePBRLoader()); + INSTANCE.register(TextureMap.class, new AtlasPBRLoader()); + } private final Map, PBRTextureLoader> loaderMap = new HashMap<>(); diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/TextureAtlasSpriteInfo.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/TextureAtlasSpriteInfo.java new file mode 100644 index 000000000..28f0a781f --- /dev/null +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/TextureAtlasSpriteInfo.java @@ -0,0 +1,30 @@ +package net.coderbot.iris.texture.pbr.loader; + +import net.minecraft.client.resources.data.AnimationMetadataSection; +import net.minecraft.util.ResourceLocation; + +public class TextureAtlasSpriteInfo { + private final ResourceLocation name; + private final int width; + private final int height; + private final AnimationMetadataSection metadata; + + public TextureAtlasSpriteInfo(ResourceLocation arg, int i, int j, AnimationMetadataSection arg2) { + this.name = arg; + this.width = i; + this.height = j; + this.metadata = arg2; + } + + public ResourceLocation name() { + return this.name; + } + + public int width() { + return this.width; + } + + public int height() { + return this.height; + } +} From de9338be1f9d30c1732f78c3a43ab562f2d9b865 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 10 Dec 2023 14:44:48 -0800 Subject: [PATCH 257/301] Try only creating the keybinds when being registered... --- src/main/java/net/coderbot/iris/Iris.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index e2634b5ea..ea897bb43 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -91,9 +91,9 @@ public class Iris { private static String IRIS_VERSION; private static boolean fallback; - private static final KeyBinding reloadKeybind = new KeyBinding("Reload Shaders", 0, "Iris Keybinds"); - private static final KeyBinding toggleShadersKeybind = new KeyBinding("Toggle Shaders", 0, "Iris Keybinds"); - private static final KeyBinding shaderpackScreenKeybind = new KeyBinding("Shaderpack Selection Screen", 0, "Iris Keybinds"); + private static KeyBinding reloadKeybind; + private static KeyBinding toggleShadersKeybind; + private static KeyBinding shaderpackScreenKeybind; public static Iris INSTANCE = new Iris(); @@ -732,6 +732,9 @@ public static ShaderpackDirectoryManager getShaderpacksDirectoryManager() { } public void registerKeybindings() { + reloadKeybind = new KeyBinding("Reload Shaders", 0, "Iris Keybinds"); + toggleShadersKeybind = new KeyBinding("Toggle Shaders", 0, "Iris Keybinds"); + shaderpackScreenKeybind = new KeyBinding("Shaderpack Selection Screen", 0, "Iris Keybinds"); ClientRegistry.registerKeyBinding(reloadKeybind); ClientRegistry.registerKeyBinding(toggleShadersKeybind); ClientRegistry.registerKeyBinding(shaderpackScreenKeybind); From 49477cd9c614201acc8325781d4cc9c54762c0a4 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 12 Dec 2023 09:56:54 -0800 Subject: [PATCH 258/301] Update README.MD --- README.MD | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.MD b/README.MD index d34f629da..f0a5fb168 100644 --- a/README.MD +++ b/README.MD @@ -1,7 +1,7 @@ # Angelica -The little Angle that supports shaders while saving your fps from a certain death -boubou -Is it obtuse, or accute? -Caedis -It's a cute angle -mitchej123 +* The little Angle that supports shaders while saving your fps from a certain death -boubou +* Is it obtuse, or accute? -Caedis +* It's a cute angle -mitchej123 **Not yet in an usable state** @@ -28,4 +28,3 @@ It's a cute angle -mitchej123 * Angelica * mitchej123, Omni, Makamys, Embeddedt, NanoLive, Caedis, Cardinalstar, Alexdoru, Eigenraven, mist475, Clepto for helping get Angelica up and running! * IMS, jss2a98aj, || dbp ||, roadhog360 for advice and moral support - * "🖕 to the people who said it couldn't be done" -GitHub Copilot From 486270bdc7c42fb036566fde242570ffe5eb0904 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Tue, 12 Dec 2023 10:25:11 -0800 Subject: [PATCH 259/301] Update README.MD --- README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MD b/README.MD index f0a5fb168..1ac7233a9 100644 --- a/README.MD +++ b/README.MD @@ -1,5 +1,5 @@ # Angelica -* The little Angle that supports shaders while saving your fps from a certain death -boubou +* The little Angle [sic] that supports shaders while saving your fps from a certain death -boubou * Is it obtuse, or accute? -Caedis * It's a cute angle -mitchej123 From 3bab88f3e14f4d8f17b9ceede1a800556b3b6b26 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 13 Dec 2023 20:29:43 -0800 Subject: [PATCH 260/301] Shaderpack selection "works"; ShaderOptions TODO --- .../angelica/client/gui/GuiSlotShaders.java | 18 +- .../angelica/proxy/ClientProxy.java | 2 +- .../client/gui/SodiumGameOptionPages.java | 84 ++- .../sodium/client/gui/SodiumGameOptions.java | 16 +- .../sodium/client/gui/SodiumOptionsGUI.java | 10 +- .../sodium/client/gui/options/OptionImpl.java | 8 + src/main/java/net/coderbot/iris/Iris.java | 138 ++--- .../coderbot/iris/apiimpl/IrisApiV0Impl.java | 3 +- .../net/coderbot/iris/config/IrisConfig.java | 2 +- .../net/coderbot/iris/gui/FileDialogUtil.java | 63 +++ .../java/net/coderbot/iris/gui/GuiUtil.java | 208 +++++++ .../iris/gui/NavigationController.java | 65 +++ .../iris/gui/element/IrisElementRow.java | 225 ++++++++ .../iris/gui/element/IrisGuiSlot.java | 32 ++ .../gui/element/ShaderPackOptionList.java | 389 +++++++++++++ .../gui/element/ShaderPackSelectionList.java | 319 +++++++++++ .../screen/ElementWidgetScreenData.java | 15 + .../element/widget/AbstractElementWidget.java | 30 + .../widget/BaseOptionElementWidget.java | 179 ++++++ .../element/widget/BooleanElementWidget.java | 111 ++++ .../widget/CommentedElementWidget.java | 15 + .../iris/gui/element/widget/IrisButton.java | 22 + .../gui/element/widget/LinkElementWidget.java | 85 +++ .../iris/gui/element/widget/OnPress.java | 6 + .../element/widget/OptionMenuConstructor.java | 87 +++ .../element/widget/ProfileElementWidget.java | 100 ++++ .../element/widget/SliderElementWidget.java | 118 ++++ .../element/widget/StringElementWidget.java | 107 ++++ .../iris/gui/option/IrisVideoSettings.java | 29 + .../coderbot/iris/gui/screen/HudHideable.java | 9 + .../iris/gui/screen/ShaderPackScreen.java | 519 ++++++++++++++++++ .../coderbot/iris/samplers/IrisSamplers.java | 6 +- .../resources/assets/angelica/lang/en_US.lang | 42 +- 33 files changed, 2898 insertions(+), 164 deletions(-) create mode 100644 src/main/java/net/coderbot/iris/gui/FileDialogUtil.java create mode 100644 src/main/java/net/coderbot/iris/gui/GuiUtil.java create mode 100644 src/main/java/net/coderbot/iris/gui/NavigationController.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/IrisButton.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/OnPress.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java create mode 100644 src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java create mode 100644 src/main/java/net/coderbot/iris/gui/screen/HudHideable.java create mode 100644 src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiSlotShaders.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiSlotShaders.java index 534b334a5..b00a89984 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiSlotShaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiSlotShaders.java @@ -15,13 +15,7 @@ public class GuiSlotShaders extends GuiSlot { public GuiSlotShaders(GuiShaders par1GuiShaders) { // super(par1GuiShaders.getMc(), par1GuiShaders.width / 2 + 20, par1GuiShaders.height, 40, par1GuiShaders.height // - 70, 16); - super( - par1GuiShaders.getMc(), - par1GuiShaders.width / 2 + 20, - par1GuiShaders.height, - 40, - par1GuiShaders.height - 70, - 16); + super(par1GuiShaders.getMc(), par1GuiShaders.width / 2 + 20, par1GuiShaders.height, 40, par1GuiShaders.height - 70, 16); this.shadersGui = par1GuiShaders; this.shaderslist = Shaders.listofShaders(); } @@ -70,12 +64,8 @@ protected void drawBackground() { } @Override - /** drawSlot */ - protected void drawSlot(int par1, int par2, int par3, int par4, Tessellator par5, int par6, int par7) { - this.shadersGui.drawCenteredString( - (String) this.shaderslist.get(par1), - this.shadersGui.width / 4 + 10, - par3 + 1, - 0xffffff); + /** drawEntry */ + protected void drawSlot(int index, int par2, int par3, int par4, Tessellator par5, int mouseX, int mouseY) { + this.shadersGui.drawCenteredString((String) this.shaderslist.get(index), this.shadersGui.width / 4 + 10, par3 + 1, 0xffffff); } } diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index b4b3fca92..f3ae012f1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -50,7 +50,7 @@ public void init(FMLInitializationEvent event) { if(AngelicaConfig.enableIris) { MinecraftForge.EVENT_BUS.register(IrisDebugScreenHandler.INSTANCE); - Iris.INSTANCE.registerKeybindings(); + Iris.INSTANCE.fmlInitEvent(); FMLCommonHandler.instance().bus().register(Iris.INSTANCE); MinecraftForge.EVENT_BUS.register(Iris.INSTANCE); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java index 58b3a2485..f8b4d5fa2 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java @@ -1,6 +1,7 @@ package me.jellysquid.mods.sodium.client.gui; import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import jss.notfine.core.Settings; import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; import me.jellysquid.mods.sodium.client.gui.options.OptionGroup; @@ -18,11 +19,14 @@ import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage; import me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw.MultidrawChunkRenderBackend; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.option.IrisVideoSettings; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.I18n; import net.minecraft.client.settings.GameSettings; import org.lwjgl.opengl.Display; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -31,32 +35,56 @@ public class SodiumGameOptionPages { private static final MinecraftOptionsStorage vanillaOpts = new MinecraftOptionsStorage(); public static OptionPage general() { - List groups = new ArrayList<>(); + final List groups = new ArrayList<>(); + final OptionGroup.Builder firstGroupBuilder = OptionGroup.createBuilder(); - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(I18n.format("options.renderDistance")) - .setTooltip(I18n.format("sodium.options.view_distance.tooltip")) - .setControl(option -> new SliderControl(option, 2, (int) GameSettings.Options.RENDER_DISTANCE.getValueMax(), 1, ControlValueFormatter.quantity("options.chunks"))) - .setBinding((options, value) -> options.renderDistanceChunks = value, options -> options.renderDistanceChunks) - .setImpact(OptionImpact.HIGH) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName(I18n.format("options.gamma")) - .setTooltip(I18n.format("sodium.options.brightness.tooltip")) - .setControl(opt -> new SliderControl(opt, 0, 100, 1, ControlValueFormatter.brightness())) - .setBinding((opts, value) -> opts.gammaSetting = value * 0.01F, (opts) -> (int) (opts.gammaSetting / 0.01F)) - .build()) - .add(Settings.MODE_SKY.option) - .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName(I18n.format("sodium.options.clouds.name")) - .setTooltip(I18n.format("sodium.options.clouds.tooltip")) - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.clouds = value, (opts) -> opts.clouds) - .setImpact(OptionImpact.LOW) - .build()) + firstGroupBuilder.add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.renderDistance")) + .setTooltip(I18n.format("sodium.options.view_distance.tooltip")) + .setControl(option -> new SliderControl(option, 2, (int) GameSettings.Options.RENDER_DISTANCE.getValueMax(), 1, ControlValueFormatter.quantity("options.chunks"))) + .setBinding((options, value) -> options.renderDistanceChunks = value, options -> options.renderDistanceChunks) + .setImpact(OptionImpact.HIGH) + .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) + .build()); + + if(AngelicaConfig.enableIris) { + final OptionImpl maxShadowDistanceSlider = OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.iris.shadowDistance")) + .setTooltip(I18n.format("options.iris.shadowDistance.sodium_tooltip")) + .setControl(option -> new SliderControl(option, 0, 32, 1, ControlValueFormatter.quantity("options.chunks"))) + .setBinding((options, value) -> { + IrisVideoSettings.shadowDistance = value; + try { + Iris.getIrisConfig().save(); + } catch (IOException e) { + e.printStackTrace(); + } + }, + options -> IrisVideoSettings.getOverriddenShadowDistance(IrisVideoSettings.shadowDistance)) + .setImpact(OptionImpact.HIGH) + .setEnabled(true) + .build(); + + maxShadowDistanceSlider.iris$dynamicallyEnable(IrisVideoSettings::isShadowDistanceSliderEnabled); + firstGroupBuilder.add(maxShadowDistanceSlider).build(); + } + + firstGroupBuilder.add(OptionImpl.createBuilder(int.class, vanillaOpts) + .setName(I18n.format("options.gamma")) + .setTooltip(I18n.format("sodium.options.brightness.tooltip")) + .setControl(opt -> new SliderControl(opt, 0, 100, 1, ControlValueFormatter.brightness())) + .setBinding((opts, value) -> opts.gammaSetting = value * 0.01F, (opts) -> (int) (opts.gammaSetting / 0.01F)) .build()); + firstGroupBuilder.add(Settings.MODE_SKY.option); + firstGroupBuilder.add(OptionImpl.createBuilder(boolean.class, vanillaOpts) + .setName(I18n.format("sodium.options.clouds.name")) + .setTooltip(I18n.format("sodium.options.clouds.tooltip")) + .setControl(TickBoxControl::new) + .setBinding((opts, value) -> opts.clouds = value, (opts) -> opts.clouds) + .setImpact(OptionImpact.LOW) + .build()); + groups.add(firstGroupBuilder.build()); + groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(int.class, vanillaOpts) @@ -78,7 +106,7 @@ public static OptionPage general() { .setBinding((opts, value) -> { opts.fullScreen = value; - Minecraft client = Minecraft.getMinecraft(); + final Minecraft client = Minecraft.getMinecraft(); if (client.isFullScreen() != opts.fullScreen) { client.toggleFullscreen(); @@ -119,7 +147,7 @@ public static OptionPage general() { } public static OptionPage quality() { - List groups = new ArrayList<>(); + final List groups = new ArrayList<>(); groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(GraphicsMode.class, vanillaOpts) @@ -234,7 +262,7 @@ public static OptionPage quality() { } public static OptionPage advanced() { - List groups = new ArrayList<>(); + final List groups = new ArrayList<>(); groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) @@ -349,7 +377,7 @@ public static OptionPage advanced() { } public static OptionPage performance() { - List groups = new ArrayList<>(); + final List groups = new ArrayList<>(); groups.add(OptionGroup.createBuilder() .add(OptionImpl.createBuilder(int.class, sodiumOpts) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 5155f2d90..dc1f99488 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -4,8 +4,10 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; +import com.gtnewhorizons.angelica.config.AngelicaConfig; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsQuality; +import net.coderbot.iris.Iris; import java.io.FileReader; import java.io.IOException; @@ -103,7 +105,7 @@ public static SodiumGameOptions load(Path path) { } public void writeChanges() throws IOException { - Path dir = this.configPath.getParent(); + final Path dir = this.configPath.getParent(); if (!Files.exists(dir)) { Files.createDirectories(dir); @@ -111,7 +113,15 @@ public void writeChanges() throws IOException { throw new IOException("Not a directory: " + dir); } - Files.write(this.configPath, GSON.toJson(this) - .getBytes(StandardCharsets.UTF_8)); + Files.write(this.configPath, GSON.toJson(this).getBytes(StandardCharsets.UTF_8)); + if(AngelicaConfig.enableIris) { + try { + if (Iris.getIrisConfig() != null) { + Iris.getIrisConfig().save(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java index 0ebeabf70..30b4ff131 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java @@ -1,7 +1,6 @@ package me.jellysquid.mods.sodium.client.gui; import com.google.common.collect.ImmutableList; -import com.gtnewhorizons.angelica.client.gui.GuiShaders; import com.gtnewhorizons.angelica.config.AngelicaConfig; import jss.notfine.gui.GuiCustomMenu; import me.jellysquid.mods.sodium.client.SodiumClientMod; @@ -19,6 +18,7 @@ import me.jellysquid.mods.sodium.client.gui.utils.URLUtils; import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget; import me.jellysquid.mods.sodium.client.util.Dim2i; +import net.coderbot.iris.gui.screen.ShaderPackScreen; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.resources.I18n; import net.minecraft.util.EnumChatFormatting; @@ -63,13 +63,15 @@ public SodiumOptionsGUI(GuiScreen prevScreen) { this.pages.add(SodiumGameOptionPages.advanced()); this.pages.add(SodiumGameOptionPages.performance()); - if(AngelicaConfig.enableIris) - this.pages.add(shaderPacks = new OptionPage(I18n.format("options.iris.shaderPackSelection"), ImmutableList.of())); + if(AngelicaConfig.enableIris) { + shaderPacks = new OptionPage(I18n.format("options.iris.shaderPackSelection"), ImmutableList.of()); + this.pages.add(shaderPacks); + } } public void setPage(OptionPage page) { if (AngelicaConfig.enableIris && page == shaderPacks) { - mc.displayGuiScreen(new GuiShaders(prevScreen, mc.gameSettings)); + mc.displayGuiScreen(new ShaderPackScreen(this)); return; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java index 7b65ea293..fa85b6848 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java @@ -10,6 +10,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.function.BiConsumer; +import java.util.function.BooleanSupplier; import java.util.function.Function; public class OptionImpl implements Option { @@ -28,6 +29,7 @@ public class OptionImpl implements Option { private T value; private T modifiedValue; + private BooleanSupplier iris$dynamicallyEnabled; private final boolean enabled; private OptionImpl(OptionStorage storage, @@ -93,6 +95,9 @@ public OptionStorage getStorage() { @Override public boolean isAvailable() { + if (iris$dynamicallyEnabled != null) { + return iris$dynamicallyEnabled.getAsBoolean(); + } return this.enabled; } @@ -106,6 +111,9 @@ public void applyChanges() { this.binding.setValue(this.storage.getData(), this.modifiedValue); this.value = this.modifiedValue; } + public void iris$dynamicallyEnable(BooleanSupplier enabled) { + this.iris$dynamicallyEnabled = enabled; + } @Override public Collection getFlags() { diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index ea897bb43..bc762785b 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -1,6 +1,7 @@ package net.coderbot.iris; import com.google.common.base.Throwables; +import com.gtnewhorizons.angelica.Tags; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.mojang.realmsclient.gui.ChatFormatting; import cpw.mods.fml.client.registry.ClientRegistry; @@ -53,11 +54,9 @@ import java.util.zip.ZipException; public class Iris { - final boolean isDevelopmentEnvironment; + public final boolean isDevelopmentEnvironment; public static ContextCapabilities capabilities; - public static final String MODID = "angelica"; - /** * The user-facing name of the mod. Moved into a constant to facilitate easy branding changes (for forks). You'll still need to change this separately in * mixin plugin classes & the language files. @@ -70,18 +69,17 @@ public class Iris { private static ShaderpackDirectoryManager shaderpacksDirectoryManager; private static ShaderPack currentPack; + @Getter private static String currentPackName; @Getter private static boolean initialized; private static PipelineManager pipelineManager; + @Getter private static IrisConfig irisConfig; private static FileSystem zipFileSystem; - // TODO: Iris Backport - // private static KeyMapping reloadKeybind; - // private static KeyMapping toggleShadersKeybind; - // private static KeyMapping shaderpackScreenKeybind; + @Getter private static final Map shaderPackOptionQueue = new HashMap<>(); // Flag variable used when reloading // Used in favor of queueDefaultShaderPackOptionValues() for resetting as the @@ -89,6 +87,7 @@ public class Iris { private static boolean resetShaderPackOptions = false; private static String IRIS_VERSION; + @Getter private static boolean fallback; private static KeyBinding reloadKeybind; @@ -97,16 +96,8 @@ public class Iris { public static Iris INSTANCE = new Iris(); - // Wrapped in try-catch due to early initializing class private Iris() { isDevelopmentEnvironment = (boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment"); - // TODO: Iris Backport - // try { - // FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onInitializeClient); - // MinecraftForge.EVENT_BUS.addListener(this::onKeyInput); - // - // ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true)); - // }catch(Exception ignored) {} } @SubscribeEvent @@ -158,8 +149,6 @@ public void onEarlyInitialize() { logger.warn("", e); } - // Minecraft.getMinecraft().mcDataDir.toPath().resolve("shaderpacks") - // Minecraft.getMinecraft().mcDataDir.toPath().resolve("config") irisConfig = new IrisConfig(Minecraft.getMinecraft().mcDataDir.toPath().resolve("config").resolve("shaders.properties")); try { @@ -169,26 +158,10 @@ public void onEarlyInitialize() { logger.error("", e); } - // TODO: Iris Backport - // reloadKeybind = new KeyMapping("iris.keybind.reload", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_R, "iris.keybinds"); - // toggleShadersKeybind = new KeyMapping("iris.keybind.toggleShaders", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_K, "iris.keybinds"); - // shaderpackScreenKeybind = new KeyMapping("iris.keybind.shaderPackSelection", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_O, "iris.keybinds"); initialized = true; } - // TODO: Iris Backport - // public void onInitializeClient(final FMLClientSetupEvent event) { - // IRIS_VERSION = ModList.get().getModContainerById(MODID).get().getModInfo().getVersion().toString(); - // ClientRegistry.registerKeyBinding(reloadKeybind); - // ClientRegistry.registerKeyBinding(toggleShadersKeybind); - // ClientRegistry.registerKeyBinding(shaderpackScreenKeybind); - // } - - // TODO: Iris Backport - // public void onKeyInput(InputEvent.KeyInputEvent event) { - // handleKeybinds(Minecraft.getMinecraft()); - // } public static void identifyCapabilities() { capabilities = GLContext.getCapabilities(); } @@ -227,41 +200,6 @@ public static void onLoadingComplete() { Iris.getPipelineManager().preparePipeline(DimensionId.OVERWORLD); } - // TODO: Iris Backport - // public static void handleKeybinds(Minecraft minecraft) { - // if (reloadKeybind.consumeClick()) { - // try { - // reload(); - // - // if (minecraft.thePlayer != null) { - // minecraft.thePlayer.sendChatMessage(I18n.format("iris.shaders.reloaded"), false); - // } - // - // } catch (Exception e) { - // logger.error("Error while reloading Shaders for " + MODNAME + "!", e); - // - // if (minecraft.thePlayer != null) { - // minecraft.thePlayer.sendChatMessage(I18n.format("iris.shaders.reloaded.failure", Throwables.getRootCause(e).getMessage()).withStyle( - // ChatFormatting.RED), false); - // } - // } - // } else if (toggleShadersKeybind.consumeClick()) { - // try { - // toggleShaders(minecraft, !irisConfig.areShadersEnabled()); - // } catch (Exception e) { - // logger.error("Error while toggling shaders!", e); - // - // if (minecraft.thePlayer != null) { - // minecraft.thePlayer.sendChatMessage(I18n.format("iris.shaders.toggled.failure", Throwables.getRootCause(e).getMessage()).withStyle(ChatFormatting.RED), false); - // } - // setShadersDisabled(); - // fallback = true; - // } - // } else if (shaderpackScreenKeybind.consumeClick()) { - // minecraft.setScreen(new ShaderPackScreen(null)); - // } - // } - public static void toggleShaders(Minecraft minecraft, boolean enabled) throws IOException { irisConfig.setShadersEnabled(enabled); irisConfig.save(); @@ -290,7 +228,7 @@ public static void loadShaderpack() { } // Attempt to load an external shaderpack if it is available - Optional externalName = irisConfig.getShaderPackName(); + final Optional externalName = irisConfig.getShaderPackName(); if (!externalName.isPresent()) { logger.info("Shaders are disabled because no valid shaderpack is selected"); @@ -308,8 +246,8 @@ public static void loadShaderpack() { } private static boolean loadExternalShaderpack(String name) { - Path shaderPackRoot; - Path shaderPackConfigTxt; + final Path shaderPackRoot; + final Path shaderPackConfigTxt; try { shaderPackRoot = getShaderpacksDirectory().resolve(name); @@ -320,10 +258,10 @@ private static boolean loadExternalShaderpack(String name) { return false; } - Path shaderPackPath; + final Path shaderPackPath; if (shaderPackRoot.toString().endsWith(".zip")) { - Optional optionalPath; + final Optional optionalPath; try { optionalPath = loadExternalZipShaderpack(shaderPackRoot); @@ -363,7 +301,7 @@ private static boolean loadExternalShaderpack(String name) { return false; } - Map changedConfigs = tryReadConfigProperties(shaderPackConfigTxt).map(properties -> (Map) (Map) properties) + final Map changedConfigs = tryReadConfigProperties(shaderPackConfigTxt).map(properties -> (Map) (Map) properties) .orElse(new HashMap<>()); changedConfigs.putAll(shaderPackOptionQueue); @@ -377,10 +315,10 @@ private static boolean loadExternalShaderpack(String name) { try { currentPack = new ShaderPack(shaderPackPath, changedConfigs, StandardMacros.createStandardEnvironmentDefines()); - MutableOptionValues changedConfigsValues = currentPack.getShaderPackOptions().getOptionValues().mutableCopy(); + final MutableOptionValues changedConfigsValues = currentPack.getShaderPackOptions().getOptionValues().mutableCopy(); // Store changed values from those currently in use by the shader pack - Properties configsToSave = new Properties(); + final Properties configsToSave = new Properties(); changedConfigsValues.getBooleanValues().forEach((k, v) -> configsToSave.setProperty(k, Boolean.toString(v))); changedConfigsValues.getStringValues().forEach(configsToSave::setProperty); @@ -401,13 +339,13 @@ private static boolean loadExternalShaderpack(String name) { } private static Optional loadExternalZipShaderpack(Path shaderpackPath) throws IOException { - FileSystem zipSystem = FileSystems.newFileSystem(shaderpackPath, Iris.class.getClassLoader()); + final FileSystem zipSystem = FileSystems.newFileSystem(shaderpackPath, Iris.class.getClassLoader()); zipFileSystem = zipSystem; // Should only be one root directory for a zip shaderpack - Path root = zipSystem.getRootDirectories().iterator().next(); + final Path root = zipSystem.getRootDirectories().iterator().next(); - Path potentialShaderDir = zipSystem.getPath("shaders"); + final Path potentialShaderDir = zipSystem.getPath("shaders"); // If the shaders dir was immediately found return it // Otherwise, manually search through each directory path until it ends with "shaders" @@ -435,7 +373,7 @@ private static void setShadersDisabled() { // Temp escalation public static void setDebug(boolean enable) { GLStateManager.assertMainThread(); - int success; + final int success; if (enable) { success = GLDebug.setupDebugMessageCallback(); } else { @@ -461,7 +399,7 @@ public static void setDebug(boolean enable) { } private static Optional tryReadConfigProperties(Path path) { - Properties properties = new Properties(); + final Properties properties = new Properties(); if (Files.exists(path)) { try (InputStream is = Files.newInputStream(path)) { @@ -517,7 +455,7 @@ public static boolean isValidShaderpack(Path pack) { if (pack.toString().endsWith(".zip")) { try (FileSystem zipSystem = FileSystems.newFileSystem(pack, Iris.class.getClassLoader())) { - Path root = zipSystem.getRootDirectories().iterator().next(); + final Path root = zipSystem.getRootDirectories().iterator().next(); try (Stream stream = Files.walk(root)) { return stream.filter(Files::isDirectory).anyMatch(path -> path.endsWith("shaders")); } @@ -532,10 +470,6 @@ public static boolean isValidShaderpack(Path pack) { return false; } - public static Map getShaderPackOptionQueue() { - return shaderPackOptionQueue; - } - public static void queueShaderPackOptionsFromProfile(Profile profile) { getShaderPackOptionQueue().putAll(profile.optionValues); } @@ -551,8 +485,8 @@ public static void queueDefaultShaderPackOptionValues() { clearShaderPackOptionQueue(); getCurrentPack().ifPresent(pack -> { - OptionSet options = pack.getShaderPackOptions().getOptionSet(); - OptionValues values = pack.getShaderPackOptions().getOptionValues(); + final OptionSet options = pack.getShaderPackOptions().getOptionSet(); + final OptionValues values = pack.getShaderPackOptions().getOptionValues(); options.getStringOptions().forEach((key, mOpt) -> { if (values.getStringValue(key).isPresent()) { @@ -623,7 +557,7 @@ private static void destroyEverything() { public static DimensionId lastDimension = null; public static DimensionId getCurrentDimension() { - WorldClient level = Minecraft.getMinecraft().theWorld; + final WorldClient level = Minecraft.getMinecraft().theWorld; if (level != null) { if (level.provider == null) return DimensionId.OVERWORLD; @@ -649,7 +583,7 @@ private static WorldRenderingPipeline createPipeline(DimensionId dimensionId) { return new FixedFunctionWorldRenderingPipeline(); } - ProgramSet programs = currentPack.getProgramSet(dimensionId); + final ProgramSet programs = currentPack.getProgramSet(dimensionId); try { @@ -677,18 +611,6 @@ public static Optional getCurrentPack() { return Optional.ofNullable(currentPack); } - public static String getCurrentPackName() { - return currentPackName; - } - - public static IrisConfig getIrisConfig() { - return irisConfig; - } - - public static boolean isFallback() { - return fallback; - } - public static String getVersion() { if (IRIS_VERSION == null) { return "Version info unknown!"; @@ -698,7 +620,7 @@ public static String getVersion() { } public static String getFormattedVersion() { - ChatFormatting color; + final ChatFormatting color; String version = getVersion(); if (version.endsWith("-development-environment")) { @@ -731,10 +653,12 @@ public static ShaderpackDirectoryManager getShaderpacksDirectoryManager() { return shaderpacksDirectoryManager; } - public void registerKeybindings() { - reloadKeybind = new KeyBinding("Reload Shaders", 0, "Iris Keybinds"); - toggleShadersKeybind = new KeyBinding("Toggle Shaders", 0, "Iris Keybinds"); - shaderpackScreenKeybind = new KeyBinding("Shaderpack Selection Screen", 0, "Iris Keybinds"); + public void fmlInitEvent() { + IRIS_VERSION = Tags.VERSION; + reloadKeybind = new KeyBinding("Reload Shaders", 0, "Iris Keybinds"); + toggleShadersKeybind = new KeyBinding("Toggle Shaders", 0, "Iris Keybinds"); + shaderpackScreenKeybind = new KeyBinding("Shaderpack Selection Screen", 0, "Iris Keybinds"); + ClientRegistry.registerKeyBinding(reloadKeybind); ClientRegistry.registerKeyBinding(toggleShadersKeybind); ClientRegistry.registerKeyBinding(shaderpackScreenKeybind); diff --git a/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java b/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java index 81bd0e8e3..4312cacbb 100644 --- a/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java +++ b/src/main/java/net/coderbot/iris/apiimpl/IrisApiV0Impl.java @@ -7,6 +7,7 @@ import net.irisshaders.iris.api.v0.IrisApi; import net.irisshaders.iris.api.v0.IrisApiConfig; + public class IrisApiV0Impl implements IrisApi { public static final IrisApiV0Impl INSTANCE = new IrisApiV0Impl(); private static final IrisApiV0ConfigImpl CONFIG = new IrisApiV0ConfigImpl(); @@ -36,7 +37,7 @@ public boolean isRenderingShadowPass() { public Object openMainIrisScreenObj(Object parent) { return new Object(); // TODO: GUI -// return new ShaderPackScreen((GuiScreen) parent); + // return new ShaderPackScreen((GuiScreen) parent); } @Override diff --git a/src/main/java/net/coderbot/iris/config/IrisConfig.java b/src/main/java/net/coderbot/iris/config/IrisConfig.java index df9fb21ed..9392cf541 100644 --- a/src/main/java/net/coderbot/iris/config/IrisConfig.java +++ b/src/main/java/net/coderbot/iris/config/IrisConfig.java @@ -158,7 +158,7 @@ public void load() throws IOException { * @throws IOException file exceptions */ public void save() throws IOException { - Properties properties = new Properties(); + final Properties properties = new Properties(); properties.setProperty("shaderPack", getShaderPackName().orElse("")); properties.setProperty("enableShaders", enableShaders ? "true" : "false"); properties.setProperty("enableDebugOptions", enableDebugOptions ? "true" : "false"); diff --git a/src/main/java/net/coderbot/iris/gui/FileDialogUtil.java b/src/main/java/net/coderbot/iris/gui/FileDialogUtil.java new file mode 100644 index 000000000..51f67a821 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/FileDialogUtil.java @@ -0,0 +1,63 @@ +package net.coderbot.iris.gui; + +import org.jetbrains.annotations.Nullable; +import org.lwjgl.PointerBuffer; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Class used to make interfacing with {@link TinyFileDialogs} easier and asynchronous. + */ +public final class FileDialogUtil { + private static final ExecutorService FILE_DIALOG_EXECUTOR = Executors.newSingleThreadExecutor(); + + private FileDialogUtil() {} + + /** + * Opens an asynchronous file select dialog window. + * + * @param dialog Whether to open a "save" dialog or an "open" dialog + * @param title The title of the dialog window + * @param origin The path that the window should start at + * @param filterLabel A label used to describe what file extensions are allowed and their purpose + * @param filters The file extension filters used by the dialog, each formatted as {@code "*.extension"} + * @return a {@link CompletableFuture} which is completed once a file is selected or the dialog is cancelled. + */ +// public static CompletableFuture> fileSelectDialog(DialogType dialog, String title, @Nullable Path origin, @Nullable String filterLabel, String ... filters) { +// CompletableFuture> future = new CompletableFuture<>(); +// +// FILE_DIALOG_EXECUTOR.submit(() -> { +// String result = null; +// +// try (MemoryStack stack = MemoryStack.stackPush()) { +// PointerBuffer filterBuffer = stack.mallocPointer(filters.length); +// +// for (String filter : filters) { +// filterBuffer.put(stack.UTF8(filter)); +// } +// filterBuffer.flip(); +// +// String path = origin != null ? origin.toAbsolutePath().toString() : null; +// +// if (dialog == DialogType.SAVE) { +// result = TinyFileDialogs.tinyfd_saveFileDialog(title, path, filterBuffer, filterLabel); +// } else if (dialog == DialogType.OPEN) { +// result = TinyFileDialogs.tinyfd_openFileDialog(title, path, filterBuffer, filterLabel, false); +// } +// } +// +// future.complete(Optional.ofNullable(result).map(Paths::get)); +// }); +// +// return future; +// } + + public enum DialogType { + SAVE, OPEN + } +} diff --git a/src/main/java/net/coderbot/iris/gui/GuiUtil.java b/src/main/java/net/coderbot/iris/gui/GuiUtil.java new file mode 100644 index 000000000..a7b53e565 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/GuiUtil.java @@ -0,0 +1,208 @@ +package net.coderbot.iris.gui; + +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import cpw.mods.fml.client.config.GuiUtils; +import lombok.Getter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL14; + +/** + * Class serving as abstraction and + * centralization for common GUI + * rendering/other code calls. + * + * Helps allow for easier portability + * to Minecraft 1.17 by abstracting + * some code that will be changed. + */ +public final class GuiUtil { + public static final ResourceLocation IRIS_WIDGETS_TEX = new ResourceLocation("iris", "textures/gui/widgets.png"); + private static final String ELLIPSIS = "..."; + + private GuiUtil() {} + + private static Minecraft client() { + return Minecraft.getMinecraft(); + } + + /** + * Binds Iris's widgets texture to be + * used for succeeding draw calls. + */ + public static void bindIrisWidgetsTexture() { + client().getTextureManager().bindTexture(IRIS_WIDGETS_TEX); + } + + /** + * Draws a button. Button textures must be mapped with the + * same coordinates as those on the vanilla widgets texture. + * + * @param x X position of the left of the button + * @param y Y position of the top of the button + * @param width Width of the button, maximum 398 + * @param height Height of the button, maximum 20 + * @param hovered Whether the button is being hovered over with the mouse + * @param disabled Whether the button should use the "disabled" texture + */ + public static void drawButton(int x, int y, int width, int height, boolean hovered, boolean disabled) { + // Create variables for half of the width and height. + // Will not be exact when width and height are odd, but + // that case is handled within the draw calls. + final int halfWidth = width / 2; + final int halfHeight = height / 2; + + // V offset for which button texture to use + final int vOffset = disabled ? 46 : hovered ? 86 : 66; + + // Sets RenderSystem to use solid white as the tint color for blend mode, and enables blend mode + GL14.glBlendColor(1.0f, 1.0f, 1.0f, 1.0f); + GLStateManager.enableBlend(); + + // Sets RenderSystem to be able to use textures when drawing + GLStateManager.enableTexture(); + + // Top left section + GuiUtils.drawTexturedModalRect(x, y, 0, vOffset, halfWidth, halfHeight, 256); + // Top right section + GuiUtils.drawTexturedModalRect(x + halfWidth, y, 200 - (width - halfWidth), vOffset, width - halfWidth, halfHeight, 256); + // Bottom left section + GuiUtils.drawTexturedModalRect(x, y + halfHeight, 0, vOffset + (20 - (height - halfHeight)), halfWidth, height - halfHeight, 256); + // Bottom right section + GuiUtils.drawTexturedModalRect(x + halfWidth, y + halfHeight, 200 - (width - halfWidth), vOffset + (20 - (height - halfHeight)), width - halfWidth, height - halfHeight, 256); + } + + /** + * Draws a translucent black panel + * with a light border. + * + * @param x The x position of the panel + * @param y The y position of the panel + * @param width The width of the panel + * @param height The height of the panel + */ + public static void drawPanel(int x, int y, int width, int height) { + final int borderColor = 0xDEDEDEDE; + final int innerColor = 0xDE000000; + + // Top border section + Gui.drawRect(x, y, x + width, y + 1, borderColor); + // Bottom border section + Gui.drawRect(x, (y + height) - 1, x + width, y + height, borderColor); + // Left border section + Gui.drawRect(x, y + 1, x + 1, (y + height) - 1, borderColor); + // Right border section + Gui.drawRect((x + width) - 1, y + 1, x + width, (y + height) - 1, borderColor); + // Inner section + Gui.drawRect(x + 1, y + 1, (x + width) - 1, (y + height) - 1, innerColor); + } + + /** + * Draws a text with a panel behind it. + * + * @param text The text String to draw + * @param x The x position of the panel + * @param y The y position of the panel + */ + public static void drawTextPanel(FontRenderer font, String text, int x, int y) { + drawPanel(x, y, font.getStringWidth(text) + 8, 16); + font.drawStringWithShadow(text, x + 4, y + 4, 0xFFFFFF); + } + + /** + * Shorten a text to a specific length, adding an ellipsis (...) + * to the end if shortened. + * + * Text may lose formatting. + * + * @param font Font to use for determining the width of text + * @param text Text to shorten + * @param width Width to shorten text to + * @return a shortened text + */ + public static String shortenText(FontRenderer font, String text, int width) { + if (font.getStringWidth(text) > width) { + return font.trimStringToWidth(text, width - font.getStringWidth(ELLIPSIS)) + ELLIPSIS; + } + return text; + } + + /** + * Creates a new translated text, if a translation + * is present. If not, will return the default text + * String passed. + * + * @param defaultText Default text to use if no translation is found + * @param translationDesc Translation key to try and use + * @param format Formatting arguments for the translated text, if created + * @return the translated text if found, otherwise the default provided + */ + public static String translateOrDefault(String defaultText, String translationDesc, Object ... format) { + final String translated = I18n.format(translationDesc, format); + if(!translated.equals(translationDesc)) { + return translated; + } + return defaultText; + } + + /** + * Plays the {@code UI_BUTTON_CLICK} sound event as a + * master sound effect. + * + * Used in non-{@code ButtonWidget} UI elements upon click + * or other action. + */ + public static void playButtonClickSound() { +// client().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1)); + } + + /** + * A class representing a section of a + * texture, to be easily drawn in GUIs. + */ + public static class Icon { + public static final Icon SEARCH = new Icon(0, 0, 7, 8); + public static final Icon CLOSE = new Icon(7, 0, 5, 6); + public static final Icon REFRESH = new Icon(12, 0, 10, 10); + public static final Icon EXPORT = new Icon(22, 0, 7, 8); + public static final Icon EXPORT_COLORED = new Icon(29, 0, 7, 8); + public static final Icon IMPORT = new Icon(22, 8, 7, 8); + public static final Icon IMPORT_COLORED = new Icon(29, 8, 7, 8); + + private final int u; + private final int v; + @Getter + private final int width; + @Getter + private final int height; + + public Icon(int u, int v, int width, int height) { + this.u = u; + this.v = v; + this.width = width; + this.height = height; + } + + /** + * Draws this icon to the screen at the specified coordinates. + * + * @param x The x position to draw the icon at (left) + * @param y The y position to draw the icon at (top) + */ + public void draw(int x, int y) { + // Sets RenderSystem to use solid white as the tint color for blend mode, and enables blend mode + GL14.glBlendColor(1.0f, 1.0f, 1.0f, 1.0f); + GLStateManager.enableBlend(); + + // Sets RenderSystem to be able to use textures when drawing + GLStateManager.enableTexture(); + + // Draw the texture to the screen + GuiUtils.drawTexturedModalRect(x, y, u, v, width, height, 256); + } + + } +} diff --git a/src/main/java/net/coderbot/iris/gui/NavigationController.java b/src/main/java/net/coderbot/iris/gui/NavigationController.java new file mode 100644 index 000000000..bb4d183f8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/NavigationController.java @@ -0,0 +1,65 @@ +package net.coderbot.iris.gui; + +import lombok.Getter; +import net.coderbot.iris.gui.element.ShaderPackOptionList; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; + +import java.util.ArrayDeque; +import java.util.Deque; + +public class NavigationController { + private final OptionMenuContainer container; + private ShaderPackOptionList optionList; + + @Getter + private String currentScreen = null; + private final Deque history = new ArrayDeque<>(); + + public NavigationController(OptionMenuContainer container) { + this.container = container; + } + + public void back() { + if (history.size() > 0) { + history.removeLast(); + + if (history.size() > 0) { + currentScreen = history.getLast(); + } else { + currentScreen = null; + } + } else { + currentScreen = null; + } + + this.rebuild(); + } + + public void open(String screen) { + currentScreen = screen; + history.addLast(screen); + + this.rebuild(); + } + + public void rebuild() { + if (optionList != null) { + optionList.rebuild(); + } + } + + public void refresh() { + if (optionList != null) { + optionList.refresh(); + } + } + + public boolean hasHistory() { + return this.history.size() > 0; + } + + public void setActiveOptionList(ShaderPackOptionList optionList) { + this.optionList = optionList; + } + +} diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java b/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java new file mode 100644 index 000000000..a5d2ab4c2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java @@ -0,0 +1,225 @@ +package net.coderbot.iris.gui.element; + +import net.coderbot.iris.gui.GuiUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +/** + * Intended to make very simple rows of buttons easier to make + */ +public class IrisElementRow { + private final Map elements = new HashMap<>(); + private final List orderedElements = new ArrayList<>(); + private final int spacing; + private int x; + private int y; + private int width; + private int height; + + public IrisElementRow(int spacing) { + this.spacing = spacing; + } + + public IrisElementRow() { + this(1); + } + + /** + * Adds an element to the right of this row. + * + * @param element The element to add + * @param width The width of the element in this row + * @return {@code this}, to be used for chaining statements + */ + public IrisElementRow add(Element element, int width) { + if (!this.orderedElements.contains(element)) { + this.orderedElements.add(element); + } + this.elements.put(element, width); + + this.width += width + this.spacing; + + return this; + } + + /** + * Modifies the width of an element. + * + * @param element The element whose width to modify + * @param width The width to be assigned to the specified element + */ + public void setWidth(Element element, int width) { + if (!this.elements.containsKey(element)) { + return; + } + + this.width -= this.elements.get(element) + 2; + + add(element, width); + } + + /** + * Renders the row, with the anchor point being the top left. + */ + public void render(int x, int y, int height, int mouseX, int mouseY, float tickDelta, boolean rowHovered) { + this.x = x; + this.y = y; + this.height = height; + + int currentX = x; + + for (Element element : this.orderedElements) { + int currentWidth = this.elements.get(element); + + element.render(currentX, y, currentWidth, height, mouseX, mouseY, tickDelta, + rowHovered && sectionHovered(currentX, currentWidth, mouseX, mouseY)); + + currentX += currentWidth + this.spacing; + } + } + + /** + * Renders the row, with the anchor point being the top right. + */ + public void renderRightAligned(int x, int y, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + render(x - this.width, y, height, mouseX, mouseY, tickDelta, hovered); + } + + private boolean sectionHovered(int sectionX, int sectionWidth, double mx, double my) { + return mx > sectionX && mx < sectionX + sectionWidth && + my > this.y && my < this.y + this.height; + } + + private Optional getHovered(double mx, double my) { + int currentX = this.x; + + for (Element element : this.orderedElements) { + int currentWidth = this.elements.get(element); + + if (sectionHovered(currentX, currentWidth, mx, my)) { + return Optional.of(element); + } + + currentX += currentWidth + this.spacing; + } + + return Optional.empty(); + } + + public boolean mouseClicked(double mx, double my, int button) { + return getHovered(mx, my).map(element -> element.mouseClicked(mx, my, button)).orElse(false); + } + + public boolean mouseReleased(double mx, double my, int button) { + return getHovered(mx, my).map(element -> element.mouseReleased(mx, my, button)).orElse(false); + } + + public static abstract class Element { + public boolean disabled = false; + private boolean hovered = false; + + public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + GuiUtil.bindIrisWidgetsTexture(); + GuiUtil.drawButton(x, y, width, height, hovered, this.disabled); + + this.hovered = hovered; + this.renderLabel(x, y, width, height, mouseX, mouseY, tickDelta, hovered); + } + + public abstract void renderLabel(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered); + + public boolean mouseClicked(double mx, double my, int button) { + return false; + } + + public boolean mouseReleased(double mx, double my, int button) { + return false; + } + + public boolean isHovered() { + return hovered; + } + } + + public static abstract class ButtonElement> extends Element { + private final Function onClick; + + protected ButtonElement(Function onClick) { + this.onClick = onClick; + } + + @Override + public boolean mouseClicked(double mx, double my, int button) { + if (this.disabled) { + return false; + } + + if (button == 0) { + return this.onClick.apply((T) this); + } + + return super.mouseClicked(mx, my, button); + } + } + + /** + * A clickable button element that uses a {@link net.coderbot.iris.gui.GuiUtil.Icon} as its label. + */ + public static class IconButtonElement extends ButtonElement { + public GuiUtil.Icon icon; + public GuiUtil.Icon hoveredIcon; + + public IconButtonElement(GuiUtil.Icon icon, GuiUtil.Icon hoveredIcon, Function onClick) { + super(onClick); + this.icon = icon; + this.hoveredIcon = hoveredIcon; + } + + public IconButtonElement(GuiUtil.Icon icon, Function onClick) { + this(icon, icon, onClick); + } + + @Override + public void renderLabel(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + int iconX = x + (int)((width - this.icon.getWidth()) * 0.5); + int iconY = y + (int)((height - this.icon.getHeight()) * 0.5); + + GuiUtil.bindIrisWidgetsTexture(); + if (!this.disabled && hovered) { + this.hoveredIcon.draw(iconX, iconY); + } else { + this.icon.draw(iconX, iconY); + } + } + } + + /** + * A clickable button element that uses a text component as its label. + */ + public static class TextButtonElement extends ButtonElement { + protected final FontRenderer font; + public String text; + + public TextButtonElement(String text, Function onClick) { + super(onClick); + + this.font = Minecraft.getMinecraft().fontRenderer; + this.text = text; + } + + @Override + public void renderLabel(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + int textX = x + (int)((width - this.font.getStringWidth(this.text)) * 0.5); + int textY = y + (int)((height - 8) * 0.5); + + this.font.drawStringWithShadow(this.text, textX, textY, 0xFFFFFF); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java b/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java new file mode 100644 index 000000000..92a0f6c6f --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java @@ -0,0 +1,32 @@ +package net.coderbot.iris.gui.element; + +import lombok.Getter; +import lombok.Setter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiSlot; +import net.minecraft.client.renderer.Tessellator; + +// TODO: look into GuiListExtended & GuiSelectStringEntries +public abstract class IrisGuiSlot extends GuiSlot { + @Setter @Getter protected boolean renderBackground = true; + + protected IrisGuiSlot(Minecraft mc, int width, int height, int top, int bottom, int slotHeight) { + super(mc, width, height, top, bottom, slotHeight); + } + + @Override + protected void drawContainerBackground(Tessellator tessellator) { + if(this.renderBackground) { + super.drawContainerBackground(tessellator); + } + } + + @Override + protected int getScrollBarX() { + // Position the scrollbar at the rightmost edge of the screen. + // By default, the scrollbar is positioned moderately offset from the center. + return this.width - 6; + } + + +} diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java new file mode 100644 index 000000000..966c26384 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java @@ -0,0 +1,389 @@ +package net.coderbot.iris.gui.element; + +import lombok.Getter; +import net.coderbot.iris.gui.FileDialogUtil; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.element.widget.AbstractElementWidget; +import net.coderbot.iris.gui.element.widget.OptionMenuConstructor; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.ShaderPack; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; +import net.minecraft.client.Minecraft; + +import net.minecraft.client.gui.GuiSlot; +import net.minecraft.client.renderer.Tessellator; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +public class ShaderPackOptionList extends IrisGuiSlot { + private final List> elementWidgets = new ArrayList<>(); + private final ShaderPackScreen screen; + @Getter + private final NavigationController navigation; + private OptionMenuContainer container; + + public ShaderPackOptionList(ShaderPackScreen screen, NavigationController navigation, ShaderPack pack, Minecraft client, int width, int height, int top, int bottom, int left, int right) { + super(client, width, height, top, bottom, 24); + this.navigation = navigation; + this.screen = screen; + + applyShaderPack(pack); + } + + public void applyShaderPack(ShaderPack pack) { + this.container = pack.getMenuContainer(); + } + + public void rebuild() { +// this.clearEntries(); +// this.setScrollAmount(0); + OptionMenuConstructor.constructAndApplyToScreen(this.container, this.screen, this, navigation); + } + + public void refresh() { + this.elementWidgets.forEach(widget -> widget.init(this.screen, this.navigation)); + } + +// @Override +// public int getRowWidth() { +// return Math.min(400, width - 12); +// } +// +// public void addHeader(Component text, boolean backButton) { +// this.addEntry(new HeaderEntry(this.screen, this.navigation, text, backButton)); +// } +// +// public void addWidgets(int columns, List> elements) { +// this.elementWidgets.addAll(elements); +// +// List> row = new ArrayList<>(); +// for (AbstractElementWidget element : elements) { +// row.add(element); +// +// if (row.size() >= columns) { +// this.addEntry(new ElementRowEntry(screen, this.navigation, row)); +// row = new ArrayList<>(); // Clearing the list would affect the row entry created above +// } +// } +// +// if (row.size() > 0) { +// while (row.size() < columns) { +// row.add(AbstractElementWidget.EMPTY); +// } +// +// this.addEntry(new ElementRowEntry(screen, this.navigation, row)); +// } +// } + + @Override + protected int getSize() { + return 0; + } + + @Override + protected void elementClicked(int p_148144_1_, boolean p_148144_2_, int p_148144_3_, int p_148144_4_) { + + } + + @Override + protected boolean isSelected(int p_148131_1_) { + return false; + } + + @Override + protected void drawBackground() { + + } + + @Override + protected void drawSlot(int p_148126_1_, int p_148126_2_, int p_148126_3_, int p_148126_4_, Tessellator p_148126_5_, int p_148126_6_, int p_148126_7_) { + + } +// +// public abstract static class BaseEntry extends ObjectSelectionList.Entry { +// protected final NavigationController navigation; +// +// protected BaseEntry(NavigationController navigation) { +// this.navigation = navigation; +// } +// } +// +// public static class HeaderEntry extends BaseEntry { +// public static final Component BACK_BUTTON_TEXT = new TextComponent("< ").append(new TranslatableComponent("options.iris.back").withStyle(ChatFormatting.ITALIC)); +// public static final MutableComponent RESET_BUTTON_TEXT_INACTIVE = new TranslatableComponent("options.iris.reset").withStyle(ChatFormatting.GRAY); +// public static final MutableComponent RESET_BUTTON_TEXT_ACTIVE = new TranslatableComponent("options.iris.reset").withStyle(ChatFormatting.YELLOW); +// +// public static final MutableComponent RESET_HOLD_SHIFT_TOOLTIP = new TranslatableComponent("options.iris.reset.tooltip.holdShift").withStyle(ChatFormatting.GOLD); +// public static final MutableComponent RESET_TOOLTIP = new TranslatableComponent("options.iris.reset.tooltip").withStyle(ChatFormatting.RED); +// public static final MutableComponent IMPORT_TOOLTIP = new TranslatableComponent("options.iris.importSettings.tooltip") +// .withStyle(style -> style.withColor(TextColor.fromRgb(0x4da6ff))); +// public static final MutableComponent EXPORT_TOOLTIP = new TranslatableComponent("options.iris.exportSettings.tooltip") +// .withStyle(style -> style.withColor(TextColor.fromRgb(0xfc7d3d))); +// +// private static final int MIN_SIDE_BUTTON_WIDTH = 42; +// private static final int BUTTON_HEIGHT = 16; +// +// private final ShaderPackScreen screen; +// private final @Nullable IrisElementRow backButton; +// private final IrisElementRow utilityButtons = new IrisElementRow(); +// private final IrisElementRow.TextButtonElement resetButton; +// private final IrisElementRow.IconButtonElement importButton; +// private final IrisElementRow.IconButtonElement exportButton; +// private final Component text; +// +// public HeaderEntry(ShaderPackScreen screen, NavigationController navigation, Component text, boolean hasBackButton) { +// super(navigation); +// +// if (hasBackButton) { +// this.backButton = new IrisElementRow().add( +// new IrisElementRow.TextButtonElement(BACK_BUTTON_TEXT, this::backButtonClicked), +// Math.max(MIN_SIDE_BUTTON_WIDTH, Minecraft.getInstance().font.width(BACK_BUTTON_TEXT) + 8) +// ); +// } else { +// this.backButton = null; +// } +// +// this.resetButton = new IrisElementRow.TextButtonElement( +// RESET_BUTTON_TEXT_INACTIVE, this::resetButtonClicked); +// this.importButton = new IrisElementRow.IconButtonElement( +// GuiUtil.Icon.IMPORT, GuiUtil.Icon.IMPORT_COLORED, this::importSettingsButtonClicked); +// this.exportButton = new IrisElementRow.IconButtonElement( +// GuiUtil.Icon.EXPORT, GuiUtil.Icon.EXPORT_COLORED, this::exportSettingsButtonClicked); +// +// this.utilityButtons +// .add(this.importButton, 15) +// .add(this.exportButton, 15) +// .add(this.resetButton, Math.max(MIN_SIDE_BUTTON_WIDTH, Minecraft.getInstance().font.width(RESET_BUTTON_TEXT_INACTIVE) + 8)); +// +// this.screen = screen; +// this.text = text; +// } +// +// @Override +// public void drawScreen(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { +// // Draw dividing line +// fill(x - 3, (y + entryHeight) - 2, x + entryWidth, (y + entryHeight) - 1, 0x66BEBEBE); +// +// Font font = Minecraft.getInstance().font; +// +// // Draw header text +// drawCenteredString(font, text, x + (int)(entryWidth * 0.5), y + 5, 0xFFFFFF); +// +// GuiUtil.bindIrisWidgetsTexture(); +// +// // Draw back button if present +// if (this.backButton != null) { +// backButton.drawScreen(x, y, BUTTON_HEIGHT, mouseX, mouseY, tickDelta, hovered); +// } +// +// boolean shiftDown = Screen.hasShiftDown(); +// +// // Set the appearance of the reset button +// this.resetButton.disabled = !shiftDown; +// this.resetButton.text = shiftDown ? RESET_BUTTON_TEXT_ACTIVE : RESET_BUTTON_TEXT_INACTIVE; +// +// // Draw the utility buttons +// this.utilityButtons.renderRightAligned((x + entryWidth) - 3, y, BUTTON_HEIGHT, mouseX, mouseY, tickDelta, hovered); +// +// // Draw the reset button's tooltip +// if (this.resetButton.isHovered()) { +// Component tooltip = shiftDown ? RESET_TOOLTIP : RESET_HOLD_SHIFT_TOOLTIP; +// queueBottomRightAnchoredTooltip(mouseX, mouseY, font, tooltip); +// } +// // Draw the import/export button tooltips +// if (this.importButton.isHovered()) { +// queueBottomRightAnchoredTooltip(mouseX, mouseY, font, IMPORT_TOOLTIP); +// } +// if (this.exportButton.isHovered()) { +// queueBottomRightAnchoredTooltip(mouseX, mouseY, font, EXPORT_TOOLTIP); +// } +// } +// +// private void queueBottomRightAnchoredTooltip(int x, int y, Font font, Component text) { +// ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel( +// font, text, +// x - (font.width(text) + 10), y - 16 +// )); +// } +// +// @Override +// public boolean mouseClicked(double mouseX, double mouseY, int button) { +// boolean backButtonResult = backButton != null && backButton.mouseClicked(mouseX, mouseY, button); +// boolean utilButtonResult = utilityButtons.mouseClicked(mouseX, mouseY, button); +// +// return backButtonResult || utilButtonResult; +// } +// +// private boolean backButtonClicked(IrisElementRow.TextButtonElement button) { +// this.navigation.back(); +// GuiUtil.playButtonClickSound(); +// +// return true; +// } +// +// private boolean resetButtonClicked(IrisElementRow.TextButtonElement button) { +// if (Screen.hasShiftDown()) { +// Iris.resetShaderPackOptionsOnNextReload(); +// this.screen.applyChanges(); +// GuiUtil.playButtonClickSound(); +// +// return true; +// } +// +// return false; +// } +// +// private boolean importSettingsButtonClicked(IrisElementRow.IconButtonElement button) { +// GuiUtil.playButtonClickSound(); +// +// // Invalid state to be in +// if (!Iris.getCurrentPack().isPresent()) { +// return false; +// } +// +// // Displaying a dialog when the game is full-screened can cause severe issues +// // https://github.com/IrisShaders/Iris/issues/1258 +// if (Minecraft.getInstance().getWindow().isFullscreen()) { +// this.screen.displayNotification( +// new TranslatableComponent("options.iris.mustDisableFullscreen") +// .withStyle(ChatFormatting.RED).withStyle(ChatFormatting.BOLD)); +// return false; +// } +// +// final ShaderPackScreen originalScreen = this.screen; // Also used to prevent invalid state +// +// FileDialogUtil.fileSelectDialog( +// FileDialogUtil.DialogType.OPEN, "Import Shader Settings from File", +// Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"), +// "Shader Pack Settings (.txt)", "*.txt") +// .whenComplete((path, err) -> { +// if (err != null) { +// Iris.logger.error("Error selecting shader settings from file", err); +// +// return; +// } +// +// if (Minecraft.getInstance().screen == originalScreen) { +// path.ifPresent(originalScreen::importPackOptions); +// } +// }); +// +// return true; +// } +// +// private boolean exportSettingsButtonClicked(IrisElementRow.IconButtonElement button) { +// GuiUtil.playButtonClickSound(); +// +// // Invalid state to be in +// if (!Iris.getCurrentPack().isPresent()) { +// return false; +// } +// +// // Displaying a dialog when the game is full-screened can cause severe issues +// // https://github.com/IrisShaders/Iris/issues/1258 +// if (Minecraft.getInstance().getWindow().isFullscreen()) { +// this.screen.displayNotification( +// new TranslatableComponent("options.iris.mustDisableFullscreen") +// .withStyle(ChatFormatting.RED).withStyle(ChatFormatting.BOLD)); +// return false; +// } +// +// FileDialogUtil.fileSelectDialog( +// FileDialogUtil.DialogType.SAVE, "Export Shader Settings to File", +// Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"), +// "Shader Pack Settings (.txt)", "*.txt") +// .whenComplete((path, err) -> { +// if (err != null) { +// Iris.logger.error("Error selecting file to export shader settings", err); +// +// return; +// } +// +// path.ifPresent(p -> { +// Properties toSave = new Properties(); +// +// // Dirty way of getting the currently applied settings as a Properties, directly +// // opens and copies out of the saved settings file if it is present +// Path sourceTxtPath = Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"); +// if (Files.exists(sourceTxtPath)) { +// try (InputStream in = Files.newInputStream(sourceTxtPath)) { +// toSave.load(in); +// } catch (IOException ignored) {} +// } +// +// // Save properties to user determined file +// try (OutputStream out = Files.newOutputStream(p)) { +// toSave.store(out, null); +// } catch (IOException e) { +// Iris.logger.error("Error saving properties to \"" + p + "\"", e); +// } +// }); +// }); +// +// return true; +// } +// } +// +// public static class ElementRowEntry extends BaseEntry { +// private final List> widgets; +// private final ShaderPackScreen screen; +// +// private int cachedWidth; +// private int cachedPosX; +// +// public ElementRowEntry(ShaderPackScreen screen, NavigationController navigation, List> widgets) { +// super(navigation); +// +// this.screen = screen; +// this.widgets = widgets; +// } +// +// @Override +// public void drawScreen(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { +// this.cachedWidth = entryWidth; +// this.cachedPosX = x; +// +// // The amount of space widgets will occupy, excluding margins. Will be divided up between widgets. +// int totalWidthWithoutMargins = entryWidth - (2 * (widgets.size() - 1)); +// +// totalWidthWithoutMargins -= 3; // Centers it for some reason +// +// // Width of a single widget +// float singleWidgetWidth = (float) totalWidthWithoutMargins / widgets.size(); +// +// for (int i = 0; i < widgets.size(); i++) { +// AbstractElementWidget widget = widgets.get(i); +// boolean widgetHovered = hovered && (getHoveredWidget(mouseX) == i); +// widget.drawScreen(x + (int)((singleWidgetWidth + 2) * i), y, (int) singleWidgetWidth, entryHeight + 2, mouseX, mouseY, tickDelta, widgetHovered); +// +// screen.setElementHoveredStatus(widget, widgetHovered); +// } +// } +// +// public int getHoveredWidget(int mouseX) { +// float positionAcrossWidget = ((float) Mth.clamp(mouseX - cachedPosX, 0, cachedWidth)) / cachedWidth; +// +// return Mth.clamp((int) Math.floor(widgets.size() * positionAcrossWidget), 0, widgets.size() - 1); +// } +// +// @Override +// public boolean mouseClicked(double mouseX, double mouseY, int button) { +// return this.widgets.get(getHoveredWidget((int) mouseX)).mouseClicked(mouseX, mouseY, button); +// } +// +// @Override +// public boolean mouseReleased(double mouseX, double mouseY, int button) { +// return this.widgets.get(getHoveredWidget((int) mouseX)).mouseReleased(mouseX, mouseY, button); +// } +// } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java new file mode 100644 index 000000000..b81cd83dc --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java @@ -0,0 +1,319 @@ +package net.coderbot.iris.gui.element; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import lombok.Getter; +import lombok.Setter; +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiLabel; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.resources.I18n; + +public class ShaderPackSelectionList extends IrisGuiSlot { + private static final String PACK_LIST_LABEL = I18n.format("pack.iris.list.label"); + + private final ShaderPackScreen screen; +// @Getter +// private final TopButtonRowEntry topButtonRow; + + @Setter + @Getter + private ShaderPackEntry applied = null; + + @Setter + @Getter + private ShaderPackEntry selected = null; + + private final List entries = new ArrayList<>(); + + public ShaderPackSelectionList(ShaderPackScreen screen, Minecraft client, int width, int height, int top, int bottom, int left, int right) { + super(client, width, height, top, bottom, 20); + + this.screen = screen; +// this.topButtonRow = new TopButtonRowEntry(this, Iris.getIrisConfig().areShadersEnabled()); + + refresh(); + } + + public void refresh() { +// this.clearEntries(); + + Collection names; + + try { + names = Iris.getShaderpacksDirectoryManager().enumerate(); + } catch (Throwable e) { + Iris.logger.error("Error reading files while constructing selection UI", e); + + // Not translating this since it's going to be seen very rarely, + // We're just trying to get more information on a seemingly untraceable bug: + // - https://github.com/IrisShaders/Iris/issues/785 + this.addLabelEntries( + "", + "There was an error reading your shaderpacks directory", + "", + "Check your logs for more information.", + "Please file an issue report including a log file.", + "If you are able to identify the file causing this, please include it in your report as well.", + "Note that this might be an issue with folder permissions; ensure those are correct first." + ); + + return; + } + +// this.addEntry(topButtonRow); + + // Only allow the enable/disable shaders button if the user has added a shader pack. Otherwise, the button will be disabled. +// topButtonRow.allowEnableShadersButton = names.size() > 0; + + int index = 0; + + for (String name : names) { + index++; + addPackEntry(index, name); + } + + this.addLabelEntries(PACK_LIST_LABEL); + } + + public void addPackEntry(int index, String name) { + final ShaderPackEntry entry = new ShaderPackEntry(index, this, name); + + Iris.getIrisConfig().getShaderPackName().ifPresent(currentPackName -> { + if (name.equals(currentPackName)) { + setSelected(entry); + setApplied(entry); + } + }); + + this.entries.add(entry); + } + + public void addLabelEntries(String ... lines) { + for (String text : lines) { + this.entries.add(new LabelEntry(text)); + } + } + + public void select(String name) { + for (BaseEntry entry : this.entries) { + if (entry instanceof ShaderPackEntry shaderPackEntry && shaderPackEntry.packName.equals(name)) { + setSelected(shaderPackEntry); + return; + } + } + } + + @Override + protected int getSize() { + return this.entries.size(); + } + + @Override + protected void elementClicked(int index, boolean b, int mouseX, int mouseY) { + if(this.entries.get(index) instanceof ShaderPackEntry shaderPackEntry) { + this.setSelected(shaderPackEntry); + } + } + + @Override + protected boolean isSelected(int idx) { + return this.entries.get(idx).equals(this.selected); + } + + @Override + protected void drawBackground() { + + } + + + + @Override + protected void drawSlot(int index, int x, int y, int i3, Tessellator tessellator, int mouseX, int mouseY) { + final BaseEntry entry = this.entries.get(index); + entry.drawEntry(screen, index, (this.screen.width / 2), y + 1); + + } + + + public static abstract class BaseEntry extends GuiLabel { + protected BaseEntry() {} + + public abstract void drawEntry(ShaderPackScreen screen, int index, int x, int y); + } + + public static class ShaderPackEntry extends BaseEntry { + @Getter + private final String packName; + private final ShaderPackSelectionList list; + private final int index; + + public ShaderPackEntry(int index, ShaderPackSelectionList list, String packName) { + this.packName = packName; + this.list = list; + this.index = index; + } + + public boolean isApplied() { + return list.getApplied() == this; + } + + public boolean isSelected() { + return list.getSelected() == this; + } + + @Override + public void drawEntry(ShaderPackScreen screen, int index, int x, int y) { + final FontRenderer font = screen.getFontRenderer(); + + int color = 0xFFFFFF; + String name = packName; + if (font.getStringWidth(name) > this.list.getListWidth() - 3) { + name = font.trimStringToWidth(name, this.list.getListWidth() - 8) + "..."; + } + if(this.isSelected()) { + name = "§l" + name; + } + if(this.isApplied()) { + color = 0xFFF263; + } + + + + screen.drawCenteredString(name, x, y, color); + } + +// +// @Override +// public boolean mouseClicked(double mouseX, double mouseY, int button) { +// // Only do anything on left-click +// if (button != 0) { +// return false; +// } +// +// boolean didAnything = false; +// +// // UX: If shaders are disabled, then clicking a shader in the list will also +// // enable shaders on apply. Previously, it was not possible to select +// // a pack when shaders were disabled, but this was a source of confusion +// // - people did not realize that they needed to enable shaders before +// // selecting a shader pack. +// if (!list.getTopButtonRow().shadersEnabled) { +// list.getTopButtonRow().setShadersEnabled(true); +// didAnything = true; +// } +// +// if (!this.isSelected()) { +// this.list.select(this.index); +// didAnything = true; +// } +// +// return didAnything; +// } + } + + public static class LabelEntry extends BaseEntry { + private final String label; + + public LabelEntry(String label) { + this.label = label; + } + + @Override + public void drawEntry(ShaderPackScreen screen, int index, int x, int y) { + screen.drawCenteredString(label, x, y, 0xFFFFFF); + } + } + +// public static class TopButtonRowEntry extends BaseEntry { +// private static final Component REFRESH_SHADER_PACKS_LABEL = new TranslatableComponent("options.iris.refreshShaderPacks").withStyle(style -> style.withColor(TextColor.fromRgb(0x99ceff))); +// private static final Component NONE_PRESENT_LABEL = new TranslatableComponent("options.iris.shaders.nonePresent").withStyle(ChatFormatting.GRAY); +// private static final Component SHADERS_DISABLED_LABEL = new TranslatableComponent("options.iris.shaders.disabled"); +// private static final Component SHADERS_ENABLED_LABEL = new TranslatableComponent("options.iris.shaders.enabled"); +// private static final int REFRESH_BUTTON_WIDTH = 18; +// +// private final ShaderPackSelectionList list; +// private final IrisElementRow buttons = new IrisElementRow(); +// private final EnableShadersButtonElement enableDisableButton; +// private final IrisElementRow.Element refreshPacksButton; +// +// public boolean allowEnableShadersButton = true; +// public boolean shadersEnabled; +// +// public TopButtonRowEntry(ShaderPackSelectionList list, boolean shadersEnabled) { +// this.list = list; +// this.shadersEnabled = shadersEnabled; +// this.enableDisableButton = new EnableShadersButtonElement( +// getEnableDisableLabel(), +// button -> { +// if (this.allowEnableShadersButton) { +// setShadersEnabled(!this.shadersEnabled); +// GuiUtil.playButtonClickSound(); +// return true; +// } +// +// return false; +// }); +// this.refreshPacksButton = new IrisElementRow.IconButtonElement( +// GuiUtil.Icon.REFRESH, +// button -> { +// this.list.refresh(); +// +// GuiUtil.playButtonClickSound(); +// return true; +// }); +// this.buttons.add(this.enableDisableButton, 0).add(this.refreshPacksButton, REFRESH_BUTTON_WIDTH); +// } +// +// public void setShadersEnabled(boolean shadersEnabled) { +// this.shadersEnabled = shadersEnabled; +// this.enableDisableButton.text = getEnableDisableLabel(); +// this.list.screen.refreshScreenSwitchButton(); +// } +// +// @Override +// public void render(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { +// this.buttons.setWidth(this.enableDisableButton, (entryWidth - 1) - REFRESH_BUTTON_WIDTH); +// this.enableDisableButton.centerX = x + (int)(entryWidth * 0.5); +// +// this.buttons.render(x - 2, y - 3, 18, mouseX, mouseY, tickDelta, hovered); +// +// if (this.refreshPacksButton.isHovered()) { +// ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> +// GuiUtil.drawTextPanel(Minecraft.getInstance().font, REFRESH_SHADER_PACKS_LABEL, +// (mouseX - 8) - Minecraft.getInstance().font.width(REFRESH_SHADER_PACKS_LABEL), mouseY - 16)); +// } +// } +// +// private Component getEnableDisableLabel() { +// return this.allowEnableShadersButton ? this.shadersEnabled ? SHADERS_ENABLED_LABEL : SHADERS_DISABLED_LABEL : NONE_PRESENT_LABEL; +// } +// +// @Override +// public boolean mouseClicked(double mouseX, double mouseY, int button) { +// return this.buttons.mouseClicked(mouseX, mouseY, button); +// } +// +// // Renders the label at an offset as to not look misaligned with the rest of the menu +// public static class EnableShadersButtonElement extends IrisElementRow.TextButtonElement { +// private int centerX; +// +// public EnableShadersButtonElement(Component text, Function onClick) { +// super(text, onClick); +// } +// +// @Override +// public void renderLabel(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { +// int textX = this.centerX - (int)(this.font.width(this.text) * 0.5); +// int textY = y + (int)((height - 8) * 0.5); +// +// this.font.drawShadow(this.text, textX, textY, 0xFFFFFF); +// } +// } +// } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java b/src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java new file mode 100644 index 000000000..d5f89f066 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/screen/ElementWidgetScreenData.java @@ -0,0 +1,15 @@ +package net.coderbot.iris.gui.element.screen; + + + +public class ElementWidgetScreenData { + public static final ElementWidgetScreenData EMPTY = new ElementWidgetScreenData("", true); + + public final String heading; + public final boolean backButton; + + public ElementWidgetScreenData(String heading, boolean backButton) { + this.heading = heading; + this.backButton = backButton; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java new file mode 100644 index 000000000..b72a3df79 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java @@ -0,0 +1,30 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; + +public abstract class AbstractElementWidget { + protected final T element; + + public static final AbstractElementWidget EMPTY = new AbstractElementWidget(null) { + @Override + public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) {} + }; + + public AbstractElementWidget(T element) { + this.element = element; + } + + public void init(ShaderPackScreen screen, NavigationController navigation) {} + + public abstract void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered); + + public boolean mouseClicked(double mx, double my, int button) { + return false; + } + + public boolean mouseReleased(double mx, double my, int button) { + return false; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java new file mode 100644 index 000000000..2fe9f9235 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java @@ -0,0 +1,179 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public abstract class BaseOptionElementWidget extends CommentedElementWidget { + protected static final String SET_TO_DEFAULT = I18n.format("options.iris.setToDefault"); + protected static final String DIVIDER = ": "; + + protected String unmodifiedLabel; + protected ShaderPackScreen screen; + protected NavigationController navigation; + private String label; + + protected String trimmedLabel; + protected String valueLabel; + + private boolean isLabelTrimmed; + private int maxLabelWidth; + private int valueSectionWidth; + + public BaseOptionElementWidget(T element) { + super(element); + } + + @Override + public void init(ShaderPackScreen screen, NavigationController navigation) { + this.screen = screen; + this.navigation = navigation; + this.valueLabel = null; + this.trimmedLabel = null; + } + + protected final void setLabel(String label) { + this.label = label + DIVIDER; + this.unmodifiedLabel = label; + } + + protected final void updateRenderParams(int width, int minValueSectionWidth) { + // Lazy init of value label + if (this.valueLabel == null) { + this.valueLabel = createValueLabel(); + } + + // Determine the width of the value box + FontRenderer font = Minecraft.getMinecraft().fontRenderer; + this.valueSectionWidth = Math.max(minValueSectionWidth, font.getStringWidth(this.valueLabel) + 8); + + // Determine maximum width of trimmed label + this.maxLabelWidth = (width - 8) - this.valueSectionWidth; + + // Lazy init of trimmed label, and make sure it is only trimmed when necessary + if (this.trimmedLabel == null || font.getStringWidth(this.label) > this.maxLabelWidth != isLabelTrimmed) { + updateLabels(); + } + + // Set whether the label has been trimmed (used when updating label and determining whether to render tooltips) + this.isLabelTrimmed = font.getStringWidth(this.label) > this.maxLabelWidth; + } + + protected final void renderOptionWithValue(int x, int y, int width, int height, boolean hovered, float sliderPosition, int sliderWidth) { + GuiUtil.bindIrisWidgetsTexture(); + + // Draw button background + GuiUtil.drawButton(x, y, width, height, hovered, false); + + // Draw the value box + GuiUtil.drawButton((x + width) - (this.valueSectionWidth + 2), y + 2, this.valueSectionWidth, height - 4, false, true); + + // Draw the preview slider + if (sliderPosition >= 0) { + // Range of x values the slider can occupy + int sliderSpace = (this.valueSectionWidth - 4) - sliderWidth; + + // Position of slider + int sliderPos = ((x + width) - this.valueSectionWidth) + (int)(sliderPosition * sliderSpace); + + GuiUtil.drawButton(sliderPos, y + 4, sliderWidth, height - 8, false, false); + } + + FontRenderer font = Minecraft.getMinecraft().fontRenderer; + + // Draw the label + font.drawStringWithShadow(this.trimmedLabel, x + 6, y + 7, 0xFFFFFF); + // Draw the value label + font.drawStringWithShadow(this.valueLabel, (x + (width - 2)) - (int)(this.valueSectionWidth * 0.5) - (int)(font.getStringWidth(this.valueLabel) * 0.5), y + 7, 0xFFFFFF); + } + + protected final void renderOptionWithValue(int x, int y, int width, int height, boolean hovered) { + this.renderOptionWithValue(x, y, width, height, hovered, -1, 0); + } + + protected final void tryRenderTooltip(int mouseX, int mouseY, boolean hovered) { + if (GuiScreen.isShiftKeyDown()) { + renderTooltip(SET_TO_DEFAULT, mouseX, mouseY, hovered); + } else if (this.isLabelTrimmed && !this.screen.isDisplayingComment()) { + renderTooltip(this.unmodifiedLabel, mouseX, mouseY, hovered); + } + } + + protected final void renderTooltip(String text, int mouseX, int mouseY, boolean hovered) { + if (hovered) { + ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel(Minecraft.getMinecraft().fontRenderer, text, mouseX + 2, mouseY - 16)); + } + } + + protected final void updateLabels() { + this.trimmedLabel = createTrimmedLabel(); + this.valueLabel = createValueLabel(); + } + + protected final String createTrimmedLabel() { + String label = GuiUtil.shortenText(Minecraft.getMinecraft().fontRenderer, this.label, this.maxLabelWidth); + + if (this.isValueModified()) { + label = label + " (*)"; //.withStyle(style -> style.withColor(TextColor.fromRgb(0xffc94a))); + } + + return label; + } + + protected abstract String createValueLabel(); + + public abstract boolean applyNextValue(); + + public abstract boolean applyPreviousValue(); + + public abstract boolean applyOriginalValue(); + + public abstract boolean isValueModified(); + + public abstract @Nullable String getCommentKey(); + + @Override + public Optional getCommentTitle() { + return Optional.of(this.unmodifiedLabel); + } + + @Override + public Optional getCommentBody() { + return Optional.ofNullable(getCommentKey()).map(I18n::format); + } + + @Override + public boolean mouseClicked(double mx, double my, int button) { +// if (button == GLFW.GLFW_MOUSE_BUTTON_1 || button == GLFW.GLFW_MOUSE_BUTTON_2) { +// boolean refresh = false; +// +// if (Screen.hasShiftDown()) { +// refresh = applyOriginalValue(); +// } +// if (!refresh) { +// if (button == GLFW.GLFW_MOUSE_BUTTON_1) { +// refresh = applyNextValue(); +// } else { +// refresh = applyPreviousValue(); +// } +// } +// +// if (refresh) { +// this.navigation.refresh(); +// } +// +// GuiUtil.playButtonClickSound(); +// +// return true; +// } + return super.mouseClicked(mx, my, button); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java new file mode 100644 index 000000000..fa87d7509 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java @@ -0,0 +1,111 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.BooleanOption; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuBooleanOptionElement; +import net.minecraft.client.resources.I18n; + +public class BooleanElementWidget extends BaseOptionElementWidget { + private static final String TEXT_TRUE = I18n.format("label.iris.true"); + private static final String TEXT_FALSE = I18n.format("label.iris.false"); + private static final String TEXT_TRUE_DEFAULT = I18n.format("label.iris.true"); + private static final String TEXT_FALSE_DEFAULT = I18n.format("label.iris.false"); + + private final BooleanOption option; + + private boolean appliedValue; + private boolean value; + private boolean defaultValue; + + public BooleanElementWidget(OptionMenuBooleanOptionElement element) { + super(element); + + this.option = element.option; + } + + @Override + public void init(ShaderPackScreen screen, NavigationController navigation) { + super.init(screen, navigation); + + // The value currently in use by the shader pack + this.appliedValue = this.element.getAppliedOptionValues().getBooleanValueOrDefault(this.option.getName()); + + // The yet-to-be-applied value that has been queued (if that is the case) + // Might be equal to the applied value + this.value = this.element.getPendingOptionValues().getBooleanValueOrDefault(this.option.getName()); + + this.defaultValue = this.element.getAppliedOptionValues().getOptionSet().getBooleanOptions() + .get(this.option.getName()).getOption().getDefaultValue(); + + this.setLabel(GuiUtil.translateOrDefault(this.option.getName(), "option." + this.option.getName())); + } + + @Override + public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + this.updateRenderParams(width, 28); + + this.renderOptionWithValue(x, y, width, height, hovered); + this.tryRenderTooltip(mouseX, mouseY, hovered); + } + + @Override + protected String createValueLabel() { + // UX: Do not use color if the value is set to default. + // + // This is because the red color for "Off" and green color of "On" + // was causing people to want to change options to On when that was + // unnecessary due to red having a bad association. + // + // This was changed on request of Emin, since people kept on changing + // Compatibility Mode to "On" when not needed. Now we use white for + // default to avoid giving a positive or negative connotation to a + // default value. + if (this.value == this.defaultValue) { + return this.value ? TEXT_TRUE_DEFAULT : TEXT_FALSE_DEFAULT; + } + + return this.value ? TEXT_TRUE : TEXT_FALSE; + } + + @Override + public String getCommentKey() { + return "option." + this.option.getName() + ".comment"; + } + + public String getValue() { + return Boolean.toString(this.value); + } + + private void queue() { + Iris.getShaderPackOptionQueue().put(this.option.getName(), this.getValue()); + } + + @Override + public boolean applyNextValue() { + this.value = !this.value; + this.queue(); + + return true; + } + + @Override + public boolean applyPreviousValue() { + return this.applyNextValue(); + } + + @Override + public boolean applyOriginalValue() { + this.value = this.option.getDefaultValue(); + this.queue(); + + return true; + } + + @Override + public boolean isValueModified() { + return this.value != this.appliedValue; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java new file mode 100644 index 000000000..ab623b516 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/CommentedElementWidget.java @@ -0,0 +1,15 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; + +import java.util.Optional; + +public abstract class CommentedElementWidget extends AbstractElementWidget { + public CommentedElementWidget(T element) { + super(element); + } + + public abstract Optional getCommentTitle(); + + public abstract Optional getCommentBody(); +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/IrisButton.java b/src/main/java/net/coderbot/iris/gui/element/widget/IrisButton.java new file mode 100644 index 000000000..05c65ba7c --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/IrisButton.java @@ -0,0 +1,22 @@ +package net.coderbot.iris.gui.element.widget; + +import net.minecraft.client.gui.GuiButton; + +import java.util.function.Consumer; +import java.util.function.Function; + +public class IrisButton extends GuiButton { + protected final Consumer onPress; + + public IrisButton(int x, int y, int width, int height, String displayString, Consumer onPress) { + super(999, x, y, width, height, displayString); + this.onPress = onPress; + + } + + public void onPress() { + this.onPress.accept(this); + } + + +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java new file mode 100644 index 000000000..5b054473e --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java @@ -0,0 +1,85 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuLinkElement; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.resources.I18n; + +import java.util.Optional; + +public class LinkElementWidget extends CommentedElementWidget { + private static final String ARROW = new String(">"); + + private final String targetScreenId; + private final String label; + + private NavigationController navigation; + private String trimmedLabel = null; + private boolean isLabelTrimmed = false; + + public LinkElementWidget(OptionMenuLinkElement element) { + super(element); + + this.targetScreenId = element.targetScreenId; + this.label = GuiUtil.translateOrDefault(new String(element.targetScreenId), "screen." + element.targetScreenId); + } + + @Override + public void init(ShaderPackScreen screen, NavigationController navigation) { + this.navigation = navigation; + } + + @Override + public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + GuiUtil.bindIrisWidgetsTexture(); + GuiUtil.drawButton(x, y, width, height, hovered, false); + + final FontRenderer font = Minecraft.getMinecraft().fontRenderer; + + final int maxLabelWidth = width - 9; + + if (font.getStringWidth(this.label) > maxLabelWidth) { + this.isLabelTrimmed = true; + } + + if (this.trimmedLabel == null) { + this.trimmedLabel = GuiUtil.shortenText(font, this.label, maxLabelWidth); + } + + int labelWidth = font.getStringWidth(this.trimmedLabel); + + font.drawStringWithShadow(this.trimmedLabel, x + (int)(width * 0.5) - (int)(labelWidth * 0.5) - (int)(0.5 * Math.max(labelWidth - (width - 18), 0)), y + 7, 0xFFFFFF); + font.drawString(ARROW, (x + width) - 9, y + 7, 0xFFFFFF); + + if (hovered && this.isLabelTrimmed) { + // To prevent other elements from being drawn on top of the tooltip + ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel(font, this.label, mouseX + 2, mouseY - 16)); + } + } + + @Override + public boolean mouseClicked(double mx, double my, int button) { + if (button == 0) { + this.navigation.open(targetScreenId); + GuiUtil.playButtonClickSound(); + + return true; + } + return super.mouseClicked(mx, my, button); + } + + @Override + public Optional getCommentTitle() { + return Optional.of(this.label); + } + + @Override + public Optional getCommentBody() { + final String translation = "screen." + this.targetScreenId + ".comment"; + final String translated = I18n.format(translation); + return Optional.ofNullable(!translated.equals(translation) ? I18n.format(translation) : null); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/OnPress.java b/src/main/java/net/coderbot/iris/gui/element/widget/OnPress.java new file mode 100644 index 000000000..8feca2ef0 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/OnPress.java @@ -0,0 +1,6 @@ +package net.coderbot.iris.gui.element.widget; + +public interface OnPress { + void onPress(IrisButton button); +} + diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java b/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java new file mode 100644 index 000000000..ad83db59f --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java @@ -0,0 +1,87 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.element.ShaderPackOptionList; +import net.coderbot.iris.gui.element.screen.ElementWidgetScreenData; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuBooleanOptionElement; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuElement; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuElementScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuLinkElement; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuMainElementScreen; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuProfileElement; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuStringOptionElement; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuSubElementScreen; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public final class OptionMenuConstructor { + private static final Map, WidgetProvider> WIDGET_CREATORS = new HashMap<>(); + private static final Map, ScreenDataProvider> SCREEN_DATA_CREATORS = new HashMap<>(); + + private OptionMenuConstructor() {} + + @SuppressWarnings("unchecked") + public static void registerWidget(Class element, WidgetProvider widget) { + WIDGET_CREATORS.put(element, (WidgetProvider) widget); + } + + @SuppressWarnings("unchecked") + public static void registerScreen(Class screen, ScreenDataProvider data) { + SCREEN_DATA_CREATORS.put(screen, (ScreenDataProvider) data); + } + + public static AbstractElementWidget createWidget(OptionMenuElement element) { + return WIDGET_CREATORS.getOrDefault(element.getClass(), e -> AbstractElementWidget.EMPTY).create(element); + } + + public static ElementWidgetScreenData createScreenData(OptionMenuElementScreen screen) { + return SCREEN_DATA_CREATORS.getOrDefault(screen.getClass(), s -> ElementWidgetScreenData.EMPTY).create(screen); + } + + @SuppressWarnings("unchecked") + public static void constructAndApplyToScreen(OptionMenuContainer container, ShaderPackScreen packScreen, ShaderPackOptionList optionList, NavigationController navigation) { + OptionMenuElementScreen screen = container.mainScreen; + + if (navigation.getCurrentScreen() != null && container.subScreens.containsKey(navigation.getCurrentScreen())) { + screen = container.subScreens.get(navigation.getCurrentScreen()); + } + + ElementWidgetScreenData data = createScreenData(screen); + +// optionList.addHeader(data.heading, data.backButton); +// optionList.addWidgets(screen.getColumnCount(), screen.elements.stream().map(element -> { +// AbstractElementWidget widget = (AbstractElementWidget) createWidget(element); +// widget.init(packScreen, navigation); +// return widget; +// }).collect(Collectors.toList())); + } + + static { + registerScreen(OptionMenuMainElementScreen.class, screen -> + new ElementWidgetScreenData(Iris.getCurrentPackName() + (Iris.isFallback() ? " (fallback)" : ""), false)); + + registerScreen(OptionMenuSubElementScreen.class, screen -> + new ElementWidgetScreenData(GuiUtil.translateOrDefault(new String(screen.screenId), "screen." + screen.screenId), true)); + + registerWidget(OptionMenuBooleanOptionElement.class, BooleanElementWidget::new); + registerWidget(OptionMenuProfileElement.class, ProfileElementWidget::new); + registerWidget(OptionMenuLinkElement.class, LinkElementWidget::new); + + registerWidget(OptionMenuStringOptionElement.class, element -> + element.slider ? new SliderElementWidget(element) : new StringElementWidget(element)); + } + + public interface WidgetProvider { + AbstractElementWidget create(T element); + } + + public interface ScreenDataProvider { + ElementWidgetScreenData create(T screen); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java new file mode 100644 index 000000000..0b2d54e30 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java @@ -0,0 +1,100 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.OptionSet; +import net.coderbot.iris.shaderpack.option.Profile; +import net.coderbot.iris.shaderpack.option.ProfileSet; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuProfileElement; +import net.coderbot.iris.shaderpack.option.values.OptionValues; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; + +import java.util.Optional; + +public class ProfileElementWidget extends BaseOptionElementWidget { + private static final String PROFILE_LABEL = I18n.format("options.iris.profile"); + private static final String PROFILE_CUSTOM = I18n.format("options.iris.profile.custom"); + + private Profile next; + private Profile previous; + private String profileLabel; + + public ProfileElementWidget(OptionMenuProfileElement element) { + super(element); + } + + @Override + public void init(ShaderPackScreen screen, NavigationController navigation) { + super.init(screen, navigation); + this.setLabel(PROFILE_LABEL); + + final ProfileSet profiles = this.element.profiles; + final OptionSet options = this.element.options; + final OptionValues pendingValues = this.element.getPendingOptionValues(); + + final ProfileSet.ProfileResult result = profiles.scan(options, pendingValues); + + this.next = result.next; + this.previous = result.previous; + final Optional profileName = result.current.map(p -> p.name); + + this.profileLabel = profileName.map(name -> GuiUtil.translateOrDefault(name, "profile." + name)).orElse(PROFILE_CUSTOM); + } + + @Override + public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + this.updateRenderParams(width, width - (Minecraft.getMinecraft().fontRenderer.getStringWidth(PROFILE_LABEL) + 16)); + + this.renderOptionWithValue(x, y, width, height, hovered); + } + + @Override + protected String createValueLabel() { + return this.profileLabel; + } + + @Override + public Optional getCommentTitle() { + return Optional.of(PROFILE_LABEL); + } + + @Override + public String getCommentKey() { + return "profile.comment"; + } + + @Override + public boolean applyNextValue() { + if (this.next == null) { + return false; + } + + Iris.queueShaderPackOptionsFromProfile(this.next); + + return true; + } + + @Override + public boolean applyPreviousValue() { + if (this.previous == null) { + return false; + } + + Iris.queueShaderPackOptionsFromProfile(this.previous); + + return true; + } + + @Override + public boolean applyOriginalValue() { + return false; // Resetting options is the way to return to the "default profile" + } + + @Override + public boolean isValueModified() { + return false; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java new file mode 100644 index 000000000..9bb43b96a --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java @@ -0,0 +1,118 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuStringOptionElement; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.util.MathHelper; + +public class SliderElementWidget extends StringElementWidget { + private static final int PREVIEW_SLIDER_WIDTH = 4; + private static final int ACTIVE_SLIDER_WIDTH = 6; + + private boolean mouseDown = false; + + public SliderElementWidget(OptionMenuStringOptionElement element) { + super(element); + } + + @Override + public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + this.updateRenderParams(width, 35); + + if (!hovered) { + this.renderOptionWithValue(x, y, width, height, false, (float)valueIndex / (valueCount - 1), PREVIEW_SLIDER_WIDTH); + } else { + this.renderSlider(x, y, width, height, mouseX, mouseY, tickDelta); + } + + if (GuiScreen.isShiftKeyDown()) { + renderTooltip(SET_TO_DEFAULT, mouseX, mouseY, hovered); + } else if (!this.screen.isDisplayingComment()) { + renderTooltip(this.unmodifiedLabel, mouseX, mouseY, hovered); + } + + if (this.mouseDown) { + // Release if the mouse went off the slider + if (!hovered) { + this.onReleased(); + } + + whileDragging(x, width, mouseX); + } + } + + private void renderSlider(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta) { + GuiUtil.bindIrisWidgetsTexture(); + + // Draw background button + GuiUtil.drawButton(x, y, width, height, false, false); + // Draw slider area + GuiUtil.drawButton(x + 2, y + 2, width - 4, height - 4, false, true); + + // Range of x values the slider can occupy + final int sliderSpace = (width - 8) - ACTIVE_SLIDER_WIDTH; + // Position of slider + final int sliderPos = (x + 4) + (int)(((float)valueIndex / (valueCount - 1)) * sliderSpace); + // Draw slider + GuiUtil.drawButton(sliderPos, y + 4, ACTIVE_SLIDER_WIDTH, height - 8, this.mouseDown, false); + + // Draw value label + final FontRenderer font = Minecraft.getMinecraft().fontRenderer; + font.drawStringWithShadow(this.valueLabel, (int)(x + (width * 0.5)) - (int)(font.getStringWidth(this.valueLabel) * 0.5), y + 7, 0xFFFFFF); + } + + private void whileDragging(int x, int width, int mouseX) { + final float mousePositionAcrossWidget = MathHelper.clamp_float((float)(mouseX - (x + 4)) / (width - 8), 0, 1); + + final int newValueIndex = Math.min(valueCount - 1, (int)(mousePositionAcrossWidget * valueCount)); + + if (valueIndex != newValueIndex) { + this.valueIndex = newValueIndex; + + this.updateLabels(); + } + } + + private void onReleased() { + mouseDown = false; + + this.queue(); + this.navigation.refresh(); + + GuiUtil.playButtonClickSound(); + } + + @Override + public boolean mouseClicked(double mx, double my, int button) { + if (button == 0) { + if (GuiScreen.isShiftKeyDown()) { + if (this.applyOriginalValue()) { + this.navigation.refresh(); + } + GuiUtil.playButtonClickSound(); + + return true; + } + + mouseDown = true; + GuiUtil.playButtonClickSound(); + + return true; + } + + // Do not use base widget's button click behavior + return false; + } + + @Override + public boolean mouseReleased(double mx, double my, int button) { + if (button == 0) { + this.onReleased(); + + return true; + } + return super.mouseReleased(mx, my, button); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java new file mode 100644 index 000000000..5dc5ca2a4 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java @@ -0,0 +1,107 @@ +package net.coderbot.iris.gui.element.widget; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.coderbot.iris.shaderpack.option.StringOption; +import net.coderbot.iris.shaderpack.option.menu.OptionMenuStringOptionElement; + +import java.util.List; + +public class StringElementWidget extends BaseOptionElementWidget { + protected final StringOption option; + + protected String appliedValue; + protected int valueCount; + protected int valueIndex; + + public StringElementWidget(OptionMenuStringOptionElement element) { + super(element); + + this.option = element.option; + } + + @Override + public void init(ShaderPackScreen screen, NavigationController navigation) { + super.init(screen, navigation); + + // The yet-to-be-applied value that has been queued (if that is the case) + // Might be equal to the applied value + final String actualPendingValue = this.element.getPendingOptionValues().getStringValueOrDefault(this.option.getName()); + + // The value currently in use by the shader pack + this.appliedValue = this.element.getAppliedOptionValues().getStringValueOrDefault(this.option.getName()); + + this.setLabel(GuiUtil.translateOrDefault(this.option.getName(), "option." + this.option.getName())); + + List values = this.option.getAllowedValues(); + + this.valueCount = values.size(); + this.valueIndex = values.indexOf(actualPendingValue); + } + + @Override + public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + this.updateRenderParams(width, 0); + + this.renderOptionWithValue(x, y, width, height, hovered); + this.tryRenderTooltip(mouseX, mouseY, hovered); + } + + private void increment(int amount) { + this.valueIndex = Math.max(this.valueIndex, 0); + + this.valueIndex = Math.floorMod(this.valueIndex + amount, this.valueCount); + } + + @Override + protected String createValueLabel() { + return GuiUtil.translateOrDefault(getValue(), "value." + this.option.getName() + "." + getValue()); + } + + @Override + public String getCommentKey() { + return "option." + this.option.getName() + ".comment"; + } + + public String getValue() { + if (this.valueIndex < 0) { + return this.appliedValue; + } + return this.option.getAllowedValues().get(this.valueIndex); + } + + protected void queue() { + Iris.getShaderPackOptionQueue().put(this.option.getName(), this.getValue()); + } + + @Override + public boolean applyNextValue() { + this.increment(1); + this.queue(); + + return true; + } + + @Override + public boolean applyPreviousValue() { + this.increment(-1); + this.queue(); + + return true; + } + + @Override + public boolean applyOriginalValue() { + this.valueIndex = this.option.getAllowedValues().indexOf(this.option.getDefaultValue()); + this.queue(); + + return true; + } + + @Override + public boolean isValueModified() { + return !this.appliedValue.equals(this.getValue()); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java b/src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java new file mode 100644 index 000000000..8337106fc --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/option/IrisVideoSettings.java @@ -0,0 +1,29 @@ +package net.coderbot.iris.gui.option; + +import java.io.IOException; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; + +public class IrisVideoSettings { + public static int shadowDistance = 32; + + // TODO: Tell the user to check in the shader options once that's supported. + private static final String DISABLED_TOOLTIP = I18n.format("options.iris.shadowDistance.disabled"); + private static final String ENABLED_TOOLTIP = I18n.format("options.iris.shadowDistance.enabled"); + + public static int getOverriddenShadowDistance(int base) { + return Iris.getPipelineManager().getPipeline() + .map(pipeline -> pipeline.getForcedShadowRenderDistanceChunksForDisplay().orElse(base)) + .orElse(base); + } + + public static boolean isShadowDistanceSliderEnabled() { + return Iris.getPipelineManager().getPipeline() + .map(pipeline -> !pipeline.getForcedShadowRenderDistanceChunksForDisplay().isPresent()) + .orElse(true); + } + +} diff --git a/src/main/java/net/coderbot/iris/gui/screen/HudHideable.java b/src/main/java/net/coderbot/iris/gui/screen/HudHideable.java new file mode 100644 index 000000000..71a88e4e2 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/screen/HudHideable.java @@ -0,0 +1,9 @@ +package net.coderbot.iris.gui.screen; + +/** + * Screens implementing this will hide the player hand and HUD + * + * Only used for instanceof checks + */ +public interface HudHideable { +} diff --git a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java new file mode 100644 index 000000000..3d54532b7 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java @@ -0,0 +1,519 @@ +package net.coderbot.iris.gui.screen; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +import com.gtnewhorizons.angelica.client.Shaders; +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.element.ShaderPackOptionList; +import net.coderbot.iris.gui.element.widget.AbstractElementWidget; +import net.coderbot.iris.gui.element.widget.CommentedElementWidget; +import net.coderbot.iris.gui.element.ShaderPackSelectionList; +import net.coderbot.iris.gui.element.widget.IrisButton; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import org.jetbrains.annotations.Nullable; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.ShaderPack; +import net.irisshaders.iris.api.v0.IrisApi; +import org.lwjgl.Sys; +import org.lwjgl.input.Keyboard; + +public class ShaderPackScreen extends GuiScreen implements HudHideable { + /** + * Queue rendering to happen on top of all elements. Useful for tooltips or dialogs. + */ + public static final Set TOP_LAYER_RENDER_QUEUE = new HashSet<>(); + + private static final String SELECT_TITLE = I18n.format("pack.iris.select.title"); + private static final String CONFIGURE_TITLE = I18n.format("pack.iris.configure.title"); + private static final int COMMENT_PANEL_WIDTH = 314; + + private final GuiScreen parent; + private final String title; + + private final String irisTextComponent; + + private ShaderPackSelectionList shaderPackList; + + private @Nullable ShaderPackOptionList shaderOptionList = null; + private @Nullable NavigationController navigation = null; + private GuiButton screenSwitchButton; + + private String notificationDialog = null; + private int notificationDialogTimer = 0; + + private @Nullable AbstractElementWidget hoveredElement = null; + private Optional hoveredElementCommentTitle = Optional.empty(); + private List hoveredElementCommentBody = new ArrayList<>(); + private int hoveredElementCommentTimer = 0; + + private boolean optionMenuOpen = false; + + private boolean dropChanges = false; + private static final String development = "Development Environment"; + private String developmentComponent; + private String updateComponent; + + private boolean guiHidden = false; + private float guiButtonHoverTimer = 0.0f; + + public ShaderPackScreen(GuiScreen parent) { + this.title = I18n.format("options.iris.shaderPackSelection.title"); + + this.parent = parent; + + String irisName = Iris.MODNAME; // + " " + Iris.getVersion(); // TEMP + + if (Iris.INSTANCE.isDevelopmentEnvironment) { + this.developmentComponent = "Development Environment"; + irisName = irisName.replace("-development-environment", ""); + } + + this.irisTextComponent = irisName; + + refreshForChangedPack(); + } + @Override + public void drawScreen(int mouseX, int mouseY, float delta) { + + if (this.mc.theWorld == null) { + super.drawDefaultBackground(); +// this.renderBackground(poseStack); + } else if (!this.guiHidden) { + this.drawGradientRect(0, 0, width, height, 0x4F232323, 0x4F232323); + } + + if (!this.guiHidden) { + if (optionMenuOpen && this.shaderOptionList != null) { + this.shaderOptionList.drawScreen(mouseX, mouseY, delta); + } else { + this.shaderPackList.drawScreen(mouseX, mouseY, delta); + } + } + + final float previousHoverTimer = this.guiButtonHoverTimer; + super.drawScreen(mouseX, mouseY, delta); + if (previousHoverTimer == this.guiButtonHoverTimer) { + this.guiButtonHoverTimer = 0.0f; + } + + if (!this.guiHidden) { + drawCenteredString(this.fontRendererObj, this.title, (int) (this.width * 0.5), 8, 0xFFFFFF); + + if (notificationDialog != null && notificationDialogTimer > 0) { + drawCenteredString(this.fontRendererObj, notificationDialog, (int) (this.width * 0.5), 21, 0xFFFFFF); + } else { + if (optionMenuOpen) { + drawCenteredString(this.fontRendererObj, CONFIGURE_TITLE, (int) (this.width * 0.5), 21, 0xFFFFFF); + } else { + drawCenteredString(this.fontRendererObj, SELECT_TITLE, (int) (this.width * 0.5), 21, 0xFFFFFF); + } + } + + // Draw the comment panel + if (this.isDisplayingComment()) { + // Determine panel height and position + int panelHeight = Math.max(50, 18 + (this.hoveredElementCommentBody.size() * 10)); + int x = (int) (0.5 * this.width) - 157; + int y = this.height - (panelHeight + 4); + // Draw panel + GuiUtil.drawPanel(x, y, COMMENT_PANEL_WIDTH, panelHeight); + // Draw text + this.fontRendererObj.drawStringWithShadow(this.hoveredElementCommentTitle.orElse(""), x + 4, y + 4, 0xFFFFFF); + for (int i = 0; i < this.hoveredElementCommentBody.size(); i++) { + this.fontRendererObj.drawStringWithShadow(this.hoveredElementCommentBody.get(i), x + 4, (y + 16) + (i * 10), 0xFFFFFF); + } + } + } + + // Render everything queued to render last + for (Runnable render : TOP_LAYER_RENDER_QUEUE) { + render.run(); + } + TOP_LAYER_RENDER_QUEUE.clear(); + + if (this.developmentComponent != null) { + this.fontRendererObj.drawStringWithShadow(developmentComponent, 2, this.height - 10, 0xFFFFFF); + this.fontRendererObj.drawStringWithShadow(irisTextComponent, 2, this.height - 20, 0xFFFFFF); + } else if (this.updateComponent != null) { + this.fontRendererObj.drawStringWithShadow(updateComponent, 2, this.height - 10, 0xFFFFFF); + this.fontRendererObj.drawStringWithShadow(irisTextComponent, 2, this.height - 20, 0xFFFFFF); + } else { + this.fontRendererObj.drawStringWithShadow(irisTextComponent, 2, this.height - 10, 0xFFFFFF); + } + } + + @Override + public void initGui() { + super.initGui(); + final int bottomCenter = this.width / 2 - 50; + final int topCenter = this.width / 2 - 76; + final boolean inWorld = this.mc.theWorld != null; + +// this.children.remove(this.shaderPackList); +// this.children.remove(this.shaderOptionList); + + this.shaderPackList = new ShaderPackSelectionList(this, this.mc, this.width, this.height, 32, this.height - 58, 0, this.width); + + if (Iris.getCurrentPack().isPresent() && this.navigation != null) { + ShaderPack currentPack = Iris.getCurrentPack().get(); + + this.shaderOptionList = new ShaderPackOptionList(this, this.navigation, currentPack, this.mc, this.width, this.height, 32, this.height - 58, 0, this.width); + this.navigation.setActiveOptionList(this.shaderOptionList); + + this.shaderOptionList.rebuild(); + } else { + optionMenuOpen = false; + this.shaderOptionList = null; + } + + if (inWorld) { + this.shaderPackList.setRenderBackground(false); + if (shaderOptionList != null) { + this.shaderOptionList.setRenderBackground(false); + } + } + + this.buttonList.clear(); +// this.children.clear(); + + if (!this.guiHidden) { +// if (optionMenuOpen && shaderOptionList != null) { +// this.children.add(shaderOptionList); +// } else { +// this.children.add(shaderPackList); +// } + + this.buttonList.add(new IrisButton(bottomCenter + 104, this.height - 27, 100, 20, + I18n.format("gui.done"), button -> this.onClose())); + + this.buttonList.add(new IrisButton(bottomCenter, this.height - 27, 100, 20, + I18n.format("options.iris.apply"), button -> this.applyChanges())); + + this.buttonList.add(new IrisButton(bottomCenter - 104, this.height - 27, 100, 20, + I18n.format("gui.cancel"), button -> this.dropChangesAndClose())); + + this.buttonList.add(new IrisButton(topCenter - 78, this.height - 51, 152, 20, + I18n.format("options.iris.openShaderPackFolder"), button -> this.openShaderPackFolder())); + + this.screenSwitchButton = new IrisButton(topCenter + 78, this.height - 51, 152, 20, + I18n.format("options.iris.shaderPackList"), button -> { + this.optionMenuOpen = !this.optionMenuOpen; + + // UX: Apply changes before switching screens to avoid unintuitive behavior + // + // Not doing this leads to unintuitive behavior, since selecting a pack in the + // list (but not applying) would open the settings for the previous pack, rather + // than opening the settings for the selected (but not applied) pack. + this.applyChanges(); + + initGui(); + } + ); + this.buttonList.add(this.screenSwitchButton); + + refreshScreenSwitchButton(); + } + + if (inWorld) { + final String showOrHide = this.guiHidden + ? I18n.format("options.iris.gui.show") + : I18n.format("options.iris.gui.hide"); + + final float endOfLastButton = this.width / 2.0f + 154.0f; + final float freeSpace = this.width - endOfLastButton; + final int x; + if (freeSpace > 100.0f) { + x = this.width - 50; + } else if (freeSpace < 20.0f) { + x = this.width - 20; + } else { + x = (int) (endOfLastButton + (freeSpace / 2.0f)) - 10; + } + + this.buttonList.add(new IrisButton( + x, this.height - 39, + 20, 20, +// this.guiHidden ? 20 : 0, 146, 20, +// GuiUtil.IRIS_WIDGETS_TEX, +// 256, 256, + showOrHide, + button -> { + this.guiHidden = !this.guiHidden; + this.initGui(); + } +// , +// (button, i, j) -> { +// this.guiButtonHoverTimer += this.mc.getDeltaFrameTime(); +// if (this.guiButtonHoverTimer >= 10.0f) { +// TOP_LAYER_RENDER_QUEUE.add(() -> this.renderTooltip(showOrHide, i, j)); +// } +// }, +// showOrHide + )); + } + + // NB: Don't let comment remain when exiting options screen + // https://github.com/IrisShaders/Iris/issues/1494 + this.hoveredElement = null; + this.hoveredElementCommentTimer = 0; + } + + @Override + protected void actionPerformed(GuiButton guiButton) { + if(guiButton.enabled) { + if(guiButton instanceof IrisButton irisButton) { + irisButton.onPress(); + } + } + } + + public void refreshForChangedPack() { + if (Iris.getCurrentPack().isPresent()) { + final ShaderPack currentPack = Iris.getCurrentPack().get(); + + this.navigation = new NavigationController(currentPack.getMenuContainer()); + + if (this.shaderOptionList != null) { + this.shaderOptionList.applyShaderPack(currentPack); + this.shaderOptionList.rebuild(); + } + } else { + this.navigation = null; + } + + refreshScreenSwitchButton(); + } + + public void refreshScreenSwitchButton() { + if (this.screenSwitchButton != null) { + this.screenSwitchButton.displayString = optionMenuOpen ? I18n.format("options.iris.shaderPackList") : I18n.format("options.iris.shaderPackSettings"); + this.screenSwitchButton.enabled = optionMenuOpen; // || shaderPackList.getTopButtonRow().shadersEnabled; + } + } + + @Override + protected void keyTyped(char typedChar, int keyCode) { + if (keyCode == Keyboard.KEY_ESCAPE) { + if (this.guiHidden) { + this.guiHidden = false; + this.initGui(); + } else if (this.navigation != null && this.navigation.hasHistory()) { + this.navigation.back(); + } else if (this.optionMenuOpen) { + this.optionMenuOpen = false; + this.initGui(); + } + } + } + + public void displayNotification(String String) { + this.notificationDialog = String; + this.notificationDialogTimer = 100; + } + + public void importPackOptions(Path settingFile) { + try (InputStream in = Files.newInputStream(settingFile)) { + final Properties properties = new Properties(); + properties.load(in); + + Iris.queueShaderPackOptionsFromProperties(properties); + + this.notificationDialog = I18n.format( + "options.iris.shaderPackOptions.importedSettings", + settingFile.getFileName().toString() + ); + this.notificationDialogTimer = 100; // 5 seconds (100 ticks) + + if (this.navigation != null) { + this.navigation.refresh(); + } + } catch (Exception e) { + // If the file could not be properly parsed or loaded, + // log the error and display a message to the user + Iris.logger.error("Error importing shader settings file \""+ settingFile.toString() +"\"", e); + + this.notificationDialog = I18n.format( + "options.iris.shaderPackOptions.failedImport", + settingFile.getFileName().toString() + ); + this.notificationDialogTimer = 100; // 5 seconds (100 ticks) + } + } + + public void onClose() { + if (!dropChanges) { + applyChanges(); + } else { + discardChanges(); + } + + this.mc.displayGuiScreen(parent); + } + + private void dropChangesAndClose() { + dropChanges = true; + onClose(); + } + + public void applyChanges() { + ShaderPackSelectionList.BaseEntry base = this.shaderPackList.getSelected(); + + if (!(base instanceof ShaderPackSelectionList.ShaderPackEntry)) { + return; + } + + ShaderPackSelectionList.ShaderPackEntry entry = (ShaderPackSelectionList.ShaderPackEntry)base; + this.shaderPackList.setApplied(entry); + + String name = entry.getPackName(); + + // If the pack is being changed, clear pending options from the previous pack to + // avoid possible undefined behavior from applying one pack's options to another pack + if (!name.equals(Iris.getCurrentPackName())) { + Iris.clearShaderPackOptionQueue(); + } + + boolean enabled = true; //this.shaderPackList.getTopButtonRow().shadersEnabled; + + String previousPackName = Iris.getIrisConfig().getShaderPackName().orElse(null); + boolean previousShadersEnabled = Iris.getIrisConfig().areShadersEnabled(); + + // Only reload if the pack would be different from before, or shaders were toggled, or options were changed, or if we're about to reset options. + if (!name.equals(previousPackName) || enabled != previousShadersEnabled || !Iris.getShaderPackOptionQueue().isEmpty() || Iris.shouldResetShaderPackOptionsOnNextReload()) { + Iris.getIrisConfig().setShaderPackName(name); + IrisApi.getInstance().getConfig().setShadersEnabledAndApply(enabled); + } + + refreshForChangedPack(); + } + + private void discardChanges() { + Iris.clearShaderPackOptionQueue(); + } + + private void openShaderPackFolder() { + CompletableFuture.runAsync(() -> openUri(Iris.getShaderpacksDirectoryManager().getDirectoryUri())); + } + + private void openUri(URI directoryUri) { + switch (net.minecraft.util.Util.getOSType()) { + case OSX: { + try { + Runtime.getRuntime().exec(new String[] { "/usr/bin/open", directoryUri.toString() }); + return; + } catch (IOException var7) { + var7.printStackTrace(); + } + } + break; + case WINDOWS: { + String var2 = String.format( + "cmd.exe /C start \"Open file\" \"%s\"", + new Object[] { directoryUri.toString() }); + + try { + Runtime.getRuntime().exec(var2); + return; + } catch (IOException var6) { + var6.printStackTrace(); + } + } + break; + default: + break; + } + boolean openViaSystemClass = false; + + try { + final Class aClass = Class.forName("java.awt.Desktop"); + final Object getDesktop = aClass.getMethod("getDesktop").invoke((Object) null); + aClass.getMethod("browse", URI.class).invoke(getDesktop, (new File(this.mc.mcDataDir, Shaders.shaderpacksdirname)).toURI()); + } catch (Throwable var5) { + var5.printStackTrace(); + openViaSystemClass = true; + } + + if (openViaSystemClass) { + AngelicaTweaker.LOGGER.debug("Opening via system class!"); + Sys.openURL("file://" + Shaders.shaderpacksdir.getAbsolutePath()); + } + } + + // Let the screen know if an element is hovered or not, allowing for accurately updating which element is hovered + public void setElementHoveredStatus(AbstractElementWidget widget, boolean hovered) { + if (hovered && widget != this.hoveredElement) { + this.hoveredElement = widget; + + if (widget instanceof CommentedElementWidget) { + this.hoveredElementCommentTitle = ((CommentedElementWidget) widget).getCommentTitle(); + + Optional commentBody = ((CommentedElementWidget) widget).getCommentBody(); + if (!commentBody.isPresent()) { + this.hoveredElementCommentBody.clear(); + } else { + String rawCommentBody = commentBody.get(); + + // Strip any trailing "."s + if (rawCommentBody.endsWith(".")) { + rawCommentBody = rawCommentBody.substring(0, rawCommentBody.length() - 1); + } + // Split comment body into lines by separator ". " + List splitByPeriods = Arrays.stream(rawCommentBody.split("\\. [ ]*")).map(String::new).collect(Collectors.toList()); + // Line wrap + this.hoveredElementCommentBody = new ArrayList<>(); + for (String text : splitByPeriods) { + this.hoveredElementCommentBody.addAll(this.fontRendererObj.listFormattedStringToWidth(text, COMMENT_PANEL_WIDTH - 8)); + } + } + } else { + this.hoveredElementCommentTitle = Optional.empty(); + this.hoveredElementCommentBody.clear(); + } + + this.hoveredElementCommentTimer = 0; + } else if (!hovered && widget == this.hoveredElement) { + this.hoveredElement = null; + this.hoveredElementCommentTitle = Optional.empty(); + this.hoveredElementCommentBody.clear(); + this.hoveredElementCommentTimer = 0; + } + } + + public boolean isDisplayingComment() { + return this.hoveredElementCommentTimer > 20 && + this.hoveredElementCommentTitle.isPresent() && + !this.hoveredElementCommentBody.isEmpty(); + } + public void drawCenteredString(String text, int x, int y, int color) { + this.drawCenteredString(this.fontRendererObj, text, x, y, color); + } + public void drawString(String text, int x, int y, int color) { + this.drawString(this.fontRendererObj, text, x, y, color); + } + + + public FontRenderer getFontRenderer() { + return this.fontRendererObj; + } +} diff --git a/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java b/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java index e88508713..38c8d4303 100644 --- a/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java +++ b/src/main/java/net/coderbot/iris/samplers/IrisSamplers.java @@ -100,8 +100,7 @@ public static boolean addShadowSamplers(SamplerHolder samplers, ShadowRenderTarg if (waterShadowEnabled) { usesShadows = true; samplers.addDynamicSampler(shadowRenderTargets.getDepthTexture()::getTextureId, "shadowtex0", "watershadow"); - samplers.addDynamicSampler(shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, - "shadowtex1", "shadow"); + samplers.addDynamicSampler(shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, "shadowtex1", "shadow"); } else { usesShadows = samplers.addDynamicSampler(shadowRenderTargets.getDepthTexture()::getTextureId, "shadowtex0", "shadow"); usesShadows |= samplers.addDynamicSampler(shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, "shadowtex1"); @@ -130,8 +129,7 @@ public static void addLevelSamplers(SamplerHolder samplers, WorldRenderingPipeli samplers.addExternalSampler(ALBEDO_TEXTURE_UNIT, "tex", "texture", "gtexture"); } else { // TODO: Rebind unbound sampler IDs instead of hardcoding a list... - samplers.addDynamicSampler(whitePixel::getGlTextureId, "tex", "texture", "gtexture", - "gcolor", "colortex0"); + samplers.addDynamicSampler(whitePixel::getGlTextureId, "tex", "texture", "gtexture", "gcolor", "colortex0"); } if (availability.lightmap) { diff --git a/src/main/resources/assets/angelica/lang/en_US.lang b/src/main/resources/assets/angelica/lang/en_US.lang index d34456d29..6af5f9db9 100644 --- a/src/main/resources/assets/angelica/lang/en_US.lang +++ b/src/main/resources/assets/angelica/lang/en_US.lang @@ -81,8 +81,48 @@ sodium.options.use_no_error_context.name=Use No Error Context sodium.options.use_no_error_context.tooltip=If enabled, the OpenGL context will be created with error checking disabled. This may slightly improve performance, but it also increases the risk that the game will crash instead of gracefully handling OpenGL errors. You should disable this option if you are experiencing sudden unexplained crashes. sodium.options.threads.value=%s thread(s) sodium.options.default=Default -sodium.options.buttons.undo=Undot +sodium.options.buttons.undo=Undo sodium.options.buttons.apply=Apply sodium.options.buttons.donate=Buy coffee for JellySquid! +options.framerate=%s FPS iris.shaders.toggled=Toggled shaders to %s! iris.shaders.disabled=Shaders disabled! +options.iris.apply=Apply +options.iris.refresh=Refresh +options.iris.openShaderPackFolder=Open Shader Pack Folder... +options.iris.shaderPackSettings=Shader Pack Settings... +options.iris.shaderPackList=Shader Pack List... +options.iris.refreshShaderPacks=Refresh Shader Packs +options.iris.shaderPackSelection=Shader Packs... +options.iris.shaderPackSelection.title=Shader Packs +options.iris.shaderPackSelection.addedPack=Added Shader Pack "%s" +options.iris.shaderPackSelection.addedPacks=Added %s Shader Packs +options.iris.shaderPackSelection.failedAdd=Files were not valid Shader Packs +options.iris.shaderPackSelection.failedAddSingle="%s" is not a valid Shader Pack +options.iris.shaderPackSelection.copyError=Could not add Shader Pack "%s" +options.iris.shaderPackSelection.copyErrorAlreadyExists="%s" is already in your Shader Packs folder! +options.iris.shaderPackOptions.tooManyFiles=Cannot import multiple Shader Settings files! +options.iris.shaderPackOptions.failedImport=Failed to import Shader Settings file "%s" +options.iris.shaderPackOptions.importedSettings=Imported Shader Settings from "%s" +options.iris.shaders.disabled=Shaders: Disabled +options.iris.shaders.enabled=Shaders: Enabled +options.iris.shaders.nonePresent=Shaders: No Packs Present +options.iris.back=Back +options.iris.reset=Reset +options.iris.reset.tooltip=Reset ALL options and apply? +options.iris.reset.tooltip.holdShift=Hold SHIFT and click to reset +options.iris.importSettings.tooltip=Import settings from file +options.iris.exportSettings.tooltip=Export applied settings to file +options.iris.mustDisableFullscreen=Please disable fullscreen first! +options.iris.setToDefault=Set option to default value? +options.iris.profile=Profile +options.iris.profile.custom=Custom +options.iris.shadowDistance=Max Shadow Distance +options.iris.shadowDistance.enabled=Allows you to change the maximum distance for shadows. Terrain and entities beyond this distance will not cast shadows. Lowering the shadow distance can significantly increase performance. +options.iris.shadowDistance.disabled=Your current shader pack has already set a render distance for shadows; you cannot change it. +options.iris.gui.hide=Hide GUI +options.iris.gui.show=Show GUI +pack.iris.select.title=Select +pack.iris.configure.title=Configure +label.iris.true=On +label.iris.false=Off From 06f921c5f3d9cd3b0f883ca06e8844c8fdd35661 Mon Sep 17 00:00:00 2001 From: Ryan Nasers <42074409+Cardinalstars@users.noreply.github.com> Date: Wed, 13 Dec 2023 22:30:46 -0600 Subject: [PATCH 261/301] Hud caching angelica (#28) * Potential hud-caching fix * Adding config for testing * adding comments * Removing redundant calls * More comments * Adding some error handling, I really don't know exactly what I should be doing for errors or how to know when to throw one --- .../angelica/config/AngelicaConfig.java | 2 +- .../loading/MixinCompatHackTweaker.java | 3 + .../transform/RenderItemTransformer.java | 219 ++++++++++++++++++ 3 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index a03f87db5..cc7796f20 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -44,7 +44,7 @@ public class AngelicaConfig { @Config.Comment("Renders the HUD elements once per tick and reuses the pixels to improve performance. [Experimental]") - @Config.DefaultBoolean(false) + @Config.DefaultBoolean(true) @Config.RequiresMcRestart // TODO disabled for now as it doesn't render items with an enchantment glint in the hotbar properly as well as doesn't render the vignette public static boolean enableHudCaching; diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java index 933846856..668acc0db 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java @@ -4,6 +4,7 @@ import cpw.mods.fml.common.Loader; import cpw.mods.fml.relauncher.FMLLaunchHandler; import net.minecraft.launchwrapper.IClassTransformer; +import com.gtnewhorizons.angelica.transform.RenderItemTransformer; import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; @@ -73,8 +74,10 @@ public String getLaunchTarget() { public String[] getLaunchArguments() { if (FMLLaunchHandler.side().isClient()) { // Run after Mixins, but before LWJGl3ify + Launch.classLoader.registerTransformer(RenderItemTransformer.class.getName()); Launch.classLoader.registerTransformer(RedirectorTransformer.class.getName()); } + return new String[0]; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java new file mode 100644 index 000000000..de0495474 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java @@ -0,0 +1,219 @@ +package com.gtnewhorizons.angelica.transform; + +import net.minecraft.launchwrapper.IClassTransformer; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; + +import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static org.objectweb.asm.Opcodes.INVOKESTATIC; +import static org.objectweb.asm.Opcodes.GETSTATIC; + + +public class RenderItemTransformer implements IClassTransformer { + private static final String classToTransform = "net.minecraft.client.renderer.entity.RenderItem"; + @Override + public byte[] transform(String name, String transformedName, byte[] classBeingTransformed) + { + boolean isObfuscated = name.equals(transformedName); + return transformedName.equals(classToTransform) ? transform(classBeingTransformed, isObfuscated) : classBeingTransformed; + } + + private static byte[] transform(byte[] classBeingTranformed, boolean isObfuscated) + { + System.out.println("Transforming: " + classToTransform); + try + { + ClassNode classNode = new ClassNode(); + ClassReader classReader = new ClassReader(classBeingTranformed); + classReader.accept(classNode, 0); + + transformRenderItem(classNode, isObfuscated); + + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + classNode.accept(classWriter); + return classWriter.toByteArray(); + } + catch (Exception e) + { + System.out.println("FATAL ERROR in RenderItemTransformer"); + e.printStackTrace(); + } + return classBeingTranformed; + } + + private static void transformRenderItem(ClassNode renderItemClass, boolean isObfuscated) + { + final String RENDER_ITEM_INTO_GUI = "renderItemIntoGUI"; + final String RENDER_ITEM_INTO_GUI_DESC = "(Lnet/minecraft/client/gui/FontRenderer;Lnet/minecraft/client/renderer/texture/TextureManager;Lnet/minecraft/item/ItemStack;IIZ)V"; + + for (MethodNode method : renderItemClass.methods) + { + if (method.name.equals(RENDER_ITEM_INTO_GUI) && method.desc.equals(RENDER_ITEM_INTO_GUI_DESC)) + { + AbstractInsnNode targetNode = null; + boolean tesselatorFound = false; + boolean glDisableFound = false; + boolean glColorMaskFound = false; + for (AbstractInsnNode instruction : method.instructions.toArray()) + { + if (instruction.getOpcode() == GETSTATIC) { + if (!tesselatorFound && ((FieldInsnNode) instruction).desc.equals("Lnet/minecraft/client/renderer/Tessellator;")) { + targetNode = instruction; + removeTesselatorAndCleanupCallsBlock(targetNode, method); + tesselatorFound = true; + break; + } + } + if (instruction.getOpcode() == INVOKESTATIC) + { + if (!glDisableFound && ((MethodInsnNode) instruction).name.equals("glDisable")) + { + if (instruction.getPrevious() instanceof IntInsnNode && ((IntInsnNode) instruction.getPrevious()).operand == 3553) + { + targetNode = instruction; + removeGLDisable(targetNode, method); + glDisableFound = true; + continue; + } + } + if (!glColorMaskFound && ((MethodInsnNode) instruction).name.equals("glColorMask")) + { + targetNode = instruction; + removeColorMask(targetNode, method); + glColorMaskFound = true; + } + } + } + } + } + } + + // This essnetially comments out the all tesselator calls completely in renderItemIntoGUI found in the + // render item class. More lines need to be removed in this transform like redundant GLState + // updating if these lines are commented out. This is just the inital testing to see if this + // change is smart or stupid. I really don't know, but the tesselator calls seem + // completely redundant. + + // All of this code is removing items from this block in render item: + + // else if (p_77015_3_.getItem().requiresMultipleRenderPasses()) + // { + // GL11.glDisable(GL11.GL_LIGHTING); + // GL11.glEnable(GL11.GL_ALPHA_TEST); + // p_77015_2_.bindTexture(TextureMap.locationItemsTexture); + // GL11.glDisable(GL11.GL_ALPHA_TEST); + // GL11.glDisable(GL11.GL_TEXTURE_2D); + // GL11.glEnable(GL11.GL_BLEND); + // OpenGlHelper.glBlendFunc(0, 0, 0, 0); + // GL11.glColorMask(false, false, false, true); + // GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + // Tessellator tessellator = Tessellator.instance; + // tessellator.startDrawingQuads(); + // tessellator.setColorOpaque_I(-1); + // tessellator.addVertex((double)(p_77015_4_ - 2), (double)(p_77015_5_ + 18), (double)this.zLevel); + // tessellator.addVertex((double)(p_77015_4_ + 18), (double)(p_77015_5_ + 18), (double)this.zLevel); + // tessellator.addVertex((double)(p_77015_4_ + 18), (double)(p_77015_5_ - 2), (double)this.zLevel); + // tessellator.addVertex((double)(p_77015_4_ - 2), (double)(p_77015_5_ - 2), (double)this.zLevel); + // tessellator.draw(); + // GL11.glColorMask(true, true, true, true); + // GL11.glEnable(GL11.GL_TEXTURE_2D); + // GL11.glEnable(GL11.GL_ALPHA_TEST); + // + // Item item = p_77015_3_.getItem(); + // for (l = 0; l < item.getRenderPasses(k); ++l) + + // It is changed to the following: + + // else if (p_77015_3_.getItem().requiresMultipleRenderPasses()) + // { + // GL11.glDisable(GL11.GL_LIGHTING); + // GL11.glEnable(GL11.GL_ALPHA_TEST); + // p_77015_2_.bindTexture(TextureMap.locationItemsTexture); + // GL11.glEnable(GL11.GL_BLEND); + // OpenGlHelper.glBlendFunc(0, 0, 0, 0); + // GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + // + // Item item = p_77015_3_.getItem(); + // for (l = 0; l < item.getRenderPasses(k); ++l) + + private static void removeTesselatorAndCleanupCallsBlock(AbstractInsnNode targetNode, MethodNode method) + { + try + { + if (targetNode != null) + { + method.instructions.remove(targetNode.getPrevious()); + method.instructions.remove(targetNode.getPrevious()); + while(!(targetNode.getNext().getNext().getNext().getOpcode() == INVOKEVIRTUAL && ((MethodInsnNode) targetNode.getNext().getNext().getNext()).name.equals("getItem"))) + { + targetNode = targetNode.getNext(); + method.instructions.remove(targetNode.getPrevious()); + } + } + else + { + throw new Exception(); + } + } + catch(Exception e) + { + System.out.println("Could not find the tesselator to remove"); + e.printStackTrace(); + } + } + + private static void removeGLDisable(AbstractInsnNode targetNode, MethodNode method) + { + try + { + if (targetNode != null) + { + while (!(targetNode.getOpcode() == INVOKEVIRTUAL && ((MethodInsnNode) targetNode).name.equals("bindTexture"))) + { + targetNode = targetNode.getPrevious(); + method.instructions.remove(targetNode.getNext()); + } + } + else + { + throw new Exception(); + } + } + catch(Exception e) + { + System.out.println("Could not find the correct GLDisable functions to remove"); + e.printStackTrace(); + } + + } + + private static void removeColorMask(AbstractInsnNode targetNode, MethodNode method) + { + try + { + if (targetNode != null) + { + while (!(targetNode.getOpcode() == INVOKESTATIC && ((MethodInsnNode) targetNode).name.equals("glBlendFunc"))) + { + targetNode = targetNode.getPrevious(); + method.instructions.remove(targetNode.getNext()); + } + } + else + { + throw new Exception(); + } + } + catch(Exception e) + { + System.out.println("Could not find the correct colorMask function to remove"); + e.printStackTrace(); + } + } +} From b055874bdc65c5e26be1d846490066ce58e6dfa4 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Wed, 13 Dec 2023 22:03:54 -0800 Subject: [PATCH 262/301] Iris shaderpack keybind works --- src/main/java/net/coderbot/iris/Iris.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index bc762785b..2e1b4af78 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -11,6 +11,7 @@ import net.coderbot.iris.config.IrisConfig; import net.coderbot.iris.gl.GLDebug; import net.coderbot.iris.gl.shader.StandardMacros; +import net.coderbot.iris.gui.screen.ShaderPackScreen; import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline; import net.coderbot.iris.pipeline.FixedFunctionWorldRenderingPipeline; import net.coderbot.iris.pipeline.PipelineManager; @@ -125,8 +126,7 @@ public void onKeypress(InputEvent.KeyInputEvent event) { } } else if (shaderpackScreenKeybind.isPressed()) { final Minecraft mc = Minecraft.getMinecraft(); - if (mc.thePlayer != null) mc.thePlayer.addChatMessage(new ChatComponentText( "Shaderpack selection screen is not implemented yet!")); -// minecraft.setScreen(new ShaderPackScreen(null)); + mc.displayGuiScreen(new ShaderPackScreen(null)); } } From 3f416894e6e5bf9f14f05edbae7e919600d2dc20 Mon Sep 17 00:00:00 2001 From: rjnasers Date: Thu, 14 Dec 2023 13:57:06 -0600 Subject: [PATCH 263/301] Small mis-translation fixed --- .../coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java index 148d11566..8cbc086d5 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java @@ -153,7 +153,7 @@ protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourc int x = ((TextureAtlasSpriteAccessor) sprite).getX(); int y = ((TextureAtlasSpriteAccessor) sprite).getY(); - pbrSprite = new PBRTextureAtlasSprite(pbrSpriteInfo, animationMetadata, atlasWidth, atlasHeight, x, y, nativeImage, texMap); + pbrSprite = new PBRTextureAtlasSprite(pbrSpriteInfo, animationMetadata, atlasWidth, atlasHeight, x, y, nativeImage, texMap, mipLevel); syncAnimation(sprite, pbrSprite); } catch (FileNotFoundException e) { // @@ -217,10 +217,10 @@ public PBRTextureAtlasSpriteInfo(ResourceLocation name, int width, int height, A public static class PBRTextureAtlasSprite extends TextureAtlasSprite implements CustomMipmapGenerator.Provider { // This feels super janky - protected PBRTextureAtlasSprite(TextureAtlasSpriteInfo info, AnimationMetadataSection animationMetaDataSection,int atlasWidth, int atlasHeight, int x, int y, NativeImage nativeImage, TextureMap texMap) { + protected PBRTextureAtlasSprite(TextureAtlasSpriteInfo info, AnimationMetadataSection animationMetaDataSection, int atlasWidth, int atlasHeight, int x, int y, NativeImage nativeImage, TextureMap texMap, int miplevel) { super(info.name().toString()); super.initSprite(atlasWidth, atlasHeight, x, y, false); - super.loadSprite(getMipmapGenerator(info, atlasWidth, atlasHeight).generateMipLevels(nativeImage, ((TextureMapAccessor) texMap).getMipmapLevels()), animationMetaDataSection, ((TextureMapAccessor) texMap).getAnisotropicFiltering() == 1); + super.loadSprite(getMipmapGenerator(info, atlasWidth, atlasHeight).generateMipLevels(nativeImage, miplevel), animationMetaDataSection, ((TextureMapAccessor) texMap).getAnisotropicFiltering() == 1); } @Override From 0ec86fa3d52dd445f0cd526d38f96124cb5bdce9 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 14 Dec 2023 17:23:50 -0800 Subject: [PATCH 264/301] TopButton almost works correctly --- .../client/font/BatchingFontRenderer.java | 2 +- .../iris/gui/element/IrisElementRow.java | 24 +- .../iris/gui/element/IrisGuiSlot.java | 7 + .../gui/element/ShaderPackSelectionList.java | 235 +++--------------- .../coderbot/iris/gui/entry/BaseEntry.java | 14 ++ .../coderbot/iris/gui/entry/LabelEntry.java | 19 ++ .../iris/gui/entry/ShaderPackEntry.java | 56 +++++ .../iris/gui/entry/TopButtonRowEntry.java | 89 +++++++ .../iris/gui/screen/ShaderPackScreen.java | 64 +++-- .../assets/iris/textures/gui/widgets.png | Bin 0 -> 3587 bytes 10 files changed, 262 insertions(+), 248 deletions(-) create mode 100644 src/main/java/net/coderbot/iris/gui/entry/BaseEntry.java create mode 100644 src/main/java/net/coderbot/iris/gui/entry/LabelEntry.java create mode 100644 src/main/java/net/coderbot/iris/gui/entry/ShaderPackEntry.java create mode 100644 src/main/java/net/coderbot/iris/gui/entry/TopButtonRowEntry.java create mode 100644 src/main/resources/assets/iris/textures/gui/widgets.png diff --git a/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java b/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java index 7a369b6d0..1dead8301 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/font/BatchingFontRenderer.java @@ -322,7 +322,7 @@ public float drawString(final float anchorX, final float anchorY, final int colo return 0.0f; } final int shadowColor = (color & 0xfcfcfc) >> 2 | color & 0xff000000; - ; + this.beginBatch(); float curX = anchorX; try { diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java b/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java index a5d2ab4c2..8a232033f 100644 --- a/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java +++ b/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java @@ -1,5 +1,6 @@ package net.coderbot.iris.gui.element; +import lombok.Getter; import net.coderbot.iris.gui.GuiUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; @@ -76,7 +77,7 @@ public void render(int x, int y, int height, int mouseX, int mouseY, float tickD int currentX = x; for (Element element : this.orderedElements) { - int currentWidth = this.elements.get(element); + final int currentWidth = this.elements.get(element); element.render(currentX, y, currentWidth, height, mouseX, mouseY, tickDelta, rowHovered && sectionHovered(currentX, currentWidth, mouseX, mouseY)); @@ -101,7 +102,7 @@ private Optional getHovered(double mx, double my) { int currentX = this.x; for (Element element : this.orderedElements) { - int currentWidth = this.elements.get(element); + final int currentWidth = this.elements.get(element); if (sectionHovered(currentX, currentWidth, mx, my)) { return Optional.of(element); @@ -121,9 +122,9 @@ public boolean mouseReleased(double mx, double my, int button) { return getHovered(mx, my).map(element -> element.mouseReleased(mx, my, button)).orElse(false); } - public static abstract class Element { + public abstract static class Element { public boolean disabled = false; - private boolean hovered = false; + @Getter private boolean hovered = false; public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { GuiUtil.bindIrisWidgetsTexture(); @@ -143,12 +144,9 @@ public boolean mouseReleased(double mx, double my, int button) { return false; } - public boolean isHovered() { - return hovered; - } - } + } - public static abstract class ButtonElement> extends Element { + public abstract static class ButtonElement> extends Element { private final Function onClick; protected ButtonElement(Function onClick) { @@ -188,8 +186,8 @@ public IconButtonElement(GuiUtil.Icon icon, Function @Override public void renderLabel(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - int iconX = x + (int)((width - this.icon.getWidth()) * 0.5); - int iconY = y + (int)((height - this.icon.getHeight()) * 0.5); + final int iconX = x + (int)((width - this.icon.getWidth()) * 0.5); + final int iconY = y + (int)((height - this.icon.getHeight()) * 0.5); GuiUtil.bindIrisWidgetsTexture(); if (!this.disabled && hovered) { @@ -216,8 +214,8 @@ public TextButtonElement(String text, Function onCli @Override public void renderLabel(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - int textX = x + (int)((width - this.font.getStringWidth(this.text)) * 0.5); - int textY = y + (int)((height - 8) * 0.5); + final int textX = x + (int)((width - this.font.getStringWidth(this.text)) * 0.5); + final int textY = y + (int)((height - 8) * 0.5); this.font.drawStringWithShadow(this.text, textX, textY, 0xFFFFFF); } diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java b/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java index 92a0f6c6f..ef9b2b999 100644 --- a/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java +++ b/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java @@ -28,5 +28,12 @@ protected int getScrollBarX() { return this.width - 6; } + @Override + protected void drawSelectionBox(int x, int y, int mouseX, int mouseY) { + final int oldPadding = this.headerPadding; + this.headerPadding = 2; + super.drawSelectionBox(x, y, mouseX, mouseY); + this.headerPadding = oldPadding; + } } diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java index b81cd83dc..232d4f6a9 100644 --- a/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java +++ b/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java @@ -1,25 +1,25 @@ package net.coderbot.iris.gui.element; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - import lombok.Getter; import lombok.Setter; import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.entry.BaseEntry; +import net.coderbot.iris.gui.entry.LabelEntry; +import net.coderbot.iris.gui.entry.ShaderPackEntry; +import net.coderbot.iris.gui.entry.TopButtonRowEntry; import net.coderbot.iris.gui.screen.ShaderPackScreen; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.gui.GuiLabel; import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.resources.I18n; -public class ShaderPackSelectionList extends IrisGuiSlot { - private static final String PACK_LIST_LABEL = I18n.format("pack.iris.list.label"); +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +public class ShaderPackSelectionList extends IrisGuiSlot { + @Getter private final ShaderPackScreen screen; -// @Getter -// private final TopButtonRowEntry topButtonRow; + @Getter + private final TopButtonRowEntry topButtonRow; @Setter @Getter @@ -35,15 +35,15 @@ public ShaderPackSelectionList(ShaderPackScreen screen, Minecraft client, int wi super(client, width, height, top, bottom, 20); this.screen = screen; -// this.topButtonRow = new TopButtonRowEntry(this, Iris.getIrisConfig().areShadersEnabled()); + this.topButtonRow = new TopButtonRowEntry(this, Iris.getIrisConfig().areShadersEnabled()); refresh(); } public void refresh() { -// this.clearEntries(); + this.entries.clear(); - Collection names; + final Collection names; try { names = Iris.getShaderpacksDirectoryManager().enumerate(); @@ -66,10 +66,10 @@ public void refresh() { return; } -// this.addEntry(topButtonRow); + this.entries.add(topButtonRow); // Only allow the enable/disable shaders button if the user has added a shader pack. Otherwise, the button will be disabled. -// topButtonRow.allowEnableShadersButton = names.size() > 0; + topButtonRow.allowEnableShadersButton = names.size() > 0; int index = 0; @@ -78,7 +78,6 @@ public void refresh() { addPackEntry(index, name); } - this.addLabelEntries(PACK_LIST_LABEL); } public void addPackEntry(int index, String name) { @@ -96,13 +95,13 @@ public void addPackEntry(int index, String name) { public void addLabelEntries(String ... lines) { for (String text : lines) { - this.entries.add(new LabelEntry(text)); + this.entries.add(new LabelEntry(this, text)); } } public void select(String name) { for (BaseEntry entry : this.entries) { - if (entry instanceof ShaderPackEntry shaderPackEntry && shaderPackEntry.packName.equals(name)) { + if (entry instanceof ShaderPackEntry shaderPackEntry && name.equals(shaderPackEntry.getPackName())) { setSelected(shaderPackEntry); return; } @@ -115,9 +114,15 @@ protected int getSize() { } @Override - protected void elementClicked(int index, boolean b, int mouseX, int mouseY) { - if(this.entries.get(index) instanceof ShaderPackEntry shaderPackEntry) { + protected void elementClicked(int index, boolean doubleClick, int mouseX, int mouseY) { + final BaseEntry entry = this.entries.get(index); + if(entry instanceof ShaderPackEntry shaderPackEntry) { this.setSelected(shaderPackEntry); + if (!topButtonRow.shadersEnabled) { + topButtonRow.setShadersEnabled(true); + } + } else if( entry instanceof TopButtonRowEntry topButtonRowEntry) { + topButtonRowEntry.mouseClicked(mouseX, mouseY, 0); } } @@ -127,193 +132,21 @@ protected boolean isSelected(int idx) { } @Override - protected void drawBackground() { - + public int getListWidth() { + return Math.min(308, width - 50); } - - @Override - protected void drawSlot(int index, int x, int y, int i3, Tessellator tessellator, int mouseX, int mouseY) { - final BaseEntry entry = this.entries.get(index); - entry.drawEntry(screen, index, (this.screen.width / 2), y + 1); - - } - - - public static abstract class BaseEntry extends GuiLabel { - protected BaseEntry() {} - - public abstract void drawEntry(ShaderPackScreen screen, int index, int x, int y); - } - - public static class ShaderPackEntry extends BaseEntry { - @Getter - private final String packName; - private final ShaderPackSelectionList list; - private final int index; - - public ShaderPackEntry(int index, ShaderPackSelectionList list, String packName) { - this.packName = packName; - this.list = list; - this.index = index; - } - - public boolean isApplied() { - return list.getApplied() == this; - } - - public boolean isSelected() { - return list.getSelected() == this; - } - - @Override - public void drawEntry(ShaderPackScreen screen, int index, int x, int y) { - final FontRenderer font = screen.getFontRenderer(); - - int color = 0xFFFFFF; - String name = packName; - if (font.getStringWidth(name) > this.list.getListWidth() - 3) { - name = font.trimStringToWidth(name, this.list.getListWidth() - 8) + "..."; - } - if(this.isSelected()) { - name = "§l" + name; - } - if(this.isApplied()) { - color = 0xFFF263; - } - - - - screen.drawCenteredString(name, x, y, color); - } + protected void drawBackground() { -// -// @Override -// public boolean mouseClicked(double mouseX, double mouseY, int button) { -// // Only do anything on left-click -// if (button != 0) { -// return false; -// } -// -// boolean didAnything = false; -// -// // UX: If shaders are disabled, then clicking a shader in the list will also -// // enable shaders on apply. Previously, it was not possible to select -// // a pack when shaders were disabled, but this was a source of confusion -// // - people did not realize that they needed to enable shaders before -// // selecting a shader pack. -// if (!list.getTopButtonRow().shadersEnabled) { -// list.getTopButtonRow().setShadersEnabled(true); -// didAnything = true; -// } -// -// if (!this.isSelected()) { -// this.list.select(this.index); -// didAnything = true; -// } -// -// return didAnything; -// } } - public static class LabelEntry extends BaseEntry { - private final String label; - public LabelEntry(String label) { - this.label = label; - } - - @Override - public void drawEntry(ShaderPackScreen screen, int index, int x, int y) { - screen.drawCenteredString(label, x, y, 0xFFFFFF); - } + @Override + protected void drawSlot(int index, int x, int y, int i1, Tessellator tessellator, int mouseX, int mouseY) { + final BaseEntry entry = this.entries.get(index); + final boolean isMouseOver = this.func_148124_c/*getSlotIndexFromScreenCoords*/(mouseX, mouseY) == index; + entry.drawEntry(screen, index, x - 2, y + 4, this.getListWidth(), tessellator, mouseX, mouseY, isMouseOver); } -// public static class TopButtonRowEntry extends BaseEntry { -// private static final Component REFRESH_SHADER_PACKS_LABEL = new TranslatableComponent("options.iris.refreshShaderPacks").withStyle(style -> style.withColor(TextColor.fromRgb(0x99ceff))); -// private static final Component NONE_PRESENT_LABEL = new TranslatableComponent("options.iris.shaders.nonePresent").withStyle(ChatFormatting.GRAY); -// private static final Component SHADERS_DISABLED_LABEL = new TranslatableComponent("options.iris.shaders.disabled"); -// private static final Component SHADERS_ENABLED_LABEL = new TranslatableComponent("options.iris.shaders.enabled"); -// private static final int REFRESH_BUTTON_WIDTH = 18; -// -// private final ShaderPackSelectionList list; -// private final IrisElementRow buttons = new IrisElementRow(); -// private final EnableShadersButtonElement enableDisableButton; -// private final IrisElementRow.Element refreshPacksButton; -// -// public boolean allowEnableShadersButton = true; -// public boolean shadersEnabled; -// -// public TopButtonRowEntry(ShaderPackSelectionList list, boolean shadersEnabled) { -// this.list = list; -// this.shadersEnabled = shadersEnabled; -// this.enableDisableButton = new EnableShadersButtonElement( -// getEnableDisableLabel(), -// button -> { -// if (this.allowEnableShadersButton) { -// setShadersEnabled(!this.shadersEnabled); -// GuiUtil.playButtonClickSound(); -// return true; -// } -// -// return false; -// }); -// this.refreshPacksButton = new IrisElementRow.IconButtonElement( -// GuiUtil.Icon.REFRESH, -// button -> { -// this.list.refresh(); -// -// GuiUtil.playButtonClickSound(); -// return true; -// }); -// this.buttons.add(this.enableDisableButton, 0).add(this.refreshPacksButton, REFRESH_BUTTON_WIDTH); -// } -// -// public void setShadersEnabled(boolean shadersEnabled) { -// this.shadersEnabled = shadersEnabled; -// this.enableDisableButton.text = getEnableDisableLabel(); -// this.list.screen.refreshScreenSwitchButton(); -// } -// -// @Override -// public void render(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { -// this.buttons.setWidth(this.enableDisableButton, (entryWidth - 1) - REFRESH_BUTTON_WIDTH); -// this.enableDisableButton.centerX = x + (int)(entryWidth * 0.5); -// -// this.buttons.render(x - 2, y - 3, 18, mouseX, mouseY, tickDelta, hovered); -// -// if (this.refreshPacksButton.isHovered()) { -// ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> -// GuiUtil.drawTextPanel(Minecraft.getInstance().font, REFRESH_SHADER_PACKS_LABEL, -// (mouseX - 8) - Minecraft.getInstance().font.width(REFRESH_SHADER_PACKS_LABEL), mouseY - 16)); -// } -// } -// -// private Component getEnableDisableLabel() { -// return this.allowEnableShadersButton ? this.shadersEnabled ? SHADERS_ENABLED_LABEL : SHADERS_DISABLED_LABEL : NONE_PRESENT_LABEL; -// } -// -// @Override -// public boolean mouseClicked(double mouseX, double mouseY, int button) { -// return this.buttons.mouseClicked(mouseX, mouseY, button); -// } -// -// // Renders the label at an offset as to not look misaligned with the rest of the menu -// public static class EnableShadersButtonElement extends IrisElementRow.TextButtonElement { -// private int centerX; -// -// public EnableShadersButtonElement(Component text, Function onClick) { -// super(text, onClick); -// } -// -// @Override -// public void renderLabel(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { -// int textX = this.centerX - (int)(this.font.width(this.text) * 0.5); -// int textY = y + (int)((height - 8) * 0.5); -// -// this.font.drawShadow(this.text, textX, textY, 0xFFFFFF); -// } -// } -// } } diff --git a/src/main/java/net/coderbot/iris/gui/entry/BaseEntry.java b/src/main/java/net/coderbot/iris/gui/entry/BaseEntry.java new file mode 100644 index 000000000..2b3e2aae3 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/entry/BaseEntry.java @@ -0,0 +1,14 @@ +package net.coderbot.iris.gui.entry; + +import net.coderbot.iris.gui.element.IrisGuiSlot; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.minecraft.client.renderer.Tessellator; + +public abstract class BaseEntry { + protected IrisGuiSlot list; + protected BaseEntry(IrisGuiSlot list) { + this.list = list; + } + + public abstract void drawEntry(ShaderPackScreen screen, int index, int x, int y, int listWidth, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver); +} diff --git a/src/main/java/net/coderbot/iris/gui/entry/LabelEntry.java b/src/main/java/net/coderbot/iris/gui/entry/LabelEntry.java new file mode 100644 index 000000000..5ab1a0f60 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/entry/LabelEntry.java @@ -0,0 +1,19 @@ +package net.coderbot.iris.gui.entry; + +import net.coderbot.iris.gui.element.IrisGuiSlot; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.minecraft.client.renderer.Tessellator; + +public class LabelEntry extends BaseEntry { + private final String label; + + public LabelEntry(IrisGuiSlot list, String label) { + super(list); + this.label = label; + } + + @Override + public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int listWidth, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver) { + screen.drawCenteredString(label, x, y, 0xFFFFFF); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/entry/ShaderPackEntry.java b/src/main/java/net/coderbot/iris/gui/entry/ShaderPackEntry.java new file mode 100644 index 000000000..e3e62fb1a --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/entry/ShaderPackEntry.java @@ -0,0 +1,56 @@ +package net.coderbot.iris.gui.entry; + +import lombok.Getter; +import net.coderbot.iris.gui.element.ShaderPackSelectionList; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.Tessellator; + +public class ShaderPackEntry extends BaseEntry { + @Getter private final String packName; + private final ShaderPackSelectionList shaderPackSelectionList; + private final int index; + + public ShaderPackEntry(int index, ShaderPackSelectionList list, String packName) { + super(list); + this.packName = packName; + this.shaderPackSelectionList = list; + this.index = index; + } + + public boolean isApplied() { + return shaderPackSelectionList.getApplied() == this; + } + + public boolean isSelected() { + return shaderPackSelectionList.getSelected() == this; + } + + @Override + public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int listWidth, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver) { + final FontRenderer font = screen.getFontRenderer(); + final boolean shadersEnabled = shaderPackSelectionList.getTopButtonRow().shadersEnabled; + + int color = 0xFFFFFF; + String name = packName; + if (font.getStringWidth(name) > this.list.getListWidth() - 3) { + name = font.trimStringToWidth(name, this.list.getListWidth() - 8) + "..."; + } + + if(isMouseOver) { + name = "§l" + name; + } + + if(this.isApplied()) { + color = 0xFFF263; + } + + if(!shadersEnabled && !isMouseOver) { + color = 0xA2A2A2; + } + + + + screen.drawCenteredString(name, (x + listWidth / 2) - 2, y, color); + } +} diff --git a/src/main/java/net/coderbot/iris/gui/entry/TopButtonRowEntry.java b/src/main/java/net/coderbot/iris/gui/entry/TopButtonRowEntry.java new file mode 100644 index 000000000..0d732ce83 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/entry/TopButtonRowEntry.java @@ -0,0 +1,89 @@ +package net.coderbot.iris.gui.entry; + +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.element.IrisElementRow; +import net.coderbot.iris.gui.element.ShaderPackSelectionList; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.resources.I18n; + +import java.util.function.Function; + +public class TopButtonRowEntry extends BaseEntry { + private static final String NONE_PRESENT_LABEL = I18n.format("options.iris.shaders.nonePresent"); //.withStyle(ChatFormatting.GRAY); + private static final String SHADERS_DISABLED_LABEL = I18n.format("options.iris.shaders.disabled"); + private static final String SHADERS_ENABLED_LABEL = I18n.format("options.iris.shaders.enabled"); + private static final int REFRESH_BUTTON_WIDTH = 18; + + private final ShaderPackSelectionList shaderPackSelectionList; + private final IrisElementRow buttons = new IrisElementRow(); + private final EnableShadersButtonElement enableDisableButton; + private final IrisElementRow.Element refreshPacksButton; + + public boolean allowEnableShadersButton = true; + public boolean shadersEnabled; + + public TopButtonRowEntry(ShaderPackSelectionList list, boolean shadersEnabled) { + super(list); + this.shaderPackSelectionList = list; + this.shadersEnabled = shadersEnabled; + this.enableDisableButton = new EnableShadersButtonElement( + getEnableDisableLabel(), + button -> { + if (this.allowEnableShadersButton) { + setShadersEnabled(!this.shadersEnabled); + GuiUtil.playButtonClickSound(); + return true; + } + + return false; + }); + this.refreshPacksButton = new IrisElementRow.IconButtonElement( + GuiUtil.Icon.REFRESH, + button -> { + this.shaderPackSelectionList.refresh(); + + GuiUtil.playButtonClickSound(); + return true; + }); + this.buttons.add(this.enableDisableButton, 0).add(this.refreshPacksButton, REFRESH_BUTTON_WIDTH); + } + + public void setShadersEnabled(boolean shadersEnabled) { + this.shadersEnabled = shadersEnabled; + this.enableDisableButton.text = getEnableDisableLabel(); + this.shaderPackSelectionList.getScreen().refreshScreenSwitchButton(); + } + + public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int listWidth, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver) { + this.buttons.setWidth(this.enableDisableButton, (listWidth - 1) - REFRESH_BUTTON_WIDTH); + this.enableDisableButton.centerX = x + (int)(listWidth * 0.5); + + this.buttons.render(x - 2, y - 3, 18, mouseX, mouseY, 0, isMouseOver); + } + + private String getEnableDisableLabel() { + return this.allowEnableShadersButton ? this.shadersEnabled ? SHADERS_ENABLED_LABEL : SHADERS_DISABLED_LABEL : NONE_PRESENT_LABEL; + } + + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return this.buttons.mouseClicked(mouseX, mouseY, button); + } + + // Renders the label at an offset as to not look misaligned with the rest of the menu + public static class EnableShadersButtonElement extends IrisElementRow.TextButtonElement { + private int centerX; + + public EnableShadersButtonElement(String text, Function onClick) { + super(text, onClick); + } + + @Override + public void renderLabel(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + final int textX = this.centerX - (int)(this.font.getStringWidth(this.text) * 0.5); + final int textY = y + (int)((height - 8) * 0.5); + + this.font.drawStringWithShadow(this.text, textX, textY, 0xFFFFFF); + } + } +} diff --git a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java index 3d54532b7..09c7b1ccf 100644 --- a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java +++ b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java @@ -1,43 +1,42 @@ package net.coderbot.iris.gui.screen; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; - import com.gtnewhorizons.angelica.client.Shaders; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import net.coderbot.iris.Iris; import net.coderbot.iris.gui.GuiUtil; import net.coderbot.iris.gui.NavigationController; import net.coderbot.iris.gui.element.ShaderPackOptionList; +import net.coderbot.iris.gui.element.ShaderPackSelectionList; import net.coderbot.iris.gui.element.widget.AbstractElementWidget; import net.coderbot.iris.gui.element.widget.CommentedElementWidget; -import net.coderbot.iris.gui.element.ShaderPackSelectionList; import net.coderbot.iris.gui.element.widget.IrisButton; +import net.coderbot.iris.gui.entry.ShaderPackEntry; +import net.coderbot.iris.shaderpack.ShaderPack; +import net.irisshaders.iris.api.v0.IrisApi; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.resources.I18n; import org.jetbrains.annotations.Nullable; - -import net.coderbot.iris.Iris; -import net.coderbot.iris.shaderpack.ShaderPack; -import net.irisshaders.iris.api.v0.IrisApi; import org.lwjgl.Sys; import org.lwjgl.input.Keyboard; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + public class ShaderPackScreen extends GuiScreen implements HudHideable { /** * Queue rendering to happen on top of all elements. Useful for tooltips or dialogs. @@ -308,7 +307,7 @@ public void refreshForChangedPack() { public void refreshScreenSwitchButton() { if (this.screenSwitchButton != null) { this.screenSwitchButton.displayString = optionMenuOpen ? I18n.format("options.iris.shaderPackList") : I18n.format("options.iris.shaderPackSettings"); - this.screenSwitchButton.enabled = optionMenuOpen; // || shaderPackList.getTopButtonRow().shadersEnabled; + this.screenSwitchButton.enabled = optionMenuOpen || shaderPackList.getTopButtonRow().shadersEnabled; } } @@ -318,13 +317,17 @@ protected void keyTyped(char typedChar, int keyCode) { if (this.guiHidden) { this.guiHidden = false; this.initGui(); + return; } else if (this.navigation != null && this.navigation.hasHistory()) { this.navigation.back(); + return; } else if (this.optionMenuOpen) { this.optionMenuOpen = false; this.initGui(); + return; } } + super.keyTyped(typedChar, keyCode); } public void displayNotification(String String) { @@ -377,16 +380,11 @@ private void dropChangesAndClose() { } public void applyChanges() { - ShaderPackSelectionList.BaseEntry base = this.shaderPackList.getSelected(); - - if (!(base instanceof ShaderPackSelectionList.ShaderPackEntry)) { - return; - } + final ShaderPackEntry entry = this.shaderPackList.getSelected(); - ShaderPackSelectionList.ShaderPackEntry entry = (ShaderPackSelectionList.ShaderPackEntry)base; this.shaderPackList.setApplied(entry); - String name = entry.getPackName(); + final String name = entry.getPackName(); // If the pack is being changed, clear pending options from the previous pack to // avoid possible undefined behavior from applying one pack's options to another pack @@ -394,10 +392,10 @@ public void applyChanges() { Iris.clearShaderPackOptionQueue(); } - boolean enabled = true; //this.shaderPackList.getTopButtonRow().shadersEnabled; + final boolean enabled = this.shaderPackList.getTopButtonRow().shadersEnabled; - String previousPackName = Iris.getIrisConfig().getShaderPackName().orElse(null); - boolean previousShadersEnabled = Iris.getIrisConfig().areShadersEnabled(); + final String previousPackName = Iris.getIrisConfig().getShaderPackName().orElse(null); + final boolean previousShadersEnabled = Iris.getIrisConfig().areShadersEnabled(); // Only reload if the pack would be different from before, or shaders were toggled, or options were changed, or if we're about to reset options. if (!name.equals(previousPackName) || enabled != previousShadersEnabled || !Iris.getShaderPackOptionQueue().isEmpty() || Iris.shouldResetShaderPackOptionsOnNextReload()) { diff --git a/src/main/resources/assets/iris/textures/gui/widgets.png b/src/main/resources/assets/iris/textures/gui/widgets.png new file mode 100644 index 0000000000000000000000000000000000000000..d4a74a0e00bbf824bcf12a9a98dee8589474123f GIT binary patch literal 3587 zcmb_ec{H2r)_)W8oVJvrXs;^TYbteUqozhe4K;+4;#5&%OOqO7YE>0gN>xj!IgP0_ zJ!VnGQA1ioh=@399#4)Trf}n1>s#yl^M2>vcdh-t`&rL^_Wtehc@u4{%tQpG1pxpM zLBLII0RY5dK>$B5=Yt9^^WrSxeN0Sj5GE!H4}$M|`S^PRfN~l(4GM3!5s$aFE4Eb? zeFRx}`Ck7PL?S2yc`+`20C{h?ZMr!6d(jz0P>?uENc7+$@-!+3gLxpq-6jvw)jfY* zQia)4^!;q7P%0~E0-C^D<$8il!Fw?j^L<~ZAv!xEe{~RUI{Sn_lHWMv4ZgG{NiUQ# z0>#+UJ3?QFF!FTD#4UNZO{c<2WKJ@9nad@`4=2ux);=$S4c$GjpkoB@z3e%nP>gX@jhpX(I+~;uNRPg> zj&tp8@@7!8+3&J*={akBPjkcOn!L%p{p&bZ4(qC>>PLzdJY944^Y%v`1D6gdk7O?u ziI2>+Ww)NBH}d$YtH7otywW2tskzlMJy~)9*9~JJwDf(7 z{4SNk)3J7xtCkP|=?qyKJ)M3xc_E1>_Qj~TqY`E3%2a0NH)oIJ#E=6izp86en2nmX zFF$J%p@(PrfeR|qyJSrHMvJ;WvLT(-XXoj*OvzW@s=rSO>sWK0_|;=3aPdB<8jT&+ z-(P0ktf#Wr!=tBEo1d?V$*Hwm3mqMUM%af_2ZE@N6A}SKF4Nq`W#6iA7qARlF2m)k z)W@Y3ph&*O(l?tM-9PrO*?&|yjaU<&8$?}`VUL!l%YvEB&p4`VAJ%<4I%;(pH z#i9J@Df=LU$*=hAHC#l~|%_DyL>KJY4}8GKS6pv#q6h3D~fN-YPYC`h@9RR=uAA7jM$R zFRb;XBmF)j!N1QZIDa1$5gLD*_#qwKG< z*=+qs%T6Nic=IR5Wl58h`Q=3O(m}0G<*Xi`EqbgbjN*K~u)tomI5AORW<4w=Il0`w z2Q;oN2^>#+@(S27Dv9hvKnWJcFZQXe6%N;X80GVo-{zW5$h)gv7f?2Hf zCN~(jx3{Mk^}W+=^hmvSP#350eR{e`Fy6T19*DFk3GX08t7X}pO?#;c^Csgkxd*t2 z)gSZoWr{xj{=Fiby7wo_yW}EnB$^uI?alG_AB>{GF*AaSDtY7!Y4AEg0Wn9;8)35; zRqyi-U1Xv{tQwd&7;dKoW@e_Nt*wZtY$8%DrNK^DzzD%O!$ec&d(u5+29=5*R8PJ4 zbFgqX@3Z-sDq?Iq>tsMg@%5#VDo3fOY7YRX2ozbTv#h@UR`v}T#|3FAsqdw~NwoU; z_}sLxuwb@h2S}utrwIw0{a4ns3;FyI~ykr+g( zDj_ZH*pWI$3)Woem2Y66mmJ{qc>J+pt^9OiAXjBbpxq;P!vRUZFQSnx)EN;-_*AYN8LLbaZrl!o$O7oQ3jBP(U?BHT#BYt`#R=^Q2g= zRZyO?RMWV|f9um0L;5{!=vuFv7TlQjj~ zZOGRSo6@`QcG%`=!tnOrpa_2V0D+<@u#)uXn z<3S1KL{B}?&&?z0#Q;Bt`!0mwy{OvqU0^7oM?k7|YITh0*LI>%YjAK-FfRY%`N`$o z0)?01n;m*);B^jkgJeb8;9#LemRkMZU!l0xvVWA=s&M8D!A3dboLCB~Iea)pcJ{+s z#9D5;;^tcD9hJ?G!u&&tE#*oH-X@;`48@4{u74PU~&pEIxWOmX)K4w>$gH>ct@)93Jpxwp@ zl5vjv)(vcPK!sMqmSZyaha;Thp3pJo2%Ua=OYbe$v(>?N4NjA03@m(V{N_j#ZL-0x zoj)Ev%{JKlOk5nNm${J z5O;hiSuUDa;rQvKD45A!cX#*mGkbTIYK;^g-fIn~Ip2nqA?0JnE(ifP`EGxcHADvz zJuL9*;ZE}dvPX_e0tM8A)z#G+LdaL=rCFeW5Vn7KBBvSs+t98WZ){7nO5utmd7f>i z?fbtv#>G@76$uqsk8y9JOnHQ`YP6t&7D3(qq#6Uf`hlOcbobi2`U`b z_fet$?2WM?xf{ k;#aMI@89IVAe9d~5W~su@HulmxpAZpaox(a(%3!jU+08jAOHXW literal 0 HcmV?d00001 From 4ac36fa1d13fbdcf9a7fd6bf39404267d5f849c9 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 14 Dec 2023 18:23:38 -0800 Subject: [PATCH 265/301] Fix mistranslation of blit... not sure what the 256, 256 was; but it wasn't the z level... --- .../java/net/coderbot/iris/gui/GuiUtil.java | 8 +-- .../iris/gui/screen/ShaderPackScreen.java | 60 ++----------------- 2 files changed, 10 insertions(+), 58 deletions(-) diff --git a/src/main/java/net/coderbot/iris/gui/GuiUtil.java b/src/main/java/net/coderbot/iris/gui/GuiUtil.java index a7b53e565..66e6fdfd4 100644 --- a/src/main/java/net/coderbot/iris/gui/GuiUtil.java +++ b/src/main/java/net/coderbot/iris/gui/GuiUtil.java @@ -66,13 +66,13 @@ public static void drawButton(int x, int y, int width, int height, boolean hover GLStateManager.enableTexture(); // Top left section - GuiUtils.drawTexturedModalRect(x, y, 0, vOffset, halfWidth, halfHeight, 256); + GuiUtils.drawTexturedModalRect(x, y, 0, vOffset, halfWidth, halfHeight, 0); // Top right section - GuiUtils.drawTexturedModalRect(x + halfWidth, y, 200 - (width - halfWidth), vOffset, width - halfWidth, halfHeight, 256); + GuiUtils.drawTexturedModalRect(x + halfWidth, y, 200 - (width - halfWidth), vOffset, width - halfWidth, halfHeight, 0); // Bottom left section - GuiUtils.drawTexturedModalRect(x, y + halfHeight, 0, vOffset + (20 - (height - halfHeight)), halfWidth, height - halfHeight, 256); + GuiUtils.drawTexturedModalRect(x, y + halfHeight, 0, vOffset + (20 - (height - halfHeight)), halfWidth, height - halfHeight, 0); // Bottom right section - GuiUtils.drawTexturedModalRect(x + halfWidth, y + halfHeight, 200 - (width - halfWidth), vOffset + (20 - (height - halfHeight)), width - halfWidth, height - halfHeight, 256); + GuiUtils.drawTexturedModalRect(x + halfWidth, y + halfHeight, 200 - (width - halfWidth), vOffset + (20 - (height - halfHeight)), width - halfWidth, height - halfHeight, 0); } /** diff --git a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java index 09c7b1ccf..3d744b3a3 100644 --- a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java +++ b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java @@ -97,7 +97,6 @@ public void drawScreen(int mouseX, int mouseY, float delta) { if (this.mc.theWorld == null) { super.drawDefaultBackground(); -// this.renderBackground(poseStack); } else if (!this.guiHidden) { this.drawGradientRect(0, 0, width, height, 0x4F232323, 0x4F232323); } @@ -132,9 +131,9 @@ public void drawScreen(int mouseX, int mouseY, float delta) { // Draw the comment panel if (this.isDisplayingComment()) { // Determine panel height and position - int panelHeight = Math.max(50, 18 + (this.hoveredElementCommentBody.size() * 10)); - int x = (int) (0.5 * this.width) - 157; - int y = this.height - (panelHeight + 4); + final int panelHeight = Math.max(50, 18 + (this.hoveredElementCommentBody.size() * 10)); + final int x = (int) (0.5 * this.width) - 157; + final int y = this.height - (panelHeight + 4); // Draw panel GuiUtil.drawPanel(x, y, COMMENT_PANEL_WIDTH, panelHeight); // Draw text @@ -169,13 +168,10 @@ public void initGui() { final int topCenter = this.width / 2 - 76; final boolean inWorld = this.mc.theWorld != null; -// this.children.remove(this.shaderPackList); -// this.children.remove(this.shaderOptionList); - this.shaderPackList = new ShaderPackSelectionList(this, this.mc, this.width, this.height, 32, this.height - 58, 0, this.width); if (Iris.getCurrentPack().isPresent() && this.navigation != null) { - ShaderPack currentPack = Iris.getCurrentPack().get(); + final ShaderPack currentPack = Iris.getCurrentPack().get(); this.shaderOptionList = new ShaderPackOptionList(this, this.navigation, currentPack, this.mc, this.width, this.height, 32, this.height - 58, 0, this.width); this.navigation.setActiveOptionList(this.shaderOptionList); @@ -194,14 +190,8 @@ public void initGui() { } this.buttonList.clear(); -// this.children.clear(); if (!this.guiHidden) { -// if (optionMenuOpen && shaderOptionList != null) { -// this.children.add(shaderOptionList); -// } else { -// this.children.add(shaderPackList); -// } this.buttonList.add(new IrisButton(bottomCenter + 104, this.height - 27, 100, 20, I18n.format("gui.done"), button -> this.onClose())); @@ -253,22 +243,11 @@ public void initGui() { this.buttonList.add(new IrisButton( x, this.height - 39, 20, 20, -// this.guiHidden ? 20 : 0, 146, 20, -// GuiUtil.IRIS_WIDGETS_TEX, -// 256, 256, showOrHide, button -> { this.guiHidden = !this.guiHidden; this.initGui(); } -// , -// (button, i, j) -> { -// this.guiButtonHoverTimer += this.mc.getDeltaFrameTime(); -// if (this.guiButtonHoverTimer >= 10.0f) { -// TOP_LAYER_RENDER_QUEUE.add(() -> this.renderTooltip(showOrHide, i, j)); -// } -// }, -// showOrHide )); } @@ -335,35 +314,6 @@ public void displayNotification(String String) { this.notificationDialogTimer = 100; } - public void importPackOptions(Path settingFile) { - try (InputStream in = Files.newInputStream(settingFile)) { - final Properties properties = new Properties(); - properties.load(in); - - Iris.queueShaderPackOptionsFromProperties(properties); - - this.notificationDialog = I18n.format( - "options.iris.shaderPackOptions.importedSettings", - settingFile.getFileName().toString() - ); - this.notificationDialogTimer = 100; // 5 seconds (100 ticks) - - if (this.navigation != null) { - this.navigation.refresh(); - } - } catch (Exception e) { - // If the file could not be properly parsed or loaded, - // log the error and display a message to the user - Iris.logger.error("Error importing shader settings file \""+ settingFile.toString() +"\"", e); - - this.notificationDialog = I18n.format( - "options.iris.shaderPackOptions.failedImport", - settingFile.getFileName().toString() - ); - this.notificationDialogTimer = 100; // 5 seconds (100 ticks) - } - } - public void onClose() { if (!dropChanges) { applyChanges(); @@ -415,6 +365,7 @@ private void openShaderPackFolder() { } private void openUri(URI directoryUri) { + // TODO: Borrowed from ShadersMod... doesn't seem to work on Linux switch (net.minecraft.util.Util.getOSType()) { case OSX: { try { @@ -460,6 +411,7 @@ private void openUri(URI directoryUri) { // Let the screen know if an element is hovered or not, allowing for accurately updating which element is hovered public void setElementHoveredStatus(AbstractElementWidget widget, boolean hovered) { + // TODO: Unused, but might be useful for shader options if (hovered && widget != this.hoveredElement) { this.hoveredElement = widget; From 5cfe9e93961b7fd418299aeace2cfa83c8aced21 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Thu, 14 Dec 2023 22:47:14 -0800 Subject: [PATCH 266/301] Shader Options GUI work - Not fully wired up --- .../angelica/client/Shaders.java | 4 +- .../angelica/client/ShadersRender.java | 2 +- .../angelica/compat/mojang/BufferBuilder.java | 2 +- .../angelica/compat/mojang/RenderPhase.java | 4 +- .../angelica/config/AngelicaConfig.java | 4 +- .../archaic/MixinNetHandlerPlayClient.java | 2 +- .../notfine/clouds/MixinGameSettings.java | 2 +- .../notfine/clouds/MixinRenderGlobal.java | 4 +- .../particles/MixinEffectRenderer.java | 2 +- .../early/shaders/MixinFramebuffer.java | 2 +- .../transform/RenderItemTransformer.java | 4 +- .../iris/gui/element/IrisElementRow.java | 4 +- .../gui/element/ShaderPackOptionList.java | 364 +++--------------- .../gui/element/ShaderPackSelectionList.java | 8 +- .../gui/element/shaderoptions/BaseEntry.java | 15 + .../shaderoptions/ElementRowEntry.java | 62 +++ .../element/shaderoptions/HeaderEntry.java | 218 +++++++++++ .../shaderselection}/BaseEntry.java | 2 +- .../shaderselection}/LabelEntry.java | 2 +- .../shaderselection}/ShaderPackEntry.java | 5 +- .../shaderselection}/TopButtonRowEntry.java | 4 +- .../element/widget/AbstractElementWidget.java | 4 +- .../widget/BaseOptionElementWidget.java | 2 +- .../element/widget/BooleanElementWidget.java | 2 +- .../gui/element/widget/LinkElementWidget.java | 2 +- .../element/widget/ProfileElementWidget.java | 2 +- .../element/widget/SliderElementWidget.java | 2 +- .../element/widget/StringElementWidget.java | 2 +- .../iris/gui/screen/ShaderPackScreen.java | 8 +- 29 files changed, 379 insertions(+), 361 deletions(-) create mode 100644 src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java create mode 100644 src/main/java/net/coderbot/iris/gui/element/shaderoptions/HeaderEntry.java rename src/main/java/net/coderbot/iris/gui/{entry => element/shaderselection}/BaseEntry.java (89%) rename src/main/java/net/coderbot/iris/gui/{entry => element/shaderselection}/LabelEntry.java (91%) rename src/main/java/net/coderbot/iris/gui/{entry => element/shaderselection}/ShaderPackEntry.java (91%) rename src/main/java/net/coderbot/iris/gui/{entry => element/shaderselection}/TopButtonRowEntry.java (96%) diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java index 7309cee1b..717880fdc 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java @@ -2267,7 +2267,7 @@ public static void setCamera(float tickDelta) { shadowModelView.position(0); shadowModelViewInverse.position(0); - // Also render player shadow + // Also drawScreen player shadow mc.gameSettings.thirdPersonView = 1; checkGLError("setCamera"); return; @@ -2542,7 +2542,7 @@ public static void renderComposites(int programBase, int programCount, boolean r } private static void renderFinal() { - // final render target + // final drawScreen target isRenderingDfb = false; if (true) return; mc.getFramebuffer().bindFramebuffer(true); diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShadersRender.java b/src/main/java/com/gtnewhorizons/angelica/client/ShadersRender.java index e5c81a8b9..6956918ea 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShadersRender.java +++ b/src/main/java/com/gtnewhorizons/angelica/client/ShadersRender.java @@ -76,7 +76,7 @@ public static void renderItemFP(ItemRenderer itemRenderer, float par1) { Shaders.setDrawBuffers(drawBuffers); GL11.glPopMatrix(); GL11.glDepthFunc(GL11.GL_LEQUAL); - // really render item or hand + // really drawScreen item or hand itemRenderer.renderItemInFirstPerson(par1); } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java index 3675b8058..edd6218f3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java @@ -112,7 +112,7 @@ public void setupBufferSlice(ByteBuffer buffer, DrawState drawState) { @Override public void teardownBufferSlice() { - // the parameters got popped by the render call, we don't need to worry about them + // the parameters got popped by the drawScreen call, we don't need to worry about them // make sure to un-set the buffer to prevent anything bad from happening with it. this.buffer = null; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java index 48490fa58..ad3caa1f5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java @@ -491,13 +491,13 @@ public DiffuseLighting(boolean guiLighting) { super("diffuse_lighting", () -> { if (guiLighting) { throw new RuntimeException("Not Implemented Yet"); -// net.minecraft.client.render.DiffuseLighting.enable(); +// net.minecraft.client.drawScreen.DiffuseLighting.enable(); } }, () -> { if (guiLighting) { throw new RuntimeException("Not Implemented Yet"); -// net.minecraft.client.render.DiffuseLighting.disable(); +// net.minecraft.client.drawScreen.DiffuseLighting.disable(); } }, guiLighting); diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index cc7796f20..ff7c0507b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -46,10 +46,10 @@ public class AngelicaConfig { @Config.Comment("Renders the HUD elements once per tick and reuses the pixels to improve performance. [Experimental]") @Config.DefaultBoolean(true) @Config.RequiresMcRestart - // TODO disabled for now as it doesn't render items with an enchantment glint in the hotbar properly as well as doesn't render the vignette + // TODO disabled for now as it doesn't drawScreen items with an enchantment glint in the hotbar properly as well as doesn't drawScreen the vignette public static boolean enableHudCaching; - @Config.Comment("Batch render fonts [Experimental]") + @Config.Comment("Batch drawScreen fonts [Experimental]") @Config.DefaultBoolean(false) @Config.RequiresMcRestart public static boolean enableFontRenderer; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinNetHandlerPlayClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinNetHandlerPlayClient.java index e3c3f0301..c4db1f4b4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinNetHandlerPlayClient.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/archaic/MixinNetHandlerPlayClient.java @@ -13,7 +13,7 @@ * Makes interdimensional teleportation nearly as fast as same-dimension * teleportation by removing the "Downloading terrain..." screen. This will cause * the player to see partially loaded terrain rather than waiting for the whole - * render distance to load, but that's also the vanilla behaviour for same-dimension + * drawScreen distance to load, but that's also the vanilla behaviour for same-dimension * teleportation. [From ArchaicFix] */ @Mixin(value = NetHandlerPlayClient.class, priority = 500) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinGameSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinGameSettings.java index f07465695..ad1a7a76f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinGameSettings.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinGameSettings.java @@ -10,7 +10,7 @@ public abstract class MixinGameSettings { /** * @author jss2a98aj - * @reason Make clouds render at any render distance. + * @reason Make clouds drawScreen at any drawScreen distance. */ @Overwrite public boolean shouldRenderClouds() { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java index 7fdb20883..1c97ba3e3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/clouds/MixinRenderGlobal.java @@ -24,7 +24,7 @@ public abstract class MixinRenderGlobal { /** * @author jss2a98aj - * @reason Adjust how cloud render mode is selected. + * @reason Adjust how cloud drawScreen mode is selected. */ @Overwrite public void renderClouds(float partialTicks) { @@ -45,7 +45,7 @@ public void renderClouds(float partialTicks) { /** * @author jss2a98aj - * @reason Adjust fancy cloud render. + * @reason Adjust fancy cloud drawScreen. */ @Overwrite public void renderCloudsFancy(float partialTicks) { diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java index 0ab4c61b2..148659868 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/particles/MixinEffectRenderer.java @@ -10,7 +10,7 @@ public abstract class MixinEffectRenderer { /** * @author jss2a98aj - * @reason Makes most particles render with the expected depth. + * @reason Makes most particles drawScreen with the expected depth. */ @Redirect( method = "renderParticles", diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java index 94bdd81cc..5d7027f6d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinFramebuffer.java @@ -44,7 +44,7 @@ public abstract class MixinFramebuffer implements IRenderTargetExt { return iris$colorBufferVersion; } - // Use a depth texture instead of a depth render buffer + // Use a depth texture instead of a depth drawScreen buffer @Inject(method="Lnet/minecraft/client/shader/Framebuffer;createBindFramebuffer(II)V", at=@At(value="HEAD")) private void iris$useDepthTexture(int width, int height, CallbackInfo ci) { if(this.useDepth) { diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java index de0495474..d3450ced8 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java @@ -95,12 +95,12 @@ private static void transformRenderItem(ClassNode renderItemClass, boolean isObf } // This essnetially comments out the all tesselator calls completely in renderItemIntoGUI found in the - // render item class. More lines need to be removed in this transform like redundant GLState + // drawScreen item class. More lines need to be removed in this transform like redundant GLState // updating if these lines are commented out. This is just the inital testing to see if this // change is smart or stupid. I really don't know, but the tesselator calls seem // completely redundant. - // All of this code is removing items from this block in render item: + // All of this code is removing items from this block in drawScreen item: // else if (p_77015_3_.getItem().requiresMultipleRenderPasses()) // { diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java b/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java index 8a232033f..ea94291d0 100644 --- a/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java +++ b/src/main/java/net/coderbot/iris/gui/element/IrisElementRow.java @@ -69,7 +69,7 @@ public void setWidth(Element element, int width) { /** * Renders the row, with the anchor point being the top left. */ - public void render(int x, int y, int height, int mouseX, int mouseY, float tickDelta, boolean rowHovered) { + public void drawScreen(int x, int y, int height, int mouseX, int mouseY, float tickDelta, boolean rowHovered) { this.x = x; this.y = y; this.height = height; @@ -90,7 +90,7 @@ public void render(int x, int y, int height, int mouseX, int mouseY, float tickD * Renders the row, with the anchor point being the top right. */ public void renderRightAligned(int x, int y, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { - render(x - this.width, y, height, mouseX, mouseY, tickDelta, hovered); + drawScreen(x - this.width, y, height, mouseX, mouseY, tickDelta, hovered); } private boolean sectionHovered(int sectionX, int sectionWidth, double mx, double my) { diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java index 966c26384..29c5fb10a 100644 --- a/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java +++ b/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java @@ -1,29 +1,21 @@ package net.coderbot.iris.gui.element; import lombok.Getter; -import net.coderbot.iris.gui.FileDialogUtil; -import net.coderbot.iris.gui.GuiUtil; import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.element.shaderoptions.BaseEntry; +import net.coderbot.iris.gui.element.shaderoptions.ElementRowEntry; +import net.coderbot.iris.gui.element.shaderoptions.HeaderEntry; import net.coderbot.iris.gui.element.widget.AbstractElementWidget; import net.coderbot.iris.gui.element.widget.OptionMenuConstructor; -import net.coderbot.iris.Iris; import net.coderbot.iris.gui.screen.ShaderPackScreen; import net.coderbot.iris.shaderpack.ShaderPack; import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiSlot; import net.minecraft.client.renderer.Tessellator; -import org.jetbrains.annotations.Nullable; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.Properties; public class ShaderPackOptionList extends IrisGuiSlot { private final List> elementWidgets = new ArrayList<>(); @@ -31,6 +23,7 @@ public class ShaderPackOptionList extends IrisGuiSlot { @Getter private final NavigationController navigation; private OptionMenuContainer container; + private final List entries = new ArrayList<>(); public ShaderPackOptionList(ShaderPackScreen screen, NavigationController navigation, ShaderPack pack, Minecraft client, int width, int height, int top, int bottom, int left, int right) { super(client, width, height, top, bottom, 24); @@ -54,36 +47,40 @@ public void refresh() { this.elementWidgets.forEach(widget -> widget.init(this.screen, this.navigation)); } -// @Override -// public int getRowWidth() { -// return Math.min(400, width - 12); -// } -// -// public void addHeader(Component text, boolean backButton) { -// this.addEntry(new HeaderEntry(this.screen, this.navigation, text, backButton)); -// } -// -// public void addWidgets(int columns, List> elements) { -// this.elementWidgets.addAll(elements); -// -// List> row = new ArrayList<>(); -// for (AbstractElementWidget element : elements) { -// row.add(element); -// -// if (row.size() >= columns) { -// this.addEntry(new ElementRowEntry(screen, this.navigation, row)); -// row = new ArrayList<>(); // Clearing the list would affect the row entry created above -// } -// } -// -// if (row.size() > 0) { -// while (row.size() < columns) { -// row.add(AbstractElementWidget.EMPTY); -// } -// -// this.addEntry(new ElementRowEntry(screen, this.navigation, row)); -// } -// } + @Override + public int getListWidth() { + return Math.min(400, width - 12); + } + + protected void addEntry(BaseEntry entry) { + this.entries.add(entry); + } + + public void addHeader(String text, boolean backButton) { + this.addEntry(new HeaderEntry(this.screen, this.navigation, text, backButton)); + } + + public void addWidgets(int columns, List> elements) { + this.elementWidgets.addAll(elements); + + List> row = new ArrayList<>(); + for (AbstractElementWidget element : elements) { + row.add(element); + + if (row.size() >= columns) { + this.addEntry(new ElementRowEntry(screen, this.navigation, row)); + row = new ArrayList<>(); // Clearing the list would affect the row entry created above + } + } + + if (row.size() > 0) { + while (row.size() < columns) { + row.add(AbstractElementWidget.EMPTY); + } + + this.addEntry(new ElementRowEntry(screen, this.navigation, row)); + } + } @Override protected int getSize() { @@ -106,284 +103,13 @@ protected void drawBackground() { } @Override - protected void drawSlot(int p_148126_1_, int p_148126_2_, int p_148126_3_, int p_148126_4_, Tessellator p_148126_5_, int p_148126_6_, int p_148126_7_) { - + protected void drawSlot(int index, int x, int y, int i1, Tessellator tessellator, int mouseX, int mouseY) { + final BaseEntry entry = this.entries.get(index); + final boolean isMouseOver = this.func_148124_c/*getSlotIndexFromScreenCoords*/(mouseX, mouseY) == index; + entry.drawEntry(screen, index, x - 2, y + 4, this.getListWidth(), this.slotHeight, tessellator, mouseX, mouseY, isMouseOver); } + // -// public abstract static class BaseEntry extends ObjectSelectionList.Entry { -// protected final NavigationController navigation; -// -// protected BaseEntry(NavigationController navigation) { -// this.navigation = navigation; -// } -// } -// -// public static class HeaderEntry extends BaseEntry { -// public static final Component BACK_BUTTON_TEXT = new TextComponent("< ").append(new TranslatableComponent("options.iris.back").withStyle(ChatFormatting.ITALIC)); -// public static final MutableComponent RESET_BUTTON_TEXT_INACTIVE = new TranslatableComponent("options.iris.reset").withStyle(ChatFormatting.GRAY); -// public static final MutableComponent RESET_BUTTON_TEXT_ACTIVE = new TranslatableComponent("options.iris.reset").withStyle(ChatFormatting.YELLOW); -// -// public static final MutableComponent RESET_HOLD_SHIFT_TOOLTIP = new TranslatableComponent("options.iris.reset.tooltip.holdShift").withStyle(ChatFormatting.GOLD); -// public static final MutableComponent RESET_TOOLTIP = new TranslatableComponent("options.iris.reset.tooltip").withStyle(ChatFormatting.RED); -// public static final MutableComponent IMPORT_TOOLTIP = new TranslatableComponent("options.iris.importSettings.tooltip") -// .withStyle(style -> style.withColor(TextColor.fromRgb(0x4da6ff))); -// public static final MutableComponent EXPORT_TOOLTIP = new TranslatableComponent("options.iris.exportSettings.tooltip") -// .withStyle(style -> style.withColor(TextColor.fromRgb(0xfc7d3d))); -// -// private static final int MIN_SIDE_BUTTON_WIDTH = 42; -// private static final int BUTTON_HEIGHT = 16; -// -// private final ShaderPackScreen screen; -// private final @Nullable IrisElementRow backButton; -// private final IrisElementRow utilityButtons = new IrisElementRow(); -// private final IrisElementRow.TextButtonElement resetButton; -// private final IrisElementRow.IconButtonElement importButton; -// private final IrisElementRow.IconButtonElement exportButton; -// private final Component text; -// -// public HeaderEntry(ShaderPackScreen screen, NavigationController navigation, Component text, boolean hasBackButton) { -// super(navigation); -// -// if (hasBackButton) { -// this.backButton = new IrisElementRow().add( -// new IrisElementRow.TextButtonElement(BACK_BUTTON_TEXT, this::backButtonClicked), -// Math.max(MIN_SIDE_BUTTON_WIDTH, Minecraft.getInstance().font.width(BACK_BUTTON_TEXT) + 8) -// ); -// } else { -// this.backButton = null; -// } -// -// this.resetButton = new IrisElementRow.TextButtonElement( -// RESET_BUTTON_TEXT_INACTIVE, this::resetButtonClicked); -// this.importButton = new IrisElementRow.IconButtonElement( -// GuiUtil.Icon.IMPORT, GuiUtil.Icon.IMPORT_COLORED, this::importSettingsButtonClicked); -// this.exportButton = new IrisElementRow.IconButtonElement( -// GuiUtil.Icon.EXPORT, GuiUtil.Icon.EXPORT_COLORED, this::exportSettingsButtonClicked); -// -// this.utilityButtons -// .add(this.importButton, 15) -// .add(this.exportButton, 15) -// .add(this.resetButton, Math.max(MIN_SIDE_BUTTON_WIDTH, Minecraft.getInstance().font.width(RESET_BUTTON_TEXT_INACTIVE) + 8)); -// -// this.screen = screen; -// this.text = text; -// } -// -// @Override -// public void drawScreen(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { -// // Draw dividing line -// fill(x - 3, (y + entryHeight) - 2, x + entryWidth, (y + entryHeight) - 1, 0x66BEBEBE); -// -// Font font = Minecraft.getInstance().font; -// -// // Draw header text -// drawCenteredString(font, text, x + (int)(entryWidth * 0.5), y + 5, 0xFFFFFF); -// -// GuiUtil.bindIrisWidgetsTexture(); -// -// // Draw back button if present -// if (this.backButton != null) { -// backButton.drawScreen(x, y, BUTTON_HEIGHT, mouseX, mouseY, tickDelta, hovered); -// } -// -// boolean shiftDown = Screen.hasShiftDown(); -// -// // Set the appearance of the reset button -// this.resetButton.disabled = !shiftDown; -// this.resetButton.text = shiftDown ? RESET_BUTTON_TEXT_ACTIVE : RESET_BUTTON_TEXT_INACTIVE; -// -// // Draw the utility buttons -// this.utilityButtons.renderRightAligned((x + entryWidth) - 3, y, BUTTON_HEIGHT, mouseX, mouseY, tickDelta, hovered); -// -// // Draw the reset button's tooltip -// if (this.resetButton.isHovered()) { -// Component tooltip = shiftDown ? RESET_TOOLTIP : RESET_HOLD_SHIFT_TOOLTIP; -// queueBottomRightAnchoredTooltip(mouseX, mouseY, font, tooltip); -// } -// // Draw the import/export button tooltips -// if (this.importButton.isHovered()) { -// queueBottomRightAnchoredTooltip(mouseX, mouseY, font, IMPORT_TOOLTIP); -// } -// if (this.exportButton.isHovered()) { -// queueBottomRightAnchoredTooltip(mouseX, mouseY, font, EXPORT_TOOLTIP); -// } -// } -// -// private void queueBottomRightAnchoredTooltip(int x, int y, Font font, Component text) { -// ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel( -// font, text, -// x - (font.width(text) + 10), y - 16 -// )); -// } -// -// @Override -// public boolean mouseClicked(double mouseX, double mouseY, int button) { -// boolean backButtonResult = backButton != null && backButton.mouseClicked(mouseX, mouseY, button); -// boolean utilButtonResult = utilityButtons.mouseClicked(mouseX, mouseY, button); -// -// return backButtonResult || utilButtonResult; -// } -// -// private boolean backButtonClicked(IrisElementRow.TextButtonElement button) { -// this.navigation.back(); -// GuiUtil.playButtonClickSound(); -// -// return true; -// } -// -// private boolean resetButtonClicked(IrisElementRow.TextButtonElement button) { -// if (Screen.hasShiftDown()) { -// Iris.resetShaderPackOptionsOnNextReload(); -// this.screen.applyChanges(); -// GuiUtil.playButtonClickSound(); -// -// return true; -// } -// -// return false; -// } -// -// private boolean importSettingsButtonClicked(IrisElementRow.IconButtonElement button) { -// GuiUtil.playButtonClickSound(); -// -// // Invalid state to be in -// if (!Iris.getCurrentPack().isPresent()) { -// return false; -// } -// -// // Displaying a dialog when the game is full-screened can cause severe issues -// // https://github.com/IrisShaders/Iris/issues/1258 -// if (Minecraft.getInstance().getWindow().isFullscreen()) { -// this.screen.displayNotification( -// new TranslatableComponent("options.iris.mustDisableFullscreen") -// .withStyle(ChatFormatting.RED).withStyle(ChatFormatting.BOLD)); -// return false; -// } -// -// final ShaderPackScreen originalScreen = this.screen; // Also used to prevent invalid state -// -// FileDialogUtil.fileSelectDialog( -// FileDialogUtil.DialogType.OPEN, "Import Shader Settings from File", -// Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"), -// "Shader Pack Settings (.txt)", "*.txt") -// .whenComplete((path, err) -> { -// if (err != null) { -// Iris.logger.error("Error selecting shader settings from file", err); -// -// return; -// } -// -// if (Minecraft.getInstance().screen == originalScreen) { -// path.ifPresent(originalScreen::importPackOptions); -// } -// }); -// -// return true; -// } -// -// private boolean exportSettingsButtonClicked(IrisElementRow.IconButtonElement button) { -// GuiUtil.playButtonClickSound(); -// -// // Invalid state to be in -// if (!Iris.getCurrentPack().isPresent()) { -// return false; -// } -// -// // Displaying a dialog when the game is full-screened can cause severe issues -// // https://github.com/IrisShaders/Iris/issues/1258 -// if (Minecraft.getInstance().getWindow().isFullscreen()) { -// this.screen.displayNotification( -// new TranslatableComponent("options.iris.mustDisableFullscreen") -// .withStyle(ChatFormatting.RED).withStyle(ChatFormatting.BOLD)); -// return false; -// } -// -// FileDialogUtil.fileSelectDialog( -// FileDialogUtil.DialogType.SAVE, "Export Shader Settings to File", -// Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"), -// "Shader Pack Settings (.txt)", "*.txt") -// .whenComplete((path, err) -> { -// if (err != null) { -// Iris.logger.error("Error selecting file to export shader settings", err); -// -// return; -// } -// -// path.ifPresent(p -> { -// Properties toSave = new Properties(); -// -// // Dirty way of getting the currently applied settings as a Properties, directly -// // opens and copies out of the saved settings file if it is present -// Path sourceTxtPath = Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"); -// if (Files.exists(sourceTxtPath)) { -// try (InputStream in = Files.newInputStream(sourceTxtPath)) { -// toSave.load(in); -// } catch (IOException ignored) {} -// } -// -// // Save properties to user determined file -// try (OutputStream out = Files.newOutputStream(p)) { -// toSave.store(out, null); -// } catch (IOException e) { -// Iris.logger.error("Error saving properties to \"" + p + "\"", e); -// } -// }); -// }); -// -// return true; -// } -// } -// -// public static class ElementRowEntry extends BaseEntry { -// private final List> widgets; -// private final ShaderPackScreen screen; -// -// private int cachedWidth; -// private int cachedPosX; -// -// public ElementRowEntry(ShaderPackScreen screen, NavigationController navigation, List> widgets) { -// super(navigation); -// -// this.screen = screen; -// this.widgets = widgets; -// } -// -// @Override -// public void drawScreen(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { -// this.cachedWidth = entryWidth; -// this.cachedPosX = x; -// -// // The amount of space widgets will occupy, excluding margins. Will be divided up between widgets. -// int totalWidthWithoutMargins = entryWidth - (2 * (widgets.size() - 1)); -// -// totalWidthWithoutMargins -= 3; // Centers it for some reason -// -// // Width of a single widget -// float singleWidgetWidth = (float) totalWidthWithoutMargins / widgets.size(); -// -// for (int i = 0; i < widgets.size(); i++) { -// AbstractElementWidget widget = widgets.get(i); -// boolean widgetHovered = hovered && (getHoveredWidget(mouseX) == i); -// widget.drawScreen(x + (int)((singleWidgetWidth + 2) * i), y, (int) singleWidgetWidth, entryHeight + 2, mouseX, mouseY, tickDelta, widgetHovered); -// -// screen.setElementHoveredStatus(widget, widgetHovered); -// } -// } -// -// public int getHoveredWidget(int mouseX) { -// float positionAcrossWidget = ((float) Mth.clamp(mouseX - cachedPosX, 0, cachedWidth)) / cachedWidth; -// -// return Mth.clamp((int) Math.floor(widgets.size() * positionAcrossWidget), 0, widgets.size() - 1); -// } -// -// @Override -// public boolean mouseClicked(double mouseX, double mouseY, int button) { -// return this.widgets.get(getHoveredWidget((int) mouseX)).mouseClicked(mouseX, mouseY, button); -// } -// -// @Override -// public boolean mouseReleased(double mouseX, double mouseY, int button) { -// return this.widgets.get(getHoveredWidget((int) mouseX)).mouseReleased(mouseX, mouseY, button); -// } -// } + + } diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java index 232d4f6a9..d6bee9a27 100644 --- a/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java +++ b/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java @@ -3,10 +3,10 @@ import lombok.Getter; import lombok.Setter; import net.coderbot.iris.Iris; -import net.coderbot.iris.gui.entry.BaseEntry; -import net.coderbot.iris.gui.entry.LabelEntry; -import net.coderbot.iris.gui.entry.ShaderPackEntry; -import net.coderbot.iris.gui.entry.TopButtonRowEntry; +import net.coderbot.iris.gui.element.shaderselection.BaseEntry; +import net.coderbot.iris.gui.element.shaderselection.LabelEntry; +import net.coderbot.iris.gui.element.shaderselection.ShaderPackEntry; +import net.coderbot.iris.gui.element.shaderselection.TopButtonRowEntry; import net.coderbot.iris.gui.screen.ShaderPackScreen; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.Tessellator; diff --git a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java new file mode 100644 index 000000000..22589280b --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java @@ -0,0 +1,15 @@ +package net.coderbot.iris.gui.element.shaderoptions; + +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.minecraft.client.renderer.Tessellator; + +public abstract class BaseEntry { + protected final NavigationController navigation; + + protected BaseEntry(NavigationController navigation) { + this.navigation = navigation; + } + + public abstract void drawEntry(ShaderPackScreen screen, int index, int x, int y, int slotWidth, int slotHeight, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver); +} diff --git a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java new file mode 100644 index 000000000..5af2bedb7 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java @@ -0,0 +1,62 @@ +package net.coderbot.iris.gui.element.shaderoptions; + +import buildcraft.core.lib.utils.MathUtils; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.element.widget.AbstractElementWidget; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.minecraft.client.renderer.Tessellator; + +import java.util.List; + +public class ElementRowEntry extends BaseEntry { + + private final List> widgets; + private final ShaderPackScreen screen; + + private int cachedWidth; + private int cachedPosX; + + public ElementRowEntry(ShaderPackScreen screen, NavigationController navigation, List> widgets) { + super(navigation); + + this.screen = screen; + this.widgets = widgets; + } + + @Override + public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int slotWidth, int slotHeight, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver) { + this.cachedWidth = slotWidth; + this.cachedPosX = x; + + // The amount of space widgets will occupy, excluding margins. Will be divided up between widgets. + int totalWidthWithoutMargins = slotWidth - (2 * (widgets.size() - 1)); + + totalWidthWithoutMargins -= 3; // Centers it for some reason + + // Width of a single widget + final float singleWidgetWidth = (float) totalWidthWithoutMargins / widgets.size(); + + for (int i = 0; i < widgets.size(); i++) { + final AbstractElementWidget widget = widgets.get(i); + final boolean widgetHovered = isMouseOver && (getHoveredWidget(mouseX) == i); + widget.drawScreen(x + (int) ((singleWidgetWidth + 2) * i), y, (int) singleWidgetWidth, slotHeight + 2, mouseX, mouseY, 0, widgetHovered); + + screen.setElementHoveredStatus(widget, widgetHovered); + } + } + + public int getHoveredWidget(int mouseX) { + final float positionAcrossWidget = ((float) MathUtils.clamp(mouseX - cachedPosX, 0, cachedWidth)) / cachedWidth; + + return MathUtils.clamp((int) Math.floor(widgets.size() * positionAcrossWidget), 0, widgets.size() - 1); + } + + public boolean mouseClicked(double mouseX, double mouseY, int button) { + return this.widgets.get(getHoveredWidget((int) mouseX)).mouseClicked(mouseX, mouseY, button); + } + + public boolean mouseReleased(double mouseX, double mouseY, int button) { + return this.widgets.get(getHoveredWidget((int) mouseX)).mouseReleased(mouseX, mouseY, button); + } + +} diff --git a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/HeaderEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/HeaderEntry.java new file mode 100644 index 000000000..a42ce8e71 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/HeaderEntry.java @@ -0,0 +1,218 @@ +package net.coderbot.iris.gui.element.shaderoptions; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.gui.GuiUtil; +import net.coderbot.iris.gui.NavigationController; +import net.coderbot.iris.gui.element.IrisElementRow; +import net.coderbot.iris.gui.screen.ShaderPackScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.EnumChatFormatting; +import org.jetbrains.annotations.Nullable; + +public class HeaderEntry extends BaseEntry { + + public static final String BACK_BUTTON_TEXT = EnumChatFormatting.ITALIC + "< " + I18n.format("options.iris.back"); + public static final String RESET_BUTTON_TEXT_INACTIVE = EnumChatFormatting.GRAY + I18n.format("options.iris.reset"); + public static final String RESET_BUTTON_TEXT_ACTIVE = EnumChatFormatting.YELLOW + I18n.format("options.iris.reset"); + + public static final String RESET_HOLD_SHIFT_TOOLTIP = EnumChatFormatting.BOLD + I18n.format("options.iris.reset.tooltip.holdShift"); + public static final String RESET_TOOLTIP = EnumChatFormatting.RED + I18n.format("options.iris.reset.tooltip"); + public static final String IMPORT_TOOLTIP = I18n.format("options.iris.importSettings.tooltip"); + // .withStyle(style -> style.withColor(TextColor.fromRgb(0x4da6ff))); + public static final String EXPORT_TOOLTIP = I18n.format("options.iris.exportSettings.tooltip"); + // .withStyle(style -> style.withColor(TextColor.fromRgb(0xfc7d3d))); + + private static final int MIN_SIDE_BUTTON_WIDTH = 42; + private static final int BUTTON_HEIGHT = 16; + + private final ShaderPackScreen screen; + private final @Nullable IrisElementRow backButton; + private final IrisElementRow utilityButtons = new IrisElementRow(); + private final IrisElementRow.TextButtonElement resetButton; + private final IrisElementRow.IconButtonElement importButton; + private final IrisElementRow.IconButtonElement exportButton; + private final String text; + + public HeaderEntry(ShaderPackScreen screen, NavigationController navigation, String text, boolean hasBackButton) { + super(navigation); + + if (hasBackButton) { + this.backButton = new IrisElementRow().add(new IrisElementRow.TextButtonElement(BACK_BUTTON_TEXT, this::backButtonClicked), + Math.max(MIN_SIDE_BUTTON_WIDTH, Minecraft.getMinecraft().fontRenderer.getStringWidth(BACK_BUTTON_TEXT) + 8)); + } else { + this.backButton = null; + } + + this.resetButton = new IrisElementRow.TextButtonElement(RESET_BUTTON_TEXT_INACTIVE, this::resetButtonClicked); + this.importButton = new IrisElementRow.IconButtonElement(GuiUtil.Icon.IMPORT, GuiUtil.Icon.IMPORT_COLORED, this::importSettingsButtonClicked); + this.exportButton = new IrisElementRow.IconButtonElement(GuiUtil.Icon.EXPORT, GuiUtil.Icon.EXPORT_COLORED, this::exportSettingsButtonClicked); + + this.utilityButtons.add(this.importButton, 15).add(this.exportButton, 15) + .add(this.resetButton, Math.max(MIN_SIDE_BUTTON_WIDTH, Minecraft.getMinecraft().fontRenderer.getStringWidth((RESET_BUTTON_TEXT_INACTIVE) + 8))); + + this.screen = screen; + this.text = text; + } + + public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int slotWidth, int slotHeight, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver) { + // Draw dividing line + // fill(x - 3, (y + slotHeight) - 2, x + slotWidth, (y + slotHeight) - 1, 0x66BEBEBE); + final int tickDelta = 0; + final FontRenderer font = Minecraft.getMinecraft().fontRenderer; + + // Draw header text + this.screen.drawCenteredString(font, text, x + (int) (slotWidth * 0.5), y + 5, 0xFFFFFF); + + GuiUtil.bindIrisWidgetsTexture(); + + // Draw back button if present + if (this.backButton != null) { + backButton.drawScreen(x, y, BUTTON_HEIGHT, mouseX, mouseY, tickDelta, isMouseOver); + } + + final boolean shiftDown = GuiScreen.isShiftKeyDown(); + + // Set the appearance of the reset button + this.resetButton.disabled = !shiftDown; + this.resetButton.text = shiftDown ? RESET_BUTTON_TEXT_ACTIVE : RESET_BUTTON_TEXT_INACTIVE; + + // Draw the utility buttons + this.utilityButtons.renderRightAligned((x + slotWidth) - 3, y, BUTTON_HEIGHT, mouseX, mouseY, tickDelta, isMouseOver); + + // Draw the reset button's tooltip + if (this.resetButton.isHovered()) { + final String tooltip = shiftDown ? RESET_TOOLTIP : RESET_HOLD_SHIFT_TOOLTIP; + queueBottomRightAnchoredTooltip(mouseX, mouseY, font, tooltip); + } + // Draw the import/export button tooltips + if (this.importButton.isHovered()) { + queueBottomRightAnchoredTooltip(mouseX, mouseY, font, IMPORT_TOOLTIP); + } + if (this.exportButton.isHovered()) { + queueBottomRightAnchoredTooltip(mouseX, mouseY, font, EXPORT_TOOLTIP); + } + } + + private void queueBottomRightAnchoredTooltip(int x, int y, FontRenderer font, String text) { + ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel(font, text, x - (font.getStringWidth(text) + 10), y - 16)); + } + + public boolean mouseClicked(double mouseX, double mouseY, int button) { + final boolean backButtonResult = backButton != null && backButton.mouseClicked(mouseX, mouseY, button); + final boolean utilButtonResult = utilityButtons.mouseClicked(mouseX, mouseY, button); + + return backButtonResult || utilButtonResult; + } + + private boolean backButtonClicked(IrisElementRow.TextButtonElement button) { + this.navigation.back(); + GuiUtil.playButtonClickSound(); + + return true; + } + + private boolean resetButtonClicked(IrisElementRow.TextButtonElement button) { + if (GuiScreen.isShiftKeyDown()) { + Iris.resetShaderPackOptionsOnNextReload(); + this.screen.applyChanges(); + GuiUtil.playButtonClickSound(); + + return true; + } + + return false; + } + + private boolean importSettingsButtonClicked(IrisElementRow.IconButtonElement button) { + // GuiUtil.playButtonClickSound(); + // + // // Invalid state to be in + // if (!Iris.getCurrentPack().isPresent()) { + // return false; + // } + // + // // Displaying a dialog when the game is full-screened can cause severe issues + // // https://github.com/IrisShaders/Iris/issues/1258 + // if (Minecraft.getMinecraft().isFullScreen()) { + // this.screen.displayNotification( + // "" + EnumChatFormatting.RED + EnumChatFormatting.BOLD + I18n.format("options.iris.mustDisableFullscreen"); + // return false; + // } + // + // final ShaderPackScreen originalScreen = this.screen; // Also used to prevent invalid state + // + // FileDialogUtil.fileSelectDialog( + // FileDialogUtil.DialogType.OPEN, "Import Shader Settings from File", + // Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"), + // "Shader Pack Settings (.txt)", "*.txt") + // .whenComplete((path, err) -> { + // if (err != null) { + // Iris.logger.error("Error selecting shader settings from file", err); + // + // return; + // } + // + // if (Minecraft.getInstance().screen == originalScreen) { + // path.ifPresent(originalScreen::importPackOptions); + // } + // }); + // + return true; + } + + private boolean exportSettingsButtonClicked(IrisElementRow.IconButtonElement button) { + // GuiUtil.playButtonClickSound(); + // + // // Invalid state to be in + // if (!Iris.getCurrentPack().isPresent()) { + // return false; + // } + // + // // Displaying a dialog when the game is full-screened can cause severe issues + // // https://github.com/IrisShaders/Iris/issues/1258 + // if (Minecraft.getInstance().getWindow().isFullscreen()) { + // this.screen.displayNotification( + // I18n.format("options.iris.mustDisableFullscreen") + // .withStyle(ChatFormatting.RED).withStyle(ChatFormatting.BOLD)); + // return false; + // } + // + // FileDialogUtil.fileSelectDialog( + // FileDialogUtil.DialogType.SAVE, "Export Shader Settings to File", + // Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"), + // "Shader Pack Settings (.txt)", "*.txt") + // .whenComplete((path, err) -> { + // if (err != null) { + // Iris.logger.error("Error selecting file to export shader settings", err); + // + // return; + // } + // + // path.ifPresent(p -> { + // Properties toSave = new Properties(); + // + // // Dirty way of getting the currently applied settings as a Properties, directly + // // opens and copies out of the saved settings file if it is present + // Path sourceTxtPath = Iris.getShaderpacksDirectory().resolve(Iris.getCurrentPackName() + ".txt"); + // if (Files.exists(sourceTxtPath)) { + // try (InputStream in = Files.newInputStream(sourceTxtPath)) { + // toSave.load(in); + // } catch (IOException ignored) {} + // } + // + // // Save properties to user determined file + // try (OutputStream out = Files.newOutputStream(p)) { + // toSave.store(out, null); + // } catch (IOException e) { + // Iris.logger.error("Error saving properties to \"" + p + "\"", e); + // } + // }); + // }); + + return true; + } +} diff --git a/src/main/java/net/coderbot/iris/gui/entry/BaseEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderselection/BaseEntry.java similarity index 89% rename from src/main/java/net/coderbot/iris/gui/entry/BaseEntry.java rename to src/main/java/net/coderbot/iris/gui/element/shaderselection/BaseEntry.java index 2b3e2aae3..5df911356 100644 --- a/src/main/java/net/coderbot/iris/gui/entry/BaseEntry.java +++ b/src/main/java/net/coderbot/iris/gui/element/shaderselection/BaseEntry.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.gui.entry; +package net.coderbot.iris.gui.element.shaderselection; import net.coderbot.iris.gui.element.IrisGuiSlot; import net.coderbot.iris.gui.screen.ShaderPackScreen; diff --git a/src/main/java/net/coderbot/iris/gui/entry/LabelEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderselection/LabelEntry.java similarity index 91% rename from src/main/java/net/coderbot/iris/gui/entry/LabelEntry.java rename to src/main/java/net/coderbot/iris/gui/element/shaderselection/LabelEntry.java index 5ab1a0f60..a94acf858 100644 --- a/src/main/java/net/coderbot/iris/gui/entry/LabelEntry.java +++ b/src/main/java/net/coderbot/iris/gui/element/shaderselection/LabelEntry.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.gui.entry; +package net.coderbot.iris.gui.element.shaderselection; import net.coderbot.iris.gui.element.IrisGuiSlot; import net.coderbot.iris.gui.screen.ShaderPackScreen; diff --git a/src/main/java/net/coderbot/iris/gui/entry/ShaderPackEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderselection/ShaderPackEntry.java similarity index 91% rename from src/main/java/net/coderbot/iris/gui/entry/ShaderPackEntry.java rename to src/main/java/net/coderbot/iris/gui/element/shaderselection/ShaderPackEntry.java index e3e62fb1a..dcb952870 100644 --- a/src/main/java/net/coderbot/iris/gui/entry/ShaderPackEntry.java +++ b/src/main/java/net/coderbot/iris/gui/element/shaderselection/ShaderPackEntry.java @@ -1,10 +1,11 @@ -package net.coderbot.iris.gui.entry; +package net.coderbot.iris.gui.element.shaderselection; import lombok.Getter; import net.coderbot.iris.gui.element.ShaderPackSelectionList; import net.coderbot.iris.gui.screen.ShaderPackScreen; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.EnumChatFormatting; public class ShaderPackEntry extends BaseEntry { @Getter private final String packName; @@ -38,7 +39,7 @@ public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int list } if(isMouseOver) { - name = "§l" + name; + name = EnumChatFormatting.BOLD + name; } if(this.isApplied()) { diff --git a/src/main/java/net/coderbot/iris/gui/entry/TopButtonRowEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderselection/TopButtonRowEntry.java similarity index 96% rename from src/main/java/net/coderbot/iris/gui/entry/TopButtonRowEntry.java rename to src/main/java/net/coderbot/iris/gui/element/shaderselection/TopButtonRowEntry.java index 0d732ce83..28470e6a9 100644 --- a/src/main/java/net/coderbot/iris/gui/entry/TopButtonRowEntry.java +++ b/src/main/java/net/coderbot/iris/gui/element/shaderselection/TopButtonRowEntry.java @@ -1,4 +1,4 @@ -package net.coderbot.iris.gui.entry; +package net.coderbot.iris.gui.element.shaderselection; import net.coderbot.iris.gui.GuiUtil; import net.coderbot.iris.gui.element.IrisElementRow; @@ -59,7 +59,7 @@ public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int list this.buttons.setWidth(this.enableDisableButton, (listWidth - 1) - REFRESH_BUTTON_WIDTH); this.enableDisableButton.centerX = x + (int)(listWidth * 0.5); - this.buttons.render(x - 2, y - 3, 18, mouseX, mouseY, 0, isMouseOver); + this.buttons.drawScreen(x - 2, y - 3, 18, mouseX, mouseY, 0, isMouseOver); } private String getEnableDisableLabel() { diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java index b72a3df79..6e3b807f8 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java @@ -9,7 +9,7 @@ public abstract class AbstractElementWidget { public static final AbstractElementWidget EMPTY = new AbstractElementWidget(null) { @Override - public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) {} + public void drawScreen(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) {} }; public AbstractElementWidget(T element) { @@ -18,7 +18,7 @@ public AbstractElementWidget(T element) { public void init(ShaderPackScreen screen, NavigationController navigation) {} - public abstract void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered); + public abstract void drawScreen(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered); public boolean mouseClicked(double mx, double my, int button) { return false; diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java index 2fe9f9235..729528bc5 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java @@ -155,7 +155,7 @@ public boolean mouseClicked(double mx, double my, int button) { // if (button == GLFW.GLFW_MOUSE_BUTTON_1 || button == GLFW.GLFW_MOUSE_BUTTON_2) { // boolean refresh = false; // -// if (Screen.hasShiftDown()) { +// if (GuiScreen.isShiftKeyDown()) { // refresh = applyOriginalValue(); // } // if (!refresh) { diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java index fa87d7509..27bf9e6f6 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/BooleanElementWidget.java @@ -44,7 +44,7 @@ public void init(ShaderPackScreen screen, NavigationController navigation) { } @Override - public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + public void drawScreen(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { this.updateRenderParams(width, 28); this.renderOptionWithValue(x, y, width, height, hovered); diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java index 5b054473e..bbe44813a 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java @@ -33,7 +33,7 @@ public void init(ShaderPackScreen screen, NavigationController navigation) { } @Override - public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + public void drawScreen(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { GuiUtil.bindIrisWidgetsTexture(); GuiUtil.drawButton(x, y, width, height, hovered, false); diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java index 0b2d54e30..1e1310d6a 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/ProfileElementWidget.java @@ -45,7 +45,7 @@ public void init(ShaderPackScreen screen, NavigationController navigation) { } @Override - public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + public void drawScreen(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { this.updateRenderParams(width, width - (Minecraft.getMinecraft().fontRenderer.getStringWidth(PROFILE_LABEL) + 16)); this.renderOptionWithValue(x, y, width, height, hovered); diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java index 9bb43b96a..d8cad8396 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java @@ -18,7 +18,7 @@ public SliderElementWidget(OptionMenuStringOptionElement element) { } @Override - public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + public void drawScreen(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { this.updateRenderParams(width, 35); if (!hovered) { diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java index 5dc5ca2a4..a1de6088f 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/StringElementWidget.java @@ -42,7 +42,7 @@ public void init(ShaderPackScreen screen, NavigationController navigation) { } @Override - public void render(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { + public void drawScreen(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered) { this.updateRenderParams(width, 0); this.renderOptionWithValue(x, y, width, height, hovered); diff --git a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java index 3d744b3a3..ed7b7df5c 100644 --- a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java +++ b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java @@ -10,7 +10,7 @@ import net.coderbot.iris.gui.element.widget.AbstractElementWidget; import net.coderbot.iris.gui.element.widget.CommentedElementWidget; import net.coderbot.iris.gui.element.widget.IrisButton; -import net.coderbot.iris.gui.entry.ShaderPackEntry; +import net.coderbot.iris.gui.element.shaderselection.ShaderPackEntry; import net.coderbot.iris.shaderpack.ShaderPack; import net.irisshaders.iris.api.v0.IrisApi; import net.minecraft.client.gui.FontRenderer; @@ -23,16 +23,12 @@ import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Optional; -import java.util.Properties; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -144,7 +140,7 @@ public void drawScreen(int mouseX, int mouseY, float delta) { } } - // Render everything queued to render last + // Render everything queued to drawScreen last for (Runnable render : TOP_LAYER_RENDER_QUEUE) { render.run(); } From 0027e774092fd516c42f2cc7738d998a4b6f8e72 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 15 Dec 2023 09:23:11 -0800 Subject: [PATCH 267/301] Shader Options almost working ** Clicking on everything doesn't yet work, and the visuals are slightly off --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../mixins/early/shaders/MixinLocale.java | 82 +++++++++++++++++++ .../gui/element/ShaderPackOptionList.java | 12 +-- .../gui/element/shaderoptions/BaseEntry.java | 3 + .../shaderoptions/ElementRowEntry.java | 6 +- .../element/widget/OptionMenuConstructor.java | 12 +-- .../coderbot/iris/shaderpack/LanguageMap.java | 10 +-- 7 files changed, 106 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinLocale.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 9bb49d2c2..445591fc2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -119,6 +119,7 @@ public enum Mixins { "shaders.MixinEntityRenderer" ,"shaders.MixinFramebuffer" ,"shaders.MixinItem" + ,"shaders.MixinLocale" ,"shaders.MixinOpenGlHelper" ,"shaders.MixinRenderGlobal" ) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinLocale.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinLocale.java new file mode 100644 index 000000000..eab97ec11 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinLocale.java @@ -0,0 +1,82 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.shaderpack.LanguageMap; +import net.coderbot.iris.shaderpack.ShaderPack; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.client.resources.Locale; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +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.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +@Mixin(Locale.class) +public class MixinLocale { + // storage + @Shadow Map field_135032_a; + + @Unique + private static final List languageCodes = new ArrayList<>(); + + @Inject(method = "translateKeyPrivate", at = @At("HEAD"), cancellable = true) + private void iris$overrideLanguageEntries(String key, CallbackInfoReturnable cir) { + final String override = iris$lookupOverriddenEntry(key); + + if (override != null) { + cir.setReturnValue(override); + } + } + + @Unique + private String iris$lookupOverriddenEntry(String key) { + final ShaderPack pack = Iris.getCurrentPack().orElse(null); + + if (pack == null) { + // If no shaderpack is loaded, do not try to process language overrides. + // + // This prevents a cryptic NullPointerException when shaderpack loading fails for some reason. + return null; + } + + // Minecraft loads the "en_US" language code by default, and any other code will be right after it. + // + // So we also check if the user is loading a special language, and if the shaderpack has support for that + // language. If they do, we load that, but if they do not, we load "en_US" instead. + final LanguageMap languageMap = pack.getLanguageMap(); + + if (field_135032_a.containsKey(key)) { + return null; + } + + for (String code : languageCodes) { + final Map translations = languageMap.getTranslations(code); + + if (translations != null) { + final String translation = translations.get(key); + + if (translation != null) { + return translation; + } + } + } + + return null; + } + + @Inject(method = "loadLocaleDataFiles", at = @At("HEAD")) + private void iris$addLanguageCodes(IResourceManager resourceManager, List definitions, CallbackInfo ci) { + languageCodes.clear(); + + // Reverse order due to how minecraft has English and then the primary language in the language definitions list + new LinkedList<>(definitions).descendingIterator().forEachRemaining(languageCodes::add); + } + +} diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java index 29c5fb10a..8049cafd5 100644 --- a/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java +++ b/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java @@ -11,7 +11,6 @@ import net.coderbot.iris.shaderpack.ShaderPack; import net.coderbot.iris.shaderpack.option.menu.OptionMenuContainer; import net.minecraft.client.Minecraft; - import net.minecraft.client.renderer.Tessellator; import java.util.ArrayList; @@ -38,6 +37,7 @@ public void applyShaderPack(ShaderPack pack) { } public void rebuild() { + this.entries.clear(); // this.clearEntries(); // this.setScrollAmount(0); OptionMenuConstructor.constructAndApplyToScreen(this.container, this.screen, this, navigation); @@ -84,17 +84,19 @@ public void addWidgets(int columns, List> elements) { @Override protected int getSize() { - return 0; + return entries.size(); } @Override - protected void elementClicked(int p_148144_1_, boolean p_148144_2_, int p_148144_3_, int p_148144_4_) { + protected void elementClicked(int index, boolean doubleClick, int mouseX, int mouseY) { + final BaseEntry entry = this.entries.get(index); + entry.mouseClicked(mouseX, mouseY, 0); } @Override - protected boolean isSelected(int p_148131_1_) { - return false; + protected boolean isSelected(int idx) { + return false;//return this.entries.get(idx).equals(this.selected); } @Override diff --git a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java index 22589280b..3120383b7 100644 --- a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java +++ b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java @@ -11,5 +11,8 @@ protected BaseEntry(NavigationController navigation) { this.navigation = navigation; } + public abstract boolean mouseClicked(double mouseX, double mouseY, int button); + + public abstract void drawEntry(ShaderPackScreen screen, int index, int x, int y, int slotWidth, int slotHeight, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver); } diff --git a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java index 5af2bedb7..1b39da200 100644 --- a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java +++ b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java @@ -1,10 +1,10 @@ package net.coderbot.iris.gui.element.shaderoptions; -import buildcraft.core.lib.utils.MathUtils; import net.coderbot.iris.gui.NavigationController; import net.coderbot.iris.gui.element.widget.AbstractElementWidget; import net.coderbot.iris.gui.screen.ShaderPackScreen; import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.MathHelper; import java.util.List; @@ -46,9 +46,9 @@ public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int slot } public int getHoveredWidget(int mouseX) { - final float positionAcrossWidget = ((float) MathUtils.clamp(mouseX - cachedPosX, 0, cachedWidth)) / cachedWidth; + final float positionAcrossWidget = ((float) MathHelper.clamp_int(mouseX - cachedPosX, 0, cachedWidth)) / cachedWidth; - return MathUtils.clamp((int) Math.floor(widgets.size() * positionAcrossWidget), 0, widgets.size() - 1); + return MathHelper.clamp_int((int) Math.floor(widgets.size() * positionAcrossWidget), 0, widgets.size() - 1); } public boolean mouseClicked(double mouseX, double mouseY, int button) { diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java b/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java index ad83db59f..380c5b593 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/OptionMenuConstructor.java @@ -54,12 +54,12 @@ public static void constructAndApplyToScreen(OptionMenuContainer container, Shad ElementWidgetScreenData data = createScreenData(screen); -// optionList.addHeader(data.heading, data.backButton); -// optionList.addWidgets(screen.getColumnCount(), screen.elements.stream().map(element -> { -// AbstractElementWidget widget = (AbstractElementWidget) createWidget(element); -// widget.init(packScreen, navigation); -// return widget; -// }).collect(Collectors.toList())); + optionList.addHeader(data.heading, data.backButton); + optionList.addWidgets(screen.getColumnCount(), screen.elements.stream().map(element -> { + AbstractElementWidget widget = (AbstractElementWidget) createWidget(element); + widget.init(packScreen, navigation); + return widget; + }).collect(Collectors.toList())); } static { diff --git a/src/main/java/net/coderbot/iris/shaderpack/LanguageMap.java b/src/main/java/net/coderbot/iris/shaderpack/LanguageMap.java index 09797e6b0..c1468acfc 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/LanguageMap.java +++ b/src/main/java/net/coderbot/iris/shaderpack/LanguageMap.java @@ -32,19 +32,17 @@ public LanguageMap(Path root) throws IOException { // There is also Files.list which can be used for similar behavior try (Stream stream = Files.list(root)) { stream.filter(path -> !Files.isDirectory(path)).forEach(path -> { - // Shader packs use legacy file name coding which is different than modern minecraft's. - // An example of this is using "en_US.lang" compared to "en_us.json" // Also note that OptiFine uses a property scheme for loading language entries to keep parity with other // OptiFine features - String currentFileName = path.getFileName().toString().toLowerCase(Locale.ROOT); + final String currentFileName = path.getFileName().toString(); if (!currentFileName.endsWith(".lang")) { // This file lacks a .lang file extension and should be ignored. return; } - String currentLangCode = currentFileName.substring(0, currentFileName.lastIndexOf(".")); - Properties properties = new Properties(); + final String currentLangCode = currentFileName.substring(0, currentFileName.lastIndexOf(".")); + final Properties properties = new Properties(); // Use InputStreamReader to avoid the default charset of ISO-8859-1. // This is needed since shader language files are specified to be in UTF-8. @@ -54,7 +52,7 @@ public LanguageMap(Path root) throws IOException { Iris.logger.error("Failed to parse shader pack language file " + path, e); } - ImmutableMap.Builder builder = ImmutableMap.builder(); + final ImmutableMap.Builder builder = ImmutableMap.builder(); properties.forEach((key, value) -> builder.put(key.toString(), value.toString())); From fedbafcefb4c75ae81b78afb267e50d14812ad70 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Fri, 15 Dec 2023 17:43:54 -0800 Subject: [PATCH 268/301] Entity shadows seem to be working --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 + .../render/chunk/ChunkRenderManager.java | 8 ++-- .../coderbot/iris/gl/IrisRenderSystem.java | 8 ++-- .../iris/pipeline/ShadowRenderer.java | 37 ++++++++++++------- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 445591fc2..27e22908c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -121,6 +121,7 @@ public enum Mixins { ,"shaders.MixinItem" ,"shaders.MixinLocale" ,"shaders.MixinOpenGlHelper" + ,"shaders.MixinRender" ,"shaders.MixinRenderGlobal" ) ), diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 2ff703613..0650284f3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -499,11 +499,11 @@ private ChunkRenderContainer createChunkRender(ChunkRenderColumn column, i } public void renderLayer(MatrixStack matrixStack, BlockRenderPass pass, double x, double y, double z) { - ChunkRenderList chunkRenderList = this.chunkRenderLists[pass.ordinal()]; - ChunkRenderListIterator iterator = chunkRenderList.iterator(pass.isTranslucent()); + final ChunkRenderList chunkRenderList = this.chunkRenderLists[pass.ordinal()]; + final ChunkRenderListIterator iterator = chunkRenderList.iterator(pass.isTranslucent()); - RenderDevice device = RenderDevice.INSTANCE; - CommandList commandList = device.createCommandList(); + final RenderDevice device = RenderDevice.INSTANCE; + final CommandList commandList = device.createCommandList(); if(AngelicaConfig.enableIris) this.backend.iris$begin(matrixStack, pass); else this.backend.begin(matrixStack); diff --git a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java index 374918fb6..75c35a14c 100644 --- a/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java +++ b/src/main/java/net/coderbot/iris/gl/IrisRenderSystem.java @@ -233,13 +233,13 @@ public static void bindTextureToUnit(int unit, int texture) { dsaState.bindTextureToUnit(unit, texture); } + public static FloatBuffer PROJECTION_MATRIX_BUFFER = BufferUtils.createFloatBuffer(16); public static void setupProjectionMatrix(Matrix4f matrix) { GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glPushMatrix(); - // TODO: allocations - FloatBuffer buffer = BufferUtils.createFloatBuffer(16); - matrix.get(buffer); - GL11.glLoadMatrix(buffer); + PROJECTION_MATRIX_BUFFER.clear().rewind(); + matrix.get(PROJECTION_MATRIX_BUFFER); + GL11.glLoadMatrix(PROJECTION_MATRIX_BUFFER); GL11.glMatrixMode(GL11.GL_MODELVIEW); } diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index b4a547d43..063c7f264 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -30,6 +30,7 @@ import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.culling.Frustrum; +import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.entity.Entity; import net.minecraft.profiler.Profiler; @@ -45,13 +46,16 @@ import org.lwjgl.opengl.GL14; import org.lwjgl.opengl.GL30; +import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Objects; public class ShadowRenderer { public static final Matrix4f MODELVIEW = new Matrix4f(); + public static FloatBuffer MODELVIEW_BUFFER = BufferUtils.createFloatBuffer(16); public static final Matrix4f PROJECTION = new Matrix4f(); public static List visibleTileEntities; public static boolean ACTIVE = false; @@ -357,27 +361,33 @@ private void renderEntities(EntityRenderer levelRenderer, Frustrum frustum, Buff // TODO: I'm sure that this can be improved / optimized. // TODO: Render -// for (Entity entity : getLevel().entitiesForRendering()) { -// if (!dispatcher.shouldRender(entity, frustum, cameraX, cameraY, cameraZ) || entity.isSpectator()) { -// continue; -// } -// -// renderedEntities.add(entity); -// } + // TODO: Entity culling + for (Entity entity : getLevel().loadedEntityList) { + if (false/*!dispatcher.shouldRender(entity, frustum, cameraX, cameraY, cameraZ) || entity.isSpectator()*/) { + continue; + } + + renderedEntities.add(entity); + } profiler.endStartSection("sort"); // TODO: Render // Sort the entities by type first in order to allow vanilla's entity batching system to work better. -// renderedEntities.sort(Comparator.comparingInt(entity -> entity.getType().hashCode())); + renderedEntities.sort(Comparator.comparingInt(entity -> entity.getClass().hashCode())); profiler.endStartSection("build geometry"); // TODO: Render -// for (Entity entity : renderedEntities) { -// levelRenderer.invokeRenderEntity(entity, cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); -// shadowEntities++; -// } + GL11.glPushMatrix(); + MODELVIEW_BUFFER.clear().rewind(); + modelView.peek().getModel().get(MODELVIEW_BUFFER); + GL11.glLoadMatrix(MODELVIEW_BUFFER); + for (Entity entity : renderedEntities) { + RenderManager.instance.renderEntitySimple(entity, tickDelta);//(entity, cameraX, cameraY, cameraZ, tickDelta, modelView, bufferSource); + shadowEntities++; + } + GL11.glPopMatrix(); renderedShadowEntities = shadowEntities; @@ -567,9 +577,10 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // } // BufferSource bufferSource = buffers.bufferSource(); + BufferSource bufferSource = null; if (shouldRenderEntities) { -// renderEntities(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); + renderEntities(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); } else if (shouldRenderPlayer) { // renderPlayerEntity(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); } From 0795c82986afe6985ec1dfcf6ec441fd555fc6f9 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 16 Dec 2023 15:03:54 -0800 Subject: [PATCH 269/301] Add missing mixin --- .../mixins/early/shaders/MixinRender.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRender.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRender.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRender.java new file mode 100644 index 000000000..c1af075a1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRender.java @@ -0,0 +1,22 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders; + +import net.coderbot.iris.Iris; +import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.minecraft.client.renderer.entity.Render; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Render.class) +public class MixinRender { + @Inject(method = "renderShadow(Lnet/minecraft/entity/Entity;DDDFF)V", at = @At("HEAD"), cancellable = true) + private void angelica$checkShouldSkipDefaultShadow(CallbackInfo ci) { + final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable(); + + if (pipeline != null && pipeline.shouldDisableVanillaEntityShadows()) { + ci.cancel(); + } + } + +} From f93bf516328d2a9184c16f7462ba184bf37ff84a Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Sat, 16 Dec 2023 18:10:21 -0500 Subject: [PATCH 270/301] Move glint fix to Mixin --- .../loading/MixinCompatHackTweaker.java | 2 - .../gtnewhorizons/angelica/mixins/Mixins.java | 3 +- .../mixins/dummy/DummyTessellator.java | 25 ++ .../angelica/hudcaching/MixinRenderItem.java | 56 +++++ .../transform/RenderItemTransformer.java | 219 ------------------ 5 files changed, 83 insertions(+), 222 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/dummy/DummyTessellator.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java diff --git a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java index 668acc0db..2807bd169 100644 --- a/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java +++ b/src/main/java/com/gtnewhorizons/angelica/loading/MixinCompatHackTweaker.java @@ -4,7 +4,6 @@ import cpw.mods.fml.common.Loader; import cpw.mods.fml.relauncher.FMLLaunchHandler; import net.minecraft.launchwrapper.IClassTransformer; -import com.gtnewhorizons.angelica.transform.RenderItemTransformer; import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; @@ -74,7 +73,6 @@ public String getLaunchTarget() { public String[] getLaunchArguments() { if (FMLLaunchHandler.side().isClient()) { // Run after Mixins, but before LWJGl3ify - Launch.classLoader.registerTransformer(RenderItemTransformer.class.getName()); Launch.classLoader.registerTransformer(RedirectorTransformer.class.getName()); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 27e22908c..4d181e0ec 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -151,7 +151,8 @@ public enum Mixins { "angelica.hudcaching.MixinEntityRenderer_HUDCaching", "angelica.hudcaching.MixinFramebuffer_HUDCaching", "angelica.hudcaching.MixinGuiIngame_HUDCaching", - "angelica.hudcaching.MixinGuiIngameForge_HUDCaching") + "angelica.hudcaching.MixinGuiIngameForge_HUDCaching", + "angelica.hudcaching.MixinRenderItem") ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/dummy/DummyTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/dummy/DummyTessellator.java new file mode 100644 index 000000000..a4017740f --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/dummy/DummyTessellator.java @@ -0,0 +1,25 @@ +package com.gtnewhorizons.angelica.mixins.dummy; + +import net.minecraft.client.renderer.Tessellator; + +/** + * No-op tessellator to replace the inconvienent one + */ +public class DummyTessellator extends Tessellator { + + public static Tessellator instance = new DummyTessellator(); + + @Override + public void startDrawingQuads() {} + + @Override + public void setColorOpaque_I(int whocares) {} + + @Override + public void addVertex(double thing1, double thing2, double thereaintnothing3) {} + + @Override + public int draw() { + return 0; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java new file mode 100644 index 000000000..21510cf4b --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java @@ -0,0 +1,56 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.hudcaching; + +import com.gtnewhorizons.angelica.mixins.dummy.DummyTessellator; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.entity.RenderItem; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.*; + +import static org.lwjgl.opengl.GL11.*; + +@Mixin(RenderItem.class) +public class MixinRenderItem { + + @ModifyExpressionValue( + method = "renderItemIntoGUI(Lnet/minecraft/client/gui/FontRenderer;Lnet/minecraft/client/renderer/texture/TextureManager;Lnet/minecraft/item/ItemStack;IIZ)V", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;instance:Lnet/minecraft/client/renderer/Tessellator;") + ) + private Tessellator angelica$neuterTesselator(Tessellator useless) { + return DummyTessellator.instance; + } + + @Redirect( + method = "renderItemIntoGUI(Lnet/minecraft/client/gui/FontRenderer;Lnet/minecraft/client/renderer/texture/TextureManager;Lnet/minecraft/item/ItemStack;IIZ)V", + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V"), + slice = @Slice( + from = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;requiresMultipleRenderPasses()Z"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItem()Lnet/minecraft/item/Item;", ordinal = 4) + ) + ) + private void angelica$neuterGlDisable(int cap) { + if (cap == GL_LIGHTING) GL11.glDisable(cap); + } + + @Redirect( + method = "renderItemIntoGUI(Lnet/minecraft/client/gui/FontRenderer;Lnet/minecraft/client/renderer/texture/TextureManager;Lnet/minecraft/item/ItemStack;IIZ)V", + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V"), + slice = @Slice( + from = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Tessellator;startDrawingQuads()V", ordinal = 0), + to = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItem()Lnet/minecraft/item/Item;", ordinal = 4) + ) + ) + private void angelica$neuterGlEnable(int cap) {} + + @Redirect( + method = "renderItemIntoGUI(Lnet/minecraft/client/gui/FontRenderer;Lnet/minecraft/client/renderer/texture/TextureManager;Lnet/minecraft/item/ItemStack;IIZ)V", + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glColorMask(ZZZZ)V"), + slice = @Slice( + from = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;requiresMultipleRenderPasses()Z"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItem()Lnet/minecraft/item/Item;", ordinal = 4) + ) + ) + private void angelica$neuterGlColorMask(boolean red, boolean green, boolean blue, boolean alpha) {} +} diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java deleted file mode 100644 index d3450ced8..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RenderItemTransformer.java +++ /dev/null @@ -1,219 +0,0 @@ -package com.gtnewhorizons.angelica.transform; - -import net.minecraft.launchwrapper.IClassTransformer; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.IntInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; - -import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; -import static org.objectweb.asm.Opcodes.INVOKESTATIC; -import static org.objectweb.asm.Opcodes.GETSTATIC; - - -public class RenderItemTransformer implements IClassTransformer { - private static final String classToTransform = "net.minecraft.client.renderer.entity.RenderItem"; - @Override - public byte[] transform(String name, String transformedName, byte[] classBeingTransformed) - { - boolean isObfuscated = name.equals(transformedName); - return transformedName.equals(classToTransform) ? transform(classBeingTransformed, isObfuscated) : classBeingTransformed; - } - - private static byte[] transform(byte[] classBeingTranformed, boolean isObfuscated) - { - System.out.println("Transforming: " + classToTransform); - try - { - ClassNode classNode = new ClassNode(); - ClassReader classReader = new ClassReader(classBeingTranformed); - classReader.accept(classNode, 0); - - transformRenderItem(classNode, isObfuscated); - - ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - classNode.accept(classWriter); - return classWriter.toByteArray(); - } - catch (Exception e) - { - System.out.println("FATAL ERROR in RenderItemTransformer"); - e.printStackTrace(); - } - return classBeingTranformed; - } - - private static void transformRenderItem(ClassNode renderItemClass, boolean isObfuscated) - { - final String RENDER_ITEM_INTO_GUI = "renderItemIntoGUI"; - final String RENDER_ITEM_INTO_GUI_DESC = "(Lnet/minecraft/client/gui/FontRenderer;Lnet/minecraft/client/renderer/texture/TextureManager;Lnet/minecraft/item/ItemStack;IIZ)V"; - - for (MethodNode method : renderItemClass.methods) - { - if (method.name.equals(RENDER_ITEM_INTO_GUI) && method.desc.equals(RENDER_ITEM_INTO_GUI_DESC)) - { - AbstractInsnNode targetNode = null; - boolean tesselatorFound = false; - boolean glDisableFound = false; - boolean glColorMaskFound = false; - for (AbstractInsnNode instruction : method.instructions.toArray()) - { - if (instruction.getOpcode() == GETSTATIC) { - if (!tesselatorFound && ((FieldInsnNode) instruction).desc.equals("Lnet/minecraft/client/renderer/Tessellator;")) { - targetNode = instruction; - removeTesselatorAndCleanupCallsBlock(targetNode, method); - tesselatorFound = true; - break; - } - } - if (instruction.getOpcode() == INVOKESTATIC) - { - if (!glDisableFound && ((MethodInsnNode) instruction).name.equals("glDisable")) - { - if (instruction.getPrevious() instanceof IntInsnNode && ((IntInsnNode) instruction.getPrevious()).operand == 3553) - { - targetNode = instruction; - removeGLDisable(targetNode, method); - glDisableFound = true; - continue; - } - } - if (!glColorMaskFound && ((MethodInsnNode) instruction).name.equals("glColorMask")) - { - targetNode = instruction; - removeColorMask(targetNode, method); - glColorMaskFound = true; - } - } - } - } - } - } - - // This essnetially comments out the all tesselator calls completely in renderItemIntoGUI found in the - // drawScreen item class. More lines need to be removed in this transform like redundant GLState - // updating if these lines are commented out. This is just the inital testing to see if this - // change is smart or stupid. I really don't know, but the tesselator calls seem - // completely redundant. - - // All of this code is removing items from this block in drawScreen item: - - // else if (p_77015_3_.getItem().requiresMultipleRenderPasses()) - // { - // GL11.glDisable(GL11.GL_LIGHTING); - // GL11.glEnable(GL11.GL_ALPHA_TEST); - // p_77015_2_.bindTexture(TextureMap.locationItemsTexture); - // GL11.glDisable(GL11.GL_ALPHA_TEST); - // GL11.glDisable(GL11.GL_TEXTURE_2D); - // GL11.glEnable(GL11.GL_BLEND); - // OpenGlHelper.glBlendFunc(0, 0, 0, 0); - // GL11.glColorMask(false, false, false, true); - // GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - // Tessellator tessellator = Tessellator.instance; - // tessellator.startDrawingQuads(); - // tessellator.setColorOpaque_I(-1); - // tessellator.addVertex((double)(p_77015_4_ - 2), (double)(p_77015_5_ + 18), (double)this.zLevel); - // tessellator.addVertex((double)(p_77015_4_ + 18), (double)(p_77015_5_ + 18), (double)this.zLevel); - // tessellator.addVertex((double)(p_77015_4_ + 18), (double)(p_77015_5_ - 2), (double)this.zLevel); - // tessellator.addVertex((double)(p_77015_4_ - 2), (double)(p_77015_5_ - 2), (double)this.zLevel); - // tessellator.draw(); - // GL11.glColorMask(true, true, true, true); - // GL11.glEnable(GL11.GL_TEXTURE_2D); - // GL11.glEnable(GL11.GL_ALPHA_TEST); - // - // Item item = p_77015_3_.getItem(); - // for (l = 0; l < item.getRenderPasses(k); ++l) - - // It is changed to the following: - - // else if (p_77015_3_.getItem().requiresMultipleRenderPasses()) - // { - // GL11.glDisable(GL11.GL_LIGHTING); - // GL11.glEnable(GL11.GL_ALPHA_TEST); - // p_77015_2_.bindTexture(TextureMap.locationItemsTexture); - // GL11.glEnable(GL11.GL_BLEND); - // OpenGlHelper.glBlendFunc(0, 0, 0, 0); - // GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - // - // Item item = p_77015_3_.getItem(); - // for (l = 0; l < item.getRenderPasses(k); ++l) - - private static void removeTesselatorAndCleanupCallsBlock(AbstractInsnNode targetNode, MethodNode method) - { - try - { - if (targetNode != null) - { - method.instructions.remove(targetNode.getPrevious()); - method.instructions.remove(targetNode.getPrevious()); - while(!(targetNode.getNext().getNext().getNext().getOpcode() == INVOKEVIRTUAL && ((MethodInsnNode) targetNode.getNext().getNext().getNext()).name.equals("getItem"))) - { - targetNode = targetNode.getNext(); - method.instructions.remove(targetNode.getPrevious()); - } - } - else - { - throw new Exception(); - } - } - catch(Exception e) - { - System.out.println("Could not find the tesselator to remove"); - e.printStackTrace(); - } - } - - private static void removeGLDisable(AbstractInsnNode targetNode, MethodNode method) - { - try - { - if (targetNode != null) - { - while (!(targetNode.getOpcode() == INVOKEVIRTUAL && ((MethodInsnNode) targetNode).name.equals("bindTexture"))) - { - targetNode = targetNode.getPrevious(); - method.instructions.remove(targetNode.getNext()); - } - } - else - { - throw new Exception(); - } - } - catch(Exception e) - { - System.out.println("Could not find the correct GLDisable functions to remove"); - e.printStackTrace(); - } - - } - - private static void removeColorMask(AbstractInsnNode targetNode, MethodNode method) - { - try - { - if (targetNode != null) - { - while (!(targetNode.getOpcode() == INVOKESTATIC && ((MethodInsnNode) targetNode).name.equals("glBlendFunc"))) - { - targetNode = targetNode.getPrevious(); - method.instructions.remove(targetNode.getNext()); - } - } - else - { - throw new Exception(); - } - } - catch(Exception e) - { - System.out.println("Could not find the correct colorMask function to remove"); - e.printStackTrace(); - } - } -} From f2aa411bacfdcf6ae6fd7b4c2b7d08c3ec1d2838 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 16 Dec 2023 16:24:22 -0800 Subject: [PATCH 271/301] Rework mouse handling for ShaderPackConfig * Scrolling by clicking isn't currently wired up --- .../early/notfine/glint/MixinRenderItem.java | 9 +- .../iris/gui/element/IrisGuiSlot.java | 167 ++++++++++++++++++ .../gui/element/ShaderPackOptionList.java | 13 +- .../gui/element/ShaderPackSelectionList.java | 12 +- .../gui/element/shaderoptions/BaseEntry.java | 2 +- .../shaderoptions/ElementRowEntry.java | 8 +- .../element/shaderoptions/HeaderEntry.java | 2 +- .../element/widget/AbstractElementWidget.java | 2 +- .../widget/BaseOptionElementWidget.java | 48 ++--- .../gui/element/widget/IrisImageButton.java | 52 ++++++ .../gui/element/widget/LinkElementWidget.java | 4 +- .../element/widget/SliderElementWidget.java | 2 +- .../iris/gui/screen/ShaderPackScreen.java | 55 +++++- src/main/resources/META-INF/angelica_at.cfg | 10 ++ 14 files changed, 332 insertions(+), 54 deletions(-) create mode 100644 src/main/java/net/coderbot/iris/gui/element/widget/IrisImageButton.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java index a327caeab..a9cc227a7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/notfine/glint/MixinRenderItem.java @@ -1,15 +1,14 @@ package com.gtnewhorizons.angelica.mixins.early.notfine.glint; import jss.notfine.core.Settings; -import net.minecraft.item.ItemStack; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java b/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java index ef9b2b999..6cdfbd23f 100644 --- a/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java +++ b/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java @@ -4,7 +4,10 @@ import lombok.Setter; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiSlot; +import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.Tessellator; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; // TODO: look into GuiListExtended & GuiSelectStringEntries public abstract class IrisGuiSlot extends GuiSlot { @@ -35,5 +38,169 @@ protected void drawSelectionBox(int x, int y, int mouseX, int mouseY) { super.drawSelectionBox(x, y, mouseX, mouseY); this.headerPadding = oldPadding; } + @Override + protected void elementClicked(int index, boolean doubleClick, int mouseX, int mouseY) { + // Do nothing + } + + protected boolean elementClicked(int index, boolean doubleClick, int mouseX, int mouseY, int button) { + return false; + } + + public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) { + if(!this.func_148125_i/*enabled*/()) { + return false; + } + final int size = this.getSize(); + final int scrollBarX = this.getScrollBarX(); + final int rightEdge = scrollBarX + 6; + final int elementLeft = this.width / 2 - this.getListWidth() / 2; + final int elementRight = this.width / 2 + this.getListWidth() / 2; + final int relativeY = mouseY - this.top - this.headerPadding + (int) this.amountScrolled - 4; + boolean handled = false; + final boolean leftMouseDown = Mouse.isButtonDown(0); + final boolean rightMouseDown = Mouse.isButtonDown(1); + boolean scrolling = false; + + if (mouseX <= this.left || mouseX >= this.right || mouseY <= this.top || mouseY >= this.bottom) { + return handled; + } + if (leftMouseDown && mouseX >= scrollBarX && mouseX <= rightEdge) { + // TODO: Handle scrolling + scrolling = true; + } + + if ((leftMouseDown || rightMouseDown)) { + final int index = relativeY / this.slotHeight; + + if (mouseX >= elementLeft && mouseX <= elementRight && index >= 0 && relativeY >= 0 && index < size) { + final boolean doubleCLick = index == this.selectedElement && Minecraft.getSystemTime() - this.lastClicked < 250L; + + handled = this.elementClicked(index, doubleCLick, mouseX, mouseY, mouseButton); + this.selectedElement = index; + this.lastClicked = Minecraft.getSystemTime(); + } else if (mouseX >= elementLeft && mouseX <= elementRight && relativeY < 0) { + this.func_148132_a(mouseX - elementLeft, mouseY - this.top + (int) this.amountScrolled - 4); + } + } + + return handled; + } + + public boolean mouseReleased(int mouseX, int mouseY, int button) { + return false; + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + this.mouseX = mouseX; + this.mouseY = mouseY; + this.drawBackground(); + final int scrollBarX = this.getScrollBarX(); + final int rightEdge = scrollBarX + 6; + final byte offset = 4; + + // Scrollwheel nonsense + for (; !this.mc.gameSettings.touchscreen && Mouse.next(); this.mc.currentScreen.handleMouseInput()) { + int dWheel = Mouse.getEventDWheel(); + + if (dWheel != 0) { + if (dWheel > 0) { + dWheel = -1; + } else { + dWheel = 1; + } + + this.amountScrolled += (dWheel * this.slotHeight / 2.0f); + } + } + + + this.bindAmountScrolled(); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_FOG); + final Tessellator tessellator = Tessellator.instance; + drawContainerBackground(tessellator); + final int elementRight = this.left + this.width / 2 - this.getListWidth() / 2 + 2; + final int relativeY = this.top + 4 - (int) this.amountScrolled; + + if (this.hasListHeader) { + this.drawListHeader(elementRight, relativeY, tessellator); + } + + this.drawSelectionBox(elementRight, relativeY, mouseX, mouseY); + GL11.glDisable(GL11.GL_DEPTH_TEST); + this.overlayBackground(0, this.top, 255, 255); + this.overlayBackground(this.bottom, this.height, 255, 255); + GL11.glEnable(GL11.GL_BLEND); + OpenGlHelper.glBlendFunc(770, 771, 0, 1); + GL11.glDisable(GL11.GL_ALPHA_TEST); + GL11.glShadeModel(GL11.GL_SMOOTH); + GL11.glDisable(GL11.GL_TEXTURE_2D); + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_I(0, 0); + tessellator.addVertexWithUV(this.left, (this.top + offset), 0.0D, 0.0D, 1.0D); + tessellator.addVertexWithUV(this.right, (this.top + offset), 0.0D, 1.0D, 1.0D); + tessellator.setColorRGBA_I(0, 255); + tessellator.addVertexWithUV(this.right, this.top, 0.0D, 1.0D, 0.0D); + tessellator.addVertexWithUV(this.left, this.top, 0.0D, 0.0D, 0.0D); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_I(0, 255); + tessellator.addVertexWithUV(this.left, this.bottom, 0.0D, 0.0D, 1.0D); + tessellator.addVertexWithUV(this.right, this.bottom, 0.0D, 1.0D, 1.0D); + tessellator.setColorRGBA_I(0, 0); + tessellator.addVertexWithUV(this.right, (this.bottom - offset), 0.0D, 1.0D, 0.0D); + tessellator.addVertexWithUV(this.left, (this.bottom - offset), 0.0D, 0.0D, 0.0D); + tessellator.draw(); + + // Draw scrollbar if needed + final int contentOverflow = this.func_148135_f(); + if (contentOverflow > 0) { + registerScrollButtons(7, 8); + int scrollPosSize = (this.bottom - this.top) * (this.bottom - this.top) / this.getContentHeight(); + + if (scrollPosSize < 32) { + scrollPosSize = 32; + } + + if (scrollPosSize > this.bottom - this.top - 8) { + scrollPosSize = this.bottom - this.top - 8; + } + + int scrollPos = (int) this.amountScrolled * (this.bottom - this.top - scrollPosSize) / contentOverflow + this.top; + + if (scrollPos < this.top) { + scrollPos = this.top; + } + + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_I(0, 255); + tessellator.addVertexWithUV(scrollBarX, this.bottom, 0.0D, 0.0D, 1.0D); + tessellator.addVertexWithUV(rightEdge, this.bottom, 0.0D, 1.0D, 1.0D); + tessellator.addVertexWithUV(rightEdge, this.top, 0.0D, 1.0D, 0.0D); + tessellator.addVertexWithUV(scrollBarX, this.top, 0.0D, 0.0D, 0.0D); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_I(8421504, 255); + tessellator.addVertexWithUV(scrollBarX, (scrollPos + scrollPosSize), 0.0D, 0.0D, 1.0D); + tessellator.addVertexWithUV(rightEdge, (scrollPos + scrollPosSize), 0.0D, 1.0D, 1.0D); + tessellator.addVertexWithUV(rightEdge, scrollPos, 0.0D, 1.0D, 0.0D); + tessellator.addVertexWithUV(scrollBarX, scrollPos, 0.0D, 0.0D, 0.0D); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_I(12632256, 255); + tessellator.addVertexWithUV(scrollBarX, (scrollPos + scrollPosSize - 1), 0.0D, 0.0D, 1.0D); + tessellator.addVertexWithUV((rightEdge - 1), (scrollPos + scrollPosSize - 1), 0.0D, 1.0D, 1.0D); + tessellator.addVertexWithUV((rightEdge - 1), scrollPos, 0.0D, 1.0D, 0.0D); + tessellator.addVertexWithUV(scrollBarX, scrollPos, 0.0D, 0.0D, 0.0D); + tessellator.draw(); + } + + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glShadeModel(GL11.GL_FLAT); + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glDisable(GL11.GL_BLEND); + } } diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java index 8049cafd5..a3ec7fea3 100644 --- a/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java +++ b/src/main/java/net/coderbot/iris/gui/element/ShaderPackOptionList.java @@ -25,7 +25,7 @@ public class ShaderPackOptionList extends IrisGuiSlot { private final List entries = new ArrayList<>(); public ShaderPackOptionList(ShaderPackScreen screen, NavigationController navigation, ShaderPack pack, Minecraft client, int width, int height, int top, int bottom, int left, int right) { - super(client, width, height, top, bottom, 24); + super(client, width, height, top, bottom, 20); this.navigation = navigation; this.screen = screen; @@ -38,8 +38,7 @@ public void applyShaderPack(ShaderPack pack) { public void rebuild() { this.entries.clear(); -// this.clearEntries(); -// this.setScrollAmount(0); + this.amountScrolled = 0; OptionMenuConstructor.constructAndApplyToScreen(this.container, this.screen, this, navigation); } @@ -88,10 +87,9 @@ protected int getSize() { } @Override - protected void elementClicked(int index, boolean doubleClick, int mouseX, int mouseY) { + protected boolean elementClicked(int index, boolean doubleClick, int mouseX, int mouseY, int mouseButton) { final BaseEntry entry = this.entries.get(index); - entry.mouseClicked(mouseX, mouseY, 0); - + return entry.mouseClicked(mouseX, mouseY, mouseButton); } @Override @@ -101,7 +99,7 @@ protected boolean isSelected(int idx) { @Override protected void drawBackground() { - + // noop } @Override @@ -111,7 +109,6 @@ protected void drawSlot(int index, int x, int y, int i1, Tessellator tessellator entry.drawEntry(screen, index, x - 2, y + 4, this.getListWidth(), this.slotHeight, tessellator, mouseX, mouseY, isMouseOver); } -// } diff --git a/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java b/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java index d6bee9a27..44156e420 100644 --- a/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java +++ b/src/main/java/net/coderbot/iris/gui/element/ShaderPackSelectionList.java @@ -114,16 +114,22 @@ protected int getSize() { } @Override - protected void elementClicked(int index, boolean doubleClick, int mouseX, int mouseY) { + protected boolean elementClicked(int index, boolean doubleClick, int mouseX, int mouseY, int mouseButton) { + // Only do anything on left-click + if (mouseButton != 0) { + return false; + } final BaseEntry entry = this.entries.get(index); if(entry instanceof ShaderPackEntry shaderPackEntry) { this.setSelected(shaderPackEntry); if (!topButtonRow.shadersEnabled) { topButtonRow.setShadersEnabled(true); } + return true; } else if( entry instanceof TopButtonRowEntry topButtonRowEntry) { - topButtonRowEntry.mouseClicked(mouseX, mouseY, 0); + return topButtonRowEntry.mouseClicked(mouseX, mouseY, 0); } + return false; } @Override @@ -138,7 +144,7 @@ public int getListWidth() { @Override protected void drawBackground() { - + // Do nothing } diff --git a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java index 3120383b7..b1bc897b9 100644 --- a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java +++ b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/BaseEntry.java @@ -11,7 +11,7 @@ protected BaseEntry(NavigationController navigation) { this.navigation = navigation; } - public abstract boolean mouseClicked(double mouseX, double mouseY, int button); + public abstract boolean mouseClicked(int mouseX, int mouseY, int button); public abstract void drawEntry(ShaderPackScreen screen, int index, int x, int y, int slotWidth, int slotHeight, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver); diff --git a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java index 1b39da200..e75e69d0d 100644 --- a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java +++ b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/ElementRowEntry.java @@ -51,12 +51,12 @@ public int getHoveredWidget(int mouseX) { return MathHelper.clamp_int((int) Math.floor(widgets.size() * positionAcrossWidget), 0, widgets.size() - 1); } - public boolean mouseClicked(double mouseX, double mouseY, int button) { - return this.widgets.get(getHoveredWidget((int) mouseX)).mouseClicked(mouseX, mouseY, button); + public boolean mouseClicked(int mouseX, int mouseY, int button) { + return this.widgets.get(getHoveredWidget(mouseX)).mouseClicked(mouseX, mouseY, button); } - public boolean mouseReleased(double mouseX, double mouseY, int button) { - return this.widgets.get(getHoveredWidget((int) mouseX)).mouseReleased(mouseX, mouseY, button); + public boolean mouseReleased(int mouseX, int mouseY, int button) { + return this.widgets.get(getHoveredWidget(mouseX)).mouseReleased(mouseX, mouseY, button); } } diff --git a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/HeaderEntry.java b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/HeaderEntry.java index a42ce8e71..c5ecf1081 100644 --- a/src/main/java/net/coderbot/iris/gui/element/shaderoptions/HeaderEntry.java +++ b/src/main/java/net/coderbot/iris/gui/element/shaderoptions/HeaderEntry.java @@ -101,7 +101,7 @@ private void queueBottomRightAnchoredTooltip(int x, int y, FontRenderer font, St ShaderPackScreen.TOP_LAYER_RENDER_QUEUE.add(() -> GuiUtil.drawTextPanel(font, text, x - (font.getStringWidth(text) + 10), y - 16)); } - public boolean mouseClicked(double mouseX, double mouseY, int button) { + public boolean mouseClicked(int mouseX, int mouseY, int button) { final boolean backButtonResult = backButton != null && backButton.mouseClicked(mouseX, mouseY, button); final boolean utilButtonResult = utilityButtons.mouseClicked(mouseX, mouseY, button); diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java index 6e3b807f8..c41c5dab2 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/AbstractElementWidget.java @@ -20,7 +20,7 @@ public void init(ShaderPackScreen screen, NavigationController navigation) {} public abstract void drawScreen(int x, int y, int width, int height, int mouseX, int mouseY, float tickDelta, boolean hovered); - public boolean mouseClicked(double mx, double my, int button) { + public boolean mouseClicked(int mouseX, int mouseY, int button) { return false; } diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java index 729528bc5..eed322d0c 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/BaseOptionElementWidget.java @@ -151,29 +151,29 @@ public Optional getCommentBody() { } @Override - public boolean mouseClicked(double mx, double my, int button) { -// if (button == GLFW.GLFW_MOUSE_BUTTON_1 || button == GLFW.GLFW_MOUSE_BUTTON_2) { -// boolean refresh = false; -// -// if (GuiScreen.isShiftKeyDown()) { -// refresh = applyOriginalValue(); -// } -// if (!refresh) { -// if (button == GLFW.GLFW_MOUSE_BUTTON_1) { -// refresh = applyNextValue(); -// } else { -// refresh = applyPreviousValue(); -// } -// } -// -// if (refresh) { -// this.navigation.refresh(); -// } -// -// GuiUtil.playButtonClickSound(); -// -// return true; -// } - return super.mouseClicked(mx, my, button); + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (button == 0 || button == 1) { + boolean refresh = false; + + if (GuiScreen.isShiftKeyDown()) { + refresh = applyOriginalValue(); + } + if (!refresh) { + if (button == 0) { + refresh = applyNextValue(); + } else { + refresh = applyPreviousValue(); + } + } + + if (refresh) { + this.navigation.refresh(); + } + + GuiUtil.playButtonClickSound(); + + return true; + } + return super.mouseClicked(mouseX, mouseY, button); } } diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/IrisImageButton.java b/src/main/java/net/coderbot/iris/gui/element/widget/IrisImageButton.java new file mode 100644 index 000000000..2361e6cdc --- /dev/null +++ b/src/main/java/net/coderbot/iris/gui/element/widget/IrisImageButton.java @@ -0,0 +1,52 @@ +package net.coderbot.iris.gui.element.widget; + +import com.gtnewhorizons.angelica.glsm.GLStateManager; +import cpw.mods.fml.client.config.GuiUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL14; + +import java.util.function.Consumer; + +public class IrisImageButton extends IrisButton { + private final ResourceLocation textureLocation; + private final int xTexStart; + private final int yTexStart; + private final int yDiffTex; + + public IrisImageButton(int x, int y, int width, int height, int xTexStart, int yTexStart, int yDiffTex, ResourceLocation resourceLocation,Consumer onPress) { + super(x, y, width, height, "", onPress); + + this.textureLocation = resourceLocation; + this.xTexStart = xTexStart; + this.yTexStart = yTexStart; + this.yDiffTex = yDiffTex; + } + + + @Override + public void drawButton(Minecraft mc, int mouseX, int mouseY) { + if(!this.visible) { + return; + } + + int yTex = this.yTexStart; + this.field_146123_n/*isMouseOver*/ = mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + this.width && mouseY < this.yPosition + this.height; + if(this.getHoverState(this.field_146123_n) == 2) { + yTex += this.yDiffTex; + } + + // Sets RenderSystem to use solid white as the tint color for blend mode, and enables blend mode + GL14.glBlendColor(1.0f, 1.0f, 1.0f, 1.0f); + GLStateManager.enableBlend(); + + // Sets RenderSystem to be able to use textures when drawing + GLStateManager.enableTexture(); + mc.getTextureManager().bindTexture(this.textureLocation); + + // Draw the texture to the screen + GuiUtils.drawTexturedModalRect(this.xPosition, this.yPosition, this.xTexStart, yTex, width, height, 256); + + } + +} diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java index bbe44813a..a3df4da2d 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/LinkElementWidget.java @@ -61,14 +61,14 @@ public void drawScreen(int x, int y, int width, int height, int mouseX, int mous } @Override - public boolean mouseClicked(double mx, double my, int button) { + public boolean mouseClicked(int mouseX, int mouseY, int button) { if (button == 0) { this.navigation.open(targetScreenId); GuiUtil.playButtonClickSound(); return true; } - return super.mouseClicked(mx, my, button); + return super.mouseClicked(mouseX, mouseY, button); } @Override diff --git a/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java b/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java index d8cad8396..e174d3388 100644 --- a/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java +++ b/src/main/java/net/coderbot/iris/gui/element/widget/SliderElementWidget.java @@ -85,7 +85,7 @@ private void onReleased() { } @Override - public boolean mouseClicked(double mx, double my, int button) { + public boolean mouseClicked(int mouseX, int mouseY, int button) { if (button == 0) { if (GuiScreen.isShiftKeyDown()) { if (this.applyOriginalValue()) { diff --git a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java index ed7b7df5c..4445c127a 100644 --- a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java +++ b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java @@ -7,10 +7,11 @@ import net.coderbot.iris.gui.NavigationController; import net.coderbot.iris.gui.element.ShaderPackOptionList; import net.coderbot.iris.gui.element.ShaderPackSelectionList; +import net.coderbot.iris.gui.element.shaderselection.ShaderPackEntry; import net.coderbot.iris.gui.element.widget.AbstractElementWidget; import net.coderbot.iris.gui.element.widget.CommentedElementWidget; import net.coderbot.iris.gui.element.widget.IrisButton; -import net.coderbot.iris.gui.element.shaderselection.ShaderPackEntry; +import net.coderbot.iris.gui.element.widget.IrisImageButton; import net.coderbot.iris.shaderpack.ShaderPack; import net.irisshaders.iris.api.v0.IrisApi; import net.minecraft.client.gui.FontRenderer; @@ -20,6 +21,7 @@ import org.jetbrains.annotations.Nullable; import org.lwjgl.Sys; import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; import java.io.File; import java.io.IOException; @@ -70,6 +72,7 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable { private String updateComponent; private boolean guiHidden = false; + private boolean dirty = false; private float guiButtonHoverTimer = 0.0f; public ShaderPackScreen(GuiScreen parent) { @@ -90,6 +93,10 @@ public ShaderPackScreen(GuiScreen parent) { } @Override public void drawScreen(int mouseX, int mouseY, float delta) { + if(dirty) { + dirty = false; + this.initGui(); + } if (this.mc.theWorld == null) { super.drawDefaultBackground(); @@ -236,13 +243,14 @@ public void initGui() { x = (int) (endOfLastButton + (freeSpace / 2.0f)) - 10; } - this.buttonList.add(new IrisButton( + this.buttonList.add(new IrisImageButton( x, this.height - 39, 20, 20, - showOrHide, + this.guiHidden ? 20 : 0, 146, 20, + GuiUtil.IRIS_WIDGETS_TEX, button -> { this.guiHidden = !this.guiHidden; - this.initGui(); + this.dirty = true; } )); } @@ -253,6 +261,45 @@ public void initGui() { this.hoveredElementCommentTimer = 0; } + + /** + * Called when the mouse is clicked. + */ + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) { + boolean handled = false; + if (!this.guiHidden) { + if (optionMenuOpen && this.shaderOptionList != null ) { + handled = this.shaderOptionList.mouseClicked(mouseX, mouseY, mouseButton); + } else { + handled = this.shaderPackList.mouseClicked(mouseX, mouseY, mouseButton); + } + } + if(!handled) { + super.mouseClicked(mouseX, mouseY, mouseButton); + } + } + + /** + * Called when the mouse is moved or a mouse button is released. Signature: (mouseX, mouseY, which) which==-1 is + * mouseMove, which==0 or which==1 is mouseUp + */ + @Override + protected void mouseMovedOrUp(int mouseX, int mouseY, int state) { + boolean handled = false; + if (!this.guiHidden && state != -1) { + if (optionMenuOpen && this.shaderOptionList != null) { + handled = this.shaderOptionList.mouseReleased(mouseX, mouseY, Mouse.getEventButton()); + } else { + handled = this.shaderPackList.mouseReleased(mouseX, mouseY, Mouse.getEventButton()); + } + } + if(!handled) { + super.mouseMovedOrUp(mouseX, mouseY, state); + } + } + + @Override protected void actionPerformed(GuiButton guiButton) { if(guiButton.enabled) { diff --git a/src/main/resources/META-INF/angelica_at.cfg b/src/main/resources/META-INF/angelica_at.cfg index 18b4b9ec8..6c4318eef 100644 --- a/src/main/resources/META-INF/angelica_at.cfg +++ b/src/main/resources/META-INF/angelica_at.cfg @@ -36,3 +36,13 @@ public net.minecraft.client.renderer.texture.TextureMap func_147634_a(Lnet/minec public net.minecraft.client.gui.GuiVideoSettings field_146498_f # parentGuiScreen public net.minecraft.entity.Entity field_70151_c # fire + +public net.minecraft.client.gui.GuiSlot field_148157_o # initialClickY +public net.minecraft.client.gui.GuiSlot field_148167_s # lastClicked +public net.minecraft.client.gui.GuiSlot field_148169_q # amountScrolled +public net.minecraft.client.gui.GuiSlot field_148170_p # scrollMultiplier +public net.minecraft.client.gui.GuiSlot field_148168_r # selectedElement +public net.minecraft.client.gui.GuiSlot field_148165_u # hasListHeader +public net.minecraft.client.gui.GuiSlot field_148161_k # mc +public net.minecraft.client.gui.GuiSlot func_148121_k()V # void bindAmountScrolled() +public net.minecraft.client.gui.GuiSlot func_148136_c(IIII)V # void overlayBackground() From 0b748fea38ab0891621ceaca4e2be639562ea30c Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 16 Dec 2023 16:25:07 -0800 Subject: [PATCH 272/301] No star imports --- .../mixins/early/angelica/hudcaching/MixinRenderItem.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java index 21510cf4b..e4a443abb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java @@ -2,14 +2,15 @@ import com.gtnewhorizons.angelica.mixins.dummy.DummyTessellator; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RenderItem; import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.Slice; -import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.opengl.GL11.GL_LIGHTING; @Mixin(RenderItem.class) public class MixinRenderItem { From 74c56f5a1c463a052fb272c3aac3ac69734765f5 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 16 Dec 2023 16:30:25 -0800 Subject: [PATCH 273/301] No remap --- .../mixins/early/angelica/hudcaching/MixinRenderItem.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java index e4a443abb..0418164cb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/hudcaching/MixinRenderItem.java @@ -25,7 +25,7 @@ public class MixinRenderItem { @Redirect( method = "renderItemIntoGUI(Lnet/minecraft/client/gui/FontRenderer;Lnet/minecraft/client/renderer/texture/TextureManager;Lnet/minecraft/item/ItemStack;IIZ)V", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V"), + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false), slice = @Slice( from = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;requiresMultipleRenderPasses()Z"), to = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItem()Lnet/minecraft/item/Item;", ordinal = 4) @@ -37,7 +37,7 @@ public class MixinRenderItem { @Redirect( method = "renderItemIntoGUI(Lnet/minecraft/client/gui/FontRenderer;Lnet/minecraft/client/renderer/texture/TextureManager;Lnet/minecraft/item/ItemStack;IIZ)V", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V"), + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false), slice = @Slice( from = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Tessellator;startDrawingQuads()V", ordinal = 0), to = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItem()Lnet/minecraft/item/Item;", ordinal = 4) @@ -47,7 +47,7 @@ public class MixinRenderItem { @Redirect( method = "renderItemIntoGUI(Lnet/minecraft/client/gui/FontRenderer;Lnet/minecraft/client/renderer/texture/TextureManager;Lnet/minecraft/item/ItemStack;IIZ)V", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glColorMask(ZZZZ)V"), + at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glColorMask(ZZZZ)V", remap = false), slice = @Slice( from = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;requiresMultipleRenderPasses()Z"), to = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItem()Lnet/minecraft/item/Item;", ordinal = 4) From 14bb8d08b5d8da6bc5c648ae7cf2fd99c9c87152 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 16 Dec 2023 17:13:34 -0800 Subject: [PATCH 274/301] Stop centering shader options vertically --- src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java b/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java index 6cdfbd23f..43f5fa827 100644 --- a/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java +++ b/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java @@ -15,6 +15,9 @@ public abstract class IrisGuiSlot extends GuiSlot { protected IrisGuiSlot(Minecraft mc, int width, int height, int top, int bottom, int slotHeight) { super(mc, width, height, top, bottom, slotHeight); + // Set Center Vertically to false + this.field_148163_i = false; + } @Override From 4fa880181fd0520931dede0e4bf07b78c435b9f1 Mon Sep 17 00:00:00 2001 From: Ryan Nasers <42074409+Cardinalstars@users.noreply.github.com> Date: Sat, 16 Dec 2023 19:45:38 -0600 Subject: [PATCH 275/301] Angelica pbr (#31) * Stuff is sort of working * A little more progress --- .../gtnewhorizons/angelica/mixins/Mixins.java | 2 ++ .../accessors/TextureAtlasSpriteAccessor.java | 12 +------ .../shaders/accessors/TextureMapAccessor.java | 4 +++ .../shaders/startup/MixinAbstractTexture.java | 21 +++++++++++++ .../startup/MixinTextureAtlasSprite.java | 26 ++++++++++++++++ .../client/render/SodiumWorldRenderer.java | 2 +- .../iris/pipeline/ShadowRenderer.java | 2 +- .../iris/texture/pbr/PBRAtlasTexture.java | 31 ++++++++++--------- .../iris/texture/pbr/PBRSpriteHolder.java | 10 ------ .../texture/pbr/loader/AtlasPBRLoader.java | 14 ++++----- 10 files changed, 78 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinAbstractTexture.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinTextureAtlasSprite.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 4d181e0ec..9579e4c49 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -63,6 +63,8 @@ public enum Mixins { "shaders.startup.MixinGameSettings" ,"shaders.startup.MixinGuiMainMenu" ,"shaders.startup.MixinInitRenderer" + ,"shaders.startup.MixinAbstractTexture" + ,"shaders.startup.MixinTextureAtlasSprite" ) ), diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureAtlasSpriteAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureAtlasSpriteAccessor.java index d6a74e3d6..75315a593 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureAtlasSpriteAccessor.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureAtlasSpriteAccessor.java @@ -4,6 +4,7 @@ import net.minecraft.client.resources.data.AnimationMetadataSection; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; import java.util.List; @@ -15,12 +16,6 @@ public interface TextureAtlasSpriteAccessor { @Accessor("framesTextureData") List getFramesTextureData(); - @Accessor("originX") - int getX(); - - @Accessor("originY") - int getY(); - @Accessor("frameCounter") int getFrame(); @@ -32,9 +27,4 @@ public interface TextureAtlasSpriteAccessor { @Accessor("tickCounter") void setSubFrame(int subFrame); - - - // -// @Invoker("upload") -// void callUpload(int frameIndex); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureMapAccessor.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureMapAccessor.java index e9389e612..1e34f880c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureMapAccessor.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/accessors/TextureMapAccessor.java @@ -1,6 +1,7 @@ package com.gtnewhorizons.angelica.mixins.early.shaders.accessors; import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.util.ResourceLocation; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -18,4 +19,7 @@ public interface TextureMapAccessor { @Accessor("mipmapLevels") int getMipmapLevels(); + @Accessor("locationBlocksTexture") + ResourceLocation getLocationBlocksTexture(); + } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinAbstractTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinAbstractTexture.java new file mode 100644 index 000000000..2c7d42093 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinAbstractTexture.java @@ -0,0 +1,21 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders.startup; + +import net.coderbot.iris.texture.TextureTracker; +import net.minecraft.client.renderer.texture.AbstractTexture; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(AbstractTexture.class) +public class MixinAbstractTexture { + @Shadow + public int glTextureId; + + // Inject after the newly-generated texture ID has been stored into the id field + @Inject(method = "getGlTextureId()I", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/texture/TextureUtil;glGenTextures()I", shift = At.Shift.BY, by = 2)) + private void iris$afterGenerateId(CallbackInfoReturnable cir) { + TextureTracker.INSTANCE.trackTexture(glTextureId, (AbstractTexture) (Object) this); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinTextureAtlasSprite.java new file mode 100644 index 000000000..f7fd38865 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/startup/MixinTextureAtlasSprite.java @@ -0,0 +1,26 @@ +package com.gtnewhorizons.angelica.mixins.early.shaders.startup; + +import net.coderbot.iris.texture.pbr.PBRSpriteHolder; +import net.coderbot.iris.texture.pbr.TextureAtlasSpriteExtension; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(TextureAtlasSprite.class) +public class MixinTextureAtlasSprite implements TextureAtlasSpriteExtension { + @Unique + private PBRSpriteHolder pbrHolder; + + @Override + public PBRSpriteHolder getPBRHolder() { + return pbrHolder; + } + + @Override + public PBRSpriteHolder getOrCreatePBRHolder() { + if (pbrHolder == null) { + pbrHolder = new PBRSpriteHolder(); + } + return pbrHolder; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index c2f0201ed..6b3664e5e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -253,7 +253,7 @@ public void updateChunks(Camera camera, Frustrum frustum, boolean hasForcedFrust public void drawChunkLayer(BlockRenderPass pass, MatrixStack matrixStack, double x, double y, double z) { if(AngelicaConfig.enableIris) iris$ensureStateSwapped(); // startDrawing/endDrawing are handled by 1.7 already - //pass.startDrawing(); + // pass.startDrawing(); this.chunkRenderManager.renderLayer(matrixStack, pass, x, y, z); diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 063c7f264..6f6e65e33 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -539,7 +539,7 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { if (shouldRenderTerrain) { rg.sortAndRender(mc.thePlayer, 0, playerCamera.getPartialTicks()); -// levelRenderer.invokeRenderChunkLayer(RenderLayer.solid(), modelView, cameraX, cameraY, cameraZ); +// levelRenderer.invokeRenderChunkLayer(RenderLayer.solid(), modelView, cameraX, cameraY, cameraZ); // levelRenderer.invokeRenderChunkLayer(RenderLayer.cutout(), modelView, cameraX, cameraY, cameraZ); // levelRenderer.invokeRenderChunkLayer(RenderLayer.cutoutMipped(), modelView, cameraX, cameraY, cameraZ); } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java index 99765da2b..b98cbbe09 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java @@ -3,10 +3,13 @@ import com.gtnewhorizons.angelica.mixins.early.angelica.textures.MixinTextureAtlasSprite; import com.gtnewhorizons.angelica.compat.mojang.AutoClosableAbstractTexture; import com.gtnewhorizons.angelica.compat.mojang.TextureAtlas; +import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.TextureAtlasSpriteAccessor; +import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.TextureMapAccessor; import net.coderbot.iris.texture.util.TextureExporter; import net.coderbot.iris.texture.util.TextureManipulationUtil; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.texture.TextureUtil; import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.data.AnimationMetadataSection; import net.minecraft.crash.CrashReport; @@ -31,9 +34,8 @@ public class PBRAtlasTexture extends AutoClosableAbstractTexture { public PBRAtlasTexture(TextureMap textureMap, PBRType type) { this.texMap = textureMap; this.type = type; -// id = type.appendToFileLocation(atlasTexture.location()); + id = type.appendToFileLocation(((TextureMapAccessor)textureMap).getLocationBlocksTexture()); - id = type.appendToFileLocation(new ResourceLocation("stuff", getType().name())); } public PBRType getType() { @@ -47,8 +49,8 @@ public ResourceLocation getAtlasId() { public void addSprite(TextureAtlasSprite sprite) { // TODO: PBR - Wants location // sprites.put(sprite.getName(), sprite); - sprites.put(new ResourceLocation("stuff", sprite.getIconName()), sprite); - if (((MixinTextureAtlasSprite) (Object)sprite).isAnimation()) { + sprites.put(texMap.completeResourceLocation(new ResourceLocation(sprite.getIconName()), 0), sprite); + if (sprite.hasAnimationMetadata()) { animatedSprites.add(sprite); } } @@ -63,9 +65,9 @@ public void clear() { animatedSprites.clear(); } - public void upload(int atlasWidth, int atlasHeight, int mipLevel) { + public void upload(int atlasWidth, int atlasHeight, int mipLevel, float anisotropicFiltering) { int glId = getGlTextureId(); -// TextureUtil.prepareImage(glId, mipLevel, atlasWidth, atlasHeight); + TextureUtil.allocateTextureImpl(glId, mipLevel, atlasWidth, atlasHeight, anisotropicFiltering); TextureManipulationUtil.fillWithColor(glId, mipLevel, type.getDefaultValue()); for (TextureAtlasSprite sprite : sprites.values()) { @@ -97,9 +99,9 @@ public void upload(int atlasWidth, int atlasHeight, int mipLevel) { } } - public boolean tryUpload(int atlasWidth, int atlasHeight, int mipLevel) { + public boolean tryUpload(int atlasWidth, int atlasHeight, int mipLevel, float anisotropicFiltering) { try { - upload(atlasWidth, atlasHeight, mipLevel); + upload(atlasWidth, atlasHeight, mipLevel, anisotropicFiltering); return true; } catch (Throwable t) { return false; @@ -112,21 +114,20 @@ public void loadTexture(IResourceManager p_110551_1_) throws IOException { } protected void uploadSprite(TextureAtlasSprite sprite) { - if (((MixinTextureAtlasSprite) (Object)sprite).isAnimation()) { - MixinTextureAtlasSprite mixinSprite = ((MixinTextureAtlasSprite) (Object) sprite); - AnimationMetadataSection metadata = mixinSprite.getMetadata(); + TextureAtlasSpriteAccessor accessor = (TextureAtlasSpriteAccessor) sprite; + if (accessor.getMetadata().getFrameCount() > 1) { + AnimationMetadataSection metadata = accessor.getMetadata(); int frameCount = sprite.getFrameCount(); - for (int frame = mixinSprite.getFrame(); frame >= 0; frame--) { + for (int frame = accessor.getFrame(); frame >= 0; frame--) { int frameIndex = metadata.getFrameIndex(frame); if (frameIndex >= 0 && frameIndex < frameCount) { - mixinSprite.callUpload(frameIndex); + TextureUtil.uploadTextureMipmap(sprite.getFrameTextureData(frameIndex), sprite.getIconWidth(), sprite.getIconHeight(), sprite.getOriginX(), sprite.getOriginY(), false, false); return; } } } - -// sprite.uploadFirstFrame(); + TextureUtil.uploadTextureMipmap(sprite.getFrameTextureData(0), sprite.getIconWidth(), sprite.getIconHeight(), sprite.getOriginX(), sprite.getOriginY(), false, false); } public void cycleAnimationFrames() { diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java index 8913b04d5..97ed0bffb 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRSpriteHolder.java @@ -24,14 +24,4 @@ public void setNormalSprite(TextureAtlasSprite sprite) { public void setSpecularSprite(TextureAtlasSprite sprite) { specularSprite = sprite; } - - public void close() { - // TODO: AutoClosable -// if (normalSprite != null) { -// normalSprite.close(); -// } -// if (specularSprite != null) { -// specularSprite.close(); -// } - } } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java index 8cbc086d5..7c1f1b68f 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java @@ -73,20 +73,19 @@ public void load(TextureMap texMap, IResourceManager resourceManager, PBRTexture } if (normalAtlas != null) { - if (normalAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { + if (normalAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel, ((TextureMapAccessor) texMap).getAnisotropicFiltering())) { pbrTextureConsumer.acceptNormalTexture(normalAtlas); } } if (specularAtlas != null) { - if (specularAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel)) { + if (specularAtlas.tryUpload(atlasWidth, atlasHeight, mipLevel, ((TextureMapAccessor) texMap).getAnisotropicFiltering())) { pbrTextureConsumer.acceptSpecularTexture(specularAtlas); } } } protected static int fetchAtlasMipLevel(TextureMap texMap) { - TextureAtlasSprite missingSprite = texMap.getAtlasSprite("missingno"); - return ((TextureAtlasSpriteAccessor) missingSprite).getFramesTextureData().size() - 1; + return ((TextureMapAccessor) texMap).getMipmapLevels(); } @Nullable @@ -106,7 +105,6 @@ protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourc animationMetadata = new AnimationMetadataSection(Lists.newArrayList(), -1, -1, -1); } - Pair frameSize = this.getFrameSize(nativeImage.getWidth(), nativeImage.getHeight(), animationMetadata); int frameWidth = frameSize.getLeft(); int frameHeight = frameSize.getRight(); @@ -151,8 +149,8 @@ protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourc ResourceLocation pbrSpriteName = new ResourceLocation(spriteName.getResourceDomain(), spriteName.getResourcePath() + pbrType.getSuffix()); TextureAtlasSpriteInfo pbrSpriteInfo = new PBRTextureAtlasSpriteInfo(pbrSpriteName, frameWidth, frameHeight, animationMetadata, pbrType); - int x = ((TextureAtlasSpriteAccessor) sprite).getX(); - int y = ((TextureAtlasSpriteAccessor) sprite).getY(); + int x = sprite.getOriginX(); + int y = sprite.getOriginY(); pbrSprite = new PBRTextureAtlasSprite(pbrSpriteInfo, animationMetadata, atlasWidth, atlasHeight, x, y, nativeImage, texMap, mipLevel); syncAnimation(sprite, pbrSprite); } catch (FileNotFoundException e) { @@ -220,7 +218,7 @@ public static class PBRTextureAtlasSprite extends TextureAtlasSprite implements protected PBRTextureAtlasSprite(TextureAtlasSpriteInfo info, AnimationMetadataSection animationMetaDataSection, int atlasWidth, int atlasHeight, int x, int y, NativeImage nativeImage, TextureMap texMap, int miplevel) { super(info.name().toString()); super.initSprite(atlasWidth, atlasHeight, x, y, false); - super.loadSprite(getMipmapGenerator(info, atlasWidth, atlasHeight).generateMipLevels(nativeImage, miplevel), animationMetaDataSection, ((TextureMapAccessor) texMap).getAnisotropicFiltering() == 1); + super.loadSprite(getMipmapGenerator(info, atlasWidth, atlasHeight).generateMipLevels(nativeImage, miplevel), animationMetaDataSection, (float)((TextureMapAccessor) texMap).getAnisotropicFiltering() > 1.0F); } @Override From a9aba9cc46ffc3ad7a368aa093be0883710cdf07 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 16 Dec 2023 21:26:51 -0500 Subject: [PATCH 276/301] Only use Sodium light pipeline if useSeparateAo is on Sodium pipeline is still very buggy, so isolate it to Iris-only for now --- .../early/sodium/MixinRenderBlocks.java | 32 +++++++------------ .../client/render/pipeline/BlockRenderer.java | 23 ++++++------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java index 7b3849a93..aaa3df878 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderBlocks.java @@ -1,34 +1,24 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; +import com.gtnewhorizons.angelica.config.AngelicaConfig; +import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderBlocks; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(RenderBlocks.class) public abstract class MixinRenderBlocks { - @Shadow - public abstract boolean renderStandardBlockWithColorMultiplier(Block block, int x, int y, int z, float f, float f1, float f2); + @Redirect(method = "renderStandardBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;isAmbientOcclusionEnabled()Z")) + private boolean checkAOEnabled() { + if(AngelicaConfig.enableIris && BlockRenderingSettings.INSTANCE.shouldUseSeparateAo()) { + return false; // force Sodium pipeline + } - /** - * @author mitchej123 - * @reason Let sodium handle AO - */ - @Overwrite - public boolean renderStandardBlockWithAmbientOcclusion(Block block, int x, int y, int z, float f, float f1, float f2) { - return renderStandardBlockWithColorMultiplier(block, x, y, z, f, f1, f2); + return Minecraft.isAmbientOcclusionEnabled(); } - - /** - * @author mitchej123 - * @reason Let sodium handle AO - */ - @Overwrite - public boolean renderStandardBlockWithAmbientOcclusionPartial(Block block, int x, int y, int z, float f, float f1, float f2) { - return renderStandardBlockWithColorMultiplier(block, x, y, z, f, f1, f2); - } - - - } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index c0120ecb3..34ee39bac 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -158,8 +158,13 @@ private void renderQuadList(BlockPos pos, LightPipeline lighter, ChunkModelBuffe if(quad.normal != facing) continue; + final QuadLightData light = this.cachedQuadLightData; - lighter.calculate(quad, pos, light, cullFace, quad.getFace(), quad.hasShade()); + + // TODO: use Sodium pipeline always + if(this.useSeparateAo) { + lighter.calculate(quad, pos, light, cullFace, quad.getFace(), quad.hasShade()); + } this.renderQuad(sink, quad, light, renderData); @@ -170,13 +175,7 @@ private void renderQuadList(BlockPos pos, LightPipeline lighter, ChunkModelBuffe private void renderQuad(ModelVertexSink sink, Quad quad, QuadLightData light, ChunkRenderData.Builder renderData) { - final ModelQuadOrientation order = ModelQuadOrientation.orient(light.br);; - - int[] colors = null; - - if (quad.hasColor()) { - colors = quad.getColors(); - } + final ModelQuadOrientation order = useSeparateAo ? ModelQuadOrientation.orient(light.br) : ModelQuadOrientation.NORMAL; for (int dstIndex = 0; dstIndex < 4; dstIndex++) { final int srcIndex = order.getVertexIndex(dstIndex); @@ -185,20 +184,18 @@ private void renderQuad(ModelVertexSink sink, Quad quad, QuadLightData light, Ch final float y = quad.getY(srcIndex); final float z = quad.getZ(srcIndex); -// int color = quad.getColor(srcIndex); - int color = colors != null ? colors[srcIndex] : quad.getColor(srcIndex); + int color = quad.getColor(srcIndex); final float ao = light.br[srcIndex]; if (useSeparateAo) { color &= 0x00FFFFFF; color |= ((int) (ao * 255.0f)) << 24; - } else { - color = ColorABGR.mul(color, ao); } final float u = quad.getTexU(srcIndex); final float v = quad.getTexV(srcIndex); - final int lm = ModelQuadUtil.mergeBakedLight(quad.getLight(srcIndex), light.lm[srcIndex]); + int quadLight = quad.getLight(srcIndex); + final int lm = useSeparateAo ? ModelQuadUtil.mergeBakedLight(quadLight, light.lm[srcIndex]) : quadLight; sink.writeQuad(x, y, z, color, u, v, lm); } From 9510b789d9540ad75d52aa6636d84074aeb635ac Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 16 Dec 2023 22:24:02 -0500 Subject: [PATCH 277/301] Fix region sorting for translucency --- .../multidraw/MultidrawChunkRenderBackend.java | 6 +++--- .../client/render/chunk/region/ChunkRegion.java | 14 +++++++++++++- .../render/chunk/region/ChunkRegionManager.java | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java index c268e2650..0705b9695 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/MultidrawChunkRenderBackend.java @@ -264,9 +264,9 @@ private void buildCommandBuffer() { if(this.reverseRegions) { ChunkCameraContext camera = this.regionCamera; for (ChunkRegion region : this.pendingBatches) { - float x = camera.getChunkModelOffset(region.x * 16, camera.blockOriginX, camera.originX); - float y = camera.getChunkModelOffset(region.y * 16, camera.blockOriginY, camera.originY); - float z = camera.getChunkModelOffset(region.z * 16, camera.blockOriginZ, camera.originZ); + float x = camera.getChunkModelOffset(region.getCenterBlockX(), camera.blockOriginX, camera.originX); + float y = camera.getChunkModelOffset(region.getCenterBlockY(), camera.blockOriginY, camera.originY); + float z = camera.getChunkModelOffset(region.getCenterBlockZ(), camera.blockOriginZ, camera.originZ); region.camDistance = x * x + y * y + z * z; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegion.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegion.java index 8e73b037f..4be360a93 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegion.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegion.java @@ -21,7 +21,7 @@ public class ChunkRegion { private GlTessellation tessellation; - public final int x, y, z; + private final int x, y, z; public float camDistance; @@ -39,6 +39,18 @@ public ChunkRegion(RenderDevice device, int size, int x, int y, int z) { this.z = z; } + public int getCenterBlockX() { + return (this.x * ChunkRegionManager.BUFFER_WIDTH * 16) + (ChunkRegionManager.BUFFER_WIDTH / 2 * 16); + } + + public int getCenterBlockY() { + return (this.y * ChunkRegionManager.BUFFER_HEIGHT * 16) + (ChunkRegionManager.BUFFER_HEIGHT / 2 * 16); + } + + public int getCenterBlockZ() { + return (this.z * ChunkRegionManager.BUFFER_LENGTH * 16) + (ChunkRegionManager.BUFFER_LENGTH / 2 * 16); + } + public GlBufferArena getBufferArena() { return this.arena; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java index 9dff791f8..3bcf773f6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java @@ -42,7 +42,7 @@ public ChunkRegion getOrCreateRegion(int x, int y, int z) { ChunkRegion region = this.regions.get(key); if (region == null) { - this.regions.put(key, region = new ChunkRegion<>(this.device, BUFFER_SIZE, x, y, z)); + this.regions.put(key, region = new ChunkRegion<>(this.device, BUFFER_SIZE, x >> BUFFER_WIDTH_SH, y >> BUFFER_HEIGHT_SH, z >> BUFFER_LENGTH_SH)); } return region; From 105ddd02d1960bae58631568856bdf345e0b3f4b Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 17 Dec 2023 10:37:45 -0800 Subject: [PATCH 278/301] Cleanup some PBR todos --- .../mojang/AutoClosableAbstractTexture.java | 2 +- .../texture/format/LabPBRTextureFormat.java | 4 +- .../iris/texture/format/TextureFormat.java | 1 - .../texture/mipmap/CustomMipmapGenerator.java | 2 - .../iris/texture/pbr/PBRAtlasTexture.java | 47 ++++------- .../texture/pbr/loader/AtlasPBRLoader.java | 79 +++++++++---------- 6 files changed, 57 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java index 90f543a1a..f7332d781 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java @@ -9,7 +9,7 @@ public abstract class AutoClosableAbstractTexture extends AbstractTexture implements AutoCloseable { - public abstract void load(IResourceManager manager) throws IOException; + public abstract void loadTexture(IResourceManager manager) throws IOException; @Override public void close() throws Exception {} diff --git a/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java b/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java index 2e8029b4f..0687d3bb9 100644 --- a/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java +++ b/src/main/java/net/coderbot/iris/texture/format/LabPBRTextureFormat.java @@ -9,7 +9,6 @@ import java.util.Objects; -// TODO: PBR public class LabPBRTextureFormat implements TextureFormat { public static final ChannelMipmapGenerator SPECULAR_MIPMAP_GENERATOR = new ChannelMipmapGenerator( LinearBlendFunction.INSTANCE, @@ -45,8 +44,7 @@ public boolean canInterpolateValues(PBRType pbrType) { return true; } - // TODO: PBR - @Override + @Override public @Nullable CustomMipmapGenerator getMipmapGenerator(PBRType pbrType) { if (pbrType == PBRType.SPECULAR) { return SPECULAR_MIPMAP_GENERATOR; diff --git a/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java b/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java index 1be75c2d8..603665dd8 100644 --- a/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java +++ b/src/main/java/net/coderbot/iris/texture/format/TextureFormat.java @@ -55,7 +55,6 @@ default void setupTextureParameters(PBRType pbrType, AbstractTexture texture) { } } - // TODO: PBR @Nullable CustomMipmapGenerator getMipmapGenerator(PBRType pbrType); diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java index 1a52e59b5..e95820361 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java @@ -2,14 +2,12 @@ import com.gtnewhorizons.angelica.compat.NativeImage; import net.coderbot.iris.texture.pbr.loader.TextureAtlasSpriteInfo; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import javax.annotation.Nullable; public interface CustomMipmapGenerator { NativeImage[] generateMipLevels(NativeImage image, int mipLevel); - // TODO: PBR public interface Provider { @Nullable CustomMipmapGenerator getMipmapGenerator(TextureAtlasSpriteInfo info, int atlasWidth, int atlasHeight); diff --git a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java index b98cbbe09..c9a454239 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/PBRAtlasTexture.java @@ -1,10 +1,9 @@ package net.coderbot.iris.texture.pbr; -import com.gtnewhorizons.angelica.mixins.early.angelica.textures.MixinTextureAtlasSprite; import com.gtnewhorizons.angelica.compat.mojang.AutoClosableAbstractTexture; -import com.gtnewhorizons.angelica.compat.mojang.TextureAtlas; import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.TextureAtlasSpriteAccessor; import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.TextureMapAccessor; +import lombok.Getter; import net.coderbot.iris.texture.util.TextureExporter; import net.coderbot.iris.texture.util.TextureManipulationUtil; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -26,7 +25,8 @@ public class PBRAtlasTexture extends AutoClosableAbstractTexture { protected final TextureMap texMap; - protected final PBRType type; + @Getter + protected final PBRType type; protected final ResourceLocation id; protected final Map sprites = new HashMap<>(); protected final Set animatedSprites = new HashSet<>(); @@ -38,17 +38,11 @@ public PBRAtlasTexture(TextureMap textureMap, PBRType type) { } - public PBRType getType() { - return type; - } - - public ResourceLocation getAtlasId() { + public ResourceLocation getAtlasId() { return id; } public void addSprite(TextureAtlasSprite sprite) { - // TODO: PBR - Wants location -// sprites.put(sprite.getName(), sprite); sprites.put(texMap.completeResourceLocation(new ResourceLocation(sprite.getIconName()), 0), sprite); if (sprite.hasAnimationMetadata()) { animatedSprites.add(sprite); @@ -66,7 +60,7 @@ public void clear() { } public void upload(int atlasWidth, int atlasHeight, int mipLevel, float anisotropicFiltering) { - int glId = getGlTextureId(); + final int glId = getGlTextureId(); TextureUtil.allocateTextureImpl(glId, mipLevel, atlasWidth, atlasHeight, anisotropicFiltering); TextureManipulationUtil.fillWithColor(glId, mipLevel, type.getDefaultValue()); @@ -83,7 +77,7 @@ public void upload(int atlasWidth, int atlasHeight, int mipLevel, float anisotro } if (!animatedSprites.isEmpty()) { - PBRAtlasHolder pbrHolder = ((TextureAtlasExtension) texMap).getOrCreatePBRHolder(); + final PBRAtlasHolder pbrHolder = ((TextureAtlasExtension) texMap).getOrCreatePBRHolder(); switch (type) { case NORMAL: pbrHolder.setNormalAtlas(this); @@ -109,18 +103,18 @@ public boolean tryUpload(int atlasWidth, int atlasHeight, int mipLevel, float an } @Override - public void loadTexture(IResourceManager p_110551_1_) throws IOException { + public void loadTexture(IResourceManager manager) throws IOException { // todo } protected void uploadSprite(TextureAtlasSprite sprite) { - TextureAtlasSpriteAccessor accessor = (TextureAtlasSpriteAccessor) sprite; + final TextureAtlasSpriteAccessor accessor = (TextureAtlasSpriteAccessor) sprite; if (accessor.getMetadata().getFrameCount() > 1) { - AnimationMetadataSection metadata = accessor.getMetadata(); - int frameCount = sprite.getFrameCount(); + final AnimationMetadataSection metadata = accessor.getMetadata(); + final int frameCount = sprite.getFrameCount(); for (int frame = accessor.getFrame(); frame >= 0; frame--) { - int frameIndex = metadata.getFrameIndex(frame); + final int frameIndex = metadata.getFrameIndex(frame); if (frameIndex >= 0 && frameIndex < frameCount) { TextureUtil.uploadTextureMipmap(sprite.getFrameTextureData(frameIndex), sprite.getIconWidth(), sprite.getIconHeight(), sprite.getOriginX(), sprite.getOriginY(), false, false); return; @@ -133,27 +127,18 @@ protected void uploadSprite(TextureAtlasSprite sprite) { public void cycleAnimationFrames() { bind(); for (TextureAtlasSprite sprite : animatedSprites) { -// sprite.cycleFrames(); sprite.updateAnimation(); } } @Override public void close() { - PBRAtlasHolder pbrHolder = ((TextureAtlasExtension) texMap).getPBRHolder(); + final PBRAtlasHolder pbrHolder = ((TextureAtlasExtension) texMap).getPBRHolder(); if (pbrHolder != null) { - switch (type) { - case NORMAL: - pbrHolder.setNormalAtlas(null); - break; - case SPECULAR: - pbrHolder.setSpecularAtlas(null); - break; - } + switch (type) { + case NORMAL -> pbrHolder.setNormalAtlas(null); + case SPECULAR -> pbrHolder.setSpecularAtlas(null); + } } } - - @Override - public void load(IResourceManager manager) { - } } diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java index 7c1f1b68f..c44cf162c 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java @@ -41,11 +41,10 @@ public class AtlasPBRLoader implements PBRTextureLoader { @Override public void load(TextureMap texMap, IResourceManager resourceManager, PBRTextureConsumer pbrTextureConsumer) { - // TODO: PBR - TextureInfoCache.TextureInfo textureInfo = TextureInfoCache.INSTANCE.getInfo(texMap.getGlTextureId()); - int atlasWidth = textureInfo.getWidth(); - int atlasHeight = textureInfo.getHeight(); - int mipLevel = fetchAtlasMipLevel(texMap); + final TextureInfoCache.TextureInfo textureInfo = TextureInfoCache.INSTANCE.getInfo(texMap.getGlTextureId()); + final int atlasWidth = textureInfo.getWidth(); + final int atlasHeight = textureInfo.getHeight(); + final int mipLevel = fetchAtlasMipLevel(texMap); PBRAtlasTexture normalAtlas = null; PBRAtlasTexture specularAtlas = null; @@ -58,7 +57,7 @@ public void load(TextureMap texMap, IResourceManager resourceManager, PBRTexture normalAtlas = new PBRAtlasTexture(texMap, PBRType.NORMAL); } normalAtlas.addSprite(normalSprite); - PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); + final PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); pbrSpriteHolder.setNormalSprite(normalSprite); } if (specularSprite != null) { @@ -66,7 +65,7 @@ public void load(TextureMap texMap, IResourceManager resourceManager, PBRTexture specularAtlas = new PBRAtlasTexture(texMap, PBRType.SPECULAR); } specularAtlas.addSprite(specularSprite); - PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); + final PBRSpriteHolder pbrSpriteHolder = ((TextureAtlasSpriteExtension) sprite).getOrCreatePBRHolder(); pbrSpriteHolder.setSpecularSprite(specularSprite); } } @@ -90,36 +89,36 @@ protected static int fetchAtlasMipLevel(TextureMap texMap) { @Nullable protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourceManager resourceManager, TextureMap texMap, int atlasWidth, int atlasHeight, int mipLevel, PBRType pbrType) { - ResourceLocation spriteName = new ResourceLocation(sprite.getIconName()); - ResourceLocation imageLocation = texMap.completeResourceLocation(spriteName, 0); - ResourceLocation pbrImageLocation = pbrType.appendToFileLocation(imageLocation); + final ResourceLocation spriteName = new ResourceLocation(sprite.getIconName()); + final ResourceLocation imageLocation = texMap.completeResourceLocation(spriteName, 0); + final ResourceLocation pbrImageLocation = pbrType.appendToFileLocation(imageLocation); TextureAtlasSprite pbrSprite = null; try { // This is no longer closable. Not sure about this. - IResource resource = resourceManager.getResource(pbrImageLocation); + final IResource resource = resourceManager.getResource(pbrImageLocation); NativeImage nativeImage = NativeImage.read(resource.getInputStream()); AnimationMetadataSection animationMetadata = (AnimationMetadataSection) resource.getMetadata("animation"); if (animationMetadata == null) { animationMetadata = new AnimationMetadataSection(Lists.newArrayList(), -1, -1, -1); } - Pair frameSize = this.getFrameSize(nativeImage.getWidth(), nativeImage.getHeight(), animationMetadata); + final Pair frameSize = this.getFrameSize(nativeImage.getWidth(), nativeImage.getHeight(), animationMetadata); int frameWidth = frameSize.getLeft(); int frameHeight = frameSize.getRight(); - int targetFrameWidth = sprite.getIconWidth(); - int targetFrameHeight = sprite.getIconHeight(); + final int targetFrameWidth = sprite.getIconWidth(); + final int targetFrameHeight = sprite.getIconHeight(); if (frameWidth != targetFrameWidth || frameHeight != targetFrameHeight) { - int imageWidth = nativeImage.getWidth(); - int imageHeight = nativeImage.getHeight(); + final int imageWidth = nativeImage.getWidth(); + final int imageHeight = nativeImage.getHeight(); // We can assume the following is always true as a result of getFrameSize's check: // imageWidth % frameWidth == 0 && imageHeight % frameHeight == 0 - int targetImageWidth = imageWidth / frameWidth * targetFrameWidth; - int targetImageHeight = imageHeight / frameHeight * targetFrameHeight; + final int targetImageWidth = imageWidth / frameWidth * targetFrameWidth; + final int targetImageHeight = imageHeight / frameHeight * targetFrameHeight; - NativeImage scaledImage; + final NativeImage scaledImage; if (targetImageWidth % imageWidth == 0 && targetImageHeight % imageHeight == 0) { scaledImage = ImageManipulationUtil.scaleNearestNeighbor(nativeImage, targetImageWidth, targetImageHeight); } else { @@ -134,9 +133,9 @@ protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourc frameHeight = targetFrameHeight; if (!animationMetadata.equals(new AnimationMetadataSection(Lists.newArrayList(), -1, -1, -1))) { - AnimationMetadataSectionAccessor animationAccessor = (AnimationMetadataSectionAccessor) animationMetadata; - int internalFrameWidth = animationAccessor.getFrameHeight(); - int internalFrameHeight = animationAccessor.getFrameHeight(); + final AnimationMetadataSectionAccessor animationAccessor = (AnimationMetadataSectionAccessor) animationMetadata; + final int internalFrameWidth = animationAccessor.getFrameHeight(); + final int internalFrameHeight = animationAccessor.getFrameHeight(); if (internalFrameWidth != -1) { animationAccessor.setFrameWidth(frameWidth); } @@ -146,11 +145,11 @@ protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourc } } - ResourceLocation pbrSpriteName = new ResourceLocation(spriteName.getResourceDomain(), spriteName.getResourcePath() + pbrType.getSuffix()); - TextureAtlasSpriteInfo pbrSpriteInfo = new PBRTextureAtlasSpriteInfo(pbrSpriteName, frameWidth, frameHeight, animationMetadata, pbrType); + final ResourceLocation pbrSpriteName = new ResourceLocation(spriteName.getResourceDomain(), spriteName.getResourcePath() + pbrType.getSuffix()); + final TextureAtlasSpriteInfo pbrSpriteInfo = new PBRTextureAtlasSpriteInfo(pbrSpriteName, frameWidth, frameHeight, animationMetadata, pbrType); - int x = sprite.getOriginX(); - int y = sprite.getOriginY(); + final int x = sprite.getOriginX(); + final int y = sprite.getOriginY(); pbrSprite = new PBRTextureAtlasSprite(pbrSpriteInfo, animationMetadata, atlasWidth, atlasHeight, x, y, nativeImage, texMap, mipLevel); syncAnimation(sprite, pbrSprite); } catch (FileNotFoundException e) { @@ -167,23 +166,23 @@ protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourc protected void syncAnimation(TextureAtlasSprite source, TextureAtlasSprite target) { // TODO: Iris Shaders - animationMetadata && animationMetadata.getFrameCount() > 0 - if (!source.hasAnimationMetadata() || !target.hasAnimationMetadata()) { + if (!source.hasAnimationMetadata() || !target.hasAnimationMetadata()) { return; } - TextureAtlasSpriteAccessor sourceAccessor = ((TextureAtlasSpriteAccessor) source); - AnimationMetadataSection sourceMetadata = sourceAccessor.getMetadata(); + final TextureAtlasSpriteAccessor sourceAccessor = ((TextureAtlasSpriteAccessor) source); + final AnimationMetadataSection sourceMetadata = sourceAccessor.getMetadata(); int ticks = 0; for (int f = 0; f < sourceAccessor.getFrame(); f++) { ticks += sourceMetadata.getFrameTimeSingle(f); } - TextureAtlasSpriteAccessor targetAccessor = ((TextureAtlasSpriteAccessor) target); - AnimationMetadataSection targetMetadata = targetAccessor.getMetadata(); + final TextureAtlasSpriteAccessor targetAccessor = ((TextureAtlasSpriteAccessor) target); + final AnimationMetadataSection targetMetadata = targetAccessor.getMetadata(); int cycleTime = 0; - int frameCount = targetMetadata.getFrameCount(); + final int frameCount = targetMetadata.getFrameCount(); for (int f = 0; f < frameCount; f++) { cycleTime += targetMetadata.getFrameTimeSingle(f); } @@ -191,7 +190,7 @@ protected void syncAnimation(TextureAtlasSprite source, TextureAtlasSprite targe int targetFrame = 0; while (true) { - int time = targetMetadata.getFrameTimeSingle(targetFrame); + final int time = targetMetadata.getFrameTimeSingle(targetFrame); if (ticks >= time) { targetFrame++; ticks -= time; @@ -223,11 +222,11 @@ protected PBRTextureAtlasSprite(TextureAtlasSpriteInfo info, AnimationMetadataSe @Override public CustomMipmapGenerator getMipmapGenerator(TextureAtlasSpriteInfo info, int atlasWidth, int atlasHeight) { - if (info instanceof PBRTextureAtlasSpriteInfo) { - PBRType pbrType = ((PBRTextureAtlasSpriteInfo) info).pbrType; - TextureFormat format = TextureFormatLoader.getFormat(); + if (info instanceof PBRTextureAtlasSpriteInfo pbrInfo) { + final PBRType pbrType = pbrInfo.pbrType; + final TextureFormat format = TextureFormatLoader.getFormat(); if (format != null) { - CustomMipmapGenerator generator = format.getMipmapGenerator(pbrType); + final CustomMipmapGenerator generator = format.getMipmapGenerator(pbrType); if (generator != null) { return generator; } @@ -238,9 +237,9 @@ public CustomMipmapGenerator getMipmapGenerator(TextureAtlasSpriteInfo info, int } private Pair getFrameSize(int i, int j, AnimationMetadataSection animationMetadataSection) { - Pair pair = this.calculateFrameSize(i, j, animationMetadataSection); - int k = (Integer)pair.getLeft(); - int l = (Integer)pair.getRight(); + final Pair pair = this.calculateFrameSize(i, j, animationMetadataSection); + final int k = pair.getLeft(); + final int l = pair.getRight(); if (isDivisionInteger(i, k) && isDivisionInteger(j, l)) { return pair; } else { From 834794733cef5f6df0e14c26295232f352f8de1f Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 17 Dec 2023 11:29:14 -0800 Subject: [PATCH 279/301] Open Shaderpack now works on Linux * Still needs testing on OSX/Windows --- .../iris/gui/screen/ShaderPackScreen.java | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java index 4445c127a..c2cd0f7a5 100644 --- a/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java +++ b/src/main/java/net/coderbot/iris/gui/screen/ShaderPackScreen.java @@ -1,6 +1,5 @@ package net.coderbot.iris.gui.screen; -import com.gtnewhorizons.angelica.client.Shaders; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import net.coderbot.iris.Iris; import net.coderbot.iris.gui.GuiUtil; @@ -407,48 +406,49 @@ private void openShaderPackFolder() { CompletableFuture.runAsync(() -> openUri(Iris.getShaderpacksDirectoryManager().getDirectoryUri())); } - private void openUri(URI directoryUri) { - // TODO: Borrowed from ShadersMod... doesn't seem to work on Linux + private void openUri(URI uri) { switch (net.minecraft.util.Util.getOSType()) { - case OSX: { + case OSX -> { try { - Runtime.getRuntime().exec(new String[] { "/usr/bin/open", directoryUri.toString() }); + Runtime.getRuntime().exec(new String[] { "/usr/bin/open", uri.toString() }); return; - } catch (IOException var7) { - var7.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); } } - break; - case WINDOWS: { - String var2 = String.format( - "cmd.exe /C start \"Open file\" \"%s\"", - new Object[] { directoryUri.toString() }); - + case WINDOWS -> { + try { + Runtime.getRuntime().exec(new String[] { "rundll32", "url.dll,FileProtocolHandler", uri.toString() }); + return; + } catch (IOException e) { + e.printStackTrace(); + } + } + case LINUX -> { try { - Runtime.getRuntime().exec(var2); + Runtime.getRuntime().exec(new String[] { "xdg-open", uri.toString() }); return; - } catch (IOException var6) { - var6.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); } } - break; - default: - break; + default -> { + } } boolean openViaSystemClass = false; try { final Class aClass = Class.forName("java.awt.Desktop"); final Object getDesktop = aClass.getMethod("getDesktop").invoke((Object) null); - aClass.getMethod("browse", URI.class).invoke(getDesktop, (new File(this.mc.mcDataDir, Shaders.shaderpacksdirname)).toURI()); - } catch (Throwable var5) { - var5.printStackTrace(); + aClass.getMethod("browse", URI.class).invoke(getDesktop, uri); + } catch (Exception e) { + e.printStackTrace(); openViaSystemClass = true; } if (openViaSystemClass) { AngelicaTweaker.LOGGER.debug("Opening via system class!"); - Sys.openURL("file://" + Shaders.shaderpacksdir.getAbsolutePath()); + Sys.openURL("file://" + uri); } } From ca6ddb3d24fce5749f59601e41c68e5220e3cea8 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 17 Dec 2023 11:29:53 -0800 Subject: [PATCH 280/301] RM Shadersmod --- .../angelica/client/DefaultTexture.java | 16 - .../angelica/client/HFNoiseTexture.java | 77 - .../angelica/client/IShaderPack.java | 10 - .../angelica/client/MultiTexID.java | 14 - .../angelica/client/ShaderPackDefault.java | 16 - .../angelica/client/ShaderPackFolder.java | 29 - .../angelica/client/ShaderPackNone.java | 16 - .../angelica/client/ShaderPackZip.java | 45 - .../angelica/client/Shaders.java | 3226 ----------------- .../angelica/client/ShadersRender.java | 88 - .../angelica/client/ShadersTess.java | 265 -- .../angelica/client/ShadersTex.java | 882 ----- .../client/gui/AngelicaVideoSettings.java | 25 - .../angelica/client/gui/GuiShaders.java | 321 -- .../angelica/client/gui/GuiShadersButton.java | 24 - .../angelica/client/gui/GuiSlotShaders.java | 71 - .../textures/MixinTextureAtlasSprite.java | 2 +- .../early/shadersmod/lighting/MixinBlock.java | 19 - .../lighting/MixinRenderBlocks.java | 109 - .../renderer/MixinAbstractTexture.java | 29 - .../renderer/MixinDynamicTexture.java | 39 - .../renderer/MixinEntityRenderer.java | 275 -- .../renderer/MixinITextureObject.java | 14 - .../renderer/MixinItemRenderer.java | 45 - .../renderer/MixinLayeredTexture.java | 30 - .../renderer/MixinModelRenderer.java | 27 - .../renderer/MixinOpenGlHelper.java | 19 - .../shadersmod/renderer/MixinRender.java | 19 - .../renderer/MixinRenderBlocks.java | 61 - .../renderer/MixinRenderDragon.java | 26 - .../renderer/MixinRenderEnderman.java | 26 - .../renderer/MixinRenderGlobal.java | 175 - .../renderer/MixinRenderSpider.java | 26 - .../renderer/MixinRendererLivingEntity.java | 84 - .../renderer/MixinSimpleTexture.java | 34 - .../shadersmod/renderer/MixinTessellator.java | 249 -- .../renderer/MixinTextureAtlasSprite.java | 25 - .../renderer/MixinTextureClock.java | 24 - .../renderer/MixinTextureCompass.java | 25 - .../renderer/MixinTextureManager.java | 39 - .../shadersmod/renderer/MixinTextureMap.java | 86 - .../MixinThreadDownloadImageData.java | 28 - .../settings/MixinGuiVideoSettings.java | 44 - .../mixins/early/sodium/MixinEntityFX.java | 2 +- .../interfaces}/ISpriteExt.java | 2 +- .../render/chunk/data/ChunkRenderData.java | 2 +- .../texture/pbr/loader/AtlasPBRLoader.java | 4 +- 47 files changed, 6 insertions(+), 6708 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/DefaultTexture.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/HFNoiseTexture.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/IShaderPack.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/MultiTexID.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/ShaderPackDefault.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/ShaderPackFolder.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/ShaderPackNone.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/ShaderPackZip.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/Shaders.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/ShadersRender.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/ShadersTess.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShaders.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShadersButton.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/client/gui/GuiSlotShaders.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinBlock.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinRenderBlocks.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinAbstractTexture.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinDynamicTexture.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinEntityRenderer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinITextureObject.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinItemRenderer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinModelRenderer.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinOpenGlHelper.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRender.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderBlocks.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderDragon.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderEnderman.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderGlobal.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderSpider.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRendererLivingEntity.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinSimpleTexture.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTessellator.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureAtlasSprite.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureClock.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureCompass.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureManager.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureMap.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinThreadDownloadImageData.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/settings/MixinGuiVideoSettings.java rename src/main/java/com/gtnewhorizons/angelica/{client/textures => mixins/interfaces}/ISpriteExt.java (81%) diff --git a/src/main/java/com/gtnewhorizons/angelica/client/DefaultTexture.java b/src/main/java/com/gtnewhorizons/angelica/client/DefaultTexture.java deleted file mode 100644 index ef44df10d..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/DefaultTexture.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -import net.minecraft.client.renderer.texture.AbstractTexture; -import net.minecraft.client.resources.IResourceManager; - -public class DefaultTexture extends AbstractTexture { - - public DefaultTexture() { - loadTexture(null); - } - - public void loadTexture(IResourceManager resourcemanager) { - int[] aint = ShadersTex.createAIntImage(1, 0xFFFFFFFF); -// ShadersTex.setupTexture(this.angelica$getMultiTexID(), aint, 1, 1, false, false); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/HFNoiseTexture.java b/src/main/java/com/gtnewhorizons/angelica/client/HFNoiseTexture.java deleted file mode 100644 index 05db4ff04..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/HFNoiseTexture.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.GL11; - -import java.nio.ByteBuffer; - -/** - * - * @author Nathanael Lane - */ -public class HFNoiseTexture { - - public int texID; - public int textureUnit; - - public HFNoiseTexture(int width, int height) { - texID = GL11.glGenTextures(); - textureUnit = 15; - - byte[] image = genHFNoiseImage(width, height); - ByteBuffer data = BufferUtils.createByteBuffer(image.length); - data.put(image); - data.flip(); - - // GL13.glActiveTexture(GL13.GL_TEXTURE0 + this.textureUnit); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID); - GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, width, height, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, data); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); - // GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); - } - - public int getID() { - return texID; - } - - public void destroy() { - GL11.glDeleteTextures(texID); - texID = 0; - } - - // from George Marsaglia's paper on XORshift PRNGs - private int random(int seed) { - seed ^= (seed << 13); - seed ^= (seed >> 17); - seed ^= (seed << 5); - return seed; - } - - private byte random(int x, int y, int z) { - int seed = (random(x) + random(y * 19)) * random(z * 23) - z; - return (byte) (random(seed) % 128); - } - - /* - * Just a random value for each pixel to get maximum frequency - */ - private byte[] genHFNoiseImage(int width, int height) { - - byte[] image = new byte[width * height * 3]; - int index = 0; - - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - for (int z = 1; z < 4; z++) { - image[index++] = random(x, y, z); - } - } - } - - return image; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/IShaderPack.java b/src/main/java/com/gtnewhorizons/angelica/client/IShaderPack.java deleted file mode 100644 index 3b9979e0b..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/IShaderPack.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -import java.io.InputStream; - -public interface IShaderPack { - - void close(); - - InputStream getResourceAsStream(String resName); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/MultiTexID.java b/src/main/java/com/gtnewhorizons/angelica/client/MultiTexID.java deleted file mode 100644 index 0c8e18c64..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/MultiTexID.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -public class MultiTexID { - - public int base; - public int norm; - public int spec; - - public MultiTexID(int baseTex, int normTex, int specTex) { - base = baseTex; - norm = normTex; - spec = specTex; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackDefault.java b/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackDefault.java deleted file mode 100644 index e407d4c9f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackDefault.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -import java.io.InputStream; - -public class ShaderPackDefault implements IShaderPack { - - public ShaderPackDefault() {} - - @Override - public void close() {} - - @Override - public InputStream getResourceAsStream(String resName) { - return ShaderPackDefault.class.getResourceAsStream(resName); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackFolder.java b/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackFolder.java deleted file mode 100644 index 682e2c6bd..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackFolder.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; - -public class ShaderPackFolder implements IShaderPack { - - protected File packFile; - - public ShaderPackFolder(String name, File file) { - packFile = file; - } - - @Override - public void close() {} - - @Override - public InputStream getResourceAsStream(String resName) { - try { - File resFile = new File(packFile, resName.substring(1)); - if (resFile != null) { - return new BufferedInputStream(new FileInputStream(resFile)); - } - } catch (Exception excp) {} - return null; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackNone.java b/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackNone.java deleted file mode 100644 index 552bb1606..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackNone.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -import java.io.InputStream; - -public class ShaderPackNone implements IShaderPack { - - public ShaderPackNone() {} - - @Override - public void close() {} - - @Override - public InputStream getResourceAsStream(String resName) { - return null; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackZip.java b/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackZip.java deleted file mode 100644 index 8315a20e5..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShaderPackZip.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -import java.io.File; -import java.io.InputStream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -public class ShaderPackZip implements IShaderPack { - - protected File packFile; - protected ZipFile packZipFile; - - public ShaderPackZip(String name, File file) { - packFile = file; - packZipFile = null; - } - - @Override - public void close() { - if (packZipFile != null) { - try { - packZipFile.close(); - } catch (Exception excp) {} - packZipFile = null; - } - } - - @Override - public InputStream getResourceAsStream(String resName) { - if (packZipFile == null) { - try { - packZipFile = new ZipFile(packFile); - } catch (Exception excp) {} - } - if (packZipFile != null) { - try { - ZipEntry entry = packZipFile.getEntry(resName.substring(1)); - if (entry != null) { - return packZipFile.getInputStream(entry); - } - } catch (Exception excp) {} - } - return null; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java b/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java deleted file mode 100644 index 717880fdc..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/Shaders.java +++ /dev/null @@ -1,3226 +0,0 @@ -// Code written by daxnitro modified by id_miner and karyonix. -// Do what you want with it but give us some credit if you use it in whole or in part. - -package com.gtnewhorizons.angelica.client; - -import com.gtnewhorizons.angelica.Tags; -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; -import com.gtnewhorizons.angelica.mixins.interfaces.IModelRenderer; -import lombok.Getter; -import net.minecraft.block.Block; -import net.minecraft.block.material.Material; -import net.minecraft.client.Minecraft; -import net.minecraft.client.model.ModelBase; -import net.minecraft.client.model.ModelRenderer; -import net.minecraft.client.renderer.EntityRenderer; -import net.minecraft.client.renderer.RenderBlocks; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.entity.Render; -import net.minecraft.client.renderer.entity.RenderManager; -import net.minecraft.client.renderer.entity.RendererLivingEntity; -import net.minecraft.client.renderer.texture.ITextureObject; -import net.minecraft.client.settings.GameSettings; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ChatComponentText; -import net.minecraft.util.Vec3; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.joml.Vector3d; -import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.ContextCapabilities; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL12; -import org.lwjgl.opengl.GL13; -import org.lwjgl.opengl.GL14; -import org.lwjgl.opengl.GL20; -import org.lwjgl.opengl.GL30; -import org.lwjgl.opengl.GLContext; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Properties; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static org.lwjgl.opengl.ARBFragmentShader.GL_FRAGMENT_SHADER_ARB; -import static org.lwjgl.opengl.ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB; -import static org.lwjgl.opengl.ARBShaderObjects.glAttachObjectARB; -import static org.lwjgl.opengl.ARBShaderObjects.glCompileShaderARB; -import static org.lwjgl.opengl.ARBShaderObjects.glCreateProgramObjectARB; -import static org.lwjgl.opengl.ARBShaderObjects.glCreateShaderObjectARB; -import static org.lwjgl.opengl.ARBShaderObjects.glDeleteObjectARB; -import static org.lwjgl.opengl.ARBShaderObjects.glDetachObjectARB; -import static org.lwjgl.opengl.ARBShaderObjects.glGetInfoLogARB; -import static org.lwjgl.opengl.ARBShaderObjects.glGetObjectParameterARB; -import static org.lwjgl.opengl.ARBShaderObjects.glGetUniformLocationARB; -import static org.lwjgl.opengl.ARBShaderObjects.glLinkProgramARB; -import static org.lwjgl.opengl.ARBShaderObjects.glShaderSourceARB; -import static org.lwjgl.opengl.ARBShaderObjects.glUniform1fARB; -import static org.lwjgl.opengl.ARBShaderObjects.glUniform1iARB; -import static org.lwjgl.opengl.ARBShaderObjects.glUniform2iARB; -import static org.lwjgl.opengl.ARBShaderObjects.glUniform3fARB; -import static org.lwjgl.opengl.ARBShaderObjects.glUniformMatrix4ARB; -import static org.lwjgl.opengl.ARBShaderObjects.glUseProgramObjectARB; -import static org.lwjgl.opengl.ARBShaderObjects.glValidateProgramARB; -import static org.lwjgl.opengl.ARBVertexShader.GL_VERTEX_SHADER_ARB; -import static org.lwjgl.opengl.ARBVertexShader.glBindAttribLocationARB; -import static org.lwjgl.opengl.EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT; -import static org.lwjgl.opengl.EXTFramebufferObject.GL_COLOR_ATTACHMENT1_EXT; -import static org.lwjgl.opengl.EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT; -import static org.lwjgl.opengl.EXTFramebufferObject.GL_FRAMEBUFFER_COMPLETE_EXT; -import static org.lwjgl.opengl.EXTFramebufferObject.GL_FRAMEBUFFER_EXT; -import static org.lwjgl.opengl.EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; -import static org.lwjgl.opengl.EXTFramebufferObject.GL_INVALID_FRAMEBUFFER_OPERATION_EXT; -import static org.lwjgl.opengl.EXTFramebufferObject.GL_MAX_COLOR_ATTACHMENTS_EXT; -import static org.lwjgl.opengl.EXTFramebufferObject.glBindFramebufferEXT; -import static org.lwjgl.opengl.EXTFramebufferObject.glCheckFramebufferStatusEXT; -import static org.lwjgl.opengl.EXTFramebufferObject.glDeleteFramebuffersEXT; -import static org.lwjgl.opengl.EXTFramebufferObject.glFramebufferTexture2DEXT; -import static org.lwjgl.opengl.EXTFramebufferObject.glGenFramebuffersEXT; -import static org.lwjgl.util.glu.GLU.gluErrorString; - -public class Shaders { - - public static final String versionString = Tags.VERSION; - public static final int versionNumber = 0x020312; - public static final int buildNumber = 53; - - private static Minecraft mc; - - public static boolean isInitialized = false; - private static boolean notFirstInit = false; - public static ContextCapabilities capabilities; - public static boolean hasGlGenMipmap = false; - public static int numberResetDisplayList = 0; - - private static int renderDisplayWidth = 0; - private static int renderDisplayHeight = 0; - public static int renderWidth = 0; - public static int renderHeight = 0; - - public static boolean isRenderingWorld = false; - public static boolean isRenderingSky = false; - public static boolean isCompositeRendered = false; - public static boolean isRenderingDfb = false; - public static boolean isShadowPass = false; - public static int activeTexUnit = 0; - - public static boolean isHandRendered; - public static ItemStack itemToRender; - - private static float[] sunPosition = new float[4]; - private static float[] moonPosition = new float[4]; - private static float[] upPosition = new float[4]; - - private static float[] upPosModelView = new float[] { 0.0F, 100.0F, 0.0F, 0.0F }; - private static float[] sunPosModelView = new float[] { 0.0F, 100.0F, 0.0F, 0.0F }; - private static float[] moonPosModelView = new float[] { 0.0F, -100.0F, 0.0F, 0.0F }; - private static float[] tempMat = new float[16]; - - private static float clearColorR; - private static float clearColorG; - private static float clearColorB; - - private static float skyColorR; - private static float skyColorG; - private static float skyColorB; - - private static long worldTime = 0; - private static long lastWorldTime = 0; - private static long diffWorldTime = 0; - private static float sunAngle = 0; - private static float shadowAngle = 0; - private static int moonPhase = 0; - - private static long systemTime = 0; - private static long lastSystemTime = 0; - private static long diffSystemTime = 0; - - private static int frameCounter = 0; - private static float frameTimeCounter = 0.0f; - - private static int systemTimeInt32 = 0; - - private static float rainStrength = 0.0f; - private static float wetness = 0.0f; - public static float wetnessHalfLife = 30 * 20; - public static float drynessHalfLife = 10 * 20; - public static float eyeBrightnessHalflife = 10.0f; - private static boolean usewetness = false; - private static int isEyeInWater = 0; - private static int eyeBrightness = 0; - private static float eyeBrightnessFadeX = 0; - private static float eyeBrightnessFadeY = 0; - @Getter - private static float eyePosY = 0; - private static float centerDepth = 0; - private static float centerDepthSmooth = 0; - private static float centerDepthSmoothHalflife = 1.0f; - private static boolean centerDepthSmoothEnabled = false; - private static int superSamplingLevel = 1; - - private static boolean updateChunksErrorRecorded = false; - - private static boolean lightmapEnabled = false; - @Getter - private static boolean fogEnabled = true; - - public static int entityAttrib = 10; - public static int midTexCoordAttrib = 11; - public static boolean useEntityAttrib = false; - public static boolean useMidTexCoordAttrib = false; - public static boolean useMultiTexCoord3Attrib = false; - public static boolean progUseEntityAttrib = false; - public static boolean progUseMidTexCoordAttrib = false; - - public static int atlasSizeX = 0, atlasSizeY = 0; - public static int uniformEntityHurt = -1; - public static int uniformEntityFlash = -1; - public static boolean useEntityHurtFlash; - - private static final double[] previousCameraPosition = new double[3]; - private static final double[] cameraPosition = new double[3]; - - - public static Vector3d getCameraPosition() { - return new Vector3d(cameraPosition[0], cameraPosition[1], cameraPosition[2]); - } - - // Shadow stuff - - // configuration - private static int shadowPassInterval = 0; - public static boolean needResizeShadow = false; - private static int shadowMapWidth = 1024; - private static int shadowMapHeight = 1024; - private static int spShadowMapWidth = 1024; - private static int spShadowMapHeight = 1024; - private static float shadowMapFOV = 90.0f; - private static float shadowMapHalfPlane = 160.0f; - private static boolean shadowMapIsOrtho = true; - - private static int shadowPassCounter = 0; - - private static int preShadowPassThirdPersonView; - - public static boolean shouldSkipDefaultShadow = false; - - private static boolean waterShadowEnabled = false; - - // Color attachment stuff - - private static final int MaxDrawBuffers = 8; - private static final int MaxColorBuffers = 8; - private static final int MaxDepthBuffers = 3; - private static final int MaxShadowColorBuffers = 8; - private static final int MaxShadowDepthBuffers = 2; - private static int usedColorBuffers = 0; - private static int usedDepthBuffers = 0; - private static int usedShadowColorBuffers = 0; - private static int usedShadowDepthBuffers = 0; - private static int usedColorAttachs = 0; - private static int usedDrawBuffers = 0; - - private static int dfb = 0; - private static int sfb = 0; - - private static final int[] gbuffersFormat = new int[MaxColorBuffers]; - - // Program stuff - - public static int activeProgram = 0; - - public static final int ProgramNone = 0; - public static final int ProgramBasic = 1; - public static final int ProgramTextured = 2; - public static final int ProgramTexturedLit = 3; - public static final int ProgramSkyBasic = 4; - public static final int ProgramSkyTextured = 5; - public static final int ProgramClouds = 6; - public static final int ProgramTerrain = 7; - public static final int ProgramTerrainSolid = 8; - public static final int ProgramTerrainCutoutMip = 9; - public static final int ProgramTerrainCutout = 10; - public static final int ProgramDamagedBlock = 11; - public static final int ProgramWater = 12; - public static final int ProgramBlock = 13; - public static final int ProgramBeaconBeam = 14; - public static final int ProgramItem = 15; - public static final int ProgramEntities = 16; - public static final int ProgramArmorGlint = 17; - public static final int ProgramSpiderEyes = 18; - public static final int ProgramHand = 19; - public static final int ProgramWeather = 20; - public static final int ProgramComposite = 21; - public static final int ProgramComposite1 = 22; - public static final int ProgramComposite2 = 23; - public static final int ProgramComposite3 = 24; - public static final int ProgramComposite4 = 25; - public static final int ProgramComposite5 = 26; - public static final int ProgramComposite6 = 27; - public static final int ProgramComposite7 = 28; - public static final int ProgramFinal = 29; - public static final int ProgramShadow = 30; - public static final int ProgramShadowSolid = 31; - public static final int ProgramShadowCutout = 32; - public static final int ProgramDeferred = 33; - public static final int ProgramDeferred1 = 34; - public static final int ProgramDeferred2 = 35; - public static final int ProgramDeferred3 = 36; - public static final int ProgramDeferred4 = 37; - public static final int ProgramDeferred5 = 38; - public static final int ProgramDeferred6 = 39; - public static final int ProgramDeferred7 = 40; - public static final int ProgramHandWater = 41; - public static final int ProgramDeferredLast = 42; - public static final int ProgramCompositeLast = 43; - public static final int ProgramCount = 44; - public static final int MaxCompositePasses = 8; - public static final int MaxDeferredPasses = 8; - - private static final String[] programNames = new String[] { "", "gbuffers_basic", "gbuffers_textured", - "gbuffers_textured_lit", "gbuffers_skybasic", "gbuffers_skytextured", "gbuffers_clouds", "gbuffers_terrain", - "gbuffers_terrain_solid", "gbuffers_terrain_cutout_mip", "gbuffers_terrain_cutout", "gbuffers_damagedblock", "gbuffers_water", - "gbuffers_block", "gbuffers_beaconbeam", "gbuffers_item", "gbuffers_entities", "gbuffers_armor_glint", "gbuffers_spidereyes", - "gbuffers_hand", "gbuffers_weather", "composite", "composite1", "composite2", "composite3", "composite4", "composite5", - "composite6", "composite7", "final", "shadow", "shadow_solid", "shadow_cutout", "deferred", "deferred1", "deferred2", "deferred3", - "deferred4", "deferred5", "deferred6", "deferred7", "gbuffers_hand_water", "deferred_last", "composite_last" - }; - - private static final int[] programBackups = new int[] { - ProgramNone, // none - ProgramNone, // basic - ProgramBasic, // textured - ProgramTextured, // textured/lit - ProgramBasic, // skybasic - ProgramTextured, // skytextured - ProgramTextured, // clouds - ProgramTexturedLit, // terrain - ProgramTerrain, // terrain solid - ProgramTerrain, // terrain solid cutout mip - ProgramTerrain, // terrain solid cutout - ProgramTerrain, // block damage - ProgramTerrain, // water - ProgramTerrain, // block - ProgramTextured, // beacon beam - ProgramTexturedLit, // item - ProgramTexturedLit, // entities - ProgramTextured, // armor glint - ProgramTextured, // spidereyes - ProgramTexturedLit, // hand - ProgramTexturedLit, // weather - ProgramNone, // composite - ProgramNone, // composite1 - ProgramNone, // composite2 - ProgramNone, // composite3 - ProgramNone, // composite4 - ProgramNone, // composite5 - ProgramNone, // composite6 - ProgramNone, // composite7 - ProgramNone, // final - ProgramNone, // shadow - ProgramShadow, // shadow solid - ProgramShadow, // shadow solid cutout - ProgramNone, // deferred - ProgramNone, // deferred1 - ProgramNone, // deferred2 - ProgramNone, // deferred3 - ProgramNone, // deferred4 - ProgramNone, // deferred5 - ProgramNone, // deferred6 - ProgramNone, // deferred7 - ProgramHand, // hand water - ProgramNone, // deferred last - ProgramNone, // composite last - - }; - - private static final int[] programsID = new int[ProgramCount]; - private static final int[] programsRef = new int[ProgramCount]; - private static int programIDCopyDepth = 0; - - private static final String[] programsDrawBufSettings = new String[ProgramCount]; - private static String newDrawBufSetting = null; - private static final IntBuffer[] programsDrawBuffers = new IntBuffer[ProgramCount]; - static IntBuffer activeDrawBuffers = null; - - private static final String[] programsColorAtmSettings = new String[ProgramCount]; - private static String newColorAtmSetting = null; - private static String activeColorAtmSettings = null; - - private static final int[] programsCompositeMipmapSetting = new int[ProgramCount]; - private static int newCompositeMipmapSetting = 0; - private static int activeCompositeMipmapSetting = 0; - - public static Properties loadedShaders = null; - public static Properties shadersConfig = null; - - // public static TextureManager textureManager = null; - public static ITextureObject defaultTexture = null; - public static boolean normalMapEnabled = false; - public static boolean[] shadowHardwareFilteringEnabled = new boolean[MaxShadowDepthBuffers]; - public static boolean[] shadowMipmapEnabled = new boolean[MaxShadowDepthBuffers]; - public static boolean[] shadowFilterNearest = new boolean[MaxShadowDepthBuffers]; - public static boolean[] shadowColorMipmapEnabled = new boolean[MaxShadowColorBuffers]; - public static boolean[] shadowColorFilterNearest = new boolean[MaxShadowColorBuffers]; - - // config - public static boolean configTweakBlockDamage = false; - public static boolean configCloudShadow = true; - public static float configHandDepthMul = 0.125f; - public static float configRenderResMul = 1.0f; - public static float configShadowResMul = 1.0f; - public static int configTexMinFilB = 0; - public static int configTexMinFilN = 0; - public static int configTexMinFilS = 0; - public static int configTexMagFilB = 0; - public static int configTexMagFilN = 0; - public static int configTexMagFilS = 0; - public static boolean configShadowClipFrustrum = true; - public static boolean configNormalMap = true; - public static boolean configSpecularMap = true; - public static boolean configOldLighting = false; - - // related to config - public static final int texMinFilRange = 3; - public static final int texMagFilRange = 2; - public static final String[] texMinFilDesc = { "Nearest", "Nearest-Nearest", "Nearest-Linear" }; - public static final String[] texMagFilDesc = { "Nearest", "Linear" }; - public static final int[] texMinFilValue = { GL11.GL_NEAREST, GL11.GL_NEAREST_MIPMAP_NEAREST, - GL11.GL_NEAREST_MIPMAP_LINEAR }; - public static final int[] texMagFilValue = { GL11.GL_NEAREST, GL11.GL_LINEAR }; - - // shaderpack - public static IShaderPack shaderPack = null; - public static File currentshader; - public static String currentshadername; - public static String packNameNone = "(none)"; - public static String packNameDefault = "(internal)"; - public static String shaderpacksdirname = "shaderpacks"; - public static String optionsfilename = "optionsshaders.txt"; - public static File shadersdir = new File(Minecraft.getMinecraft().mcDataDir, "shaders"); - public static File shaderpacksdir = new File(Minecraft.getMinecraft().mcDataDir, shaderpacksdirname); - public static File configFile = new File(Minecraft.getMinecraft().mcDataDir, optionsfilename); - - public static final boolean enableShadersOption = true; - private static final boolean enableShadersDebug = true; - - public static float blockLightLevel05 = 0.5f; - public static float blockLightLevel06 = 0.6f; - public static float blockLightLevel08 = 0.8f; - - public static float aoLevel = 0.8f; - public static float blockAoLight = 1.0f - aoLevel; - - public static float sunPathRotation = 0.0f; - public static float shadowAngleInterval = 0.0f; - public static int fogMode = 0; - public static float fogDensity = 0; - public static float fogStart = 0; - public static float fogEnd = 0; - - public static float fogColorR, fogColorG, fogColorB; - public static float shadowIntervalSize = 2.0f; - public static int terrainIconSize = 16; - public static int[] terrainTextureSize = new int[2]; - - private static HFNoiseTexture noiseTexture; - private static boolean noiseTextureEnabled = false; - private static int noiseTextureResolution = 256; - - // direct buffers - private static final int bigBufferSize = (16 * 12 + MaxColorBuffers + MaxDepthBuffers + MaxShadowColorBuffers + MaxShadowDepthBuffers + MaxDrawBuffers * 8 + MaxDrawBuffers * ProgramCount) * 4; - private static final ByteBuffer bigBuffer = (ByteBuffer) BufferUtils.createByteBuffer(bigBufferSize).limit(0); - - private static final FloatBuffer previousProjection = nextFloatBuffer(16); - private static final FloatBuffer projection = nextFloatBuffer(16); - private static final FloatBuffer projectionInverse = nextFloatBuffer(16); - private static final FloatBuffer previousModelView = nextFloatBuffer(16); - private static final FloatBuffer modelView = nextFloatBuffer(16); - private static final FloatBuffer modelViewInverse = nextFloatBuffer(16); - private static final FloatBuffer shadowProjection = nextFloatBuffer(16); - private static final FloatBuffer shadowProjectionInverse = nextFloatBuffer(16); - private static final FloatBuffer shadowModelView = nextFloatBuffer(16); - private static final FloatBuffer shadowModelViewInverse = nextFloatBuffer(16); - private static final FloatBuffer tempMatrixDirectBuffer = nextFloatBuffer(16); - private static final FloatBuffer tempDirectFloatBuffer = nextFloatBuffer(16); - - private static final IntBuffer dfbColorTextures = nextIntBuffer(MaxColorBuffers); - private static final IntBuffer dfbDepthTextures = nextIntBuffer(MaxDepthBuffers); - private static final IntBuffer sfbColorTextures = nextIntBuffer(MaxShadowColorBuffers); - private static final IntBuffer sfbDepthTextures = nextIntBuffer(MaxShadowDepthBuffers); - - static final IntBuffer dfbDrawBuffers = nextIntBuffer(MaxDrawBuffers); - static final IntBuffer sfbDrawBuffers = nextIntBuffer(MaxDrawBuffers); - static final IntBuffer drawBuffersNone = nextIntBuffer(MaxDrawBuffers); - static final IntBuffer drawBuffersAll = nextIntBuffer(MaxDrawBuffers); - static final IntBuffer drawBuffersClear0 = nextIntBuffer(MaxDrawBuffers); - static final IntBuffer drawBuffersClear1 = nextIntBuffer(MaxDrawBuffers); - static final IntBuffer drawBuffersClearColor = nextIntBuffer(MaxDrawBuffers); - static final IntBuffer drawBuffersColorAtt0 = nextIntBuffer(MaxDrawBuffers); - - static final IntBuffer[] drawBuffersBuffer = nextIntBufferArray(ProgramCount, MaxDrawBuffers); - - static { - drawBuffersNone.limit(0); - drawBuffersColorAtt0.put(GL_COLOR_ATTACHMENT0_EXT).position(0).limit(1); - } - - private Shaders() {} - - /** set position to limit and advance limit by size */ - private static ByteBuffer nextByteBuffer(int size) { - ByteBuffer buffer = bigBuffer; - int pos = buffer.limit(); - buffer.position(pos).limit(pos + size); - return buffer.slice(); - } - - private static IntBuffer nextIntBuffer(int size) { - ByteBuffer buffer = bigBuffer; - int pos = buffer.limit(); - buffer.position(pos).limit(pos + size * 4); - return buffer.asIntBuffer(); - } - - private static FloatBuffer nextFloatBuffer(int size) { - ByteBuffer buffer = bigBuffer; - int pos = buffer.limit(); - buffer.position(pos).limit(pos + size * 4); - return buffer.asFloatBuffer(); - } - - private static IntBuffer[] nextIntBufferArray(int count, int size) { - IntBuffer[] aib = new IntBuffer[count]; - for (int i = 0; i < count; ++i) aib[i] = nextIntBuffer(size); - return aib; - } - - public static void loadConfig() { - AngelicaTweaker.LOGGER.info("[Shaders] Loading configuration."); - try { - if (!shaderpacksdir.exists()) shaderpacksdir.mkdir(); - } catch (Exception e) { - AngelicaTweaker.LOGGER.warn("[Shaders] Failed openning shaderpacks directory."); - } - - shadersConfig = new Properties(); - shadersConfig.setProperty("shaderPack", ""); - if (configFile.exists()) { - try { - FileReader reader = new FileReader(configFile); - shadersConfig.load(reader); - reader.close(); - } catch (Exception ignored) {} - } - - if (!configFile.exists()) { - try { - storeConfig(); - } catch (Exception ignored) {} - } - configNormalMap = Boolean.parseBoolean(shadersConfig.getProperty("normalMapEnabled", "true")); - configSpecularMap = Boolean.parseBoolean(shadersConfig.getProperty("specularMapEnabled", "true")); - configTweakBlockDamage = Boolean.parseBoolean(shadersConfig.getProperty("tweakBlockDamage", shadersConfig.getProperty("dtweak", "false"))); - configCloudShadow = Boolean.parseBoolean(shadersConfig.getProperty("cloudShadow", "true")); - configHandDepthMul = Float.parseFloat(shadersConfig.getProperty("handDepthMul", "0.125")); - configRenderResMul = Float.parseFloat(shadersConfig.getProperty("renderResMul", "1.0")); - configShadowResMul = Float.parseFloat(shadersConfig.getProperty("shadowResMul", "1.0")); - configShadowClipFrustrum = Boolean.parseBoolean(shadersConfig.getProperty("shadowClipFrustrum", "true")); - configOldLighting = Boolean.parseBoolean(shadersConfig.getProperty("oldLighting", "false")); - configTexMinFilB = Integer.parseInt(shadersConfig.getProperty("TexMinFilB", "0")) % texMinFilRange; - configTexMinFilN = Integer.parseInt(shadersConfig.getProperty("TexMinFilN", Integer.toString(configTexMinFilB))) % texMinFilRange; - configTexMinFilS = Integer.parseInt(shadersConfig.getProperty("TexMinFilS", Integer.toString(configTexMinFilB))) % texMinFilRange; - configTexMagFilB = Integer.parseInt(shadersConfig.getProperty("TexMagFilB", "0")) % texMagFilRange; - configTexMagFilN = Integer.parseInt(shadersConfig.getProperty("TexMagFilN", "0")) % texMagFilRange; - configTexMagFilS = Integer.parseInt(shadersConfig.getProperty("TexMagFilS", "0")) % texMagFilRange; - currentshadername = shadersConfig.getProperty("shaderPack", packNameDefault); - loadShaderPack(); - } - - public static void storeConfig() { - AngelicaTweaker.LOGGER.info("[Shaders] Save configuration."); - shadersConfig.setProperty("normalMapEnabled", Boolean.toString(configNormalMap)); - shadersConfig.setProperty("specularMapEnabled", Boolean.toString(configSpecularMap)); - shadersConfig.setProperty("tweakBlockDamage", Boolean.toString(configTweakBlockDamage)); - shadersConfig.setProperty("cloudShadow", Boolean.toString(configCloudShadow)); - shadersConfig.setProperty("handDepthMul", Float.toString(configHandDepthMul)); - shadersConfig.setProperty("renderResMul", Float.toString(configRenderResMul)); - shadersConfig.setProperty("shadowResMul", Float.toString(configShadowResMul)); - shadersConfig.setProperty("shadowClipFrustrum", Boolean.toString(configShadowClipFrustrum)); - shadersConfig.setProperty("oldLighting", Boolean.toString(configOldLighting)); - shadersConfig.setProperty("TexMinFilB", Integer.toString(configTexMinFilB)); - shadersConfig.setProperty("TexMinFilN", Integer.toString(configTexMinFilN)); - shadersConfig.setProperty("TexMinFilS", Integer.toString(configTexMinFilS)); - shadersConfig.setProperty("TexMagFilB", Integer.toString(configTexMagFilB)); - shadersConfig.setProperty("TexMagFilN", Integer.toString(configTexMagFilN)); - shadersConfig.setProperty("TexMagFilS", Integer.toString(configTexMagFilS)); - try { - FileWriter writer = new FileWriter(configFile); - shadersConfig.store(writer, null); - writer.close(); - } catch (Exception ignored) {} - } - - public static void setShaderPack(String par1name) { - currentshadername = par1name; - shadersConfig.setProperty("shaderPack", par1name); - // loadShaderPack(); - } - - public static void loadShaderPack() { - if (shaderPack != null) { - shaderPack.close(); - shaderPack = null; - } - String packName = shadersConfig.getProperty("shaderPack", packNameDefault); - if (!packName.isEmpty() && !packName.equals(packNameNone)) { - if (packName.equals(packNameDefault)) { - shaderPack = new ShaderPackDefault(); - } else { - try { - File packFile = new File(shaderpacksdir, packName); - if (packFile.isDirectory()) { - shaderPack = new ShaderPackFolder(packName, packFile); - } else if (packFile.isFile() && packName.toLowerCase().endsWith(".zip")) { - shaderPack = new ShaderPackZip(packName, packFile); - } - } catch (Exception e) {} - } - } - if (shaderPack != null) { - AngelicaTweaker.LOGGER.info("[Shaders] Loaded shaderpack."); - } else { - AngelicaTweaker.LOGGER.error("[Shaders] Did not load shaderpack."); - shaderPack = new ShaderPackNone(); - } - } - - public static List listofShaders() { - List list = new ArrayList<>(); - list.add(packNameNone); - list.add(packNameDefault); - try { - if (!shaderpacksdir.exists()) shaderpacksdir.mkdir(); - File[] listOfFiles = shaderpacksdir.listFiles(); - for (int i = 0; i < listOfFiles.length; i++) { - File file = listOfFiles[i]; - String name = file.getName(); - if (file.isDirectory() || file.isFile() && name.toLowerCase().endsWith(".zip")) { - list.add(name); - } - } - } catch (Exception ignored) {} - return list; - } - - static String versiontostring(int vv) { - String vs = Integer.toString(vv); - return Integer.toString(Integer.parseInt(vs.substring(1, 3))) + "." - + Integer.toString(Integer.parseInt(vs.substring(3, 5))) - + "." - + Integer.toString(Integer.parseInt(vs.substring(5))); - } - - - public static int checkFramebufferStatus(String location) { - int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - AngelicaTweaker.LOGGER.error(String.format("FramebufferStatus 0x%04X at %s", status, location)); - return status; - } - - public static int checkGLError(String location) { - int errorCode = GL11.glGetError(); - if (errorCode != GL11.GL_NO_ERROR) { - boolean skipPrint = false; - if (!skipPrint) { - if (errorCode == GL_INVALID_FRAMEBUFFER_OPERATION_EXT) { - int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - AngelicaTweaker.LOGGER.error(String.format("GL error 0x%04X: %s (Fb status 0x%04X) at %s", errorCode, gluErrorString(errorCode), status, location)); - } else { - AngelicaTweaker.LOGGER.error(String.format("GL error 0x%04X: %s at %s", errorCode, gluErrorString(errorCode), location)); - } - } - } - return errorCode; - } - - public static int checkGLError(String location, String info) { - int errorCode = GL11.glGetError(); - if (errorCode != GL11.GL_NO_ERROR) { - AngelicaTweaker.LOGGER.error(String.format("GL error 0x%04x: %s at %s %s", errorCode, gluErrorString(errorCode), location, info)); - } - return errorCode; - } - - public static int checkGLError(String location, String info1, String info2) { - int errorCode = GL11.glGetError(); - if (errorCode != GL11.GL_NO_ERROR) { - AngelicaTweaker.LOGGER.error(String.format("GL error 0x%04x: %s at %s %s %s", errorCode, gluErrorString(errorCode), location, info1, info2)); - } - return errorCode; - } - - private static String printChatAndLogError(String str) { - mc.ingameGUI.getChatGUI().printChatMessage(new ChatComponentText(str)); - AngelicaTweaker.LOGGER.error(str); - return str; - } - - public static void printIntBuffer(String title, IntBuffer buf) { - StringBuilder sb = new StringBuilder(128); - sb.append(title).append(" [pos ").append(buf.position()).append(" lim ").append(buf.limit()).append(" cap ") - .append(buf.capacity()).append(" :"); - for (int lim = buf.limit(), i = 0; i < lim; ++i) sb.append(" ").append(buf.get(i)); - sb.append("]"); - AngelicaTweaker.LOGGER.debug(sb.toString()); - } - - public static void startup(Minecraft mc) { - Shaders.mc = mc; - AngelicaTweaker.LOGGER.info("Angelica version " + versionString); - Shaders.loadConfig(); - } - - private static String toStringYN(boolean b) { - return b ? "Y" : "N"; - } - - public static void updateBlockLightLevel() { - if (configOldLighting) { - blockLightLevel05 = 0.5f; - blockLightLevel06 = 0.6f; - blockLightLevel08 = 0.8f; - } else { - blockLightLevel05 = 1.0f; - blockLightLevel06 = 1.0f; - blockLightLevel08 = 1.0f; - } - } - - public static void init() { - if (true) return; - if (isInitialized) { - return; - } - mc = Minecraft.getMinecraft(); - checkGLError("Shaders.init pre"); - capabilities = GLContext.getCapabilities(); - AngelicaTweaker.LOGGER.debug( - "[Shaders] OpenGL 2.0 = " + toStringYN(capabilities.OpenGL20) - + " 2.1 = " + toStringYN(capabilities.OpenGL21) - + " 3.0 = " + toStringYN(capabilities.OpenGL30) - + " 3.2 = " + toStringYN(capabilities.OpenGL32)); - if (!capabilities.OpenGL21) { - printChatAndLogError("[Shaders] No OpenGL 2.1."); - } - if (!capabilities.GL_EXT_framebuffer_object) { - printChatAndLogError("[Shaders] No EXT_framebuffer_object."); - } - if (!capabilities.OpenGL20 || !capabilities.GL_EXT_framebuffer_object) { - printChatAndLogError("[Shaders] Your GPU is not compatible with the Shaders mod."); - } - - hasGlGenMipmap = capabilities.OpenGL30; - dfbDrawBuffers.position(0).limit(MaxDrawBuffers); - dfbColorTextures.position(0).limit(MaxColorBuffers); - dfbDepthTextures.position(0).limit(MaxDepthBuffers); - sfbDrawBuffers.position(0).limit(MaxDrawBuffers); - sfbDepthTextures.position(0).limit(MaxShadowDepthBuffers); - sfbColorTextures.position(0).limit(MaxShadowColorBuffers); - - int maxDrawBuffers = GL11.glGetInteger(GL20.GL_MAX_DRAW_BUFFERS); - int maxColorAttach = GL11.glGetInteger(GL_MAX_COLOR_ATTACHMENTS_EXT); - AngelicaTweaker.LOGGER.debug("[Shaders] GL_MAX_DRAW_BUFFERS = " + maxDrawBuffers); - AngelicaTweaker.LOGGER.debug("[Shaders] GL_MAX_COLOR_ATTACHMENTS_EXT = " + maxColorAttach); - AngelicaTweaker.LOGGER.debug("[Shaders] GL_MAX_TEXTURE_IMAGE_UNITS = " + GL11.glGetInteger(GL20.GL_MAX_TEXTURE_IMAGE_UNITS)); - - usedColorBuffers = 4; - usedDepthBuffers = 1; - usedShadowColorBuffers = 0; - usedShadowDepthBuffers = 0; - usedColorAttachs = 1; - usedDrawBuffers = 1; - Arrays.fill(gbuffersFormat, GL11.GL_RGBA); - // Arrays.fill(gbuffersClear, true); - Arrays.fill(shadowHardwareFilteringEnabled, false); - Arrays.fill(shadowMipmapEnabled, false); - Arrays.fill(shadowFilterNearest, false); - Arrays.fill(shadowColorMipmapEnabled, false); - Arrays.fill(shadowColorFilterNearest, false); - centerDepthSmoothEnabled = false; - noiseTextureEnabled = false; - sunPathRotation = 0f; - shadowIntervalSize = 2.0f; - aoLevel = 0.8f; - blockAoLight = 1.0f - aoLevel; - useEntityAttrib = false; - useMidTexCoordAttrib = false; - useMultiTexCoord3Attrib = false; - waterShadowEnabled = false; - updateChunksErrorRecorded = false; - updateBlockLightLevel(); - - for (int i = 0; i < ProgramCount; ++i) { - if (programNames[i].isEmpty()) { - programsID[i] = programsRef[i] = 0; - programsDrawBufSettings[i] = null; - programsColorAtmSettings[i] = null; - programsCompositeMipmapSetting[i] = 0; - } else { - newDrawBufSetting = null; - newColorAtmSetting = null; - newCompositeMipmapSetting = 0; - final String str = "/shaders/" + programNames[i]; - int pr = setupProgram( i, str + ".vsh", str + ".fsh"); - programsID[i] = programsRef[i] = pr; - programsDrawBufSettings[i] = (pr != 0) ? newDrawBufSetting : null; - programsColorAtmSettings[i] = (pr != 0) ? newColorAtmSetting : null; - programsCompositeMipmapSetting[i] = (pr != 0) ? newCompositeMipmapSetting : 0; - } - } - - for (int p = 0; p < ProgramCount; ++p) { - if (p == ProgramFinal) { - programsDrawBuffers[p] = null; - } else if (programsID[p] == 0) { - if (p == ProgramShadow) { - programsDrawBuffers[p] = drawBuffersNone; - } else { - programsDrawBuffers[p] = drawBuffersColorAtt0; - } - } else { - String str = programsDrawBufSettings[p]; - if (str != null) { - IntBuffer intbuf = drawBuffersBuffer[p]; - int numDB = str.length(); - if (numDB > usedDrawBuffers) { - usedDrawBuffers = numDB; - } - if (numDB > maxDrawBuffers) { - numDB = maxDrawBuffers; - } - programsDrawBuffers[p] = intbuf; - intbuf.limit(numDB); - for (int i = 0; i < numDB; ++i) { - int d = GL11.GL_NONE; - if (str.length() > i) { - int ca = str.charAt(i) - '0'; - if (p != ProgramShadow) { - if (ca >= 0 && ca <= 7) { - d = ca + GL_COLOR_ATTACHMENT0_EXT; - if (ca > usedColorAttachs) { - usedColorAttachs = ca; - } - if (ca > usedColorBuffers) { - usedColorBuffers = ca; - } - } - } else { - if (ca >= 0 && ca <= 1) { - d = ca + GL_COLOR_ATTACHMENT0_EXT; - if (ca > usedShadowColorBuffers) { - usedShadowColorBuffers = ca; - } - } - } - } - intbuf.put(i, d); - } - } else { - if (p != ProgramShadow) { - programsDrawBuffers[p] = dfbDrawBuffers; - usedDrawBuffers = usedColorBuffers; - } else { - programsDrawBuffers[p] = sfbDrawBuffers; - } - } - } - } - - // TO DO: add color attachment option - usedColorAttachs = usedColorBuffers; - - shadowPassInterval = (usedShadowDepthBuffers > 0) ? 1 : 0; - shouldSkipDefaultShadow = (usedShadowDepthBuffers > 0); - - dfbDrawBuffers.position(0).limit(usedDrawBuffers); - dfbColorTextures.position(0).limit(usedColorBuffers); - // dfbRenderBuffers.limit(colorAttachments); - - for (int i = 0; i < usedDrawBuffers; ++i) { - dfbDrawBuffers.put(i, GL_COLOR_ATTACHMENT0_EXT + i); - } - - if (usedDrawBuffers > maxDrawBuffers) { - printChatAndLogError( - "[Shaders] Not enough draw buffers! Requires " + usedDrawBuffers - + ". Has " - + maxDrawBuffers - + "."); - } - - sfbDrawBuffers.position(0).limit(usedShadowColorBuffers); - for (int i = 0; i < usedShadowColorBuffers; ++i) { - sfbDrawBuffers.put(i, GL_COLOR_ATTACHMENT0_EXT + i); - } - - // Use programBackups for missing programs - for (int i = 0; i < ProgramCount; ++i) { - int n = i; - while (programsID[n] == 0 && programBackups[n] != n) n = programBackups[n]; - if (n != i && i != ProgramShadow) { - programsID[i] = programsID[n]; - programsDrawBufSettings[i] = programsDrawBufSettings[n]; - programsDrawBuffers[i] = programsDrawBuffers[n]; - } - } - - // printIntBuffer("dfb drawbuffers",dfbDrawBuffers); - // printIntBuffer("sfb drawbuffers",sfbDrawBuffers); - // printIntBuffer("pgshadow drawbf",programsDrawBuffers[ProgramShadow]); - - // setup scene frame buffer and textures - resize(); - - // setup shadow frame buffer and texture - resizeShadow(); - - if (noiseTextureEnabled) setupNoiseTexture(); - - if (defaultTexture == null) defaultTexture = ShadersTex.createDefaultTexture(); - // TextureNM texBlocks = (TextureNM)textureManager.textureMapBlocks.getTexture(); - // TextureNM texItems = (TextureNM)textureManager.textureMapBlocks.getTexture(); - // terrainTextureIdArray = new int[] { texBlocks.getGlTextureId(), texBlocks.normalMap.getGlTextureId(), - // texBlocks.specularMap.getGlTextureId() }; - // textureIdMap.put(terrainTextureIdArray[0], terrainTextureIdArray); - // int[] itemsTextureIdArray; - // itemsTextureIdArray = new int[] { texItems.getGlTextureId(), texItems.normalMap.getGlTextureId(), - // texItems.specularMap.getGlTextureId() }; - // textureIdMap.put(itemsTextureIdArray[0], itemsTextureIdArray); - - isInitialized = true; - - resetDisplayList(); - if (notFirstInit) { - mc.ingameGUI.getChatGUI().printChatMessage(new ChatComponentText("Shaders initialized.")); - } - checkGLError("Shaders.init"); - } - - public static void resetDisplayList() { - if (true) return; - ++numberResetDisplayList; - AngelicaTweaker.LOGGER.debug("Reset model renderers"); - if (Shaders.useMidTexCoordAttrib || Shaders.useMultiTexCoord3Attrib) { - for (Render ren : RenderManager.instance.entityRenderMap.values()) { - if (ren instanceof RendererLivingEntity rle) { - // System.out.format("Reset %s\n", rle.toString()); - resetDisplayListModel(rle.mainModel); - resetDisplayListModel(rle.renderPassModel); - } - } - } - AngelicaTweaker.LOGGER.debug("Reset world renderers"); - mc.renderGlobal.loadRenderers(); - } - - public static void resetDisplayListModel(ModelBase mbase) { - if (true) return; - if (mbase != null) { - for (ModelRenderer obj : mbase.boxList) { - if (obj != null) { - resetDisplayListModelRenderer(obj); - } - } - } - } - - public static void resetDisplayListModelRenderer(ModelRenderer mrr) { - if (true) return; - ((IModelRenderer) mrr).angelica$resetDisplayList(); - - if (mrr.childModels != null) { - for (int i = 0, n = mrr.childModels.size(); i < n; ++i) { - resetDisplayListModelRenderer((ModelRenderer) mrr.childModels.get(i)); - } - } - } - - // ---------------------------------------- - - private static int setupProgram(int program, String vShaderPath, String fShaderPath) { - if (true) return 0; - checkGLError("pre setupProgram"); - int programid = glCreateProgramObjectARB(); - checkGLError("create"); - if (programid == 0) { - return programid; - } - progUseEntityAttrib = false; - progUseMidTexCoordAttrib = false; - int vShader = createVertShader(vShaderPath); - int fShader = createFragShader(fShaderPath); - checkGLError("create"); - if (vShader == 0 && fShader == 0) { - glDeleteObjectARB(programid); - programid = 0; - return programid; - } - - if (vShader != 0) { - glAttachObjectARB(programid, vShader); - checkGLError("attach"); - } - if (fShader != 0) { - glAttachObjectARB(programid, fShader); - checkGLError("attach"); - } - if (progUseEntityAttrib) { - glBindAttribLocationARB(programid, entityAttrib, "mc_Entity"); - checkGLError("mc_Entity"); - } - if (progUseMidTexCoordAttrib) { - glBindAttribLocationARB(programid, midTexCoordAttrib, "mc_midTexCoord"); - checkGLError("mc_midTexCoord"); - } - glLinkProgramARB(programid); - if (vShader != 0) { - glDetachObjectARB(programid, vShader); - glDeleteObjectARB(vShader); - } - if (fShader != 0) { - glDetachObjectARB(programid, fShader); - glDeleteObjectARB(fShader); - } - programsID[program] = programid; - useProgram(program); - glValidateProgramARB(programid); - useProgram(ProgramNone); - printLogInfo(programid, vShaderPath + "," + fShaderPath); - int valid = GL20.glGetProgrami(programid, GL20.GL_VALIDATE_STATUS); - if (valid == GL11.GL_TRUE) { - AngelicaTweaker.LOGGER.debug("Program " + programNames[program] + " loaded"); - } else { - printChatAndLogError("[Shaders] Error : Invalid program " + programNames[program]); - glDeleteObjectARB(programid); - programid = 0; - } - - return programid; - } - - private static InputStream locateShaderStream(String path) { - try { - return shaderPack.getResourceAsStream(path); - } catch (Exception e) { - try { - return FileUtils.openInputStream(new File(path)); - } catch (Exception e2) { - throw new RuntimeException("Could not locate shader input " + path, e); - } - } - } - - private static String getPreprocessedShaderSources(String filename) { - filename = filename.replace('\\', '/'); - int lastSlash = filename.lastIndexOf('/'); - final String basename = (lastSlash == -1) ? "/" : filename.substring(0, lastSlash + 1); - try (InputStream is = locateShaderStream(filename)) { - if (is == null) { - AngelicaTweaker.LOGGER.debug("PreprocessedShader not found: " + filename); - throw new FileNotFoundException(filename); - } - String source = IOUtils.toString(is, StandardCharsets.UTF_8).replace("\r\n", "\n"); - StringBuffer output = new StringBuffer(2 * source.length() + 64); - - final Matcher includes = INCLUDE_PATTERN.matcher(source); - while (includes.find()) { - final String relPath = includes.group(1).replace('\\', '/'); - final String path = relPath.startsWith("/") ? ("/shaders" + relPath) : (basename + relPath); - final String src = getPreprocessedShaderSources(path); - includes.appendReplacement(output, src); - } - includes.appendTail(output); - return output.toString(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private static int createVertShader(String filename) { - if (true) return 0; - int vertShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); - if (vertShader == 0) { - return 0; - } - String shaderSrc; - try { - shaderSrc = getPreprocessedShaderSources(filename); - - for (String line : StringUtils.split(shaderSrc, '\n')) { - processVertShaderLine(line); - } - } catch (Exception e) { - glDeleteObjectARB(vertShader); - return 0; - } - - glShaderSourceARB(vertShader, shaderSrc); - glCompileShaderARB(vertShader); - printLogInfo(vertShader, filename); - return vertShader; - } - - private static void processVertShaderLine(String line) { - if (line.matches("attribute [_a-zA-Z0-9]+ mc_Entity.*")) { - useEntityAttrib = true; - progUseEntityAttrib = true; - } else if (line.matches("attribute [_a-zA-Z0-9]+ mc_midTexCoord.*")) { - useMidTexCoordAttrib = true; - progUseMidTexCoordAttrib = true; - } else if (line.matches(".*gl_MultiTexCoord3.*")) { - useMultiTexCoord3Attrib = true; - } - } - - private static final Pattern gbufferFormatPattern = Pattern - .compile("[ \t]*const[ \t]*int[ \t]*(\\w+)Format[ \t]*=[ \t]*([RGBA81632F]*)[ \t]*;.*"); - private static final Pattern gbufferMipmapEnabledPattern = Pattern - .compile("[ \t]*const[ \t]*bool[ \t]*(\\w+)MipmapEnabled[ \t]*=[ \t]*true[ \t]*;.*"); - - private static final Pattern INCLUDE_PATTERN = Pattern - .compile("^\\s*#include\\s+\"([A-Za-z0-9_\\/\\.]+)\".*$", Pattern.MULTILINE | Pattern.UNIX_LINES); - - private static int createFragShader(String filename) { - if (true) return 0; - int fragShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); - if (fragShader == 0) { - return 0; - } - String shaderSrc; - try { - shaderSrc = getPreprocessedShaderSources(filename); - - for (String line : StringUtils.split(shaderSrc, '\n')) { - processFragShaderLine(line, filename); - } - } catch (Exception e) { - glDeleteObjectARB(fragShader); - return 0; - } - - glShaderSourceARB(fragShader, shaderSrc); - glCompileShaderARB(fragShader); - printLogInfo(fragShader, filename); - return fragShader; - } - - // TODO: refactor this mess - private static void processFragShaderLine(String line, String filename) { - if (line.matches("#version .*")) { - // Do nothing - } else if (line.matches("uniform [ _a-zA-Z0-9]+ shadow;.*")) { - if (usedShadowDepthBuffers < 1) usedShadowDepthBuffers = 1; - } else if (line.matches("uniform [ _a-zA-Z0-9]+ watershadow;.*")) { - waterShadowEnabled = true; - if (usedShadowDepthBuffers < 2) usedShadowDepthBuffers = 2; - } else if (line.matches("uniform [ _a-zA-Z0-9]+ shadowtex0;.*")) { - if (usedShadowDepthBuffers < 1) usedShadowDepthBuffers = 1; - } else if (line.matches("uniform [ _a-zA-Z0-9]+ shadowtex1;.*")) { - if (usedShadowDepthBuffers < 2) usedShadowDepthBuffers = 2; - } else if (line.matches("uniform [ _a-zA-Z0-9]+ shadowcolor;.*")) { - if (usedShadowColorBuffers < 1) usedShadowColorBuffers = 1; - } else if (line.matches("uniform [ _a-zA-Z0-9]+ shadowcolor0;.*")) { - if (usedShadowColorBuffers < 1) usedShadowColorBuffers = 1; - } else if (line.matches("uniform [ _a-zA-Z0-9]+ shadowcolor1;.*")) { - if (usedShadowColorBuffers < 2) usedShadowColorBuffers = 2; - } else if (line.matches("uniform [ _a-zA-Z0-9]+ depthtex0;.*")) { - if (usedDepthBuffers < 1) usedDepthBuffers = 1; - } else if (line.matches("uniform [ _a-zA-Z0-9]+ depthtex1;.*")) { - if (usedDepthBuffers < 2) usedDepthBuffers = 2; - } else if (line.matches("uniform [ _a-zA-Z0-9]+ depthtex2;.*")) { - if (usedDepthBuffers < 3) usedDepthBuffers = 3; - } else if (line.matches("uniform [ _a-zA-Z0-9]+ gdepth;.*")) { - if (gbuffersFormat[1] == GL11.GL_RGBA) gbuffersFormat[1] = GL30.GL_RGBA32F; - } else if (usedColorBuffers < 5 && line.matches("uniform [ _a-zA-Z0-9]+ gaux1;.*")) { - usedColorBuffers = 5; - } else if (usedColorBuffers < 6 && line.matches("uniform [ _a-zA-Z0-9]+ gaux2;.*")) { - usedColorBuffers = 6; - } else if (usedColorBuffers < 7 && line.matches("uniform [ _a-zA-Z0-9]+ gaux3;.*")) { - usedColorBuffers = 7; - } else if (usedColorBuffers < 8 && line.matches("uniform [ _a-zA-Z0-9]+ gaux4;.*")) { - usedColorBuffers = 8; - } else if (usedColorBuffers < 5 && line.matches("uniform [ _a-zA-Z0-9]+ colortex4;.*")) { - usedColorBuffers = 5; - } else if (usedColorBuffers < 6 && line.matches("uniform [ _a-zA-Z0-9]+ colortex5;.*")) { - usedColorBuffers = 6; - } else if (usedColorBuffers < 7 && line.matches("uniform [ _a-zA-Z0-9]+ colortex6;.*")) { - usedColorBuffers = 7; - } else if (usedColorBuffers < 8 && line.matches("uniform [ _a-zA-Z0-9]+ colortex7;.*")) { - usedColorBuffers = 8; - - } else if (usedColorBuffers < 8 && line.matches("uniform [ _a-zA-Z0-9]+ centerDepthSmooth;.*")) { - centerDepthSmoothEnabled = true; - - // Shadow resolution - } else if (line.matches("/\\* SHADOWRES:[0-9]+ \\*/.*")) { - String[] parts = line.split("(:| )", 4); - AngelicaTweaker.LOGGER.debug("Shadow map resolution: " + parts[2]); - spShadowMapWidth = spShadowMapHeight = Integer.parseInt(parts[2]); - shadowMapWidth = shadowMapHeight = Math.round(spShadowMapWidth * configShadowResMul); - - } else if (line.matches("[ \t]*const[ \t]*int[ \t]*shadowMapResolution[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("Shadow map resolution: " + parts[1]); - spShadowMapWidth = spShadowMapHeight = Integer.parseInt(parts[1]); - shadowMapWidth = shadowMapHeight = Math.round(spShadowMapWidth * configShadowResMul); - - } else if (line.matches("/\\* SHADOWFOV:[0-9\\.]+ \\*/.*")) { - String[] parts = line.split("(:| )", 4); - AngelicaTweaker.LOGGER.debug("Shadow map field of view: " + parts[2]); - shadowMapFOV = Float.parseFloat(parts[2]); - shadowMapIsOrtho = false; - - // Shadow distance - } else if (line.matches("/\\* SHADOWHPL:[0-9\\.]+ \\*/.*")) { - String[] parts = line.split("(:| )", 4); - AngelicaTweaker.LOGGER.debug("Shadow map half-plane: " + parts[2]); - shadowMapHalfPlane = Float.parseFloat(parts[2]); - shadowMapIsOrtho = true; - - } else if (line.matches("[ \t]*const[ \t]*float[ \t]*shadowDistance[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("Shadow map distance: " + parts[1]); - shadowMapHalfPlane = Float.parseFloat(parts[1]); - shadowMapIsOrtho = true; - - } else if (line.matches("[ \t]*const[ \t]*float[ \t]*shadowIntervalSize[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("Shadow map interval size: " + parts[1]); - shadowIntervalSize = Float.parseFloat(parts[1]); - - } else if (line.matches("[ \t]*const[ \t]*bool[ \t]*generateShadowMipmap[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("Generate shadow mipmap"); - Arrays.fill(shadowMipmapEnabled, true); - - } else if (line.matches("[ \t]*const[ \t]*bool[ \t]*generateShadowColorMipmap[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("Generate shadow color mipmap"); - Arrays.fill(shadowColorMipmapEnabled, true); - - } else if (line.matches("[ \t]*const[ \t]*bool[ \t]*shadowHardwareFiltering[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("Hardware shadow filtering enabled."); - Arrays.fill(shadowHardwareFilteringEnabled, true); - - } else if (line.matches("[ \t]*const[ \t]*bool[ \t]*shadowHardwareFiltering0[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowHardwareFiltering0"); - shadowHardwareFilteringEnabled[0] = true; - - } else if (line.matches("[ \t]*const[ \t]*bool[ \t]*shadowHardwareFiltering1[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowHardwareFiltering1"); - shadowHardwareFilteringEnabled[1] = true; - - } else if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowtex0Mipmap|shadowtexMipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowtex0Mipmap"); - shadowMipmapEnabled[0] = true; - - } else if (line.matches("[ \t]*const[ \t]*bool[ \t]*(shadowtex1Mipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowtex1Mipmap"); - shadowMipmapEnabled[1] = true; - - } else if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowcolor0Mipmap|shadowColor0Mipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowcolor0Mipmap"); - shadowColorMipmapEnabled[0] = true; - - } else if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowcolor1Mipmap|shadowColor1Mipmap)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowcolor1Mipmap"); - shadowColorMipmapEnabled[1] = true; - - } else if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowtex0Nearest|shadowtexNearest|shadow0MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowtex0Nearest"); - shadowFilterNearest[0] = true; - - } else if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowtex1Nearest|shadow1MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowtex1Nearest"); - shadowFilterNearest[1] = true; - - } else if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowcolor0Nearest|shadowColor0Nearest|shadowColor0MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowcolor0Nearest"); - shadowColorFilterNearest[0] = true; - - } else if (line.matches( - "[ \t]*const[ \t]*bool[ \t]*(shadowcolor1Nearest|shadowColor1Nearest|shadowColor1MinMagNearest)[ \t]*=[ \t]*true[ \t]*;.*")) { - AngelicaTweaker.LOGGER.debug("shadowcolor1Nearest"); - shadowColorFilterNearest[1] = true; - - // Wetness half life - } else if (line.matches("/\\* WETNESSHL:[0-9\\.]+ \\*/.*")) { - String[] parts = line.split("(:| )", 4); - AngelicaTweaker.LOGGER.debug("Wetness halflife: " + parts[2]); - wetnessHalfLife = Float.parseFloat(parts[2]); - - } else if (line.matches("[ \t]*const[ \t]*float[ \t]*wetnessHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("Wetness halflife: " + parts[1]); - wetnessHalfLife = Float.parseFloat(parts[1]); - - // Dryness halflife - } else if (line.matches("/\\* DRYNESSHL:[0-9\\.]+ \\*/.*")) { - String[] parts = line.split("(:| )", 4); - AngelicaTweaker.LOGGER.debug("Dryness halflife: " + parts[2]); - drynessHalfLife = Float.parseFloat(parts[2]); - - } else if (line.matches("[ \t]*const[ \t]*float[ \t]*drynessHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("Dryness halflife: " + parts[1]); - drynessHalfLife = Float.parseFloat(parts[1]); - - // Eye brightness halflife - } else if (line.matches("[ \t]*const[ \t]*float[ \t]*eyeBrightnessHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("Eye brightness halflife: " + parts[1]); - eyeBrightnessHalflife = Float.parseFloat(parts[1]); - - // Center depth halflife - } else if (line.matches("[ \t]*const[ \t]*float[ \t]*centerDepthHalflife[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("Center depth halflife: " + parts[1]); - centerDepthSmoothHalflife = Float.parseFloat(parts[1]); - - // Sun path rotation - } else if (line.matches("[ \t]*const[ \t]*float[ \t]*sunPathRotation[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("Sun path rotation: " + parts[1]); - sunPathRotation = Float.parseFloat(parts[1]); - - // Ambient occlusion level - } else if (line.matches("[ \t]*const[ \t]*float[ \t]*ambientOcclusionLevel[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("AO Level: " + parts[1]); - aoLevel = Float.parseFloat(parts[1]); - blockAoLight = 1.0f - aoLevel; - - // super sampling - } else if (line.matches("[ \t]*const[ \t]*int[ \t]*superSamplingLevel[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - int ssaa = Integer.parseInt(parts[1]); - if (ssaa > 1) { - AngelicaTweaker.LOGGER.debug("Super sampling level: " + ssaa + "x"); - superSamplingLevel = ssaa; - } else { - superSamplingLevel = 1; - } - - // noise texture - } else if (line.matches("[ \t]*const[ \t]*int[ \t]*noiseTextureResolution[ \t]*=[ \t]*-?[0-9.]+f?;.*")) { - String[] parts = line.split("(=[ \t]*|;)"); - AngelicaTweaker.LOGGER.debug("Noise texture enabled"); - AngelicaTweaker.LOGGER.debug("Noise texture resolution: " + parts[1]); - noiseTextureResolution = Integer.parseInt(parts[1]); - noiseTextureEnabled = true; - - } else if (line.matches("[ \t]*const[ \t]*int[ \t]*\\w+Format[ \t]*=[ \t]*[RGBA81632F]*[ \t]*;.*")) { - Matcher m = gbufferFormatPattern.matcher(line); - m.matches(); - String name = m.group(1); - String value = m.group(2); - int bufferindex = getBufferIndexFromString(name); - int format = getTextureFormatFromString(value); - if (bufferindex >= 0 && format != 0) { - gbuffersFormat[bufferindex] = format; - AngelicaTweaker.LOGGER.debug("{} format: {}", name, value); - } - // gaux4 - } else if (line.matches("/\\* GAUX4FORMAT:RGBA32F \\*/.*")) { - AngelicaTweaker.LOGGER.debug("gaux4 format : RGB32AF"); - gbuffersFormat[7] = GL30.GL_RGBA32F; - } else if (line.matches("/\\* GAUX4FORMAT:RGB32F \\*/.*")) { - AngelicaTweaker.LOGGER.debug("gaux4 format : RGB32F"); - gbuffersFormat[7] = GL30.GL_RGB32F; - } else if (line.matches("/\\* GAUX4FORMAT:RGB16 \\*/.*")) { - AngelicaTweaker.LOGGER.debug("gaux4 format : RGB16"); - gbuffersFormat[7] = GL11.GL_RGB16; - - // Mipmap stuff - } else if (line.matches("[ \t]*const[ \t]*bool[ \t]*\\w+MipmapEnabled[ \t]*=[ \t]*true[ \t]*;.*")) { - if (filename.matches(".*composite[0-9]?.fsh") || filename.matches(".*final.fsh")) { - Matcher m = gbufferMipmapEnabledPattern.matcher(line); - m.matches(); - String name = m.group(1); - // String value - // =m.group(2); - int bufferindex = getBufferIndexFromString(name); - if (bufferindex >= 0) { - newCompositeMipmapSetting |= (1 << bufferindex); - AngelicaTweaker.LOGGER.debug("{} mipmap enabled for {}", name, filename); - } - } - } else if (line.matches("/\\* DRAWBUFFERS:[0-7N]* \\*/.*")) { - String[] parts = line.split("(:| )", 4); - newDrawBufSetting = parts[2]; - } - } - - private static boolean printLogInfo(int obj, String name) { - IntBuffer iVal = BufferUtils.createIntBuffer(1); - glGetObjectParameterARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal); - - int length = iVal.get(); - if (length > 1) { - ByteBuffer infoLog = BufferUtils.createByteBuffer(length); - iVal.flip(); - glGetInfoLogARB(obj, iVal, infoLog); - byte[] infoBytes = new byte[length]; - infoLog.get(infoBytes); - if (infoBytes[length - 1] == 0) infoBytes[length - 1] = 10; - String out = new String(infoBytes); - AngelicaTweaker.LOGGER.info("Info log: " + name + "\n" + out); - return false; - } - return true; - } - - public static void setDrawBuffers(IntBuffer drawBuffers) { - if (true) return; - if (activeDrawBuffers != drawBuffers) { - // printIntBuffer("setDrawBuffers", drawBuffers); - activeDrawBuffers = drawBuffers; - GL20.glDrawBuffers(drawBuffers); - } else { - // printIntBuffer("setDrawBf skip", drawBuffers); - } - } - - public static void useProgram(int program) { - if (true) return; - // System.out.println((new StringBuilder(32)).append("useProgram ").append(programNames[program])); - Shaders.checkGLError("pre-useProgram"); - if (isShadowPass) { - program = ProgramShadow; - if (programsID[ProgramShadow] == 0) { - normalMapEnabled = false; - return; - } - } - if (activeProgram == program) { - return; - } - activeProgram = program; - glUseProgramObjectARB(programsID[program]); - if (programsID[program] == 0) { - normalMapEnabled = false; - return; - } - if (checkGLError("useProgram ", programNames[program]) != 0) { - programsID[program] = 0; - } - IntBuffer drawBuffers = programsDrawBuffers[program]; - if (isRenderingDfb) { - setDrawBuffers(drawBuffers); - checkGLError(programNames[program], " draw buffers = ", programsDrawBufSettings[program]); - // ALog.info("%s",programNames[program] + " draw buffers = " + programsDrawBufSettings[program]); - } - activeCompositeMipmapSetting = programsCompositeMipmapSetting[program]; - uniformEntityHurt = glGetUniformLocationARB(programsID[activeProgram], "entityHurt"); - uniformEntityFlash = glGetUniformLocationARB(programsID[activeProgram], "entityFlash"); - switch (program) { - case ProgramBasic: - case ProgramTextured: - case ProgramTexturedLit: - case ProgramSkyBasic: - case ProgramSkyTextured: - case ProgramClouds: - case ProgramTerrain: - case ProgramTerrainSolid: - case ProgramTerrainCutoutMip: - case ProgramTerrainCutout: - case ProgramDamagedBlock: - case ProgramWater: - case ProgramBlock: - case ProgramEntities: - case ProgramSpiderEyes: - case ProgramHand: - case ProgramWeather: - case ProgramHandWater: - normalMapEnabled = true; - setProgramUniform1i("texture", 0); - setProgramUniform1i("lightmap", 1); - setProgramUniform1i("normals", 2); - setProgramUniform1i("specular", 3); - setProgramUniform1i("shadow", waterShadowEnabled ? 5 : 4); - setProgramUniform1i("watershadow", 4); - setProgramUniform1i("shadowtex0", 4); - setProgramUniform1i("shadowtex1", 5); - setProgramUniform1i("depthtex0", 6); - setProgramUniform1i("depthtex1", 12); - setProgramUniform1i("shadowcolor", 13); - setProgramUniform1i("shadowcolor0", 13); - setProgramUniform1i("shadowcolor1", 14); - setProgramUniform1i("noisetex", 15); - break; - case ProgramComposite: - case ProgramComposite1: - case ProgramComposite2: - case ProgramComposite3: - case ProgramComposite4: - case ProgramComposite5: - case ProgramComposite6: - case ProgramComposite7: - case ProgramFinal: - case ProgramDeferred: - case ProgramDeferred1: - case ProgramDeferred2: - case ProgramDeferred3: - case ProgramDeferred4: - case ProgramDeferred5: - case ProgramDeferred6: - case ProgramDeferred7: - case ProgramDeferredLast: - case ProgramCompositeLast: - normalMapEnabled = false; - setProgramUniform1i("gcolor", 0); - setProgramUniform1i("gdepth", 1); - setProgramUniform1i("gnormal", 2); - setProgramUniform1i("composite", 3); - setProgramUniform1i("gaux1", 7); - setProgramUniform1i("gaux2", 8); - setProgramUniform1i("gaux3", 9); - setProgramUniform1i("gaux4", 10); - setProgramUniform1i("colortex0", 0); - setProgramUniform1i("colortex1", 1); - setProgramUniform1i("colortex2", 2); - setProgramUniform1i("colortex3", 3); - setProgramUniform1i("colortex4", 7); - setProgramUniform1i("colortex5", 8); - setProgramUniform1i("colortex6", 9); - setProgramUniform1i("colortex7", 10); - setProgramUniform1i("shadow", waterShadowEnabled ? 5 : 4); - setProgramUniform1i("watershadow", 4); - setProgramUniform1i("shadowtex0", 4); - setProgramUniform1i("shadowtex1", 5); - setProgramUniform1i("gdepthtex", 6); - setProgramUniform1i("depthtex0", 6); - setProgramUniform1i("depthtex1", 11); - setProgramUniform1i("depthtex2", 12); - setProgramUniform1i("shadowcolor", 13); - setProgramUniform1i("shadowcolor0", 13); - setProgramUniform1i("shadowcolor1", 14); - setProgramUniform1i("noisetex", 15); - break; - case ProgramShadow: - case ProgramShadowSolid: - case ProgramShadowCutout: - setProgramUniform1i("tex", 0); - setProgramUniform1i("texture", 0); - setProgramUniform1i("lightmap", 1); - setProgramUniform1i("normals", 2); - setProgramUniform1i("specular", 3); - setProgramUniform1i("shadow", waterShadowEnabled ? 5 : 4); - setProgramUniform1i("watershadow", 4); - setProgramUniform1i("shadowtex0", 4); - setProgramUniform1i("shadowtex1", 5); - setProgramUniform1i("shadowcolor", 13); - setProgramUniform1i("shadowcolor0", 13); - setProgramUniform1i("shadowcolor1", 14); - setProgramUniform1i("noisetex", 15); - break; - default: - normalMapEnabled = false; - break; - } - ItemStack stack = mc.thePlayer.getCurrentEquippedItem(); - Item item = (stack != null) ? stack.getItem() : null; - int itemID; - Block block; - if (item != null) { - itemID = Item.itemRegistry.getIDForObject(item); - block = (Block) Block.blockRegistry.getObjectById(itemID); - } else { - itemID = -1; - block = null; - } - setProgramUniform1i("heldItemId", (itemID)); - setProgramUniform1i("heldBlockLightValue", (block != null) ? block.getLightValue() : 0); - setProgramUniform1i("fogMode", (fogEnabled ? fogMode : 0)); - setProgramUniform3f("fogColor", fogColorR, fogColorG, fogColorB); - setProgramUniform3f("skyColor", skyColorR, skyColorG, skyColorB); - setProgramUniform1i("worldTime", (int) worldTime % 24000); - setProgramUniform1i("moonPhase", moonPhase); - setProgramUniform1f("frameTimeCounter", frameTimeCounter); - setProgramUniform1f("sunAngle", sunAngle); - setProgramUniform1f("shadowAngle", shadowAngle); - setProgramUniform1f("rainStrength", rainStrength); - setProgramUniform1f("aspectRatio", (float) renderWidth / (float) renderHeight); - setProgramUniform1f("viewWidth", (float) renderWidth); - setProgramUniform1f("viewHeight", (float) renderHeight); - setProgramUniform1f("near", 0.05F); - setProgramUniform1f("far", mc.gameSettings.renderDistanceChunks * 16); - setProgramUniform3f("sunPosition", sunPosition[0], sunPosition[1], sunPosition[2]); - setProgramUniform3f("moonPosition", moonPosition[0], moonPosition[1], moonPosition[2]); - setProgramUniform3f("upPosition", upPosition[0], upPosition[1], upPosition[2]); - setProgramUniform3f("previousCameraPosition", (float) previousCameraPosition[0], (float) previousCameraPosition[1], (float) previousCameraPosition[2]); - setProgramUniform3f("cameraPosition", (float) cameraPosition[0], (float) cameraPosition[1], (float) cameraPosition[2]); - setProgramUniformMatrix4ARB("gbufferModelView", false, modelView); - setProgramUniformMatrix4ARB("gbufferModelViewInverse", false, modelViewInverse); - setProgramUniformMatrix4ARB("gbufferPreviousProjection", false, previousProjection); - setProgramUniformMatrix4ARB("gbufferProjection", false, projection); - setProgramUniformMatrix4ARB("gbufferProjectionInverse", false, projectionInverse); - setProgramUniformMatrix4ARB("gbufferPreviousModelView", false, previousModelView); - if (usedShadowDepthBuffers > 0) { - setProgramUniformMatrix4ARB("shadowProjection", false, shadowProjection); - setProgramUniformMatrix4ARB("shadowProjectionInverse", false, shadowProjectionInverse); - setProgramUniformMatrix4ARB("shadowModelView", false, shadowModelView); - setProgramUniformMatrix4ARB("shadowModelViewInverse", false, shadowModelViewInverse); - } - setProgramUniform1f("wetness", wetness); - setProgramUniform1f("eyeAltitude", eyePosY); - // .x = block brightness .y = sky brightness - // value : 0,16,32,64,96,112,128,160,192,208,224,240 for light level 0 to 15 - setProgramUniform2i("eyeBrightness", (eyeBrightness & 0xffff), (eyeBrightness >> 16)); - setProgramUniform2i("eyeBrightnessSmooth", Math.round(eyeBrightnessFadeX), Math.round(eyeBrightnessFadeY)); - setProgramUniform2i("terrainTextureSize", terrainTextureSize[0], terrainTextureSize[1]); - setProgramUniform1i("terrainIconSize", terrainIconSize); - setProgramUniform1i("isEyeInWater", isEyeInWater); - setProgramUniform1i("hideGUI", mc.gameSettings.hideGUI ? 1 : 0); - setProgramUniform1f("centerDepthSmooth", centerDepthSmooth); - setProgramUniform2i("atlasSize", atlasSizeX, atlasSizeY); - Shaders.checkGLError("useProgram ", programNames[program]); - } - - public static void setProgramUniform1i(String name, int x) { - if (true) return; - int gp = programsID[activeProgram]; - if (gp != GL11.GL_NONE) { - int uniform = glGetUniformLocationARB(gp, name); - glUniform1iARB(uniform, x); - if (enableShadersDebug) checkGLError(programNames[activeProgram], name); - } - } - - public static void setProgramUniform2i(String name, int x, int y) { - if (true) return; - int gp = programsID[activeProgram]; - if (gp != GL11.GL_NONE) { - int uniform = glGetUniformLocationARB(gp, name); - glUniform2iARB(uniform, x, y); - if (enableShadersDebug) checkGLError(programNames[activeProgram], name); - } - } - - public static void setProgramUniform1f(String name, float x) { - if (true) return; - int gp = programsID[activeProgram]; - if (gp != GL11.GL_NONE) { - int uniform = glGetUniformLocationARB(gp, name); - glUniform1fARB(uniform, x); - if (enableShadersDebug) checkGLError(programNames[activeProgram], name); - } - } - - public static void setProgramUniform3f(String name, float x, float y, float z) { - if (true) return; - int gp = programsID[activeProgram]; - if (gp != GL11.GL_NONE) { - int uniform = glGetUniformLocationARB(gp, name); - glUniform3fARB(uniform, x, y, z); - if (enableShadersDebug) checkGLError(programNames[activeProgram], name); - } - } - - public static void setProgramUniformMatrix4ARB(String name, boolean transpose, FloatBuffer matrix) { - if (true) return; - int gp = programsID[activeProgram]; - if (gp != GL11.GL_NONE && matrix != null) { - int uniform = glGetUniformLocationARB(gp, name); - glUniformMatrix4ARB(uniform, transpose, matrix); - if (enableShadersDebug) checkGLError(programNames[activeProgram], name); - } - } - - private static int getBufferIndexFromString(String name) { - return switch (name) { - case "colortex0", "gcolor" -> 0; - case "colortex1", "gdepth" -> 1; - case "colortex2", "gnormal" -> 2; - case "colortex3", "composite" -> 3; - case "colortex4", "gaux1" -> 4; - case "colortex5", "gaux2" -> 5; - case "colortex6", "gaux3" -> 6; - case "colortex7", "gaux4" -> 7; - default -> -1; - }; - } - - private static int getTextureFormatFromString(String par) { - if (par.matches("[ \t]*R8[ \t]*")) return GL30.GL_R8; - else if (par.matches("[ \t]*RG8[ \t]*")) return GL30.GL_RG8; - else if (par.matches("[ \t]*RGB8[ \t]*")) return GL11.GL_RGB8; - else if (par.matches("[ \t]*RGBA8[ \t]*")) return GL11.GL_RGBA8; - else if (par.matches("[ \t]*R16[ \t]*")) return GL30.GL_R16; - else if (par.matches("[ \t]*RG16[ \t]*")) return GL30.GL_RG16; - else if (par.matches("[ \t]*RGB16[ \t]*")) return GL11.GL_RGB16; - else if (par.matches("[ \t]*RGBA16[ \t]*")) return GL11.GL_RGBA16; - else if (par.matches("[ \t]*R32F[ \t]*")) return GL30.GL_R32F; - else if (par.matches("[ \t]*RG32F[ \t]*")) return GL30.GL_RG32F; - else if (par.matches("[ \t]*RGB32F[ \t]*")) return GL30.GL_RGB32F; - else if (par.matches("[ \t]*RGBA32F[ \t]*")) return GL30.GL_RGBA32F; - else return 0; - } - - private static void setupNoiseTexture() { - if (noiseTexture == null) noiseTexture = new HFNoiseTexture(noiseTextureResolution, noiseTextureResolution); - } - - private static IntBuffer fillIntBufferZero(IntBuffer buf) { - int limit = buf.limit(); - for (int i = buf.position(); i < limit; ++i) buf.put(i, 0); - return buf; - } - - public static void uninit() { - if (true) return; - if (!isInitialized) { - return; - } - checkGLError("Shaders.uninit pre"); - for (int i = 0; i < ProgramCount; ++i) { - if (programsRef[i] != 0) { - glDeleteObjectARB(programsRef[i]); - checkGLError("del programRef"); - } - programsRef[i] = 0; - programsID[i] = 0; - programsDrawBufSettings[i] = null; - programsDrawBuffers[i] = null; - programsCompositeMipmapSetting[i] = 0; - } - if (dfb != 0) { - glDeleteFramebuffersEXT(dfb); - dfb = 0; - checkGLError("del dfb"); - } - if (sfb != 0) { - glDeleteFramebuffersEXT(sfb); - sfb = 0; - checkGLError("del sfb"); - } - if (dfbDepthTextures != null) { - GL11.glDeleteTextures(dfbDepthTextures); - fillIntBufferZero(dfbDepthTextures); - checkGLError("del dfbDepthTextures"); - } - if (dfbColorTextures != null) { - GL11.glDeleteTextures(dfbColorTextures); - fillIntBufferZero(dfbColorTextures); - checkGLError("del dfbTextures"); - } - if (sfbDepthTextures != null) { - GL11.glDeleteTextures(sfbDepthTextures); - fillIntBufferZero(sfbDepthTextures); - checkGLError("del shadow depth"); - } - if (sfbColorTextures != null) { - GL11.glDeleteTextures(sfbColorTextures); - fillIntBufferZero(sfbColorTextures); - checkGLError("del shadow color"); - } - if (dfbDrawBuffers != null) { - fillIntBufferZero(dfbDrawBuffers); - } - if (noiseTexture != null) { - noiseTexture.destroy(); - noiseTexture = null; - } - - AngelicaTweaker.LOGGER.trace("UNINIT"); - - shadowPassInterval = 0; - shouldSkipDefaultShadow = false; - isInitialized = false; - notFirstInit = true; - checkGLError("Shaders.uninit"); - } - - public static void scheduleResize() { - renderDisplayHeight = 0; - } - - public static void scheduleResizeShadow() { - needResizeShadow = true; - } - - private static void resize() { - renderDisplayWidth = mc.displayWidth; - renderDisplayHeight = mc.displayHeight; - // renderWidth = mc.displayWidth * superSamplingLevel; - // renderHeight = mc.displayHeight * superSamplingLevel; - renderWidth = Math.round(renderDisplayWidth * configRenderResMul); - renderHeight = Math.round(renderDisplayHeight * configRenderResMul); - setupFrameBuffer(); - } - - private static void resizeShadow() { - needResizeShadow = false; - shadowMapWidth = Math.round(spShadowMapWidth * configShadowResMul); - shadowMapHeight = Math.round(spShadowMapHeight * configShadowResMul); - setupShadowFrameBuffer(); - } - - private static void setupFrameBuffer() { - if (true) return; - if (dfb != 0) { - glDeleteFramebuffersEXT(dfb); - GL11.glDeleteTextures(dfbDepthTextures); - GL11.glDeleteTextures(dfbColorTextures); - } - - dfb = glGenFramebuffersEXT(); - GL11.glGenTextures((IntBuffer) dfbDepthTextures.clear().limit(usedDepthBuffers)); - GL11.glGenTextures((IntBuffer) dfbColorTextures.clear().limit(usedColorBuffers)); - dfbDepthTextures.position(0); - dfbColorTextures.position(0); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dfb); - GL20.glDrawBuffers(GL11.GL_NONE); - GL11.glReadBuffer(GL11.GL_NONE); - - for (int i = 0; i < usedDepthBuffers; ++i) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(i)); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_DEPTH_TEXTURE_MODE, GL11.GL_LUMINANCE); - GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_DEPTH_COMPONENT, renderWidth, renderHeight, 0, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (ByteBuffer) null); - } - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, dfbDepthTextures.get(0), 0); - GL20.glDrawBuffers(dfbDrawBuffers); - GL11.glReadBuffer(GL11.GL_NONE); - checkGLError("FT d"); - - for (int i = 0; i < usedColorBuffers; ++i) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(i)); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); - GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0, gbuffersFormat[i], renderWidth, renderHeight, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (ByteBuffer) null); - glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL11.GL_TEXTURE_2D, dfbColorTextures.get(i), 0); - checkGLError("FT c"); - } - - int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - if (status == GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT) { - printChatAndLogError("Failed using multiple internal formats in frame buffer."); - for (int i = 0; i < usedColorBuffers; ++i) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(i)); - GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, renderWidth, renderHeight, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (ByteBuffer) null); - glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL11.GL_TEXTURE_2D, dfbColorTextures.get(i), 0); - checkGLError("FT c"); - } - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status == GL_FRAMEBUFFER_COMPLETE_EXT) { - printChatAndLogError("Please update graphics driver."); - } - } - - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - printChatAndLogError("Failed creating framebuffer! (Status " + status + ")"); - } else { - AngelicaTweaker.LOGGER.debug("Framebuffer created."); - } - } - - private static void setupShadowFrameBuffer() { - if (true) return; - if (usedShadowDepthBuffers == 0) { - return; - } - - if (sfb != 0) { - glDeleteFramebuffersEXT(sfb); - GL11.glDeleteTextures(sfbDepthTextures); - GL11.glDeleteTextures(sfbColorTextures); - } - - sfb = glGenFramebuffersEXT(); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sfb); - GL20.glDrawBuffers(GL11.GL_NONE); - GL11.glReadBuffer(GL11.GL_NONE); - - GL11.glGenTextures((IntBuffer) sfbDepthTextures.clear().limit(usedShadowDepthBuffers)); - GL11.glGenTextures((IntBuffer) sfbColorTextures.clear().limit(usedShadowColorBuffers)); - // printIntBuffer(sfbDepthTextures); - // printIntBuffer(sfbColorTextures); - sfbDepthTextures.position(0); - sfbColorTextures.position(0); - - // depth - for (int i = 0; i < usedShadowDepthBuffers; ++i) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbDepthTextures.get(i)); - GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); - GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); - int filter = shadowFilterNearest[i] ? GL11.GL_NEAREST : GL11.GL_LINEAR; - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter); - if (shadowHardwareFilteringEnabled[i]) - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_COMPARE_MODE, GL30.GL_COMPARE_REF_TO_TEXTURE); - GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0, GL11.GL_DEPTH_COMPONENT, shadowMapWidth, shadowMapHeight, 0, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (FloatBuffer) null); - } - glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, sfbDepthTextures.get(0), 0); - checkGLError("FT sd"); - - // color shadow - for (int i = 0; i < usedShadowColorBuffers; ++i) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbColorTextures.get(i)); - GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); - GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); - int filter = shadowColorFilterNearest[i] ? GL11.GL_NEAREST : GL11.GL_LINEAR; - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter); - GL11.glTexImage2D( GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, shadowMapWidth, shadowMapHeight, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (ByteBuffer) null); - glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL11.GL_TEXTURE_2D, sfbColorTextures.get(i), 0); - checkGLError("FT sc"); - } - - GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); - - int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - printChatAndLogError("Failed creating shadow framebuffer! (Status " + status + ")"); - } else { - AngelicaTweaker.LOGGER.debug("Shadow framebuffer created."); - } - } - - public static void beginRender(Minecraft minecraft, float f, long l) { - if (true) return; - - if (isShadowPass) { - return; - } - checkGLError("pre beginRender"); - - mc = minecraft; - mc.mcProfiler.startSection("init"); - - if (!isInitialized) { - init(); - } - if (mc.displayWidth != renderDisplayWidth || mc.displayHeight != renderDisplayHeight) { - resize(); - } - if (needResizeShadow) { - resizeShadow(); - } - - worldTime = mc.theWorld.getWorldTime(); - diffWorldTime = (worldTime - lastWorldTime) % 24000; - if (diffWorldTime < 0) diffWorldTime += 24000; - lastWorldTime = worldTime; - moonPhase = mc.theWorld.getMoonPhase(); - - systemTime = System.currentTimeMillis(); - if (lastSystemTime == 0) { - lastSystemTime = systemTime; // Initialize lastSystemTime on the first tick so that it is equal to current system time - } - diffSystemTime = systemTime - lastSystemTime; - lastSystemTime = systemTime; - - frameTimeCounter += diffSystemTime * 0.001f; - frameTimeCounter = frameTimeCounter % 100000.0f; - - rainStrength = minecraft.theWorld.getRainStrength(f); - { - float fadeScalar = diffSystemTime * 0.01f; - // float temp1 = (float)Math.exp(Math.log(0.5)*diffWorldTime/((wetness < rainStrength)? drynessHalfLife : wetnessHalfLife)); - float temp1 = (float) Math.exp(Math.log(0.5) * fadeScalar / ((wetness < rainStrength) ? drynessHalfLife : wetnessHalfLife)); - wetness = wetness * (temp1) + rainStrength * (1 - temp1); - } - - EntityLivingBase eye = mc.renderViewEntity; - eyePosY = (float) eye.posY * f + (float) eye.lastTickPosY * (1 - f); - eyeBrightness = eye.getBrightnessForRender(f); - { - // float temp2 = (float)Math.exp(Math.log(0.5)*1.0f/eyeBrightnessHalfLife); - float fadeScalar = diffSystemTime * 0.01f; - float temp2 = (float) Math.exp(Math.log(0.5) * fadeScalar / eyeBrightnessHalflife); - eyeBrightnessFadeX = eyeBrightnessFadeX * temp2 + (eyeBrightness & 0xffff) * (1 - temp2); - eyeBrightnessFadeY = eyeBrightnessFadeY * temp2 + (eyeBrightness >> 16) * (1 - temp2); - } - - isEyeInWater = (mc.gameSettings.thirdPersonView == 0 && !mc.renderViewEntity.isPlayerSleeping() - && mc.thePlayer.isInsideOfMaterial(Material.water)) ? 1 : 0; - - { - Vec3 skyColorV = mc.theWorld.getSkyColor(mc.renderViewEntity, f); - skyColorR = (float) skyColorV.xCoord; - skyColorG = (float) skyColorV.yCoord; - skyColorB = (float) skyColorV.zCoord; - } - - - isRenderingWorld = true; - isCompositeRendered = false; - isHandRendered = false; - - if (usedShadowDepthBuffers >= 1) { - GL13.glActiveTexture(GL13.GL_TEXTURE4); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbDepthTextures.get(0)); - if (usedShadowDepthBuffers >= 2) { - GL13.glActiveTexture(GL13.GL_TEXTURE5); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbDepthTextures.get(1)); - } - } - - for (int i = 0; i < 4 && 4 + i < usedColorBuffers; ++i) { - GL13.glActiveTexture(GL13.GL_TEXTURE7 + i); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(4 + i)); - } - - GL13.glActiveTexture(GL13.GL_TEXTURE6); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(0)); - - if (usedDepthBuffers >= 2) { - GL13.glActiveTexture(GL13.GL_TEXTURE11); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(1)); - - if (usedDepthBuffers >= 3) { - GL13.glActiveTexture(GL13.GL_TEXTURE12); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(2)); - } - } - - for (int i = 0; i < usedShadowColorBuffers; ++i) { - GL13.glActiveTexture(GL13.GL_TEXTURE13 + i); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbColorTextures.get(i)); - } - - if (noiseTextureEnabled) { - GL13.glActiveTexture(GL13.GL_TEXTURE0 + noiseTexture.textureUnit); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, noiseTexture.getID()); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); - } - - GL13.glActiveTexture(GL13.GL_TEXTURE0); - - previousCameraPosition[0] = cameraPosition[0]; - previousCameraPosition[1] = cameraPosition[1]; - previousCameraPosition[2] = cameraPosition[2]; - - previousProjection.position(0); - projection.position(0); - previousProjection.put(projection); - previousProjection.position(0); - projection.position(0); - previousModelView.position(0); - modelView.position(0); - previousModelView.put(modelView); - previousModelView.position(0); - modelView.position(0); - - EntityRenderer.anaglyphField = 0; - - if (usedShadowDepthBuffers > 0 && --shadowPassCounter <= 0) { - // do shadow pass - // System.out.println("shadow pass start"); - mc.mcProfiler.endStartSection("shadow pass"); - preShadowPassThirdPersonView = mc.gameSettings.thirdPersonView; - boolean preShadowPassAdvancedOpengl = mc.gameSettings.advancedOpengl; - mc.gameSettings.advancedOpengl = false; - - // moved to setCamera - // mc.gameSettings.thirdPersonView = 1; - - isShadowPass = true; - shadowPassCounter = shadowPassInterval; - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sfb); - GL20.glDrawBuffers(programsDrawBuffers[ProgramShadow]); - - useProgram(ProgramShadow); - - mc.entityRenderer.renderWorld(f, l); - - GL11.glFlush(); - - isShadowPass = false; - - mc.gameSettings.advancedOpengl = preShadowPassAdvancedOpengl; - mc.gameSettings.thirdPersonView = preShadowPassThirdPersonView; - - if (hasGlGenMipmap) { - if (usedShadowDepthBuffers >= 1) { - if (shadowMipmapEnabled[0]) { - GL13.glActiveTexture(GL13.GL_TEXTURE4); - GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, shadowFilterNearest[0] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); - } - if (usedShadowDepthBuffers >= 2) { - if (shadowMipmapEnabled[1]) { - GL13.glActiveTexture(GL13.GL_TEXTURE5); - GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, shadowFilterNearest[1] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); - } - } - GL13.glActiveTexture(GL13.GL_TEXTURE0); - } - if (usedShadowColorBuffers >= 1) { - if (shadowColorMipmapEnabled[0]) { - GL13.glActiveTexture(GL13.GL_TEXTURE13); - GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, shadowColorFilterNearest[0] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); - } - if (usedShadowColorBuffers >= 2) { - if (shadowColorMipmapEnabled[1]) { - GL13.glActiveTexture(GL13.GL_TEXTURE14); - GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, shadowColorFilterNearest[1] ? GL11.GL_NEAREST_MIPMAP_NEAREST : GL11.GL_LINEAR_MIPMAP_LINEAR); - } - } - GL13.glActiveTexture(GL13.GL_TEXTURE0); - } - } - - // System.out.println("shadow pass end"); - } - mc.mcProfiler.endSection(); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dfb); - GL11.glViewport(0, 0, Shaders.renderWidth, Shaders.renderHeight); - activeDrawBuffers = null; -// ShadersTex.bindNSTextures(defaultTexture.angelica$getMultiTexID()); - useProgram(ProgramTextured); - - checkGLError("end beginRender"); - } - - public static void setViewport(int vx, int vy, int vw, int vh) { - GL11.glViewport(vx, vy, vw, vh); - if (true) return; - GL11.glColorMask(true, true, true, true); - if (isShadowPass) { - GL11.glViewport(0, 0, shadowMapWidth, shadowMapHeight); - } else { - GL11.glViewport(0, 0, Shaders.renderWidth, Shaders.renderHeight); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dfb); - isRenderingDfb = true; - GL11.glEnable(GL11.GL_CULL_FACE); - GL11.glEnable(GL11.GL_DEPTH_TEST); - setDrawBuffers(drawBuffersNone); - useProgram(ProgramTextured); - checkGLError("beginRenderPass"); - } - } - - public static int setFogMode(int val) { - return fogMode = val; - } - - public static void setFogColor(float r, float g, float b) { - fogColorR = r; - fogColorG = g; - fogColorB = b; - } - - public static void setClearColor(float red, float green, float blue, float alpha) { - GL11.glClearColor(red, green, blue, alpha); - clearColorR = red; - clearColorG = green; - clearColorB = blue; - } - - public static void clearRenderBuffer() { - if (true) return; - if (isShadowPass) { - checkGLError("shadow clear pre"); - glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, sfbDepthTextures.get(0), 0); GL11.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); - // printIntBuffer(programsDrawBuffers[ProgramShadow]); - GL20.glDrawBuffers(programsDrawBuffers[ProgramShadow]); - checkFramebufferStatus("shadow clear"); - GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); - checkGLError("shadow clear"); - return; - } - checkGLError("clear pre"); - - /* - * glDrawBuffers(dfbDrawBuffers); GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | - * GL11.GL_DEPTH_BUFFER_BIT); - */ - - GL20.glDrawBuffers(GL_COLOR_ATTACHMENT0_EXT); - // GL11.glClearColor(clearColorR, clearColorG, clearColorB, 1.0f); - // GL11.glClearColor(1f, 0f, 0f, 1.0f); // for debug - GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); - - GL20.glDrawBuffers(GL_COLOR_ATTACHMENT1_EXT); - GL11.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); - GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); - - for (int i = 2; i < usedColorBuffers; ++i) { - GL20.glDrawBuffers(GL_COLOR_ATTACHMENT0_EXT + i); - GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); - } - - setDrawBuffers(dfbDrawBuffers); - checkFramebufferStatus("clear"); - checkGLError("clear"); - } - - public static void setCamera(float tickDelta) { - EntityLivingBase viewEntity = mc.renderViewEntity; - - double x = viewEntity.lastTickPosX + (viewEntity.posX - viewEntity.lastTickPosX) * tickDelta; - double y = viewEntity.lastTickPosY + (viewEntity.posY - viewEntity.lastTickPosY) * tickDelta; - double z = viewEntity.lastTickPosZ + (viewEntity.posZ - viewEntity.lastTickPosZ) * tickDelta; - - cameraPosition[0] = x; - cameraPosition[1] = y; - cameraPosition[2] = z; - - GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, (FloatBuffer) projection.position(0)); - invertMat4x((FloatBuffer) projection.position(0), (FloatBuffer) projectionInverse.position(0)); - projection.position(0); - projectionInverse.position(0); - - GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, (FloatBuffer) modelView.position(0)); - invertMat4x((FloatBuffer) modelView.position(0), (FloatBuffer) modelViewInverse.position(0)); - modelView.position(0); - modelViewInverse.position(0); - - if (isShadowPass) { -// GL11.glViewport(0, 0, shadowMapWidth, shadowMapHeight); -// -// GL11.glMatrixMode(GL11.GL_PROJECTION); -// GL11.glLoadIdentity(); -// -// if (shadowMapIsOrtho) { -// GL11.glOrtho( -shadowMapHalfPlane, shadowMapHalfPlane, -shadowMapHalfPlane, shadowMapHalfPlane, 0.05f, 256.0f); -// } else { -// // just backwards compatibility. it's only used when SHADOWFOV is set in the shaders. -// gluPerspective(shadowMapFOV, (float) shadowMapWidth / (float) shadowMapHeight, 0.05f, 256.0f); -// } -// -// GL11.glMatrixMode(GL11.GL_MODELVIEW); -// GL11.glLoadIdentity(); -// GL11.glTranslatef(0.0f, 0.0f, -100.0f); -// GL11.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);- - final float celestialAngle = mc.theWorld.getCelestialAngle(tickDelta); - sunAngle = (celestialAngle < 0.75f) ? celestialAngle + 0.25f : celestialAngle - 0.75f; - final float angle = celestialAngle * (-360.0f); - final float angleInterval = shadowAngleInterval > 0.0f ? (angle % shadowAngleInterval - (shadowAngleInterval * 0.5f)) : 0.0f; - if (sunAngle <= 0.5) { - // day time -// GL11.glRotatef(angle - angleInterval, 0.0f, 0.0f, 1.0f); -// GL11.glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); // rotate - shadowAngle = sunAngle; - } else { - // night time -// GL11.glRotatef(angle + 180.0f - angleInterval, 0.0f, 0.0f, 1.0f); -// GL11.glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); // rotate - shadowAngle = sunAngle - 0.5f; - } -// if (shadowMapIsOrtho) { -// // reduces jitter -// float trans = shadowIntervalSize; -// float trans2 = trans / 2.0f; -// GL11.glTranslatef((float) x % trans - trans2, (float) y % trans - trans2, (float) z % trans - trans2); -// } - - GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, (FloatBuffer) shadowProjection.position(0)); - invertMat4x((FloatBuffer) shadowProjection.position(0), (FloatBuffer) shadowProjectionInverse.position(0)); - shadowProjection.position(0); - shadowProjectionInverse.position(0); - - GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, (FloatBuffer) shadowModelView.position(0)); - invertMat4x((FloatBuffer) shadowModelView.position(0), (FloatBuffer) shadowModelViewInverse.position(0)); - shadowModelView.position(0); - shadowModelViewInverse.position(0); - - // Also drawScreen player shadow - mc.gameSettings.thirdPersonView = 1; - checkGLError("setCamera"); - return; - } - - - checkGLError("setCamera"); - } - - public static void preCelestialRotate() { - Shaders.setUpPosition(); -// GL11.glRotatef(Shaders.sunPathRotation * 1.0f, 0.0f, 0.0f, 1.0f); - checkGLError("preCelestialRotate"); - } - - public static void postCelestialRotate() { - // This is called when the current matrix is the modelview matrix based on the celestial angle. - // The sun is at (0, 100, 0), and the moon is at (0, -100, 0). - FloatBuffer modelView = tempMatrixDirectBuffer; - modelView.clear(); - GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView); - modelView.get(tempMat, 0, 16); - multiplyMat4xVec4(tempMat, sunPosModelView, sunPosition); - multiplyMat4xVec4(tempMat, moonPosModelView, moonPosition); - checkGLError("postCelestialRotate"); - } - - public static void setUpPosition() { - // Up direction in model view while rendering sky. - FloatBuffer modelView = tempMatrixDirectBuffer; - modelView.clear(); - GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView); - modelView.get(tempMat, 0, 16); - multiplyMat4xVec4(tempMat, upPosModelView, upPosition); - } - - private static float[] multiplyMat4xVec4(float[] matA, float[] vecB, float[] vecOut) { - vecOut[0] = matA[0] * vecB[0] + matA[4] * vecB[1] + matA[8] * vecB[2] + matA[12] * vecB[3]; - vecOut[1] = matA[1] * vecB[0] + matA[5] * vecB[1] + matA[9] * vecB[2] + matA[13] * vecB[3]; - vecOut[2] = matA[2] * vecB[0] + matA[6] * vecB[1] + matA[10] * vecB[2] + matA[14] * vecB[3]; - vecOut[3] = matA[3] * vecB[0] + matA[7] * vecB[1] + matA[11] * vecB[2] + matA[15] * vecB[3]; - return vecOut; - } - - static float[] invertMat4x_m = new float[16]; - static float[] invertMat4x_inv = new float[16]; - - private static FloatBuffer invertMat4x(FloatBuffer matIn, FloatBuffer invMatOut) { - float[] m = invertMat4x_m; - float[] inv = invertMat4x_inv; - float det; - int i; - - matIn.get(m); - - inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]; - inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10]; - inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9]; - inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9]; - inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10]; - inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]; - inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9]; - inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9]; - inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6]; - inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6]; - inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5]; - inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5]; - inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6]; - inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6]; - inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5]; - inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5]; - - det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]; - - if (det != 0.0) { - for (i = 0; i < 16; ++i) inv[i] /= det; - } else { - // no inverse - Arrays.fill(inv, 0); - } - - invMatOut.put(inv); - - return invMatOut; - } - - public static void genCompositeMipmap() { - if (true) return; - if (hasGlGenMipmap) { - if ((activeCompositeMipmapSetting & (1 << 0)) != 0) { - GL13.glActiveTexture(GL13.GL_TEXTURE0); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); - GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - } - - if ((activeCompositeMipmapSetting & (1 << 1)) != 0) { - GL13.glActiveTexture(GL13.GL_TEXTURE1); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); - GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - } - - if ((activeCompositeMipmapSetting & (1 << 2)) != 0) { - GL13.glActiveTexture(GL13.GL_TEXTURE2); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); - GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - } - - if ((activeCompositeMipmapSetting & (1 << 3)) != 0) { - GL13.glActiveTexture(GL13.GL_TEXTURE3); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); - GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - } - - for (int i = 0; i < 4 && 4 + i < usedColorBuffers; ++i) { - if ((activeCompositeMipmapSetting & ((1 << 4) << i)) != 0) { - GL13.glActiveTexture(GL13.GL_TEXTURE7 + i); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); - GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - } - } - - GL13.glActiveTexture(GL13.GL_TEXTURE0); - } - } - - public static void drawComposite() { - if (true) return; - GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - GL11.glBegin(GL11.GL_QUADS); - GL11.glTexCoord2f(0.0f, 0.0f); - GL11.glVertex3f(0.0f, 0.0f, 0.0f); - GL11.glTexCoord2f(1.0f, 0.0f); - GL11.glVertex3f(1.0f, 0.0f, 0.0f); - GL11.glTexCoord2f(1.0f, 1.0f); - GL11.glVertex3f(1.0f, 1.0f, 0.0f); - GL11.glTexCoord2f(0.0f, 1.0f); - GL11.glVertex3f(0.0f, 1.0f, 0.0f); - GL11.glEnd(); - } - - public static void renderDeferred() { - checkGLError("pre-renderDeferred"); - if (true) return; - renderComposites(ProgramDeferred, 8, false); - //OF: mc.getTextureManager().bindTexture(TextureMap.locationBlocksTexture); - } - - public static void renderCompositeFinal() { - if (true) return; - checkGLError("pre-renderCompositeFinal"); - renderComposites(ProgramComposite, 8, true); - } - - public static void renderComposites(int programBase, int programCount, boolean renderFinal) { - if (true) return; - if (isShadowPass) { - // useProgram(ProgramNone); - return; - } - - - GL11.glPushMatrix(); - GL11.glLoadIdentity(); - GL11.glMatrixMode(GL11.GL_PROJECTION); - GL11.glPushMatrix(); - GL11.glLoadIdentity(); - GL11.glOrtho(0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); - - GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - GL11.glEnable(GL11.GL_TEXTURE_2D); - GL11.glDisable(GL11.GL_ALPHA_TEST); - GL11.glDisable(GL11.GL_BLEND); - GL11.glEnable(GL11.GL_DEPTH_TEST); - GL11.glDepthFunc(GL11.GL_ALWAYS); - GL11.glDepthMask(false); - - // textures - GL13.glActiveTexture(GL13.GL_TEXTURE0); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(0)); - - GL13.glActiveTexture(GL13.GL_TEXTURE1); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(1)); - - GL13.glActiveTexture(GL13.GL_TEXTURE2); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(2)); - - GL13.glActiveTexture(GL13.GL_TEXTURE3); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(3)); - - if (usedShadowDepthBuffers >= 1) { - GL13.glActiveTexture(GL13.GL_TEXTURE4); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbDepthTextures.get(0)); - if (usedShadowDepthBuffers >= 2) { - GL13.glActiveTexture(GL13.GL_TEXTURE5); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbDepthTextures.get(1)); - } - } - - for (int i = 0; i < 4 && 4 + i < usedColorBuffers; ++i) { - GL13.glActiveTexture(GL13.GL_TEXTURE7 + i); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbColorTextures.get(4 + i)); - } - - GL13.glActiveTexture(GL13.GL_TEXTURE6); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(0)); - - if (usedDepthBuffers >= 2) { - GL13.glActiveTexture(GL13.GL_TEXTURE11); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(1)); - - if (usedDepthBuffers >= 3) { - GL13.glActiveTexture(GL13.GL_TEXTURE12); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, dfbDepthTextures.get(2)); - } - } - - for (int i = 0; i < usedShadowColorBuffers; ++i) { - GL13.glActiveTexture(GL13.GL_TEXTURE13 + i); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, sfbColorTextures.get(i)); - } - - if (noiseTextureEnabled) { - GL13.glActiveTexture(GL13.GL_TEXTURE0 + noiseTexture.textureUnit); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, noiseTexture.getID()); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); - } - - GL13.glActiveTexture(GL13.GL_TEXTURE0); - - // set depth buffer - glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, dfbDepthTextures.get(0), 0); - // detach depth buffer - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, 0, 0); - - // composite - GL20.glDrawBuffers(dfbDrawBuffers); - checkGLError("pre-composite"); - - for (int i = 0; i < programCount; ++i) { - if (programsID[programBase + i] != 0) { - useProgram(programBase + i); - checkGLError(programNames[programBase + i]); - if (activeCompositeMipmapSetting != 0) genCompositeMipmap(); - drawComposite(); - } - } - - // reattach depth buffer - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, dfbDepthTexture, 0); - - // final - if(renderFinal) { - renderFinal(); - } - - isCompositeRendered = true; - GL11.glEnable(GL11.GL_TEXTURE_2D); - GL11.glEnable(GL11.GL_ALPHA_TEST); - GL11.glEnable(GL11.GL_BLEND); - GL11.glDepthFunc(GL11.GL_LEQUAL); - GL11.glDepthMask(true); - - // GL11.glMatrixMode(GL11.GL_PROJECTION); - GL11.glPopMatrix(); - GL11.glMatrixMode(GL11.GL_MODELVIEW); - GL11.glPopMatrix(); - - useProgram(ProgramNone); - } - - private static void renderFinal() { - // final drawScreen target - isRenderingDfb = false; - if (true) return; - mc.getFramebuffer().bindFramebuffer(true); - // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - // GL11.glViewport(0, 0, mc.displayWidth, mc.displayHeight); - if (EntityRenderer.anaglyphEnable) { - boolean maskR = (EntityRenderer.anaglyphField != 0); - GL11.glColorMask(maskR, !maskR, !maskR, true); - } - GL11.glDepthMask(true); - GL11.glClearColor(clearColorR, clearColorG, clearColorB, 1.0f); - GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); - GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - GL11.glEnable(GL11.GL_TEXTURE_2D); - GL11.glDisable(GL11.GL_ALPHA_TEST); - GL11.glDisable(GL11.GL_BLEND); - GL11.glEnable(GL11.GL_DEPTH_TEST); - GL11.glDepthFunc(GL11.GL_ALWAYS); - GL11.glDepthMask(false); - - checkGLError("pre-final"); - useProgram(ProgramFinal); - checkGLError("final"); - if (activeCompositeMipmapSetting != 0) genCompositeMipmap(); - drawComposite(); - - // Read gl_FragColor - // ByteBuffer centerPixelColor = ByteBuffer.allocateDirect(3); - // glReadPixels(renderWidth / 2, renderHeight / 2, 1, 1, GL11.GL_RGB, GL11.GL_BYTE, centerPixelColor); - // System.out.println(centerPixelColor.get(0)); - - // end - checkGLError("renderCompositeFinal"); - } - - - public static void endRender() { - if (true) return; - if (isShadowPass) { - // useProgram(ProgramNone); - checkGLError("shadow endRender"); - return; - } - - if (!isCompositeRendered) renderCompositeFinal(); - isRenderingWorld = false; - - GL11.glColorMask(true, true, true, true); - GL11.glEnable(GL11.GL_BLEND); - useProgram(ProgramNone); - checkGLError("endRender end"); - - // defaultTexture.bind(); - } - - public static void beginSky() { - isRenderingSky = true; - fogEnabled = true; - if (true) return; - setDrawBuffers(dfbDrawBuffers); - useProgram(ProgramSkyTextured); - pushEntity(-2, 0); - } - - public static void setSkyColor(Vec3 v3color) { - skyColorR = (float) v3color.xCoord; - skyColorG = (float) v3color.yCoord; - skyColorB = (float) v3color.zCoord; - if (true) return; - setProgramUniform3f("skyColor", skyColorR, skyColorG, skyColorB); - } - - public static void drawHorizon() { - if (true) return; - Tessellator tess = Tessellator.instance; - float farDistance = mc.gameSettings.renderDistanceChunks * 16; - double xzq = farDistance * 0.9238; - double xzp = farDistance * 0.3826; - double xzn = -xzp; - double xzm = -xzq; - double top = 16f; // 256f-cameraPosition[1]; - double bot = -cameraPosition[1]; - - tess.startDrawingQuads(); - // horizon - tess.addVertex(xzn, bot, xzm); - tess.addVertex(xzn, top, xzm); - tess.addVertex(xzm, top, xzn); - tess.addVertex(xzm, bot, xzn); - - tess.addVertex(xzm, bot, xzn); - tess.addVertex(xzm, top, xzn); - tess.addVertex(xzm, top, xzp); - tess.addVertex(xzm, bot, xzp); - - tess.addVertex(xzm, bot, xzp); - tess.addVertex(xzm, top, xzp); - tess.addVertex(xzn, top, xzp); - tess.addVertex(xzn, bot, xzp); - - tess.addVertex(xzn, bot, xzp); - tess.addVertex(xzn, top, xzp); - tess.addVertex(xzp, top, xzq); - tess.addVertex(xzp, bot, xzq); - - tess.addVertex(xzp, bot, xzq); - tess.addVertex(xzp, top, xzq); - tess.addVertex(xzq, top, xzp); - tess.addVertex(xzq, bot, xzp); - - tess.addVertex(xzq, bot, xzp); - tess.addVertex(xzq, top, xzp); - tess.addVertex(xzq, top, xzn); - tess.addVertex(xzq, bot, xzn); - - tess.addVertex(xzq, bot, xzn); - tess.addVertex(xzq, top, xzn); - tess.addVertex(xzp, top, xzm); - tess.addVertex(xzp, bot, xzm); - - tess.addVertex(xzp, bot, xzm); - tess.addVertex(xzp, top, xzm); - tess.addVertex(xzn, top, xzm); - tess.addVertex(xzn, bot, xzm); - // bottom - // tess.addVertex(xzm, bot, xzm); - // tess.addVertex(xzm, bot, xzq); - // tess.addVertex(xzq, bot, xzq); - // tess.addVertex(xzq, bot, xzm); - - tess.draw(); - } - - public static void preSkyList() { - if (true) return; - GL11.glColor3f(fogColorR, fogColorG, fogColorB); - // GL11.glColor3f(0f, 1f, 0f); - // GL11.glDisable(GL11.GL_FOG); - - drawHorizon(); - - // GL11.glEnable(GL11.GL_FOG); - GL11.glColor3f(skyColorR, skyColorG, skyColorB); - } - - public static void endSky() { - isRenderingSky = false; - if (true) return; - setDrawBuffers(dfbDrawBuffers); - useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); - popEntity(); - } - - // public static void beginSunMoon() { - // useProgram(ProgramNone); - // } - - // public static void endSunMoon() { - // useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); - // } - public static void beginUpdateChunks() { - if (true) return; - // System.out.println("beginUpdateChunks"); - checkGLError("beginUpdateChunks1"); - checkFramebufferStatus("beginUpdateChunks1"); - if (!isShadowPass) { - useProgram(ProgramTerrain); - } - checkGLError("beginUpdateChunks2"); - checkFramebufferStatus("beginUpdateChunks2"); - } - - public static void endUpdateChunks() { - if (true) return; - // System.out.println("endUpdateChunks"); - checkGLError("endUpdateChunks1"); - checkFramebufferStatus("endUpdateChunks1"); - if (!isShadowPass) { - useProgram(ProgramTerrain); - } - checkGLError("endUpdateChunks2"); - checkFramebufferStatus("endUpdateChunks2"); - } - - public static boolean shouldRenderClouds(GameSettings gs) { - checkGLError("shouldRenderClouds"); - return isShadowPass ? configCloudShadow : gs.clouds; - } - - public static void beginClouds() { - if (true) return; - fogEnabled = true; - pushEntity(-3, 0); - useProgram(ProgramTextured); - } - - public static void endClouds() { - if (true) return; - disableFog(); - popEntity(); - } - - public static void beginTerrain() { - if (true) return; - if (isRenderingWorld) { - if (isShadowPass) { - GL11.glDisable(GL11.GL_CULL_FACE); - } - fogEnabled = true; - useProgram(Shaders.ProgramTerrain); - // ShadersTex.bindNSTextures(defaultTexture.getMultiTexID()); // flat - } - } - - public static void endTerrain() { - if (true) return; - if (isRenderingWorld) { - if (isShadowPass) { - GL11.glEnable(GL11.GL_CULL_FACE); - } - useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); - // ShadersTex.bindNSTextures(defaultTexture.getMultiTexID()); // flat - } - } - - public static void beginBlockEntities() { - if (true) return; - if (isRenderingWorld) { - checkGLError("beginBlockEntities"); - useProgram(Shaders.ProgramTerrain); - } - } - - public static void endBlockEntities() { - if (true) return; - if (isRenderingWorld) { - checkGLError("endBlockEntities"); - useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); -// ShadersTex.bindNSTextures(defaultTexture.angelica$getMultiTexID()); - } - } - - public static void beginBlockDestroyProgress() { - if (true) return; - if (isRenderingWorld) { - useProgram(ProgramTerrain); - if (Shaders.configTweakBlockDamage) { - setDrawBuffers(drawBuffersColorAtt0); - GL11.glDepthMask(false); - // GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA,GL11.GL_ONE,GL11.GL_ZERO); - } - } - } - - public static void endBlockDestroyProgress() { - if (true) return; - if (isRenderingWorld) { - GL11.glDepthMask(true); - useProgram(ProgramTexturedLit); - } - } - - public static void beginEntities() { - if (true) return; - if (isRenderingWorld) { - useProgram(ProgramEntities); - if (programsID[activeProgram] != 0) { - useEntityHurtFlash = (uniformEntityHurt != -1) || (uniformEntityFlash != -1); - if (uniformEntityHurt != -1) glUniform1iARB(uniformEntityHurt, 0); - if (uniformEntityHurt != -1) glUniform1iARB(uniformEntityFlash, 0); - } else { - useEntityHurtFlash = false; - } - } - } - - public static void nextEntity() { - if (true) return; - if (isRenderingWorld) { - useProgram(ProgramEntities); - } - } - - public static void beginGlowingEyes() { - if (true) return; - if (isRenderingWorld) { - useProgram(ProgramSpiderEyes); - if (programsID[ProgramSpiderEyes] == programsID[ProgramTextured]) { - GL11.glEnable(GL11.GL_ALPHA_TEST); - GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE); - } - } - } - - public static void endEntities() { - if (true) return; - if (isRenderingWorld) { - useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); - } - } - - public static void setEntityHurtFlash(int hurt, int flash) { - if (true) return; - if (useEntityHurtFlash && isRenderingWorld && !isShadowPass) { - if (uniformEntityHurt != -1) glUniform1iARB(uniformEntityHurt, hurt); - if (uniformEntityFlash != -1) glUniform1iARB(uniformEntityFlash, flash >> 24); - checkGLError("setEntityHurtFlash"); - } - } - - public static void resetEntityHurtFlash() { - if (true) return; - setEntityHurtFlash(0, 0); - } - - public static void beginLivingDamage() { - if (true) return; - if (isRenderingWorld) { - ShadersTex.bindTexture(defaultTexture); - if (!isShadowPass) { - // useProgram(ProgramBasic); - setDrawBuffers(drawBuffersColorAtt0); - } - } - } - - public static void endLivingDamage() { - if (true) return; - if (isRenderingWorld) { - if (!isShadowPass) { - // useProgram(ProgramEntities); - setDrawBuffers(programsDrawBuffers[ProgramEntities]); - } - } - } - - public static void beginLitParticles() { - if (true) return; - // GL11.glDepthMask(false); - Tessellator.instance.setNormal(0f, 0f, 0f); - useProgram(ProgramTexturedLit); - } - - public static void beginParticles() { - if (true) return; - // GL11.glDepthMask(false); - Tessellator.instance.setNormal(0f, 0f, 0f); - useProgram(ProgramTextured); - } - - public static void endParticles() { - if (true) return; - Tessellator.instance.setNormal(0f, 0f, 0f); - useProgram(ProgramTexturedLit); - } - - public static void preWater() { - if (true) return; - if (isShadowPass) { - if (usedShadowDepthBuffers >= 2) { - // copy depth buffer to shadowtex1 - GL13.glActiveTexture(GL13.GL_TEXTURE5); - checkGLError("pre copy shadow depth"); - GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowMapWidth, shadowMapHeight); - checkGLError("copy shadow depth"); - GL13.glActiveTexture(GL13.GL_TEXTURE0); - } - } else { - if (usedDepthBuffers >= 2) { - // copy depth buffer to depthtex1 - GL13.glActiveTexture(GL13.GL_TEXTURE11); - checkGLError("pre copy depth"); - GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, renderWidth, renderHeight); - checkGLError("copy depth"); - GL13.glActiveTexture(GL13.GL_TEXTURE0); - } -// ShadersTex.bindNSTextures(defaultTexture.angelica$getMultiTexID()); // flat - } - } - - public static void beginWater() { - if (true) return; - if (isRenderingWorld) { - if (!isShadowPass) { - // program water - useProgram(Shaders.ProgramWater); - GL11.glEnable(GL11.GL_BLEND); - GL11.glDepthMask(true); - } else { - GL11.glDepthMask(true); - } - } - } - - public static void endWater() { - if (true) return; - if (isRenderingWorld) { - if (isShadowPass) { - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, - // sfbDepthTexture, 0); - } else { - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, - // dfbDepthTexture, 0); - } - useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); - } - } - - public static void readCenterDepth() { - if (true) return; - if (!isShadowPass) { - // Read depth buffer at center of screen for DOF - if (centerDepthSmoothEnabled) { - tempDirectFloatBuffer.clear(); - GL11.glReadPixels( renderWidth / 2, renderHeight / 2, 1, 1, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, tempDirectFloatBuffer); - centerDepth = tempDirectFloatBuffer.get(0); - - // Smooth depth value - float fadeScalar = diffSystemTime * 0.01f; - float fadeFactor = (float) Math.exp(Math.log(0.5) * fadeScalar / centerDepthSmoothHalflife); - centerDepthSmooth = centerDepthSmooth * (fadeFactor) + centerDepth * (1 - fadeFactor); - } - } - } - - public static void beginWeather() { - if (true) return; - if (!isShadowPass) { - if (usedDepthBuffers >= 3) { - // copy depth buffer to depthtex2 - GL13.glActiveTexture(GL13.GL_TEXTURE12); - GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, renderWidth, renderHeight); - GL13.glActiveTexture(GL13.GL_TEXTURE0); - } - // GL11.glDepthMask(false); - GL11.glEnable(GL11.GL_DEPTH_TEST); - GL11.glEnable(GL11.GL_BLEND); - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - GL11.glEnable(GL11.GL_ALPHA_TEST); - useProgram(Shaders.ProgramWeather); - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, - // dfbWaterDepthTexture, 0); - } - - // if (isShadowPass) { - // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // will be set to sbf in endHand() - // } - } - - public static void endWeather() { - if (true) return; - // GL11.glDepthMask(true); - GL11.glDisable(GL11.GL_BLEND); - useProgram(ProgramTexturedLit); - // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, dfbDepthTexture, 0); - - // if (isShadowPass) { - // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, sfb); // was set to 0 in beginWeather() - // } - } - - public static void beginProjectRedHalo() { - if (true) return; - useProgram(ProgramBasic); - } - - public static void endProjectRedHalo() { - if (true) return; - useProgram(ProgramTexturedLit); - } - - public static void applyHandDepth() { - if (true) return; - if (Shaders.configHandDepthMul != 1.0) { - GL11.glScaled(1.0, 1.0, Shaders.configHandDepthMul); - } - } - - public static void beginHand() { - if (true) return; - // GL11.glEnable(GL11.GL_BLEND); - // GL11.glDisable(GL11.GL_BLEND); - GL11.glMatrixMode(GL11.GL_MODELVIEW); - GL11.glPushMatrix(); - GL11.glMatrixMode(GL11.GL_PROJECTION); - GL11.glPushMatrix(); - GL11.glMatrixMode(GL11.GL_MODELVIEW); - useProgram(Shaders.ProgramHand); - checkGLError("beginHand"); - checkFramebufferStatus("beginHand"); - } - - public static void endHand() { - if (true) return; - // GL11.glDisable(GL11.GL_BLEND); - checkGLError("pre endHand"); - checkFramebufferStatus("pre endHand"); - GL11.glMatrixMode(GL11.GL_PROJECTION); - GL11.glPopMatrix(); - GL11.glMatrixMode(GL11.GL_MODELVIEW); - GL11.glPopMatrix(); - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - // useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); - checkGLError("endHand"); - } - - public static void beginFPOverlay() { - if (true) return; - // GL11.glDisable(GL11.GL_BLEND); - // GL11.glEnable(GL11.GL_BLEND); - // GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - } - - public static void endFPOverlay() { - if (true) return; - // GL11.glDisable(GL11.GL_BLEND); - } - - // ---------------------------------------- - - public static void glEnableWrapper(int cap) { - GL11.glEnable(cap); - if (cap == GL11.GL_TEXTURE_2D) enableTexture2D(); - else if (cap == GL11.GL_FOG) enableFog(); - } - - public static void glDisableWrapper(int cap) { - GL11.glDisable(cap); - if (cap == GL11.GL_TEXTURE_2D) disableTexture2D(); - else if (cap == GL11.GL_FOG) disableFog(); - } - - public static void glEnableT2D(int cap) { - GL11.glEnable(cap); // GL11.GL_TEXTURE_2D - enableTexture2D(); - } - - public static void glDisableT2D(int cap) { - GL11.glDisable(cap); // GL11.GL_TEXTURE_2D - disableTexture2D(); - } - - public static void glEnableFog(int cap) { - GL11.glEnable(cap); // GL11.GL_FOG - enableFog(); - } - - public static void glDisableFog(int cap) { - GL11.glDisable(cap); // GL11.GL_FOG - disableFog(); - } - - public static void enableTexture2D() { - if (true) return; - if (isRenderingSky) { - useProgram(ProgramSkyTextured); - } else if (activeProgram == ProgramBasic) { - useProgram(lightmapEnabled ? ProgramTexturedLit : ProgramTextured); - } - } - - public static void disableTexture2D() { - if (true) return; - if (isRenderingSky) { - useProgram(ProgramSkyBasic); - } else if (activeProgram == ProgramTextured || activeProgram == ProgramTexturedLit) { - useProgram(ProgramBasic); - } - } - - public static void enableFog() { - if (true) return; - fogEnabled = true; - setProgramUniform1i("fogMode", fogMode); - } - - public static void disableFog() { - if (true) return; - fogEnabled = false; - setProgramUniform1i("fogMode", 0); - } - - public static void sglFogi(int pname, int param) { - GL11.glFogi(pname, param); - if (pname == GL11.GL_FOG_MODE) { - fogMode = param; - if (fogEnabled) setProgramUniform1i("fogMode", fogMode); - } - } - - public static void sglFogf(int pname, float param) { - GL11.glFogf(pname, param); - switch (pname) { - case GL11.GL_FOG_DENSITY: - fogDensity = param; - break; - case GL11.GL_FOG_START: - fogStart = param; - break; - case GL11.GL_FOG_END: - fogEnd = param; - break; - } - } - - public static void enableLightmap() { - lightmapEnabled = true; - if (true) return; - if (activeProgram == ProgramTextured) { - useProgram(ProgramTexturedLit); - } - } - - public static void disableLightmap() { - lightmapEnabled = false; - if (true) return; - if (activeProgram == ProgramTexturedLit) { - useProgram(ProgramTextured); - } - } - - public static int entityData[] = new int[32]; - public static int entityDataIndex = 0; - - public static int getEntityData() { - return entityData[entityDataIndex * 2]; - } - - public static int getEntityData2() { - return entityData[entityDataIndex * 2 + 1]; - } - - public static int setEntityData1(int data1) { - entityData[entityDataIndex * 2] = (entityData[entityDataIndex * 2] & 0xFFFF) | (data1 << 16); - return data1; - } - - public static int setEntityData2(int data2) { - entityData[entityDataIndex * 2 + 1] = (entityData[entityDataIndex * 2 + 1] & 0xFFFF0000) | (data2 & 0xFFFF); - return data2; - } - - public static void pushEntity(int data0, int data1) { - entityDataIndex++; - entityData[entityDataIndex * 2] = (data0 & 0xFFFF) | (data1 << 16); - entityData[entityDataIndex * 2 + 1] = 0; - } - - public static void pushEntity(int data0) { - entityDataIndex++; - entityData[entityDataIndex * 2] = (data0 & 0xFFFF); - entityData[entityDataIndex * 2 + 1] = 0; - } - - public static void pushEntity(Block block) { - final int metadata = 0; - // BlockAliases.getMappedBlockId - final int blockId = Block.blockRegistry.getIDForObject(block); - entityDataIndex++; - entityData[entityDataIndex * 2] = (blockId & 0xFFFF) | (block.getRenderType() << 16); - entityData[entityDataIndex * 2 + 1] = metadata; - } - - public static void pushEntity(RenderBlocks rb, Block block, int x, int y, int z) { - final int metadata = rb.blockAccess.getBlockMetadata(x, y, z); - // BlockAliases.getMappedBlockId - final int blockId = Block.blockRegistry.getIDForObject(block); - entityDataIndex++; - entityData[entityDataIndex * 2] = (blockId & 0xFFFF) | (block.getRenderType() << 16); - entityData[entityDataIndex * 2 + 1] = metadata; - } - - public static void popEntity() { - entityData[entityDataIndex * 2] = 0; - entityData[entityDataIndex * 2 + 1] = 0; - entityDataIndex--; - } - - // ---------------------------------------- - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShadersRender.java b/src/main/java/com/gtnewhorizons/angelica/client/ShadersRender.java deleted file mode 100644 index 6956918ea..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShadersRender.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -import java.nio.IntBuffer; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockIce; -import net.minecraft.client.renderer.EntityRenderer; -import net.minecraft.client.renderer.ItemRenderer; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.renderer.culling.Frustrum; -import net.minecraft.item.Item; -import net.minecraft.item.ItemBlock; - -import org.lwjgl.opengl.GL11; - -public class ShadersRender { - - public static void setFrustrumPosition(Frustrum frustrum, double x, double y, double z) { - frustrum.setPosition(x, y, z); - } - - public static void clipRenderersByFrustrum(RenderGlobal renderGlobal, Frustrum frustrum, float par2) { - Shaders.checkGLError("pre clip"); - WorldRenderer[] worldRenderers = renderGlobal.worldRenderers; - if (!Shaders.isShadowPass) { - for (WorldRenderer worldRenderer : worldRenderers) { - if (!worldRenderer.skipAllRenderPasses()) { - worldRenderer.updateInFrustum(frustrum); - } - } - } else { - for (WorldRenderer worldRenderer : worldRenderers) { - if (!worldRenderer.skipAllRenderPasses()) { - worldRenderer.isInFrustum = true; - } - } - } - } - - public static void renderHand0(EntityRenderer er, float par1, int par2) { - if (!Shaders.isShadowPass) { - Item item = (Shaders.itemToRender != null) ? Shaders.itemToRender.getItem() : null; - Block block = (item instanceof ItemBlock) ? ((ItemBlock) item).field_150939_a : null; - // ItemCloth is for semitransparent block : stained glass, wool - if (!(item instanceof ItemBlock) && !(block instanceof BlockIce)) { - Shaders.readCenterDepth(); - Shaders.beginHand(); - er.renderHand(par1, par2); - Shaders.endHand(); - Shaders.isHandRendered = true; - } - } - } - - public static void renderHand1(EntityRenderer er, float par1, int par2) { - if (!Shaders.isShadowPass) { - if (!Shaders.isHandRendered) { - Shaders.readCenterDepth(); - GL11.glEnable(GL11.GL_BLEND); - Shaders.beginHand(); - er.renderHand(par1, par2); - Shaders.endHand(); - Shaders.isHandRendered = true; - } - } - } - - public static void renderItemFP(ItemRenderer itemRenderer, float par1) { - // clear depth buffer locally - GL11.glDepthFunc(GL11.GL_GEQUAL); - GL11.glPushMatrix(); - IntBuffer drawBuffers = Shaders.activeDrawBuffers; - Shaders.setDrawBuffers(Shaders.drawBuffersNone); - itemRenderer.renderItemInFirstPerson(par1); - Shaders.setDrawBuffers(drawBuffers); - GL11.glPopMatrix(); - GL11.glDepthFunc(GL11.GL_LEQUAL); - // really drawScreen item or hand - itemRenderer.renderItemInFirstPerson(par1); - } - - public static void renderFPOverlay(EntityRenderer er, float par1, int par2) { - Shaders.beginFPOverlay(); - er.renderHand(par1, par2); - Shaders.endFPOverlay(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTess.java b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTess.java deleted file mode 100644 index b8fcaeb55..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTess.java +++ /dev/null @@ -1,265 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; -import com.gtnewhorizons.angelica.mixins.interfaces.TessellatorAccessor; -import net.minecraft.client.renderer.OpenGlHelper; -import net.minecraft.client.renderer.Tessellator; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL13; - -import java.nio.FloatBuffer; -import java.nio.ShortBuffer; -import java.util.Arrays; - -import static org.lwjgl.opengl.ARBVertexShader.glDisableVertexAttribArrayARB; -import static org.lwjgl.opengl.ARBVertexShader.glEnableVertexAttribArrayARB; -import static org.lwjgl.opengl.ARBVertexShader.glVertexAttribPointerARB; - -public class ShadersTess { - - public static final int vertexStride = 16; - - public static int draw(Tessellator tess) { - final TessellatorAccessor tessa = (TessellatorAccessor) tess; - if (!tess.isDrawing) { - throw new IllegalStateException("Not tesselating!"); - } else { - tess.isDrawing = false; - if (tess.drawMode == GL11.GL_QUADS && tess.vertexCount % 4 != 0) { - AngelicaTweaker.LOGGER.warn("%s", "bad vertexCount"); - } - int voffset = 0; - int realDrawMode = tess.drawMode; - while (voffset < tess.vertexCount) { - int vcount; - vcount = Math.min( - tess.vertexCount - voffset, - tessa.angelica$getByteBuffer().capacity() / (vertexStride * 4)); - if (realDrawMode == GL11.GL_QUADS) vcount = vcount / 4 * 4; - tessa.angelica$getFloatBuffer().clear(); - tessa.angelica$getShortBuffer().clear(); - tessa.angelica$getIntBuffer().clear(); - tessa.angelica$getIntBuffer().put(tess.rawBuffer, voffset * vertexStride, vcount * vertexStride); - tessa.angelica$getByteBuffer().position(0); - tessa.angelica$getByteBuffer().limit(vcount * (vertexStride * 4)); - voffset += vcount; - - if (tess.hasTexture) { - tessa.angelica$getFloatBuffer().position(3); - GL11.glTexCoordPointer(2, (vertexStride * 4), tessa.angelica$getFloatBuffer()); - GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); - } - if (tess.hasBrightness) { - OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); - tessa.angelica$getShortBuffer().position(6 * 2); - GL11.glTexCoordPointer(2, (vertexStride * 4), tessa.angelica$getShortBuffer()); - GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); - OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); - } - if (tess.hasColor) { - tessa.angelica$getByteBuffer().position(5 * 4); - GL11.glColorPointer(4, true, (vertexStride * 4), tessa.angelica$getByteBuffer()); - GL11.glEnableClientState(GL11.GL_COLOR_ARRAY); - } - if (tess.hasNormals) { - tessa.angelica$getFloatBuffer().position(9); - GL11.glNormalPointer((vertexStride * 4), tessa.angelica$getFloatBuffer()); - GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY); - } - tessa.angelica$getFloatBuffer().position(0); - GL11.glVertexPointer(3, (vertexStride * 4), tessa.angelica$getFloatBuffer()); - ShadersTess.preDrawArray(tess); - - GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); - GL11.glDrawArrays(realDrawMode, 0, vcount); - } - // end loop - - GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY); - ShadersTess.postDrawArray(tess); - if (tess.hasTexture) { - GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); - } - if (tess.hasBrightness) { - OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); - GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); - OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); - } - if (tess.hasColor) { - GL11.glDisableClientState(GL11.GL_COLOR_ARRAY); - } - if (tess.hasNormals) { - GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY); - } - - int n = tess.rawBufferIndex * 4; - tess.reset(); - return n; - } - } - - public static void preDrawArray(Tessellator tess) { - final TessellatorAccessor tessa = (TessellatorAccessor) tess; - // Shaders.checkGLError("preDrawArray"); - if (Shaders.useMultiTexCoord3Attrib && tess.hasTexture) { - GL13.glClientActiveTexture(GL13.GL_TEXTURE3); - GL11.glTexCoordPointer(2, (vertexStride * 4), (FloatBuffer) tessa.angelica$getFloatBuffer().position(12)); - GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); - GL13.glClientActiveTexture(GL13.GL_TEXTURE0); - } - if (Shaders.useMidTexCoordAttrib && tess.hasTexture) { - glVertexAttribPointerARB( - Shaders.midTexCoordAttrib, - 2, - false, - vertexStride * 4, - (FloatBuffer) tessa.angelica$getFloatBuffer().position(12)); - glEnableVertexAttribArrayARB(Shaders.midTexCoordAttrib); - } - if (Shaders.useEntityAttrib) { - glVertexAttribPointerARB( - Shaders.entityAttrib, - 3, - false, - false, - vertexStride * 4, - (ShortBuffer) tessa.angelica$getShortBuffer().position(7 * 2)); - glEnableVertexAttribArrayARB(Shaders.entityAttrib); - } - // Shaders.checkGLError("preDrawArray"); - } - - public static void preDrawArrayVBO(Tessellator tess) { - // Shaders.checkGLError("preDrawArray"); - if (Shaders.useMultiTexCoord3Attrib && tess.hasTexture) { - GL13.glClientActiveTexture(GL13.GL_TEXTURE3); - GL11.glTexCoordPointer(2, GL11.GL_FLOAT, (vertexStride * 4), 12 * 4L); - GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); - GL13.glClientActiveTexture(GL13.GL_TEXTURE0); - } - if (Shaders.useMidTexCoordAttrib && tess.hasTexture) { - glVertexAttribPointerARB(Shaders.midTexCoordAttrib, 2, GL11.GL_FLOAT, false, vertexStride * 4, 12 * 4L); - glEnableVertexAttribArrayARB(Shaders.midTexCoordAttrib); - } - if (Shaders.useEntityAttrib) { - glVertexAttribPointerARB(Shaders.entityAttrib, 3, GL11.GL_SHORT, false, vertexStride * 4, 7 * 4L); - glEnableVertexAttribArrayARB(Shaders.entityAttrib); - } - // Shaders.checkGLError("preDrawArray"); - } - - public static void postDrawArray(Tessellator tess) { - // Shaders.checkGLError("postDrawArray"); - if (Shaders.useEntityAttrib) { - glDisableVertexAttribArrayARB(Shaders.entityAttrib); - } - if (Shaders.useMidTexCoordAttrib && tess.hasTexture) { - glDisableVertexAttribArrayARB(Shaders.midTexCoordAttrib); - } - if (Shaders.useMultiTexCoord3Attrib && tess.hasTexture) { - GL13.glClientActiveTexture(GL13.GL_TEXTURE3); - GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); - GL13.glClientActiveTexture(GL13.GL_TEXTURE0); - } - // Shaders.checkGLError("postDrawArray"); - } - - public static void addVertex(Tessellator tess, double parx, double pary, double parz) { - final TessellatorAccessor tessa = (TessellatorAccessor) (Object) tess; - int[] rawBuffer = tess.rawBuffer; - int rbi = tess.rawBufferIndex; - float fx = (float) (parx + tess.xOffset); - float fy = (float) (pary + tess.yOffset); - float fz = (float) (parz + tess.zOffset); - // Check if buffer is nearly full - if (rbi >= tess.bufferSize - vertexStride * 4) { - if (tess.bufferSize >= 0x1000000) { - // Max size reached. Just draw. - if (tess.addedVertices % 4 == 0) { - tess.draw(); - tess.isDrawing = true; - } - } else if (tess.bufferSize > 0) { - // Expand - tess.bufferSize *= 2; - tess.rawBuffer = rawBuffer = Arrays.copyOf(tess.rawBuffer, tess.bufferSize); - AngelicaTweaker.LOGGER.trace("Expand tesselator buffer {}", tess.bufferSize); - } else { - // Initialize - tess.bufferSize = 0x10000; - tess.rawBuffer = rawBuffer = new int[tess.bufferSize]; - } - } - - // shaders mod calculate normal and mid UV - if (tess.drawMode == 7) { - int i = tess.addedVertices % 4; - float[] vertexPos = tessa.angelica$getVertexPos(); - vertexPos[i * 4 + 0] = fx; - vertexPos[i * 4 + 1] = fy; - vertexPos[i * 4 + 2] = fz; - if (i == 3) { - // calculate normal - float x1 = vertexPos[8 + 0] - vertexPos[+0]; - float y1 = vertexPos[8 + 1] - vertexPos[+1]; - float z1 = vertexPos[8 + 2] - vertexPos[+2]; - float x2 = vertexPos[12 + 0] - vertexPos[4 + 0]; - float y2 = vertexPos[12 + 1] - vertexPos[4 + 1]; - float z2 = vertexPos[12 + 2] - vertexPos[4 + 2]; - float vnx = y1 * z2 - y2 * z1; - float vny = z1 * x2 - z2 * x1; - float vnz = x1 * y2 - x2 * y1; - float lensq = vnx * vnx + vny * vny + vnz * vnz; - float mult = (lensq != 0.0) ? (float) (1f / Math.sqrt(lensq)) : 1f; - float normalX = vnx * mult; - float normalY = vny * mult; - float normalZ = vnz * mult; - tessa.angelica$setNormalX(normalX); - tessa.angelica$setNormalY(normalY); - tessa.angelica$setNormalZ(normalZ); - rawBuffer[rbi + (9 - vertexStride * 3)] = rawBuffer[rbi + (9 - vertexStride * 2)] = - rawBuffer[rbi + (9 - vertexStride * 1)] = Float.floatToRawIntBits(normalX); - rawBuffer[rbi + (10 - vertexStride * 3)] = rawBuffer[rbi + (10 - vertexStride * 2)] = - rawBuffer[rbi + (10 - vertexStride * 1)] = Float.floatToRawIntBits(normalY); - rawBuffer[rbi + (11 - vertexStride * 3)] = rawBuffer[rbi + (11 - vertexStride * 2)] = - rawBuffer[rbi + (11 - vertexStride * 1)] = Float.floatToRawIntBits(normalZ); - tess.hasNormals = true; - // mid UV - tessa.angelica$setMidTextureU( - (Float.intBitsToFloat(rawBuffer[rbi + (3 - vertexStride * 3)]) - + Float.intBitsToFloat(rawBuffer[rbi + (3 - vertexStride * 2)]) - + Float.intBitsToFloat(rawBuffer[rbi + (3 - vertexStride * 1)]) - + (float) tess.textureU) / 4); - tessa.angelica$setMidTextureV( - (Float.intBitsToFloat(rawBuffer[rbi + (4 - vertexStride * 3)]) - + Float.intBitsToFloat(rawBuffer[rbi + (4 - vertexStride * 2)]) - + Float.intBitsToFloat(rawBuffer[rbi + (4 - vertexStride * 1)]) - + (float) tess.textureV) / 4); - rawBuffer[rbi + (12 - vertexStride * 3)] = rawBuffer[rbi + (12 - vertexStride * 2)] = - rawBuffer[rbi + (12 - vertexStride * 1)] = Float.floatToRawIntBits(tessa.angelica$getMidTextureU()); - rawBuffer[rbi + (13 - vertexStride * 3)] = rawBuffer[rbi + (13 - vertexStride * 2)] = - rawBuffer[rbi + (13 - vertexStride * 1)] = Float.floatToRawIntBits(tessa.angelica$getMidTextureV()); - } - } - // end normal and mid UV calculation - - ++tess.addedVertices; - rawBuffer[rbi + 0] = Float.floatToRawIntBits((float) fx); - rawBuffer[rbi + 1] = Float.floatToRawIntBits((float) fy); - rawBuffer[rbi + 2] = Float.floatToRawIntBits((float) fz); - rawBuffer[rbi + 3] = Float.floatToRawIntBits((float) tess.textureU); - rawBuffer[rbi + 4] = Float.floatToRawIntBits((float) tess.textureV); - rawBuffer[rbi + 5] = tess.color; - rawBuffer[rbi + 6] = tess.brightness; - rawBuffer[rbi + 7] = Shaders.getEntityData(); - rawBuffer[rbi + 8] = Shaders.getEntityData2(); - rawBuffer[rbi + 9] = Float.floatToRawIntBits((float) tessa.angelica$getNormalX()); - rawBuffer[rbi + 10] = Float.floatToRawIntBits((float) tessa.angelica$getNormalY()); - rawBuffer[rbi + 11] = Float.floatToRawIntBits((float) tessa.angelica$getNormalZ()); - rawBuffer[rbi + 12] = Float.floatToRawIntBits((float) tessa.angelica$getMidTextureU()); - rawBuffer[rbi + 13] = Float.floatToRawIntBits((float) ((TessellatorAccessor) tess).angelica$getMidTextureV()); - - tess.rawBufferIndex = rbi += vertexStride; - ++tess.vertexCount; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java b/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java deleted file mode 100644 index 4cceb7a43..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/ShadersTex.java +++ /dev/null @@ -1,882 +0,0 @@ -package com.gtnewhorizons.angelica.client; - -import net.minecraft.client.renderer.texture.AbstractTexture; -import net.minecraft.client.renderer.texture.DynamicTexture; -import net.minecraft.client.renderer.texture.ITextureObject; -import net.minecraft.client.renderer.texture.LayeredTexture; -import net.minecraft.client.renderer.texture.Stitcher; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureMap; -import net.minecraft.client.renderer.texture.TextureUtil; -import net.minecraft.client.resources.IResource; -import net.minecraft.client.resources.IResourceManager; -import net.minecraft.util.ResourceLocation; -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.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.IntBuffer; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ShadersTex { - - public static final int initialBufferSize = 1048576; - public static ByteBuffer byteBuffer = BufferUtils.createByteBuffer(initialBufferSize * 4); - public static IntBuffer intBuffer = byteBuffer.asIntBuffer(); - public static int[] intArray = new int[initialBufferSize]; - public static final int defBaseTexColor = 0x00000000; - public static final int defNormTexColor = 0xFF7F7FFF; - public static final int defSpecTexColor = 0x00000000; - public static Map multiTexMap = new HashMap<>(); - public static TextureMap updatingTextureMap = null; - public static TextureAtlasSprite updatingSprite = null; - public static MultiTexID updatingTex = null; - public static MultiTexID boundTex = null; - public static int updatingPage = 0; - public static String iconName = null; - - public static IntBuffer getIntBuffer(int size) { - if (intBuffer.capacity() < size) { - int bufferSize = roundUpPOT(size); - byteBuffer = BufferUtils.createByteBuffer(bufferSize * 4); - intBuffer = byteBuffer.asIntBuffer(); - } - return intBuffer; - } - - public static int[] getIntArray(int size) { - if (intArray.length < size) { - intArray = null; - intArray = new int[roundUpPOT(size)]; - } - return intArray; - } - - public static int roundUpPOT(int x) { - int i = x - 1; - i |= (i >> 1); - i |= (i >> 2); - i |= (i >> 4); - i |= (i >> 8); - i |= (i >> 16); - return i + 1; - } - - public static IntBuffer fillIntBuffer(int size, int value) { - getIntArray(size); - getIntBuffer(size); - Arrays.fill(intArray, 0, size, value); - intBuffer.put(intArray, 0, size); - return intBuffer; - } - - public static int[] createAIntImage(int size) { - int[] aint = new int[size * 3]; - Arrays.fill(aint, 0, size, defBaseTexColor); - Arrays.fill(aint, size, size * 2, defNormTexColor); - Arrays.fill(aint, size * 2, size * 3, defSpecTexColor); - return aint; - } - - public static int[] createAIntImage(int size, int color) { - int[] aint = new int[size * 3]; - Arrays.fill(aint, 0, size, color); - Arrays.fill(aint, size, size * 2, defNormTexColor); - Arrays.fill(aint, size * 2, size * 3, defSpecTexColor); - return aint; - } - - public static MultiTexID getMultiTexID(AbstractTexture tex) { - return null; -// MultiTexID multiTex = tex.angelica$multiTex; -// if (multiTex == null) { -// int baseTex = tex.getGlTextureId(); -// multiTex = multiTexMap.get(Integer.valueOf(baseTex)); -// if (multiTex == null) { -// multiTex = new MultiTexID(baseTex, GL11.glGenTextures(), GL11.glGenTextures()); -// multiTexMap.put(baseTex, multiTex); -// } -// tex.angelica$multiTex = multiTex; -// } -// return multiTex; - } - - public static void deleteTextures(AbstractTexture atex) { -// int texid = atex.glTextureId; -// if (texid != -1) { -// GL11.glDeleteTextures(texid); -// atex.glTextureId = -1; -// } -// MultiTexID multiTex = atex.angelica$multiTex; -// if (multiTex != null) { -// atex.angelica$multiTex = null; -// multiTexMap.remove(Integer.valueOf(multiTex.base)); -// GL11.glDeleteTextures(multiTex.norm); -// GL11.glDeleteTextures(multiTex.spec); -// if (multiTex.base != texid) { -// AngelicaTweaker.LOGGER.warn("Error : MultiTexID.base mismatch."); -// GL11.glDeleteTextures(multiTex.base); -// } -// } - } - - /** Remove MultiTexID object reference and delete textures */ - public static int deleteMultiTex(ITextureObject tex) { - if (tex instanceof AbstractTexture) { - deleteTextures((AbstractTexture) tex); - } else { - GL11.glDeleteTextures(tex.getGlTextureId()); - } - return 0; - } - - public static void bindNSTextures(int normTex, int specTex) { - // Shaders.checkGLError("pre bindNSTextures"); - if (Shaders.isRenderingWorld && Shaders.activeTexUnit == GL13.GL_TEXTURE0) { - GL13.glActiveTexture(GL13.GL_TEXTURE2); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, normTex); - GL13.glActiveTexture(GL13.GL_TEXTURE3); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, specTex); - GL13.glActiveTexture(GL13.GL_TEXTURE0); - } - // Shaders.checkGLError("bindNSTextures"); - } - - public static void bindNSTextures(MultiTexID multiTex) { - bindNSTextures(multiTex.norm, multiTex.spec); - } - - public static void bindTextures(int baseTex, int normTex, int specTex) { - // Shaders.checkGLError("pre bindTextures"); - if (Shaders.isRenderingWorld && Shaders.activeTexUnit == GL13.GL_TEXTURE0) { - GL13.glActiveTexture(GL13.GL_TEXTURE2); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, normTex); - GL13.glActiveTexture(GL13.GL_TEXTURE3); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, specTex); - GL13.glActiveTexture(GL13.GL_TEXTURE0); - } - GL11.glBindTexture(GL11.GL_TEXTURE_2D, baseTex); - // Shaders.checkGLError("bindTextures"); - } - - public static void bindTextures(MultiTexID multiTex) { - boundTex = multiTex; - if (Shaders.isRenderingWorld && Shaders.activeTexUnit == GL13.GL_TEXTURE0) { - if (Shaders.configNormalMap) { - GL13.glActiveTexture(GL13.GL_TEXTURE2); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - } - if (Shaders.configSpecularMap) { - GL13.glActiveTexture(GL13.GL_TEXTURE3); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); - } - GL13.glActiveTexture(GL13.GL_TEXTURE0); - } - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); - } - - public static void bindTexture(ITextureObject tex) { -// if (tex instanceof TextureMap) { -// Shaders.atlasSizeX = ((TextureMap) tex).angelica$atlasWidth; -// Shaders.atlasSizeY = ((TextureMap) tex).angelica$atlasHeight; -// } else { -// Shaders.atlasSizeX = 0; -// Shaders.atlasSizeY = 0; -// } -// bindTextures(tex.angelica$getMultiTexID()); - } - - /** not used */ - public static void bindTextures(int baseTex) { - MultiTexID multiTex = multiTexMap.get(Integer.valueOf(baseTex)); - bindTextures(multiTex); - } - - public static void allocTexStorage(int width, int height, int maxLevel) { - Shaders.checkGLError("pre allocTexStorage"); - int level; - for (level = 0; (width >> level) > 0 && (height >> level) > 0 /* && level<=maxLevel */; ++level) { - GL11.glTexImage2D(GL11.GL_TEXTURE_2D, level, GL11.GL_RGBA, (width >> level), (height >> level), 0, - GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (IntBuffer) null); - } - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, level - 1); - Shaders.checkGLError("allocTexStorage"); - // clear unused level otherwise glTexSubImage2D will crash on AMD when reallocation texture of different size. - // for ( ; level < 16 ; ++level) { - // GL11.glTexImage2D(GL11.GL_TEXTURE_2D, level, GL11.GL_RGBA, 0, 0, 0, GL12.GL_BGRA, - // GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (IntBuffer)null); - // } - GL11.glGetError(); // It usually returns error 0x0501 Invalid value for width 0 height 0. Ignore it. - } - - // for Dynamic Texture - public static void initDynamicTexture(int texID, int width, int height, DynamicTexture tex) { - // TODO: PBR -// MultiTexID multiTex = tex.angelica$getMultiTexID(); -// int[] aint = tex.getTextureData(); -// int size = width * height; -// Arrays.fill(aint, size, size * 2, defNormTexColor); -// Arrays.fill(aint, size * 2, size * 3, defSpecTexColor); -// // base texture -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); -// allocTexStorage(width, height, 0); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0); -// -// // This seems PBR related... -// // norm texture -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); -// allocTexStorage(width, height, 0); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0); -// -// // spec texture -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); -// allocTexStorage(width, height, 0); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0); -// -// // base texture -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); - } - - public static ITextureObject createDefaultTexture() { - DynamicTexture tex = new DynamicTexture(1, 1); - tex.getTextureData()[0] = 0xffffffff; - tex.updateDynamicTexture(); - return tex; - } - - // for TextureMap - public static void allocateTextureMap(int texID, int mipmapLevels, int width, int height, float anisotropy, - Stitcher stitcher, TextureMap tex) { -// AngelicaTweaker.LOGGER.trace("allocateTextureMap {} {} {} {} {}", tex.getTextureType(), mipmapLevels, width, height, anisotropy); -// updatingTextureMap = tex; -// tex.angelica$atlasWidth = width; -// tex.angelica$atlasHeight = height; -// MultiTexID multiTex = getMultiTexID(tex); -// updatingTex = multiTex; -// TextureUtil.allocateTextureImpl(multiTex.base, mipmapLevels, width, height, anisotropy); -// if (Shaders.configNormalMap) -// TextureUtil.allocateTextureImpl(multiTex.norm, mipmapLevels, width, height, anisotropy); -// if (Shaders.configSpecularMap) -// TextureUtil.allocateTextureImpl(multiTex.spec, mipmapLevels, width, height, anisotropy); -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID); - } - - public static TextureAtlasSprite setSprite(TextureAtlasSprite tas) { - return updatingSprite = tas; - } - - public static String setIconName(String name) { - return iconName = name; - } - - public static void uploadTexSubForLoadAtlas(int[][] data, int width, int height, int xoffset, int yoffset, - boolean linear, boolean clamp) { - TextureUtil.uploadTextureMipmap(data, width, height, xoffset, yoffset, linear, clamp); - boolean border = updatingSprite.useAnisotropicFiltering; - int[][] aaint; - // - if (Shaders.configNormalMap) { - aaint = readImageAndMipmaps(iconName + "_n", width, height, data.length, border, defNormTexColor); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.norm); - TextureUtil.uploadTextureMipmap(aaint, width, height, xoffset, yoffset, linear, clamp); - } - // - if (Shaders.configSpecularMap) { - aaint = readImageAndMipmaps(iconName + "_s", width, height, data.length, border, defSpecTexColor); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.spec); - TextureUtil.uploadTextureMipmap(aaint, width, height, xoffset, yoffset, linear, clamp); - } - // - GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.base); - } - - public static int[][] readImageAndMipmaps(String name, int width, int height, int numLevels, boolean border, - int defColor) { - int[][] aaint = new int[numLevels][]; - int[] aint; - aaint[0] = aint = new int[width * height]; - boolean goodImage = false; - BufferedImage image = readImage(updatingTextureMap.completeResourceLocation(new ResourceLocation(name), 0)); - if (image != null) { - int imageWidth = image.getWidth(); - int imageHeight = image.getHeight(); - if (imageWidth + (border ? 16 : 0) == width) { - goodImage = true; - image.getRGB(0, 0, imageWidth, imageWidth, aint, 0, imageWidth); - if (border) TextureUtil.prepareAnisotropicData(aint, imageWidth, imageWidth, 8); - } - } - if (!goodImage) { - Arrays.fill(aint, defColor); - } - GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.spec); - aaint = genMipmapsSimple(aaint.length - 1, width, aaint); - return aaint; - } - - public static BufferedImage readImage(ResourceLocation resLoc) { - BufferedImage image = null; - InputStream istr = null; - if (resManager != null) { - try { - istr = resManager.getResource(resLoc).getInputStream(); - image = ImageIO.read(istr); - } catch (IOException e) {} - if (istr != null) { - try { - istr.close(); - } catch (IOException e) {} - istr = null; - } - } - return image; - } - - public static int[][] genMipmapsSimple(int maxLevel, int width, int[][] data) { - int level; - for (level = 1; level <= maxLevel; ++level) { - if (data[level] == null) { - int cw = width >> level; - int pw = cw * 2; - int[] aintp = data[level - 1]; - int[] aintc = data[level] = new int[cw * cw]; - int x, y; - for (y = 0; y < cw; ++y) { - for (x = 0; x < cw; ++x) { - int ppos = y * 2 * pw + x * 2; - aintc[y * cw + x] = blend4Simple(aintp[ppos], aintp[ppos + 1], aintp[ppos + pw], aintp[ppos + pw + 1]); - } - } - } - } - return data; - } - - public static void uploadTexSub(int[][] data, int width, int height, int xoffset, int yoffset, boolean linear, boolean clamp) { - // TODO: Mipmap - TextureUtil.uploadTextureMipmap(data, width, height, xoffset, yoffset, linear, clamp); - } - - public static int blend4Alpha(int c0, int c1, int c2, int c3) { - int a0 = (c0 >>> 24) & 255; - int a1 = (c1 >>> 24) & 255; - int a2 = (c2 >>> 24) & 255; - int a3 = (c3 >>> 24) & 255; - int as = a0 + a1 + a2 + a3; - int an = (as + 2) / 4; - // int an = Math.min(Math.min(Math.min(a0,a1),a2),a3); - int dv; - if (as != 0) { - dv = as; - } else { - dv = 4; - a3 = a2 = a1 = a0 = 1; - } - int frac = (dv + 1) / 2; - // return (((Math.min(Math.min(Math.min(a0,a1),a2),a3)/ 4) << 24) | - int color = (an << 24) - | (((((c0 >>> 16) & 255) * a0 + ((c1 >>> 16) & 255) * a1 - + ((c2 >>> 16) & 255) * a2 - + ((c3 >>> 16) & 255) * a3 - + frac) / dv) << 16) - | (((((c0 >>> 8) & 255) * a0 + ((c1 >>> 8) & 255) * a1 - + ((c2 >>> 8) & 255) * a2 - + ((c3 >>> 8) & 255) * a3 - + frac) / dv) << 8) - | (((((c0 >>> 0) & 255) * a0 + ((c1 >>> 0) & 255) * a1 - + ((c2 >>> 0) & 255) * a2 - + ((c3 >>> 0) & 255) * a3 - + frac) / dv) << 0); - return color; - } - - public static int blend4Simple(int c0, int c1, int c2, int c3) { - int color = (((((c0 >>> 24) & 255) + ((c1 >>> 24) & 255) + ((c2 >>> 24) & 255) + ((c3 >>> 24) & 255) + 2) / 4) - << 24) - | (((((c0 >>> 16) & 255) + ((c1 >>> 16) & 255) + ((c2 >>> 16) & 255) + ((c3 >>> 16) & 255) + 2) / 4) - << 16) - | (((((c0 >>> 8) & 255) + ((c1 >>> 8) & 255) + ((c2 >>> 8) & 255) + ((c3 >>> 8) & 255) + 2) / 4) << 8) - | (((((c0 >>> 0) & 255) + ((c1 >>> 0) & 255) + ((c2 >>> 0) & 255) + ((c3 >>> 0) & 255) + 2) / 4) << 0); - return color; - } - - public static void genMipmapAlpha(int[] aint, int offset, int width, int height) { - int level; - int w1, w2, h1, h2, o1, o2; - w1 = w2 = width; - h1 = h2 = height; - o1 = o2 = offset; - // generate mipmap from big to small - o2 = offset; - w2 = width; - h2 = height; - o1 = 0; - w1 = 0; - h1 = 0; - for (level = 0; w2 > 1 && h2 > 1; ++level, w2 = w1, h2 = h1, o2 = o1) { - o1 = o2 + w2 * h2; - w1 = w2 / 2; - h1 = h2 / 2; - for (int y = 0; y < h1; ++y) { - int p1 = o1 + y * w1; - int p2 = o2 + y * 2 * w2; - for (int x = 0; x < w1; ++x) { - aint[p1 + x] = blend4Alpha( - aint[p2 + (x * 2)], - aint[p2 + (x * 2 + 1)], - aint[p2 + w2 + (x * 2)], - aint[p2 + w2 + (x * 2 + 1)]); - } - } - } - // fix black pixels from small to big - while (level > 0) { - --level; - w2 = width >> level; - h2 = height >> level; - o2 = o1 - w2 * h2; - int p2 = o2; - for (int y = 0; y < h2; ++y) { - for (int x = 0; x < w2; ++x) { - // p2 = o2 + y*w2 + x; - if (aint[p2] == 0) { - aint[p2] = aint[o1 + (y / 2) * w1 + (x / 2)] & 0x00ffffff; - } - ++p2; - } - } - o1 = o2; - w1 = w2; - h1 = h2; - } - } - - public static void genMipmapSimple(int[] aint, int offset, int width, int height) { - int level; - int w1, w2, h1, h2, o1, o2; - w1 = w2 = width; - h1 = h2 = height; - o1 = o2 = offset; - // generate mipmap from big to small - o2 = offset; - w2 = width; - h2 = height; - o1 = 0; - w1 = 0; - h1 = 0; - for (level = 0; w2 > 1 && h2 > 1; ++level, w2 = w1, h2 = h1, o2 = o1) { - o1 = o2 + w2 * h2; - w1 = w2 / 2; - h1 = h2 / 2; - for (int y = 0; y < h1; ++y) { - int p1 = o1 + y * w1; - int p2 = o2 + y * 2 * w2; - for (int x = 0; x < w1; ++x) { - aint[p1 + x] = blend4Simple( - aint[p2 + (x * 2)], - aint[p2 + (x * 2 + 1)], - aint[p2 + w2 + (x * 2)], - aint[p2 + w2 + (x * 2 + 1)]); - } - } - } - // fix black pixels from small to big - while (level > 0) { - --level; - w2 = width >> level; - h2 = height >> level; - o2 = o1 - w2 * h2; - int p2 = o2; - for (int y = 0; y < h2; ++y) { - for (int x = 0; x < w2; ++x) { - // p2 = o2 + y*w2 + x; - if (aint[p2] == 0) { - aint[p2] = aint[o1 + (y / 2) * w1 + (x / 2)] & 0x00ffffff; - } - ++p2; - } - } - o1 = o2; - w1 = w2; - h1 = h2; - } - } - - public static boolean isSemiTransparent(int[] aint, int width, int height) { - int size = width * height; - // grass side texture ?; - if (aint[0] >>> 24 == 255 && aint[size - 1] == 0) return true; - for (int i = 0; i < size; ++i) { - int alpha = aint[i] >>> 24; - if (alpha != 0 && alpha != 255) return true; - } - return false; - } - - public static void updateSubImage1(int[] src, int width, int height, int posX, int posY, int page, int color) { - int size = width * height; - IntBuffer intBuf = getIntBuffer(size); - int[] aint = getIntArray((size * 4 + 2) / 3); - if (src.length >= size * (page + 1)) { - System.arraycopy(src, size * page, aint, 0, size); - } else { - Arrays.fill(aint, color); - } - // - // if (page == 0) - genMipmapAlpha(aint, 0, width, height); - // else - // genMipmapSimple(aint,0,width,height); - // - for (int level = 0, offset = 0, lw = width, lh = height, px = posX, py = posY; lw > 0 && lh > 0; ++level) { - int lsize = lw * lh; - intBuf.clear(); - intBuf.put(aint, offset, lsize).position(0).limit(lsize); - GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, level, px, py, lw, lh, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); - offset += lsize; - lw /= 2; - lh /= 2; - px /= 2; - py /= 2; - } - intBuf.clear(); - } - - public static void updateSubTex1(int[] src, int width, int height, int posX, int posY) { - int level; - int cw; - int ch; - int cx; - int cy; - for (level = 0, cw = width, ch = height, cx = posX, cy = posY; cw > 0 - && ch > 0; ++level, cw /= 2, ch /= 2, cx /= 2, cy /= 2) { - GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, level, cx, cy, 0, 0, cw, ch); - } - } - - /* updateSubImage for single Texture with mipmap */ - public static void updateSubImage1(int[][] src, int width, int height, int posX, int posY, int page, int color) { - int size = width * height; - IntBuffer intBuf = getIntBuffer(size); - int numLevel = src.length; - for (int level = 0, // offset=0, - lw = width, lh = height, px = posX, py = posY; lw > 0 && lh > 0 && level < numLevel; ++level) { - int lsize = lw * lh; - intBuf.clear(); - intBuf.put(src[level], 0 /* offset */, lsize).position(0).limit(lsize); - GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, level, px, py, lw, lh, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); - // offset += lsize; - lw /= 2; - lh /= 2; - px /= 2; - py /= 2; - } - intBuf.clear(); - } - - public static void setupTextureMipmap(TextureMap tex) { - /* - * MultiTexID multiTex = tex.getMultiTexID(); GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - * GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); - * GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); - * GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D); - */ - } - - public static void updateDynamicTexture(int texID, int[] src, int width, int height, DynamicTexture tex) { - // TODO: PBR -// MultiTexID multiTex = tex.angelica$getMultiTexID(); -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); -// updateSubImage1(src, width, height, 0, 0, 1, defNormTexColor); -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); -// updateSubImage1(src, width, height, 0, 0, 2, defSpecTexColor); -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); -// updateSubImage1(src, width, height, 0, 0, 0, defBaseTexColor); - } - - public static void updateSubImage(int[] src, int width, int height, int posX, int posY, boolean linear, - boolean clamp) { - if (updatingTex != null) { - GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.norm); - updateSubImage1(src, width, height, posX, posY, 1, defNormTexColor); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.spec); - updateSubImage1(src, width, height, posX, posY, 2, defSpecTexColor); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.base); - } - updateSubImage1(src, width, height, posX, posY, 0, defBaseTexColor); - } - - // not used - public static void updateAnimationTextureMap(TextureMap tex, List tasList) { -// Iterator iterator; -// MultiTexID multiTex = tex.angelica$getMultiTexID(); -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); -// for (iterator = tasList.iterator(); iterator.hasNext();) { -// TextureAtlasSprite tas = iterator.next(); -// tas.updateAnimation(); -// } -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); -// for (iterator = tasList.iterator(); iterator.hasNext();) { -// TextureAtlasSprite tas = iterator.next(); -// tas.updateAnimation(); -// } -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); -// for (iterator = tasList.iterator(); iterator.hasNext();) { -// TextureAtlasSprite tas = iterator.next(); -// tas.updateAnimation(); -// } - } - - public static void setupTexture(MultiTexID multiTex, int[] src, int width, int height, boolean linear, - boolean clamp) { - int mmfilter = linear ? GL11.GL_LINEAR : GL11.GL_NEAREST; - int wraptype = clamp ? GL11.GL_CLAMP : GL11.GL_REPEAT; - int size = width * height; - IntBuffer intBuf = getIntBuffer(size); - // - intBuf.clear(); - intBuf.put(src, 0, size).position(0).limit(size); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); - GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mmfilter); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, mmfilter); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wraptype); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wraptype); - // - intBuf.put(src, size, size).position(0).limit(size); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mmfilter); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, mmfilter); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wraptype); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wraptype); - // - intBuf.put(src, size * 2, size).position(0).limit(size); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); - GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mmfilter); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, mmfilter); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wraptype); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wraptype); - // - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); - } - - /* currently not used */ - public static void updateSubImage(MultiTexID multiTex, int[] src, int width, int height, int posX, int posY, - boolean linear, boolean clamp) { - int size = width * height; - IntBuffer intBuf = getIntBuffer(size); - // - intBuf.clear(); - intBuf.put(src, 0, size); - intBuf.position(0).limit(size); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, posX, posY, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); - if (src.length == size * 3) { - intBuf.clear(); - intBuf.put(src, size, size).position(0); - intBuf.position(0).limit(size); - } - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, posX, posY, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); - if (src.length == size * 3) { - intBuf.clear(); - intBuf.put(src, size * 2, size); - intBuf.position(0).limit(size); - } - GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); - GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); - GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, posX, posY, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf); - GL13.glActiveTexture(GL13.GL_TEXTURE0); - } - - public static ResourceLocation getNSMapLocation(ResourceLocation location, String mapName) { - String basename = location.getResourcePath(); - String[] basenameParts = basename.split(".png"); - String basenameNoFileType = basenameParts[0]; - return new ResourceLocation(location.getResourceDomain(), basenameNoFileType + "_" + mapName + ".png"); - } - - public static void loadNSMap(IResourceManager manager, ResourceLocation location, int width, int height, - int[] aint) { - if (Shaders.configNormalMap) - ShadersTex.loadNSMap1(manager, getNSMapLocation(location, "n"), width, height, aint, width * height, defNormTexColor); - if (Shaders.configSpecularMap) - ShadersTex.loadNSMap1(manager, getNSMapLocation(location, "s"), width, height, aint, width * height * 2, defSpecTexColor); - } - - public static void loadNSMap1(IResourceManager manager, ResourceLocation location, int width, int height, int[] aint, int offset, int defaultColor) { - boolean good = false; - try { - IResource res = manager.getResource(location); - BufferedImage bufferedimage = ImageIO.read(res.getInputStream()); - if (bufferedimage.getWidth() == width && bufferedimage.getHeight() == height) { - bufferedimage.getRGB(0, 0, width, height, aint, offset, width); - good = true; - } - } catch (IOException ex) {} - if (!good) { - java.util.Arrays.fill(aint, offset, offset + width * height, defaultColor); - } - } - - /** init and upload from BufferedImage */ - /* - * Replacement for TextureUtil.func_110989_a call in SimpleTexture.func_110551_a. Keep par0...par5 the same as - * func_110989_a for easy patching. More parameters added for reading N-S-Map. - */ - public static int loadSimpleTexture(int textureID, BufferedImage bufferedimage, boolean linear, boolean clamp, - IResourceManager resourceManager, ResourceLocation location, MultiTexID multiTex) { - // TODO: PBR - int width = bufferedimage.getWidth(); - int height = bufferedimage.getHeight(); - int size = width * height; - int[] aint = getIntArray(size * 3); - bufferedimage.getRGB(0, 0, width, height, aint, 0, width); - loadNSMap(resourceManager, location, width, height, aint); - setupTexture(multiTex, aint, width, height, linear, clamp); - return textureID; - } - - public static void mergeImage(int[] aint, int dstoff, int srcoff, int size) {} - - public static int blendColor(int color1, int color2, int factor1) { - int factor2 = 255 - factor1; - return (((((color1 >>> 24) & 255) * factor1 + ((color2 >>> 24) & 255) * factor2) / 255) << 24) - | (((((color1 >>> 16) & 255) * factor1 + ((color2 >>> 16) & 255) * factor2) / 255) << 16) - | (((((color1 >>> 8) & 255) * factor1 + ((color2 >>> 8) & 255) * factor2) / 255) << 8) - | (((((color1 >>> 0) & 255) * factor1 + ((color2 >>> 0) & 255) * factor2) / 255) << 0); - } - - public static void loadLayeredTexture(LayeredTexture tex, IResourceManager manager, List list) { -// int width = 0; -// int height = 0; -// int size = 0; -// int[] image = null; -// Iterator iterator; -// for (iterator = list.iterator(); iterator.hasNext();) { -// String s = iterator.next(); -// if (s != null) { -// try { -// ResourceLocation location = new ResourceLocation(s); -// InputStream inputstream = manager.getResource(location).getInputStream(); -// BufferedImage bufimg = ImageIO.read(inputstream); -// -// if (size == 0) { -// width = bufimg.getWidth(); -// height = bufimg.getHeight(); -// size = width * height; -// image = createAIntImage(size, 0x00000000); -// } -// int[] aint = getIntArray(size * 3); -// bufimg.getRGB(0, 0, width, height, aint, 0, width); -// loadNSMap(manager, location, width, height, aint); -// // merge -// for (int i = 0; i < size; ++i) { -// int alpha = (aint[i] >>> 24) & 255; -// image[size * 0 + i] = blendColor(aint[size * 0 + i], image[size * 0 + i], alpha); -// image[size * 1 + i] = blendColor(aint[size * 1 + i], image[size * 1 + i], alpha); -// image[size * 2 + i] = blendColor(aint[size * 2 + i], image[size * 2 + i], alpha); -// } -// } catch (IOException ex) { -// ex.printStackTrace(); -// } -// } -// } -// // init and upload -// setupTexture(tex.angelica$getMultiTexID(), image, width, height, false, false); - } - - /* update block texture filter +/- items texture */ - public static void updateTextureMinMagFilter() { -// TextureManager texman = Minecraft.getMinecraft().getTextureManager(); -// ITextureObject texObj = texman.getTexture(TextureMap.locationBlocksTexture); -// if (texObj != null) { -// MultiTexID multiTex = texObj.angelica$getMultiTexID(); -// // base texture -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilB]); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilB]); -// // norm texture -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilN]); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilN]); -// -// // spec texture -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilS]); -// GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilS]); -// -// GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); -// } - } - - static IResourceManager resManager = null; - static ResourceLocation resLocation = null; - static int imageSize = 0; - - public static IResource loadResource(IResourceManager manager, ResourceLocation location) throws IOException { - resManager = manager; - resLocation = location; - return manager.getResource(location); - } - - public static int[] loadAtlasSprite(BufferedImage bufferedimage, int startX, int startY, int w, int h, int[] aint, - int offset, int scansize) { - imageSize = w * h; - bufferedimage.getRGB(startX, startY, w, h, aint, offset, scansize); - loadNSMap(resManager, resLocation, w, h, aint); - return aint; - } - - public static int[] extractFrame(int[] src, int width, int height, int frameIndex) { - int srcSize = imageSize; - int frameSize = width * height; - int[] dst = new int[frameSize * 3]; - int srcPos = frameSize * frameIndex; - int dstPos = 0; - System.arraycopy(src, srcPos, dst, dstPos, frameSize); - srcPos += srcSize; - dstPos += frameSize; - System.arraycopy(src, srcPos, dst, dstPos, frameSize); - srcPos += srcSize; - dstPos += frameSize; - System.arraycopy(src, srcPos, dst, dstPos, frameSize); - return dst; - } - - public static void fixTransparentColor(TextureAtlasSprite tas, int[] aint) {} -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java deleted file mode 100644 index f4a1f3961..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/gui/AngelicaVideoSettings.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.gtnewhorizons.angelica.client.gui; - -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.resources.I18n; - -public enum AngelicaVideoSettings { - SHADERS("options.button.shader"); - - private final String unlocalizedButton; - AngelicaVideoSettings(String unlocalizedButton) { - this.unlocalizedButton = unlocalizedButton; - } - public final String getButtonLabel() { - return I18n.format(unlocalizedButton); - } - - public final String getTitleLabel() { - return I18n.format("options.title." + name().toLowerCase()); - } - - public GuiButton createButton(int xPosition, int yPosition, Object setting) { - AngelicaVideoSettings angelicaVideoSettings = (AngelicaVideoSettings) setting; - return new GuiShadersButton(xPosition, yPosition, angelicaVideoSettings); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShaders.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShaders.java deleted file mode 100644 index fee4c55f2..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShaders.java +++ /dev/null @@ -1,321 +0,0 @@ -package com.gtnewhorizons.angelica.client.gui; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.util.List; - -import com.gtnewhorizons.angelica.client.Shaders; -import com.gtnewhorizons.angelica.client.ShadersTex; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.settings.GameSettings; - -import org.lwjgl.Sys; - -import com.gtnewhorizons.angelica.loading.AngelicaTweaker; - -public class GuiShaders extends GuiScreen { - - /** This GUI's parent GUI. */ - protected GuiScreen parentGui; - - private int updateTimer = -1; - public boolean needReinit; - - /* - private class GuiListShaderpacks { - int posX,posY,sizeX,sizeY; - int viewPosY; - int itemHeight = 20; - int selection; - ArrayList listShaderpacks; - public void draw() { - Tessellator tess = Tessellator.instance; - int listSize = listShaderpacks.size(); - int i,j; - for (i=viewPosY/itemHeight, j=Math.min((viewPosY+sizeY)/itemHeight,listSize); i buttonList = this.buttonList; - int width = this.width; - int height = this.height; - buttonList.add(new GuiButton(17, width * 3 / 4 - 60, 30, 160, 18, "NormalMap: " + toStringOnOff(Shaders.configNormalMap))); - buttonList.add(new GuiButton(18, width * 3 / 4 - 60, 50, 160, 18, "SpecularMap: " + toStringOnOff(Shaders.configSpecularMap))); - buttonList.add(new GuiButton(15, width * 3 / 4 - 60, 70, 160, 18, "RenderResMul: " + String.format("%.04f", Shaders.configRenderResMul))); - buttonList.add(new GuiButton(16, width * 3 / 4 - 60, 90, 160, 18, "ShadowResMul: " + String.format("%.04f", Shaders.configShadowResMul))); - buttonList.add(new GuiButton(10, width * 3 / 4 - 60, 110, 160, 18, "HandDepth: " + String.format("%.04f", Shaders.configHandDepthMul))); - buttonList.add(new GuiButton(9, width * 3 / 4 - 60, 130, 160, 18, "CloudShadow: " + toStringOnOff(Shaders.configCloudShadow))); - // buttonList.add(new GuiButton(14, width *3 /4 -60, 150, 160, 18, "ShadowClipFrustrum: " +toStringOnOff(Shaders.configShadowClipFrustrum))); - buttonList.add(new GuiButton(4, width * 3 / 4 - 60, 170, 160, 18, "tweakBlockDamage: " + toStringOnOff(Shaders.configTweakBlockDamage))); - buttonList.add(new GuiButton(19, width * 3 / 4 - 60, 190, 160, 18, "OldLighting: " + toStringOnOff(Shaders.configOldLighting))); - // buttonList.add(new GuiButton(11, width *3 /4 -60, 210, 160, 18, "Tex Min: " +Shaders.texMinFilDesc[Shaders.configTexMinFilB])); - // buttonList.add(new GuiButton(12, width *3 /4 -60, 230, 160, 18, "Tex_n Mag: " +Shaders.texMagFilDesc[Shaders.configTexMagFilN])); - // buttonList.add(new GuiButton(13, width *3 /4 -60, 250, 160, 18, "Tex_s Mag: " +Shaders.texMagFilDesc[Shaders.configTexMagFilS])); - buttonList.add(new GuiButton(6, width * 3 / 4 - 60, height - 25, 160, 20, "Done")); - buttonList.add(new GuiButton(5, width / 4 - 80, height - 25, 160, 20, "Open shaderpacks folder")); - this.shaderList = new GuiSlotShaders(this); - this.shaderList.registerScrollButtons(7, 8); // registerScrollButtons(7, 8); - this.needReinit = false; - } - - @Override - /** - * actionPerformed Fired when a control is clicked. This is the equivalent of - * ActionListener.actionPerformed(ActionEvent e). - */ - protected void actionPerformed(GuiButton guiButton) { - if (guiButton.enabled) // enabled - { - switch (guiButton.id) // id - { - case 4: /* New block breaking */ - Shaders.configTweakBlockDamage = !Shaders.configTweakBlockDamage; - // displayString - guiButton.displayString = "tweakBlockDamage: " + toStringOnOff(Shaders.configTweakBlockDamage); - break; - - case 9: /* Cloud shadow */ - Shaders.configCloudShadow = !Shaders.configCloudShadow; - guiButton.displayString = "CloudShadow: " + toStringOnOff(Shaders.configCloudShadow); - break; - - case 10: /* Hand Depth */ { - float val = Shaders.configHandDepthMul; - float[] choices = { 0.0625f, 0.125f, 0.25f, 0.5f, 1.0f }; - int i; - if (!isShiftKeyDown()) { // isShiftKeyDown - for (i = 0; i < choices.length && choices[i] <= val; ++i) {} - if (i == choices.length) i = 0; - } else { - for (i = choices.length - 1; i >= 0 && val <= choices[i]; --i) {} - if (i < 0) i = choices.length - 1; - } - Shaders.configHandDepthMul = choices[i]; - guiButton.displayString = "HandDepth: " + String.format("%.4f", Shaders.configHandDepthMul); - break; - } - - case 15: /* Render Resolution Multiplier */ { - float val = Shaders.configRenderResMul; - float[] choices = { 0.25f, 0.3333333333f, 0.5f, 0.7071067812f, 1.0f, 1.414213562f, 2.0f }; - int i; - if (!isShiftKeyDown()) { - for (i = 0; i < choices.length && choices[i] <= val; ++i) {} - if (i == choices.length) i = 0; - } else { - for (i = choices.length - 1; i >= 0 && val <= choices[i]; --i) {} - if (i < 0) i = choices.length - 1; - } - Shaders.configRenderResMul = choices[i]; - guiButton.displayString = "RenderResMul: " + String.format("%.4f", Shaders.configRenderResMul); - Shaders.scheduleResize(); - break; - } - - case 16: /* Shadow Resolution Multiplier */ { - float val = Shaders.configShadowResMul; - float[] choices = { 0.25f, 0.3333333333f, 0.5f, 0.7071067812f, 1.0f, 1.414213562f, 2.0f, 3.0f, - 4.0f }; - int i; - if (!isShiftKeyDown()) { - for (i = 0; i < choices.length && choices[i] <= val; ++i) {} - if (i == choices.length) i = 0; - } else { - for (i = choices.length - 1; i >= 0 && val <= choices[i]; --i) {} - if (i < 0) i = choices.length - 1; - } - Shaders.configShadowResMul = choices[i]; - guiButton.displayString = "ShadowResMul: " + String.format("%.4f", Shaders.configShadowResMul); - Shaders.scheduleResizeShadow(); - break; - } - - case 17: /* Normal Map */ { - Shaders.configNormalMap = !Shaders.configNormalMap; - // displayString - guiButton.displayString = "NormapMap: " + toStringOnOff(Shaders.configNormalMap); - mc.scheduleResourcesRefresh(); // schedule refresh texture - break; - } - - case 18: /* Normal Map */ { - Shaders.configSpecularMap = !Shaders.configSpecularMap; - // displayString - guiButton.displayString = "SpecularMap: " + toStringOnOff(Shaders.configSpecularMap); - mc.scheduleResourcesRefresh(); // schedule refresh texture - break; - } - - case 19: /* old Lighting */ { - Shaders.configOldLighting = !Shaders.configOldLighting; - // displayString - guiButton.displayString = "OldLighting: " + toStringOnOff(Shaders.configOldLighting); - Shaders.updateBlockLightLevel(); - mc.renderGlobal.loadRenderers(); - break; - } - - case 11: /* texture filter */ { - Shaders.configTexMinFilB = (Shaders.configTexMinFilB + 1) % Shaders.texMinFilRange; - Shaders.configTexMinFilN = Shaders.configTexMinFilS = Shaders.configTexMinFilB; - guiButton.displayString = "Tex Min: " + Shaders.texMinFilDesc[Shaders.configTexMinFilB]; - ShadersTex.updateTextureMinMagFilter(); - break; - } - - case 12: /* texture filter */ { - Shaders.configTexMagFilN = (Shaders.configTexMagFilN + 1) % Shaders.texMagFilRange; - guiButton.displayString = "Tex_n Mag: " + Shaders.texMagFilDesc[Shaders.configTexMagFilN]; - ShadersTex.updateTextureMinMagFilter(); - break; - } - - case 13: /* texture filter */ { - Shaders.configTexMagFilS = (Shaders.configTexMagFilS + 1) % Shaders.texMagFilRange; - guiButton.displayString = "Tex_s Mag: " + Shaders.texMagFilDesc[Shaders.configTexMagFilS]; - ShadersTex.updateTextureMinMagFilter(); - break; - } - - case 14: /* shadow frustum clipping */ { - Shaders.configShadowClipFrustrum = !Shaders.configShadowClipFrustrum; - guiButton.displayString = "ShadowClipFrustrum: " + toStringOnOff(Shaders.configShadowClipFrustrum); - ShadersTex.updateTextureMinMagFilter(); - break; - } - - case 5: /* Open shaderpacks folder */ - switch (net.minecraft.util.Util.getOSType()) { - case OSX: { - try { - Runtime.getRuntime().exec(new String[] { "/usr/bin/open", Shaders.shaderpacksdir.getAbsolutePath() }); - return; - } catch (IOException var7) { - var7.printStackTrace(); - } - } - break; - case WINDOWS: { - String var2 = String.format( - "cmd.exe /C start \"Open file\" \"%s\"", - new Object[] { Shaders.shaderpacksdir.getAbsolutePath() }); - - try { - Runtime.getRuntime().exec(var2); - return; - } catch (IOException var6) { - var6.printStackTrace(); - } - } - break; - default: - break; - } - boolean openViaSystemClass = false; - - try { - Class aClass = Class.forName("java.awt.Desktop"); - Object getDesktop = aClass.getMethod("getDesktop").invoke((Object) null); - aClass.getMethod("browse", URI.class).invoke(getDesktop, (new File(mc.mcDataDir, Shaders.shaderpacksdirname)).toURI()); - } catch (Throwable var5) { - var5.printStackTrace(); - openViaSystemClass = true; - } - - if (openViaSystemClass) { - AngelicaTweaker.LOGGER.debug("Opening via system class!"); - Sys.openURL("file://" + Shaders.shaderpacksdir.getAbsolutePath()); - } - break; - - case 6: /* Done */ - try { - Shaders.storeConfig(); - } catch (Exception ignored) {} - if (needReinit) { - needReinit = false; - Shaders.loadShaderPack(); - Shaders.uninit(); - this.mc.renderGlobal.loadRenderers(); - } - this.mc.displayGuiScreen(this.parentGui); // displayGuiScreen - break; - - default: - this.shaderList.actionPerformed(guiButton); // actionPerformed - } - } - } - - @Override - /** - * Draws the screen and all the components in it. - */ - public void drawScreen(int par1, int par2, float par3) { - drawDefaultBackground(); // background - this.shaderList.drawScreen(par1, par2, par3); // drawScreen - - if (this.updateTimer <= 0) { - this.shaderList.updateList(); - this.updateTimer += 20; - } - - this.drawCenteredString(this.fontRendererObj, "Shaders ", this.width / 2, 16, 0xffffff); - this.drawCenteredString(this.fontRendererObj, " v" + Shaders.versionString, this.width - 40, 10, 0x808080); - // this.drawCenteredString(this.fontRenderer, "( Place zipped Shader files here. )", this.width / 4 + 10, this.height - 26, 0x808080); - super.drawScreen(par1, par2, par3); - } - - @Override - /* - * Called from the main game loop to update the screen. - */ - public void updateScreen() { - super.updateScreen(); - --this.updateTimer; - } - - public Minecraft getMc() { - return this.mc; - } - - public void drawCenteredString(String par1, int par2, int par3, int par4) { - this.drawCenteredString(this.fontRendererObj, par1, par2, par3, par4); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShadersButton.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShadersButton.java deleted file mode 100644 index c18faaaeb..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiShadersButton.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.gtnewhorizons.angelica.client.gui; - - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiButton; - -public class GuiShadersButton extends GuiButton { - - public GuiShadersButton(int xPosition, int yPosition, AngelicaVideoSettings setting) { - super(setting.ordinal(), xPosition, yPosition, 150, 20, setting.getButtonLabel()); - } - - @Override - public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) { - if(super.mousePressed(mc, mouseX, mouseY)) { - mc.gameSettings.saveOptions(); - mc.displayGuiScreen(new GuiShaders(mc.currentScreen, null)); - return true; - } else { - return false; - } - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiSlotShaders.java b/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiSlotShaders.java deleted file mode 100644 index b00a89984..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/client/gui/GuiSlotShaders.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.gtnewhorizons.angelica.client.gui; - -import java.util.List; - -import com.gtnewhorizons.angelica.client.Shaders; -import net.minecraft.client.gui.GuiSlot; -import net.minecraft.client.renderer.Tessellator; - -public class GuiSlotShaders extends GuiSlot { - - private List shaderslist; - - final GuiShaders shadersGui; - - public GuiSlotShaders(GuiShaders par1GuiShaders) { - // super(par1GuiShaders.getMc(), par1GuiShaders.width / 2 + 20, par1GuiShaders.height, 40, par1GuiShaders.height - // - 70, 16); - super(par1GuiShaders.getMc(), par1GuiShaders.width / 2 + 20, par1GuiShaders.height, 40, par1GuiShaders.height - 70, 16); - this.shadersGui = par1GuiShaders; - this.shaderslist = Shaders.listofShaders(); - } - - public void updateList() { - this.shaderslist = Shaders.listofShaders(); - } - - @Override - /** getSize */ - protected int getSize() { - return this.shaderslist.size(); - } - - @Override - /** elementClicked */ - protected void elementClicked(int par1, boolean par2, int par3, int par4) { - Shaders.setShaderPack((String) shaderslist.get(par1)); - shadersGui.needReinit = false; - Shaders.loadShaderPack(); - Shaders.uninit(); - } - - @Override - /** isSelected */ - protected boolean isSelected(int par1) { - return ((String) this.shaderslist.get(par1)).equals(Shaders.currentshadername); - } - - @Override - /** getScrollBarX */ - protected int getScrollBarX() { - return this.width - 6; - } - - @Override - /** getContentHeight */ - protected int getContentHeight() { - return this.getSize() * 18; - } - - @Override - /** drawBackground */ - protected void drawBackground() { - // this.shadersGui.drawDefaultBackground(); - } - - @Override - /** drawEntry */ - protected void drawSlot(int index, int par2, int par3, int par4, Tessellator par5, int mouseX, int mouseY) { - this.shadersGui.drawCenteredString((String) this.shaderslist.get(index), this.shadersGui.width / 4 + 10, par3 + 1, 0xffffff); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureAtlasSprite.java index ce6ca4a2f..d1d819200 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureAtlasSprite.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureAtlasSprite.java @@ -1,6 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.angelica.textures; -import com.gtnewhorizons.angelica.client.textures.ISpriteExt; +import com.gtnewhorizons.angelica.mixins.interfaces.ISpriteExt; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.data.AnimationMetadataSection; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinBlock.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinBlock.java deleted file mode 100644 index c47dda264..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinBlock.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.lighting; - -import net.minecraft.block.Block; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; - -import com.gtnewhorizons.angelica.client.Shaders; - -@Mixin(Block.class) -public class MixinBlock { - - @ModifyConstant(method = "getAmbientOcclusionLightValue()F", constant = @Constant(floatValue = 0.2f)) - public float angelica$blockAoLight(float constant) { - return Shaders.blockAoLight; - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinRenderBlocks.java deleted file mode 100644 index 0077e2def..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/lighting/MixinRenderBlocks.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.lighting; - -import net.minecraft.client.renderer.RenderBlocks; - -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.ModifyConstant; -import org.spongepowered.asm.mixin.injection.Slice; - -import com.gtnewhorizons.angelica.client.Shaders; - -@Mixin(RenderBlocks.class) -public class MixinRenderBlocks { - - // All of these expect 1 replacement only - @ModifyConstant( - method = { "renderBlockBed(Lnet/minecraft/block/Block;III)Z", - "renderBlockDoor(Lnet/minecraft/block/Block;III)Z", - "renderBlockLiquid(Lnet/minecraft/block/Block;III)Z", - "renderBlockCactusImpl(Lnet/minecraft/block/Block;IIIFFF)Z", - "renderStandardBlockWithColorMultiplier(Lnet/minecraft/block/Block;IIIFFF)Z", - "renderBlockSandFalling(Lnet/minecraft/block/Block;Lnet/minecraft/world/World;IIII)V" }, - constant = @Constant(floatValue = 0.5F), - expect = 1) - public float angelica$blockSingleLightLevel05(float constant) { - return Shaders.blockLightLevel05; - } - - @ModifyConstant( - method = { "renderBlockBed(Lnet/minecraft/block/Block;III)Z", - "renderBlockLiquid(Lnet/minecraft/block/Block;III)Z", - "renderBlockDoor(Lnet/minecraft/block/Block;III)Z", - "renderBlockCactusImpl(Lnet/minecraft/block/Block;IIIFFF)Z", - "renderStandardBlockWithColorMultiplier(Lnet/minecraft/block/Block;IIIFFF)Z", - "renderBlockSandFalling(Lnet/minecraft/block/Block;Lnet/minecraft/world/World;IIII)V" }, - constant = @Constant(floatValue = 0.6F), - expect = 1) - public float angelica$blockSingleLightLevel06(float constant) { - return Shaders.blockLightLevel06; - } - - @ModifyConstant( - method = { "renderBlockBed(Lnet/minecraft/block/Block;III)Z", - "renderBlockLiquid(Lnet/minecraft/block/Block;III)Z", - "renderBlockDoor(Lnet/minecraft/block/Block;III)Z", - "renderBlockCactusImpl(Lnet/minecraft/block/Block;IIIFFF)Z", - "renderStandardBlockWithColorMultiplier(Lnet/minecraft/block/Block;IIIFFF)Z", - "renderBlockSandFalling(Lnet/minecraft/block/Block;Lnet/minecraft/world/World;IIII)V" }, - constant = @Constant(floatValue = 0.8F), - expect = 1) - public float angelica$blockSingleLightLevel08(float constant) { - return Shaders.blockLightLevel08; - } - - // Piston Extension - Differing expectations, and slicing required - - @ModifyConstant( - method = "renderPistonExtension(Lnet/minecraft/block/Block;IIIZ)Z", - constant = @Constant(floatValue = 0.5F), - expect = 3, - slice = @Slice(from = @At(value = "CONSTANT", args = "doubleValue=8.0D", ordinal = 0))) - public float angelica$pistonBlockLightLevel05(float constant) { - return Shaders.blockLightLevel05; - } - - @ModifyConstant( - method = "renderPistonExtension(Lnet/minecraft/block/Block;IIIZ)Z", - constant = @Constant(floatValue = 0.6F), - expect = 12) - public float angelica$pistonBlockLightLevel06(float constant) { - return Shaders.blockLightLevel06; - } - - @ModifyConstant( - method = "renderPistonExtension(Lnet/minecraft/block/Block;IIIZ)Z", - constant = @Constant(floatValue = 0.8F), - expect = 4) - public float angelica$pistonBlockLightLevel08(float constant) { - return Shaders.blockLightLevel08; - } - - // BlockWithAmbientOcclusion - - @ModifyConstant( - method = { "renderStandardBlockWithAmbientOcclusionPartial(Lnet/minecraft/block/Block;IIIFFF)Z", - "renderStandardBlockWithAmbientOcclusion(Lnet/minecraft/block/Block;IIIFFF)Z" }, - constant = @Constant(floatValue = 0.5F)) - public float angelica$multipleBlockLightLevel05(float constant) { - return Shaders.blockLightLevel05; - } - - @ModifyConstant( - method = { "renderStandardBlockWithAmbientOcclusionPartial(Lnet/minecraft/block/Block;IIIFFF)Z", - "renderStandardBlockWithAmbientOcclusion(Lnet/minecraft/block/Block;IIIFFF)Z" }, - constant = @Constant(floatValue = 0.6F)) - public float angelica$multipleBlockLightLevel06(float constant) { - return Shaders.blockLightLevel06; - } - - @ModifyConstant( - method = { "renderStandardBlockWithAmbientOcclusionPartial(Lnet/minecraft/block/Block;IIIFFF)Z", - "renderStandardBlockWithAmbientOcclusion(Lnet/minecraft/block/Block;IIIFFF)Z" }, - constant = @Constant(floatValue = 0.8F)) - public float angelica$multipleBlockLightLevel08(float constant) { - return Shaders.blockLightLevel08; - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinAbstractTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinAbstractTexture.java deleted file mode 100644 index 50c275853..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinAbstractTexture.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.texture.AbstractTexture; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.SoftOverride; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.gtnewhorizons.angelica.client.MultiTexID; -import com.gtnewhorizons.angelica.client.ShadersTex; - -@Mixin(AbstractTexture.class) -public class MixinAbstractTexture { - - public MultiTexID angelica$multiTex; - - @Inject(at = @At("HEAD"), method = "deleteGlTexture()V") - private void angelica$deleteTextures(CallbackInfo ci) { - ShadersTex.deleteTextures((AbstractTexture) (Object) this); - } - - @SoftOverride - public MultiTexID angelica$getMultiTexID() { - return ShadersTex.getMultiTexID((AbstractTexture) (Object) this); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinDynamicTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinDynamicTexture.java deleted file mode 100644 index fc0398e68..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinDynamicTexture.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.texture.DynamicTexture; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; -import org.spongepowered.asm.mixin.injection.Redirect; - -import com.gtnewhorizons.angelica.client.ShadersTex; - -@Mixin(DynamicTexture.class) -public class MixinDynamicTexture { - // TODO: PBR - @ModifyVariable(argsOnly = true, at = @At(ordinal = 1, value = "LOAD"), index = 1, method = "(II)V") - private int angelica$resizeDynamicTextureData(int p_i1271_2_) { - return p_i1271_2_ * 3; - } - - @Redirect( - at = @At( - target = "Lnet/minecraft/client/renderer/texture/TextureUtil;allocateTexture(III)V", - value = "INVOKE"), - method = "(II)V") - private void angelica$initDynamicTexture(int p_110991_0_, int p_110991_1_, int p_110991_2_) { - // p_110991_1_ needs to be divided by 3 to revert angelica$resizeDynamicTextureData - ShadersTex.initDynamicTexture(p_110991_0_, p_110991_1_ / 3, p_110991_2_, (DynamicTexture) (Object) this); - } - - @Redirect( - at = @At( - target = "Lnet/minecraft/client/renderer/texture/TextureUtil;uploadTexture(I[III)V", - value = "INVOKE"), - method = "updateDynamicTexture()V") - private void angelica$updateDynamicTexture(int p_110988_0_, int[] p_110988_1_, int p_110988_2_, int p_110988_3_) { - ShadersTex.updateDynamicTexture(p_110988_0_, p_110988_1_, p_110988_2_, p_110988_3_, (DynamicTexture) (Object) this); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinEntityRenderer.java deleted file mode 100644 index bcbe29bf9..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinEntityRenderer.java +++ /dev/null @@ -1,275 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import com.gtnewhorizons.angelica.client.Shaders; -import com.gtnewhorizons.angelica.client.ShadersRender; -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import net.minecraft.client.Minecraft; -import net.minecraft.client.particle.EffectRenderer; -import net.minecraft.client.renderer.EntityRenderer; -import net.minecraft.client.renderer.ItemRenderer; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.culling.Frustrum; -import net.minecraft.client.renderer.culling.ICamera; -import net.minecraft.client.settings.GameSettings; -import net.minecraft.entity.EntityLivingBase; -import org.lwjgl.opengl.GL11; -import org.spongepowered.asm.lib.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -@Mixin(EntityRenderer.class) -public abstract class MixinEntityRenderer { - // TODO: Rendering - @Shadow - private Minecraft mc; - - @Shadow - public abstract void disableLightmap(double p_78483_1_); - - // renderHand - - @Inject(method = "renderHand(FI)V", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) - private void angelica$applyHandDepth(CallbackInfo ci) { - Shaders.applyHandDepth(); - } - - @Inject(method = "renderHand(FI)V", - at = @At(value = "FIELD", target = "Lnet/minecraft/client/settings/GameSettings;thirdPersonView:I", ordinal = 1), - cancellable = true) - private void angelica$checkCompositeRendered(float p_78476_1_, int p_78476_2_, CallbackInfo ci) { - if (!Shaders.isCompositeRendered) { - ci.cancel(); - } - this.disableLightmap(p_78476_1_); - } - - @Redirect(method = "renderHand(FI)V", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemRenderer;renderItemInFirstPerson(F)V")) - private void angelica$renderItemInFirstPerson(ItemRenderer itemRenderer, float partialTicks) { - ShadersRender.renderItemFP(itemRenderer, partialTicks); - } - - // disableLightmap - - @Inject(at = @At("RETURN"), method = "disableLightmap(D)V") - private void angelica$disableLightmap(CallbackInfo ci) { - Shaders.disableLightmap(); - } - - // enableLightmap - - @Inject(at = @At("RETURN"), method = "enableLightmap(D)V") - private void angelica$enableLightmap(CallbackInfo ci) { - Shaders.enableLightmap(); - } - - // renderWorld - - @Inject(at = @At("HEAD"), method = "renderWorld(FJ)V") - private void angelica$beginRender(float renderPartialTicks, long tickDelta, CallbackInfo ci) { - Shaders.beginRender(this.mc, renderPartialTicks, tickDelta); - } - - @Redirect(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glViewport(IIII)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$setViewport(int x, int y, int width, int height) { - Shaders.setViewport(x, y, width, height); - } - - @Inject(at = @At(remap = false, shift = At.Shift.AFTER, target = "Lorg/lwjgl/opengl/GL11;glClear(I)V", value = "INVOKE"), - method = "renderWorld(FJ)V", - slice = @Slice( - from = @At(args = "intValue=" + (GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT), value = "CONSTANT"), - to = @At(args = "intValue=" + GL11.GL_CULL_FACE, ordinal = 1, value = "CONSTANT"))) - private void angelica$clearRenderBuffer(CallbackInfo ci) { - Shaders.clearRenderBuffer(); - } - - @Redirect(at = @At(opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/settings/GameSettings;renderDistanceChunks:I", value = "FIELD"), - method = "renderWorld(FJ)V") - private int angelica$isShadowPass(GameSettings gameSettings) { - // A better way would be replacing the if-expression completely but I don't know how. If you figure it how, - // please let me (glowredman) know. Unless that happens, we just redirect the field access and return either 3 - // or 4 to achieve the same. - return Shaders.isShadowPass ? 3 : 4; - } - - @Inject(at = @At(target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(F)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$beginSky(CallbackInfo ci) { - Shaders.beginSky(); - } - - @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(F)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$endSky(CallbackInfo ci) { - Shaders.endSky(); - } - - @Redirect(at = @At(target = "Lnet/minecraft/client/renderer/culling/Frustrum;setPosition(DDD)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$setFrustrumPosition(Frustrum frustrum, double x, double y, double z) { - ShadersRender.setFrustrumPosition(frustrum, x, y, z); - } - - @Redirect(at = @At(target = "Lnet/minecraft/client/renderer/RenderGlobal;clipRenderersByFrustum(Lnet/minecraft/client/renderer/culling/ICamera;F)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$clipRenderersByFrustrum(RenderGlobal renderGlobal, ICamera p_72729_1_, float p_72729_2_) { - ShadersRender.clipRenderersByFrustrum(renderGlobal, (Frustrum) p_72729_1_, p_72729_2_); - } - - @Inject(at = @At(ordinal = 7, target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$beginUpdateChunks(CallbackInfo ci) { - Shaders.beginUpdateChunks(); - } - - @Inject(at = @At(opcode = Opcodes.GETFIELD, ordinal = 1, target = "Lnet/minecraft/entity/EntityLivingBase;posY:D", value = "FIELD"), - locals = LocalCapture.CAPTURE_FAILEXCEPTION, - method = "renderWorld(FJ)V") - private void angelica$endUpdateChunks(float p_78471_1_, long p_78471_2_, CallbackInfo ci, - EntityLivingBase entitylivingbase, RenderGlobal renderglobal, EffectRenderer effectrenderer, double d0, - double d1, double d2, int j) { - // A better solution would be to inject this directly at the end of the "if (j == 0)" block so checking j == 0 - // again here isn't necessary. If you figure out how to do that, please let me (glowredman) know. - if (j == 0) { - Shaders.endUpdateChunks(); - } - } - - @Inject(at = @At(ordinal = 0, target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$beginTerrain(CallbackInfo ci) { - Shaders.beginTerrain(); - } - - @Inject(at = @At(ordinal = 0, shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$endTerrain(CallbackInfo ci) { - Shaders.endTerrain(); - } - - @Inject(at = @At(target = "Lnet/minecraft/client/particle/EffectRenderer;renderLitParticles(Lnet/minecraft/entity/Entity;F)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$beginLitParticles(CallbackInfo ci) { - Shaders.beginLitParticles(); - } - - @Inject(at = @At(target = "Lnet/minecraft/client/particle/EffectRenderer;renderParticles(Lnet/minecraft/entity/Entity;F)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$beginParticles(CallbackInfo ci) { - Shaders.beginParticles(); - } - - @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/particle/EffectRenderer;renderParticles(Lnet/minecraft/entity/Entity;F)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$endParticles(CallbackInfo ci) { - Shaders.endParticles(); - } - - @Inject(at = @At(target = "Lnet/minecraft/client/renderer/EntityRenderer;renderRainSnow(F)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$beginWeather(CallbackInfo ci) { - Shaders.beginWeather(); - } - - @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/EntityRenderer;renderRainSnow(F)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$endWeather(CallbackInfo ci) { - Shaders.endWeather(); - } - - @Inject(at = @At(ordinal = 1, remap = false, shift = At.Shift.AFTER, target = "Lorg/lwjgl/opengl/GL11;glDepthMask(Z)V", value = "INVOKE"), - locals = LocalCapture.CAPTURE_FAILEXCEPTION, - method = "renderWorld(FJ)V") - private void angelica$renderHand0AndPreWater(float p_78471_1_, long p_78471_2_, CallbackInfo ci, - EntityLivingBase entitylivingbase, RenderGlobal renderglobal, EffectRenderer effectrenderer, double d0, - double d1, double d2, int j) { - ShadersRender.renderHand0((EntityRenderer) (Object) this, p_78471_1_, j); - Shaders.preWater(); - } - - @Inject(at = @At(target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", value = "INVOKE"), - method = "renderWorld(FJ)V", - slice = @Slice(from = @At(args = "stringValue=water", ordinal = 0, value = "CONSTANT"))) - private void angelica$beginWater(CallbackInfo ci) { - Shaders.beginWater(); - } - - @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/RenderGlobal;sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", value = "INVOKE"), - method = "renderWorld(FJ)V", - slice = @Slice(from = @At(args = "stringValue=water", ordinal = 0, value = "CONSTANT"))) - private void angelica$endWater(CallbackInfo ci) { - Shaders.endWater(); - } - - @Inject(at = @At(opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/entity/EntityLivingBase;posY:D", value = "FIELD"), - method = "renderWorld(FJ)V", - slice = @Slice( - from = @At(args = "stringValue=entities", value = "CONSTANT"), - to = @At(args = "stringValue=aboveClouds", value = "CONSTANT"))) - private void angelica$disableFog(CallbackInfo ci) { - Shaders.disableFog(); - } - - @ModifyExpressionValue( - at = @At(remap = false, target = "Lnet/minecraftforge/client/ForgeHooksClient;renderFirstPersonHand(Lnet/minecraft/client/renderer/RenderGlobal;FI)Z", value = "INVOKE"), - method = "renderWorld(FJ)V") - private boolean angelica$isShadowPass(boolean renderFirstPersonHand) { - return renderFirstPersonHand || Shaders.isShadowPass; - } - - @Inject(at = @At(remap = false, target = "Lorg/lwjgl/opengl/GL11;glClear(I)V", value = "INVOKE"), - locals = LocalCapture.CAPTURE_FAILEXCEPTION, - method = "renderWorld(FJ)V", - slice = @Slice(from = @At(args = "stringValue=hand", value = "CONSTANT"))) - private void angelica$renderHand1AndRenderCompositeFinal(float p_78471_1_, long p_78471_2_, CallbackInfo ci, - EntityLivingBase entitylivingbase, RenderGlobal renderglobal, EffectRenderer effectrenderer, double d0, - double d1, double d2, int j) { - ShadersRender.renderHand1((EntityRenderer) (Object) this, p_78471_1_, j); - Shaders.renderCompositeFinal(); - } - - @Redirect(at = @At(target = "Lnet/minecraft/client/renderer/EntityRenderer;renderHand(FI)V", value = "INVOKE"), - method = "renderWorld(FJ)V") - private void angelica$renderFPOverlay(EntityRenderer thizz, float p_78476_1_, int p_78476_2_) { - ShadersRender.renderFPOverlay(thizz, p_78476_1_, p_78476_2_); - } - - @Inject(at = @At(opcode = Opcodes.GETFIELD, ordinal = 0, target = "Lnet/minecraft/client/renderer/EntityRenderer;mc:Lnet/minecraft/client/Minecraft;", value = "FIELD"), - method = "renderWorld(FJ)V", - slice = @Slice(from = @At(args = "stringValue=hand", value = "CONSTANT"))) - private void angelica$endRender(CallbackInfo ci) { - Shaders.endRender(); - } - - // renderCloudsCheck - - @Redirect(at = @At(target = "Lnet/minecraft/client/settings/GameSettings;shouldRenderClouds()Z", value = "INVOKE"), - method = "renderCloudsCheck(Lnet/minecraft/client/renderer/RenderGlobal;F)V") - private boolean angelica$shouldRenderClouds(GameSettings gameSettings) { - return Shaders.shouldRenderClouds(gameSettings); - } - - @Inject(at = @At(target = "Lnet/minecraft/client/renderer/RenderGlobal;renderClouds(F)V", value = "INVOKE"), - method = "renderCloudsCheck(Lnet/minecraft/client/renderer/RenderGlobal;F)V") - private void angelica$beginClouds(CallbackInfo ci) { - Shaders.beginClouds(); - } - - @Inject(at = @At(shift = At.Shift.AFTER, target = "Lnet/minecraft/client/renderer/RenderGlobal;renderClouds(F)V", value = "INVOKE"), - method = "renderCloudsCheck(Lnet/minecraft/client/renderer/RenderGlobal;F)V") - private void angelica$endClouds(CallbackInfo ci) { - Shaders.endClouds(); - } - - - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinITextureObject.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinITextureObject.java deleted file mode 100644 index 0a3b34a4d..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinITextureObject.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.texture.ITextureObject; - -import org.spongepowered.asm.mixin.Mixin; - -import com.gtnewhorizons.angelica.client.MultiTexID; - -@Mixin(ITextureObject.class) -public interface MixinITextureObject { - - MultiTexID angelica$getMultiTexID(); - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinItemRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinItemRenderer.java deleted file mode 100644 index 45db1edfb..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinItemRenderer.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.entity.EntityClientPlayerMP; -import net.minecraft.client.renderer.ItemRenderer; -import net.minecraft.item.ItemStack; - -import org.spongepowered.asm.lib.Opcodes; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import com.gtnewhorizons.angelica.client.Shaders; - -@Mixin(ItemRenderer.class) -public class MixinItemRenderer { - // TODO: Rendering - items - @Inject( - at = @At( - opcode = Opcodes.PUTFIELD, - target = "Lnet/minecraft/client/renderer/ItemRenderer;itemToRender:Lnet/minecraft/item/ItemStack;", - value = "FIELD"), - locals = LocalCapture.CAPTURE_FAILEXCEPTION, - method = "updateEquippedItem()V") - private void angelica$setItemToRender(CallbackInfo ci, EntityClientPlayerMP entityclientplayermp, - ItemStack itemstack) { - Shaders.itemToRender = itemstack; - } - - @ModifyArg( - at = @At( - ordinal = 0, - remap = true, - target = "Lnet/minecraft/client/renderer/OpenGlHelper;glBlendFunc(IIII)V", - value = "INVOKE"), - index = 3, - method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V", - remap = false) - private int angelica$adjust_dfactorAlpha(int original) { - return 1; - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java deleted file mode 100644 index 3bb04399f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinLayeredTexture.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import com.gtnewhorizons.angelica.client.ShadersTex; -import net.minecraft.client.renderer.texture.LayeredTexture; -import net.minecraft.client.resources.IResourceManager; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.io.IOException; -import java.util.List; - -@Mixin(LayeredTexture.class) -public class MixinLayeredTexture { - // TODO: PBR - @Final - @Shadow - public List layeredTextureNames; - - /** - * @author glowredman - * @reason must take normal and specular maps into account - */ - @Overwrite - public void loadTexture(IResourceManager p_110551_1_) throws IOException { - ShadersTex.loadLayeredTexture((LayeredTexture) (Object) this, p_110551_1_, this.layeredTextureNames); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinModelRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinModelRenderer.java deleted file mode 100644 index 543b68d71..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinModelRenderer.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.model.ModelRenderer; -import net.minecraft.client.renderer.GLAllocation; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import com.gtnewhorizons.angelica.mixins.interfaces.IModelRenderer; - -@Mixin(ModelRenderer.class) -public class MixinModelRenderer implements IModelRenderer { - // TODO: Rendering - @Shadow - private boolean compiled; - - @Shadow - private int displayList; - - public void angelica$resetDisplayList() { - if (!compiled && displayList != 0) { - GLAllocation.deleteDisplayLists(displayList); - displayList = 0; - compiled = false; - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinOpenGlHelper.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinOpenGlHelper.java deleted file mode 100644 index c2fe30cab..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinOpenGlHelper.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.OpenGlHelper; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.gtnewhorizons.angelica.client.Shaders; - -@Mixin(OpenGlHelper.class) -public class MixinOpenGlHelper { - - @Inject(method = "setActiveTexture(I)V", at = @At("HEAD")) - private static void angelica$setActiveTexUnit(int activeTexture, CallbackInfo ci) { - Shaders.activeTexUnit = activeTexture; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRender.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRender.java deleted file mode 100644 index eb073ddfb..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRender.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.entity.Render; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.gtnewhorizons.angelica.client.Shaders; - -@Mixin(Render.class) -public class MixinRender { - // TODO: Rendering - @Inject(method = "renderShadow(Lnet/minecraft/entity/Entity;DDDFF)V", at = @At("HEAD"), cancellable = true) - private void angelica$checkShouldSkipDefaultShadow(CallbackInfo ci) { - if (Shaders.shouldSkipDefaultShadow) ci.cancel(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderBlocks.java deleted file mode 100644 index 160e6e7fd..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderBlocks.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockFlowerPot; -import net.minecraft.client.renderer.RenderBlocks; -import net.minecraft.item.Item; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.gtnewhorizons.angelica.client.Shaders; - -@Mixin(RenderBlocks.class) -public class MixinRenderBlocks { - - // Block - @Inject(method = "renderBlockByRenderType(Lnet/minecraft/block/Block;III)Z", at = @At("HEAD")) - private void angelica$pushEntityBlock(Block block, int x, int y, int z, CallbackInfoReturnable cir) { - Shaders.pushEntity((RenderBlocks) ((Object) this), block, x, y, z); - } - - @Inject(method = "renderBlockByRenderType(Lnet/minecraft/block/Block;III)Z", at = @At("RETURN")) - private void angelica$popEntityBlock(Block block, int x, int y, int z, CallbackInfoReturnable cir) { - Shaders.popEntity(); - } - - // BlockFlowerPot - @Inject(method = "renderBlockFlowerpot(Lnet/minecraft/block/BlockFlowerPot;III)Z", at = @At("HEAD")) - private void angelica$pushEntityBlockFlowerPot(BlockFlowerPot blockFlowerPot, int x, int y, int z, CallbackInfoReturnable cir) { - Shaders.pushEntity((RenderBlocks) ((Object) this), blockFlowerPot, x, y, z); - } - - @Inject(method = "renderBlockFlowerpot(Lnet/minecraft/block/BlockFlowerPot;III)Z", at = @At("RETURN")) - private void angelica$popEntityBlockFlowerPot(BlockFlowerPot blockFlowerPot, int x, int y, int z, CallbackInfoReturnable cir) { - Shaders.popEntity(); - } - - @WrapOperation( - method = "renderBlockFlowerpot(Lnet/minecraft/block/BlockFlowerPot;III)Z", - at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;getBlockFromItem(Lnet/minecraft/item/Item;)Lnet/minecraft/block/Block;")) - private Block angelica$pushEntityFlowerInFlowerPot(Item itemIn, Operation original) { - final Block block = original.call(itemIn); - Shaders.pushEntity(block); - return block; - } - - @Inject( - method = "renderBlockFlowerpot(Lnet/minecraft/block/BlockFlowerPot;III)Z", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/Tessellator;addTranslation(FFF)V", - shift = At.Shift.AFTER, - ordinal = 1)) - private void angelica$popEntityFlowerInFlowerPot(BlockFlowerPot blockFlowerPot, int x, int y, int z, CallbackInfoReturnable cir) { - Shaders.popEntity(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderDragon.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderDragon.java deleted file mode 100644 index 5ce485649..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderDragon.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.entity.RenderDragon; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import com.gtnewhorizons.angelica.client.Shaders; - -@Mixin(RenderDragon.class) -public class MixinRenderDragon { - // TODO: Rendering - @Inject( - at = @At( - remap = false, - shift = At.Shift.AFTER, - target = "Lorg/lwjgl/opengl/GL11;glColor4f(FFFF)V", - value = "INVOKE"), - method = "shouldRenderPass(Lnet/minecraft/entity/boss/EntityDragon;IF)I") - private void angelica$beginSpiderEyes(CallbackInfoReturnable cir) { - Shaders.beginGlowingEyes(); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderEnderman.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderEnderman.java deleted file mode 100644 index 8e1bcb564..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderEnderman.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.entity.RenderEnderman; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import com.gtnewhorizons.angelica.client.Shaders; - -@Mixin(RenderEnderman.class) -public class MixinRenderEnderman { - // TODO: Rendering - @Inject( - at = @At( - remap = false, - shift = At.Shift.AFTER, - target = "Lorg/lwjgl/opengl/GL11;glColor4f(FFFF)V", - value = "INVOKE"), - method = "shouldRenderPass(Lnet/minecraft/entity/monster/EntityEnderman;IF)I") - private void angelica$beginSpiderEyes(CallbackInfoReturnable cir) { - Shaders.beginGlowingEyes(); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderGlobal.java deleted file mode 100644 index e8d80267f..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderGlobal.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import com.gtnewhorizons.angelica.client.Shaders; -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.culling.ICamera; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.MovingObjectPosition; -import org.lwjgl.opengl.GL11; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(RenderGlobal.class) -public class MixinRenderGlobal { - // TODO: Rendering - @Inject( - method = "renderEntities(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/client/renderer/culling/ICamera;F)V", - at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", args = "ldc=entities")) - private void angelica$beginEntities(EntityLivingBase entity, ICamera camera, float p_147589_3_, CallbackInfo ci) { - Shaders.beginEntities(); - } - - @Inject( - method = "renderEntities(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/client/renderer/culling/ICamera;F)V", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)Z", ordinal = 1, shift = At.Shift.AFTER)) - private void angelica$nextEntity(EntityLivingBase entity, ICamera camera, float p_147589_3_, CallbackInfo ci) { - Shaders.nextEntity(); - } - - @Inject( - method = "renderEntities(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/client/renderer/culling/ICamera;F)V", - at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", args = "ldc=blockentities", shift = At.Shift.AFTER)) - private void angelica$endEntitiesAndBeginBlockEntities(EntityLivingBase entity, ICamera camera, float p_147589_3_, - CallbackInfo ci) { - Shaders.endEntities(); - Shaders.beginBlockEntities(); - } - - @Inject( - method = "renderEntities(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/client/renderer/culling/ICamera;F)V", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/EntityRenderer;disableLightmap(D)V", shift = At.Shift.AFTER)) - private void angelica$endBlockEntities(EntityLivingBase entity, ICamera camera, float p_147589_3_, - CallbackInfo ci) { - Shaders.endBlockEntities(); - } - - // Texture 2D - @Inject( - method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false, ordinal = 0, shift = At.Shift.AFTER), expect = 0) - private void angelica$sortandRenderDisableTexture2D(EntityLivingBase p_72719_1_, int p_72719_2_, double p_72719_3_, CallbackInfoReturnable cir) { - // Note: Conflicts with OcclusionRenderer - Shaders.disableTexture2D(); - } - - @Inject( - method = "drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MovingObjectPosition;IF)V", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false, ordinal = 0, shift = At.Shift.AFTER), expect = 1) - private void angelica$drawSelectionBoxDisableTexture2D(CallbackInfo ci) { - Shaders.disableTexture2D(); - } - - @Inject( - method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false, ordinal = 0, shift = At.Shift.AFTER), expect = 0) - private void angelica$sortAndRenderEnableTexture2D(CallbackInfoReturnable cir) { - // Note: Conflicts with OcclusionRenderer - Shaders.enableTexture2D(); - } - - @Inject( - method = "drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MovingObjectPosition;IF)V", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false, ordinal = 1, shift = At.Shift.AFTER), expect = 1) - private void angelica$drawSelectionBoxEnableTexture2D(EntityPlayer p_72731_1_, MovingObjectPosition p_72731_2_, - int p_72731_3_, float p_72731_4_, CallbackInfo ci) { - Shaders.enableTexture2D(); - } - - // Fog - @Inject( - method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false, ordinal = 3, shift = At.Shift.AFTER), expect = 0) - private void angelica$sortAndRenderDisableFog(CallbackInfoReturnable cir) { - // Note: Conflicts with OcclusionRenderer - Shaders.disableFog(); - } - - @Inject( - method = "sortAndRender(Lnet/minecraft/entity/EntityLivingBase;ID)I", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false, ordinal = 2, shift = At.Shift.AFTER), expect = 0) - private void angelica$sortAndRenderEnableFog(CallbackInfoReturnable cir) { - // Note: Conflicts with OcclusionRenderer - Shaders.enableFog(); - } - - // RenderSky - @WrapOperation(method = "renderSky(F)V", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false)) - private void angelica$renderSkyDisable(int cap, Operation original) { - original.call(cap); - - if (cap == GL11.GL_FOG) Shaders.disableFog(); - else if (cap == GL11.GL_TEXTURE_2D) Shaders.disableTexture2D(); - } - - @WrapOperation(method = "renderSky(F)V", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false)) - private void angelica$renderSkyEnable(int cap, Operation original) { - original.call(cap); - if (cap == GL11.GL_FOG) Shaders.enableFog(); - else if (cap == GL11.GL_TEXTURE_2D) Shaders.enableTexture2D(); - } - - @Inject( - method = "renderSky(F)V", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glCallList(I)V", remap = false, ordinal = 0, shift = At.Shift.BEFORE, by = 2)) - private void angelica$preSkyList(float p_72714_1_, CallbackInfo ci) { - Shaders.preSkyList(); - } - - @Inject( - method = "renderSky(F)V", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/WorldClient;getCelestialAngle(F)F", ordinal = 1, shift = At.Shift.BY, by = -2)) - private void angelica$preCelestialRotate(float p_72714_1_, CallbackInfo ci) { - Shaders.preCelestialRotate(); - } - - @Inject( - method = "renderSky(F)V", - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glRotatef(FFFF)V", remap = false, ordinal = 9, shift = At.Shift.AFTER)) - private void angelica$postCelestialRotate(float p_72714_1_, CallbackInfo ci) { - Shaders.postCelestialRotate(); - } - - // drawBlockDamageTexture - - @WrapOperation( - method = "drawBlockDamageTexture(Lnet/minecraft/client/renderer/Tessellator;Lnet/minecraft/entity/EntityLivingBase;F)V", - remap = false, - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDisable(I)V", remap = false)) - private void angelica$drawBlockDamageTextureDisable(int cap, Operation original) { - original.call(cap); - - if (cap == GL11.GL_TEXTURE_2D) Shaders.disableTexture2D(); - } - - @WrapOperation( - method = "drawBlockDamageTexture(Lnet/minecraft/client/renderer/Tessellator;Lnet/minecraft/entity/EntityLivingBase;F)V", - remap = false, - at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEnable(I)V", remap = false)) - private void angelica$drawBlockDamageTextureSkyEnable(int cap, Operation original) { - original.call(cap); - if (cap == GL11.GL_TEXTURE_2D) Shaders.enableTexture2D(); - } - - @Inject( - method = "drawBlockDamageTexture(Lnet/minecraft/client/renderer/Tessellator;Lnet/minecraft/entity/EntityLivingBase;F)V", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Tessellator;startDrawingQuads()V", ordinal = 0, shift = At.Shift.BEFORE)) - private void angelica$beginBlockDestroyProgress(Tessellator p_72717_1_, EntityLivingBase p_72717_2_, - float p_72717_3_, CallbackInfo ci) { - Shaders.beginBlockDestroyProgress(); - } - - @Inject( - method = "drawBlockDamageTexture(Lnet/minecraft/client/renderer/Tessellator;Lnet/minecraft/entity/EntityLivingBase;F)V", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Tessellator;setTranslation(DDD)V", ordinal = 1, shift = At.Shift.AFTER)) - private void angelica$endBlockDestroyProgress(Tessellator p_72717_1_, EntityLivingBase p_72717_2_, float p_72717_3_, - CallbackInfo ci) { - Shaders.endBlockDestroyProgress(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderSpider.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderSpider.java deleted file mode 100644 index 7186cb367..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRenderSpider.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.entity.RenderSpider; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import com.gtnewhorizons.angelica.client.Shaders; - -@Mixin(RenderSpider.class) -public class MixinRenderSpider { - // TODO: Rendering - @Inject( - at = @At( - remap = false, - shift = At.Shift.AFTER, - target = "Lorg/lwjgl/opengl/GL11;glColor4f(FFFF)V", - value = "INVOKE"), - method = "shouldRenderPass(Lnet/minecraft/entity/monster/EntitySpider;IF)I") - private void angelica$beginSpiderEyes(CallbackInfoReturnable cir) { - Shaders.beginGlowingEyes(); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRendererLivingEntity.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRendererLivingEntity.java deleted file mode 100644 index 233b5b93c..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinRendererLivingEntity.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.entity.RendererLivingEntity; -import net.minecraft.entity.EntityLivingBase; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.gtnewhorizons.angelica.client.Shaders; - -@Mixin(RendererLivingEntity.class) -public abstract class MixinRendererLivingEntity { - // TODO: Rendering - @Shadow - protected abstract int getColorMultiplier(EntityLivingBase p_77030_1_, float p_77030_2_, float p_77030_3_); - - @Inject(at = @At("HEAD"), method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V") - private void angelica$setEntityHurtFlash(EntityLivingBase p_76986_1_, double p_76986_2_, double p_76986_4_, double p_76986_6_, float p_76986_8_, float p_76986_9_, CallbackInfo ci) { - if (!Shaders.useEntityHurtFlash) { - Shaders.setEntityHurtFlash( - p_76986_1_.hurtTime <= 0 && p_76986_1_.deathTime <= 0 ? 0 : 102, - this.getColorMultiplier(p_76986_1_, p_76986_1_.getBrightness(p_76986_9_), p_76986_9_)); - } - } - - @Inject( - at = @At( - target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;renderEquippedItems(Lnet/minecraft/entity/EntityLivingBase;F)V", - value = "INVOKE"), - method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V") - private void angelica$resetEntityHurtFlash(CallbackInfo ci) { - Shaders.resetEntityHurtFlash(); - } - - @Inject( - at = @At( - ordinal = 1, - shift = At.Shift.AFTER, - target = "Lnet/minecraft/client/renderer/OpenGlHelper;setActiveTexture(I)V", - value = "INVOKE"), - method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V") - private void angelica$disableLightmap(CallbackInfo ci) { - Shaders.disableLightmap(); - } - - @Inject( - at = @At( - ordinal = 2, - remap = false, - shift = At.Shift.AFTER, - target = "Lorg/lwjgl/opengl/GL11;glDepthFunc(I)V", - value = "INVOKE"), - method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V") - private void angelica$beginLivingDamage(CallbackInfo ci) { - Shaders.beginLivingDamage(); - } - - @Inject( - at = @At( - ordinal = 3, - remap = false, - shift = At.Shift.AFTER, - target = "Lorg/lwjgl/opengl/GL11;glDepthFunc(I)V", - value = "INVOKE"), - method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V") - private void angelica$endLivingDamage(CallbackInfo ci) { - Shaders.endLivingDamage(); - } - - @Inject( - at = @At( - ordinal = 3, - shift = At.Shift.AFTER, - target = "Lnet/minecraft/client/renderer/OpenGlHelper;setActiveTexture(I)V", - value = "INVOKE"), - method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V") - private void angelica$enableLightmap(CallbackInfo ci) { - Shaders.enableLightmap(); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinSimpleTexture.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinSimpleTexture.java deleted file mode 100644 index 02ebf4618..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinSimpleTexture.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import com.gtnewhorizons.angelica.client.ShadersTex; -import com.llamalad7.mixinextras.sugar.Local; - -import net.minecraft.client.renderer.texture.AbstractTexture; -import net.minecraft.client.renderer.texture.SimpleTexture; -import net.minecraft.client.resources.IResourceManager; -import net.minecraft.util.ResourceLocation; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.awt.image.BufferedImage; - -@Mixin(value = SimpleTexture.class) -public abstract class MixinSimpleTexture extends AbstractTexture { - // TODO: PBR - - @Shadow - protected ResourceLocation textureLocation; - - @Redirect( - method = "loadTexture(Lnet/minecraft/client/resources/IResourceManager;)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/texture/TextureUtil;uploadTextureImageAllocate(ILjava/awt/image/BufferedImage;ZZ)I")) - private int angelica$loadSimpleTexture(int textureID, BufferedImage bufferedImage, boolean flag, boolean flag1, @Local IResourceManager p_110551_1_) { - ShadersTex.loadSimpleTexture(textureID, bufferedImage, flag, flag1, p_110551_1_, this.textureLocation, ShadersTex.getMultiTexID(this)); - return 0; - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTessellator.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTessellator.java deleted file mode 100644 index b792e1017..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTessellator.java +++ /dev/null @@ -1,249 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import com.gtnewhorizons.angelica.client.ShadersTess; -import com.gtnewhorizons.angelica.mixins.interfaces.TessellatorAccessor; -import net.minecraft.client.renderer.GLAllocation; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.shader.TesselatorVertexState; -import net.minecraft.client.util.QuadComparator; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; -import java.util.PriorityQueue; - -@Mixin(Tessellator.class) -public abstract class MixinTessellator implements TessellatorAccessor { - // TODO: Rendering - - @Shadow(remap = false) - public boolean defaultTexture; - @Shadow(remap = false) - private int rawBufferSize; - @Shadow(remap = false) - public int textureID; - @Shadow - public int[] rawBuffer; - @Shadow - public int vertexCount; - @Shadow - public int rawBufferIndex; - @Shadow - public int addedVertices; - @Shadow - public boolean hasTexture; - @Shadow - public boolean hasBrightness; - @Shadow - public boolean hasNormals; - @Shadow - public boolean hasColor; - @Shadow - public double xOffset; - @Shadow - public double yOffset; - @Shadow - public double zOffset; - private ByteBuffer angelica$byteBuffer; - private IntBuffer angelica$intBuffer; - private FloatBuffer angelica$floatBuffer; - private ShortBuffer angelica$shortBuffer; - public float[] angelica$vertexPos; - public float angelica$normalX; - public float angelica$normalY; - public float angelica$normalZ; - public float angelica$midTextureU; - public float angelica$midTextureV; - - @Inject(method = "(I)V", at = @At("TAIL")) - private void angelica$extendBufferConstructor(int bufferSize, CallbackInfo ci) { - angelica$byteBuffer = GLAllocation.createDirectByteBuffer(bufferSize * 4); - angelica$intBuffer = angelica$byteBuffer.asIntBuffer(); - angelica$floatBuffer = angelica$byteBuffer.asFloatBuffer(); - angelica$shortBuffer = angelica$byteBuffer.asShortBuffer(); - rawBuffer = new int[bufferSize]; - vertexCount = 0; - angelica$vertexPos = new float[16]; - } - - @Inject(method = "()V", at = @At("TAIL")) - private void angelica$extendEmptyConstructor(CallbackInfo ci) { - this.angelica$extendBufferConstructor(65536, null); - this.defaultTexture = false; - this.rawBufferSize = 0; - this.textureID = 0; - } - - /** - * @author eigenraven - * @reason The entire drawing process must be redirected to go through an alternative renderer - */ - @Overwrite - public int draw() { - return ShadersTess.draw((Tessellator) (Object) this); - } - - /** - * @author eigenraven - * @reason byteBuffer->angelica$byteBuffer - */ - @Overwrite - public void reset() { - this.vertexCount = 0; - this.angelica$byteBuffer.clear(); - this.rawBufferIndex = 0; - this.addedVertices = 0; - } - - /** - * @author eigenraven - * @reason The entire drawing process must be redirected to go through an alternative renderer - */ - @Overwrite - public void addVertex(double x, double y, double z) { - ShadersTess.addVertex((Tessellator) (Object) this, x, y, z); - } - - /** - * @author eigenraven - * @reason Modify 32->64, ModifyConstant causes an internal mixin crash in this method - */ - @Overwrite - public TesselatorVertexState getVertexState(float x, float y, float z) { - int[] tmpCopyBuffer = new int[this.rawBufferIndex]; - @SuppressWarnings("unchecked") - PriorityQueue pQueue = new PriorityQueue<>( - this.rawBufferIndex, - new QuadComparator(this.rawBuffer, x + (float) this.xOffset, y + (float) this.yOffset, z + (float) this.zOffset)); - byte batchSize = 64; - - for (int vidx = 0; vidx < this.rawBufferIndex; vidx += batchSize) { - pQueue.add(vidx); - } - - for (int batchVidx = 0; !pQueue.isEmpty(); batchVidx += batchSize) { - int queuedVidx = pQueue.remove(); - - for (int batchElement = 0; batchElement < batchSize; ++batchElement) { - tmpCopyBuffer[batchVidx + batchElement] = this.rawBuffer[queuedVidx + batchElement]; - } - } - - System.arraycopy(tmpCopyBuffer, 0, this.rawBuffer, 0, tmpCopyBuffer.length); - return new TesselatorVertexState(tmpCopyBuffer, this.rawBufferIndex, this.vertexCount, this.hasTexture, this.hasBrightness, this.hasNormals, this.hasColor); - } - - @Inject(method = "setNormal(FFF)V", at = @At("HEAD")) - private void angelica$captureNormalComponents(float x, float y, float z, CallbackInfo ci) { - this.angelica$normalX = x; - this.angelica$normalY = y; - this.angelica$normalZ = z; - } - - @Override - public ByteBuffer angelica$getByteBuffer() { - return angelica$byteBuffer; - } - - @Override - public IntBuffer angelica$getIntBuffer() { - return angelica$intBuffer; - } - - @Override - public FloatBuffer angelica$getFloatBuffer() { - return angelica$floatBuffer; - } - - @Override - public ShortBuffer angelica$getShortBuffer() { - return angelica$shortBuffer; - } - - @Override - public float[] angelica$getVertexPos() { - return angelica$vertexPos; - } - - @Override - public float angelica$getNormalX() { - return angelica$normalX; - } - - @Override - public float angelica$getNormalY() { - return angelica$normalY; - } - - @Override - public float angelica$getNormalZ() { - return angelica$normalZ; - } - - @Override - public float angelica$getMidTextureU() { - return angelica$midTextureU; - } - - @Override - public float angelica$getMidTextureV() { - return angelica$midTextureV; - } - - @Override - public void angelica$setByteBuffer(ByteBuffer angelica$byteBuffer) { - this.angelica$byteBuffer = angelica$byteBuffer; - } - - @Override - public void angelica$setIntBuffer(IntBuffer angelica$intBuffer) { - this.angelica$intBuffer = angelica$intBuffer; - } - - @Override - public void angelica$setFloatBuffer(FloatBuffer angelica$floatBuffer) { - this.angelica$floatBuffer = angelica$floatBuffer; - } - - @Override - public void angelica$setShortBuffer(ShortBuffer angelica$shortBuffer) { - this.angelica$shortBuffer = angelica$shortBuffer; - } - - @Override - public void angelica$setVertexPos(float[] angelica$vertexPos) { - this.angelica$vertexPos = angelica$vertexPos; - } - - @Override - public void angelica$setNormalX(float angelica$normalX) { - this.angelica$normalX = angelica$normalX; - } - - @Override - public void angelica$setNormalY(float angelica$normalY) { - this.angelica$normalY = angelica$normalY; - } - - @Override - public void angelica$setNormalZ(float angelica$normalZ) { - this.angelica$normalZ = angelica$normalZ; - } - - @Override - public void angelica$setMidTextureU(float angelica$midTextureU) { - this.angelica$midTextureU = angelica$midTextureU; - } - - @Override - public void angelica$setMidTextureV(float angelica$midTextureV) { - this.angelica$midTextureV = angelica$midTextureV; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureAtlasSprite.java deleted file mode 100644 index 213edf9cb..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureAtlasSprite.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.texture.TextureAtlasSprite; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import com.gtnewhorizons.angelica.client.ShadersTex; - -@Mixin(TextureAtlasSprite.class) -public class MixinTextureAtlasSprite { - // TODO: Mipmap/Rendering/Animation - - @Redirect( - at = @At( - target = "Lnet/minecraft/client/renderer/texture/TextureUtil;uploadTextureMipmap([[IIIIIZZ)V", - value = "INVOKE"), - method = "updateAnimation()V") - private void angelica$uploadTexSub(int[][] p_147955_0_, int p_147955_1_, int p_147955_2_, int p_147955_3_, - int p_147955_4_, boolean p_147955_5_, boolean p_147955_6_) { - ShadersTex.uploadTexSub(p_147955_0_, p_147955_1_, p_147955_2_, p_147955_3_, p_147955_4_, p_147955_5_, p_147955_6_); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureClock.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureClock.java deleted file mode 100644 index 8e59571f3..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureClock.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.texture.TextureClock; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import com.gtnewhorizons.angelica.client.ShadersTex; - -@Mixin(value = TextureClock.class) -public class MixinTextureClock { - // TODO: Mipmap/Rendering/Animation - @Redirect( - method = "updateAnimation()V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/texture/TextureUtil;uploadTextureMipmap([[IIIIIZZ)V")) - private void angelica$uploadTexSub(int[][] data, int width, int height, int xoffset, int yoffset, boolean linear, - boolean clamp) { - ShadersTex.uploadTexSub(data, width, height, xoffset, yoffset, linear, clamp); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureCompass.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureCompass.java deleted file mode 100644 index ac156f51a..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureCompass.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.texture.TextureCompass; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import com.gtnewhorizons.angelica.client.ShadersTex; - -@Mixin(value = TextureCompass.class) -public class MixinTextureCompass { - // TODO: Mipmap/Rendering/Animation - - @Redirect( - method = "updateCompass(Lnet/minecraft/world/World;DDDZZ)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/texture/TextureUtil;uploadTextureMipmap([[IIIIIZZ)V")) - private void angelica$uploadTexSub(int[][] data, int width, int height, int xoffset, int yoffset, boolean linear, - boolean clamp) { - ShadersTex.uploadTexSub(data, width, height, xoffset, yoffset, linear, clamp); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureManager.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureManager.java deleted file mode 100644 index 1d65e8a4c..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureManager.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.texture.ITextureObject; -import net.minecraft.client.renderer.texture.TextureManager; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import com.gtnewhorizons.angelica.client.ShadersTex; - -@Mixin(TextureManager.class) -public class MixinTextureManager { - // TODO: PBR - @Redirect( - at = @At(target = "Lnet/minecraft/client/renderer/texture/ITextureObject;getGlTextureId()I", value = "INVOKE"), - method = "bindTexture(Lnet/minecraft/util/ResourceLocation;)V") - private int angelica$bindTexture(ITextureObject object) { - ShadersTex.bindTexture(object); - return 0; - } - - @Redirect( - at = @At(target = "Lnet/minecraft/client/renderer/texture/TextureUtil;bindTexture(I)V", value = "INVOKE"), - method = "bindTexture(Lnet/minecraft/util/ResourceLocation;)V") - private void angelica$noop(int p_94277_0_) { - // NO-OP - } - - @Redirect( - at = @At( - target = "Lnet/minecraft/client/renderer/texture/ITextureObject;getGlTextureId()I", - value = "INVOKE"), - method = "deleteTexture(Lnet/minecraft/util/ResourceLocation;)V") - private int angelica$deleteMultiTex(ITextureObject itextureobject) { - return ShadersTex.deleteMultiTex(itextureobject); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureMap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureMap.java deleted file mode 100644 index 41341f052..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinTextureMap.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import com.gtnewhorizons.angelica.client.ShadersTex; -import com.llamalad7.mixinextras.sugar.Local; - -import net.minecraft.client.renderer.texture.Stitcher; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureMap; -import net.minecraft.client.resources.IResource; -import net.minecraft.client.resources.IResourceManager; -import net.minecraft.util.ResourceLocation; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.io.IOException; - -@Mixin(TextureMap.class) -public class MixinTextureMap extends MixinAbstractTexture { - // TODO: Textures/Stitcher - - public int angelica$atlasWidth; - public int angelica$atlasHeight; - - // loadTextureAtlas - - @Redirect( - at = @At( - target = "Lnet/minecraft/client/resources/IResourceManager;getResource(Lnet/minecraft/util/ResourceLocation;)Lnet/minecraft/client/resources/IResource;", - value = "INVOKE"), - method = "loadTextureAtlas(Lnet/minecraft/client/resources/IResourceManager;)V") - private IResource angelica$loadResource(IResourceManager p_110571_1_, ResourceLocation resourcelocation1) throws IOException { - return ShadersTex.loadResource(p_110571_1_, resourcelocation1); - } - - @Redirect( - at = @At( - target = "Lnet/minecraft/client/renderer/texture/TextureUtil;allocateTextureImpl(IIIIF)V", - value = "INVOKE"), - method = "loadTextureAtlas(Lnet/minecraft/client/resources/IResourceManager;)V") - private void angelica$allocateTextureMap(int p_147946_0_, int p_147946_1_, int p_147946_2_, int p_147946_3_, - float p_147946_4_, @Local Stitcher stitcher) { - ShadersTex.allocateTextureMap(p_147946_0_, p_147946_1_, p_147946_2_, p_147946_3_, p_147946_4_, stitcher, (TextureMap) (Object) this); - } - - @Redirect( - at = @At( - target = "Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;getIconName()Ljava/lang/String;", - value = "INVOKE"), - method = "loadTextureAtlas(Lnet/minecraft/client/resources/IResourceManager;)V", - slice = @Slice( - from = @At( - args = "ldc=Uploading GL texture", - remap = false, - target = "Lcpw/mods/fml/common/ProgressManager$ProgressBar;step(Ljava/lang/String;)V", - value = "INVOKE_STRING"))) - private String angelica$getIconName(TextureAtlasSprite textureatlassprite) { - return ShadersTex.setIconName(ShadersTex.setSprite(textureatlassprite).getIconName()); - } - - @Redirect( - at = @At( - target = "Lnet/minecraft/client/renderer/texture/TextureUtil;uploadTextureMipmap([[IIIIIZZ)V", - value = "INVOKE"), - method = "loadTextureAtlas(Lnet/minecraft/client/resources/IResourceManager;)V") - private void angelica$uploadTexSubForLoadAtlas(int[][] p_147955_0_, int p_147955_1_, int p_147955_2_, - int p_147955_3_, int p_147955_4_, boolean p_147955_5_, boolean p_147955_6_) { - ShadersTex.uploadTexSubForLoadAtlas(p_147955_0_, p_147955_1_, p_147955_2_, p_147955_3_, p_147955_4_, p_147955_5_, p_147955_6_); - } - - // updateAnimations - - @Inject(at = @At("HEAD"), method = "updateAnimations()V") - private void angelica$setUpdatingTex(CallbackInfo ci) { - ShadersTex.updatingTex = this.angelica$getMultiTexID(); - } - - @Inject(at = @At("RETURN"), method = "updateAnimations()V") - private void angelica$resetUpdatingTex(CallbackInfo ci) { - ShadersTex.updatingTex = null; - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinThreadDownloadImageData.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinThreadDownloadImageData.java deleted file mode 100644 index 16d2f75c8..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/renderer/MixinThreadDownloadImageData.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.renderer; - -import net.minecraft.client.renderer.ThreadDownloadImageData; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.SoftOverride; - -import com.gtnewhorizons.angelica.client.MultiTexID; - -@Mixin(ThreadDownloadImageData.class) -public abstract class MixinThreadDownloadImageData extends MixinAbstractTexture { - // TODO: PBR - @Shadow - private boolean textureUploaded; - - @Shadow - public abstract int getGlTextureId(); - - @SoftOverride - public MultiTexID angelica$getMultiTexID() { - if (!this.textureUploaded) { - this.getGlTextureId(); - } - return super.angelica$getMultiTexID(); - } - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/settings/MixinGuiVideoSettings.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/settings/MixinGuiVideoSettings.java deleted file mode 100644 index 029aae52e..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shadersmod/settings/MixinGuiVideoSettings.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.shadersmod.settings; - -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.gui.GuiVideoSettings; -import net.minecraft.client.settings.GameSettings; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.gtnewhorizons.angelica.client.gui.GuiShaders; - -@Mixin(GuiVideoSettings.class) -public abstract class MixinGuiVideoSettings extends GuiScreen { - - private static final int SHADER_BUTTON_ID = 190; - - @Shadow - private GameSettings guiGameSettings; - - @Inject(method = "initGui()V", at = @At(value = "TAIL")) - private void angelica$addShadersButton(CallbackInfo ci) { - // Add the Shaders Button to the bottom of Video Options - final GuiButton shaderButton = new GuiButton( - SHADER_BUTTON_ID, - this.width / 2 - 190, - this.height - 27, - 70, - 20, - "Shaders..."); - this.buttonList.add(shaderButton); - } - - @Inject(method = "actionPerformed(Lnet/minecraft/client/gui/GuiButton;)V", at = @At(value = "HEAD")) - private void angelica$actionPerformed(GuiButton button, CallbackInfo ci) { - if (button.id == SHADER_BUTTON_ID) { - this.mc.gameSettings.saveOptions(); - this.mc.displayGuiScreen(new GuiShaders(this, this.guiGameSettings)); - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityFX.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityFX.java index 6926b8273..9e0a4498a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityFX.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinEntityFX.java @@ -1,6 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; -import com.gtnewhorizons.angelica.client.textures.ISpriteExt; +import com.gtnewhorizons.angelica.mixins.interfaces.ISpriteExt; import me.jellysquid.mods.sodium.client.render.texture.SpriteUtil; import net.minecraft.client.particle.EntityFX; import net.minecraft.client.renderer.Tessellator; diff --git a/src/main/java/com/gtnewhorizons/angelica/client/textures/ISpriteExt.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ISpriteExt.java similarity index 81% rename from src/main/java/com/gtnewhorizons/angelica/client/textures/ISpriteExt.java rename to src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ISpriteExt.java index 1a1db51a1..72a8ab671 100644 --- a/src/main/java/com/gtnewhorizons/angelica/client/textures/ISpriteExt.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ISpriteExt.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.client.textures; +package com.gtnewhorizons.angelica.mixins.interfaces; import net.minecraft.client.resources.data.AnimationMetadataSection; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java index a7944914d..635917b35 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderData.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.data; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionData; -import com.gtnewhorizons.angelica.client.textures.ISpriteExt; +import com.gtnewhorizons.angelica.mixins.interfaces.ISpriteExt; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.Getter; diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java index c44cf162c..0a0507861 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java @@ -1,6 +1,7 @@ package net.coderbot.iris.texture.pbr.loader; import com.google.common.collect.Lists; +import com.gtnewhorizons.angelica.mixins.interfaces.ISpriteExt; import com.gtnewhorizons.angelica.compat.NativeImage; import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.AnimationMetadataSectionAccessor; import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.TextureAtlasSpriteAccessor; @@ -165,8 +166,7 @@ protected TextureAtlasSprite createPBRSprite(TextureAtlasSprite sprite, IResourc protected void syncAnimation(TextureAtlasSprite source, TextureAtlasSprite target) { - // TODO: Iris Shaders - animationMetadata && animationMetadata.getFrameCount() > 0 - if (!source.hasAnimationMetadata() || !target.hasAnimationMetadata()) { + if (!((ISpriteExt)source).isAnimation() || !((ISpriteExt)target).isAnimation()) { return; } From e962de08befb5c733cc84fc7e09b3b58e76d774a Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 17 Dec 2023 11:43:49 -0800 Subject: [PATCH 281/301] Move around compat into code expected to be removed, and code expected to stick around. --- .../com/gtnewhorizons/angelica/compat/Constants.java | 5 ----- .../angelica/compat/forge/VertexBufferConsumer.java | 2 +- .../compat/mojang/AutoClosableAbstractTexture.java | 6 ------ .../angelica/compat/{ => mojang}/Axis.java | 2 +- .../angelica/compat/mojang/BlockRenderView.java | 5 ----- .../angelica/compat/{ => mojang}/Camera.java | 4 ++-- .../angelica/compat/{ => mojang}/ChunkPos.java | 8 +++----- .../angelica/compat/{ => mojang}/ChunkSectionPos.java | 3 +-- .../angelica/compat/{ => mojang}/CompatMathHelper.java | 2 +- .../angelica/compat/mojang/Constants.java | 5 +++++ .../angelica/compat/{ => mojang}/NativeImage.java | 4 ++-- .../angelica/compat/toremove/BlockRenderView.java | 5 +++++ .../compat/{mojang => toremove}/BufferBuilder.java | 2 +- .../compat/{mojang => toremove}/BufferSource.java | 2 +- .../ByteBufferBackedInputStream.java | 2 +- .../{mojang => toremove}/DefaultVertexFormat.java | 3 ++- .../compat/{mojang => toremove}/DrawState.java | 2 +- .../compat/{mojang => toremove}/FluidState.java | 3 ++- .../compat/{mojang => toremove}/MatrixStack.java | 4 ++-- .../compat/{mojang => toremove}/MultiBufferSource.java | 2 +- .../compat/{mojang => toremove}/OverlayTexture.java | 2 +- .../compat/{mojang => toremove}/RenderLayer.java | 2 +- .../compat/{mojang => toremove}/RenderLayers.java | 2 +- .../compat/{mojang => toremove}/RenderPhase.java | 2 +- .../compat/{mojang => toremove}/TextureAtlas.java | 3 ++- .../compat/{mojang => toremove}/VertexConsumer.java | 2 +- .../compat/{mojang => toremove}/VertexConsumers.java | 2 +- .../compat/{mojang => toremove}/VertexFormat.java | 5 +++-- .../compat/{mojang => toremove}/VoxelShape.java | 2 +- .../compat/{mojang => toremove}/VoxelShapes.java | 2 +- .../mixins/early/shaders/MixinEntityRenderer.java | 2 +- .../mixins/early/shaders/MixinRenderGlobal.java | 2 -- .../mixins/early/sodium/MixinRenderGlobal.java | 4 ++-- .../sodium/client/gl/attribute/BufferVertexFormat.java | 2 +- .../client/model/light/cache/ArrayLightDataCache.java | 2 +- .../client/model/quad/properties/ModelQuadFlags.java | 2 +- .../mods/sodium/client/model/vertex/VertexDrain.java | 2 +- .../model/vertex/fallback/VertexWriterFallback.java | 2 +- .../model/vertex/formats/glyph/GlyphVertexSink.java | 4 ++-- .../model/vertex/formats/glyph/GlyphVertexType.java | 4 ++-- .../glyph/writer/GlyphVertexWriterFallback.java | 2 +- .../model/vertex/formats/line/LineVertexSink.java | 4 ++-- .../model/vertex/formats/line/LineVertexType.java | 4 ++-- .../formats/line/writer/LineVertexWriterFallback.java | 2 +- .../vertex/formats/particle/ParticleVertexSink.java | 4 ++-- .../vertex/formats/particle/ParticleVertexType.java | 4 ++-- .../particle/writer/ParticleVertexWriterFallback.java | 2 +- .../model/vertex/formats/quad/QuadVertexSink.java | 6 +++--- .../model/vertex/formats/quad/QuadVertexType.java | 4 ++-- .../formats/quad/writer/QuadVertexWriterFallback.java | 2 +- .../formats/screen_quad/BasicScreenQuadVertexSink.java | 4 ++-- .../formats/screen_quad/BasicScreenQuadVertexType.java | 4 ++-- .../writer/BasicScreenQuadVertexWriterFallback.java | 2 +- .../client/model/vertex/type/VanillaVertexType.java | 2 +- .../sodium/client/model/vertex/type/VertexType.java | 2 +- .../mods/sodium/client/render/GameRendererContext.java | 2 +- .../mods/sodium/client/render/SodiumWorldRenderer.java | 8 ++++---- .../sodium/client/render/chunk/ChunkRenderBackend.java | 2 +- .../client/render/chunk/ChunkRenderContainer.java | 2 +- .../sodium/client/render/chunk/ChunkRenderManager.java | 6 +++--- .../chunk/backends/multidraw/ChunkDrawCallBatcher.java | 2 +- .../sodium/client/render/chunk/cull/ChunkCuller.java | 2 +- .../render/chunk/cull/graph/ChunkGraphCuller.java | 4 ++-- .../client/render/chunk/data/ChunkRenderBounds.java | 2 +- .../render/chunk/format/hfp/HFPModelVertexType.java | 2 +- .../render/chunk/format/sfp/SFPModelVertexType.java | 2 +- .../client/render/chunk/region/ChunkRegionManager.java | 2 +- .../client/render/chunk/shader/ChunkProgram.java | 2 +- .../render/chunk/shader/ChunkRenderShaderBackend.java | 2 +- .../sodium/client/render/pipeline/BlockRenderer.java | 3 +-- .../sodium/client/render/pipeline/FluidRenderer.java | 4 ++-- .../mods/sodium/client/world/WorldSlice.java | 4 ++-- .../sodium/client/world/cloned/ChunkRenderContext.java | 2 +- .../sodium/client/world/cloned/ClonedChunkSection.java | 2 +- .../client/world/cloned/ClonedChunkSectionCache.java | 2 +- .../jellysquid/mods/sodium/common/util/WorldUtil.java | 4 ++-- .../batchedentityrendering/impl/BufferBuilderExt.java | 2 +- .../batchedentityrendering/impl/BufferSegment.java | 4 ++-- .../impl/BufferSegmentRenderer.java | 2 +- .../impl/FullyBufferedMultiBufferSource.java | 8 ++++---- .../impl/OldFullyBufferedMultiBufferSource.java | 8 ++++---- .../batchedentityrendering/impl/RenderTypeUtil.java | 2 +- .../impl/SegmentedBufferBuilder.java | 10 +++++----- .../impl/WrappableRenderType.java | 2 +- .../ordering/GraphTranslucencyRenderOrderManager.java | 2 +- .../impl/ordering/RenderOrderManager.java | 2 +- .../impl/ordering/SimpleRenderOrderManager.java | 2 +- .../impl/ordering/TranslucencyRenderOrderManager.java | 2 +- .../impl/wrappers/TaggingRenderTypeWrapper.java | 2 +- .../iris/block_rendering/BlockMaterialMapping.java | 2 +- .../iris/block_rendering/BlockRenderingSettings.java | 2 +- .../iris/fantastic/WrappingMultiBufferSource.java | 2 +- .../iris/layer/BlockEntityRenderStateShard.java | 2 +- .../coderbot/iris/layer/EntityRenderStateShard.java | 2 +- .../iris/layer/IsBlockEntityRenderStateShard.java | 2 +- .../coderbot/iris/layer/IsEntityRenderStateShard.java | 2 +- .../coderbot/iris/layer/IsOutlineRenderStateShard.java | 2 +- .../coderbot/iris/layer/OuterWrappedRenderType.java | 4 ++-- .../iris/pipeline/DeferredWorldRenderingPipeline.java | 2 +- .../pipeline/FixedFunctionWorldRenderingPipeline.java | 2 +- .../java/net/coderbot/iris/pipeline/HandRenderer.java | 4 ++-- .../net/coderbot/iris/pipeline/HorizonRenderer.java | 4 ++-- .../net/coderbot/iris/pipeline/ShadowRenderer.java | 6 +++--- .../coderbot/iris/pipeline/WorldRenderingPhase.java | 2 +- .../coderbot/iris/pipeline/WorldRenderingPipeline.java | 2 +- .../iris/postprocess/FullScreenQuadRenderer.java | 2 +- .../rendertarget/NativeImageBackedCustomTexture.java | 2 +- .../rendertarget/NativeImageBackedNoiseTexture.java | 2 +- .../NativeImageBackedSingleColorTexture.java | 2 +- .../java/net/coderbot/iris/shadow/ShadowMatrices.java | 6 ++---- .../sodium/shader_overrides/ChunkRenderBackendExt.java | 2 +- .../iris/sodium/shader_overrides/IrisChunkProgram.java | 2 +- .../entity_xhfp/EntityVertexBufferWriterNio.java | 2 +- .../entity_xhfp/EntityVertexBufferWriterUnsafe.java | 2 +- .../entity_xhfp/ExtendedGlyphVertexType.java | 4 ++-- .../entity_xhfp/ExtendedQuadVertexType.java | 4 ++-- .../entity_xhfp/GlyphVertexBufferWriterNio.java | 2 +- .../entity_xhfp/GlyphVertexBufferWriterUnsafe.java | 2 +- .../terrain_xhfp/XHFPModelVertexType.java | 2 +- .../iris/texture/mipmap/AbstractMipmapGenerator.java | 2 +- .../iris/texture/mipmap/ChannelMipmapGenerator.java | 2 +- .../iris/texture/mipmap/CustomMipmapGenerator.java | 2 +- .../iris/texture/pbr/loader/AtlasPBRLoader.java | 2 +- .../iris/texture/util/ImageManipulationUtil.java | 2 +- .../coderbot/iris/texture/util/TextureExporter.java | 2 +- .../net/coderbot/iris/uniforms/CelestialUniforms.java | 2 +- .../net/coderbot/iris/uniforms/CommonUniforms.java | 2 +- .../coderbot/iris/vertices/ExtendingBufferBuilder.java | 2 +- .../net/coderbot/iris/vertices/IrisVertexFormats.java | 4 ++-- 129 files changed, 184 insertions(+), 194 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/Constants.java rename src/main/java/com/gtnewhorizons/angelica/compat/{ => mojang}/Axis.java (87%) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java rename src/main/java/com/gtnewhorizons/angelica/compat/{ => mojang}/Camera.java (92%) rename src/main/java/com/gtnewhorizons/angelica/compat/{ => mojang}/ChunkPos.java (84%) rename src/main/java/com/gtnewhorizons/angelica/compat/{ => mojang}/ChunkSectionPos.java (95%) rename src/main/java/com/gtnewhorizons/angelica/compat/{ => mojang}/CompatMathHelper.java (92%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/mojang/Constants.java rename src/main/java/com/gtnewhorizons/angelica/compat/{ => mojang}/NativeImage.java (96%) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/BlockRenderView.java rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/BufferBuilder.java (98%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/BufferSource.java (86%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/ByteBufferBackedInputStream.java (92%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/DefaultVertexFormat.java (96%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/DrawState.java (87%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/FluidState.java (88%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/MatrixStack.java (98%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/MultiBufferSource.java (84%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/OverlayTexture.java (67%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/RenderLayer.java (99%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/RenderLayers.java (95%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/RenderPhase.java (99%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/TextureAtlas.java (88%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/VertexConsumer.java (96%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/VertexConsumers.java (97%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/VertexFormat.java (92%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/VoxelShape.java (82%) rename src/main/java/com/gtnewhorizons/angelica/compat/{mojang => toremove}/VoxelShapes.java (92%) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/Constants.java b/src/main/java/com/gtnewhorizons/angelica/compat/Constants.java deleted file mode 100644 index d039dd1b8..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/Constants.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gtnewhorizons.angelica.compat; - -public class Constants { - public final static float DEGREES_TO_RADIANS = (float)Math.PI / 180.0F; -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java index 8da39c532..4bbaa34e2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java @@ -1,6 +1,6 @@ package com.gtnewhorizons.angelica.compat.forge; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; public class VertexBufferConsumer { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java index f7332d781..ba5648877 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/AutoClosableAbstractTexture.java @@ -2,15 +2,9 @@ import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.minecraft.client.renderer.texture.AbstractTexture; -import net.minecraft.client.resources.IResourceManager; import org.lwjgl.opengl.GL11; -import java.io.IOException; - public abstract class AutoClosableAbstractTexture extends AbstractTexture implements AutoCloseable { - - public abstract void loadTexture(IResourceManager manager) throws IOException; - @Override public void close() throws Exception {} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/Axis.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java similarity index 87% rename from src/main/java/com/gtnewhorizons/angelica/compat/Axis.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java index 27fffa8e5..d69400da9 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/Axis.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Axis.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat; +package com.gtnewhorizons.angelica.compat.mojang; import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java deleted file mode 100644 index 1020f8d96..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BlockRenderView.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gtnewhorizons.angelica.compat.mojang; - -@Deprecated -public interface BlockRenderView { -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/Camera.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/compat/Camera.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java index 88969231f..7fd8d6f4b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/Camera.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat; +package com.gtnewhorizons.angelica.compat.mojang; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import lombok.Getter; @@ -23,7 +23,7 @@ public class Camera { public Camera(EntityLivingBase entity, float partialTicks) { this.partialTicks = partialTicks; - Vector4f offset = new Vector4f(); // third person offset + final Vector4f offset = new Vector4f(); // third person offset final Matrix4f inverseModelView = new Matrix4f(RenderingState.INSTANCE.getModelViewMatrix()).invert(); inverseModelView.transform(offset); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/ChunkPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java similarity index 84% rename from src/main/java/com/gtnewhorizons/angelica/compat/ChunkPos.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java index afa801ae5..95813a5f8 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/ChunkPos.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkPos.java @@ -1,6 +1,4 @@ -package com.gtnewhorizons.angelica.compat; - -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +package com.gtnewhorizons.angelica.compat.mojang; // See if we can merge/mixin/extend ChunkCoordIntPair? public class ChunkPos { @@ -42,8 +40,8 @@ public static long toLong(int x, int z) { public int hashCode() { - int i = 1664525 * this.x + 1013904223; - int j = 1664525 * (this.z ^ -559038737) + 1013904223; + final int i = 1664525 * this.x + 1013904223; + final int j = 1664525 * (this.z ^ -559038737) + 1013904223; return i ^ j; } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/ChunkSectionPos.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java similarity index 95% rename from src/main/java/com/gtnewhorizons/angelica/compat/ChunkSectionPos.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java index c20a2927a..cedd9292b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/ChunkSectionPos.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkSectionPos.java @@ -1,6 +1,5 @@ -package com.gtnewhorizons.angelica.compat; +package com.gtnewhorizons.angelica.compat.mojang; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import org.joml.Vector3i; // See if we can merge/mixin/extend ChunkPosition maybe? diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/CompatMathHelper.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/CompatMathHelper.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/compat/CompatMathHelper.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/CompatMathHelper.java index a20ed75e3..1808502a3 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/CompatMathHelper.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/CompatMathHelper.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat; +package com.gtnewhorizons.angelica.compat.mojang; public class CompatMathHelper { public static int smallestEncompassingPowerOfTwo(int value) { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Constants.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Constants.java new file mode 100644 index 000000000..e66a880c4 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Constants.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.compat.mojang; + +public class Constants { + public static final float DEGREES_TO_RADIANS = (float)Math.PI / 180.0F; +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/NativeImage.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java similarity index 96% rename from src/main/java/com/gtnewhorizons/angelica/compat/NativeImage.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java index 3e4413216..c58816eab 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/NativeImage.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java @@ -1,6 +1,6 @@ -package com.gtnewhorizons.angelica.compat; +package com.gtnewhorizons.angelica.compat.mojang; -import com.gtnewhorizons.angelica.compat.mojang.ByteBufferBackedInputStream; +import com.gtnewhorizons.angelica.compat.toremove.ByteBufferBackedInputStream; import lombok.Getter; import net.coderbot.iris.Iris; import org.lwjgl.BufferUtils; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BlockRenderView.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BlockRenderView.java new file mode 100644 index 000000000..31df72e48 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BlockRenderView.java @@ -0,0 +1,5 @@ +package com.gtnewhorizons.angelica.compat.toremove; + +@Deprecated +public interface BlockRenderView { +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferBuilder.java similarity index 98% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferBuilder.java index edd6218f3..f70f9ebfe 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferBuilder.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferBuilder.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import net.coderbot.batchedentityrendering.impl.BufferBuilderExt; import org.apache.commons.lang3.tuple.Pair; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferSource.java similarity index 86% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferSource.java index eed8ab20d..066385003 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/BufferSource.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferSource.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import java.util.Map; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/ByteBufferBackedInputStream.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/ByteBufferBackedInputStream.java index 8ac3f6b80..1f1a0dbb0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/ByteBufferBackedInputStream.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/DefaultVertexFormat.java similarity index 96% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/DefaultVertexFormat.java index 7c8c3e1a8..d6a25f259 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DefaultVertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/DefaultVertexFormat.java @@ -1,6 +1,7 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement; import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement.Type; import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement.Usage; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DrawState.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/DrawState.java similarity index 87% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/DrawState.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/DrawState.java index 0aa8acbb9..756e23e3e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/DrawState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/DrawState.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import lombok.Getter; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/FluidState.java similarity index 88% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/FluidState.java index 45d0e047f..67d144096 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/FluidState.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/FluidState.java @@ -1,5 +1,6 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; +import com.gtnewhorizons.angelica.compat.mojang.BlockPos; import net.minecraft.block.BlockLiquid; import net.minecraftforge.fluids.Fluid; import org.joml.Vector3d; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/MatrixStack.java similarity index 98% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/MatrixStack.java index 385af6fba..69632669e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MatrixStack.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/MatrixStack.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import com.google.common.collect.Queues; import org.joml.Matrix3f; @@ -14,7 +14,7 @@ public MatrixStack() { this.matrixStack = Queues.newArrayDeque(); matrixStack.add(new Entry(new Matrix4f().identity(), new Matrix3f().identity())); } - + public MatrixStack(Matrix4f initial) { this.matrixStack = Queues.newArrayDeque(); Matrix3f normal = new Matrix3f(); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/MultiBufferSource.java similarity index 84% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/MultiBufferSource.java index 745f1c9b8..40e244cfe 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/MultiBufferSource.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/MultiBufferSource.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import java.util.Map; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/OverlayTexture.java similarity index 67% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/OverlayTexture.java index fd219461f..51f4b5f4b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/OverlayTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/OverlayTexture.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; public class OverlayTexture { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayer.java similarity index 99% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayer.java index aadac15ff..e2a473648 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayer.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import com.google.common.collect.ImmutableList; import it.unimi.dsi.fastutil.Hash; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayers.java similarity index 95% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayers.java index 9cf81c8b6..07c9cf6c4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderLayers.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayers.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import net.minecraft.block.Block; import net.minecraft.block.material.Material; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderPhase.java similarity index 99% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderPhase.java index ad3caa1f5..6ba033e3b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/RenderPhase.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderPhase.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import com.gtnewhorizons.angelica.glsm.GLStateManager; import me.jellysquid.mods.sodium.client.SodiumClientMod; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/TextureAtlas.java similarity index 88% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/TextureAtlas.java index 4615a3140..530e941f2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/TextureAtlas.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/TextureAtlas.java @@ -1,10 +1,11 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.ITickable; import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourceManagerReloadListener; +@Deprecated public abstract class TextureAtlas extends AbstractTexture implements ITickable, IResourceManagerReloadListener { @Override diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexConsumer.java similarity index 96% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexConsumer.java index daf481e5b..e60530185 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexConsumer.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import javax.annotation.Nonnull; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexConsumers.java similarity index 97% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexConsumers.java index 49ed27793..1ea42b3c0 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexConsumers.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexConsumers.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; @Deprecated public class VertexConsumers { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexFormat.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexFormat.java index f6fd42101..8056827f6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexFormat.java @@ -1,7 +1,8 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import com.google.common.collect.ImmutableList; -import com.google.common.collect.UnmodifiableIterator; +import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement; +import com.gtnewhorizons.angelica.compat.toremove.DefaultVertexFormat; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import lombok.Getter; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShape.java similarity index 82% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShape.java index 3433c2ba6..b6b3af199 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShape.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShape.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; @Deprecated public enum VoxelShape { diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShapes.java similarity index 92% rename from src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java rename to src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShapes.java index 2ec1e4b5a..990189cab 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/VoxelShapes.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShapes.java @@ -1,4 +1,4 @@ -package com.gtnewhorizons.angelica.compat.mojang; +package com.gtnewhorizons.angelica.compat.toremove; import net.minecraftforge.common.util.ForgeDirection; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index a3577a5a4..4bd2eed4e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -1,6 +1,6 @@ package com.gtnewhorizons.angelica.mixins.early.shaders; -import com.gtnewhorizons.angelica.compat.Camera; +import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Share; diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java index d2d049eee..4b884e52c 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinRenderGlobal.java @@ -13,8 +13,6 @@ import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import static com.gtnewhorizons.angelica.compat.Constants.DEGREES_TO_RADIANS; - @Mixin(RenderGlobal.class) public class MixinRenderGlobal { @Inject(method = "renderSky", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/Tessellator;instance:Lnet/minecraft/client/renderer/Tessellator;")) diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index 94e55ede4..ce8170b24 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -1,7 +1,7 @@ package com.gtnewhorizons.angelica.mixins.early.sodium; -import com.gtnewhorizons.angelica.compat.Camera; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; import com.gtnewhorizons.angelica.rendering.RenderingState; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java index e5c05565d..c29582ca8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gl/attribute/BufferVertexFormat.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.gl.attribute; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; public interface BufferVertexFormat { static BufferVertexFormat from(VertexFormat format) { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java index e15e960dd..c7a445128 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/light/cache/ArrayLightDataCache.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.light.cache; -import com.gtnewhorizons.angelica.compat.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess; import me.jellysquid.mods.sodium.client.world.WorldSlice; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java index 3a55ed8db..6fd3dbdb7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/quad/properties/ModelQuadFlags.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.quad.properties; -import com.gtnewhorizons.angelica.compat.Axis; +import com.gtnewhorizons.angelica.compat.mojang.Axis; import com.gtnewhorizons.angelica.compat.nd.Quad; import net.minecraftforge.common.util.ForgeDirection; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java index c2c8bac33..699beaf0b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/VertexDrain.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.vertex; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.type.VertexType; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java index ff6436c72..c4e94727c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/fallback/VertexWriterFallback.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.vertex.fallback; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java index 2e64f800c..99f6dc181 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexSink.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph; -import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java index 2be896c8a..8e51e6c7b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/GlyphVertexType.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer.GlyphVertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer.GlyphVertexBufferWriterUnsafe; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java index 3eb3adbf2..56ec13a2a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/glyph/writer/GlyphVertexWriterFallback.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.writer; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.formats.glyph.GlyphVertexSink; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java index ea8f06945..f0170431c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexSink.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.line; -import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java index 5e2ca5f05..eca743691 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/LineVertexType.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.line; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer.LineVertexBufferWriterUnsafe; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java index 205d8fa15..83ea76e0a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/line/writer/LineVertexWriterFallback.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.line.writer; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.formats.line.LineVertexSink; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java index c0f975818..3e9b68465 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexSink.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.particle; -import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java index cdaff0e62..b333f1534 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/ParticleVertexType.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.particle; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer.ParticleVertexBufferWriterUnsafe; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java index 7d11cb0fd..58fc32a67 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/particle/writer/ParticleVertexWriterFallback.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.particle.writer; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.formats.particle.ParticleVertexSink; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java index cea8c2d02..f34a41d1a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexSink.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.quad; -import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java index 094c9e9fe..eae76e6ff 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/QuadVertexType.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.quad; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer.QuadVertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer.QuadVertexBufferWriterUnsafe; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java index 4c85cf9a4..eafc795ba 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/quad/writer/QuadVertexWriterFallback.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.quad.writer; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.formats.quad.QuadVertexSink; import me.jellysquid.mods.sodium.client.util.Norm3b; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java index e0d7836d2..84bea99f8 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexSink.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad; -import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; import me.jellysquid.mods.sodium.client.util.math.Matrix4fExtended; import me.jellysquid.mods.sodium.client.util.math.MatrixUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java index 796dd3e70..1b2527ccc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/BasicScreenQuadVertexType.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexBufferWriterNio; import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer.BasicScreenQuadVertexBufferWriterUnsafe; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java index 6633bc48f..5a1922e12 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/formats/screen_quad/writer/BasicScreenQuadVertexWriterFallback.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.writer; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.fallback.VertexWriterFallback; import me.jellysquid.mods.sodium.client.model.vertex.formats.screen_quad.BasicScreenQuadVertexSink; import me.jellysquid.mods.sodium.client.util.color.ColorABGR; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java index 50aa85301..e6b510ceb 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VanillaVertexType.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.vertex.type; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import me.jellysquid.mods.sodium.client.gl.attribute.BufferVertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java index e12fccd6d..689c2a9ee 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/model/vertex/type/VertexType.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.model.vertex.type; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import me.jellysquid.mods.sodium.client.model.vertex.VertexSink; /** diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java index 6950359c9..65535adf1 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.shadows.ShadowRenderingState; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 6b3664e5e..373c42dd5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.client.render; -import com.gtnewhorizons.angelica.compat.Camera; -import com.gtnewhorizons.angelica.compat.ChunkPos; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.glsm.GLStateManager; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java index 8472ebc9d..f45907e31 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderBackend.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import me.jellysquid.mods.sodium.client.gl.device.CommandList; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java index fabb1298c..3c9e1684e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderContainer.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import lombok.Getter; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 0650284f3..ddbc42c13 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.render.chunk; -import com.gtnewhorizons.angelica.compat.Camera; -import com.gtnewhorizons.angelica.compat.ChunkPos; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.mojang.ChunkPos; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import com.gtnewhorizons.angelica.config.AngelicaConfig; import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.ints.IntList; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java index a5fcbae6d..aeb88fbcf 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/backends/multidraw/ChunkDrawCallBatcher.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.chunk.backends.multidraw; import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; -import com.gtnewhorizons.angelica.compat.CompatMathHelper; +import com.gtnewhorizons.angelica.compat.mojang.CompatMathHelper; import me.jellysquid.mods.sodium.client.SodiumClientMod; import org.lwjgl.MemoryUtil; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java index 317adad30..c718516f4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/ChunkCuller.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.cull; -import com.gtnewhorizons.angelica.compat.Camera; +import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionData; import it.unimi.dsi.fastutil.ints.IntArrayList; import me.jellysquid.mods.sodium.client.util.math.FrustumExtended; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java index a24fa354f..ad8c891d6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/cull/graph/ChunkGraphCuller.java @@ -1,9 +1,9 @@ package me.jellysquid.mods.sodium.client.render.chunk.cull.graph; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.Camera; +import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionData; -import com.gtnewhorizons.angelica.compat.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java index 54430fd90..4a06495ab 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.data; -import com.gtnewhorizons.angelica.compat.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; public class ChunkRenderBounds { public static final ChunkRenderBounds ALWAYS_FALSE = new ChunkRenderBounds(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java index 28eb51845..5bb9db6ec 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/hfp/HFPModelVertexType.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.format.hfp; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java index b778e54ea..388a2c8a3 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/format/sfp/SFPModelVertexType.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.format.sfp; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java index 3bcf773f6..f24860fd0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/region/ChunkRegionManager.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.region; -import com.gtnewhorizons.angelica.compat.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectIterator; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java index b622a2310..f2e05b687 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.shader; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; import me.jellysquid.mods.sodium.client.render.GameRendererContext; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java index 79a8b8c1f..accd9ea15 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkRenderShaderBackend.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.shader; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.glsm.GLStateManager; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index 34ee39bac..ec05b5d48 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -1,7 +1,7 @@ package me.jellysquid.mods.sodium.client.render.pipeline; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import com.gtnewhorizons.angelica.compat.nd.Quad; import com.gtnewhorizons.angelica.compat.nd.RecyclingList; import com.gtnewhorizons.angelica.config.AngelicaConfig; @@ -16,7 +16,6 @@ import me.jellysquid.mods.sodium.client.render.chunk.data.ChunkRenderData; import me.jellysquid.mods.sodium.client.render.chunk.format.ModelVertexSink; import me.jellysquid.mods.sodium.client.util.ModelQuadUtil; -import me.jellysquid.mods.sodium.client.util.color.ColorABGR; import me.jellysquid.mods.sodium.client.util.rand.XoRoShiRoRandom; import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.minecraft.block.Block; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java index 1904deba9..1d1e45c93 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.client.render.pipeline; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; -import com.gtnewhorizons.angelica.compat.mojang.VoxelShapes; +import com.gtnewhorizons.angelica.compat.toremove.VoxelShape; +import com.gtnewhorizons.angelica.compat.toremove.VoxelShapes; import com.gtnewhorizons.angelica.config.AngelicaConfig; import me.jellysquid.mods.sodium.client.model.light.LightMode; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index fcc4edff9..10c446c1e 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -2,8 +2,8 @@ import java.util.Arrays; -import com.gtnewhorizons.angelica.compat.ChunkSectionPos; -import com.gtnewhorizons.angelica.compat.CompatMathHelper; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.CompatMathHelper; import lombok.Getter; import me.jellysquid.mods.sodium.client.world.cloned.ChunkRenderContext; import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSection; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java index 031188510..19dfd8d01 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ChunkRenderContext.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.world.cloned; -import com.gtnewhorizons.angelica.compat.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import net.minecraft.world.gen.structure.StructureBoundingBox; public class ChunkRenderContext { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java index d65a826b9..e47db970c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSection.java @@ -2,7 +2,7 @@ import com.gtnewhorizons.angelica.compat.ExtendedBlockStorageExt; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; import lombok.Getter; diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java index 48f358e1c..3d2866520 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/cloned/ClonedChunkSectionCache.java @@ -1,6 +1,6 @@ package me.jellysquid.mods.sodium.client.world.cloned; -import com.gtnewhorizons.angelica.compat.ChunkSectionPos; +import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos; import it.unimi.dsi.fastutil.longs.Long2ReferenceLinkedOpenHashMap; import net.minecraft.world.World; diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java b/src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java index e3f553ea4..29bc02a45 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java @@ -1,8 +1,8 @@ package me.jellysquid.mods.sodium.common.util; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.mojang.VoxelShape; -import com.gtnewhorizons.angelica.compat.mojang.VoxelShapes; +import com.gtnewhorizons.angelica.compat.toremove.VoxelShape; +import com.gtnewhorizons.angelica.compat.toremove.VoxelShapes; import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; import net.minecraft.block.material.Material; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java index 2eeec5207..cbc55d128 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl; -import com.gtnewhorizons.angelica.compat.mojang.DrawState; +import com.gtnewhorizons.angelica.compat.toremove.DrawState; import java.nio.ByteBuffer; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java index 95743c818..237aa54f4 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegment.java @@ -1,7 +1,7 @@ package net.coderbot.batchedentityrendering.impl; -import com.gtnewhorizons.angelica.compat.mojang.DrawState; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.DrawState; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import lombok.Getter; import java.nio.ByteBuffer; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java index 3f11be082..fc84c7d7a 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl; -import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; +import com.gtnewhorizons.angelica.compat.toremove.BufferBuilder; public class BufferSegmentRenderer { private final BufferBuilder fakeBufferBuilder; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java index 40878c78c..5185de38b 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java @@ -2,10 +2,10 @@ import net.coderbot.batchedentityrendering.impl.ordering.GraphTranslucencyRenderOrderManager; import net.coderbot.batchedentityrendering.impl.ordering.RenderOrderManager; -import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; -import com.gtnewhorizons.angelica.compat.mojang.BufferSource; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.BufferBuilder; +import com.gtnewhorizons.angelica.compat.toremove.BufferSource; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import net.coderbot.iris.fantastic.WrappingMultiBufferSource; import net.minecraft.client.Minecraft; import net.minecraft.profiler.Profiler; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java index 01256851c..aedfaf27f 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java @@ -2,10 +2,10 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; -import com.gtnewhorizons.angelica.compat.mojang.BufferSource; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.BufferBuilder; +import com.gtnewhorizons.angelica.compat.toremove.BufferSource; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java index 2ad098b6a..4598c89bb 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import org.lwjgl.opengl.GL11; public class RenderTypeUtil { diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java b/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java index 6efd95852..c417cb477 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java @@ -1,10 +1,10 @@ package net.coderbot.batchedentityrendering.impl; -import com.gtnewhorizons.angelica.compat.mojang.BufferBuilder; -import com.gtnewhorizons.angelica.compat.mojang.DrawState; -import com.gtnewhorizons.angelica.compat.mojang.MultiBufferSource; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.BufferBuilder; +import com.gtnewhorizons.angelica.compat.toremove.DrawState; +import com.gtnewhorizons.angelica.compat.toremove.MultiBufferSource; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import org.apache.commons.lang3.tuple.Pair; import java.nio.ByteBuffer; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java b/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java index 026ea5ad8..999986295 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/WrappableRenderType.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; public interface WrappableRenderType { /** diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java index fbdda0129..9d6d18db3 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/GraphTranslucencyRenderOrderManager.java @@ -10,7 +10,7 @@ import net.coderbot.batchedentityrendering.impl.BlendingStateHolder; import net.coderbot.batchedentityrendering.impl.TransparencyType; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import java.util.ArrayList; import java.util.EnumMap; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java index b3067c008..d04a89bd0 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/RenderOrderManager.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl.ordering; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; public interface RenderOrderManager { void begin(RenderLayer type); diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java index c3ecb0235..ff31730a1 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/SimpleRenderOrderManager.java @@ -1,6 +1,6 @@ package net.coderbot.batchedentityrendering.impl.ordering; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import java.util.LinkedHashSet; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java index 6a210b775..d0ff81d81 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/ordering/TranslucencyRenderOrderManager.java @@ -3,7 +3,7 @@ import net.coderbot.batchedentityrendering.impl.BlendingStateHolder; import net.coderbot.batchedentityrendering.impl.TransparencyType; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import java.util.ArrayList; import java.util.EnumMap; diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java index 02553ba5a..1805a8c07 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java @@ -1,7 +1,7 @@ package net.coderbot.batchedentityrendering.impl.wrappers; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import org.jetbrains.annotations.Nullable; import java.util.Objects; diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java index e6bee3c80..544af3fa1 100644 --- a/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockMaterialMapping.java @@ -1,6 +1,6 @@ package net.coderbot.iris.block_rendering; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; diff --git a/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java index a234d6662..cbe345740 100644 --- a/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java +++ b/src/main/java/net/coderbot/iris/block_rendering/BlockRenderingSettings.java @@ -1,6 +1,6 @@ package net.coderbot.iris.block_rendering; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import it.unimi.dsi.fastutil.objects.Object2IntFunction; import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.Getter; diff --git a/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java b/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java index b5d9c3de3..076d3a0b9 100644 --- a/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java +++ b/src/main/java/net/coderbot/iris/fantastic/WrappingMultiBufferSource.java @@ -1,6 +1,6 @@ package net.coderbot.iris.fantastic; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import java.util.function.Function; public interface WrappingMultiBufferSource { diff --git a/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java index fa942e968..67d8ea954 100644 --- a/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/BlockEntityRenderStateShard.java @@ -1,6 +1,6 @@ package net.coderbot.iris.layer; -import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; +import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; import net.coderbot.iris.uniforms.CapturedRenderingState; public final class BlockEntityRenderStateShard extends RenderPhase { diff --git a/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java index 95ca0b5b9..d47d627cb 100644 --- a/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/EntityRenderStateShard.java @@ -1,6 +1,6 @@ package net.coderbot.iris.layer; -import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; +import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; import net.coderbot.iris.uniforms.CapturedRenderingState; public final class EntityRenderStateShard extends RenderPhase { diff --git a/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java index 7b9dfcec3..f18af5669 100644 --- a/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsBlockEntityRenderStateShard.java @@ -1,6 +1,6 @@ package net.coderbot.iris.layer; -import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; +import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; public class IsBlockEntityRenderStateShard extends RenderPhase { public static final IsBlockEntityRenderStateShard INSTANCE = new IsBlockEntityRenderStateShard(); diff --git a/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java index 6fc880954..a3daa0920 100644 --- a/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsEntityRenderStateShard.java @@ -1,6 +1,6 @@ package net.coderbot.iris.layer; -import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; +import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; public class IsEntityRenderStateShard extends RenderPhase { public static final IsEntityRenderStateShard INSTANCE = new IsEntityRenderStateShard(); diff --git a/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java b/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java index 64509ce1e..2c2edc836 100644 --- a/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java +++ b/src/main/java/net/coderbot/iris/layer/IsOutlineRenderStateShard.java @@ -1,6 +1,6 @@ package net.coderbot.iris.layer; -import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; +import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; public class IsOutlineRenderStateShard extends RenderPhase { public static final IsOutlineRenderStateShard INSTANCE = new IsOutlineRenderStateShard(); diff --git a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java index 798414c8b..fef62ee06 100644 --- a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java +++ b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java @@ -1,8 +1,8 @@ package net.coderbot.iris.layer; import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import com.gtnewhorizons.angelica.compat.mojang.RenderPhase; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; import org.jetbrains.annotations.Nullable; import java.util.Objects; diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 6245de3c8..d19e1d7c3 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -3,7 +3,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Ints; -import com.gtnewhorizons.angelica.compat.Camera; +import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.Iris; diff --git a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java index 85968f8fe..efb429135 100644 --- a/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/FixedFunctionWorldRenderingPipeline.java @@ -1,6 +1,6 @@ package net.coderbot.iris.pipeline; -import com.gtnewhorizons.angelica.compat.Camera; +import com.gtnewhorizons.angelica.compat.mojang.Camera; import net.coderbot.iris.block_rendering.BlockRenderingSettings; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; diff --git a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java index 7f9938cf9..c1f84a258 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java @@ -1,9 +1,9 @@ package net.coderbot.iris.pipeline; import net.coderbot.batchedentityrendering.impl.FullyBufferedMultiBufferSource; -import com.gtnewhorizons.angelica.compat.Camera; +import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.InteractionHand; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import net.irisshaders.iris.api.v0.IrisApi; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderGlobal; diff --git a/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java index 13f0da275..5c98e7af8 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HorizonRenderer.java @@ -54,12 +54,12 @@ private void rebuildBuffer() { if (this.vertexBuffer != null) { this.vertexBuffer.close(); } - Tessellator tessellator = Tessellator.instance; + final Tessellator tessellator = Tessellator.instance; // Build the horizon quads into a buffer tessellator.startDrawingQuads(); //(GL11.GL_QUADS, DefaultVertexFormat.POSITION); buildHorizon(currentRenderDistance * 16, tessellator); - ByteBuffer buf = tessellatorToBuffer(tessellator); + final ByteBuffer buf = tessellatorToBuffer(tessellator); ((ITessellatorInstance) tessellator).discard(); this.vertexBuffer = new VertexBuffer(); diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 6f6e65e33..b56e1d297 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -1,9 +1,9 @@ package net.coderbot.iris.pipeline; import com.google.common.collect.ImmutableList; -import com.gtnewhorizons.angelica.compat.mojang.BufferSource; -import com.gtnewhorizons.angelica.compat.Camera; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.BufferSource; +import com.gtnewhorizons.angelica.compat.mojang.Camera; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.rendering.RenderingState; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java index 7a2490f00..3072f29fd 100644 --- a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java @@ -1,6 +1,6 @@ package net.coderbot.iris.pipeline; -import com.gtnewhorizons.angelica.compat.mojang.RenderLayer; +import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; public enum WorldRenderingPhase { NONE, diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java index 3167265fd..4dc2904f0 100644 --- a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPipeline.java @@ -1,6 +1,6 @@ package net.coderbot.iris.pipeline; -import com.gtnewhorizons.angelica.compat.Camera; +import com.gtnewhorizons.angelica.compat.mojang.Camera; import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability; import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition; import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener; diff --git a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java index d7dcb844a..c79d797bc 100644 --- a/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/FullScreenQuadRenderer.java @@ -2,7 +2,7 @@ import com.gtnewhorizons.angelica.glsm.GLStateManager; import net.coderbot.iris.gl.IrisRenderSystem; -import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.DefaultVertexFormat; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java index 9a92801ab..22d6e7f6d 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedCustomTexture.java @@ -1,6 +1,6 @@ package net.coderbot.iris.rendertarget; -import com.gtnewhorizons.angelica.compat.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.shaderpack.texture.CustomTextureData; import net.minecraft.client.renderer.texture.DynamicTexture; diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java index 31cd216c8..fbb7c232c 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedNoiseTexture.java @@ -1,6 +1,6 @@ package net.coderbot.iris.rendertarget; -import com.gtnewhorizons.angelica.compat.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; import net.minecraft.client.renderer.texture.DynamicTexture; import org.lwjgl.opengl.GL11; diff --git a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java index 34d6ea970..2671804d8 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java +++ b/src/main/java/net/coderbot/iris/rendertarget/NativeImageBackedSingleColorTexture.java @@ -1,6 +1,6 @@ package net.coderbot.iris.rendertarget; -import com.gtnewhorizons.angelica.compat.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; import net.minecraft.client.renderer.texture.DynamicTexture; public class NativeImageBackedSingleColorTexture extends DynamicTexture { diff --git a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java index c53220a00..7142d5e73 100644 --- a/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java +++ b/src/main/java/net/coderbot/iris/shadow/ShadowMatrices.java @@ -1,11 +1,9 @@ package net.coderbot.iris.shadow; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import org.joml.Matrix4f; -import java.nio.FloatBuffer; - -import static com.gtnewhorizons.angelica.compat.Constants.DEGREES_TO_RADIANS; +import static com.gtnewhorizons.angelica.compat.mojang.Constants.DEGREES_TO_RADIANS; public class ShadowMatrices { private static final float NEAR = 0.05f; diff --git a/src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java b/src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java index 9bf87b91b..311632a70 100644 --- a/src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java +++ b/src/main/java/net/coderbot/iris/sodium/shader_overrides/ChunkRenderBackendExt.java @@ -1,6 +1,6 @@ package net.coderbot.iris.sodium.shader_overrides; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; public interface ChunkRenderBackendExt { diff --git a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java index dc8c39c41..240927f46 100644 --- a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java +++ b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java @@ -1,6 +1,6 @@ package net.coderbot.iris.sodium.shader_overrides; -import com.gtnewhorizons.angelica.compat.mojang.MatrixStack; +import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkProgram; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderFogComponent; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java index 47631e385..a649ff0be 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterNio.java @@ -1,6 +1,6 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; -import com.gtnewhorizons.angelica.compat.mojang.OverlayTexture; +import com.gtnewhorizons.angelica.compat.toremove.OverlayTexture; 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; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java index 3f44e1045..bbb0e3913 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/EntityVertexBufferWriterUnsafe.java @@ -1,7 +1,7 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; -import com.gtnewhorizons.angelica.compat.mojang.OverlayTexture; +import com.gtnewhorizons.angelica.compat.toremove.OverlayTexture; 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; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java index 24809d274..2961eb041 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedGlyphVertexType.java @@ -1,7 +1,7 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; 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; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java index df7ddbb28..e2c128bd0 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/ExtendedQuadVertexType.java @@ -1,7 +1,7 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; 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; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java index 0ca02f7ef..e2b0d4bce 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterNio.java @@ -1,6 +1,6 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; -import com.gtnewhorizons.angelica.compat.mojang.OverlayTexture; +import com.gtnewhorizons.angelica.compat.toremove.OverlayTexture; 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; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java index f4a9222df..66e087d61 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/entity_xhfp/GlyphVertexBufferWriterUnsafe.java @@ -1,7 +1,7 @@ package net.coderbot.iris.sodium.vertex_format.entity_xhfp; import com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil; -import com.gtnewhorizons.angelica.compat.mojang.OverlayTexture; +import com.gtnewhorizons.angelica.compat.toremove.OverlayTexture; 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; diff --git a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java index 6de447e7d..70e8fd6f3 100644 --- a/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java +++ b/src/main/java/net/coderbot/iris/sodium/vertex_format/terrain_xhfp/XHFPModelVertexType.java @@ -1,6 +1,6 @@ package net.coderbot.iris.sodium.vertex_format.terrain_xhfp; -import com.gtnewhorizons.angelica.compat.mojang.VertexConsumer; +import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexAttributeFormat; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; import me.jellysquid.mods.sodium.client.model.vertex.buffer.VertexBufferView; diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java index e41cdfee8..81d1e4ba8 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/AbstractMipmapGenerator.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.mipmap; -import com.gtnewhorizons.angelica.compat.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; public abstract class AbstractMipmapGenerator implements CustomMipmapGenerator { @Override diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java index 5e7f45699..dd92ad317 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/ChannelMipmapGenerator.java @@ -1,5 +1,5 @@ package net.coderbot.iris.texture.mipmap; -import com.gtnewhorizons.angelica.compat.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; public class ChannelMipmapGenerator extends AbstractMipmapGenerator { protected final BlendFunction redFunc; diff --git a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java index e95820361..acb5b1ef7 100644 --- a/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java +++ b/src/main/java/net/coderbot/iris/texture/mipmap/CustomMipmapGenerator.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.mipmap; -import com.gtnewhorizons.angelica.compat.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; import net.coderbot.iris.texture.pbr.loader.TextureAtlasSpriteInfo; import javax.annotation.Nullable; diff --git a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java index 0a0507861..e239daf3a 100644 --- a/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java +++ b/src/main/java/net/coderbot/iris/texture/pbr/loader/AtlasPBRLoader.java @@ -2,7 +2,7 @@ import com.google.common.collect.Lists; import com.gtnewhorizons.angelica.mixins.interfaces.ISpriteExt; -import com.gtnewhorizons.angelica.compat.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.AnimationMetadataSectionAccessor; import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.TextureAtlasSpriteAccessor; import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.TextureMapAccessor; diff --git a/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java b/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java index e4a7a0db0..365c56355 100644 --- a/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java +++ b/src/main/java/net/coderbot/iris/texture/util/ImageManipulationUtil.java @@ -1,6 +1,6 @@ package net.coderbot.iris.texture.util; -import com.gtnewhorizons.angelica.compat.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; public class ImageManipulationUtil { public static NativeImage scaleNearestNeighbor(NativeImage image, int newWidth, int newHeight) { diff --git a/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java b/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java index e7bbdca1d..4a89d9583 100644 --- a/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java +++ b/src/main/java/net/coderbot/iris/texture/util/TextureExporter.java @@ -1,7 +1,7 @@ package net.coderbot.iris.texture.util; import com.gtnewhorizons.angelica.glsm.GLStateManager; -import com.gtnewhorizons.angelica.compat.NativeImage; +import com.gtnewhorizons.angelica.compat.mojang.NativeImage; import net.minecraft.client.Minecraft; import org.apache.commons.io.FilenameUtils; import org.lwjgl.opengl.GL11; diff --git a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java index f17390d14..a51bcb79a 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CelestialUniforms.java @@ -1,6 +1,6 @@ package net.coderbot.iris.uniforms; -import com.gtnewhorizons.angelica.compat.Constants; +import com.gtnewhorizons.angelica.compat.mojang.Constants; import com.gtnewhorizons.angelica.rendering.RenderingState; import net.coderbot.iris.gl.uniform.UniformHolder; import net.minecraft.client.Minecraft; diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index 6175c005a..72230f52c 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -1,6 +1,6 @@ package net.coderbot.iris.uniforms; -import com.gtnewhorizons.angelica.compat.mojang.TextureAtlas; +import com.gtnewhorizons.angelica.compat.toremove.TextureAtlas; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.glsm.states.BlendState; import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.EntityRendererAccessor; diff --git a/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java b/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java index 15cab7a6a..6814a49a0 100644 --- a/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java +++ b/src/main/java/net/coderbot/iris/vertices/ExtendingBufferBuilder.java @@ -1,6 +1,6 @@ package net.coderbot.iris.vertices; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; public interface ExtendingBufferBuilder { void iris$beginWithoutExtending(int drawMode, VertexFormat vertexFormat); diff --git a/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java b/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java index 9d66a2ad5..4b7edf3f5 100644 --- a/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java +++ b/src/main/java/net/coderbot/iris/vertices/IrisVertexFormats.java @@ -1,8 +1,8 @@ package net.coderbot.iris.vertices; import com.google.common.collect.ImmutableList; -import com.gtnewhorizons.angelica.compat.mojang.DefaultVertexFormat; -import com.gtnewhorizons.angelica.compat.mojang.VertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.DefaultVertexFormat; +import com.gtnewhorizons.angelica.compat.toremove.VertexFormat; import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement; public class IrisVertexFormats { From 4ca9aa2fcb840f7f85b73d481669068b7d645649 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 17 Dec 2023 11:45:18 -0800 Subject: [PATCH 282/301] yeet --- .../compat/toremove/TextureAtlas.java | 20 ------------------- .../iris/uniforms/CommonUniforms.java | 4 ++-- 2 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/TextureAtlas.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/TextureAtlas.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/TextureAtlas.java deleted file mode 100644 index 530e941f2..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/TextureAtlas.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -import net.minecraft.client.renderer.texture.AbstractTexture; -import net.minecraft.client.renderer.texture.ITickable; -import net.minecraft.client.resources.IResourceManager; -import net.minecraft.client.resources.IResourceManagerReloadListener; - -@Deprecated -public abstract class TextureAtlas extends AbstractTexture implements ITickable, IResourceManagerReloadListener { - - @Override - public void tick() { - - } - - @Override - public void onResourceManagerReload(IResourceManager p_110549_1_) { - - } -} diff --git a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java index 72230f52c..d9fdd25d9 100644 --- a/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java +++ b/src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java @@ -1,6 +1,5 @@ package net.coderbot.iris.uniforms; -import com.gtnewhorizons.angelica.compat.toremove.TextureAtlas; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.glsm.states.BlendState; import com.gtnewhorizons.angelica.mixins.early.shaders.accessors.EntityRendererAccessor; @@ -17,6 +16,7 @@ import net.minecraft.block.material.Material; 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; @@ -64,7 +64,7 @@ public static void addCommonUniforms(DynamicUniformHolder uniforms, IdMap idMap, final int glId = GLStateManager.getTextures()[0].binding; final AbstractTexture texture = TextureTracker.INSTANCE.getTexture(glId); - if (texture instanceof TextureAtlas) { + if (texture instanceof TextureMap) { final TextureInfoCache.TextureInfo info = TextureInfoCache.INSTANCE.getInfo(glId); return new Vector2i(info.getWidth(), info.getHeight()); } From dcd4dc1f7a9de204df76fe6703247f5c732f068f Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 17 Dec 2023 11:48:37 -0800 Subject: [PATCH 283/301] yeet more --- .../angelica/compat/forge/IForgeBlockState.java | 5 ----- .../gtnewhorizons/angelica/compat/forge/IModelData.java | 5 ----- .../angelica/compat/forge/VertexBufferConsumer.java | 8 -------- 3 files changed, 18 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBlockState.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/IModelData.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBlockState.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBlockState.java deleted file mode 100644 index 679700acb..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IForgeBlockState.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -public interface IForgeBlockState { - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IModelData.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/IModelData.java deleted file mode 100644 index fb2ed15d0..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/IModelData.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -public interface IModelData { - -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java b/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java deleted file mode 100644 index 4bbaa34e2..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/forge/VertexBufferConsumer.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.gtnewhorizons.angelica.compat.forge; - -import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; - -public class VertexBufferConsumer { - - public void setBuffer(VertexConsumer buffer) {} -} From 39509de00e398b90b3f61e57fba1b13362408639 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Sun, 17 Dec 2023 22:08:34 -0500 Subject: [PATCH 284/301] Move NEI to devOnlyNonPublishable --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index bd85c8860..cfe2ed757 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -52,7 +52,7 @@ dependencies { compileOnly "org.apache.ant:ant:1.8.2" // Because who doesn't want NEI - compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.4.9-GTNH:dev') + devOnlyNonPublishable('com.github.GTNewHorizons:NotEnoughItems:2.4.9-GTNH:dev') // Notfine Deps compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev") From 573ee464be05cb4aa6a13458fedc31ffc46581c9 Mon Sep 17 00:00:00 2001 From: Caedis Date: Mon, 18 Dec 2023 07:20:46 -0600 Subject: [PATCH 285/301] Initial iris scrollbar clicking --- .../iris/gui/element/IrisGuiSlot.java | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java b/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java index 43f5fa827..26b5b4379 100644 --- a/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java +++ b/src/main/java/net/coderbot/iris/gui/element/IrisGuiSlot.java @@ -12,6 +12,7 @@ // TODO: look into GuiListExtended & GuiSelectStringEntries public abstract class IrisGuiSlot extends GuiSlot { @Setter @Getter protected boolean renderBackground = true; + boolean scrolling = false; protected IrisGuiSlot(Minecraft mc, int width, int height, int top, int bottom, int slotHeight) { super(mc, width, height, top, bottom, slotHeight); @@ -22,7 +23,7 @@ protected IrisGuiSlot(Minecraft mc, int width, int height, int top, int bottom, @Override protected void drawContainerBackground(Tessellator tessellator) { - if(this.renderBackground) { + if (this.renderBackground) { super.drawContainerBackground(tessellator); } } @@ -41,6 +42,7 @@ protected void drawSelectionBox(int x, int y, int mouseX, int mouseY) { super.drawSelectionBox(x, y, mouseX, mouseY); this.headerPadding = oldPadding; } + @Override protected void elementClicked(int index, boolean doubleClick, int mouseX, int mouseY) { // Do nothing @@ -51,7 +53,7 @@ protected boolean elementClicked(int index, boolean doubleClick, int mouseX, int } public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) { - if(!this.func_148125_i/*enabled*/()) { + if (!this.func_148125_i/*enabled*/()) { return false; } final int size = this.getSize(); @@ -63,17 +65,14 @@ public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) { boolean handled = false; final boolean leftMouseDown = Mouse.isButtonDown(0); final boolean rightMouseDown = Mouse.isButtonDown(1); - boolean scrolling = false; if (mouseX <= this.left || mouseX >= this.right || mouseY <= this.top || mouseY >= this.bottom) { return handled; } if (leftMouseDown && mouseX >= scrollBarX && mouseX <= rightEdge) { - // TODO: Handle scrolling scrolling = true; - } - - if ((leftMouseDown || rightMouseDown)) { + this.initialClickY = (float) mouseY; + } else if ((leftMouseDown || rightMouseDown)) { final int index = relativeY / this.slotHeight; if (mouseX >= elementLeft && mouseX <= elementRight && index >= 0 && relativeY >= 0 && index < size) { @@ -91,6 +90,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) { } public boolean mouseReleased(int mouseX, int mouseY, int button) { + scrolling = false; return false; } @@ -104,18 +104,23 @@ public void drawScreen(int mouseX, int mouseY, float partialTicks) { final byte offset = 4; - // Scrollwheel nonsense - for (; !this.mc.gameSettings.touchscreen && Mouse.next(); this.mc.currentScreen.handleMouseInput()) { - int dWheel = Mouse.getEventDWheel(); + // Scrollbar nonsense + if (scrolling) { + this.amountScrolled += ((float) mouseY - this.initialClickY); + this.initialClickY = mouseY; + } else { + for (; !this.mc.gameSettings.touchscreen && Mouse.next(); this.mc.currentScreen.handleMouseInput()) { + int dWheel = Mouse.getEventDWheel(); - if (dWheel != 0) { - if (dWheel > 0) { - dWheel = -1; - } else { - dWheel = 1; - } + if (dWheel != 0) { + if (dWheel > 0) { + dWheel = -1; + } else { + dWheel = 1; + } - this.amountScrolled += (dWheel * this.slotHeight / 2.0f); + this.amountScrolled += (dWheel * this.slotHeight / 2.0f); + } } } From 25a041d8a82dc30dfac798f58e9d597039397166 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 19 Dec 2023 09:52:25 -0500 Subject: [PATCH 286/301] Punt unsupported ISBRHs to the main thread --- .../early/sodium/MixinRenderGlobal.java | 2 + .../rendering/AngelicaRenderQueue.java | 52 ++++++++++++ .../render/chunk/compile/ChunkBuilder.java | 15 +++- .../chunk/tasks/ChunkRenderRebuildTask.java | 80 +++++++++++++++++++ .../util/collections/FutureDequeDrain.java | 3 + 5 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaRenderQueue.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index ce8170b24..edee622f7 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; +import com.gtnewhorizons.angelica.rendering.AngelicaRenderQueue; import com.gtnewhorizons.angelica.rendering.RenderingState; import lombok.Getter; @@ -134,6 +135,7 @@ public void markRenderersForNewPosition(int p_72722_1_, int p_72722_2_, int p_72 */ @Overwrite public boolean updateRenderers(EntityLivingBase e, boolean b){ + AngelicaRenderQueue.processTasks(1); return true; } diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaRenderQueue.java b/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaRenderQueue.java new file mode 100644 index 000000000..fb2058784 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaRenderQueue.java @@ -0,0 +1,52 @@ +package com.gtnewhorizons.angelica.rendering; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.LockSupport; +import java.util.function.BooleanSupplier; + +public class AngelicaRenderQueue { + private static final Thread MAIN_THREAD = Thread.currentThread(); + private static final Queue TASKS = new ConcurrentLinkedQueue<>(); + + private static final Executor EXECUTOR = (runnable) -> { + if(Thread.currentThread() == MAIN_THREAD) { + runnable.run(); + } else { + TASKS.add(runnable); + LockSupport.unpark(MAIN_THREAD); + } + }; + + public static Executor executor() { + return EXECUTOR; + } + + public static int processTasks(int max) { + int tasksRun = 0; + while(tasksRun < max) { + Runnable r = TASKS.poll(); + if(r == null) + break; + r.run(); + tasksRun++; + } + return tasksRun; + } + + public static int processTasks() { + return processTasks(Integer.MAX_VALUE); + } + + private static final long WAIT_TIME = TimeUnit.MILLISECONDS.toNanos(50); + + public static void managedBlock(BooleanSupplier isDone) { + while(!isDone.getAsBoolean()) { + if(AngelicaRenderQueue.processTasks(1) == 0) { + LockSupport.parkNanos(WAIT_TIME); + } + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java index 5e99fc6cc..cb2335ff9 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; +import com.gtnewhorizons.angelica.rendering.AngelicaRenderQueue; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.model.vertex.type.ChunkVertexType; @@ -100,6 +101,15 @@ public void startWorkers() { LOGGER.info("Started {} worker threads", this.threads.size()); } + private boolean workersAlive() { + for (Thread thread : this.threads) { + if (thread.isAlive()) { + return true; + } + } + return false; + } + /** * Notifies all worker threads to stop and blocks until all workers terminate. After the workers have been shut * down, all tasks are cancelled and the pending queues are cleared. If the builder is already stopped, this @@ -121,7 +131,10 @@ public void stopWorkers() { this.jobNotifier.notifyAll(); } - // Wait for every remaining thread to terminate + // Keep processing the main thread tasks so the workers don't block forever + AngelicaRenderQueue.managedBlock(() -> !workersAlive()); + + // Ensure every remaining thread has terminated for (Thread thread : this.threads) { try { thread.join(); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index abb37cc7c..7f7948495 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionDataBuilder; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.glsm.TessellatorManager; +import com.gtnewhorizons.angelica.rendering.AngelicaRenderQueue; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer; @@ -31,6 +32,9 @@ import net.minecraftforge.fluids.IFluidBlock; import org.joml.Vector3d; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + /** * Rebuilds all the meshes of a chunk for each given render pass with non-occluded blocks. The result is then uploaded * to graphics memory on the main thread. @@ -82,6 +86,10 @@ private boolean rendersOutsideBoundingBox(TileEntity entity, int baseX, int base return false; } + private boolean rendersOffThread(int type) { + return type < 42 && type != 22; + } + @Override public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildBuffers buffers, CancellationSource cancellationSource) { // COMPATIBLITY NOTE: Oculus relies on the LVT of this method being unchanged, at least in 16.5 @@ -104,6 +112,8 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB BlockPos renderOffset = this.offset; final Tessellator tessellator = TessellatorManager.get(); + boolean hasMainThreadBlocks = false; + for (int relY = 0; relY < 16; relY++) { if (cancellationSource.isCancelled()) { return null; @@ -119,6 +129,11 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB continue; } + if (!rendersOffThread(block.getRenderType())) { + hasMainThreadBlocks = true; + continue; + } + int meta = slice.getBlockMetadataRelative(relX + 16, relY + 16, relZ + 16); pos.set(baseX + relX, baseY + relY, baseZ + relZ); @@ -168,6 +183,20 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB } } + if(hasMainThreadBlocks) { + // Render the other blocks on the main thread + try { + CompletableFuture.runAsync(() -> this.performMainBuild(cache, buffers, cancellationSource, bounds), AngelicaRenderQueue.executor()).get(); + } catch(InterruptedException e) { + Thread.currentThread().interrupt(); + return null; + } catch(ExecutionException e) { + throw new RuntimeException(e); + } + // Check if cancellation happened during that, so we don't render an incomplete chunk + if(cancellationSource.isCancelled()) return null; + } + render.setRebuildForTranslucents(false); for (BlockRenderPass pass : BlockRenderPass.VALUES) { ChunkMeshData mesh = buffers.createMesh(pass, (float)camera.x - offset.getX(), (float)camera.y - offset.getY(), (float)camera.z - offset.getZ(), this.translucencySorting); @@ -185,6 +214,57 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB return new ChunkBuildResult<>(this.render, renderData.build()); } + /** + * Render the blocks that should be rendered on the main thread. + * + * TODO: Deduplicate this with the main method above. + */ + private void performMainBuild(ChunkRenderCacheLocal cache, ChunkBuildBuffers buffers, CancellationSource cancellationSource, ChunkRenderBounds.Builder bounds) { + WorldSlice slice = cache.getWorldSlice(); + BlockPos.Mutable pos = new BlockPos.Mutable(); + int baseX = this.render.getOriginX(); + int baseY = this.render.getOriginY(); + int baseZ = this.render.getOriginZ(); + BlockPos renderOffset = this.offset; + RenderBlocks rb = new RenderBlocks(slice); + for (int relY = 0; relY < 16; relY++) { + if (cancellationSource.isCancelled()) { + return; + } + for (int relZ = 0; relZ < 16; relZ++) { + for (int relX = 0; relX < 16; relX++) { + Block block = slice.getBlockRelative(relX + 16, relY + 16, relZ + 16); + + // Only render blocks that need main thread assistance + if (block.getMaterial() == Material.air || rendersOffThread(block.getRenderType())) { + continue; + } + + // TODO: Collect data on which render types are hitting this code path most often + // so mods can be updated slowly + + int meta = slice.getBlockMetadataRelative(relX + 16, relY + 16, relZ + 16); + + pos.set(baseX + relX, baseY + relY, baseZ + relZ); + buffers.setRenderOffset(pos.x - renderOffset.getX(), pos.y - renderOffset.getY(), pos.z - renderOffset.getZ()); + if(AngelicaConfig.enableIris) buffers.iris$setLocalPos(relX, relY, relZ); + + // Do regular block rendering + for (BlockRenderPass pass : BlockRenderPass.VALUES) { + if (block.canRenderInPass(pass.ordinal()) && (!AngelicaConfig.enableSodiumFluidRendering || !(block instanceof IFluidBlock))) { + long seed = MathUtil.hashPos(pos.x, pos.y, pos.z); + if(AngelicaConfig.enableIris) buffers.iris$setMaterialId(block, ExtendedDataHelper.BLOCK_RENDER_TYPE); + + if (cache.getBlockRenderer().renderModel(cache.getWorldSlice(), Tessellator.instance, rb, block, meta, pos, buffers.get(pass), true, seed)) { + bounds.addBlock(relX, relY, relZ); + } + } + } + } + } + } + } + @Override public void releaseResources() { this.context.releaseResources(); diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java b/src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java index 69c5e72fd..7218be3c7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/collections/FutureDequeDrain.java @@ -1,5 +1,7 @@ package me.jellysquid.mods.sodium.common.util.collections; +import com.gtnewhorizons.angelica.rendering.AngelicaRenderQueue; + import java.util.Deque; import java.util.Iterator; import java.util.NoSuchElementException; @@ -30,6 +32,7 @@ private void findNext() { CompletableFuture future = deque.remove(); try { + AngelicaRenderQueue.managedBlock(future::isDone); next = future.join(); return; } catch (CancellationException e) { From 1869b22d767845bb4f99b8854ac81448a819a946 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 19 Dec 2023 09:52:59 -0500 Subject: [PATCH 287/301] Delete the ISBRH lock, shouldn't be needed anymore --- .../gtnewhorizons/angelica/mixins/Mixins.java | 1 - .../early/sodium/MixinRenderingRegistry.java | 21 ------- .../AngelicaBlockRenderingHandler.java | 56 ------------------- 3 files changed, 78 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderingRegistry.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockRenderingHandler.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 9579e4c49..180eba4cb 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -96,7 +96,6 @@ public enum Mixins { ,"sodium.MixinTessellator" ,"sodium.MixinGuiIngameForge" ,"sodium.MixinEffectRenderer" - ,"sodium.MixinRenderingRegistry" // TODO Doesn't work correctly //,"sodium.MixinTextureAtlasSprite" //,"sodium.MixinTextureMap" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderingRegistry.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderingRegistry.java deleted file mode 100644 index 0008bf28e..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderingRegistry.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.early.sodium; - -import com.gtnewhorizons.angelica.rendering.AngelicaBlockRenderingHandler; -import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; -import cpw.mods.fml.client.registry.RenderingRegistry; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyVariable; - -@Mixin(RenderingRegistry.class) -public class MixinRenderingRegistry { - @ModifyVariable(method = "registerBlockHandler(Lcpw/mods/fml/client/registry/ISimpleBlockRenderingHandler;)V", at = @At("HEAD"), index = 0, argsOnly = true, remap = false) - private static ISimpleBlockRenderingHandler getThreadSafeWrapper(ISimpleBlockRenderingHandler handler) { - return AngelicaBlockRenderingHandler.forHandler(handler); - } - - @ModifyVariable(method = "registerBlockHandler(ILcpw/mods/fml/client/registry/ISimpleBlockRenderingHandler;)V", at = @At("HEAD"), index = 1, argsOnly = true, remap = false) - private static ISimpleBlockRenderingHandler getThreadSafeWrapper2(ISimpleBlockRenderingHandler handler) { - return AngelicaBlockRenderingHandler.forHandler(handler); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockRenderingHandler.java b/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockRenderingHandler.java deleted file mode 100644 index 0bfc054d6..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockRenderingHandler.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.gtnewhorizons.angelica.rendering; - -import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; -import net.minecraft.block.Block; -import net.minecraft.client.renderer.RenderBlocks; -import net.minecraft.world.IBlockAccess; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.Map; - -public class AngelicaBlockRenderingHandler implements ISimpleBlockRenderingHandler { - private final ISimpleBlockRenderingHandler delegate; - private static final Map HANDLERS = Collections.synchronizedMap(new IdentityHashMap<>()); - private static final Logger LOGGER = LogManager.getLogger("Angelica"); - - public static ISimpleBlockRenderingHandler forHandler(ISimpleBlockRenderingHandler delegate) { - return HANDLERS.computeIfAbsent(delegate, h -> { - // TODO add whitelist - LOGGER.warn("Renderer {} will be synchronized, which may degrade performance", h.getClass().getName()); - return new AngelicaBlockRenderingHandler(h); - }); - } - - private AngelicaBlockRenderingHandler(ISimpleBlockRenderingHandler delegate) { - this.delegate = delegate; - } - - @Override - public void renderInventoryBlock(Block block, int metadata, int modelId, RenderBlocks renderer) { - synchronized (AngelicaBlockRenderingHandler.class) { - this.delegate.renderInventoryBlock(block, metadata, modelId, renderer); - } - } - - @Override - public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { - synchronized (AngelicaBlockRenderingHandler.class) { - return this.delegate.renderWorldBlock(world, x, y, z, block, modelId, renderer); - } - } - - @Override - public boolean shouldRender3DInInventory(int modelId) { - synchronized (AngelicaBlockRenderingHandler.class) { - return this.delegate.shouldRender3DInInventory(modelId); - } - } - - @Override - public int getRenderId() { - return this.delegate.getRenderId(); - } -} From c5cd94f45026248bba08f5be39a421a9b5d82499 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Tue, 19 Dec 2023 11:47:19 -0500 Subject: [PATCH 288/301] Render GT blocks on main thread --- .../AngelicaBlockSafetyRegistry.java | 47 +++++++++++++++++++ .../chunk/tasks/ChunkRenderRebuildTask.java | 10 ++-- 2 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockSafetyRegistry.java diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockSafetyRegistry.java b/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockSafetyRegistry.java new file mode 100644 index 000000000..b857a97b7 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/rendering/AngelicaBlockSafetyRegistry.java @@ -0,0 +1,47 @@ +package com.gtnewhorizons.angelica.rendering; + +import it.unimi.dsi.fastutil.objects.Reference2BooleanMap; +import it.unimi.dsi.fastutil.objects.Reference2BooleanOpenHashMap; +import net.minecraft.block.Block; + +import java.util.concurrent.locks.StampedLock; + +public class AngelicaBlockSafetyRegistry { + private static final Reference2BooleanMap SAFETY_MAP = new Reference2BooleanOpenHashMap<>(); + private static final StampedLock LOCK = new StampedLock(); + + public static boolean canBlockRenderOffThread(Block block) { + long stamp = LOCK.readLock(); + boolean isOffThread, shouldPopulate; + try { + isOffThread = SAFETY_MAP.getBoolean(block); + if (isOffThread) { + return true; // no need to check if 'false' was due to not being populated + } + + shouldPopulate = !SAFETY_MAP.containsKey(block); + } finally { + LOCK.unlock(stamp); + } + + if(shouldPopulate) { + isOffThread = populateCanRenderOffThread(block); + } + + return isOffThread; + } + + private static boolean populateCanRenderOffThread(Block block) { + boolean canBeOffThread = !(block.getClass().getName().startsWith("gregtech.")); + + long stamp = LOCK.writeLock(); + + try { + SAFETY_MAP.put(block, canBeOffThread); + } finally { + LOCK.unlock(stamp); + } + + return canBeOffThread; + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 7f7948495..93c245251 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -4,6 +4,7 @@ import com.gtnewhorizons.angelica.compat.mojang.ChunkOcclusionDataBuilder; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.glsm.TessellatorManager; +import com.gtnewhorizons.angelica.rendering.AngelicaBlockSafetyRegistry; import com.gtnewhorizons.angelica.rendering.AngelicaRenderQueue; import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; @@ -86,8 +87,9 @@ private boolean rendersOutsideBoundingBox(TileEntity entity, int baseX, int base return false; } - private boolean rendersOffThread(int type) { - return type < 42 && type != 22; + private boolean rendersOffThread(Block block) { + int type = block.getRenderType(); + return type < 42 && type != 22 && AngelicaBlockSafetyRegistry.canBlockRenderOffThread(block); } @Override @@ -129,7 +131,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB continue; } - if (!rendersOffThread(block.getRenderType())) { + if (!rendersOffThread(block)) { hasMainThreadBlocks = true; continue; } @@ -236,7 +238,7 @@ private void performMainBuild(ChunkRenderCacheLocal cache, ChunkBuildBuffers buf Block block = slice.getBlockRelative(relX + 16, relY + 16, relZ + 16); // Only render blocks that need main thread assistance - if (block.getMaterial() == Material.air || rendersOffThread(block.getRenderType())) { + if (block.getMaterial() == Material.air || rendersOffThread(block)) { continue; } From 00b583f227fc990e4599bddd5e3b982114d24347 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 23 Dec 2023 10:11:33 -0800 Subject: [PATCH 289/301] misc --- .../angelica/compat/mojang/Camera.java | 5 +- .../mojang/ChunkOcclusionDataBuilder.java | 73 +++++++++---------- .../compat/toremove/VertexFormat.java | 1 - .../transform/RedirectorTransformer.java | 8 +- 4 files changed, 41 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java index 7fd8d6f4b..07f8c0297 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/Camera.java @@ -1,16 +1,13 @@ package com.gtnewhorizons.angelica.compat.mojang; -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; +import com.gtnewhorizons.angelica.rendering.RenderingState; import lombok.Getter; import net.minecraft.client.Minecraft; import net.minecraft.entity.EntityLivingBase; - import org.joml.Matrix4f; import org.joml.Vector3d; import org.joml.Vector4f; -import com.gtnewhorizons.angelica.rendering.RenderingState; - @Getter public class Camera { final Vector3d pos = new Vector3d(); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java index 9a91cc87a..e4e1eb7a4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ChunkOcclusionDataBuilder.java @@ -22,8 +22,6 @@ public class ChunkOcclusionDataBuilder { private static final int[] EDGE_POINTS = new int[1352]; static { - int i = 0; - int j = 15; int k = 0; for(int l = 0; l < 16; ++l) { @@ -52,7 +50,7 @@ private static int pack(int x, int y, int z) { } public ChunkOcclusionData build() { - ChunkOcclusionData lv = new ChunkOcclusionData(); + final ChunkOcclusionData lv = new ChunkOcclusionData(); if (4096 - this.openCount < 256) { lv.fill(true); } else if (this.openCount == 0) { @@ -69,17 +67,17 @@ public ChunkOcclusionData build() { } private Set getOpenFaces(int pos) { - Set set = EnumSet.noneOf(ForgeDirection.class); - IntPriorityQueue intPriorityQueue = new IntArrayFIFOQueue(); + final Set set = EnumSet.noneOf(ForgeDirection.class); + final IntPriorityQueue intPriorityQueue = new IntArrayFIFOQueue(); intPriorityQueue.enqueue(pos); this.closed.set(pos, true); while(!intPriorityQueue.isEmpty()) { - int j = intPriorityQueue.dequeueInt(); + final int j = intPriorityQueue.dequeueInt(); this.addEdgeFaces(j, set); for(ForgeDirection lv : DIRECTIONS) { - int k = this.offset(j, lv); + final int k = this.offset(j, lv); if (k >= 0 && !this.closed.get(k)) { this.closed.set(k, true); intPriorityQueue.enqueue(k); @@ -91,21 +89,21 @@ private Set getOpenFaces(int pos) { } private void addEdgeFaces(int pos, Set openFaces) { - int j = pos >> 0 & 15; + final int j = pos >> 0 & 15; if (j == 0) { openFaces.add(ForgeDirection.WEST); } else if (j == 15) { openFaces.add(ForgeDirection.EAST); } - int k = pos >> 8 & 15; + final int k = pos >> 8 & 15; if (k == 0) { openFaces.add(ForgeDirection.DOWN); } else if (k == 15) { openFaces.add(ForgeDirection.UP); } - int l = pos >> 4 & 15; + final int l = pos >> 4 & 15; if (l == 0) { openFaces.add(ForgeDirection.NORTH); } else if (l == 15) { @@ -114,45 +112,44 @@ private void addEdgeFaces(int pos, Set openFaces) { } private int offset(int pos, ForgeDirection arg) { - switch(arg) { - case DOWN: + return switch (arg) { + case DOWN -> { if ((pos >> 8 & 15) == 0) { - return -1; + yield -1; } - - return pos - STEP_Y; - case UP: + yield pos - STEP_Y; + } + case UP -> { if ((pos >> 8 & 15) == 15) { - return -1; + yield -1; } - - return pos + STEP_Y; - case NORTH: + yield pos + STEP_Y; + } + case NORTH -> { if ((pos >> 4 & 15) == 0) { - return -1; + yield -1; } - - return pos - STEP_Z; - case SOUTH: + yield pos - STEP_Z; + } + case SOUTH -> { if ((pos >> 4 & 15) == 15) { - return -1; + yield -1; } - - return pos + STEP_Z; - case WEST: + yield pos + STEP_Z; + } + case WEST -> { if ((pos >> 0 & 15) == 0) { - return -1; + yield -1; } - - return pos - STEP_X; - case EAST: + yield pos - STEP_X; + } + case EAST -> { if ((pos >> 0 & 15) == 15) { - return -1; + yield -1; } - - return pos + STEP_X; - default: - return -1; - } + yield pos + STEP_X; + } + default -> -1; + }; } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexFormat.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexFormat.java index 8056827f6..5efd8b511 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexFormat.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexFormat.java @@ -2,7 +2,6 @@ import com.google.common.collect.ImmutableList; import com.gtnewhorizons.angelica.compat.mojang.VertexFormatElement; -import com.gtnewhorizons.angelica.compat.toremove.DefaultVertexFormat; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import lombok.Getter; diff --git a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java index a4b8d25a6..124e84239 100644 --- a/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java +++ b/src/main/java/com/gtnewhorizons/angelica/transform/RedirectorTransformer.java @@ -205,7 +205,8 @@ public byte[] transform(final String className, String transformedName, byte[] b remaps++; } } - } else if (node.getOpcode() == Opcodes.GETSTATIC && node instanceof FieldInsnNode fNode) { + } + else if (node.getOpcode() == Opcodes.GETSTATIC && node instanceof FieldInsnNode fNode) { if ((fNode.name.equals("field_78398_a") || fNode.name.equals("instance")) && fNode.owner.equals(TessellatorClass)) { if (IrisLogging.ENABLE_SPAM) { AngelicaTweaker.LOGGER.info("Redirecting Tessellator.instance field in {} to TessellatorManager.get()", transformedName); @@ -213,7 +214,8 @@ public byte[] transform(final String className, String transformedName, byte[] b mn.instructions.set(node, new MethodInsnNode(Opcodes.INVOKESTATIC, "com/gtnewhorizons/angelica/glsm/TessellatorManager", "get", "()Lnet/minecraft/client/renderer/Tessellator;", false)); changed = true; } - } else if ((node.getOpcode() == Opcodes.GETFIELD || node.getOpcode() == Opcodes.PUTFIELD) && node instanceof FieldInsnNode fNode) { + } + else if ((node.getOpcode() == Opcodes.GETFIELD || node.getOpcode() == Opcodes.PUTFIELD) && node instanceof FieldInsnNode fNode) { if(fNode.owner.equals(BlockClass)) { Pair fieldToRedirect = null; for(Pair blockPairs : BlockBoundsFields) { @@ -236,7 +238,7 @@ public byte[] transform(final String className, String transformedName, byte[] b } else if(node.getOpcode() == Opcodes.PUTFIELD) { // FIXME: this code assumes doubles // Stack: Block, double - InsnList beforePut = new InsnList(); + final InsnList beforePut = new InsnList(); beforePut.add(new InsnNode(Opcodes.DUP2_X1)); // Stack: double, Block, double beforePut.add(new InsnNode(Opcodes.POP2)); From 1bccf448a8ad635bbe6bdaa9c75c1e0052552c51 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sat, 23 Dec 2023 12:47:14 -0800 Subject: [PATCH 290/301] Yeet stuff, enable some features by default --- .../ByteBufferBackedInputStream.java | 10 +- .../angelica/compat/mojang/NativeImage.java | 1 - .../compat/toremove/BlockRenderView.java | 5 - .../compat/toremove/BufferBuilder.java | 157 ----------- .../compat/toremove/BufferSource.java | 15 - .../angelica/compat/toremove/FluidState.java | 41 --- .../compat/toremove/MultiBufferSource.java | 12 - .../compat/toremove/OverlayTexture.java | 1 + .../angelica/compat/toremove/RenderLayer.java | 206 +------------- .../compat/toremove/RenderLayers.java | 31 --- .../compat/toremove/VertexConsumers.java | 73 ----- .../angelica/compat/toremove/VoxelShape.java | 18 -- .../angelica/compat/toremove/VoxelShapes.java | 27 -- .../angelica/config/AngelicaConfig.java | 7 +- .../early/shaders/MixinEntityRenderer.java | 10 +- .../early/sodium/MixinRenderGlobal.java | 3 +- .../client/render/pipeline/FluidRenderer.java | 12 +- .../mods/sodium/common/util/WorldUtil.java | 6 - .../impl/BufferBuilderExt.java | 4 +- .../impl/BufferSegmentRenderer.java | 32 --- .../impl/FullyBufferedMultiBufferSource.java | 259 ------------------ .../OldFullyBufferedMultiBufferSource.java | 145 ---------- .../impl/RenderTypeUtil.java | 10 - .../impl/SegmentedBufferBuilder.java | 100 ------- .../wrappers/TaggingRenderTypeWrapper.java | 69 ----- .../iris/layer/OuterWrappedRenderType.java | 92 ------- .../DeferredWorldRenderingPipeline.java | 2 +- .../coderbot/iris/pipeline/HandRenderer.java | 26 +- .../iris/pipeline/ShadowRenderer.java | 10 +- .../iris/pipeline/WorldRenderingPhase.java | 15 - 30 files changed, 41 insertions(+), 1358 deletions(-) rename src/main/java/com/gtnewhorizons/angelica/compat/{toremove => mojang}/ByteBufferBackedInputStream.java (75%) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/BlockRenderView.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferBuilder.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferSource.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/FluidState.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/MultiBufferSource.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayers.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexConsumers.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShape.java delete mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShapes.java delete mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java delete mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java delete mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java delete mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java delete mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java delete mode 100644 src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java delete mode 100644 src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/ByteBufferBackedInputStream.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java similarity index 75% rename from src/main/java/com/gtnewhorizons/angelica/compat/toremove/ByteBufferBackedInputStream.java rename to src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java index 1f1a0dbb0..e0b61f1ed 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/ByteBufferBackedInputStream.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/ByteBufferBackedInputStream.java @@ -1,10 +1,12 @@ -package com.gtnewhorizons.angelica.compat.toremove; +package com.gtnewhorizons.angelica.compat.mojang; + +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; -@Deprecated + public class ByteBufferBackedInputStream extends InputStream { ByteBuffer buf; @@ -20,8 +22,8 @@ public int read() throws IOException { return buf.get() & 0xFF; } - public int read(byte[] bytes, int off, int len) - throws IOException { + @Override + public int read(byte @NotNull [] bytes, int off, int len) throws IOException { if (!buf.hasRemaining()) { return -1; } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java index c58816eab..03ddd3c51 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java @@ -1,6 +1,5 @@ package com.gtnewhorizons.angelica.compat.mojang; -import com.gtnewhorizons.angelica.compat.toremove.ByteBufferBackedInputStream; import lombok.Getter; import net.coderbot.iris.Iris; import org.lwjgl.BufferUtils; diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BlockRenderView.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BlockRenderView.java deleted file mode 100644 index 31df72e48..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BlockRenderView.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -@Deprecated -public interface BlockRenderView { -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferBuilder.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferBuilder.java deleted file mode 100644 index f70f9ebfe..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferBuilder.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -import net.coderbot.batchedentityrendering.impl.BufferBuilderExt; -import org.apache.commons.lang3.tuple.Pair; -import org.jetbrains.annotations.NotNull; -import org.lwjgl.BufferUtils; - -import java.nio.ByteBuffer; -import java.util.List; - -// This is the Tessellator - TODO: Merge/Overwrite -@Deprecated -public class BufferBuilder implements VertexConsumer, BufferBuilderExt { - private ByteBuffer buffer; - private List vertexCounts; - private int lastRenderedCountIndex; - private int totalRenderedBytes; - private int nextElementByte; - private int totalUploadedBytes; - private int vertices; - private VertexFormat format; - - private boolean dupeNextVertex; - int i; - - public BufferBuilder() { - this(0); - } - - public BufferBuilder(int i) { - this.buffer = BufferUtils.createByteBuffer(i * 4); - } - - public void begin(int glQuads, VertexFormat position) {} - - public void end() {} - - @Override - public VertexConsumer vertex(double d, double e, double f) { - return null; - } - - @NotNull - @Override - public VertexConsumer color(int r, int g, int b, int a) { - return null; - } - - @NotNull - @Override - public VertexConsumer texture(float u, float v) { - return null; - } - - @NotNull - @Override - public VertexConsumer overlay(int u, int v) { - return null; - } - - @NotNull - @Override - public VertexConsumer light(int u, int v) { - return null; - } - - @NotNull - @Override - public VertexConsumer normal(float x, float y, float z) { - return null; - } - - @Override - public void next() { - - } - - public void sortQuads(int i, int i1, int i2) {} - - public Pair popNextBuffer() { - return null; - } - - public void clear() {} - - @Override - public void setupBufferSlice(ByteBuffer buffer, DrawState drawState) { - // add the buffer slice - this.buffer = buffer; - - // add our singular parameter - this.vertexCounts.clear(); - this.vertexCounts.add(drawState); - - // should be zero, just making sure - this.lastRenderedCountIndex = 0; - - // configure the build start (to avoid a warning message) and element offset (probably not important) - this.totalRenderedBytes = drawState.getVertexCount() * drawState.getFormat().getVertexSize(); - this.nextElementByte = this.totalRenderedBytes; - - // should be zero, just making sure - this.totalUploadedBytes = 0; - - // target.vertexCount is never nonzero in this process. - // target.currentElement is never non-null in this process. - // target.currentElementId is never nonzero. - // target.drawMode is irrelevant. - // target.format is irrelevant. - // The final 3 booleans are also irrelevant. - } - - @Override - public void teardownBufferSlice() { - // the parameters got popped by the drawScreen call, we don't need to worry about them - // make sure to un-set the buffer to prevent anything bad from happening with it. - this.buffer = null; - - // target.parameters gets reset. - // target.lastParameterIndex gets reset. - // target.buildStart gets reset. - // target.elementOffset gets reset. - // target.nextDrawStart gets reset. - - // target.vertexCount is never nonzero in this process. - // target.currentElement is never non-null in this process. - // target.currentElementId is never nonzero. - // target.drawMode is irrelevant. - // target.format is irrelevant. - // The final 3 booleans are also irrelevant. - } - - @Override - public void splitStrip() { - if (vertices == 0) { - // no strip to split, not building. - return; - } - - duplicateLastVertex(); - dupeNextVertex = true; - } - - private void duplicateLastVertex() { - int i = this.format.getVertexSize(); - this.buffer.position(this.nextElementByte); - ByteBuffer byteBuffer = this.buffer.duplicate(); - byteBuffer.position(this.nextElementByte - i).limit(this.nextElementByte); - this.buffer.put(byteBuffer); - this.nextElementByte += i; - ++this.vertices; - this.ensureVertexCapacity(); - } - protected void ensureVertexCapacity() { - - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferSource.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferSource.java deleted file mode 100644 index 066385003..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/BufferSource.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -import java.util.Map; - -@Deprecated -public class BufferSource implements MultiBufferSource { - - public BufferSource(BufferBuilder bufferBuilder, Map kvMap) {} - - public VertexConsumer getBuffer(RenderLayer renderType) { - return null; - } - public void endBatch() {} - public void endBatch(RenderLayer type) {} -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/FluidState.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/FluidState.java deleted file mode 100644 index 67d144096..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/FluidState.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import net.minecraft.block.BlockLiquid; -import net.minecraftforge.fluids.Fluid; -import org.joml.Vector3d; - -@Deprecated -public class FluidState { - - private final Fluid fluid; - private final int meta; - - public FluidState(Fluid fluid, int meta) { - this.fluid = fluid; - this.meta = meta; - } - - public boolean isEmpty() { - return fluid == null; - } - - public Fluid getFluid() { - return fluid; - } - - public Vector3d getVelocity(BlockRenderView world, BlockPos pos) { - return new Vector3d(); - } - - public boolean method_15756(BlockRenderView world, BlockPos set) { - return true; - } - - /** - * Returns how much of the block is fluid, from 0 to 1. - */ - public float getHeight(BlockRenderView world, BlockPos pos) { - return fluid == null ? 0 : 1 - BlockLiquid.getLiquidHeightPercent(meta); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/MultiBufferSource.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/MultiBufferSource.java deleted file mode 100644 index 40e244cfe..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/MultiBufferSource.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -import java.util.Map; - -@Deprecated -public interface MultiBufferSource { - static BufferSource immediateWithBuffers(Map map, BufferBuilder arg) { - return new BufferSource(arg, map); - } - - VertexConsumer getBuffer(RenderLayer arg); -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/OverlayTexture.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/OverlayTexture.java index 51f4b5f4b..54a3ab1f1 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/OverlayTexture.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/OverlayTexture.java @@ -1,5 +1,6 @@ package com.gtnewhorizons.angelica.compat.toremove; +@Deprecated public class OverlayTexture { // This is definitely wrong diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayer.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayer.java index e2a473648..38045148e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayer.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayer.java @@ -7,32 +7,13 @@ import net.minecraft.util.ResourceLocation; import javax.annotation.Nullable; -import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.OptionalDouble; public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris) private static final RenderLayer SOLID = of("solid", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 2097152, true, false, RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).build(true)); - private static final RenderLayer CUTOUT_MIPPED = of("cutout_mipped", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 131072, true, false, RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).alpha(HALF_ALPHA).build(true)); private static final RenderLayer CUTOUT = of("cutout", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 131072, true, false, RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(BLOCK_ATLAS_TEXTURE).alpha(HALF_ALPHA).build(true)); private static final RenderLayer TRANSLUCENT = of("translucent", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 262144, true, true, createTranslucentPhaseData()); - private static final RenderLayer TRANSLUCENT_MOVING_BLOCK = of("translucent_moving_block", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 262144, false, true, getItemPhaseData()); - private static final RenderLayer TRANSLUCENT_NO_CRUMBLING = of("translucent_no_crumbling", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 262144, false, true, createTranslucentPhaseData()); - private static final RenderLayer LEASH = of("leash", DefaultVertexFormat.POSITION_COLOR_LIGHT, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(NO_TEXTURE).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).build(false)); - private static final RenderLayer WATER_MASK = of("water_mask", DefaultVertexFormat.POSITION, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(NO_TEXTURE).writeMaskState(DEPTH_MASK).build(false)); -// private static final RenderLayer ARMOR_GLINT = of("armor_glint", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(GLINT_TEXTURING).layering(VIEW_OFFSET_Z_LAYERING).build(false)); -// private static final RenderLayer ARMOR_ENTITY_GLINT = of("armor_entity_glint", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(ENTITY_GLINT_TEXTURING).layering(VIEW_OFFSET_Z_LAYERING).build(false)); -// private static final RenderLayer GLINT_TRANSLUCENT = of("glint_translucent", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(GLINT_TEXTURING).target(ITEM_TARGET).build(false)); -// private static final RenderLayer GLINT = of("glint", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(GLINT_TEXTURING).build(false)); -// private static final RenderLayer DIRECT_GLINT = of("glint_direct", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(GLINT_TEXTURING).build(false)); -// private static final RenderLayer ENTITY_GLINT = of("entity_glint", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).target(ITEM_TARGET).texturing(ENTITY_GLINT_TEXTURING).build(false)); -// private static final RenderLayer DIRECT_ENTITY_GLINT = of("entity_glint_direct", DefaultVertexFormat.POSITION_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(ItemRenderer.ENCHANTED_ITEM_GLINT, true, false)).writeMaskState(COLOR_MASK).cull(DISABLE_CULLING).depthTest(EQUAL_DEPTH_TEST).transparency(GLINT_TRANSPARENCY).texturing(ENTITY_GLINT_TEXTURING).build(false)); - private static final RenderLayer LIGHTNING = of("lightning", DefaultVertexFormat.POSITION_COLOR, 7, 256, false, true, RenderLayer.MultiPhaseParameters.builder().writeMaskState(ALL_MASK).transparency(LIGHTNING_TRANSPARENCY).target(WEATHER_TARGET).shadeModel(SMOOTH_SHADE_MODEL).build(false)); - private static final RenderLayer TRIPWIRE = of("tripwire", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 262144, true, true, getTripwirePhaseData()); - private static final RenderLayer LINES = of("lines", DefaultVertexFormat.POSITION_COLOR, 1, 256, RenderLayer.MultiPhaseParameters.builder().lineWidth(new RenderPhase.LineWidth(OptionalDouble.empty())).layering(VIEW_OFFSET_Z_LAYERING).transparency(TRANSLUCENT_TRANSPARENCY).target(ITEM_TARGET).writeMaskState(ALL_MASK).build(false)); - - private static List BLOCK_LAYERS = ImmutableList.of(RenderLayer.solid(), RenderLayer.cutoutMipped(), RenderLayer.cutout(), RenderLayer.translucent(), RenderLayer.tripwire()); @Getter private final VertexFormat vertexFormat; @@ -40,22 +21,12 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris private final int drawMode; @Getter private final int expectedBufferSize; - private final boolean hasCrumbling; - private final boolean translucent; - private final Optional optionalThis; - private static MultiPhaseParameters getTripwirePhaseData() { - return MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).transparency(TRANSLUCENT_TRANSPARENCY).target(WEATHER_TARGET).build(true); - } - - public RenderLayer(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, Runnable startAction, Runnable endAction) { + public RenderLayer(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, Runnable startAction, Runnable endAction) { super(name, startAction, endAction); this.vertexFormat = vertexFormat; this.drawMode = drawMode; this.expectedBufferSize = expectedBufferSize; - this.hasCrumbling = hasCrumbling; - this.translucent = translucent; - this.optionalThis = Optional.of(this); } @@ -76,9 +47,6 @@ public static RenderLayer cutout() { return CUTOUT; } - public static RenderLayer cutoutMipped() { - return CUTOUT_MIPPED; - } private static MultiPhaseParameters createTranslucentPhaseData() { return RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).transparency(TRANSLUCENT_TRANSPARENCY).target(TRANSLUCENT_TARGET).build(true); } @@ -87,156 +55,14 @@ public static RenderLayer translucent() { return TRANSLUCENT; } - private static MultiPhaseParameters getItemPhaseData() { - return RenderLayer.MultiPhaseParameters.builder().shadeModel(SMOOTH_SHADE_MODEL).lightmap(ENABLE_LIGHTMAP).texture(MIPMAP_BLOCK_ATLAS_TEXTURE).transparency(TRANSLUCENT_TRANSPARENCY).target(ITEM_TARGET).build(true); - } - - public static RenderLayer getArmorCutoutNoCull(ResourceLocation texture) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(NO_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).layering(VIEW_OFFSET_Z_LAYERING).build(true); - return of("armor_cutout_no_cull", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, false, rendertype$state); - } - - public static RenderLayer getEntitySolid(ResourceLocation texture) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(NO_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(true); - return of("entity_solid", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, false, rendertype$state); - } - - public static RenderLayer getEntityCutout(ResourceLocation texture) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(NO_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(true); - return of("entity_cutout", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, false, rendertype$state); - } - - public static RenderLayer getEntityCutoutNoCull(ResourceLocation texture, boolean affectsOutline) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(NO_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(affectsOutline); - return of("entity_cutout_no_cull", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, false, rendertype$state); - } - - public static RenderLayer getEntityCutoutNoCull(ResourceLocation texture) { - return getEntityCutoutNoCull(texture, true); - } - - public static RenderLayer getEntityCutoutNoCullZOffset(ResourceLocation texture, boolean affectsOutline) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(NO_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).layering(VIEW_OFFSET_Z_LAYERING).build(affectsOutline); - return of("entity_cutout_no_cull_z_offset", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, false, rendertype$state); - } - - public static RenderLayer getEntityCutoutNoCullZOffset(ResourceLocation texture) { - return getEntityCutoutNoCullZOffset(texture, true); - } - - public static RenderLayer getItemEntityTranslucentCull(ResourceLocation texture) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(TRANSLUCENT_TRANSPARENCY).target(ITEM_TARGET).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).writeMaskState(RenderPhase.ALL_MASK).build(true); - return of("item_entity_translucent_cull", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, true, rendertype$state); - } - - public static RenderLayer getEntityTranslucentCull(ResourceLocation texture) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(TRANSLUCENT_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(true); - return of("entity_translucent_cull", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, true, rendertype$state); - } - - public static RenderLayer getEntityTranslucent(ResourceLocation texture, boolean affectsOutline) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(TRANSLUCENT_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(affectsOutline); - return of("entity_translucent", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, true, rendertype$state); - } - - public static RenderLayer getEntityTranslucent(ResourceLocation texture) { - return getEntityTranslucent(texture, true); - } - - public static RenderLayer getEntitySmoothCutout(ResourceLocation texture) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).alpha(HALF_ALPHA).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).shadeModel(SMOOTH_SHADE_MODEL).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).build(true); - return of("entity_smooth_cutout", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, rendertype$state); - } - - public static RenderLayer getBeaconBeam(ResourceLocation texture, boolean translucent) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(translucent ? TRANSLUCENT_TRANSPARENCY : NO_TRANSPARENCY).writeMaskState(translucent ? COLOR_MASK : ALL_MASK).fog(NO_FOG).build(false); - return of("beacon_beam", DefaultVertexFormat.POSITION_COLOR_TEXTURE_LIGHT_NORMAL, 7, 256, false, true, rendertype$state); - } - - public static RenderLayer getEntityDecal(ResourceLocation texture) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).depthTest(EQUAL_DEPTH_TEST).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(false); - return of("entity_decal", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, rendertype$state); - } - - public static RenderLayer getEntityNoOutline(ResourceLocation texture) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(TRANSLUCENT_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).writeMaskState(COLOR_MASK).build(false); - return of("entity_no_outline", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, false, true, rendertype$state); - } - - public static RenderLayer getEntityShadow(ResourceLocation texture) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).transparency(TRANSLUCENT_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(ENABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).writeMaskState(COLOR_MASK).depthTest(LEQUAL_DEPTH_TEST).layering(VIEW_OFFSET_Z_LAYERING).build(false); - return of("entity_shadow", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, false, false, rendertype$state); - } - - public static RenderLayer getEntityAlpha(ResourceLocation texture, float alpha) { - MultiPhaseParameters rendertype$state = RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).alpha(new RenderPhase.Alpha(alpha)).cull(DISABLE_CULLING).build(true); - return of("entity_alpha", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, rendertype$state); - } - - public static RenderLayer getEyes(ResourceLocation texture) { - RenderPhase.Texture renderstate$texturestate = new RenderPhase.Texture(texture, false, false); - return of("eyes", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, false, true, RenderLayer.MultiPhaseParameters.builder().texture(renderstate$texturestate).transparency(ADDITIVE_TRANSPARENCY).writeMaskState(COLOR_MASK).fog(BLACK_FOG).build(false)); - } - - public static RenderLayer getEnergySwirl(ResourceLocation texture, float x, float y) { - return of("energy_swirl", DefaultVertexFormat.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, false, true, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).texturing(new RenderPhase.OffsetTexturing(x, y)).fog(BLACK_FOG).transparency(ADDITIVE_TRANSPARENCY).diffuseLighting(ENABLE_DIFFUSE_LIGHTING).alpha(ONE_TENTH_ALPHA).cull(DISABLE_CULLING).lightmap(ENABLE_LIGHTMAP).overlay(ENABLE_OVERLAY_COLOR).build(false)); - } - - public static RenderLayer getOutline(ResourceLocation texture) { - return getOutline(texture, DISABLE_CULLING); - } - public static RenderLayer getOutline(ResourceLocation texture, RenderPhase.Cull cull) { return of("outline", DefaultVertexFormat.POSITION_COLOR_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).cull(cull).depthTest(ALWAYS_DEPTH_TEST).alpha(ONE_TENTH_ALPHA).texturing(OUTLINE_TEXTURING).fog(NO_FOG).target(OUTLINE_TARGET).build(RenderLayer.OutlineMode.IS_OUTLINE)); } - - public static RenderLayer tripwire() { - return TRIPWIRE; - } - - public static List getBlockLayers() { - return BLOCK_LAYERS; - } - public int mode() { return this.drawMode; } - public VertexFormat format() { - return vertexFormat; - } - - public boolean shouldSortOnUpload() { - return false; - } - - public int bufferSize() { - return 0; - } - - public void end(BufferBuilder buffer, int i, int i1, int i2) {} - - public boolean hasCrumbling() { - return hasCrumbling; - } - - public Optional outline() { - return Optional.empty(); - } - - public boolean isOutline() { - return false; - } - - public Optional asOptional() { - return optionalThis; - } - - public void draw(BufferBuilder lv, int cameraX, int cameraY, int cameraZ) { - } - - static final class MultiPhase extends RenderLayer { private static final ObjectOpenCustomHashSet CACHE; private final MultiPhaseParameters phases; @@ -245,7 +71,7 @@ static final class MultiPhase extends RenderLayer { private final boolean outline; private MultiPhase(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, MultiPhaseParameters phases) { - super(name, vertexFormat, drawMode, expectedBufferSize, hasCrumbling, translucent, () -> { + super(name, vertexFormat, drawMode, expectedBufferSize, () -> { phases.phases.forEach(RenderPhase::startDrawing); }, () -> { phases.phases.forEach(RenderPhase::endDrawing); @@ -267,10 +93,6 @@ public Optional getAffectedOutline() { return this.affectedOutline; } - public boolean isOutline() { - return this.outline; - } - public boolean equals(@Nullable Object object) { return this == object; } @@ -414,11 +236,6 @@ public Builder transparency(RenderPhase.Transparency transparency) { return this; } - public Builder diffuseLighting(RenderPhase.DiffuseLighting diffuseLighting) { - this.diffuseLighting = diffuseLighting; - return this; - } - public Builder shadeModel(RenderPhase.ShadeModel shadeModel) { this.shadeModel = shadeModel; return this; @@ -454,11 +271,6 @@ public Builder fog(RenderPhase.Fog fog) { return this; } - public Builder layering(RenderPhase.Layering layering) { - this.layering = layering; - return this; - } - public Builder target(RenderPhase.Target target) { this.target = target; return this; @@ -469,16 +281,6 @@ public Builder texturing(RenderPhase.Texturing texturing) { return this; } - public Builder writeMaskState(RenderPhase.WriteMaskState writeMaskState) { - this.writeMaskState = writeMaskState; - return this; - } - - public Builder lineWidth(RenderPhase.LineWidth lineWidth) { - this.lineWidth = lineWidth; - return this; - } - public MultiPhaseParameters build(boolean affectsOutline) { return this.build(affectsOutline ? RenderLayer.OutlineMode.AFFECTS_OUTLINE : RenderLayer.OutlineMode.NONE); } @@ -489,14 +291,14 @@ public MultiPhaseParameters build(OutlineMode outlineMode) { } } - static enum OutlineMode { + enum OutlineMode { NONE("none"), IS_OUTLINE("is_outline"), AFFECTS_OUTLINE("affects_outline"); private final String name; - private OutlineMode(String name) { + OutlineMode(String name) { this.name = name; } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayers.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayers.java deleted file mode 100644 index 07c9cf6c4..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/RenderLayers.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -import net.minecraft.block.Block; -import net.minecraft.block.material.Material; - -@Deprecated -public class RenderLayers { - public static boolean canRenderInLayer(Block block, RenderLayer layer) { - if(layer == RenderLayer.translucent()) - return block.canRenderInPass(1); - else if(layer == RenderLayer.cutoutMipped()) - return block.canRenderInPass(0); - - return false; - } - - public static boolean canRenderInLayer(FluidState fluidState, RenderLayer layer) { - return canRenderFluidInLayer(fluidState.getFluid().getBlock(), layer); - } - - public static boolean canRenderFluidInLayer(Block block, RenderLayer layer) { - // Make all water-type fluids translucent, and all others solid - // This may be revisited later, but it *should* be fine for now - // Translucent fluids - if (block.getMaterial() == Material.water) { - return layer == RenderLayer.solid(); - } - - return layer == RenderLayer.solid(); - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexConsumers.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexConsumers.java deleted file mode 100644 index 1ea42b3c0..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VertexConsumers.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -@Deprecated -public class VertexConsumers { - public static VertexConsumer union(VertexConsumer first, VertexConsumer second) { - return new Dual(first, second); - } - - @Deprecated - static class Dual implements VertexConsumer { - private final VertexConsumer first; - private final VertexConsumer second; - - public Dual(VertexConsumer first, VertexConsumer second) { - if (first == second) { - throw new IllegalArgumentException("Duplicate delegates"); - } else { - this.first = first; - this.second = second; - } - } - @Override - public VertexConsumer vertex(double x, double y, double z) { - this.first.vertex(x, y, z); - this.second.vertex(x, y, z); - return this; - } - - @Override - public VertexConsumer color(int red, int green, int blue, int alpha) { - this.first.color(red, green, blue, alpha); - this.second.color(red, green, blue, alpha); - return this; - } - - @Override - public VertexConsumer texture(float u, float v) { - this.first.texture(u, v); - this.second.texture(u, v); - return this; - } - - @Override - public VertexConsumer overlay(int u, int v) { - this.first.overlay(u, v); - this.second.overlay(u, v); - return this; - } - - @Override - public VertexConsumer light(int u, int v) { - this.first.light(u, v); - this.second.light(u, v); - return this; - } - @Override - public VertexConsumer normal(float x, float y, float z) { - this.first.normal(x, y, z); - this.second.normal(x, y, z); - return this; - } - @Override - public void vertex(float x, float y, float z, float red, float green, float blue, float alpha, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) { - this.first.vertex(x, y, z, red, green, blue, alpha, u, v, overlay, light, normalX, normalY, normalZ); - this.second.vertex(x, y, z, red, green, blue, alpha, u, v, overlay, light, normalX, normalY, normalZ); - } - - public void next() { - this.first.next(); - this.second.next(); - } - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShape.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShape.java deleted file mode 100644 index b6b3af199..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShape.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -@Deprecated -public enum VoxelShape { - - FULL_CUBE(false), - EMPTY(true); - - private final boolean empty; - - VoxelShape(boolean empty) { - this.empty = empty; - } - - public boolean isEmpty() { - return empty; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShapes.java b/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShapes.java deleted file mode 100644 index 990189cab..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/compat/toremove/VoxelShapes.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gtnewhorizons.angelica.compat.toremove; - -import net.minecraftforge.common.util.ForgeDirection; - -@Deprecated -public final class VoxelShapes { - - public static VoxelShape fullCube() { - return VoxelShape.FULL_CUBE; - } - - public static VoxelShape empty() { - return VoxelShape.EMPTY; - } - - public static boolean matchesAnywhere(VoxelShape shape1, VoxelShape shape2, Object predicate) { - return false; - } - - public static VoxelShape cuboid(double v, double v1, double v2, double v3, float height, double v4) { - return null; - } - - public static boolean isSideCovered(VoxelShape threshold, VoxelShape shape, ForgeDirection dir) { - return true; - } -} diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index ff7c0507b..966d45ff6 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -18,12 +18,12 @@ public class AngelicaConfig { public static boolean enableIris; @Config.Comment("Enable NotFine optimizations") - @Config.DefaultBoolean(false) + @Config.DefaultBoolean(true) @Config.RequiresMcRestart public static boolean enableNotFineOptimizations; @Config.Comment("Enable NotFine features") - @Config.DefaultBoolean(false) + @Config.DefaultBoolean(true) @Config.RequiresMcRestart public static boolean enableNotFineFeatures; @@ -46,11 +46,10 @@ public class AngelicaConfig { @Config.Comment("Renders the HUD elements once per tick and reuses the pixels to improve performance. [Experimental]") @Config.DefaultBoolean(true) @Config.RequiresMcRestart - // TODO disabled for now as it doesn't drawScreen items with an enchantment glint in the hotbar properly as well as doesn't drawScreen the vignette public static boolean enableHudCaching; @Config.Comment("Batch drawScreen fonts [Experimental]") - @Config.DefaultBoolean(false) + @Config.DefaultBoolean(true) @Config.RequiresMcRestart public static boolean enableFontRenderer; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java index 4bd2eed4e..8d243dc31 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/shaders/MixinEntityRenderer.java @@ -7,6 +7,7 @@ import com.llamalad7.mixinextras.sugar.ref.LocalRef; import net.coderbot.iris.Iris; import net.coderbot.iris.gl.program.Program; +import net.coderbot.iris.pipeline.HandRenderer; import net.coderbot.iris.pipeline.WorldRenderingPhase; import net.coderbot.iris.pipeline.WorldRenderingPipeline; import net.coderbot.iris.uniforms.CapturedRenderingState; @@ -18,6 +19,7 @@ import net.minecraft.client.settings.GameSettings; import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; @@ -25,6 +27,8 @@ @Mixin(EntityRenderer.class) public abstract class MixinEntityRenderer implements IResourceManagerReloadListener { + @Shadow public Minecraft mc; + @Inject(at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glClear(I)V", shift = At.Shift.AFTER, ordinal = 0), method = "renderWorld(FJ)V", remap = false) private void iris$beginRender(float partialTicks, long startTime, CallbackInfo ci, @Share("pipeline") LocalRef pipeline) { CapturedRenderingState.INSTANCE.setTickDelta(partialTicks); @@ -41,7 +45,8 @@ public abstract class MixinEntityRenderer implements IResourceManagerReloadListe @Inject(method = "renderWorld(FJ)V", at = @At(value = "RETURN", shift = At.Shift.BEFORE)) private void iris$endLevelRender(float partialTicks, long limitTime, CallbackInfo callback, @Share("pipeline") LocalRef pipeline) { // TODO: Iris -// HandRenderer.INSTANCE.renderTranslucent(poseStack, tickDelta, camera, gameRenderer, pipeline); + final Camera camera = new Camera(mc.renderViewEntity, partialTicks); + HandRenderer.INSTANCE.renderTranslucent(null /*poseStack*/, partialTicks, camera, mc.renderGlobal, pipeline.get()); Minecraft.getMinecraft().mcProfiler.endStartSection("iris_final"); pipeline.get().finalizeLevelRendering(); pipeline.set(null); @@ -50,8 +55,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 pipeline) { - final Minecraft mc = Minecraft.getMinecraft(); - Camera camera = new Camera(mc.renderViewEntity, partialTicks); + final Camera camera = new Camera(mc.renderViewEntity, partialTicks); pipeline.get().renderShadows((EntityRenderer) (Object) this, camera); } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java index edee622f7..6d617dd4f 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/sodium/MixinRenderGlobal.java @@ -150,7 +150,6 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) pipeline = null; } else { pipeline = Iris.getPipelineManager().getPipelineNullable(); -// pipeline.setPhase(WorldRenderingPhase.fromTerrainRenderType(renderType)); pipeline.setPhase(WorldRenderingPhase.TERRAIN_CUTOUT); if(pass == 1) { @@ -158,7 +157,7 @@ public int sortAndRender(EntityLivingBase entity, int pass, double partialTicks) // iris$beginTranslucents pipeline.beginHand(); - HandRenderer.INSTANCE.renderSolid(null /*poseStack*/, (float) partialTicks, camera, null /*gameRenderer*/, pipeline); + HandRenderer.INSTANCE.renderSolid(null /*poseStack*/, (float) partialTicks, camera, mc.renderGlobal, pipeline); mc.mcProfiler.endStartSection("iris_pre_translucent"); pipeline.beginTranslucents(); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java index 1d1e45c93..05ce7207c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/FluidRenderer.java @@ -1,8 +1,6 @@ package me.jellysquid.mods.sodium.client.render.pipeline; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.toremove.VoxelShape; -import com.gtnewhorizons.angelica.compat.toremove.VoxelShapes; import com.gtnewhorizons.angelica.config.AngelicaConfig; import me.jellysquid.mods.sodium.client.model.light.LightMode; import me.jellysquid.mods.sodium.client.model.light.LightPipeline; @@ -72,19 +70,15 @@ private boolean isSideExposed(IBlockAccess world, int x, int y, int z, ForgeDire Block block = world.getBlock(pos.x, pos.y, pos.z); if (block.getMaterial().isOpaque()) { - VoxelShape shape = WorldUtil.getCullingShape(block); + final boolean renderAsFullCube = block.renderAsNormalBlock(); // Hoist these checks to avoid allocating the shape below - if (shape == VoxelShapes.fullCube()) { + if (renderAsFullCube) { // The top face always be inset, so if the shape above is a full cube it can't possibly occlude return dir == ForgeDirection.UP; - } else if (shape.isEmpty()) { + } else { return true; } - - VoxelShape threshold = VoxelShapes.cuboid(0.0D, 0.0D, 0.0D, 1.0D, height, 1.0D); - - return !VoxelShapes.isSideCovered(threshold, shape, dir); } return true; diff --git a/src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java b/src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java index 29bc02a45..f7ce2e49b 100644 --- a/src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java +++ b/src/main/java/me/jellysquid/mods/sodium/common/util/WorldUtil.java @@ -1,8 +1,6 @@ package me.jellysquid.mods.sodium.common.util; import com.gtnewhorizons.angelica.compat.mojang.BlockPos; -import com.gtnewhorizons.angelica.compat.toremove.VoxelShape; -import com.gtnewhorizons.angelica.compat.toremove.VoxelShapes; import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; import net.minecraft.block.material.Material; @@ -85,10 +83,6 @@ public static boolean method_15756(IBlockAccess world, BlockPos pos, Fluid fluid return false; } - public static VoxelShape getCullingShape(Block block) { - return block.renderAsNormalBlock() ? VoxelShapes.fullCube() : VoxelShapes.empty(); - } - /** * Returns fluid height as a percentage of the block; 0 is none and 1 is full. */ diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java index cbc55d128..cc0a98ae1 100644 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java +++ b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferBuilderExt.java @@ -5,7 +5,5 @@ import java.nio.ByteBuffer; public interface BufferBuilderExt { - void setupBufferSlice(ByteBuffer buffer, DrawState drawState); - void teardownBufferSlice(); - void splitStrip(); + } diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java b/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java deleted file mode 100644 index fc84c7d7a..000000000 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/BufferSegmentRenderer.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.coderbot.batchedentityrendering.impl; - -import com.gtnewhorizons.angelica.compat.toremove.BufferBuilder; - -public class BufferSegmentRenderer { - private final BufferBuilder fakeBufferBuilder; - private final BufferBuilderExt fakeBufferBuilderExt; - - public BufferSegmentRenderer() { - this.fakeBufferBuilder = new BufferBuilder(0); - this.fakeBufferBuilderExt = (BufferBuilderExt) this.fakeBufferBuilder; - } - - /** - * Sets up the render type, draws the buffer, and then tears down the render type. - */ - public void draw(BufferSegment segment) { - segment.getRenderType().startDrawing(); - drawInner(segment); - segment.getRenderType().endDrawing(); - } - - /** - * Like draw(), but it doesn't setup / tear down the render type. - */ - public void drawInner(BufferSegment segment) { - fakeBufferBuilderExt.setupBufferSlice(segment.getSlice(), segment.getDrawState()); - // TODO: BufferUploader -// BufferUploader.end(fakeBufferBuilder); - fakeBufferBuilderExt.teardownBufferSlice(); - } -} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java deleted file mode 100644 index 5185de38b..000000000 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/FullyBufferedMultiBufferSource.java +++ /dev/null @@ -1,259 +0,0 @@ -package net.coderbot.batchedentityrendering.impl; - -import net.coderbot.batchedentityrendering.impl.ordering.GraphTranslucencyRenderOrderManager; -import net.coderbot.batchedentityrendering.impl.ordering.RenderOrderManager; -import com.gtnewhorizons.angelica.compat.toremove.BufferBuilder; -import com.gtnewhorizons.angelica.compat.toremove.BufferSource; -import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; -import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; -import net.coderbot.iris.fantastic.WrappingMultiBufferSource; -import net.minecraft.client.Minecraft; -import net.minecraft.profiler.Profiler; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -public class FullyBufferedMultiBufferSource extends BufferSource implements MemoryTrackingBuffer, Groupable, WrappingMultiBufferSource { - private static final int NUM_BUFFERS = 32; - - private final RenderOrderManager renderOrderManager; - private final SegmentedBufferBuilder[] builders; - /** - * An LRU cache mapping RenderType objects to a relevant buffer. - */ - private final LinkedHashMap affinities; - private int drawCalls; - private int renderTypes; - - private final BufferSegmentRenderer segmentRenderer; - private final UnflushableWrapper unflushableWrapper; - private final List> wrappingFunctionStack; - private Function wrappingFunction = null; - - public FullyBufferedMultiBufferSource() { - super(new BufferBuilder(0), Collections.emptyMap()); - - this.renderOrderManager = new GraphTranslucencyRenderOrderManager(); - this.builders = new SegmentedBufferBuilder[NUM_BUFFERS]; - - for (int i = 0; i < this.builders.length; i++) { - this.builders[i] = new SegmentedBufferBuilder(); - } - - // use accessOrder=true so our LinkedHashMap works as an LRU cache. - this.affinities = new LinkedHashMap<>(32, 0.75F, true); - - this.drawCalls = 0; - this.segmentRenderer = new BufferSegmentRenderer(); - this.unflushableWrapper = new UnflushableWrapper(this); - this.wrappingFunctionStack = new ArrayList<>(); - } - - @Override - public VertexConsumer getBuffer(RenderLayer renderType) { - if (wrappingFunction != null) { - renderType = wrappingFunction.apply(renderType); - } - - renderOrderManager.begin(renderType); - Integer affinity = affinities.get(renderType); - - if (affinity == null) { - if (affinities.size() < builders.length) { - affinity = affinities.size(); - } else { - // We remove the element from the map that is used least-frequently. - // With how we've configured our LinkedHashMap, that is the first element. - Iterator> iterator = affinities.entrySet().iterator(); - Map.Entry evicted = iterator.next(); - iterator.remove(); - - // The previous type is no longer associated with this buffer ... - affinities.remove(evicted.getKey()); - - // ... since our new type is now associated with it. - affinity = evicted.getValue(); - } - - affinities.put(renderType, affinity); - } - - return builders[affinity].getBuffer(renderType); - } - - @Override - public void endBatch() { - Profiler profiler = Minecraft.getMinecraft().mcProfiler; - - profiler.startSection("collect"); - - Map> typeToSegment = new HashMap<>(); - - for (SegmentedBufferBuilder builder : builders) { - List segments = builder.getSegments(); - - for (BufferSegment segment : segments) { - typeToSegment.computeIfAbsent(segment.getRenderType(), (type) -> new ArrayList<>()).add(segment); - } - } - - profiler.endStartSection("resolve ordering"); - - Iterable renderOrder = renderOrderManager.getRenderOrder(); - - profiler.endStartSection("draw buffers"); - - for (RenderLayer type : renderOrder) { - type.startDrawing(); - - renderTypes += 1; - - for (BufferSegment segment : typeToSegment.getOrDefault(type, Collections.emptyList())) { - segmentRenderer.drawInner(segment); - drawCalls += 1; - } - - type.endDrawing(); - } - - profiler.endStartSection("reset"); - - renderOrderManager.reset(); - affinities.clear(); - - profiler.endSection(); - } - - public int getDrawCalls() { - return drawCalls; - } - - public int getRenderTypes() { - return renderTypes; - } - - public void resetDrawCalls() { - drawCalls = 0; - renderTypes = 0; - } - - @Override - public void endBatch(RenderLayer type) { - // Disable explicit flushing - } - - public BufferSource getUnflushableWrapper() { - return unflushableWrapper; - } - - @Override - public int getAllocatedSize() { - int size = 0; - - for (SegmentedBufferBuilder builder : builders) { - size += builder.getAllocatedSize(); - } - - return size; - } - - @Override - public int getUsedSize() { - int size = 0; - - for (SegmentedBufferBuilder builder : builders) { - size += builder.getUsedSize(); - } - - return size; - } - - @Override - public void startGroup() { - renderOrderManager.startGroup(); - } - - @Override - public boolean maybeStartGroup() { - return renderOrderManager.maybeStartGroup(); - } - - @Override - public void endGroup() { - renderOrderManager.endGroup(); - } - - @Override - public void pushWrappingFunction(Function wrappingFunction) { - if (this.wrappingFunction != null) { - this.wrappingFunctionStack.add(this.wrappingFunction); - } - - this.wrappingFunction = wrappingFunction; - } - - @Override - public void popWrappingFunction() { - if (this.wrappingFunctionStack.isEmpty()) { - this.wrappingFunction = null; - } else { - this.wrappingFunction = this.wrappingFunctionStack.remove(this.wrappingFunctionStack.size() - 1); - } - } - - @Override - public void assertWrapStackEmpty() { - if (!this.wrappingFunctionStack.isEmpty() || this.wrappingFunction != null) { - throw new IllegalStateException("Wrapping function stack not empty!"); - } - } - - /** - * A wrapper that prevents callers from explicitly flushing anything. - */ - private static class UnflushableWrapper extends BufferSource implements Groupable { - private final FullyBufferedMultiBufferSource wrapped; - - UnflushableWrapper(FullyBufferedMultiBufferSource wrapped) { - super(new BufferBuilder(0), Collections.emptyMap()); - - this.wrapped = wrapped; - } - - @Override - public VertexConsumer getBuffer(RenderLayer renderType) { - return wrapped.getBuffer(renderType); - } - - @Override - public void endBatch() { - // Disable explicit flushing - } - - @Override - public void endBatch(RenderLayer type) { - // Disable explicit flushing - } - - @Override - public void startGroup() { - wrapped.startGroup(); - } - - @Override - public boolean maybeStartGroup() { - return wrapped.maybeStartGroup(); - } - - @Override - public void endGroup() { - wrapped.endGroup(); - } - } -} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java b/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java deleted file mode 100644 index aedfaf27f..000000000 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/OldFullyBufferedMultiBufferSource.java +++ /dev/null @@ -1,145 +0,0 @@ -package net.coderbot.batchedentityrendering.impl; - -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import com.gtnewhorizons.angelica.compat.toremove.BufferBuilder; -import com.gtnewhorizons.angelica.compat.toremove.BufferSource; -import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; -import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class OldFullyBufferedMultiBufferSource extends BufferSource { - private final Map bufferBuilders; - private final Object2IntMap unused; - private final Set activeBuffers; - private boolean flushed; - - private final Set typesThisFrame; - private final List typesInOrder; - - public OldFullyBufferedMultiBufferSource() { - super(new BufferBuilder(0), Collections.emptyMap()); - - this.bufferBuilders = new HashMap<>(); - this.unused = new Object2IntOpenHashMap<>(); - this.activeBuffers = new HashSet<>(); - this.flushed = false; - - this.typesThisFrame = new HashSet<>(); - this.typesInOrder = new ArrayList<>(); - } - - private TransparencyType getTransparencyType(RenderLayer type) { - while (type instanceof WrappableRenderType) { - type = ((WrappableRenderType) type).unwrap(); - } - - if (type instanceof BlendingStateHolder) { - return ((BlendingStateHolder) type).getTransparencyType(); - } - - // Default to "generally transparent" if we can't figure it out. - return TransparencyType.GENERAL_TRANSPARENT; - } - - @Override - public VertexConsumer getBuffer(RenderLayer renderType) { - flushed = false; - - BufferBuilder buffer = bufferBuilders.computeIfAbsent(renderType, type -> new BufferBuilder(type.bufferSize())); - - if (activeBuffers.add(buffer)) { - buffer.begin(renderType.mode(), renderType.format()); - } - - if (this.typesThisFrame.add(renderType)) { - // If we haven't seen this type yet, add it to the list of types to render. - // - // We keep track of the order that types were added, in order to ensure that if layers are not - // sorted relative each other due to translucency, that they are sorted in the order that they were - // drawn in. - // - // This is important for things like villager rendering, where the clothes and skin of villagers overlap - // each other, so if the clothes are drawn before the skin, they appear to be poorly-clothed. - this.typesInOrder.add(renderType); - } - - // If this buffer is scheduled to be removed, unschedule it since it's now being used. - unused.removeInt(renderType); - - return buffer; - } - - @Override - public void endBatch() { - if (flushed) { - return; - } - - List removedTypes = new ArrayList<>(); - - unused.forEach((unusedType, unusedCount) -> { - if (unusedCount < 10) { - // Removed after 10 frames of not being used - return; - } - - BufferBuilder buffer = bufferBuilders.remove(unusedType); - removedTypes.add(unusedType); - - if (activeBuffers.contains(buffer)) { - throw new IllegalStateException( - "A buffer was simultaneously marked as inactive and as active, something is very wrong..."); - } - }); - - for (RenderLayer removed : removedTypes) { - unused.removeInt(removed); - } - - // Make sure translucent types are rendered after non-translucent ones. - typesInOrder.sort(Comparator.comparing(this::getTransparencyType)); - - for (RenderLayer type : typesInOrder) { - drawInternal(type); - } - - typesInOrder.clear(); - typesThisFrame.clear(); - - flushed = true; - } - - @Override - public void endBatch(RenderLayer type) { - // Disable explicit flushing - } - - private void drawInternal(RenderLayer type) { - BufferBuilder buffer = bufferBuilders.get(type); - - if (buffer == null) { - return; - } - - if (activeBuffers.remove(buffer)) { - type.end(buffer, 0, 0, 0); - buffer.clear(); - } else { - // Schedule the buffer for removal next frame if it isn't used this frame. - int unusedCount = unused.getOrDefault(type, 0); - - unusedCount += 1; - - unused.put(type, unusedCount); - } - } -} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java b/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java deleted file mode 100644 index 4598c89bb..000000000 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/RenderTypeUtil.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.coderbot.batchedentityrendering.impl; - -import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; -import org.lwjgl.opengl.GL11; - -public class RenderTypeUtil { - public static boolean isTriangleStripDrawMode(RenderLayer renderType) { - return renderType.mode() == GL11.GL_TRIANGLE_STRIP; - } -} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java b/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java deleted file mode 100644 index c417cb477..000000000 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/SegmentedBufferBuilder.java +++ /dev/null @@ -1,100 +0,0 @@ -package net.coderbot.batchedentityrendering.impl; - -import com.gtnewhorizons.angelica.compat.toremove.BufferBuilder; -import com.gtnewhorizons.angelica.compat.toremove.DrawState; -import com.gtnewhorizons.angelica.compat.toremove.MultiBufferSource; -import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; -import com.gtnewhorizons.angelica.compat.toremove.VertexConsumer; -import org.apache.commons.lang3.tuple.Pair; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -public class SegmentedBufferBuilder implements MultiBufferSource, MemoryTrackingBuffer { - private final BufferBuilder buffer; - private final List usedTypes; - private RenderLayer currentType; - - public SegmentedBufferBuilder() { - // 2 MB initial allocation - this.buffer = new BufferBuilder(512 * 1024); - this.usedTypes = new ArrayList<>(256); - - this.currentType = null; - } - - @Override - public VertexConsumer getBuffer(RenderLayer renderType) { - if (!Objects.equals(currentType, renderType)) { - if (currentType != null) { - if (shouldSortOnUpload(currentType)) { - buffer.sortQuads(0, 0, 0); - } - - buffer.end(); - usedTypes.add(currentType); - } - - buffer.begin(renderType.mode(), renderType.format()); - - currentType = renderType; - } - - // Use duplicate vertices to break up triangle strips - // https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/Art/degenerate_triangle_strip_2x.png - // This works by generating zero-area triangles that don't end up getting rendered. - // TODO: How do we handle DEBUG_LINE_STRIP? - if (RenderTypeUtil.isTriangleStripDrawMode(currentType)) { - ((BufferBuilderExt) buffer).splitStrip(); - } - - return buffer; - } - - public List getSegments() { - if (currentType == null) { - return Collections.emptyList(); - } - - usedTypes.add(currentType); - - if (shouldSortOnUpload(currentType)) { - buffer.sortQuads(0, 0, 0); - } - - buffer.end(); - currentType = null; - - List segments = new ArrayList<>(usedTypes.size()); - - for (RenderLayer type : usedTypes) { - Pair pair = buffer.popNextBuffer(); - - DrawState drawState = pair.getLeft(); - ByteBuffer slice = pair.getRight(); - - segments.add(new BufferSegment(slice, drawState, type)); - } - - usedTypes.clear(); - - return segments; - } - - private static boolean shouldSortOnUpload(RenderLayer type) { - return type.shouldSortOnUpload(); - } - - @Override - public int getAllocatedSize() { - return ((MemoryTrackingBuffer) buffer).getAllocatedSize(); - } - - @Override - public int getUsedSize() { - return ((MemoryTrackingBuffer) buffer).getUsedSize(); - } -} diff --git a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java b/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java deleted file mode 100644 index 1805a8c07..000000000 --- a/src/main/java/net/coderbot/batchedentityrendering/impl/wrappers/TaggingRenderTypeWrapper.java +++ /dev/null @@ -1,69 +0,0 @@ -package net.coderbot.batchedentityrendering.impl.wrappers; - -import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; -import java.util.Optional; - -public class TaggingRenderTypeWrapper extends RenderLayer implements WrappableRenderType { - private final int tag; - private final RenderLayer wrapped; - - public TaggingRenderTypeWrapper(String name, RenderLayer wrapped, int tag) { - super(name, wrapped.format(), wrapped.mode(), wrapped.bufferSize(), - wrapped.hasCrumbling(), shouldSortOnUpload(wrapped), wrapped::startDrawing, wrapped::endDrawing); - - this.tag = tag; - this.wrapped = wrapped; - } - - @Override - public RenderLayer unwrap() { - return this.wrapped; - } - - @Override - public Optional outline() { - return this.wrapped.outline(); - } - - @Override - public boolean isOutline() { - return this.wrapped.isOutline(); - } - - @Override - public boolean equals(@Nullable Object object) { - if (object == null) { - return false; - } - - if (object.getClass() != this.getClass()) { - return false; - } - - TaggingRenderTypeWrapper other = (TaggingRenderTypeWrapper) object; - - return this.tag == other.tag && Objects.equals(this.wrapped, other.wrapped); - } - - @Override - public int hashCode() { - // Add one so that we don't have the exact same hash as the wrapped object. - // This means that we won't have a guaranteed collision if we're inserted to a map alongside the unwrapped object. - return this.wrapped.hashCode() + 1; - } - - @Override - public String toString() { - return "tagged(" +tag+ "):" + this.wrapped.toString(); - } - - private static boolean shouldSortOnUpload(RenderLayer type) { - return true; - // TODO: Iris -// return ((RenderTypeAccessor) type).shouldSortOnUpload(); - } -} diff --git a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java b/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java deleted file mode 100644 index fef62ee06..000000000 --- a/src/main/java/net/coderbot/iris/layer/OuterWrappedRenderType.java +++ /dev/null @@ -1,92 +0,0 @@ -package net.coderbot.iris.layer; - -import net.coderbot.batchedentityrendering.impl.WrappableRenderType; -import com.gtnewhorizons.angelica.compat.toremove.RenderPhase; -import com.gtnewhorizons.angelica.compat.toremove.RenderLayer; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; -import java.util.Optional; - -public class OuterWrappedRenderType extends RenderLayer implements WrappableRenderType { - private final RenderPhase extra; - private final RenderLayer wrapped; - - private OuterWrappedRenderType(String name, RenderLayer wrapped, RenderPhase extra) { - super(name, wrapped.format(), wrapped.mode(), wrapped.bufferSize(), - wrapped.hasCrumbling(), shouldSortOnUpload(wrapped), wrapped::startDrawing, wrapped::endDrawing); - - this.extra = extra; - this.wrapped = wrapped; - } - - public static OuterWrappedRenderType wrapExactlyOnce(String name, RenderLayer wrapped, RenderPhase extra) { - if (wrapped instanceof OuterWrappedRenderType outerWrappedRenderType) { - wrapped = outerWrappedRenderType.unwrap(); - } - - return new OuterWrappedRenderType(name, wrapped, extra); - } - - @Override - public void startDrawing() { - extra.startDrawing(); - - super.startDrawing(); - } - - @Override - public void endDrawing() { - super.endDrawing(); - - extra.endDrawing(); - } - - @Override - public RenderLayer unwrap() { - return this.wrapped; - } - - @Override - public Optional outline() { - return this.wrapped.outline(); - } - - @Override - public boolean isOutline() { - return this.wrapped.isOutline(); - } - - @Override - public boolean equals(@Nullable Object object) { - if (object == null) { - return false; - } - - if (object.getClass() != this.getClass()) { - return false; - } - - OuterWrappedRenderType other = (OuterWrappedRenderType) object; - - return Objects.equals(this.wrapped, other.wrapped) && Objects.equals(this.extra, other.extra); - } - - @Override - public int hashCode() { - // Add one so that we don't have the exact same hash as the wrapped object. - // This means that we won't have a guaranteed collision if we're inserted to a map alongside the unwrapped object. - return this.wrapped.hashCode() + 1; - } - - @Override - public String toString() { - return "iris_wrapped:" + this.wrapped.toString(); - } - - private static boolean shouldSortOnUpload(RenderLayer type) { - return true; - // TODO: Iris -// return ((RenderTypeAccessor) type).shouldSortOnUpload(); - } -} diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index d19e1d7c3..67b0c104c 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -1084,7 +1084,7 @@ public void beginLevelRendering() { isPostChain = false; phase = WorldRenderingPhase.NONE; overridePhase = null; - HandRenderer.INSTANCE.getBufferSource().resetDrawCalls(); +// HandRenderer.INSTANCE.getBufferSource().resetDrawCalls(); checkWorld(); diff --git a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java index c1f84a258..28b100b7c 100644 --- a/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/HandRenderer.java @@ -1,6 +1,5 @@ package net.coderbot.iris.pipeline; -import net.coderbot.batchedentityrendering.impl.FullyBufferedMultiBufferSource; import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.mojang.InteractionHand; import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; @@ -18,15 +17,13 @@ public class HandRenderer { private boolean ACTIVE; private boolean renderingSolid; - private final FullyBufferedMultiBufferSource bufferSource = new FullyBufferedMultiBufferSource(); - public static final float DEPTH = 0.125F; private void setupGlState(RenderGlobal gameRenderer, Camera camera, MatrixStack poseStack, float tickDelta) { - final MatrixStack.Entry pose = poseStack.peek(); +// final MatrixStack.Entry pose = poseStack.peek(); // We need to scale the matrix by 0.125 so the hand doesn't clip through blocks. - Matrix4f scaleMatrix = new Matrix4f().scale(1F, 1F, DEPTH); +// Matrix4f scaleMatrix = new Matrix4f().scale(1F, 1F, DEPTH); // TODO: ProjectionMatrix // scaleMatrix.multiply(gameRenderer.getProjectionMatrix(camera, tickDelta, false)); // scaleMatrix.mul(projectionMatrix); @@ -35,14 +32,14 @@ private void setupGlState(RenderGlobal gameRenderer, Camera camera, MatrixStack // RenderSystem.multMatrix(arg); // RenderSystem.matrixMode(5888); - pose.getModel().identity(); - pose.getNormal().identity(); +// pose.getModel().identity(); +// pose.getNormal().identity(); // gameRenderer.invokeBobHurt(poseStack, tickDelta); - - if (Minecraft.getMinecraft().gameSettings.viewBobbing) { -// gameRenderer.invokeBobView(poseStack, tickDelta); - } +// +// if (Minecraft.getMinecraft().gameSettings.viewBobbing) { +//// gameRenderer.invokeBobView(poseStack, tickDelta); +// } } private boolean canRender(Camera camera, RenderGlobal gameRenderer) { @@ -103,7 +100,7 @@ public void renderSolid(MatrixStack poseStack, float tickDelta, Camera camera, R // poseStack.pop(); - bufferSource.endBatch(); +// bufferSource.endBatch(); renderingSolid = false; @@ -137,7 +134,7 @@ public void renderTranslucent(MatrixStack poseStack, float tickDelta, Camera cam // TODO: ProjectionMatrix // gameRenderer.resetProjectionMatrix(CapturedRenderingState.INSTANCE.getGbufferProjection()); - bufferSource.endBatch(); +// bufferSource.endBatch(); pipeline.setPhase(WorldRenderingPhase.NONE); @@ -152,7 +149,4 @@ public boolean isRenderingSolid() { return renderingSolid; } - public FullyBufferedMultiBufferSource getBufferSource() { - return bufferSource; - } } diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index b56e1d297..bc39af666 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -1,7 +1,6 @@ package net.coderbot.iris.pipeline; import com.google.common.collect.ImmutableList; -import com.gtnewhorizons.angelica.compat.toremove.BufferSource; import com.gtnewhorizons.angelica.compat.mojang.Camera; import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import com.gtnewhorizons.angelica.glsm.GLStateManager; @@ -349,7 +348,7 @@ private void copyPreTranslucentDepth() { targets.copyPreTranslucentDepth(); } - private void renderEntities(EntityRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { + private void renderEntities(EntityRenderer levelRenderer, Frustrum frustum, Object bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { // TODO: Render // EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); @@ -394,7 +393,7 @@ private void renderEntities(EntityRenderer levelRenderer, Frustrum frustum, Buff profiler.endSection(); } - private void renderPlayerEntity(EntityRenderer levelRenderer, Frustrum frustum, BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { + private void renderPlayerEntity(EntityRenderer levelRenderer, Frustrum frustum, Object bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float tickDelta) { // TODO: Render // EntityRenderDispatcher dispatcher = levelRenderer.getEntityRenderDispatcher(); @@ -431,7 +430,7 @@ private void renderPlayerEntity(EntityRenderer levelRenderer, Frustrum frustum, profiler.endSection(); } - private void renderTileEntities(BufferSource bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float partialTicks, boolean hasEntityFrustum) { + private void renderTileEntities(Object bufferSource, MatrixStack modelView, double cameraX, double cameraY, double cameraZ, float partialTicks, boolean hasEntityFrustum) { profiler.startSection("build blockentities"); int shadowTileEntities = 0; @@ -577,10 +576,9 @@ public void renderShadows(EntityRenderer levelRenderer, Camera playerCamera) { // } // BufferSource bufferSource = buffers.bufferSource(); - BufferSource bufferSource = null; if (shouldRenderEntities) { - renderEntities(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); + renderEntities(levelRenderer, entityShadowFrustum, null, modelView, cameraX, cameraY, cameraZ, tickDelta); } else if (shouldRenderPlayer) { // renderPlayerEntity(levelRenderer, entityShadowFrustum, bufferSource, modelView, cameraX, cameraY, cameraZ, tickDelta); } diff --git a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java index 3072f29fd..81a1e2224 100644 --- a/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java +++ b/src/main/java/net/coderbot/iris/pipeline/WorldRenderingPhase.java @@ -28,19 +28,4 @@ public enum WorldRenderingPhase { WORLD_BORDER, HAND_TRANSLUCENT; - public static WorldRenderingPhase fromTerrainRenderType(RenderLayer renderType) { - if (renderType == RenderLayer.solid()) { - return WorldRenderingPhase.TERRAIN_SOLID; - } else if (renderType == RenderLayer.cutout()) { - return WorldRenderingPhase.TERRAIN_CUTOUT; - } else if (renderType == RenderLayer.cutoutMipped()) { - return WorldRenderingPhase.TERRAIN_CUTOUT_MIPPED; - } else if (renderType == RenderLayer.translucent()) { - return WorldRenderingPhase.TERRAIN_TRANSLUCENT; - } else if (renderType == RenderLayer.tripwire()) { - return WorldRenderingPhase.TRIPWIRE; - } else { - throw new IllegalStateException("Illegal render type!"); - } - } } From 553735a44c3ba2b360b2e89ffbe670c35a7a8676 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 24 Dec 2023 10:42:23 -0800 Subject: [PATCH 291/301] RM --- .../gtnewhorizons/angelica/mixins/Mixins.java | 5 ----- .../mixins/late/compat/MixinJabba.java | 18 ------------------ .../client/render/pipeline/BlockRenderer.java | 2 -- 3 files changed, 25 deletions(-) delete mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinJabba.java diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 180eba4cb..29c4fe79a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -105,11 +105,6 @@ public enum Mixins { ) ), - SODIUM_JABBA_COMPAT(new Builder("Sodium Jabba Compat").addTargetedMod(TargetedMod.JABBA).setSide(Side.CLIENT) - .setPhase(Phase.LATE).setApplyIf(() -> AngelicaConfig.enableSodium) - .addMixinClasses("compat.MixinJabba") - ), - // Required for Sodium's FluidRenderer, so it treats vanilla liquids as IFluidBlocks SODIUM_WISHLIST(new Builder("Sodiumer").addTargetedMod(TargetedMod.VANILLA).setSide(Side.BOTH) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableSodiumFluidRendering).addMixinClasses( diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinJabba.java b/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinJabba.java deleted file mode 100644 index b6dbfad35..000000000 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/late/compat/MixinJabba.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.gtnewhorizons.angelica.mixins.late.compat; - -import mcp.mobius.betterbarrels.client.ClientProxy; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -@Mixin(value = ClientProxy.class, remap = false) -public class MixinJabba { - - /** - * @author mitchej123 - * @reason We're redirecting their renderer so don't blow up - */ - @Overwrite - public void registerRenderers() { - // Do nothing - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java index ec05b5d48..39bb9e67d 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/pipeline/BlockRenderer.java @@ -32,8 +32,6 @@ import java.util.Random; public class BlockRenderer { - public static Vector3d ZERO = new Vector3d(0, 0, 0); - private static final MatrixStack EMPTY_STACK = new MatrixStack(); private final Random random = new XoRoShiRoRandom(); From fbbd642c4ee39ce2abded97a28e0fe032fb59118 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 24 Dec 2023 10:46:04 -0800 Subject: [PATCH 292/301] Require CCC 1.2.0+ --- src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index 256b1a2b0..f7508b79a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -12,7 +12,7 @@ modid = "angelica", name = "Angelica", version = Tags.VERSION, - dependencies = " before:lwjgl3ify@[1.5.3,);" + " after:hodgepodge@[2.3.35,);", + dependencies = " before:lwjgl3ify@[1.5.3,);" + " after:hodgepodge@[2.3.35,);" + " after:CodeChickenCore@[1.2.0,);", acceptedMinecraftVersions = "[1.7.10]", acceptableRemoteVersions = "*") public class AngelicaMod { From c012480e16636dbcb62d0459bc2f94c9c399b937 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 24 Dec 2023 11:42:51 -0800 Subject: [PATCH 293/301] Depend on CCC 1.2 --- dependencies.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/dependencies.gradle b/dependencies.gradle index cfe2ed757..9c8f64738 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -53,6 +53,7 @@ dependencies { // Because who doesn't want NEI devOnlyNonPublishable('com.github.GTNewHorizons:NotEnoughItems:2.4.9-GTNH:dev') + api('com.github.GTNewHorizons:CodeChickenCore:1.2.0:dev') // Notfine Deps compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev") From 3473b30aec783f52b5cf3fc2d7f4e209fcead891 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 24 Dec 2023 11:43:25 -0800 Subject: [PATCH 294/301] devOnlyNonPublishable --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 9c8f64738..ee4c72f6b 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -53,7 +53,7 @@ dependencies { // Because who doesn't want NEI devOnlyNonPublishable('com.github.GTNewHorizons:NotEnoughItems:2.4.9-GTNH:dev') - api('com.github.GTNewHorizons:CodeChickenCore:1.2.0:dev') + devOnlyNonPublishable('com.github.GTNewHorizons:CodeChickenCore:1.2.0:dev') // Notfine Deps compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev") From cae6672a463e29bb9f6b5d77b73ee827d89e1d1a Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 24 Dec 2023 14:51:19 -0500 Subject: [PATCH 295/301] Fix TESRs not being tracked for blocks rendered on main thread --- .../chunk/tasks/ChunkRenderRebuildTask.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java index 93c245251..b12e5b60f 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/tasks/ChunkRenderRebuildTask.java @@ -131,34 +131,34 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB continue; } - if (!rendersOffThread(block)) { - hasMainThreadBlocks = true; - continue; - } - int meta = slice.getBlockMetadataRelative(relX + 16, relY + 16, relZ + 16); pos.set(baseX + relX, baseY + relY, baseZ + relZ); buffers.setRenderOffset(pos.x - renderOffset.getX(), pos.y - renderOffset.getY(), pos.z - renderOffset.getZ()); + if(AngelicaConfig.enableIris) buffers.iris$setLocalPos(relX, relY, relZ); - // Do regular block rendering - for (BlockRenderPass pass : BlockRenderPass.VALUES) { - if (block.canRenderInPass(pass.ordinal()) && (!AngelicaConfig.enableSodiumFluidRendering || !(block instanceof IFluidBlock))) { - long seed = MathUtil.hashPos(pos.x, pos.y, pos.z); - if(AngelicaConfig.enableIris) buffers.iris$setMaterialId(block, ExtendedDataHelper.BLOCK_RENDER_TYPE); + if (rendersOffThread(block)) { + // Do regular block rendering + for (BlockRenderPass pass : BlockRenderPass.VALUES) { + if (block.canRenderInPass(pass.ordinal()) && (!AngelicaConfig.enableSodiumFluidRendering || !(block instanceof IFluidBlock))) { + long seed = MathUtil.hashPos(pos.x, pos.y, pos.z); + if(AngelicaConfig.enableIris) buffers.iris$setMaterialId(block, ExtendedDataHelper.BLOCK_RENDER_TYPE); - if (cache.getBlockRenderer().renderModel(cache.getWorldSlice(), tessellator, renderBlocks, block, meta, pos, buffers.get(pass), true, seed)) { - bounds.addBlock(relX, relY, relZ); + if (cache.getBlockRenderer().renderModel(cache.getWorldSlice(), tessellator, renderBlocks, block, meta, pos, buffers.get(pass), true, seed)) { + bounds.addBlock(relX, relY, relZ); + } } } + } else { + hasMainThreadBlocks = true; } // Do fluid rendering without RenderBlocks if (AngelicaConfig.enableSodiumFluidRendering && block instanceof IFluidBlock) { for (BlockRenderPass pass : BlockRenderPass.VALUES) { if (block.canRenderInPass(pass.ordinal())) { - if(AngelicaConfig.enableIris) buffers.iris$setMaterialId(block, ExtendedDataHelper.FLUID_RENDER_TYPE); + if(AngelicaConfig.enableIris) buffers.iris$setMaterialId(block, ExtendedDataHelper.FLUID_RENDER_TYPE); if (cache.getFluidRenderer().render(slice, cache.getWorldSlice(), block, pos, buffers.get(pass))) { bounds.addBlock(relX, relY, relZ); @@ -168,6 +168,7 @@ public ChunkBuildResult performBuild(ChunkRenderCacheLocal cache, ChunkBuildB } if(AngelicaConfig.enableIris) buffers.iris$resetBlockContext(); + if (block.hasTileEntity(meta)) { TileEntity entity = slice.getTileEntity(pos.x, pos.y, pos.z); @@ -262,6 +263,8 @@ private void performMainBuild(ChunkRenderCacheLocal cache, ChunkBuildBuffers buf } } } + + if(AngelicaConfig.enableIris) buffers.iris$resetBlockContext(); } } } From 8c8ed87e83e1dd6c45b45a270663e063293aea00 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 24 Dec 2023 15:37:41 -0500 Subject: [PATCH 296/301] Cut down number of runtime dependencies, enable CoreTweaks in dev by default --- dependencies.gradle | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index ee4c72f6b..71a03a6f8 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -35,7 +35,7 @@ */ dependencies { - api("com.github.GTNewHorizons:Hodgepodge:2.3.37") + compileOnly("com.github.GTNewHorizons:Hodgepodge:2.3.37") compileOnly("org.projectlombok:lombok:1.18.22") {transitive = false } annotationProcessor("org.projectlombok:lombok:1.18.22") @@ -52,26 +52,26 @@ dependencies { compileOnly "org.apache.ant:ant:1.8.2" // Because who doesn't want NEI - devOnlyNonPublishable('com.github.GTNewHorizons:NotEnoughItems:2.4.9-GTNH:dev') - devOnlyNonPublishable('com.github.GTNewHorizons:CodeChickenCore:1.2.0:dev') + compileOnly('com.github.GTNewHorizons:NotEnoughItems:2.4.9-GTNH:dev') + compileOnly('com.github.GTNewHorizons:CodeChickenCore:1.2.0:dev') // Notfine Deps compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev") runtimeOnly("com.github.GTNewHorizons:Baubles:1.0.1.16:dev") compileOnly("com.github.GTNewHorizons:twilightforest:2.5.1:dev") {transitive = false } - devOnlyNonPublishable(rfg.deobf('curse.maven:witchery-69673:2234410')) + compileOnly(rfg.deobf('curse.maven:witchery-69673:2234410')) compileOnly(rfg.deobf("curse.maven:extrautils-225561:2264383")) compileOnly(rfg.deobf("curse.maven:dynamiclights-227874:2337326")) compileOnly("com.github.GTNewHorizons:NotEnoughIds:1.5.3:dev") // Mixin Version - devOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughIds-Legacy:1.4.7:dev") // ASM Version + compileOnly("com.github.GTNewHorizons:NotEnoughIds-Legacy:1.4.7:dev") // ASM Version compileOnly("com.github.GTNewHorizons:Jabba:1.3.1:dev") // HMMMMM compileOnly(rfg.deobf("curse.maven:journeymap-32274:2367915")) -// runtimeOnly(deobf("https://github.com/makamys/CoreTweaks/releases/download/0.3.0.4/CoreTweaks-1.7.10-0.3.0.4+nomixin.jar")) + runtimeOnly(deobf("https://github.com/makamys/CoreTweaks/releases/download/0.3.3.2/CoreTweaks-1.7.10-0.3.3.2+nomixin.jar")) } From fa55c68bceba04d5e64aa9de87be96083722530e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 24 Dec 2023 15:39:39 -0500 Subject: [PATCH 297/301] Turn off mixin debug by default Should make launches slightly faster in dev --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 0a4da1cc3..dc5aec721 100644 --- a/gradle.properties +++ b/gradle.properties @@ -67,7 +67,7 @@ accessTransformersFile = angelica_at.cfg notfine_at.cfg archaicfix_at.cfg # Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! usesMixins = true # Adds some debug arguments like verbose output and export -usesMixinDebug = true +usesMixinDebug = false # Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise. mixinPlugin = # Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail! From 96d94faf0e9ed59f50256a815ef228da8b93a677 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 24 Dec 2023 15:41:04 -0500 Subject: [PATCH 298/301] Temporarily patch build.gradle to reduce configure times Will be fixed upstream in https://github.com/GTNewHorizons/ExampleMod1.7.10/pull/244 --- build.gradle | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index 394d31cb3..65487eae8 100644 --- a/build.gradle +++ b/build.gradle @@ -628,7 +628,7 @@ repositories { } maven { name = "ic2" - url = getURL("https://maven.ic2.player.to/", "https://maven2.ic2.player.to/") + url = getURL("https://maven2.ic2.player.to/", "https://maven.ic2.player.to/") content { includeGroup "net.industrial-craft" } @@ -972,10 +972,6 @@ if (usesShadowedDependencies.toBoolean()) { configurations.apiElements.outgoing.artifacts.clear() configurations.runtimeElements.outgoing.artifact(tasks.named("shadowJar", ShadowJar)) configurations.apiElements.outgoing.artifact(tasks.named("shadowJar", ShadowJar)) - tasks.named("jar", Jar) { - enabled = false - finalizedBy(tasks.shadowJar) - } tasks.named("reobfJar", ReobfuscatedJar) { inputJar.set(tasks.named("shadowJar", ShadowJar).flatMap({it.archiveFile})) } @@ -983,11 +979,6 @@ if (usesShadowedDependencies.toBoolean()) { javaComponent.withVariantsFromConfiguration(configurations.shadowRuntimeElements) { skip() } - for (runTask in ["runClient", "runServer", "runClient17", "runServer17"]) { - tasks.named(runTask).configure { - dependsOn("shadowJar") - } - } } ext.publishableDevJar = usesShadowedDependencies.toBoolean() ? tasks.shadowJar : tasks.jar ext.publishableObfJar = tasks.reobfJar From 2c0c9a810bd4607ca54fee0a96010e524ceb906e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 24 Dec 2023 16:09:26 -0500 Subject: [PATCH 299/301] Add modern F3 background --- .../angelica/proxy/ClientProxy.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java index f3ae012f1..7e2b7477a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizons/angelica/proxy/ClientProxy.java @@ -16,7 +16,10 @@ import net.coderbot.iris.client.IrisDebugScreenHandler; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.GuiMainMenu; +import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.util.Direction; @@ -123,6 +126,31 @@ public void onRenderOverlay(RenderGameOverlayEvent.Text event) { event.left.set(i + 3, String.format("Facing: %s (%s) (%.1f / %.1f)", Direction.directions[heading].toLowerCase(Locale.ROOT), heading_str, MathHelper.wrapAngleTo180_float(mc.thePlayer.rotationYaw), MathHelper.wrapAngleTo180_float(mc.thePlayer.rotationPitch))); } } + event.setCanceled(true); + /* render ourselves for modern background */ + FontRenderer fontrenderer = mc.fontRenderer; + int fontColor = 0xe0e0e0; + int rectColor = 0x90505050; + for (int x = 0; x < event.left.size(); x++) + { + String msg = event.left.get(x); + if (msg == null) continue; + int strX = 2; + int strY = 2 + x * fontrenderer.FONT_HEIGHT; + Gui.drawRect(1, strY - 1, strX + fontrenderer.getStringWidth(msg) + 1, strY + fontrenderer.FONT_HEIGHT - 1, rectColor); + fontrenderer.drawString(msg, strX, strY, fontColor); + } + int width = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight).getScaledWidth(); + for (int x = 0; x < event.right.size(); x++) + { + String msg = event.right.get(x); + if (msg == null) continue; + int w = fontrenderer.getStringWidth(msg); + int strX = width - w - 2; + int strY = 2 + x * fontrenderer.FONT_HEIGHT; + Gui.drawRect(strX - 1, strY - 1, strX + w + 1, strY + fontrenderer.FONT_HEIGHT - 1, rectColor); + fontrenderer.drawString(msg, strX, strY, fontColor); + } } } From edff367e34efe7a0b617c248d9e1bbc75be4d576 Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 24 Dec 2023 15:56:54 -0800 Subject: [PATCH 300/301] Pull over some hodgepodge mixins --- build.gradle | 2 +- dependencies.gradle | 2 +- .../gtnewhorizons/angelica/AngelicaMod.java | 6 +- .../angelica/config/AngelicaConfig.java | 16 +++++ .../gtnewhorizons/angelica/mixins/Mixins.java | 34 ++++++--- .../angelica/animation/MixinBlockFire.java | 22 ++++++ .../angelica/animation/MixinChunkCache.java | 21 ++++++ .../animation/MixinMinecraftForgeClient.java | 39 ++++++++++ .../animation/MixinRenderBlockFluid.java | 43 +++++++++++ .../angelica/animation/MixinRenderBlocks.java | 57 +++++++++++++++ .../angelica/animation/MixinRenderItem.java | 25 +++++++ .../animation/MixinTextureAtlasSprite.java | 57 +++++++++++++++ .../angelica/animation/MixinTextureMap.java | 60 ++++++++++++++++ .../animation/MixinWorldRenderer.java | 46 ++++++++++++ .../MixinWorld_FixLightUpdateLag.java | 39 ++++++++++ .../MixinTextureUtil_OptimizeMipmap.java | 71 +++++++++++++++++++ .../IPatchedTextureAtlasSprite.java | 12 ++++ .../mixins/interfaces/ITexturesCache.java | 10 +++ .../angelica/utils/AnimationMode.java | 7 ++ .../angelica/utils/AnimationsRenderUtils.java | 31 ++++++++ .../angelica/utils/ManagedEnum.java | 52 ++++++++++++++ .../gtnewhorizons/angelica/utils/Mipmaps.java | 25 +++++++ .../mods/sodium/client/world/WorldSlice.java | 61 ++++++++-------- src/main/java/net/coderbot/iris/Iris.java | 17 +++++ .../iris/client/IrisDebugScreenHandler.java | 6 ++ src/main/resources/mcmod.info | 18 ----- 26 files changed, 718 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinBlockFire.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinChunkCache.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinMinecraftForgeClient.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderBlockFluid.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderBlocks.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderItem.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinTextureAtlasSprite.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinTextureMap.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinWorldRenderer.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/lighting/MixinWorld_FixLightUpdateLag.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureUtil_OptimizeMipmap.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IPatchedTextureAtlasSprite.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ITexturesCache.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/utils/AnimationMode.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/utils/AnimationsRenderUtils.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/utils/ManagedEnum.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/utils/Mipmaps.java diff --git a/build.gradle b/build.gradle index 65487eae8..5eab54f53 100644 --- a/build.gradle +++ b/build.gradle @@ -798,7 +798,7 @@ dependencies { java17Dependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}") } if (modId != 'hodgepodge') { - java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.3.17') + java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.4.3') } java17PatchDependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}:forgePatches") {transitive = false} diff --git a/dependencies.gradle b/dependencies.gradle index 71a03a6f8..cc3bc52d4 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -35,7 +35,7 @@ */ dependencies { - compileOnly("com.github.GTNewHorizons:Hodgepodge:2.3.37") + compileOnly("com.github.GTNewHorizons:Hodgepodge:2.4.3") compileOnly("org.projectlombok:lombok:1.18.22") {transitive = false } annotationProcessor("org.projectlombok:lombok:1.18.22") diff --git a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java index f7508b79a..91d120bca 100644 --- a/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/AngelicaMod.java @@ -1,6 +1,8 @@ package com.gtnewhorizons.angelica; import com.gtnewhorizons.angelica.proxy.CommonProxy; +import com.gtnewhorizons.angelica.utils.AnimationMode; +import com.gtnewhorizons.angelica.utils.ManagedEnum; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.SidedProxy; @@ -12,7 +14,7 @@ modid = "angelica", name = "Angelica", version = Tags.VERSION, - dependencies = " before:lwjgl3ify@[1.5.3,);" + " after:hodgepodge@[2.3.35,);" + " after:CodeChickenCore@[1.2.0,);", + dependencies = " before:lwjgl3ify@[1.5.3,);" + " after:hodgepodge@[2.4.3,);" + " after:CodeChickenCore@[1.2.0,);", acceptedMinecraftVersions = "[1.7.10]", acceptableRemoteVersions = "*") public class AngelicaMod { @@ -24,6 +26,8 @@ public class AngelicaMod { public static boolean isOldNEIDLoaded; public static final boolean lwjglDebug = Boolean.parseBoolean(System.getProperty("org.lwjgl.util.Debug", "false")); + public static final ManagedEnum animationsMode = new ManagedEnum<>(AnimationMode.VISIBLE_ONLY); + @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { isNEIDLoaded = Loader.isModLoaded("neid"); diff --git a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java index 966d45ff6..cc110d193 100644 --- a/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java +++ b/src/main/java/com/gtnewhorizons/angelica/config/AngelicaConfig.java @@ -36,6 +36,7 @@ public class AngelicaConfig { public static boolean showBlockDebugInfo; @Config.DefaultBoolean(true) + @Config.Comment("Hide downloading terrain screen. [From ArchaicFix]") public static boolean hideDownloadingTerrainScreen; @Config.Comment("Show memory usage during game load. [From ArchaicFix]") @@ -52,4 +53,19 @@ public class AngelicaConfig { @Config.DefaultBoolean(true) @Config.RequiresMcRestart public static boolean enableFontRenderer; + + @Config.Comment("Optimize world update light. [From Hodgepodge]") + @Config.DefaultBoolean(true) + @Config.RequiresMcRestart + public static boolean optimizeWorldUpdateLight; + + @Config.Comment("Speedup Animations. [From Hodgepodge]") + @Config.DefaultBoolean(true) + @Config.RequiresMcRestart + public static boolean speedupAnimations; + + @Config.Comment("Optimize Texture Loading. [From Hodgepodge]") + @Config.DefaultBoolean(true) + @Config.RequiresMcRestart + public static boolean optimizeTextureLoading; } diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 29c4fe79a..036801d03 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -3,8 +3,8 @@ import com.gtnewhorizons.angelica.AngelicaMod; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import com.mitchej123.hodgepodge.Common; import cpw.mods.fml.relauncher.FMLLaunchHandler; -import me.jellysquid.mods.sodium.common.config.SodiumConfig; import java.util.ArrayList; import java.util.Arrays; @@ -152,17 +152,31 @@ public enum Mixins { ), - // TODO: Iris -// SHADERSMOD_COMPAT_PR_ILLUMINATION( -// new Builder("ProjectRed Illumination compat").addTargetedMod(TargetedMod.PROJECTRED_ILLUMINATION) -// .setSide(Side.CLIENT).addMixinClasses("compat.MixinRenderHalo")), -// -// SHADERSMOD_COMPAT_SMART_RENDER(new Builder("Smart Render compat").addTargetedMod(TargetedMod.SMART_RENDER).setSide(Side.CLIENT) -// .addMixinClasses("compat.MixinModelRotationRenderer")) + OPTIMIZE_WORLD_UPDATE_LIGHT(new Builder("Optimize world updateLightByType method").setPhase(Phase.EARLY) + .setSide(Side.BOTH).addTargetedMod(TargetedMod.VANILLA).setApplyIf(() -> AngelicaConfig.optimizeWorldUpdateLight) + .addMixinClasses("angelica.lighting.MixinWorld_FixLightUpdateLag")), + + + SPEEDUP_VANILLA_ANIMATIONS(new Builder("Speedup Vanilla Animations").setPhase(Phase.EARLY) + .setApplyIf(() -> AngelicaConfig.speedupAnimations).setSide(Side.CLIENT).addTargetedMod(TargetedMod.VANILLA) + .addMixinClasses( + "angelica.animation.MixinTextureAtlasSprite", + "angelica.animation.MixinTextureMap", + "angelica.animation.MixinBlockFire", + "angelica.animation.MixinMinecraftForgeClient", + "angelica.animation.MixinChunkCache", + "angelica.animation.MixinRenderBlocks", + "angelica.animation.MixinRenderBlockFluid", + "angelica.animation.MixinWorldRenderer", + "angelica.animation.MixinRenderItem")), + + OPTIMIZE_TEXTURE_LOADING(new Builder("Optimize Texture Loading").setPhase(Phase.EARLY) + .addMixinClasses("angelica.textures.MixinTextureUtil_OptimizeMipmap").addTargetedMod(TargetedMod.VANILLA) + .setApplyIf(() -> AngelicaConfig.optimizeTextureLoading).setSide(Side.CLIENT)), NOTFINE_OPTIMIZATION(new Builder("NotFine Optimizations").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableNotFineOptimizations).addMixinClasses( - "notfine.faceculling.MixinBlock" + "notfine.faceculling.MixinBlock" ,"notfine.faceculling.MixinBlockSlab" ,"notfine.faceculling.MixinBlockSnow" ,"notfine.faceculling.MixinBlockStairs" @@ -170,7 +184,7 @@ public enum Mixins { NOTFINE_FEATURES(new Builder("NotFine Features").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT) .setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.enableNotFineFeatures).addMixinClasses( - "notfine.glint.MixinItemRenderer" + "notfine.glint.MixinItemRenderer" ,"notfine.glint.MixinRenderBiped" ,"notfine.glint.MixinRenderItem" ,"notfine.glint.MixinRenderPlayer" diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinBlockFire.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinBlockFire.java new file mode 100644 index 000000000..47178e159 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinBlockFire.java @@ -0,0 +1,22 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.animation; + +import com.gtnewhorizons.angelica.utils.AnimationsRenderUtils; +import net.minecraft.block.BlockFire; +import net.minecraft.util.IIcon; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(BlockFire.class) +public class MixinBlockFire { + + @Shadow + private IIcon[] field_149850_M; + + @Inject(method = "getFireIcon", at = @At("HEAD")) + private void hodgepodge$markFireAnimationForUpdate(int p_149840_1_, CallbackInfoReturnable cir) { + AnimationsRenderUtils.markBlockTextureForUpdate(field_149850_M[p_149840_1_]); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinChunkCache.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinChunkCache.java new file mode 100644 index 000000000..e8a7f2dee --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinChunkCache.java @@ -0,0 +1,21 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.animation; + +import com.gtnewhorizons.angelica.mixins.interfaces.ITexturesCache; +import net.minecraft.util.IIcon; +import net.minecraft.world.ChunkCache; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +import java.util.HashSet; + +@Mixin(ChunkCache.class) +public class MixinChunkCache implements ITexturesCache { + + @Unique + private final HashSet renderedIcons = new HashSet<>(); + + @Override + public HashSet getRenderedTextures() { + return renderedIcons; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinMinecraftForgeClient.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinMinecraftForgeClient.java new file mode 100644 index 000000000..8b6d7152b --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinMinecraftForgeClient.java @@ -0,0 +1,39 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.animation; + +import com.gtnewhorizons.angelica.mixins.interfaces.IPatchedTextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraftforge.client.IItemRenderer; +import net.minecraftforge.client.MinecraftForgeClient; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(MinecraftForgeClient.class) +public class MixinMinecraftForgeClient { + + /** + * @author laetansky We can just mark any item texture that gets rendered for an update + */ + @Inject(method = "getItemRenderer", at = @At("HEAD"), remap = false) + private static void hodgepodge$beforeRenderItem(ItemStack itemStack, IItemRenderer.ItemRenderType type, + CallbackInfoReturnable cir) { + final Item item = itemStack.getItem(); + if (item.requiresMultipleRenderPasses()) { + for (int i = 0; i < item.getRenderPasses(itemStack.getItemDamage()); i++) { + IIcon icon = item.getIcon(itemStack, i); + if (icon instanceof TextureAtlasSprite) { + ((IPatchedTextureAtlasSprite) icon).markNeedsAnimationUpdate(); + } + } + } else { + final IIcon icon = itemStack.getIconIndex(); + if (icon instanceof TextureAtlasSprite) { + ((IPatchedTextureAtlasSprite) icon).markNeedsAnimationUpdate(); + } + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderBlockFluid.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderBlockFluid.java new file mode 100644 index 000000000..de4a96698 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderBlockFluid.java @@ -0,0 +1,43 @@ +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; + +@Mixin(value = RenderBlockFluid.class, remap = false) +public abstract class MixinRenderBlockFluid { + + @Unique + private IBlockAccess currentBlockAccess; + + @Inject(method = "renderWorldBlock", at = @At(value = "HEAD")) + private void hodgepodge$saveCurrentBlockAccess(IBlockAccess world, int x, int y, int z, Block block, int modelId, + RenderBlocks renderer, CallbackInfoReturnable 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"); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderBlocks.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderBlocks.java new file mode 100644 index 000000000..ffdc7c827 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderBlocks.java @@ -0,0 +1,57 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.animation; + +import com.gtnewhorizons.angelica.utils.AnimationsRenderUtils; +import net.minecraft.block.Block; +import net.minecraft.block.BlockFire; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(RenderBlocks.class) +public class MixinRenderBlocks { + + @Shadow + public IBlockAccess blockAccess; + + @Shadow + public IIcon overrideBlockTexture; + + /** + * @author laetansky Here where things get very tricky. We can't just mark blocks textures for update because this + * method gets called only when chunk render cache needs an update (that happens when a state of any block + * in that chunk changes). What we can do though is pass the rendered textures up to the WorldRenderer and + * later use it in RenderGlobal to mark textures for update and before that even sort WorldRenderers and + * apply Occlusion Querry (Basically that means that we will only mark those textures for update that are + * visible (on the viewport) at the moment) + */ + @Inject(method = "*(Lnet/minecraft/block/Block;DDDLnet/minecraft/util/IIcon;)V", at = @At("HEAD")) + public void hodgepodge$beforeRenderFace(Block p_147761_1_, double p_147761_2_, double p_147761_4_, + double p_147761_6_, IIcon icon, CallbackInfo ci) { + if (overrideBlockTexture != null) { + icon = overrideBlockTexture; + } + + AnimationsRenderUtils.markBlockTextureForUpdate(icon, blockAccess); + } + + @Inject(method = "renderBlockFire", at = @At("HEAD")) + public void hodgepodge$markFireBlockAnimationForUpdate(BlockFire instance, int x, int y, int z, + CallbackInfoReturnable cir) { + AnimationsRenderUtils.markBlockTextureForUpdate(instance.getFireIcon(0), blockAccess); + AnimationsRenderUtils.markBlockTextureForUpdate(instance.getFireIcon(1), blockAccess); + } + + @ModifyVariable(method = "renderBlockLiquid", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/client/renderer/RenderBlocks;getBlockIconFromSideAndMetadata(Lnet/minecraft/block/Block;II)Lnet/minecraft/util/IIcon;")) + public IIcon hodgepodge$markFluidAnimationForUpdate(IIcon icon) { + AnimationsRenderUtils.markBlockTextureForUpdate(icon, blockAccess); + + return icon; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderItem.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderItem.java new file mode 100644 index 000000000..00c88c523 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinRenderItem.java @@ -0,0 +1,25 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.animation; + +import com.gtnewhorizons.angelica.mixins.interfaces.IPatchedTextureAtlasSprite; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.IIcon; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(RenderItem.class) +public class MixinRenderItem { + + /** + * Some mods may call it to render their internally stored icons, so we make sure we mark those for an update + */ + @Inject(method = "renderIcon", at = @At("HEAD")) + private void hodgepodge$beforeRenderIcon(int p_94149_1_, int p_94149_2_, IIcon icon, int p_94149_4_, int p_94149_5_, + CallbackInfo ci) { + if (icon instanceof TextureAtlasSprite) { + ((IPatchedTextureAtlasSprite) icon).markNeedsAnimationUpdate(); + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinTextureAtlasSprite.java new file mode 100644 index 000000000..eed3a916c --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinTextureAtlasSprite.java @@ -0,0 +1,57 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.animation; + +import com.gtnewhorizons.angelica.mixins.interfaces.IPatchedTextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.data.AnimationMetadataSection; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +import java.util.List; + +@Mixin(TextureAtlasSprite.class) +public abstract class MixinTextureAtlasSprite implements IPatchedTextureAtlasSprite { + + @Unique + private boolean needsAnimationUpdate = false; + + @Shadow + protected int tickCounter; + @Shadow + protected int frameCounter; + + @Shadow + private AnimationMetadataSection animationMetadata; + + @Shadow + protected List framesTextureData; + + @Override + public void markNeedsAnimationUpdate() { + needsAnimationUpdate = true; + } + + @Override + public boolean needsAnimationUpdate() { + return needsAnimationUpdate; + } + + @Override + public void unmarkNeedsAnimationUpdate() { + needsAnimationUpdate = false; + } + + @Override + public void updateAnimationsDryRun() { + // account for weird subclass that doesn't use the stock mechanisms for animation + if (animationMetadata == null || framesTextureData == null) return; + + tickCounter++; + if (tickCounter >= animationMetadata.getFrameTimeSingle(frameCounter)) { + int j = this.animationMetadata.getFrameCount() == 0 ? framesTextureData.size() + : this.animationMetadata.getFrameCount(); + this.frameCounter = (this.frameCounter + 1) % j; + this.tickCounter = 0; + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinTextureMap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinTextureMap.java new file mode 100644 index 000000000..e75b58bc1 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinTextureMap.java @@ -0,0 +1,60 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.animation; + +import com.gtnewhorizons.angelica.AngelicaMod; +import com.gtnewhorizons.angelica.mixins.interfaces.IPatchedTextureAtlasSprite; +import com.gtnewhorizons.angelica.utils.AnimationMode; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +import java.util.List; + +@Mixin(value = TextureMap.class, priority = 999) +@SuppressWarnings("ForLoopReplaceableByForEach") +public abstract class MixinTextureMap extends AbstractTexture { + + @Shadow + @Final + private List listAnimatedSprites; + + @Unique + private static final Minecraft mc = Minecraft.getMinecraft(); + + /** + * @author laetansky + * @reason only update animations for textures that are being currently drawn By default minecraft handles any + * animations that present in listAnimatedSprites no matter if you see it or not which can lead to a huge + * performance decrease + */ + @Overwrite + public void updateAnimations() { + final boolean renderAllAnimations = AngelicaMod.animationsMode.is(AnimationMode.ALL); + final boolean renderVisibleAnimations = AngelicaMod.animationsMode.is(AnimationMode.VISIBLE_ONLY); + + mc.mcProfiler.startSection("updateAnimations"); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.getGlTextureId()); + // C Style loop should be faster + final int size = listAnimatedSprites.size(); + for (int i = 0; i < size; i++) { + final TextureAtlasSprite textureAtlasSprite = listAnimatedSprites.get(i); + final IPatchedTextureAtlasSprite patchedTextureAtlasSprite = ((IPatchedTextureAtlasSprite) textureAtlasSprite); + + if (renderAllAnimations || (renderVisibleAnimations && patchedTextureAtlasSprite.needsAnimationUpdate())) { + mc.mcProfiler.startSection(textureAtlasSprite.getIconName()); + textureAtlasSprite.updateAnimation(); + patchedTextureAtlasSprite.unmarkNeedsAnimationUpdate(); + mc.mcProfiler.endSection(); + } else { + patchedTextureAtlasSprite.updateAnimationsDryRun(); + } + } + mc.mcProfiler.endSection(); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinWorldRenderer.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinWorldRenderer.java new file mode 100644 index 000000000..01da53aa0 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/animation/MixinWorldRenderer.java @@ -0,0 +1,46 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.animation; + +import com.gtnewhorizons.angelica.mixins.interfaces.IPatchedTextureAtlasSprite; +import com.gtnewhorizons.angelica.mixins.interfaces.ITexturesCache; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +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.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Set; + +@Mixin(WorldRenderer.class) +public class MixinWorldRenderer implements ITexturesCache { + + @Shadow + public boolean isInFrustum; + + @Unique + private Set renderedIcons; + + @ModifyArg(method = "updateRenderer", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderBlocks;(Lnet/minecraft/world/IBlockAccess;)V")) + private IBlockAccess hodgepodge$onUpdateRenderer(IBlockAccess chunkCache) { + renderedIcons = ((ITexturesCache) chunkCache).getRenderedTextures(); + return chunkCache; + } + + @Inject(method = "getGLCallListForPass", at = @At("HEAD")) + private void hodgepodge$getGLCallListForPass(int pass, CallbackInfoReturnable cir) { + if (isInFrustum && pass == 0 && renderedIcons != null) { + for (IIcon icon : renderedIcons) { + ((IPatchedTextureAtlasSprite) icon).markNeedsAnimationUpdate(); + } + } + } + + @Override + public Set getRenderedTextures() { + return renderedIcons; + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/lighting/MixinWorld_FixLightUpdateLag.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/lighting/MixinWorld_FixLightUpdateLag.java new file mode 100644 index 000000000..e01327618 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/lighting/MixinWorld_FixLightUpdateLag.java @@ -0,0 +1,39 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.lighting; + +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalIntRef; +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * This mixin is a backport of a Forge fix https://github.com/MinecraftForge/MinecraftForge/pull/4729 + */ +@Mixin(World.class) +public abstract class MixinWorld_FixLightUpdateLag { + + @Shadow + public abstract boolean doChunksNearChunkExist(int p_72873_1_, int p_72873_2_, int p_72873_3_, int p_72873_4_); + + @ModifyConstant(method = "updateLightByType", constant = @Constant(intValue = 17, ordinal = 0)) + public int hodgepodge$modifyRangeCheck1(int cst) { + return 16; + } + + @Inject(method = "updateLightByType", at = @At(value = "FIELD", target = "Lnet/minecraft/world/World;theProfiler:Lnet/minecraft/profiler/Profiler;", shift = At.Shift.BEFORE, ordinal = 0)) + public void hodgepodge$modifyUpdateRange(EnumSkyBlock p_147463_1_, int x, int y, int z, + CallbackInfoReturnable cir, @Share("updateRange") LocalIntRef updateRange) { + updateRange.set(this.doChunksNearChunkExist(x, y, z, 18) ? 17 : 15); + } + + @ModifyConstant(method = "updateLightByType", constant = { @Constant(intValue = 17, ordinal = 1), @Constant(intValue = 17, ordinal = 2) }) + public int hodgepodge$modifyRangeCheck2(int cst, @Share("updateRange") LocalIntRef updateRange) { + return updateRange.get(); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureUtil_OptimizeMipmap.java b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureUtil_OptimizeMipmap.java new file mode 100644 index 000000000..d6d2a427f --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/early/angelica/textures/MixinTextureUtil_OptimizeMipmap.java @@ -0,0 +1,71 @@ +package com.gtnewhorizons.angelica.mixins.early.angelica.textures; + +import com.gtnewhorizons.angelica.utils.Mipmaps; +import net.minecraft.client.renderer.texture.TextureUtil; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(TextureUtil.class) +public class MixinTextureUtil_OptimizeMipmap { + + /** + * @author SuperCoder79 + * @reason Rewrite mipmap color math to use memoized value array instead of using Math.pow directly + */ + @Overwrite + private static int func_147943_a(int one, int two, int three, int four, boolean alpha) { + if (!alpha) { + final int a = Mipmaps.getColorComponent(one, two, three, four, 24); + final int r = Mipmaps.getColorComponent(one, two, three, four, 16); + final int g = Mipmaps.getColorComponent(one, two, three, four, 8); + final int b = Mipmaps.getColorComponent(one, two, three, four, 0); + return a << 24 | r << 16 | g << 8 | b; + } else { + float a = 0.0F; + float r = 0.0F; + float g = 0.0F; + float b = 0.0F; + if (one >> 24 != 0) { + a += Mipmaps.get(one >> 24); + r += Mipmaps.get(one >> 16); + g += Mipmaps.get(one >> 8); + b += Mipmaps.get(one >> 0); + } + + if (two >> 24 != 0) { + a += Mipmaps.get(two >> 24); + r += Mipmaps.get(two >> 16); + g += Mipmaps.get(two >> 8); + b += Mipmaps.get(two >> 0); + } + + if (three >> 24 != 0) { + a += Mipmaps.get(three >> 24); + r += Mipmaps.get(three >> 16); + g += Mipmaps.get(three >> 8); + b += Mipmaps.get(three >> 0); + } + + if (four >> 24 != 0) { + a += Mipmaps.get(four >> 24); + r += Mipmaps.get(four >> 16); + g += Mipmaps.get(four >> 8); + b += Mipmaps.get(four >> 0); + } + + a /= 4.0F; + r /= 4.0F; + g /= 4.0F; + b /= 4.0F; + int ia = (int) (Math.pow((double) a, 0.45454545454545453) * 255.0); + final int ir = (int) (Math.pow((double) r, 0.45454545454545453) * 255.0); + final int ig = (int) (Math.pow((double) g, 0.45454545454545453) * 255.0); + final int ib = (int) (Math.pow((double) b, 0.45454545454545453) * 255.0); + if (ia < 96) { + ia = 0; + } + + return ia << 24 | ir << 16 | ig << 8 | ib; + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IPatchedTextureAtlasSprite.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IPatchedTextureAtlasSprite.java new file mode 100644 index 000000000..43dc253eb --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/IPatchedTextureAtlasSprite.java @@ -0,0 +1,12 @@ +package com.gtnewhorizons.angelica.mixins.interfaces; + +public interface IPatchedTextureAtlasSprite { + + void markNeedsAnimationUpdate(); + + boolean needsAnimationUpdate(); + + void unmarkNeedsAnimationUpdate(); + + void updateAnimationsDryRun(); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ITexturesCache.java b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ITexturesCache.java new file mode 100644 index 000000000..0cbfe99fd --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/interfaces/ITexturesCache.java @@ -0,0 +1,10 @@ +package com.gtnewhorizons.angelica.mixins.interfaces; + +import net.minecraft.util.IIcon; + +import java.util.Set; + +public interface ITexturesCache { + + Set getRenderedTextures(); +} diff --git a/src/main/java/com/gtnewhorizons/angelica/utils/AnimationMode.java b/src/main/java/com/gtnewhorizons/angelica/utils/AnimationMode.java new file mode 100644 index 000000000..0dee6b633 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/utils/AnimationMode.java @@ -0,0 +1,7 @@ +package com.gtnewhorizons.angelica.utils; + +public enum AnimationMode { + NONE, + VISIBLE_ONLY, + ALL +} diff --git a/src/main/java/com/gtnewhorizons/angelica/utils/AnimationsRenderUtils.java b/src/main/java/com/gtnewhorizons/angelica/utils/AnimationsRenderUtils.java new file mode 100644 index 000000000..38ed419a7 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/utils/AnimationsRenderUtils.java @@ -0,0 +1,31 @@ +package com.gtnewhorizons.angelica.utils; + +import com.gtnewhorizons.angelica.mixins.interfaces.IPatchedTextureAtlasSprite; +import com.gtnewhorizons.angelica.mixins.interfaces.ITexturesCache; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; + +public class AnimationsRenderUtils { + + public static void markBlockTextureForUpdate(IIcon icon) { + markBlockTextureForUpdate(icon, null); + } + + public static void markBlockTextureForUpdate(IIcon icon, IBlockAccess blockAccess) { + final TextureMap textureMap = Minecraft.getMinecraft().getTextureMapBlocks(); + final TextureAtlasSprite textureAtlasSprite = textureMap.getAtlasSprite(icon.getIconName()); + + if (textureAtlasSprite != null && textureAtlasSprite.hasAnimationMetadata()) { + // null if called by anything but chunk render cache update (for example to get blocks rendered as items in + // inventory) + if (blockAccess instanceof ITexturesCache) { + ((ITexturesCache) blockAccess).getRenderedTextures().add(textureAtlasSprite); + } else { + ((IPatchedTextureAtlasSprite) textureAtlasSprite).markNeedsAnimationUpdate(); + } + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/utils/ManagedEnum.java b/src/main/java/com/gtnewhorizons/angelica/utils/ManagedEnum.java new file mode 100644 index 000000000..c1bf72c99 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/utils/ManagedEnum.java @@ -0,0 +1,52 @@ +package com.gtnewhorizons.angelica.utils; + +public class ManagedEnum> { + + private final T[] allValues; + private T value; + + public ManagedEnum(T initialValue) { + if (initialValue == null) throw new IllegalArgumentException(); + value = initialValue; + @SuppressWarnings("unchecked") + T[] allValues = (T[]) value.getClass().getEnumConstants(); + this.allValues = allValues; + } + + public boolean is(T value) { + return this.value == value; + } + + public T next() { + value = allValues[(value.ordinal() + 1) % allValues.length]; + return value; + } + + public void set(T value) { + this.value = value; + } + + public void set(int ordinal) { + this.value = allValues[Math.min(Math.max(0, ordinal), allValues.length - 1)]; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ManagedEnum that = (ManagedEnum) o; + + return value == that.value; + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public String toString() { + return value.toString(); + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/utils/Mipmaps.java b/src/main/java/com/gtnewhorizons/angelica/utils/Mipmaps.java new file mode 100644 index 000000000..c7df94c19 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/utils/Mipmaps.java @@ -0,0 +1,25 @@ +package com.gtnewhorizons.angelica.utils; + +public class Mipmaps { + + private static final float[] VALS = new float[256]; + + public static float get(int i) { + return VALS[i & 0xFF]; + } + + public static int getColorComponent(int one, int two, int three, int four, int bits) { + final float f = Mipmaps.get(one >> bits); + final float g = Mipmaps.get(two >> bits); + final float h = Mipmaps.get(three >> bits); + final float i = Mipmaps.get(four >> bits); + final float j = (float) Math.pow((f + g + h + i) * 0.25, 0.45454545454545453); + return (int) (j * 255.0); + } + + static { + for (int i = 0; i < VALS.length; ++i) { + VALS[i] = (float) Math.pow((float) i / 255.0F, 2.2); + } + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java index 10c446c1e..c8761bf93 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/world/WorldSlice.java @@ -10,6 +10,7 @@ import me.jellysquid.mods.sodium.client.world.cloned.ClonedChunkSectionCache; import net.minecraft.block.Block; import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.MathHelper; import net.minecraft.world.EnumSkyBlock; @@ -90,7 +91,7 @@ public static ChunkRenderContext prepare(World world, ChunkSectionPos origin, Cl return null; } - StructureBoundingBox volume = new StructureBoundingBox(origin.getMinX() - NEIGHBOR_BLOCK_RADIUS, + final StructureBoundingBox volume = new StructureBoundingBox(origin.getMinX() - NEIGHBOR_BLOCK_RADIUS, origin.getMinY() - NEIGHBOR_BLOCK_RADIUS, origin.getMinZ() - NEIGHBOR_BLOCK_RADIUS, origin.getMaxX() + NEIGHBOR_BLOCK_RADIUS, @@ -106,7 +107,7 @@ public static ChunkRenderContext prepare(World world, ChunkSectionPos origin, Cl final int maxChunkY = origin.y + NEIGHBOR_CHUNK_RADIUS; final int maxChunkZ = origin.z + NEIGHBOR_CHUNK_RADIUS; - ClonedChunkSection[] sections = new ClonedChunkSection[SECTION_TABLE_ARRAY_SIZE]; + final ClonedChunkSection[] sections = new ClonedChunkSection[SECTION_TABLE_ARRAY_SIZE]; for (int chunkX = minChunkX; chunkX <= maxChunkX; chunkX++) { for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; chunkZ++) { @@ -162,7 +163,7 @@ public void copyData(ChunkRenderContext context) { @Override public int getLightBrightnessForSkyBlocks(int x, int y, int z, int min) { - int skyBrightness = this.getSkyBlockTypeBrightness(net.minecraft.world.EnumSkyBlock.Sky, x, y, z); + final int skyBrightness = this.getSkyBlockTypeBrightness(net.minecraft.world.EnumSkyBlock.Sky, x, y, z); int blockBrightness = this.getSkyBlockTypeBrightness(net.minecraft.world.EnumSkyBlock.Block, x, y, z); if (blockBrightness < min) { @@ -178,10 +179,10 @@ public int getSkyBlockTypeBrightness(EnumSkyBlock skyBlock, int x, int y, int z) } if (this.getBlock(x, y, z).getUseNeighborBrightness()) { int yp = this.getLightLevel(skyBlock, x, y + 1, z); - int xp = this.getLightLevel(skyBlock, x + 1, y, z); - int xm = this.getLightLevel(skyBlock, x - 1, y, z); - int zp = this.getLightLevel(skyBlock, x, y, z + 1); - int zm = this.getLightLevel(skyBlock, x, y, z - 1); + final int xp = this.getLightLevel(skyBlock, x + 1, y, z); + final int xm = this.getLightLevel(skyBlock, x - 1, y, z); + final int zp = this.getLightLevel(skyBlock, x, y, z + 1); + final int zm = this.getLightLevel(skyBlock, x, y, z - 1); if (xp > yp) yp = xp; if (xm > yp) yp = xm; @@ -206,9 +207,9 @@ public boolean isAirBlock(int x, int y, int z) { @Override public BiomeGenBase getBiomeGenForCoords(int x, int z) { - int relX = x - this.baseX; - int relY = 0; - int relZ = z - this.baseZ; + final int relX = x - this.baseX; + final int relY = 0; + final int relZ = z - this.baseZ; BiomeGenBase biome = this.biomeData[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)] [(x & 15) | (z & 15) << 4]; @@ -255,14 +256,14 @@ private static void copyBlocks(Block[] blocks, int[] metas, ClonedChunkSection s private void unpackBlockDataR(Block[] blocks, int metas[], ClonedChunkSection section, StructureBoundingBox box) { ChunkSectionPos pos = section.getPosition(); - int minBlockX = Math.max(box.minX, pos.getMinX()); - int maxBlockX = Math.min(box.maxX, pos.getMaxX()); + final int minBlockX = Math.max(box.minX, pos.getMinX()); + final int maxBlockX = Math.min(box.maxX, pos.getMaxX()); - int minBlockY = Math.max(box.minY, pos.getMinY()); - int maxBlockY = Math.min(box.maxY, pos.getMaxY()); + final int minBlockY = Math.max(box.minY, pos.getMinY()); + final int maxBlockY = Math.min(box.maxY, pos.getMaxY()); - int minBlockZ = Math.max(box.minZ, pos.getMinZ()); - int maxBlockZ = Math.min(box.maxZ, pos.getMaxZ()); + final int minBlockZ = Math.max(box.minZ, pos.getMinZ()); + final int maxBlockZ = Math.min(box.maxZ, pos.getMaxZ()); copyBlocks(blocks, metas, section, minBlockY, maxBlockY, minBlockZ, maxBlockZ, minBlockX, maxBlockX); } @@ -271,25 +272,25 @@ private void unpackBlockDataZ(Block[] blocks, int[] metas, ClonedChunkSection se // TODO: Look into a faster copy for this? final ChunkSectionPos pos = section.getPosition(); - int minBlockX = pos.getMinX(); - int maxBlockX = pos.getMaxX(); + final int minBlockX = pos.getMinX(); + final int maxBlockX = pos.getMaxX(); - int minBlockY = pos.getMinY(); - int maxBlockY = pos.getMaxY(); + final int minBlockY = pos.getMinY(); + final int maxBlockY = pos.getMaxY(); - int minBlockZ = pos.getMinZ(); - int maxBlockZ = pos.getMaxZ(); + final int minBlockZ = pos.getMinZ(); + final int maxBlockZ = pos.getMaxZ(); // TODO: Can this be optimized? copyBlocks(blocks, metas, section, minBlockY, maxBlockY, minBlockZ, maxBlockZ, minBlockX, maxBlockX); } public Block getBlock(int x, int y, int z) { - int relX = x - this.baseX; - int relY = y - this.baseY; - int relZ = z - this.baseZ; - - return this.blockArrays[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)][getLocalBlockIndex(relX & 15, relY & 15, relZ & 15)]; + final int relX = x - this.baseX; + final int relY = y - this.baseY; + final int relZ = z - this.baseZ; + final Block block = this.blockArrays[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)][getLocalBlockIndex(relX & 15, relY & 15, relZ & 15)]; + return block == null ? Blocks.air : block; } public Block getBlockRelative(int x, int y, int z) { @@ -302,9 +303,9 @@ public int getBlockMetadataRelative(int x, int y, int z) { @Override public int getBlockMetadata(int x, int y, int z) { - int relX = x - this.baseX; - int relY = y - this.baseY; - int relZ = z - this.baseZ; + final int relX = x - this.baseX; + final int relY = y - this.baseY; + final int relZ = z - this.baseZ; return this.metadataArrays[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)][getLocalBlockIndex(relX & 15, relY & 15, relZ & 15)]; } diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 2e1b4af78..e00cf5ed9 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -1,8 +1,11 @@ package net.coderbot.iris; import com.google.common.base.Throwables; +import com.gtnewhorizons.angelica.AngelicaMod; import com.gtnewhorizons.angelica.Tags; import com.gtnewhorizons.angelica.glsm.GLStateManager; +import com.mitchej123.hodgepodge.Common; +import com.mitchej123.hodgepodge.client.HodgepodgeClient; import com.mojang.realmsclient.gui.ChatFormatting; import cpw.mods.fml.client.registry.ClientRegistry; import cpw.mods.fml.common.eventhandler.SubscribeEvent; @@ -27,12 +30,14 @@ import net.coderbot.iris.shaderpack.option.values.OptionValues; import net.coderbot.iris.texture.pbr.PBRTextureManager; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.resources.I18n; import net.minecraft.client.settings.KeyBinding; import net.minecraft.launchwrapper.Launch; import net.minecraft.util.ChatComponentText; import org.jetbrains.annotations.NotNull; +import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.ContextCapabilities; import org.lwjgl.opengl.GLContext; @@ -130,6 +135,18 @@ public void onKeypress(InputEvent.KeyInputEvent event) { } } + + @SubscribeEvent + public void keyUp(InputEvent.KeyInputEvent event) { + final int key = Keyboard.getEventKey(); + final boolean released = !Keyboard.getEventKeyState(); + if (Minecraft.getMinecraft().gameSettings.showDebugInfo && GuiScreen.isShiftKeyDown() && GuiScreen.isCtrlKeyDown() && released) { + if (key == Keyboard.KEY_N) { + AngelicaMod.animationsMode.next(); + } + } + } + /** * Called very early on in Minecraft initialization. At this point we *cannot* safely access OpenGL, but we can do some very basic setup, config loading, * and environment checks. diff --git a/src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java b/src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java index ea7535f52..ffcc3ec53 100644 --- a/src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java +++ b/src/main/java/net/coderbot/iris/client/IrisDebugScreenHandler.java @@ -1,5 +1,8 @@ package net.coderbot.iris.client; +import com.gtnewhorizons.angelica.AngelicaMod; +import com.gtnewhorizons.angelica.config.AngelicaConfig; +import com.mitchej123.hodgepodge.client.HodgepodgeClient; import cpw.mods.fml.common.eventhandler.EventPriority; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.coderbot.iris.Iris; @@ -46,6 +49,9 @@ public void onRenderGameOverlayTextEvent(RenderGameOverlayEvent.Text event) { } else { event.right.add("[" + Iris.MODNAME + "] Shaders are disabled"); } + if(AngelicaConfig.speedupAnimations) { + event.right.add(9, "animationsMode: " + AngelicaMod.animationsMode); + } Iris.getPipelineManager().getPipeline().ifPresent(pipeline -> pipeline.addDebugText(event.left)); diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index 18dc4dd71..21ceb2475 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -46,24 +46,6 @@ "dependants": [], "useDependencyInformation": true }, - { - "modid": "archaicfix", - "name": "ArchaicFix", - "description": "Swiss army knife of bugfixes for 1.7.", - "version": "${modVersion}", - "mcversion": "${minecraftVersion}", - "url": "", - "updateUrl": "", - "authorList": [ - "embeddedt" - ], - "credits": "The Forge and FML guys, for making this example", - "logoFile": "", - "screenshots": [], - "dependencies": [ - "required-after:gtnhmixins@[2.0.0,)" - ] - }, { "modid": "embeddium", "name": "Embeddium", From deacdd3ba54f230e7a532bb504046710ca1bb1ad Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 24 Dec 2023 16:31:18 -0800 Subject: [PATCH 301/301] Update Readme --- README.MD | 23 +++++++++++++++---- .../angelica/rendering/RenderingState.java | 1 + 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/README.MD b/README.MD index 1ac7233a9..8484924b4 100644 --- a/README.MD +++ b/README.MD @@ -3,7 +3,20 @@ * Is it obtuse, or accute? -Caedis * It's a cute angle -mitchej123 -**Not yet in an usable state** +**Alpha Quality - Here there be Dragons** + +# 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 +* EndlessIDs - Future compat planned +* RPLE - Future compat planned + +# Permanent Incompatibilities +* Optifine [Disabled, won't fix] +* Fastcraft [Disable, won't fix] +* ArchaicFix 0.6.2 and below - Use 0.7.0 or above +* Hodgepodge 2.4.2 and below - Use 2.4.3 or above +* CodeChickenCore/Lib <1.2.0 - Threading issues, use 1.2.0+ # Credits * ShadersMod @@ -11,16 +24,16 @@ * eigenraven, Caedis, glowredman, and mitchej123 for the conversion of ASM to Mixin * eigenraven and vlaetansky for getting the original ShadersMod compiling again * ArchaicFix - * Includes graphic enhancements from [ArchaicFix](https://github.com/embeddedt/ArchaicFix/commit/4afb943751883b27a1f0aa7c5ba71698bc897e95) by embeddedt under the [LGPL](https://github.com/embeddedt/ArchaicFix/blob/main/LICENSE.md) + * Includes graphic enhancements from [ArchaicFix](https://github.com/embeddedt/ArchaicFix/tree/4afb943751883b27a1f0aa7c5ba71698bc897e95) by embeddedt under the [LGPL](https://github.com/embeddedt/ArchaicFix/blob/main/LICENSE.md) * NotFine - * Includes modified version of [NotFine](https://github.com/jss2a98aj/NotFine/commit/a2652e24b5654f437fb7138f6d1f5e947a7d7125) by jss2a98aj under the LGPL + * Includes modified version of [NotFine](https://github.com/jss2a98aj/NotFine/tree/a2652e24b5654f437fb7138f6d1f5e947a7d7125) by jss2a98aj under the LGPL * Iris Shaders * The [Iris](https://github.com/IrisShaders/Iris) Team: coderbot, IMS212, Justsnoopy30, FoundationGames - * Asek3 for the Iris Forge port [Oculus](https://github.com/Asek3/Oculus/commit/839ce8eca8cf0c4f6b7a1322b906e5c99125ca69) + * Asek3 for the Iris Forge port [Oculus](https://github.com/Asek3/Oculus/tree/839ce8eca8cf0c4f6b7a1322b906e5c99125ca69) * Backported code under the LGPL * Sodium * JellySquid & the CaffeineMC team, for making Sodium in the first place - * Embeddedt for [Embeddium](https://github.com/embeddedt/embeddium/commit/dc59ca357c25beefd6288f0d1d40b4cd8e670ab8) under the [LGPL 3.0](https://github.com/embeddedt/embeddium/blob/16.x/forge/LICENSE) + * Embeddedt for [Embeddium](https://github.com/embeddedt/embeddium/tree/dc59ca357c25beefd6288f0d1d40b4cd8e670ab8) under the [LGPL 3.0](https://github.com/embeddedt/embeddium/blob/16.x/forge/LICENSE) * Neodymium * Makamys for [Neodymium](https://github.com/makamys/Neodymium) - Various Tessellator -> Quad functionality taken under the LGPL 3 * HUDCaching diff --git a/src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java b/src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java index fdcfb291e..a532442a4 100644 --- a/src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java +++ b/src/main/java/com/gtnewhorizons/angelica/rendering/RenderingState.java @@ -27,6 +27,7 @@ public void setCameraPosition(double x, double y, double z) { } public void captureProjectionMatrix() { + // Not very fast, but given we're not on 3.2+ core and are still using the opengl matrix stack, we don't have much alternative projectionBuffer.position(0); GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projectionBuffer); projectionMatrix.set(projectionBuffer);